aboutsummaryrefslogtreecommitdiff
path: root/vendor/voclient/voapps
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/voclient/voapps')
-rw-r--r--vendor/voclient/voapps/.BASE0
-rw-r--r--vendor/voclient/voapps/Makefile314
-rw-r--r--vendor/voclient/voapps/README324
-rw-r--r--vendor/voclient/voapps/README.samp171
-rw-r--r--vendor/voclient/voapps/TODO4
-rw-r--r--vendor/voclient/voapps/Tasks59
-rw-r--r--vendor/voclient/voapps/_examples41
-rw-r--r--vendor/voclient/voapps/_vo-cli.demo44
-rw-r--r--vendor/voclient/voapps/_vo.cap90
-rwxr-xr-xvendor/voclient/voapps/_z13
l---------vendor/voclient/voapps/data1
-rw-r--r--vendor/voclient/voapps/f77/README9
-rw-r--r--vendor/voclient/voapps/generic.c221
-rw-r--r--vendor/voclient/voapps/lib/Makefile134
-rw-r--r--vendor/voclient/voapps/lib/proto236
-rw-r--r--vendor/voclient/voapps/lib/voAclist.c299
-rw-r--r--vendor/voclient/voapps/lib/voAppProto.h238
-rw-r--r--vendor/voclient/voapps/lib/voApps_f77.c0
-rw-r--r--vendor/voclient/voapps/lib/voApps_spp.c271
-rw-r--r--vendor/voclient/voapps/lib/voDALUtil.c839
-rw-r--r--vendor/voclient/voapps/lib/voFITS.c467
-rw-r--r--vendor/voclient/voapps/lib/voHTML.c131
-rw-r--r--vendor/voclient/voapps/lib/voInv.c501
-rw-r--r--vendor/voclient/voapps/lib/voKML.c543
-rw-r--r--vendor/voclient/voapps/lib/voLog.c225
-rw-r--r--vendor/voclient/voapps/lib/voObj.c761
-rw-r--r--vendor/voclient/voapps/lib/voParams.c189
-rw-r--r--vendor/voclient/voapps/lib/voRanges.c286
-rw-r--r--vendor/voclient/voapps/lib/voSCS.c265
-rw-r--r--vendor/voclient/voapps/lib/voSIAP.c295
-rw-r--r--vendor/voclient/voapps/lib/voSSAP.c233
-rw-r--r--vendor/voclient/voapps/lib/voSvc.c874
-rw-r--r--vendor/voclient/voapps/lib/voTask.c856
-rw-r--r--vendor/voclient/voapps/lib/voUtil.c2389
-rw-r--r--vendor/voclient/voapps/lib/voXML.c166
-rw-r--r--vendor/voclient/voapps/lib/vosUtil.c998
-rw-r--r--vendor/voclient/voapps/session_cmd.c171
-rw-r--r--vendor/voclient/voapps/spp/README9
-rw-r--r--vendor/voclient/voapps/task/Makefile169
-rw-r--r--vendor/voclient/voapps/task/Notes.fitz99
-rw-r--r--vendor/voclient/voapps/task/Notes.tody164
-rw-r--r--vendor/voclient/voapps/task/_pkgbin31
-rwxr-xr-xvendor/voclient/voapps/task/mkpy5
-rw-r--r--vendor/voclient/voapps/task/pkgMain.c117
-rw-r--r--vendor/voclient/voapps/task/test.py4
-rw-r--r--vendor/voclient/voapps/task/vaopackage.py453
-rw-r--r--vendor/voclient/voapps/task/voPackage.c78
-rw-r--r--vendor/voclient/voapps/task/voParam.c418
-rw-r--r--vendor/voclient/voapps/task/voPkg.c333
-rw-r--r--vendor/voclient/voapps/task/voTask.c258
-rw-r--r--vendor/voclient/voapps/task/voTask.h133
-rw-r--r--vendor/voclient/voapps/task/voTaskMethod.c49
-rw-r--r--vendor/voclient/voapps/task/voTaskUtil.c133
-rw-r--r--vendor/voclient/voapps/task/votools.h79
-rw-r--r--vendor/voclient/voapps/task/zz.c0
-rw-r--r--vendor/voclient/voapps/task/zz.py60
-rw-r--r--vendor/voclient/voapps/task/zztest.c0
-rw-r--r--vendor/voclient/voapps/test.xml137
-rw-r--r--vendor/voclient/voapps/test/_tasks17
-rw-r--r--vendor/voclient/voapps/test/_tests167
-rw-r--r--vendor/voclient/voapps/test/gal.jpgbin0 -> 7300 bytes
-rwxr-xr-xvendor/voclient/voapps/test/test.voatlas10
-rw-r--r--vendor/voclient/voapps/voApps.c137
-rw-r--r--vendor/voclient/voapps/voApps.h180
-rw-r--r--vendor/voclient/voapps/voApps.i90
-rw-r--r--vendor/voclient/voapps/voAppsP.h255
-rw-r--r--vendor/voclient/voapps/voApps_spp.c255
-rw-r--r--vendor/voclient/voapps/voatlas.c660
-rw-r--r--vendor/voclient/voapps/vocatalog.c155
-rwxr-xr-xvendor/voclient/voapps/voclient_test29
-rw-r--r--vendor/voclient/voapps/vodata.c2387
-rw-r--r--vendor/voclient/voapps/vodata.c.bak2256
-rw-r--r--vendor/voclient/voapps/voimage.c133
-rw-r--r--vendor/voclient/voapps/voiminfo.c493
-rw-r--r--vendor/voclient/voapps/voregistry.c1291
-rw-r--r--vendor/voclient/voapps/vosamp.c2298
-rw-r--r--vendor/voclient/voapps/vosesame.c680
-rw-r--r--vendor/voclient/voapps/vosession.c1278
-rw-r--r--vendor/voclient/voapps/vosloanspec.c765
-rw-r--r--vendor/voclient/voapps/vospectra.c130
-rw-r--r--vendor/voclient/voapps/votcat.c181
-rw-r--r--vendor/voclient/voapps/votcnv.c259
-rw-r--r--vendor/voclient/voapps/votget.c1089
-rw-r--r--vendor/voclient/voapps/votinfo.c455
-rw-r--r--vendor/voclient/voapps/votjoin.c203
-rw-r--r--vendor/voclient/voapps/votopic.c268
-rw-r--r--vendor/voclient/voapps/votpos.c249
-rw-r--r--vendor/voclient/voapps/votsort.c394
-rw-r--r--vendor/voclient/voapps/votsplit.c202
-rw-r--r--vendor/voclient/voapps/votstat.c281
-rw-r--r--vendor/voclient/voapps/zzparam.c87
-rw-r--r--vendor/voclient/voapps/zztest.c427
-rw-r--r--vendor/voclient/voapps/zzwcs.c106
93 files changed, 33254 insertions, 0 deletions
diff --git a/vendor/voclient/voapps/.BASE b/vendor/voclient/voapps/.BASE
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/vendor/voclient/voapps/.BASE
diff --git a/vendor/voclient/voapps/Makefile b/vendor/voclient/voapps/Makefile
new file mode 100644
index 00000000..ed6e30df
--- /dev/null
+++ b/vendor/voclient/voapps/Makefile
@@ -0,0 +1,314 @@
+#///////////////////////////////////////////////////////////////////////////////
+#//
+#// Makefile for the VOClient Package Applications
+#//
+#///////////////////////////////////////////////////////////////////////////////
+
+# primary dependencies
+
+NAME = VOApps
+VERSION = 1.0
+PLATFORM := $(shell uname -s)
+PLMACH := $(shell uname -m)
+HERE := $(shell /bin/pwd)
+BINDIR := ../bin/
+LIBDIR := ../lib/
+INCDIR := ../include/
+
+
+# secondary dependencies
+LIBBASE = lib$(NAME)
+STATICLIB = $(HERE)/$(LIBBASE).a
+SHAREDLIB = $(HERE)/$(LIBBASE).so.$(VERSION)
+
+
+# stuff that's precious to keep
+.PRECIOUS: $(STATICLIB) $(SHAREDLIB)
+.KEEP_STATE:
+
+
+# includes, flags and libraries
+CC = gcc
+CINCS = -I$(HERE) -I../ -I$(INCDIR) -I../../../include
+LFLAGS = -L../ -L../lib/ -L../../../bin/
+
+#F77 = g77
+F77 = gfortran
+FFLAGS = -g -Wall
+
+
+ifeq ($(PLATFORM),Darwin)
+ LIBCURL = -lcurl
+else
+ LIBCURL = ../lib/libcurl.a
+endif
+LIBCFITSIO = ../lib/libcfitsio.a
+
+ifeq ($(PLATFORM),Darwin)
+ ifeq ($(PLMACH),x86_64)
+ CARCH = -m64 -mmacosx-version-min=10.5
+ else
+ CARCH = -arch i386 -m32 -mmacosx-version-min=10.4
+ endif
+ ifdef IRAFARCH
+ ifeq ($(IRAFARCH),macintel)
+ CARCH = -m64 -mmacosx-version-min=10.5
+ else
+ CARCH = -arch i386 -m32 -mmacosx-version-min=10.5
+ endif
+ endif
+else
+ CLIBS = $(LIBCURL) -lm -lc -lpthread -lrt
+ CARCH =
+ ifeq ($(PLMACH),x86_64)
+ LFLAGS = -L/usr/lib64 $(LFLAGS)
+ endif
+endif
+
+#CLIBS = $(LIBCURL) -lm -lpthread -lc
+CFLAGS = -g -Wall $(CARCH) -D$(PLATFORM) $(CINCS) -L./
+
+
+
+# list of source and include files
+
+C_SRCS = votcnv.c votget.c votinfo.c vosesame.c vodata.c voregistry.c \
+ votpos.c votcat.c votsplit.c votstat.c votjoin.c voatlas.c \
+ votsort.c vosamp.c voiminfo.c \
+ voimage.c vocatalog.c vospectra.c votopic.c \
+ voApps_spp.c
+C_OBJS = votcnv.o votget.o votinfo.o vosesame.o vodata.o voregistry.o \
+ votpos.o votcat.o votsplit.o votstat.o votjoin.o voatlas.o \
+ votsort.o vosamp.o voiminfo.o \
+ voimage.o vocatalog.o vospectra.o votopic.o \
+ voApps_spp.o
+C_INCS = voApps.h voAppsP.h
+
+
+
+F77_SRCS =
+F77_OBJS =
+F77_INCS =
+
+SPP_SRCS =
+SPP_OBJS =
+SPP_INCS = votParse_spp.h
+
+SPP_TASKS =
+F77_TASKS =
+C_TASKS = voregistry \
+ vosesame \
+ vodata voatlas voimage vocatalog vospectra votopic \
+ votcnv votget votpos votinfo votstat votsort \
+ vosamp \
+ voiminfo \
+
+ # Not yet imlemented (and/or working)
+ #votcat votsplit votjoin
+
+
+TARGETS = $(F77_TASKS) $(SPP_TASKS) $(C_TASKS)
+
+SRCS = $(C_SRCS) $(F77_SRCS) $(SPP_SRCS)
+OBJS = $(C_OBJS) $(F77_OBJS) $(SPP_OBJS)
+HOST_LIBS = $(LIBCURL) $(LFLAGS) -lcfitsio $(CLIBS)
+LIBS = lib$(NAME).a -lVOTable -lVOClient -lsamp $(HOST_LIBS)
+
+
+
+all:
+ (make c_progs)
+ cp lib$(NAME).a $(LIBDIR)
+ cp $(TARGETS) $(BINDIR)
+
+
+World: lib
+
+install: all
+ cp lib$(NAME).a $(LIBDIR)
+ mv $(TARGETS) $(BINDIR)
+
+objs: $(OBJS)
+
+
+
+# Targets
+
+#all: $(TARGETS)
+
+c_progs: $(C_TASKS)
+spp_progs: $(SPP_TASKS)
+f77_progs: $(F77_TASKS)
+
+distclean:
+ make clean
+ /bin/rm -rf *.fits *.xml
+
+clean:
+ /bin/rm -rf .make.state .nse_depinfo *.[aeo] *.dSYM
+ /bin/rm -rf $(TARGETS)
+
+everything:
+ make clean
+ make all
+ make install
+
+help: HELP
+
+install: all
+
+
+
+####################################
+# LIBVOAPPS dependency libraries.
+####################################
+
+lib: objs suplib
+ ar rv lib$(NAME).a $(OBJS)
+ $(RM) $(OBJS)
+
+suplib:
+ (cd lib ; make all)
+
+
+###############################################################################
+# Unit test programs to be built.
+###############################################################################
+
+demo: $(TARGETS)
+
+zztest: zztest.c
+ $(CC) $(CFLAGS) -o zztest zztest.c $(LIBS)
+
+
+###########################
+# C Test programs
+###########################
+
+# Note: VOSESSION has its own main()
+vosession: vosession.o lib
+ $(CC) $(CFLAGS) -o vosession vosession.c $(LIBS)
+ /bin/rm -rf vosession.dSYM
+
+session_cmd: session_cmd.o lib
+ $(CC) $(CFLAGS) -o session_cmd session_cmd.c $(LIBS)
+ /bin/rm -rf session_cmd.dSYM
+
+
+vodata: voApps.c vodata.o lib
+ $(CC) $(CFLAGS) -o vodata voApps.c $(LIBS)
+ /bin/rm -rf vodata.dSYM
+
+voregistry: voApps.c voregistry.o lib
+ $(CC) $(CFLAGS) -o voregistry voApps.c $(LIBS)
+ /bin/rm -rf voregistry.dSYM
+
+vosamp: voApps.c vosamp.o lib
+ $(CC) $(CFLAGS) -o vosamp voApps.c $(LIBS)
+ /bin/rm -rf vosamp.dSYM
+
+voatlas: voApps.c voatlas.o lib
+ $(CC) $(CFLAGS) -o voatlas voApps.c $(LIBS)
+ /bin/rm -rf voatlas.dSYM
+
+voiminfo: voApps.c voiminfo.o lib
+ $(CC) $(CFLAGS) -o voiminfo voApps.c $(LIBS)
+ /bin/rm -rf voiminfo.dSYM
+
+vosloanspec: voApps.c vosloanspec.o lib
+ $(CC) $(CFLAGS) -o vosloanspec voApps.c $(LIBS)
+ /bin/rm -rf vosloanspec.dSYM
+
+votcnv: voApps.c votcnv.o lib
+ $(CC) $(CFLAGS) -o votcnv voApps.c $(LIBS)
+ /bin/rm -rf votcnv.dSYM
+
+votcat: voApps.c votcat.o lib
+ $(CC) $(CFLAGS) -o votcat voApps.c $(LIBS)
+ /bin/rm -rf votcat.dSYM
+
+votget: voApps.c votget.o lib
+ $(CC) $(CFLAGS) -o votget voApps.c $(LIBS)
+ /bin/rm -rf votget.dSYM
+
+votpos: voApps.c votpos.o lib
+ $(CC) $(CFLAGS) -o votpos voApps.c $(LIBS)
+ /bin/rm -rf votpos.dSYM
+
+votinfo: voApps.c votinfo.o lib
+ $(CC) $(CFLAGS) -o votinfo voApps.c $(LIBS)
+ /bin/rm -rf votinfo.dSYM
+
+votjoin: voApps.c votjoin.o lib
+ $(CC) $(CFLAGS) -o votjoin voApps.c $(LIBS)
+ /bin/rm -rf votjoin.dSYM
+
+votsort: voApps.c votsort.o lib
+ $(CC) $(CFLAGS) -o votsort voApps.c $(LIBS)
+ /bin/rm -rf votsort.dSYM
+
+votsplit: voApps.c votsplit.o lib
+ $(CC) $(CFLAGS) -o votsplit voApps.c $(LIBS)
+ /bin/rm -rf votsplit.dSYM
+
+votstat: voApps.c votstat.o lib
+ $(CC) $(CFLAGS) -o votstat voApps.c $(LIBS)
+ /bin/rm -rf votstat.dSYM
+
+vosesame: voApps.c vosesame.o lib
+ $(CC) $(CFLAGS) -o vosesame voApps.c $(LIBS)
+ /bin/rm -rf vosesame.dSYM
+
+voimage: voApps.c voimage.o lib
+ $(CC) $(CFLAGS) -o voimage voApps.c $(LIBS)
+ /bin/rm -rf voimage.dSYM
+
+vocatalog: voApps.c vocatalog.o lib
+ $(CC) $(CFLAGS) -o vocatalog voApps.c $(LIBS)
+ /bin/rm -rf vocatalog.dSYM
+
+vospectra: voApps.c vospectra.o lib
+ $(CC) $(CFLAGS) -o vospectra voApps.c $(LIBS)
+ /bin/rm -rf vospectra.dSYM
+
+votopic: voApps.c votopic.o lib
+ $(CC) $(CFLAGS) -o votopic voApps.c $(LIBS)
+ /bin/rm -rf votopic.dSYM
+
+
+
+###########################
+# SPP Test programs
+###########################
+
+
+
+
+###########################
+# Fortran Test programs.
+###########################
+
+
+
+
+
+
+###############################################################################
+# Leave this stuff alone.
+###############################################################################
+
+$(STATICLIB): $(C_SRCS:%.c=Static/%.o)
+ /usr/bin/ar rv $@ $?
+Static/%.o: %.c $(C_INCS)
+ /usr/bin/gcc $(CINCS) $(CFLAGS) -g -c $< -o $@
+Static:
+ /bin/mkdir $@
+ chmod 777 $@
+
+$(SHAREDLIB): $(C_SRCS:%.c=Shared/%.o)
+ /usr/bin/ld -shared -o $@ $? -lc -ldl
+Shared/%.o: %.c $(C_INCS)
+ /usr/bin/gcc $(CINCS) $(CFLAGS) -fpic -shared -c $< -o $@
+Shared:
+ /bin/mkdir $@
+ chmod 777 $@
diff --git a/vendor/voclient/voapps/README b/vendor/voclient/voapps/README
new file mode 100644
index 00000000..aea037b0
--- /dev/null
+++ b/vendor/voclient/voapps/README
@@ -0,0 +1,324 @@
+
+=============================
+Last Modified: Aug 10, 2012
+=============================
+
+
+ This directory contains the VOClient command-line applications.
+Key files in this directory include:
+
+ voApps.c The generic unix main() linked to all tasks
+ generic.c A template code for building VOClient apps
+
+ voatlas.c The VOATLAS multi-wavelength image atlas task
+ vodata.c The VODATA general data query retrieval task
+
+ voregistry.c The VOREGISTRY task to query/resolve Registry resources
+
+ vosesame.c The VOSESAME name resolver
+
+ vosamp.c The VOSAMP command-line SAMP tool
+
+ votcnv.c The VOTCNV votable conversion tool
+ votget.a The VOTGET task to retrieve acrefs from a votable
+ votinfo.c The VOTINFO task to print information about a votable
+ votpos.c The VOTPOS task to extract positional cols from votables
+ votsort.c The VOTSORT task to sort a votable based on a column
+ votstat.c The VOTSTAT task to print colum statistics
+
+
+ Planned tasks Not Yet Implemented:
+
+ votcat.c // VOTable Resource concatenator
+ votjoin.c // VOTable inner joins
+ votselect.c // Select rows/cols by index/expr
+ votsplit.c // Split multi-resource votables
+
+ VOClientd // C-based minimal implementation of VOClient Daeomon
+ hub // C implementation of SAMP Hub
+
+ voxmatch // Cross-compare local table and VO data
+
+ vosput // Put files to a VOSpace
+ vosget // Get files from a VOSpace
+ vosmove // Move files/nodes between VOSpaces
+ voslist // List files/nodes in a VOSpace
+ vosdelete // Delete files/nodes in a VOSpace
+
+ voskybot // List known moving objects in an image
+
+
+
+The 'lib' subdirectory contains support code for the applications. Of
+particular interest is the 'lib/voTask.c' code that defines the tasking
+interface used by the applications.
+
+
+Task Interface
+--------------
+
+ All VOClient apps are written as C procedures sharing a common signature:
+
+ <task> (int argc, char **argv, size_t *len, void **result);
+
+where 'argc' and 'argv' have the usual meaning for the CLI argument vector,
+'len' is the length of any returned object (or 0 if there is no return),
+and 'result' is a pointer to the returned object in memory. The task()
+procedure returns 0 for success, and a positive value to indicate an error
+return (this may include a signal number for a crashed child process as
+well as task-specific error return codes).
+
+ Tasks share a common main() responsible only for passing in the
+parameter options, executing the task as a connected subprocess (or by
+calling the procedure directly if the VOAPP_CONNECTED environment variable
+is defined, this is to aid in debugging) and for retrieving any returned
+result object. This architecture ensures that any memory allocated or
+threads spawned by the VOClient app do not interfere with an app using
+the language API.
+
+ Host Process App Sub-Process
+ +----------+ +----------------------+
+ | C | parameters | |
+ | main() |--------------->| VOClient |
+ | or |<---------------| application code |
+ | Lang API | result | |
+ +----------+ +----------------------+
+
+The application is spawned as a child process by the main() and the CLI
+parameters are sent over IPC. Likewise, any return value from the app is
+sent back via IPC, a host CLI tool would simply discard this result however
+a language binding or other API would then have a pointer to the result
+object it could pass up to the calling interface. The details of what can
+be returned by a task is task-specific and the caller must be aware of the
+options to be of use, for this discussion the returned 'result' is a memory
+object of size 'len' given the above calling signature.
+
+ The 'voApps.c' code contains the common main() function which normally
+calls the vo_runTask() procedure to execute the task based on the task name
+derived from a lookup table. (See lib/voTask.c for this procedure).
+
+
+
+Parameter Interface
+-------------------
+
+ VOClient apps are written to accept CLI/parameter options in a number
+of formats suited for use as Unix tasks or from an API that may be better
+suited to pass in "<param>=<value>" strings. The following formats for
+option strings are supported by all tasks:
+
+ -p param[+-] --param --param=value param=<value>
+
+For CLI tasks the following would be equivalent:
+
+ % task -p # to set the 'p' option
+ % task --param # long-form of 'p' option
+ % task --param+ # if 'param' is a boolean option
+ % task --param=value # to set a specific value for param
+ % task --param value # to set a specific value for param
+ % task param=value # to set a specific value for param
+
+From an API one could imagine these same parameters being passed in to form
+the required argument/parameter 'argv' vector as e.g.
+
+ from VOClient import tasks as voc
+ status = voc.task ("param=value", ....)
+
+Accomodating a return value from the task would affect this sort of interface
+(e.g. if the task were to return an in-memory FITS file instead of a status
+code) but the idea is to support both standard CLI options as well as a p=v
+format more appropriate for a tasking API interface.
+
+
+Common Options/Parameters:
+
+ All tasks(*) support a core set of options, namely
+
+ -h,--help Print a task usage summary and examples
+ -%,--test <input> Run unit tests (some tasks require <input>)
+ -r,--return <opt> Return optional result object
+
+All other options are task-specific however an effort has been made to make
+these consistent across tasks (e.g. a "--input" for input files, "--fmt" for
+output VOTable formats, "--samp" for SAMP functionality, etc).
+
+ The "--help" (or "-h") option to each task should provide enough runtime
+documentation to get started with using a task, in particular the examples
+given in the help are meant to always be valid.
+
+ The "--test" (or "-%") option is a way to run unit tests on a particular
+task, primarily based on the examples given in "--help". Depending on the
+task an input file/arguments of some form must be provided for the tests to
+work. For example, unit tests of VOTable tools can be run using votables
+returned from various data services to ensure proper behavior for all VO
+resources or to test operation against various (non)compliant files. This
+same mechanism can be used to build a regression test suite against a static
+list of VO Resources or standardized data files.
+
+ The "--return" option is task-specific and its use will depend largely
+on the API implementing it. A detailed description of the return objects
+will be provided in the task/API documentation.
+
+
+ (*) Exceptions as of this writing are the original VO-CLI tasks
+ VODATA/VOSESAME/VODIRECTORY, these will be implemented before
+ release.
+
+
+
+SAMP Interoperability
+---------------------
+
+ The VOSAMP task a CLI tool for sending messages to other SAMP-enabled
+applications, either as a one-off CLI execution or from within a scripted
+environment. To hide the SAMP details, the CLI interface is written to be
+more user-friendly, e.g. the options(*) on the command line are (in part):
+
+
+ load <url> load the named image/table file
+ loadImage <url> load the named image
+ loadVOTable <url> load the named VOTable
+ loadFITS <url> load the named FITS bintable
+ showRow [<url>] <row> [tblId] highlight specified row
+ selectRows [<url>] <rows> [tblId] select specified rows
+ bibcode <bibcode> load the named bibcode
+
+ exec <cmd> execute a client command
+ pointAt <ra> <dec> point at given coords
+ setenv <name> <value> set an environment value
+ getenv <name> get an environment value
+ setparam <name> <value> set a parameter value
+ getparam <name> get a parameter value
+
+ send <mtype> [<args> ...] generalized <mtype> message send
+
+
+where "<url>" might be an actual HTTP reference, a local file path/name, or
+a 'file://' URI. The commands themselves are cases insensitive and the
+VOSAMP help page should be consulted for details on sending non-standard
+messages using the 'send' option for general messages (i.e. those messages
+that don't conform to an IVOA-supported 'mtype' but which might be used in
+a custom workflow). When VOSAMP is called using an API these commands are
+passed through the argument string an provide a trivial high-level method
+of sending SAMP messages without requiring the app to explicty connect to
+the Hub (receiving messages will still normally require the app to register
+itself in order to handle messages using the application's callbacks).
+
+ A "normal" SAMP-enabled application will establish a connection to the
+local desktop apps once and then process subsequent messages for the life
+of the application. In a CLI tool, this model introduces the overhead of
+the initial connection (several seconds) on each command, an effect which
+compounds when a CLI tool is used from within a script that might be
+processing many tens-to-thousands of messages as it is used in some
+user-defined workflow. To avoid this overhead, the VOSAMP task will
+default to become a bacakground 'proxy' service that lingers after the
+initial command is executed, i.e. in the same way a 'sudo' command won't
+require a password for each command for some time after the initial call,
+VOSAMP will background itself after the first command to maintain its
+connection to SAMP Hub, subsequent calls to VOSAMP will simply forward the
+command from the CLI to this proxy to make use of the existing SAMP
+connection and execute as quickly as any other persistant SAMP task.
+
+(*) SSA message data are not yet implemented.
+
+
+Inter-Desktop Messaging:
+
+ VOSAMP reads its command either from stdin, a named command file (e.g.
+as from a VOSAMP-shell interpreter), or from a socket created when the proxy
+process is created. This socket is created on an inet port that may be
+visible to the whole internet, or on a private port restricted by local
+system administrators to trusted clients (e.g. port 8080 if that is a
+general service provided by a site, or the default port 4000 for sites
+willing to open a firewall hole).
+
+ An example sequence of SAMP commands would be something like
+
+ % vosamp listClients
+ % vosamp loadVOTable foo.xml
+
+where the first command establishes a SAMP connection, and the second would
+forward the CLI command to the (already running) proxy client without
+establishing a new-application context.
+
+ In this model, a proxy VOSAMP app reading from an inet socket opens
+the possibility of using this proxy from a remote host that can send a
+command from a trusted machine. For example,
+
+ On host A:
+ % vosamp start # start proxy client on host A (140.252.1.86)
+
+ On host B:
+ % vosamp --proxy=140.252.1.86:4000 loadVOTable foo.xml
+
+where the '140.252.1.86' is the machine running the intial VOSAMP task,
+'4000' is the inet port that proxy is reading commands, and the remainder
+of the commandline are args to be passed thru as it they were issued from
+the local host. Local data (e.g. the 'foo.xml' file) is sent to the remote
+before executing the command, file:// URL's are rewritten so the file
+reference remains valid on the remote machine (http:// URLs are unchanged).
+
+
+SAMP Session Manager: (In development)
+
+ By using the proxy client, we can send commands to a VOSAMP application
+from a remote machine, but this is not quite the same as federating two (or
+more) desktops in a shared session. We are also limited by the ability to
+bypass firewalls in order to connect to the proxy client. The solution then
+is to have a public "session manager" service that serves as an alternate
+input source to the proxy client and will acto to forward message from one
+machine to the others. For example,
+
+ +-------------+
+ | Session Mgr |
+ +-------------+
+ ^
+ / \
+ / \
+ +-------------------------+ +-------------------------+
+ | Topcat \ | | / Topcat |
+ | Hub - VOSAMP | | VOSAMP - Hub |
+ | Aladin / | | \ IRAF |
+ +-------------------------+ +-------------------------+
+ Host A Host B
+
+Since the session manager is on a public host, the VOSAMP on each machine
+makes an outgoing client connection and sets up that socket to receive
+commands and subscribes to all message types so that SAMP messages received
+on the local machine can be forwarded back to the session manager and then
+on to other machines in the session. For example, the Aladin on Host A
+broadcasts an image.load.FITS message, the VOSAMP on Host forwards the
+message to the session manager than then passes it on to the VOSAMP on
+Host B for rebroadcast. In this way the message is seen on both desktops
+transparently. When local data is being used, this is uploaded to the
+session manager for storage in a web-accessible area, the forwarded message
+is then rewritten to use the URL and is accessed only when needed.
+
+ Sessions are created/joined with no special setup required, e.g.
+
+ % vosamp --session=foo e.g. commandline tool
+or
+ voc.vosamp ("session=foo") e.g. from language API
+
+The VOSAMP in this case would contact the session manager to join the list
+of machines in session 'foo', this session would be created if it did not
+already exist and sessions quietly end when the VOSAMP proxies timeout due
+to inactivity or are shut down explicitly. There is no need for formal
+security since it is up to the parties in the session to agree on and share
+the session name of their choosing. Applications written using the language
+bindings can participate in sessions by simply calling the VOSAMP task to
+create the proxy regardless of whether it is used explicitly for messaging.
+
+ If the VAO were to operate a public session manager service, it would
+trivial to log its use for reporting to the funding agencies, and would
+meet the mandate of VAO providing tools for community use. Details of
+the communication protocol could be written as an IVOA note to allow other
+implementations to make use of the service, or it could be formalized into
+a next version of the SAMP protocol itself.
+
+[Status: Proxy clients for use on the desktop and between trusted machines
+ is implemented, development of the session manager and extensions to
+ VOSAMP will be ready for demonstration at the Seattle meeting. (8/11/12)]
+
+
+
diff --git a/vendor/voclient/voapps/README.samp b/vendor/voclient/voapps/README.samp
new file mode 100644
index 00000000..326eccb0
--- /dev/null
+++ b/vendor/voclient/voapps/README.samp
@@ -0,0 +1,171 @@
+
+
+VOSAMP -- SAMP cmdline tool
+
+
+ Usage:
+
+ % vosamp [-hvd] [-t to] [-p pattern] [-f file] <cmd> [args ...]
+
+ where <cmd> command to process
+ -h print help summary
+ -v verbose output
+ -d debug output
+
+ -m handle multiple messages
+ -s <sender> handly only msgs from <sender>
+
+ -t <to> send to specified app (or all)
+ -p <pattern> message pattern: sync|async|notify
+ -f <file> send all commands in the file
+
+ Commands:
+
+ snoop print all received messages
+ send <mtype> [<args> ...] generalized <mtype> message send
+
+ status print Hub availability
+ list list all registered clients
+ access <appName> print <appName> availability
+ handle <mtype> wait for <mtype> message
+
+ exec <cmd> execute a client command
+ setenv <name> <value> set an environment value
+ getenv <name> get an environment value
+ setparam <name> <value> set a parameter value
+ getparam <name> get a parameter value
+
+ load <url> load the image/table
+ loadImage <url> load the named image
+ loadVOTable <url> load the named VOTable
+ loadFITS <url> load the named FITS bintable
+ loadSpec <url> load the named spectrum
+ loadResource <ivorn> load the named VO Resource
+
+ pointAt <ra> <dec> point at given coords
+ showRow [<url>] [<tblId>] <row> highlight specified row
+ selectRows [<url>] [<tblId>] <rows> select specified rows
+ bibcode <bibcode> load the bibcode
+
+
+==============================================================================
+
+
+VOSESSION -- Session manager for inter-desktop messaging
+
+ VOSAMP reads its command either from stdin, a named command file (e.g.
+as from a VOSAMP-shell interpreter), or from a socket created when the proxy
+process is created. This socket is created on an inet port that may be
+visible to the whole internet, or on a private port restricted by local
+system administrators to trusted clients (e.g. port 8080 if that is a
+general service provided by a site, or the default port 4000 for sites
+willing to open a firewall hole).
+
+ An example sequence of SAMP commands would be something like
+
+ % vosamp listClients
+ % vosamp loadVOTable foo.xml
+
+where the first command establishes a SAMP connection, and the second would
+forward the CLI command to the (already running) proxy client without
+establishing a new-application context.
+
+ In this model, a proxy VOSAMP app reading from an inet socket opens
+the possibility of using this proxy from a remote host that can send a
+command from a trusted machine. For example,
+
+ On host A:
+ % vosamp start # start proxy client on host A (140.252.1.86)
+
+ On host B:
+ % vosamp --proxy=140.252.1.86:4000 loadVOTable foo.xml
+
+where the '140.252.1.86' is the machine running the intial VOSAMP task,
+'4000' is the inet port that proxy is reading commands, and the remainder
+of the commandline are args to be passed thru as it they were issued from
+the local host. Local data (e.g. the 'foo.xml' file) is sent to the remote
+before executing the command, file:// URL's are rewritten so the file
+reference remains valid on the remote machine (http:// URLs are unchanged).
+
+
+SAMP Session Manager: (In development)
+
+ By using the proxy client, we can send commands to a VOSAMP application
+from a remote machine, but this is not quite the same as federating two (or
+more) desktops in a shared session. We are also limited by the ability to
+bypass firewalls in order to connect to the proxy client. The solution then
+is to have a public "session manager" service that serves as an alternate
+input source to the proxy client and will acto to forward message from one
+machine to the others. For example,
+
+ +-------------+
+ | Session Mgr |
+ +-------------+
+ ^
+ / \
+ / \
+ +-------------------------+ +-------------------------+
+ | Topcat \ | | / Topcat |
+ | Hub - VOSAMP | | VOSAMP - Hub |
+ | Aladin / | | \ IRAF |
+ +-------------------------+ +-------------------------+
+ Host A Host B
+
+Since the session manager is on a public host, the VOSAMP on each machine
+makes an outgoing client connection and sets up that socket to receive
+commands and subscribes to all message types so that SAMP messages received
+on the local machine can be forwarded back to the session manager and then
+on to other machines in the session. For example, the Aladin on Host A
+broadcasts an image.load.FITS message, the VOSAMP on Host forwards the
+message to the session manager than then passes it on to the VOSAMP on
+Host B for rebroadcast. In this way the message is seen on both desktops
+transparently. When local data is being used, this is uploaded to the
+session manager for storage in a web-accessible area, the forwarded message
+is then rewritten to use the URL and is accessed only when needed.
+
+ Sessions are created/joined with no special setup required, e.g.
+
+ % vosamp --session=foo e.g. commandline tool
+or
+ voc.vosamp ("session=foo") e.g. from language API
+
+The VOSAMP in this case would contact the session manager to join the list
+of machines in session 'foo', this session would be created if it did not
+already exist and sessions quietly end when the VOSAMP proxies timeout due
+to inactivity or are shut down explicitly. There is no need for formal
+security since it is up to the parties in the session to agree on and share
+the session name of their choosing. Applications written using the language
+bindings can participate in sessions by simply calling the VOSAMP task to
+create the proxy regardless of whether it is used explicitly for messaging.
+
+
+
+=============================================================================
+
+#define DEF_PORT 4433 /* Session Mgr contact port */
+
+#define MAX_SESSIONS 64 /* Max sessions to manage */
+#define MAX_CLIENTS 64 /* Max clients in each session */
+
+#define SZ_IPSTR 16 /* Size of an IP string */
+
+
+typedef struct {
+ int port; /* connection port */
+ char hostIP[SZ_IPSTR]; /* host IP address */
+} Client, *ClientP;
+
+
+typedef struct {
+ int nclients; /* number of clients */
+ Client *clients[MAX_CLIENTS]; /* clients in session */
+ char dataCache[SZ_LINE]; /* path to local data cache */
+} Session, *SessionP;
+
+
+#define CALLBACK 0 /* mgr sends callback port */
+#define QUIT 1 /* mgr sends disconnect/client retires */
+#define SEND 2 /* mgr/client forwards cmd */
+#define READY 3 /* mgr ready on port */
+
+
diff --git a/vendor/voclient/voapps/TODO b/vendor/voclient/voapps/TODO
new file mode 100644
index 00000000..d55c3f8c
--- /dev/null
+++ b/vendor/voclient/voapps/TODO
@@ -0,0 +1,4 @@
+
+ - test cases for all tasks
+ - VOTINFO should work on multi-RESOURCE VOTables 2/12/13
+ - VOTINFO should print <DESCRIPTION> indented properly
diff --git a/vendor/voclient/voapps/Tasks b/vendor/voclient/voapps/Tasks
new file mode 100644
index 00000000..37c35bb0
--- /dev/null
+++ b/vendor/voclient/voapps/Tasks
@@ -0,0 +1,59 @@
+
+
+VO Registry:
+ voregistry VO Resource discovery
+
+VO Data Access:
+ vodata Query and Access VO data
+ vocatalog Query VO catalog services
+ voimage Query VO image services
+* vospectrum Query VO spectrum services
+
+ voatlas Multi-wavelength atlas images
+* voobslog Query public observation logs
+ vosloanspec SDSS spectral data interface
+
+VOTable Tools
+* votcat Concatenate VOTable into a single multi-resource VOTable
+ votcnv Convert to/from votable format
+ votget Download data access references in a VOTable (w/ selection)
+ votinfo Print information about a votable
+* votjoin Perfom an inner-join between two VOTables
+ votpos Extract positional information from a VOTable
+* votselect Select rows from a table
+ votsort Sort a VOTable by a column
+* votsplit Split a multi-resource votable
+ votstat Compute statistics for numeric columns in a VOTable
+
+SAMP:
+ vosamp SAMP utility command (sessions, list clients, start hub, etc)
+
+Name Resolver:
+ vosesame Resolve object names to positions
+
+ * Will be in final v1.0 release, probably not in Aug test release
+
+
+
+===============================================================================
+== For later versions ==
+===============================================================================
+
+VOClientd C-based minimal implementation of VOClient Daeomon
+
+SAMP:
+ hub C implementation of SAMP Hub
+ samp_proxy Inter-machine SAMP proxy application
+
+Cross-Compare
+ voxmatch Cross-compare local table an VO data
+
+VOSpace:
+ vosput Put files to a VOSpace
+ vosget Get files from a VOSpace
+ vosmove Move files/nodes between VOSpaces
+ voslist List files/nodes in a VOSpace
+ vosdelete Delete files/nodes in a VOSpace
+
+Moving Targets:
+ skybot List known moving objects in an image
diff --git a/vendor/voclient/voapps/_examples b/vendor/voclient/voapps/_examples
new file mode 100644
index 00000000..dfffa465
--- /dev/null
+++ b/vendor/voclient/voapps/_examples
@@ -0,0 +1,41 @@
+
+VOSESAME
+ vosesame m31 # decimal output
+ vosesame -a m31 # print all info
+ vosesame -nd m31 # name/decimal
+ vosesame -dn m31 # decimal/name
+
+VOREGISTRY
+ voregistry -r gsc2.3 # resolve serviceURL
+ voregistry -R hst # expand resolution term
+ voregistry -t image -b x-ray any # search by constraint
+ voregistry -t image -b x-ray -v any
+ voregistry -t image -b x-ray -vv any
+
+ voregistry -list gsc2.3 # list "full" record
+ voregistry -meta gsc2.3 # list table metadata
+
+ voregistry cooling flow # keyword search
+ voregistry -vv cooling flow # very-verbose
+
+VODATA
+ vodata gsc2.3 ngc1234 # simplest query
+ vodata gsc2.3 /tmp/_abell.pos # multi-src file input (speed)
+ vodata -rm 10 gsc2.3 ngc1234 # alt SR spec
+ vodata -all hst ngc1234
+ vodata gsc2.3 ngc1234
+ vodata -t image -all hst ngc428 # all HST imgs of obj
+ # ....use of '-get'
+ vodata -c -t image noao IC10 # query all image resources
+ vodata -ep -eu -t image -all hst ngc4258 # ...plus extras
+ vodata -ep messier m1 180.0 # all-sky, extract pos file
+
+Combined/Misc
+ voregistry cooling flow # keyword search
+ vodata -O white97 -all J/MNRAS/292/419/ # get all tables in paper
+
+ vodata -q -O - http://iraf.net # cat URL
+
+ vodata -cq chandra -i - # interactive use
+
+
diff --git a/vendor/voclient/voapps/_vo-cli.demo b/vendor/voclient/voapps/_vo-cli.demo
new file mode 100644
index 00000000..60f19e51
--- /dev/null
+++ b/vendor/voclient/voapps/_vo-cli.demo
@@ -0,0 +1,44 @@
+VOSESAME
+ vosesame m31 # decimal output
+ vosesame -a m31 # print all info
+ vosesame -nd m31 # name/decimal
+ vosesame -dn m31 # decimal/name
+
+VOREGISTRY
+ voregistry -r gsc2.3 # resolve serviceURL
+ voregistry -R hst # expand resolution term
+ voregistry -t image -b x-ray any # search by constraint
+ voregistry -t image -b x-ray -v any
+ voregistry -t image -b x-ray -vv any
+
+ voregistry -list gsc2.3 # list "full" record
+ voregistry -meta gsc2.3 # list table metadata
+
+ voregistry cooling flow # keyword search
+ voregistry -vv cooling flow # very-verbose
+
+VODATA
+ vodata gsc2.3 ngc1234 # simplest query
+ vodata gsc2.3 /tmp/_abell.pos # multi-src file input (speed)
+ vodata -rm 10 gsc2.3 ngc1234 # alt SR spec
+ vodata -all hst ngc1234
+ vodata gsc2.3 ngc1234
+ vodata -t image -all hst ngc428 # all HST imgs of obj
+ # ....use of '-get'
+ vodata -c -t image noao IC10 # query all image resources
+ vodata -ep -eu -t image -all hst ngc4258 # ...plus extras
+ vodata -ep messier m1 180.0 # all-sky, extract pos file
+
+Combined/Misc
+ voregistry cooling flow # keyword search
+ vodata -O white97 -all J/MNRAS/292/419/ # get all tables in paper
+
+ vodata -q -O - http://iraf.net # cat URL
+
+ vodata -cq chandra -i - # interactive use
+
+Web-Page Interface
+
+GS Demo
+
+
diff --git a/vendor/voclient/voapps/_vo.cap b/vendor/voclient/voapps/_vo.cap
new file mode 100644
index 00000000..6e2da272
--- /dev/null
+++ b/vendor/voclient/voapps/_vo.cap
@@ -0,0 +1,90 @@
+
+
+ We didn't really get to it yesterday, but I wanted to start a
+discussion about what specific capabilities we might want to deliver by
+June. My understanding is that "immediately useful" has a very high
+priority, and a distribution of desktop tools serves a different audience
+than an API in any language.
+
+ This set of tools may be packaged and distributed differently
+than the API release but offers something people can immediate begin to
+play with, rather than tinkering with code to write their own (that will
+hopefully come later as well). Also, lots of astronomers will simply want
+FITS files or tables to appear to their machine, they may be turned off at
+the prospect of walking a votable themselves.
+
+ Given that starting position, I took a look at what's currently
+available/possible in VOClient and borrowed some ideas from the IRAF
+integration, and came up with about two dozen CLI tools that could
+realistically be delivered by a June review (assuming work is split up
+between core voclient dev and writing utilities from existing interfaces).
+These would be C tools, but the same functionality could be wrapped in
+an pythonic interface to provide similar high-level capabilities to
+programmers (or simply used to build some other VO tool in python).
+
+ This is just a first cut at such a list, but I think it would be
+pretty easy to write user-stories about how having these *capabilities* at
+the command-line or scripting environment could be used in a science
+workflow. I'd have to think some more about how these fit into the current
+ecosystem diagram. Comments?
+
+
+Cheers,
+-Mike
+
+-----------
+
+
+Registry:
+ vodirectory VO Resource discovery (keyword search, resolution, info)
+
+Data Access:
+ vodata Query and Access VO data (general engine)
+ vocatalog Query VO catalog services (SAMP load to overlay) (1
+ voimage Query VO image services (SAMP load to display) (1
+ vospectrum Query VO spectrum services (SAMP load) (1
+
+ dss Load DSS field in display (SAMP to ds9/aladin) (1
+ obslog Query public observation logs (1
+
+ Notes: do we need SED and/or Time Series access tools here?
+
+VOTable:
+ votcnv Convert to/from votable format
+ votget Download data access references in a VOTable (w/ selection)
+ votsplit Split a multi-resource votable (opt. output conversion) (2a
+ votjoin Join multiple votables into a multi-resource table (2a
+ votinfo Print information about a votable
+
+ Notes: similar tools for VOEvent packets could be written
+
+SAMP:
+ samp SAMP utility command (list clients, start hub, etc) (2a
+ send Send a SAMP message from the cmdline (2a
+ listener Listen for SAMP messages (2a
+
+ Notes: similar tools for VOEvent packets could be written
+
+Cross-Compare
+ voxmatch Cross-compare local table an VO data (3
+
+VOSpace:
+
+ vosput Put files to a VOSpace (4
+ vosget Get files from a VOSpace (4
+ vosmove Move files/nodes between VOSpaces (4
+ voslist List files/nodes in a VOSpace (4
+ vosdelete Delete files/nodes in a VOSpace (4
+
+Name Resolver:
+ sesame Resolve object names to positions
+
+Moving Targets:
+ skybot List known moving objects in an image (2b
+
+
+ Notes: 1) utility wrapper command around vodata
+ 2a) exists as simple demo currently and would need work,
+ 2b) could be written, doesn't currently exist
+ 3) would require work on SCC progrmmatic interface
+ 4) would require VOSpace implementation in voclient
diff --git a/vendor/voclient/voapps/_z b/vendor/voclient/voapps/_z
new file mode 100755
index 00000000..d041968c
--- /dev/null
+++ b/vendor/voclient/voapps/_z
@@ -0,0 +1,13 @@
+#!/bin/csh -fx
+
+./voatlas -b infrared -o img001.fits ngc4258
+./voatlas -p nvss -v -o img002.fits
+./voatlas -s 20m --survey=wise22 -o img003.fits m101
+./voatlas -n 256 --survey=sdssg -o img004.fits ngc4258
+#
+./voatlas -n 256 -p sdssg -o img005.fits ngc4258
+#
+./voatlas --band=infrared -o img006.fits ngc4258
+./voatlas --survey=nvss -v -o img007.fits
+./voatlas --size=20m --survey=wise22 -o img008.fits m101
+./voatlas --naxis=256 --survey=sdssg -o img009.fits ngc4258
diff --git a/vendor/voclient/voapps/data b/vendor/voclient/voapps/data
new file mode 120000
index 00000000..92e397c5
--- /dev/null
+++ b/vendor/voclient/voapps/data
@@ -0,0 +1 @@
+../test-data \ No newline at end of file
diff --git a/vendor/voclient/voapps/f77/README b/vendor/voclient/voapps/f77/README
new file mode 100644
index 00000000..0574b098
--- /dev/null
+++ b/vendor/voclient/voapps/f77/README
@@ -0,0 +1,9 @@
+
+ This directory contains tasks written or designed for use with
+Fortran. In some cases these will simply be example tasks to exercise
+or demonstrate the language support.
+
+
+Current Tasks include:
+
+ [None at this time]
diff --git a/vendor/voclient/voapps/generic.c b/vendor/voclient/voapps/generic.c
new file mode 100644
index 00000000..ddb86adf
--- /dev/null
+++ b/vendor/voclient/voapps/generic.c
@@ -0,0 +1,221 @@
+/*
+ * GENERIC -- Template file for VOApps task
+ *
+ * Usage:
+ * generic [<otps>] <votable>
+ *
+ * @file generic.c
+ * @author Mike Fitzpatrick
+ * @date 6/03/12
+ *
+ * @brief Template file for VOApps task.
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+
+#include "votParse.h" /* keep these in order! */
+#include "voApps.h"
+
+
+/* All tasks should support a "--return" flag if they can return a pointer
+ * to a result as part of the programmatic invocation. As a cmdline task
+ * 'reslen' and 'result' are ignored (actually, they're thrown away), but
+ * when called from an API the 'result' is a pointer to an arbitrary memory
+ * location that is passed back to the caller.
+ *
+ * The result object is defined by the task and can be anything. The
+ * '--return' flag can be defined to take an optional argument to specify
+ * which of multiple possible objects are returned (e.g. "--return=fits"
+ * "--return=votable") but the task is responsible for creating the object.
+ */
+static int do_return = 0; /* return result? */
+
+/* Global task declarations. These should all be defined as 'static' to
+ * avoid namespace collisions.
+ */
+static int foo = 0;
+
+
+/* A result buffer should be defined to point to the result object if it is
+ * created dynamically, e.g. a list of votable columns. The task is
+ * responsible for initially allocating this pointer and then resizing as
+ * needed.
+ */
+#define SZ_RESBUF 8192
+
+static char *resbuf;
+
+
+/* Task specific option declarations. Task options are declared using the
+ * getopt_long(3) syntax.
+ */
+static Task self = { "generic", generic, 0, 0, 0 };
+
+static char *opts = "%hno:r";
+static struct option long_opts[] = {
+ { "test", 2, 0, '%'}, /* --test is std */
+ { "help", 2, 0, 'h'}, /* --help is std */
+ { "number", 2, 0, 'n'}, /* opt w/ no arg */
+ { "output", 1, 0, 'o'}, /* opt w/ required arg */
+ { "return", 2, 0, 'r'}, /* --return is std */
+ { NULL, 0, 0, 0 }
+};
+
+
+/* All tasks should declare a static Usage() method to print the help
+ * text in response to a '-h' or '--help' flag. The help text should
+ * include a usage summary, a description of options, and some examples.
+ */
+static void Usage (void);
+static void Tests (char *input);
+
+
+/**
+ * Application entry point. All VOApps tasks MUST contain this
+ * method signature.
+ */
+int
+generic (int argc, char **argv, size_t *reslen, void **result)
+{
+ /* These declarations are required for the VOApps param interface.
+ */
+ char **pargv, optval[SZ_FNAME];
+
+ /* These declarations are specific to the task.
+ */
+ char *iname, *oname;
+ int ch = 0, status = OK, number = 0, pos = 0;
+ FILE *fd = (FILE *) NULL;
+
+
+ /* Initialize result object whether we return an object or not.
+ */
+ *reslen = 0;
+ *result = NULL;
+
+ /* Initialize local task values.
+ */
+ iname = NULL;
+ oname = NULL;
+
+
+ /* Parse the argument list. The use of vo_paramInit() is required to
+ * rewrite the argv[] strings in a way vo_paramNext() can be used to
+ * parse them. The programmatic interface allows "param=value" to
+ * be passed in, but the getopt_long() interface requires these to
+ * be written as "--param=value" so they are not confused with
+ * positional parameters (i.e. any param w/out a leading '-').
+ */
+ pargv = vo_paramInit (argc, argv, opts, long_opts);
+ while ((ch = vo_paramNext(opts,long_opts,argc,pargv,optval,&pos)) != 0) {
+ if (ch > 0) {
+ /* If the 'ch' value is > 0 we are parsing a single letter
+ * flag as defined in the 'opts string.
+ */
+ switch (ch) {
+ case '%': Tests (); return (self.nfail);
+ case 'h': Usage (); return (OK);
+ case 'n': number++; break;
+ case 'o': oname = strdup (optval); break;
+ case 'r': do_return=1; break;
+ default:
+ fprintf (stderr, "Invalid option '%s'\n", optval);
+ return (1);
+ }
+
+ } else if (ch == PARG_ERR) {
+ return (ERR);
+
+ } else {
+ /* This code processes the positional arguments. The 'optval'
+ * string contains the value but since this string is
+ * overwritten w/ each arch we need to make a copy (and must
+ * remember to free it later.
+ */
+ iname = strdup (optval);
+ break;
+ }
+ }
+
+
+ /* Sanity checks. Tasks should validate input and accept stdin/stdout
+ * where it makes sense.
+ */
+ if (iname == NULL) iname = strdup ("stdin");
+ if (oname == NULL) oname = strdup ("stdout");
+ if (strcmp (iname, "-") == 0) { free (iname), iname = strdup ("stdin"); }
+ if (strcmp (oname, "-") == 0) { free (oname), oname = strdup ("stdout"); }
+
+
+
+ /********
+ ********
+ ********
+ ********
+ ******** Main body of task
+ ********
+ ********
+ ********
+ *******/
+
+
+
+
+ /* Clean up. Rememebr to free whatever pointers were created when
+ * parsing arguments.
+ */
+ if (iname)
+ free (iname);
+ if (oname)
+ free (oname);
+
+ vo_paramFree (argc, pargv);
+
+ return (status); /* status must be OK or ERR (i.e. 0 or 1) */
+}
+
+
+/**
+ * USAGE -- Print task help summary.
+ */
+static void
+Usage (void)
+{
+ fprintf (stderr, "\n Usage:\n\t"
+ "generic [<opts>] votable.xml\n\n"
+ " where\n"
+ " -%%,--test run unit tests\n"
+ " -h,--help this message\n"
+ " -n,--number number output\n"
+ " -o,--output=<file> output file\n"
+ " -r,--return return result from method\n"
+ "\n"
+ " Examples:\n\n"
+ " 1) First example\n\n"
+ " %% generic test.xml\n"
+ " %% generic -n test.xml\n"
+ " %% cat test.xml | generic\n"
+ "\n"
+ " 2) Second example\n\n"
+ " %% generic -o pos.txt test.xml\n"
+ "\n"
+ );
+}
+
+
+/**
+ * Tests -- Task unit tests.
+ */
+static void
+Tests (char *input)
+{
+ /* First argument must always be the 'self' variable, the last must
+ * always be a NULL to terminate the cmd args.
+ */
+ vo_taskTest (self, "--help", NULL);
+}
+
diff --git a/vendor/voclient/voapps/lib/Makefile b/vendor/voclient/voapps/lib/Makefile
new file mode 100644
index 00000000..166d64b6
--- /dev/null
+++ b/vendor/voclient/voapps/lib/Makefile
@@ -0,0 +1,134 @@
+#///////////////////////////////////////////////////////////////////////////////
+#//
+#// Makefile for the VOClient Package Applications
+#//
+#///////////////////////////////////////////////////////////////////////////////
+
+# primary dependencies
+
+NAME = VOApps
+VERSION = 1.0
+PLATFORM := $(shell uname -s)
+PLMACH := $(shell uname -m)
+HERE := $(shell /bin/pwd)
+BINDIR := ../../bin/
+LIBDIR := ../../lib/
+INCDIR := ../../include/
+
+
+# secondary dependencies
+LIBBASE = ../lib$(NAME)
+STATICLIB = $(HERE)/$(LIBBASE).a
+SHAREDLIB = $(HERE)/$(LIBBASE).so.$(VERSION)
+
+
+# stuff that's precious to keep
+.PRECIOUS: $(STATICLIB) $(SHAREDLIB)
+.KEEP_STATE:
+
+
+# includes, flags and libraries
+CC = gcc
+CINCS = -I$(HERE) -I../ -I../../include -I../../../../include -L../../lib/
+
+
+ifeq ($(PLATFORM),Darwin)
+ ifeq ($(PLMACH),x86_64)
+ CARCH = -m64 -mmacosx-version-min=10.5
+ else
+ CARCH = -arch i386 -m32 -mmacosx-version-min=10.4
+ endif
+ ifdef IRAFARCH
+ ifeq ($(IRAFARCH),macintel)
+ CARCH = -m64 -mmacosx-version-min=10.5
+ else
+ CARCH = -arch i386 -m32 -mmacosx-version-min=10.5
+ endif
+ endif
+else
+ CLIBS = -lm -lc -lcurl -lpthread
+ CARCH =
+endif
+
+CLIBS = -lm -lc -lcurl -lpthread -lm
+CFLAGS = -g -Wall $(CARCH) -D$(PLATFORM) $(CINCS) -L./
+
+
+
+
+
+# list of source and include files
+
+SRCS = voObj.c voSvc.c voAclist.c voDALUtil.c voFITS.c voUtil.c \
+ voSCS.c voSIAP.c voSSAP.c voUtil.c voRanges.c voLog.c \
+ voKML.c voXML.c voHTML.c voTask.c voParams.c vosUtil.c
+OBJS = voObj.o voSvc.o voAclist.o voDALUtil.o voFITS.o voUtil.o \
+ voSCS.o voSIAP.o voSSAP.o voUtil.o voRanges.o voLog.o \
+ voKML.o voXML.o voHTML.o voTask.o voParams.o vosUtil.o
+INCS = ../voApps.h ../voAppsP.h
+
+
+all: lib
+
+install: all
+
+objs: $(OBJS)
+
+
+# Targets
+
+clean:
+ /bin/rm -rf .make.state .nse_depinfo *.[aeo] *.dSYM
+ /bin/rm -rf $(TARGETS)
+
+everything:
+ make clean
+ make all
+ make install
+
+help: HELP
+
+install: all
+
+
+
+####################################
+# LIBVOAPPS dependency libraries.
+####################################
+
+lib: objs
+ ar rv ../lib$(NAME).a $(OBJS)
+ $(RM) $(OBJS)
+
+
+
+###############################################################################
+# Unit test programs to be built.
+###############################################################################
+
+demo: $(TARGETS)
+
+zztest: zztest.c
+ $(CC) $(CFLAGS) -o zztest zztest.c $(LIBS)
+
+
+
+###############################################################################
+# Leave this stuff alone.
+###############################################################################
+
+$(STATICLIB): $(C_SRCS:%.c=Static/%.o)
+ /usr/bin/ar rv $@ $?
+Static/%.o: %.c $(C_INCS)
+ /usr/bin/gcc $(CINCS) $(CFLAGS) -c $< -o $@
+Static:
+ /bin/mkdir $@
+ chmod 777 $@
+
+$(SHAREDLIB): $(C_SRCS:%.c=Shared/%.o)
+ /usr/bin/ld -shared -o $@ $? -lc -ldl
+Shared/%.o: %.c $(C_INCS)
+ /usr/bin/gcc $(CINCS) $(CFLAGS) -fpic -shared -c $< -o $@
+Shared:
+ /bin/mkdir $@
+ chmod 777 $@
diff --git a/vendor/voclient/voapps/lib/proto b/vendor/voclient/voapps/lib/proto
new file mode 100644
index 00000000..4977acef
--- /dev/null
+++ b/vendor/voclient/voapps/lib/proto
@@ -0,0 +1,236 @@
+/**
+ * VOAPPPROTO.H -- VOApps prototype headers.
+ */
+
+
+/**
+ * VOACLIST.C -- Procedures for handling the AccessList of images/data
+ */
+void vot_addToAclist (char *url, char *outfile);
+void vot_freeAclist (void);
+void vot_procAclist (void);
+
+
+/**
+ * VODALUTIL.C -- Utility procedures for the DAL interface worker procedures.
+*/
+int vot_extractResults (char *result, char delim, svcParams *pars);
+char *vot_openExFile (svcParams *pars, int nrows, char *extn, FILE **ofd);
+char *vot_getOFName (svcParams *pars, char *extn, int pid);
+char *vot_getOFIndex (svcParams *pars, char *extn, int pid);
+int vot_countResults (char *result);
+void vot_dalExit (int code, int count);
+void vot_printHdr (int fd, svcParams *pars);
+void vot_printCountHdr (void);
+int vot_printCount (Query query, svcParams *pars, int *res_count);
+void vot_printCountLine (int nrec, svcParams *pars);
+
+char vot_svcTypeCode (int type);
+char *vot_getExtn (void);
+
+char *vot_procTimestamp (void);
+void vot_concat (void);
+
+
+/**
+ * VODALUTIL.C -- Utility procedures for the DAL interface worker procedures.
+ */
+void vot_initHTML (FILE *fd, svcParams *pars);
+void vot_printHTMLRow (FILE *fd, char *line, int isHdr, int rownum);
+void vot_closeHTML (FILE *fd);
+
+
+/**
+ * VOINV.C -- VOInventory service routines.
+ */
+char *vot_doInventory (void);
+char *vot_execInv (double ra, double dec, double radius, char *sources,
+ char *resources, char *id, char *rettype, FILE *outfile);
+
+
+/**
+ * VOKML.C -- Utility procedures for writing Google KML files.
+ */
+void vot_initKML (FILE *fd, svcParams *pars);
+void vot_printKMLPlacemark (FILE *fd, char *id, double ra, double dec,
+ char *line, char *acref, svcParams *pars);
+void vot_mkPlaceDescr (FILE *fd, char *line, char *acref, svcParams *pars);
+void vot_closeKML (FILE *fd);
+void vot_concatKML (char *fname);
+void vot_concatKMLByObject (FILE *fd);
+void vot_concatKMLByService (FILE *fd);
+char *vot_getSName (char *root);
+char *vot_getOName (char *root);
+int vot_copyKMLFile (char *root, char *name, FILE *fd);
+void vot_cleanKML (void);
+
+
+/**
+ * VOLOG.C -- VOApps logging interface.
+ */
+void vo_appLog (FILE *fd, char *format, ...);
+void vo_encodeString (char *buf, char *format, va_list *argp);
+char *vo_doarg (va_list **argp, int dtype);
+char *vo_logtime (void);
+
+
+/**
+ * VOARGS.C -- Procedures for commandline argument handling. We also do
+ */
+int vot_parseObjectList (char *list, int isCmdLine);
+void vot_freeObjectList (void);
+int vot_countObjectList (void);
+int vot_printObjectList (FILE *fd);
+void vot_readObjFile (char *fname);
+
+
+/**
+ * VOPARAMS.C -- Interface to manage cmdline options or library parameters.
+ */
+char **vo_paramInit (int argc, char *argv[]);
+int vo_paramNext (char *opts, struct option long_opts[], int argc,
+ char *argv[], char *optval, int *posindex);
+void vo_paramFree (int argc, char *argv[]);
+
+
+/**
+ * VORANGES -- Simple range-specification package to decode lists of numbers
+ * or ranges of the form:
+ */
+int vot_decodeRanges (range_string, ranges, max_ranges, nvalues);
+int get_next_number (int ranges[], int number);
+int is_in_range (int ranges[], int number);
+
+
+/**
+ * VOSCS.C -- Worker procedure to query a Simple Cone Search service.
+ */
+int vot_callConeSvc (svcParams *pars);
+
+
+/**
+ * VOSIAP.C -- Worker procedure to make a query to an SIAP service.
+ */
+int vot_callSiapSvc (svcParams *pars);
+char *vot_validateFile (char *fname);
+
+
+/**
+ * VOSSAP.C -- Worker procedure to make a query to an SSAP service.
+ */
+int vot_callSsapSvc (svcParams *pars);
+
+
+/**
+ * VOSVC.C -- Procedures for commandline argument and DAL service handling.
+ */
+int vot_parseServiceList (char *list, int dalOnly);
+void vot_freeServiceList (void);
+void vot_resetServiceCounters (void);
+void vot_addToSvcList (char *name, char *ident, char *url, char *type,
+ char *title);
+int vot_countServiceList (void);
+int vot_printServiceList (FILE *fd);
+int vot_printServiceVOTable (FILE *fd);
+void vot_readSvcFile (char *fname, int dalOnly);
+
+
+/**
+ * VOTASK.C -- Utilities to run a VOApps task as a connected subprocess.
+ */
+int vo_runTask (char *method, Task *apps, int argc, char **argv, size_t *len,
+ void **result);
+int vo_taskTest (Task self, char *arg, ...);
+
+int vo_setResultFromFile (char *fname, size_t *len, void **data);
+int vo_setResultFromInt (int value, size_t *len, void **data);
+int vo_setResultFromReal (float value, size_t *len, void **data);
+int vo_setResultFromString (char *str, size_t *len, void **data);
+
+
+/**
+ * VOUTIL.C -- Utility procedures for the VO-CLI tasks.
+ */
+int vot_regResolver (char *term, char *svctype, char *bpass, char *subject,
+ char *fields, int index, int exact, int dalOnly, char **res);
+int vot_regSearch (char **ids, int nids, char *svctype, char *bpass,
+ char *subject, int orValues, int votable, int dalOnly,
+ int sortRes, int terse);
+void pretty_print (char *result, int nresults);
+
+void ppResSummary (char *result, int nresults);
+void ppMultiLine (char *result, int poffset, int pwidth, int maxchars);
+
+void pretty_print_table (char *result, int nresults, char *fields);
+char *vot_parseSvcType (char *svctype, int exact);
+
+char *vot_parseBandpass (char *bpass);
+char *vot_parseSubject (char *subject);
+
+char *vot_urlFname (char *url);
+void vot_printAttrs (char *fname, Query query, char *ident);
+void vot_printRegVOTableHdr (FILE *fd);
+
+void vot_printRegVOTableRec (FILE *fd, RegResult resource, int recnum);
+void vot_printRegVOTableTail (FILE *fd);
+
+char *xmlEncode (char *in);
+char *vot_getline (FILE *fd);
+char *vot_normalizeCoord (char *coord);
+char *vot_normalize (char *str);
+
+int isVOTable (char *fname); /* utility functions */
+int isSexagesimal (char *str);
+int isDecimal (char *str);
+float sexa (char *s);
+char *toSexa (double pos);
+char *toSexaTime (int nsec);
+char *vot_mktemp (char *root);
+char *vot_copyStdin (void);
+void vot_skipHdr (FILE *fd);
+
+char *vot_getTableCol (char *line, int col, int span);
+int vot_isNumericField (handle_t field);
+int vot_fileType (char *fname);
+int vot_sum32 (char *str);
+int strdic (char *in_str, char *out_str, int maxchars, char *dict);
+
+
+/**
+** VOXML.C -- Utility procedures for writing XML files, i.e. the raw
+*/
+
+void vot_concatXML (char *fname);
+int vot_copyXMLFile (char *root, char *name, FILE *fd);
+void vot_cleanXML (void);
+
+
+/**
+ * VOSUTIL.C - Utility routines for the VOSAMP tools.
+ */
+int vos_urlType (char *url);
+char *vos_getFName (char *path);
+char *vos_typeName (int type);
+int vos_getURL (char *url, char *fname);
+char *vos_optArg (char *arg);
+char *vos_toURL (char *arg);
+int *vos_toIntArray (char *arg, int *nrows);
+
+int vos_openServerSocket (int port);
+int vos_openClientSocket (char *host, int port, int retry);
+int vos_testClientSocket (char *host, int port);
+int vos_sockReadHdr (int fd, int *len, char *name, int *type, int *mode);
+int vos_sockWriteHdr (int fd, int len, char *name, int type, int mode,
+ char *to);
+void vos_sockPrintHdr (char *msg, int fd);
+int vos_sockRead (int fd, void *vptr, int nbytes);
+int vos_sockWrite (int fd, void *vptr, int nbytes);
+int vos_fileRead (int fd, void *vptr, int nbytes);
+int vos_fileWrite (int fd, void *vptr, int nbytes);
+void vos_setNonBlock (int sock);
+char *vos_getLocalIP (void);
+
+struct hostent *vos_getHostByName (char *name);
+struct hostent *vos_dupHostent (struct hostent *hentry);
+
+int vos_strsub (char *in, char *from, char *to, char *outstr, int maxch);
diff --git a/vendor/voclient/voapps/lib/voAclist.c b/vendor/voclient/voapps/lib/voAclist.c
new file mode 100644
index 00000000..de63c6f8
--- /dev/null
+++ b/vendor/voclient/voapps/lib/voAclist.c
@@ -0,0 +1,299 @@
+/************************************************************************
+** VOACLIST.C -- Procedures for handling the AccessList of images/data
+** to be downloaded.
+**
+** M. Fitzpatrick, NOAO, July 2007
+*/
+
+#include <pthread.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <sys/ipc.h>
+#include <sys/sem.h>
+#include "VOClient.h"
+#include "voAppsP.h"
+
+
+/* Local processing definitions.
+*/
+
+extern Acref *acList, *acTail; /* Access reference linked list */
+extern int nacrefs; /* number of access refs */
+extern int file_get; /* number of files to get */
+extern time_t as_time, ae_time; /* processing times */
+
+extern int debug, verbose, quiet;
+extern int max_download;
+extern char *output;
+extern int errno; /* system error code */
+
+extern Range fileRange; /* download file range list */
+
+extern char *vot_validateFile (char *fname);
+extern char *vot_urlFname (char *url);
+
+
+/* Local task prototypes.
+*/
+void vot_addToAclist (char *url, char *fname);
+void vot_freeAclist (void);
+void vot_procAclist (void);
+
+static pid_t vot_dlProc (Acref *ac, int filenum);
+static int vot_acGetURL (char *url, char *fname, long *size);
+
+
+
+/************************************************************************
+** VOT_ADDTOACLIST -- Add the given url/id to the file access list.
+*/
+void
+vot_addToAclist (char *url, char *outfile)
+{
+ Acref *new = calloc (1, sizeof (Acref));
+
+ bzero (new->url, SZ_LINE);
+ bzero (new->fname, SZ_FNAME);
+
+ strncpy (new->url, url, strlen (url));
+ if (outfile)
+ strncpy (new->fname, outfile, strlen (outfile));
+ new->index = nacrefs;
+
+ new->status = AC_PENDING;
+ if (!acList) {
+ acList = acTail = new;
+
+ } else {
+ acTail->next = new;
+ acTail = new;
+ }
+ nacrefs++;
+}
+
+
+/************************************************************************
+** VOT_FREEACLIST -- Free the Aclist structure and reset the counter.
+*/
+void
+vot_freeAclist ()
+{
+ register int i;
+ Acref *cur, *next;
+
+
+ cur = acList;
+ for (i=0; i < nacrefs; i++) {
+ next = cur->next;
+ if (cur)
+ free ((void *)cur);
+ cur = next;
+ }
+
+ nacrefs = 0;
+ acList = acTail = (Acref *) NULL;
+}
+
+
+/************************************************************************
+** VOT_PROCACLIST -- Begin processing the access list. We do this by
+** spawning up to MAX_DOWNLOADS procs to download the references in
+** parallel.
+*/
+void
+vot_procAclist (void)
+{
+ int nthreads, nfile, nrunning, nremaining;
+ pid_t pid, rc, status;
+ Acref *ac = acList;
+
+
+ /* Initialize.
+ */
+ nthreads = (nacrefs > max_download) ? max_download : nacrefs;
+ nrunning = 0;
+ nremaining = nacrefs;
+
+ as_time = time ((time_t) NULL); /* get start time */
+
+
+ if (verbose && !quiet)
+ printf ("\n# Beginning download of %d files....\n", nacrefs);
+
+ for (nfile=1; nremaining > 0;) {
+
+ /* Spawn a process thread for each access reference.
+ */
+ if (nrunning < nthreads && nfile <= nacrefs) {
+
+ if (debug)
+ fprintf (stderr, "Starting download for '%s'\n", ac->url);
+
+ if ((pid = vot_dlProc (ac, nfile)) < 0) {
+ fprintf (stderr, "ERROR: process fork() fails\n");
+ exit (-1);
+ }
+ nrunning++;
+ nfile++;
+
+ if (ac)
+ ac = ac->next;
+
+ } else {
+ /* All processes running, wait for one to finish.
+ */
+ if (debug)
+ fprintf (stderr, "Waiting on download\n");
+
+ if ((rc = waitpid ((pid_t)-1, &status, (int) 0)) < 0) {
+ fprintf (stderr, "ERROR: aclist waitpid() fails, code: %d\n",
+ (int)rc);
+ exit (-1);
+ }
+ status = WEXITSTATUS(status);
+
+ nrunning--;
+ nremaining--;
+ }
+ }
+
+ if (verbose && !quiet)
+ printf ("#\n# Downloads complete.\n");
+
+
+ ae_time = time ((time_t) NULL); /* get end time */
+
+ return;
+}
+
+
+/************************************************************************
+** VOT_DLPROC -- Procedure used to spawn a download child process. We
+** return the child pid, and fork off the actual download. The caller
+** will wait for completion.
+*/
+static pid_t
+vot_dlProc (Acref *ac, int filenum)
+{
+ pid_t cpid;
+ int nerrs = 0;
+ long nbytes = 0;
+ char *urlFname, *out, svc[SZ_FNAME], idx[10], fname[SZ_FNAME];
+
+
+ if (debug)
+ fprintf (stderr, "vot_dlProc(%d): %s\n", filenum, ac->url);
+
+ if ((cpid = fork()) < 0) {
+ fprintf (stderr,
+ "vot_dlProc: Unable to create child process, exiting\n");
+ exit (-1);
+
+ } else if (cpid > 0) {
+ return (cpid); /* parent */
+
+ } else { /* child */
+ /* Initialize the VOClient code. Error messages are printed by the
+ ** interface so we just quit if there is a problem.
+ */
+ if (voc_initVOClient ((char *) NULL) == ERR)
+ exit (1);
+
+ bzero (idx, 10);
+ bzero (svc, SZ_FNAME);
+ if (ac->fname[0]) {
+ char *ip, *op;
+
+ strcpy (fname, ac->fname);
+ for (ip=fname,op=svc; *ip && *ip != '.'; )
+ *op++ = *ip++;
+ ip++;
+ if (isdigit(*ip))
+ strcpy (idx, ip);
+ else
+ strcpy (idx, "001");
+ } else {
+ bzero (fname, SZ_FNAME);
+ sprintf (fname, "%s%03d", (output ? output : "file"), filenum);
+ strcpy (svc, "file");
+ sprintf (idx, "%03d", filenum);
+ }
+
+ urlFname = vot_urlFname(ac->url);
+ if (verbose) {
+ if (strcmp (idx, "001") == 0 && !quiet)
+ fprintf (stderr, "#\n# Downloading URLs from service: %s...\n",
+ svc);
+ if (!quiet)
+ fprintf (stderr, "# File %s...", idx);
+ }
+
+ nerrs = vot_acGetURL (ac->url, fname, &nbytes);
+
+ out = vot_validateFile (fname);
+
+ if (verbose && !quiet && !nerrs)
+ fprintf (stderr, " (%ld bytes) file: %s\n", nbytes, out);
+
+ strcpy (ac->fname, fname);
+ ac->nbytes = nbytes;
+ ac->status = (nerrs ? AC_ERROR : AC_COMPLETE);
+
+ voc_closeVOClient (0); /* close VOClient connection */
+ }
+
+ exit (0);
+}
+
+
+/************************************************************************
+** Download a raw URL to the named file.
+*/
+
+static int
+vot_acGetURL (char *url, char *fname, long *size)
+{
+ int fd, nbytes, err = 0;
+ char *res;
+ extern char *output;
+
+
+ if ((res = voc_getRawURL (url, &nbytes)) == NULL) {
+ fprintf (stderr, "Cannot access URL\n");
+ err++;
+ } else {
+ if (output && output[0] == '-') /* use stdout */
+ fd = fileno(stdout);
+ else {
+ if (access (fname, R_OK|W_OK) == 0) /* overwrite */
+ unlink (fname);
+
+ /* Open the file.
+ */
+ if ((fd = open (fname, O_RDWR|O_CREAT, 0644)) < 0) {
+ fprintf (stderr, "Cannot open file '%s'\n",
+ fname);
+ err++;
+ }
+ }
+
+ /* Write the (binary) result string to the file.
+ */
+ if (write (fd, res, nbytes) != nbytes) {
+ fprintf (stderr, "Short file write\n");
+ err++;
+ }
+
+ if (fd != fileno(stdout)) /* close if not stdout */
+ close (fd);
+ }
+
+ if (res)
+ free ((char *) res);
+
+ *size = nbytes; /* return the size */
+ return (err);
+}
diff --git a/vendor/voclient/voapps/lib/voAppProto.h b/vendor/voclient/voapps/lib/voAppProto.h
new file mode 100644
index 00000000..7114afda
--- /dev/null
+++ b/vendor/voclient/voapps/lib/voAppProto.h
@@ -0,0 +1,238 @@
+/**
+ * VOAPPPROTO.H -- VOApps prototype headers.
+ */
+
+
+/**
+ * VOACLIST.C -- Procedures for handling the AccessList of images/data
+ */
+void vot_addToAclist (char *url, char *outfile);
+void vot_freeAclist (void);
+void vot_procAclist (void);
+
+
+/**
+ * VODALUTIL.C -- Utility procedures for the DAL interface worker procedures.
+*/
+int vot_extractResults (char *result, char delim, svcParams *pars);
+char *vot_openExFile (svcParams *pars, int nrows, char *extn, FILE **ofd);
+char *vot_getOFName (svcParams *pars, char *extn, int pid);
+char *vot_getOFIndex (svcParams *pars, char *extn, int pid);
+int vot_countResults (char *result);
+void vot_dalExit (int code, int count);
+void vot_printHdr (int fd, svcParams *pars);
+void vot_printCountHdr (void);
+int vot_printCount (Query query, svcParams *pars, int *res_count);
+void vot_printCountLine (int nrec, svcParams *pars);
+
+char vot_svcTypeCode (int type);
+char *vot_getExtn (void);
+
+char *vot_procTimestamp (void);
+void vot_concat (void);
+
+
+/**
+ * VODALUTIL.C -- Utility procedures for the DAL interface worker procedures.
+ */
+void vot_initHTML (FILE *fd, svcParams *pars);
+void vot_printHTMLRow (FILE *fd, char *line, int isHdr, int rownum);
+void vot_closeHTML (FILE *fd);
+
+
+/**
+ * VOINV.C -- VOInventory service routines.
+ */
+char *vot_doInventory (void);
+char *vot_execInv (double ra, double dec, double radius, char *sources,
+ char *resources, char *id, char *rettype, FILE *outfile);
+
+
+/**
+ * VOKML.C -- Utility procedures for writing Google KML files.
+ */
+void vot_initKML (FILE *fd, svcParams *pars);
+void vot_printKMLPlacemark (FILE *fd, char *id, double ra, double dec,
+ char *line, char *acref, svcParams *pars);
+void vot_mkPlaceDescr (FILE *fd, char *line, char *acref, svcParams *pars);
+void vot_closeKML (FILE *fd);
+void vot_concatKML (char *fname);
+void vot_concatKMLByObject (FILE *fd);
+void vot_concatKMLByService (FILE *fd);
+char *vot_getSName (char *root);
+char *vot_getOName (char *root);
+int vot_copyKMLFile (char *root, char *name, FILE *fd);
+void vot_cleanKML (void);
+
+
+/**
+ * VOLOG.C -- VOApps logging interface.
+ */
+void vo_appLog (FILE *fd, char *format, ...);
+void vo_encodeString (char *buf, char *format, va_list *argp);
+char *vo_doarg (va_list **argp, int dtype);
+char *vo_logtime (void);
+
+
+/**
+ * VOARGS.C -- Procedures for commandline argument handling. We also do
+ */
+int vot_parseObjectList (char *list, int isCmdLine);
+void vot_freeObjectList (void);
+int vot_countObjectList (void);
+int vot_printObjectList (FILE *fd);
+void vot_readObjFile (char *fname);
+
+
+/**
+ * VOPARAMS.C -- Interface to manage cmdline options or library parameters.
+ */
+char **vo_paramInit (int argc, char *argv[]);
+int vo_paramNext (char *opts, struct option long_opts[], int argc,
+ char *argv[], char *optval, int *posindex);
+void vo_paramFree (int argc, char *argv[]);
+
+
+/**
+ * VORANGES -- Simple range-specification package to decode lists of numbers
+ * or ranges of the form:
+ */
+int vot_decodeRanges (range_string, ranges, max_ranges, nvalues);
+int get_next_number (int ranges[], int number);
+int is_in_range (int ranges[], int number);
+
+
+/**
+ * VOSCS.C -- Worker procedure to query a Simple Cone Search service.
+ */
+int vot_callConeSvc (svcParams *pars);
+
+
+/**
+ * VOSIAP.C -- Worker procedure to make a query to an SIAP service.
+ */
+int vot_callSiapSvc (svcParams *pars);
+char *vot_validateFile (char *fname);
+
+
+/**
+ * VOSSAP.C -- Worker procedure to make a query to an SSAP service.
+ */
+int vot_callSsapSvc (svcParams *pars);
+
+
+/**
+ * VOSVC.C -- Procedures for commandline argument and DAL service handling.
+ */
+int vot_parseServiceList (char *list, int dalOnly);
+void vot_freeServiceList (void);
+void vot_resetServiceCounters (void);
+void vot_addToSvcList (char *name, char *ident, char *url, char *type,
+ char *title);
+int vot_countServiceList (void);
+int vot_printServiceList (FILE *fd);
+int vot_printServiceVOTable (FILE *fd);
+void vot_readSvcFile (char *fname, int dalOnly);
+
+
+/**
+ * VOTASK.C -- Utilities to run a VOApps task as a connected subprocess.
+ */
+int vo_runTask (char *method, Task *apps, int argc, char **argv, size_t *len,
+ void **result);
+int vo_taskTest (Task self, char *arg, ...);
+
+int vo_setResultFromFile (char *fname, size_t *len, void **data);
+int vo_setResultFromInt (int value, size_t *len, void **data);
+int vo_setResultFromReal (float value, size_t *len, void **data);
+int vo_setResultFromString (char *str, size_t *len, void **data);
+
+
+/**
+ * VOUTIL.C -- Utility procedures for the VO-CLI tasks.
+ */
+int vot_regResolver (char *term, char *svctype, char *bpass, char *subject,
+ char *fields, int index, int exact, int dalOnly, char **res);
+int vot_regSearch (char **ids, int nids, char *svctype, char *bpass,
+ char *subject, int orValues, int votable, FILE *vot_fd,
+ int dalOnly, int sortRes, int terse);
+void pretty_print (char *result, int nresults);
+
+void ppResSummary (char *result, int nresults);
+void ppMultiLine (char *result, int poffset, int pwidth, int maxchars);
+
+void pretty_print_table (char *result, int nresults, char *fields);
+char *vot_parseSvcType (char *svctype, int exact);
+
+char *vot_parseBandpass (char *bpass);
+char *vot_parseSubject (char *subject);
+
+char *vot_urlFname (char *url);
+void vot_printAttrs (char *fname, Query query, char *ident);
+void vot_printRegVOTableHdr (FILE *fd);
+
+void vot_printRegVOTableRec (FILE *fd, RegResult resource, int recnum);
+void vot_printRegVOTableTail (FILE *fd);
+
+char *xmlEncode (char *in);
+char *vot_getline (FILE *fd);
+char *vot_normalizeCoord (char *coord);
+char *vot_normalize (char *str);
+char *vot_toURL (char *arg);
+void vot_setArg (char **argv, int *argc, char *value);
+
+int isVOTable (char *fname); /* utility functions */
+int isSexagesimal (char *str);
+int isDecimal (char *str);
+float sexa (char *s);
+char *toSexa (double pos);
+char *toSexaTime (int nsec);
+char *vot_mktemp (char *root);
+char *vot_copyStdin (void);
+void vot_skipHdr (FILE *fd);
+
+char *vot_getTableCol (char *line, int col, int span);
+int vot_isNumericField (handle_t field);
+int vot_fileType (char *fname);
+int vot_sum32 (char *str);
+int strdic (char *in_str, char *out_str, int maxchars, char *dict);
+
+
+/**
+** VOXML.C -- Utility procedures for writing XML files, i.e. the raw
+*/
+
+void vot_concatXML (char *fname);
+int vot_copyXMLFile (char *root, char *name, FILE *fd);
+void vot_cleanXML (void);
+
+
+/**
+ * VOSUTIL.C - Utility routines for the VOSAMP tools.
+ */
+int vos_urlType (char *url);
+char *vos_getFName (char *path);
+char *vos_typeName (int type);
+int vos_getURL (char *url, char *fname);
+char *vos_optArg (char *arg);
+char *vos_toURL (char *arg);
+int *vos_toIntArray (char *arg, int *nrows);
+
+int vos_openServerSocket (int port);
+int vos_openClientSocket (char *host, int port, int retry);
+int vos_testClientSocket (char *host, int port);
+int vos_sockReadHdr (int fd, int *len, char *name, int *type, int *mode);
+int vos_sockWriteHdr (int fd, int len, char *name, int type, int mode,
+ char *to);
+void vos_sockPrintHdr (char *msg, int fd);
+int vos_sockRead (int fd, void *vptr, int nbytes);
+int vos_sockWrite (int fd, void *vptr, int nbytes);
+int vos_fileRead (int fd, void *vptr, int nbytes);
+int vos_fileWrite (int fd, void *vptr, int nbytes);
+void vos_setNonBlock (int sock);
+char *vos_getLocalIP (void);
+
+struct hostent *vos_getHostByName (char *name);
+struct hostent *vos_dupHostent (struct hostent *hentry);
+
+int vos_strsub (char *in, char *from, char *to, char *outstr, int maxch);
diff --git a/vendor/voclient/voapps/lib/voApps_f77.c b/vendor/voclient/voapps/lib/voApps_f77.c
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/vendor/voclient/voapps/lib/voApps_f77.c
diff --git a/vendor/voclient/voapps/lib/voApps_spp.c b/vendor/voclient/voapps/lib/voApps_spp.c
new file mode 100644
index 00000000..568cd97f
--- /dev/null
+++ b/vendor/voclient/voapps/lib/voApps_spp.c
@@ -0,0 +1,271 @@
+/**
+ * VOTAPP_SPP.C -- SPP Interface routines to applications code.
+ *
+ * @file votApp_spp.c
+ * @author Mike Fitzpatrick
+ * @date 6/03/11
+ *
+ * @brief SPP Interface routines to applications code.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+#include <unistd.h>
+#include <ctype.h>
+#include <errno.h>
+
+/*
+#include "votParseP.h"
+*/
+#include "votParse.h"
+
+
+/* SPP Type definitions.
+*/
+#define XCHAR short
+#define PKCHAR char
+#define XINT int
+#define XEOS 0
+
+
+/* SPP Interface Definitions.
+ *
+ * SPP compilers on various platforms may append one or more trailing
+ * underscores to symbol names, we'll use macros for the interface names
+ * and use defines to see what the symbol name is.
+*/
+#ifdef _NO_US_
+
+#define VX_VODATA vxvoda
+#define VX_VODIRECTORY vxvody
+#define VX_VODSS vxvods
+#define VX_VOSESAME vxvose
+
+#define VX_VOCOPY vxvocy
+#define VX_VOGET vxvogt
+#define VX_VOINFO vxvoio
+
+#else
+
+#define VX_VODATA vxvoda_
+#define VX_VODIRECTORY vxvody_
+#define VX_VODSS vxvods_
+#define VX_VOSESAME vxvose_
+
+#define VX_VOCOPY vxvocy_
+#define VX_VOGET vxvogt_
+#define VX_VOINFO vxvoio_
+
+#endif
+
+typedef void (*PFV)();
+typedef int (*PFI)();
+
+
+
+/**
+ * Local interface declarations.
+ */
+static PKCHAR *spp2c (XCHAR *instr, int maxch);
+static int spplen (XCHAR *str);
+static void func_exec (PFV func, char *name, int *argc, XCHAR *firstArg,
+ va_list argp);
+
+
+
+/*****************************************************************************
+ * Application Interfaces
+ ****************************************************************************/
+
+#define MAX_ARGS 64
+
+void vodata (int argc, char **argv);
+void vodirectory (int argc, char **argv);
+void vodss (int argc, char **argv);
+void vosesame (int argc, char **argv);
+
+void votcopy (int argc, char **argv);
+void votget (int argc, char **argv);
+void votinfo (int argc, char **argv);
+
+void voc_debug (void);
+
+
+
+/**
+ * FUNC_EXEC -- Execute a VOClient function from the SPP binding.
+ */
+static void
+func_exec (PFV func, char *name, int *argc, XCHAR *firstArg, va_list argp)
+{
+ int i, _argc = *argc;
+ char *_argv[MAX_ARGS];
+ XCHAR *arg;
+
+ if (firstArg == NULL) /* must pass in at least one arg */
+ return;
+
+
+ /* Process the argument list.
+ */
+ _argc = *argc + 1;
+ _argv[0] = strdup (name);
+ _argv[1] = spp2c (firstArg, spplen (firstArg));
+
+ for (i=2; i < _argc && (arg=(XCHAR *)va_arg(argp,XCHAR *)) != NULL; i++)
+ if (arg)
+ _argv[i] = spp2c (arg, spplen (arg));
+
+ /* Debug output.
+ */
+ if (access ("/tmp/VOC_DEBUG", F_OK) == 0) {
+ for (i=0; i < _argc; i++)
+ fprintf (stderr, "%s ", _argv[i]);
+ fprintf (stderr, "\n");
+ }
+
+
+ (*func) (_argc, _argv); /* call the task */
+
+ for (i=0; i < *argc; i++) /* free the arg pointers */
+ if (_argv[i])
+ free ((char *) _argv[i]);
+
+ return;
+}
+
+
+/****************************************************************************
+ * Task wrappers
+ ****************************************************************************/
+
+/**
+ * VX_VOCOPY -- Application interface to the VOCOPY task.
+ */
+void VX_VOCOPY (int *argc, XCHAR *firstArg, ...)
+{
+ va_list argp;
+
+ va_start (argp, firstArg);
+ func_exec (votcopy, "votcopy", argc, firstArg, argp);
+ va_end (argp);
+}
+
+
+/**
+ * VX_VODATA -- Application interface to the VODATA task.
+ */
+void VX_VODATA (int *argc, XCHAR *firstArg, ...)
+{
+ va_list argp;
+
+ va_start (argp, firstArg);
+ func_exec (vodata, "vodata", argc, firstArg, argp);
+ va_end (argp);
+}
+
+
+/**
+ * VX_VODIRECTORY -- Application interface to the VODIRECTORY task.
+ */
+void VX_VODIRECTORY (int *argc, XCHAR *firstArg, ...)
+{
+ va_list argp;
+
+ va_start (argp, firstArg);
+ func_exec (vodirectory, "vodirectory", argc, firstArg, argp);
+ va_end (argp);
+}
+
+
+/**
+ * VX_VODSS -- Application interface to the VODSS task.
+ */
+void VX_VODSS (int *argc, XCHAR *firstArg, ...)
+{
+ va_list argp;
+
+ va_start (argp, firstArg);
+ func_exec (vodss, "vodss", argc, firstArg, argp);
+ va_end (argp);
+}
+
+
+/**
+ * VX_VOGET -- Application interface to the VOGET task.
+ */
+void VX_VOGET (int *argc, XCHAR *firstArg, ...)
+{
+ va_list argp;
+
+ va_start (argp, firstArg);
+ func_exec (votget, "votget", argc, firstArg, argp);
+ va_end (argp);
+}
+
+/**
+ * VX_VOINFO -- Application interface to the VOTINFO task.
+ */
+void VX_VOINFO (int *argc, XCHAR *firstArg, ...)
+{
+ va_list argp;
+
+ va_start (argp, firstArg);
+ func_exec (votinfo, "votinfo", argc, firstArg, argp);
+ va_end (argp);
+}
+
+
+/**
+ * VX_VOSESAME -- Application interface to the VOSESAME task.
+ */
+void VX_VOSESAME (int *argc, XCHAR *firstArg, ...)
+{
+ va_list argp;
+
+ va_start (argp, firstArg);
+ func_exec (vosesame, "vosesame", argc, firstArg, argp);
+ va_end (argp);
+}
+
+
+
+/****************************************************************************
+ * Private utility procedures
+ ****************************************************************************/
+
+/**
+ * SPP2C -- Convert an SPP string to a host C string.
+ */
+static char *
+spp2c (XCHAR *instr, int maxch)
+{
+ XCHAR *ip = instr;
+ char *outstr = (char *) calloc (1, maxch+1);
+ char *op = (char *) outstr;
+ int n = maxch;
+
+ while ((*op++ = (char)*ip++) != (char)XEOS && --n >= 0)
+ ;
+ *--op = (char) XEOS;
+
+ return (outstr);
+}
+
+
+/**
+ * SPPLEN -- Get the length of an SPP string.
+ */
+static int
+spplen (XCHAR *str)
+{
+ int len = 0;
+
+ for (len=0; str[len] != (XCHAR) XEOS; len++)
+ ;
+ return (len);
+}
+
+void voc_debug () { int junk; junk = 1; }
diff --git a/vendor/voclient/voapps/lib/voDALUtil.c b/vendor/voclient/voapps/lib/voDALUtil.c
new file mode 100644
index 00000000..f02ffda1
--- /dev/null
+++ b/vendor/voclient/voapps/lib/voDALUtil.c
@@ -0,0 +1,839 @@
+/************************************************************************
+** VODALUTIL.C -- Utility procedures for the DAL interface worker
+** procedures.
+**
+** M. Fitzpatrick, NOAO, July 2007
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/ipc.h>
+#include <sys/sem.h>
+#include <time.h>
+#include <pthread.h>
+#include "VOClient.h"
+#include "voAppsP.h"
+
+
+extern int errno, nservices, nobjects, quiet, format, simple_out, numout;
+extern int debug, verbose, all_named, all_data, save_res, extract;
+extern int meta, dverbose, count, count_only, file_get, use_name;
+extern int kml_max, kml_sample, kml_region, kml_label;
+extern char *output;
+
+extern Service *svcList;
+extern Object *objList;
+
+extern char *vot_getSName (char *root);
+extern char *vot_getOName (char *root);
+
+
+
+int vot_extractResults (char *result, char delim, svcParams *pars);
+int vot_printCount (Query query, svcParams *pars, int *count);
+char vot_svcTypeCode (int type);
+char *vot_getOFName (svcParams *pars, char *extn, int pid);
+char *vot_getOFIndex (svcParams *pars, char *extn, int pid);
+char *vot_openExFile (svcParams *pars, int nrows, char *extn, FILE **ofd);
+char *vot_procTimestamp (void);
+char *vot_getExtn (void);
+void vot_printCountHdr (void);
+void vot_printCountLine (int nrec, svcParams *pars);
+void vot_dalExit (int code, int count);
+void vot_printHdr (int fd, svcParams *pars);
+void vot_concat ();
+
+static void vot_clean (char *extn);
+static int vot_copyFile (char *root, char *extn, char *name,
+ FILE *fd, int hdr, int nrows);
+
+extern char *vot_normalize (char *str);
+extern char *vot_normalizeCoord (char *str);
+
+extern void vot_initKML (FILE *fd, svcParams *pars);
+extern void vot_printKMLPlacemark (FILE *fd, char *id,
+ double ra, double dec, char *line, char *acref,
+ svcParams *pars);
+extern void vot_closeKML (FILE *fd);
+
+extern void vot_initHTML (FILE *fd, svcParams *pars);
+extern void vot_printHTMLRow (FILE *fd, char *line, int isHdr, int rnum);
+extern void vot_closeHTML (FILE *fd);
+
+
+
+
+
+/************************************************************************
+** VOC_EXTRACTRESULTS -- Extract the position and acref information from
+** a DAL query result. We use the first occurance of the POS_EQ_MAIN_<t>
+** UCDs for the position and either ID_MAIN or an artificial ID. Format
+** for the position file is fixed but may be generalized later to allow
+** the order/delimiter to be controlled by the user. The acref file
+** contains the contents of the VOX:Image_AccessReference element.
+*/
+int
+vot_extractResults (char *result, char delim, svcParams *pars)
+{
+ int id=-1, ra=-1, dec=-1, acref=-1, colnum, rownum, nrows, ncols, np, na;
+ char col[SZ_LINE], s_id[SZ_LINE], s_ra[SZ_LINE], s_dec[SZ_LINE];
+ char s_acref[SZ_URL], afname[SZ_LINE], pfname[SZ_LINE];
+ char hfname[SZ_LINE], kfname[SZ_LINE];
+ char *ip = result, *sres, *op, *lp;
+ char hline[SZ_RESULT], line[SZ_RESULT];
+ FILE *pfd = (FILE *)NULL;
+ FILE *afd = (FILE *)NULL;
+ FILE *kfd = (FILE *)NULL;
+ FILE *hfd = (FILE *)NULL;
+
+ static int row_count = 0;
+
+
+ if (!result)
+ vot_dalExit (E_NODATA, 0);
+
+
+ /* Skip leading whitespace
+ */
+ for (ip=result; isspace(*ip) || *ip == '\n'; ip++)
+ ;
+ sres = ip;
+
+ /* Count the number of result records, and skip the header line.
+ */
+ for (nrows=0, ip=sres; *ip; ip++) {
+ if (*ip == '\n')
+ nrows++;
+ }
+ if (nrows > 0)
+ nrows--;
+
+ if (nrows <= 0) {
+ if (debug)
+ fprintf (stderr, "WARNING: No Data found.\n");
+ return (0);
+ }
+
+ /* Return the row count only if we're not extracting anything.
+ */
+ if (!extract)
+ return (nrows);
+
+
+ /* Get the desired column indices.
+ */
+ ip = &result[1];
+ colnum = 0;
+ bzero ((lp = hline), SZ_RESULT);
+ while (1) {
+ bzero (col, SZ_LINE);
+ for (op=col; *ip && *ip != delim && *ip != '\n';)
+ *op++ = *lp++ = *ip++;
+
+ if ((*ip == delim && *(ip+1) == delim) || !col[0]) {/* no UCD */
+ colnum+=2;
+ ip += 2;
+ bzero (col, SZ_LINE);
+ continue;
+ }
+
+
+ if ((strcasecmp ("ID_MAIN", col) == 0) ||
+ (strcasecmp ("meta.id;meta.main", col) == 0))
+ id = colnum;
+ else if ((strcasecmp ("POS_EQ_RA_MAIN", col) == 0) ||
+ (strcasecmp ("pos.eq.ra;meta.main", col) == 0))
+ ra = colnum;
+ else if ((strcasecmp ("POS_EQ_DEC_MAIN", col) == 0) ||
+ (strcasecmp ("pos.eq.dec;meta.main", col) == 0))
+ dec = colnum;
+
+ else if (strcasecmp ("VOX:Image_AccessReference", col) == 0)
+ acref = colnum;
+ else if (strcasecmp ("meta.ref.url", col) == 0)
+ acref = colnum;
+ else if (strcasecmp ("DATA_LINK", col) == 0)
+ acref = colnum;
+
+ while (*ip == delim && *ip != '\n') /* Skip the delimiter. */
+ *lp++ = *ip++;
+
+ if (*ip == '\n') { /* Only process first line here */
+ *lp++ = *ip;
+ break;
+ }
+ colnum++;
+ }
+ ncols = colnum + 1;
+
+ if (debug) {
+ printf ("%s: %c id=%d ra=%d dec=%d acref=%d extract=%d (%d,%d)\n",
+ pars->name, vot_svcTypeCode(pars->type), id, ra, dec,
+ acref, extract, ncols, nrows);
+ }
+
+ /* Begin processing.
+ */
+ for (ip=sres; *ip != '\n'; ip++) ; /* skip header line */
+ ip++;
+
+ bzero (s_id, SZ_LINE);
+ bzero (s_ra, SZ_LINE);
+ bzero (s_dec, SZ_LINE);
+ bzero (s_acref, SZ_URL);
+ bzero (line, SZ_RESULT);
+
+ if (extract & EX_POS && (abs(ra) >= 0 && abs(dec) >= 0)) {
+ bzero (pfname, SZ_LINE);
+ strcpy (pfname, vot_openExFile (pars, nrows, "pos", &pfd) );
+ }
+ if (extract & EX_ACREF && acref >= 0) {
+ bzero (afname, SZ_LINE);
+ strcpy (afname, vot_openExFile (pars, nrows, "urls", &afd) );
+ }
+ if ((extract & EX_KML) && (abs(ra) >= 0 && abs(dec) >= 0)) {
+ bzero (kfname, SZ_LINE);
+ strcpy (kfname, vot_openExFile (pars, nrows, "kml", &kfd) );
+
+ vot_initKML (kfd, pars);
+ }
+ if (extract & EX_HTML) {
+ if (output && output[0] == '-') {
+ hfd = stdout;
+ } else {
+ bzero (hfname, SZ_LINE);
+ strcpy (hfname, vot_openExFile (pars, nrows, "html", &hfd) );
+ }
+
+ vot_initHTML (hfd, pars);
+ vot_printHTMLRow (hfd, hline, TRUE, 0);
+ }
+
+#ifdef FD_DEBUG
+ fprintf (stderr, "%s: pfd=%d afd=%d kfd=%d hfd=%d\n",
+ pars->name, (int)pfd, (int)afd, (int)kfd, (int)hfd);
+#endif
+
+ colnum = 0;
+ rownum = 1;
+ np = 0;
+ na = 0;
+ strcpy (line, hline);
+ lp = line + strlen (line);
+
+ while (*ip) {
+ memset (col, 0, SZ_LINE); /* get value */
+ for (op=col; *ip && *ip != delim && *ip != '\n';)
+ *op++ = *lp++ = *ip++;
+
+ *lp++ = *ip; /* save to line buffer */
+ if (*ip && *ip != '\n') /* skip the delimiter */
+ ip++;
+
+ if (id >= 0 && colnum == id)
+ strcpy (s_id, vot_normalize(col));
+ else if (ra >= 0 && colnum == ra)
+ strcpy (s_ra, vot_normalizeCoord(col));
+ else if (dec >= 0 && colnum == dec)
+ strcpy (s_dec, vot_normalizeCoord(col));
+ else if (acref >= 0 && colnum == acref)
+ strcpy (s_acref, col);
+
+ if (*ip == '\n') {
+ if (pfd) {
+ if (s_id[0])
+ fprintf (pfd, "%s\t%s\t%s\n",
+ vot_normalize(s_id), s_ra, s_dec);
+ else
+ fprintf (pfd, "obj%03d\t%s\t%s\n", rownum, s_ra, s_dec);
+ np++;
+ }
+
+ if (afd && s_acref[0]) {
+ fprintf (afd, "%s\n", s_acref);
+ na++;
+ }
+ if (kfd) {
+ /* See if we're sampling the output. */
+ if (row_count < kml_max) {
+ if (!kml_sample || (row_count % kml_sample) == 0) {
+ vot_printKMLPlacemark (kfd, s_id, atof(s_ra),
+ atof(s_dec), line, s_acref, pars);
+ }
+ }
+ }
+ if (hfd)
+ vot_printHTMLRow (hfd, line, FALSE, row_count);
+
+ if (kfd || hfd) {
+ bzero (line, SZ_RESULT);
+ strcpy (line, hline);
+ lp = line + strlen (line);
+ }
+
+ colnum = 0; /* reinitialize */
+ rownum++;
+ bzero (s_id, SZ_LINE);
+ bzero (s_ra, SZ_LINE);
+ bzero (s_dec, SZ_LINE);
+ bzero (s_acref, SZ_URL);
+ ip++;
+
+ row_count++;
+ } else
+ colnum++;
+ }
+ if (debug) printf ("%s: np = %d na = %d\n", pars->name, np, na);
+
+ if (pfd) {
+ fclose (pfd);
+ if (!np) unlink (pfname);
+ }
+ if (afd) {
+ fclose (afd);
+ if (!na) unlink (afname);
+ }
+ if (hfd) vot_closeHTML (hfd);
+ if (kfd) vot_closeKML (kfd);
+
+
+ return (nrows);
+}
+
+
+/************************************************************************
+** Open an extraction file.
+*/
+char *
+vot_openExFile (svcParams *pars, int nrows, char *extn, FILE **ofd)
+{
+ static char fname[SZ_LINE];
+ FILE *fd = (FILE *) NULL;
+
+ bzero (fname, SZ_LINE);
+ strcpy (fname, (use_name ?
+ vot_getOFName (pars, extn, (int)getpid()) :
+ vot_getOFIndex (pars, extn, (int)getpid())) );
+
+ if ((fd = fopen (fname, "w+")) == (FILE *) NULL) {
+ fprintf (stderr, "exiting ERROR opening position file\n");
+ vot_dalExit (E_NONE, nrows);
+ }
+
+ *ofd = fd;
+ return ( fname );
+}
+
+
+/************************************************************************
+** Construct a standard filename from the service params.
+*/
+char *
+vot_getOFName (svcParams *pars, char *extn, int pid)
+{
+ static char fname[SZ_LINE], *root, spid[16];
+
+
+ bzero (fname, SZ_LINE);
+ bzero (spid, 16);
+ sprintf (spid, "_%d", pid);
+
+
+ /* Create the root part of the name. */
+ if (simple_out) {
+ sprintf (fname, "%s_%s", vot_normalize (pars->name), pars->oname);
+
+ } else if (output) {
+ root = (output[0] == '-' ? "tmp" : output);
+
+ if (numout)
+ sprintf (fname, "%s_%03d_%03d", root,
+ pars->svc_index, pars->obj_index);
+ else if (nservices == 1 && nobjects > 1)
+ sprintf (fname, "%s_%03d", root, pars->index);
+
+ else if (nservices > 1 && nobjects == 1)
+ sprintf (fname, "%s_%s", root, vot_normalize(pars->name));
+
+ else if (nservices > 1 || nobjects > 1)
+ sprintf (fname, "%s_%s_%c_%03d_%s",
+ root,
+ vot_normalize (pars->name),
+ vot_svcTypeCode(pars->type), pars->index, spid);
+ else
+ strcpy (fname, root);
+
+ } else {
+
+ if (nservices==1 && nobjects > 1)
+ sprintf (fname, "%s_%s", vot_normalize (pars->name), pars->oname);
+ else
+ sprintf (fname, "%s_%c_%s",
+ vot_normalize (pars->name),
+ vot_svcTypeCode(pars->type),
+ (pars->oname[0] ? pars->oname : "pos"));
+
+ if (nservices > 1)
+ strcat (fname, spid);
+ }
+
+ if (extn) {
+ strcat (fname, ".");
+ strcat (fname, extn);
+ }
+
+ return (fname);
+}
+
+
+char *
+vot_getOFIndex (svcParams *pars, char *extn, int pid)
+{
+ static char fname[SZ_LINE], *root, spid[16];
+
+ bzero (fname, SZ_LINE);
+ bzero (spid, 16);
+ sprintf (spid, "_%d", pid);
+
+
+ /* Create the root part of the name. */
+ if (output) {
+ root = (output[0] == '-' ? "tmp" : output);
+
+ if (numout)
+ sprintf (fname, "%s_%03d_%03d", root,
+ pars->svc_index, pars->obj_index);
+
+ else if (nservices == 1 && nobjects > 1)
+ sprintf (fname, "%s_%03d", root, pars->index);
+
+ else if (nservices > 1 && nobjects == 1)
+ sprintf (fname, "%s_%s", root, vot_normalize(pars->name));
+
+ else if (nservices > 1 || nobjects > 1)
+ sprintf (fname, "%s_%s_%c_%03d_%s",
+ root,
+ vot_normalize (pars->name),
+ vot_svcTypeCode(pars->type), pars->index, spid);
+ else
+ strcpy (fname, root);
+
+ } else {
+
+ if (nservices==1 && nobjects > 1)
+ sprintf (fname, "%s_%03d", vot_normalize (pars->name), pars->index);
+ else
+ sprintf (fname, "%s_%c_%03d",
+ vot_normalize (pars->name),
+ vot_svcTypeCode(pars->type), pars->index);
+
+ if (nservices > 1)
+ strcat (fname, spid);
+ }
+
+ if (extn) {
+ strcat (fname, ".");
+ strcat (fname, extn);
+ }
+
+ return (fname);
+}
+
+
+/************************************************************************
+** COUNTRESULTS -- Count the number of results in a raw VOTable.
+*/
+int
+vot_countResults (char *result)
+{
+ int nrows = 0;
+ char *tr = (char *) result,
+ *pos = (char *) result;
+
+
+ /* Count the number of <TR> elements in the table. Note we assume
+ ** there is only a single resource, or that the totatl count is what
+ ** we desire. Allow for upper or lower-case tag names.
+ */
+ while (tr) {
+ if ((tr = strstr (pos, "<TR>")) || (tr = strstr (pos, "<tr>")))
+ pos = tr + 4, nrows++;
+ else
+ break;
+ }
+
+ return (nrows);
+}
+
+
+/************************************************************************
+** Exit the process with the given code. Before leaving, we create a
+** semaphore based on the pid and set the value to be the result count.
+** This allows us to pass back the information to the parent thread when
+** setting the status.
+*/
+void
+vot_dalExit (int code, int count)
+{
+ int rc, sem_id, id = getpid();
+ int status = code;
+
+ if ((sem_id = semget ((key_t)id, 1, IPC_CREAT | 0777)) >= 0)
+ rc = semctl (sem_id, 0, SETVAL, count);
+
+/*
+ exit (code);
+*/
+ pthread_exit ((void *) &status);
+}
+
+
+/************************************************************************
+** Print the header for the result table.
+*/
+void
+vot_printHdr (int fd, svcParams *pars)
+{
+ char buf[SZ_LINE];
+
+ bzero (buf, SZ_LINE);
+ sprintf (buf, "# Service: %s\n# Title: %-64.64s\n",
+ pars->name, pars->title);
+ write (fd, buf, strlen (buf));
+
+ bzero (buf, SZ_LINE);
+ sprintf (buf,
+ "# ObjName: %s\n# Position: %f %f\n# Size: %f\n",
+ pars->oname, pars->ra, pars->dec, pars->sr);
+ write (fd, buf, strlen (buf));
+
+ bzero (buf, SZ_LINE);
+ sprintf (buf, "# Query Date: %s\n#\n", vot_procTimestamp());
+ write (fd, buf, strlen (buf));
+}
+
+
+/************************************************************************
+** Print the header for the result count table.
+*/
+void
+vot_printCountHdr ()
+{
+ extern int format, nobjects;
+
+
+ if (quiet)
+ return;
+
+ if (format == F_CSV && count == 0) {
+ if (use_name || all_named)
+ fprintf (stderr, "# %sService,%sNRecs\n",
+ ((nobjects > 1) ? "Rec," : ""),
+ ((nobjects > 1) ? "ObjName," : ""));
+ else
+ fprintf (stderr, "# %sService,%sNRecs\n",
+ ((nobjects > 1) ? "Rec," : ""),
+ ((nobjects > 1) ? "RA,Dec," : ""));
+ } else if (!meta) {
+ extern int inventory;
+
+ if (nobjects == 1 || inventory) {
+ fprintf (stderr, "# %-20s %s %s\n# %-20.20s %s %s\n",
+ "Service", "NRec", "Typ Resource Title",
+ "-------", "----",
+ "--- ---------------------------------------------");
+
+ } else {
+ if (use_name || all_named) {
+ fprintf (stderr, "# %3s %-12.12s\t%-15.15s\t%s\n",
+ "Rec", "Service", "Source Name", "NRecs\n");
+ fprintf (stderr, "# %3s %-12.12s\t%-15.15s\t%s\n",
+ "---", "-------", "-----------", "-----");
+ } else {
+ fprintf (stderr, "# %3s %-12.12s\t %-24.24s\t%s\n",
+ "Rec", "Service", " RA Dec", "NRecs");
+ fprintf (stderr, "# %3s %-12.12s\t %-24.24s\t%s\n",
+ "---", "-------", "-----------------------", "-----");
+ }
+ }
+ }
+}
+
+
+/************************************************************************
+** Print an individual line of the result count table.
+*/
+int
+vot_printCount (Query query, svcParams *pars, int *res_count)
+{
+ QResponse qr = (QResponse) 0; /* Query response */
+ int nrec;
+
+
+ if ((qr = voc_executeQuery (query)) <= 0) {
+ return (E_REQFAIL);
+
+ } else {
+ nrec = voc_getRecordCount(qr);
+ *res_count = nrec;
+
+ if (count_only && nrec <= 0)
+ return (E_NODATA);
+ if (count < 0 && nrec > 0)
+ return (E_NODATA);
+ if (nrec <= 0)
+ return (E_NODATA);
+
+ vot_printCountLine (nrec, pars);
+ return (E_NONE);
+ }
+
+ return (E_NONE);
+}
+
+
+/************************************************************************
+** Print an individual line of the result count table.
+*/
+void
+vot_printCountLine (int nrec, svcParams *pars)
+{
+ int fmt;
+ extern int nobjects;
+ extern void ppMultiLine();
+ extern char *toSexa();
+
+
+ if (nrec == 0 || quiet)
+ return;
+
+ fmt = (count == 1) ? F_ASCII : pars->fmt;
+fmt = F_ASCII;
+
+ switch (fmt) {
+ case F_CSV|F_HTML:
+ case F_CSV|F_KML:
+ case F_TSV:
+ case F_ASCII:
+ if (nobjects == 1) {
+ printf (" %-20.20s %4d %c ",
+ pars->name, nrec,
+ vot_svcTypeCode (pars->type));
+ ppMultiLine (pars->title, 35, 45, 1024);
+ printf ("\n");
+ } else if (use_name || all_named) {
+ printf (" %3d %-12.12s\t%-15.15s\t%6d\n",
+ pars->index, pars->name, pars->oname, nrec);
+ } else {
+ /*
+ printf (" %3d %-12.12s\t%10.6f %10.6f\t%6d",
+ pars->index, pars->name, pars->ra, pars->dec, nrec);
+ */
+ printf (" %3d %-12.12s\t", pars->index, pars->name);
+ printf ("%12.12s ", toSexa (pars->ra/15.0));
+ printf ("%12.12s\t%5d", toSexa(pars->dec), nrec);
+ if (pars->oname[0] && pars->oname && strcmp ("none", pars->oname))
+ printf (" (%s)", pars->oname);
+ printf ("\n");
+ }
+ break;
+ case F_CSV:
+ if (nobjects == 1) {
+ printf ("%s,%d,%s\n", pars->name, nrec, pars->title);
+ } else if (use_name || all_named) {
+ printf ("%d,%s,%s,%d\n",
+ pars->index, pars->name, pars->oname, nrec);
+ } else {
+ /*
+ printf ("%d,%s,%.6f,%.6f,%d\n",
+ pars->index, pars->name, pars->ra, pars->dec, nrec);
+ */
+ printf ("%d,%s,", pars->index, pars->name);
+ printf ("%s,", toSexa (pars->ra/15.0));
+ printf ("%s,%d\n", toSexa (pars->dec), nrec);
+ }
+ break;
+ case F_FITS:
+ fprintf (stderr, "FITS binary table not yet supported\n");
+ break;
+ default:
+ break;
+ }
+}
+
+
+/************************************************************************
+** Return a simple character type code for the specified service type.
+*/
+char
+vot_svcTypeCode (int type)
+{
+ switch (type) {
+ case SVC_CONE: return ('C'); break;
+ case SVC_SIAP: return ('I'); break;
+ case SVC_SSAP: return ('S'); break;
+ case SVC_VIZIER: return ('T'); break;
+ case SVC_OTHER: return ('?'); break;
+ }
+
+ return ('?');
+}
+
+
+/************************************************************************
+** GETEXTN -- Get the filename extension given the current format.
+*/
+char *
+vot_getExtn ()
+{
+ if (format & F_CSV) /* figure out the extension */
+ return ("csv");
+ else if (format & F_ASCII)
+ return ("asv");
+ else if (format & F_TSV)
+ return ("tsv");
+ else if (format & F_RAW)
+ return ("xml");
+ else if (format & F_KML)
+ return ("kml");
+ else if (format & F_XML)
+ return ("xml");
+
+ return ((char *) NULL);
+}
+
+
+/************************************************************************
+** PROCTIMESTAMP -- Return the timestamp with the system newline removed.
+*/
+char *
+vot_procTimestamp ()
+{
+ time_t clock = time (0);
+ char *tstr = ctime (&clock);
+
+ tstr[24] = '\0'; /* kill the newline */
+
+ return (tstr);
+}
+
+
+
+/************************************************************************
+** CONCAT -- Concatenate the files generated by the query into a
+** single document ordered by the service.
+*/
+void
+vot_concat ()
+{
+ FILE *fd = (FILE *) NULL;
+ Service *svc = svcList; /* the service list */
+ Proc *proc; /* process list in each service */
+ char *extn, fname[SZ_FNAME];
+ int nrows = 0;
+
+
+ extn = vot_getExtn (); /* figure out the extension */
+
+ for (svc=svcList; svc; svc=svc->next) {
+
+ if (output && output[0] == '-') {
+ fd = stdout;
+ } else {
+ /* Open a separate file for each service. Since we can't rely
+ ** one services returning the same columns it only makes sense
+ ** to concatenate similar files.
+ */
+ bzero (fname, SZ_FNAME);
+ sprintf (fname, "%s_%d.%s",
+ vot_getSName(svc->proc->root), getpid(), extn);
+
+ if ((fd = fopen (fname, "w+")) == (FILE *) NULL) {
+ fprintf (stderr, "ERROR: Cannot open output file: '%s'\n",
+ fname);
+ continue;
+ }
+ }
+
+ /* Concatenate results for each object.
+ */
+ nrows = 0;
+ for (proc=svc->proc; proc; proc=proc->next)
+ nrows += vot_copyFile (proc->root, extn, vot_getOName(proc->root),
+ fd, (proc == svc->proc), nrows);
+
+ if (fd != stdout) /* close the file descriptor */
+ fclose (fd);
+ }
+
+ /* Clean up the intermediate files if needed.
+ */
+ if (fd == stdout || (extract & EX_COLLECT))
+ vot_clean (extn);
+}
+
+
+/************************************************************************
+** COPYFILE -- Copy a result file to the output XML file.
+*/
+static int
+vot_copyFile (char *root, char *extn, char *name, FILE *fd, int hdr, int nrows)
+{
+ char line[4096], fname[SZ_FNAME];
+ FILE *ifd;
+ int nr = 0;
+
+
+ bzero (fname, SZ_FNAME);
+ sprintf (fname, "%s.%s", root, extn);
+
+ if (access (fname, R_OK) == 0) {
+ if ((ifd = fopen (fname, "r")) == (FILE *) NULL) {
+ fprintf (stderr, "Warning: Cannot open file '%s'\n", fname);
+ return (0);
+ }
+ } else
+ return (0);
+
+ /* (Slow) Copy the file until the end of the Document.
+ */
+ bzero (line, 4096);
+ while (fgets (line, 4096, ifd)) {
+ if (!nrows && hdr && line[0] == '#')
+ /*fprintf (fd, "# %s", &line[1]); */
+ fprintf (fd, "%s", &line[1]);
+ else if (nrows && !hdr && line[0] == '#')
+ ;
+ else {
+ fprintf (fd, "%s", line);
+ nr++;
+ }
+ bzero (line, 4096);
+ }
+ fflush (fd);
+
+ fclose (ifd);
+
+ return (nr);
+}
+
+
+/************************************************************************
+** CLEANXML -- Clean up the intermediate VOTable files when producing
+** the compiled XML doc..
+*/
+static void
+vot_clean (char *extn)
+{
+ Service *svc = svcList; /* the service list */
+ Proc *proc; /* process list in each service */
+ char fname[SZ_FNAME];
+
+ for (svc=svcList; svc; svc=svc->next) {
+ for (proc=svc->proc; proc; proc=proc->next) {
+ bzero (fname, SZ_FNAME);
+ sprintf (fname, "%s.%s", proc->root, extn);
+ unlink (fname);
+ }
+ }
+}
diff --git a/vendor/voclient/voapps/lib/voFITS.c b/vendor/voclient/voapps/lib/voFITS.c
new file mode 100644
index 00000000..b6d9c48e
--- /dev/null
+++ b/vendor/voclient/voapps/lib/voFITS.c
@@ -0,0 +1,467 @@
+#include <string.h>
+#include <stdio.h>
+#include <math.h>
+#include <unistd.h>
+#include "voApps.h"
+#include "fitsio.h"
+
+
+#define MAX_IMAGES 20480 /* max images to process */
+
+#define dabs(x) ((x<0.0?-x:x))
+
+
+/**
+ * Private methods.
+ */
+static void vot_printFrameInfo (FILE *fd, frameInfo *im);
+static int vot_getFrameWcs (fitsfile *fptr, frameInfo *info);
+
+extern int vot_fileType (char *name);
+
+
+
+
+/**
+ * VOT_IMAGEINFO -- Get information about a FITS file structure and WCS.
+ *
+ * @fn info = vot_imageInfo (char *name, int do_all)
+ *
+ * @brief Get information about a FITS file structure and WCS.
+ * @param name name of FITS file to open
+ * @param do_all do all extensions in an MEF file?
+ * @return pointer to ImInfo structure
+ */
+ImInfo *
+vot_imageInfo (char *name, int do_all)
+{
+ fitsfile *fptr;
+ ImInfo *info = (ImInfo *) NULL;
+ long naxes[3] = {0, 0, 0}, nrows=0;
+ int nextns=0, naxis=0, bitpix=0, extnum=0;
+ int hdupos=0, hdutype=0, ncols=0, i=0, status=0;
+ double cxsum=0.0, cysum=0.0, rxsum=0.0, rysum=0.0;
+
+
+ /* Check for file existence.
+ */
+ if (access (name, F_OK) != 0) {
+ fprintf (stderr, "Error: cannot open image '%s'\n", name);
+ return ((ImInfo *) NULL);
+ }
+ if (vot_fileType (name) != VOT_FITS) {
+ fprintf (stderr, "Error: file '%s' is not a FITS image\n", name);
+ return ((ImInfo *) NULL);
+ }
+
+ info = (ImInfo *) calloc (1, sizeof (ImInfo));
+ if (fits_open_file (&fptr, name, READONLY, &status) == 0) {
+ fits_get_num_hdus (fptr, &nextns, &status);
+ fits_get_hdu_num (fptr, &hdupos); /* get the current HDU position */
+
+ strncpy (info->imname, name, strlen(name));
+ info->nextend = (nextns - 1);
+ info->extns = (frameInfo *) calloc (nextns, sizeof (frameInfo));
+
+ for (; !status; hdupos++) { /* Main loop for each HDU */
+ fits_get_hdu_type (fptr, &hdutype, &status); /* Get the HDU type */
+
+ if (hdutype == IMAGE_HDU) { /* primary array or image HDU */
+ fits_get_img_param (fptr, 10, &bitpix, &naxis, naxes, &status);
+
+ if (hdupos == 0) { /* PHU */
+ info->frame.is_image = 1;
+ info->frame.is_table = 0;
+ info->frame.naxis = naxis;
+ info->frame.bitpix = bitpix;
+ for (i=0; i < naxis; i++)
+ info->frame.naxes[i] = naxes[i];
+
+ } else { /* EHU */
+ extnum = hdupos - 1;
+ info->extns[extnum].is_image = 1;
+ info->extns[extnum].is_table = 0;
+ info->extns[extnum].extnum = extnum;
+ info->extns[extnum].naxis = naxis;
+ info->extns[extnum].bitpix = bitpix;
+ for (i=0; i < naxis; i++)
+ info->extns[extnum].naxes[i] = naxes[i];
+
+ if (vot_getFrameWcs (fptr, &info->extns[extnum]) == 0)
+ info->extns[extnum].has_wcs = 1;
+ }
+
+ } else { /* a table HDU */
+ if (hdupos > 0) { /* EHU */
+ fits_get_num_rows (fptr, &nrows, &status);
+ fits_get_num_cols (fptr, &ncols, &status);
+
+ extnum = hdupos - 1;
+ info->extns[extnum].is_image = 0;
+ info->extns[extnum].is_table = 1;
+ info->extns[extnum].naxis = 2;
+ info->extns[extnum].bitpix = 0;
+ info->extns[extnum].naxes[0] = ncols;
+ info->extns[extnum].naxes[1] = nrows;
+ }
+
+#ifdef GET_TBLINFO
+ printf ("%s Table: %d columns x %ld rows\n",
+ ((hdutype==ASCII_TBL) ? "ASCII" : "Binary"); ncols, nrows);
+ printf(" COL NAME FORMAT\n");
+ for (i = 1; i <= ncols; i++) {
+ fits_make_keyn ("TTYPE", i, keyname,&status);
+ fits_read_key (fptr, TSTRING, keyname,colname,NULL,&status);
+ fits_make_keyn ("TFORM", i, keyname,&status);
+ fits_read_key (fptr, TSTRING, keyname,coltype,NULL,&status);
+ printf(" %3d %-16s %-16s\n", i, colname, coltype);
+ }
+#endif
+ }
+
+ /* Move to next extension.
+ */
+ fits_movrel_hdu (fptr, 1, NULL, &status);
+ }
+
+ if (status == END_OF_FILE)
+ status = 0; /* reset normal error */
+
+ } else if (status) /* print any error message */
+ fits_report_error (stderr, status);
+
+
+ /* Compute the values for the entire frame.
+ */
+ info->frame.lx = info->frame.ly = 360.0;
+ info->frame.ux = info->frame.uy = -360.0;
+
+ info->frame.cx = info->extns[0].cx;
+ info->frame.cy = info->extns[0].cy;
+ info->frame.lx = info->extns[0].lx;
+ info->frame.ly = info->extns[0].ly;
+ info->frame.ux = info->extns[0].ux;
+ info->frame.uy = info->extns[0].uy;
+ info->frame.rotang = info->extns[0].rotang;
+ info->frame.xrval = info->extns[0].xrval;
+ info->frame.yrval = info->extns[0].yrval;
+ info->frame.xrpix = info->extns[0].xrpix;
+ info->frame.yrpix = info->extns[0].yrpix;
+ info->frame.radius = info->extns[0].radius;
+
+ if (nextns == 1) {
+ for (i=0; i < naxis; i++)
+ info->frame.naxes[i] = info->extns[0].naxes[i];
+ }
+ memcpy (&info->frame.xc[0], &info->extns[0].xc[0], (sizeof(double)*4));
+ memcpy (&info->frame.yc[0], &info->extns[0].yc[0], (sizeof(double)*4));
+
+ for (i=1; i < nextns; i++) {
+ if (info->extns[i].lx < info->frame.lx)
+ info->frame.lx = info->extns[i].lx;
+ if (info->extns[i].ly < info->frame.ly)
+ info->frame.ly = info->extns[i].ly;
+
+ if (info->extns[i].ux > info->frame.ux)
+ info->frame.ux = info->extns[i].ux;
+ if (info->extns[i].uy > info->frame.uy)
+ info->frame.uy = info->extns[i].uy;
+ cxsum += info->extns[i].cx;
+ cysum += info->extns[i].cy;
+
+ rxsum += info->extns[i].naxes[0];
+ rysum += info->extns[i].naxes[1];
+
+ info->frame.scale = info->extns[i].scale;
+ info->frame.rotang = info->extns[i].rotang;
+ strcpy (info->frame.ctype, info->extns[i].ctype);
+ }
+
+ if (nextns > 1) {
+ info->frame.xrval = info->frame.cx = (cxsum / (double) nextns);
+ info->frame.yrval = info->frame.cy = (cysum / (double) nextns);
+ info->frame.xrpix = info->frame.radius /
+ (info->frame.scale / 3600.) / 2.0;
+ info->frame.yrpix = info->frame.radius /
+ (info->frame.scale / 3600.) / 2.0;
+ } else {
+ info->frame.xrval = info->frame.cx = info->extns[0].cx;
+ info->frame.yrval = info->frame.cy = info->extns[0].cy;
+ info->frame.xrpix = info->extns[0].xrpix;
+ info->frame.yrpix = info->extns[0].yrpix;
+ strcpy (info->frame.ctype, info->extns[0].ctype);
+ }
+
+ info->frame.width = ((info->frame.ux+360.) - (info->frame.lx+360.));
+ info->frame.height = ((info->frame.uy+ 90.) - (info->frame.ly+ 90.));
+ info->frame.radius = sqrt (
+ (info->frame.cx - info->frame.lx) *
+ (info->frame.cx - info->frame.lx) +
+ (info->frame.cy - info->frame.ly) *
+ (info->frame.cy - info->frame.ly) );
+ info->frame.xc[0] = info->frame.lx; info->frame.yc[0] = info->frame.ly;
+ info->frame.xc[1] = info->frame.lx; info->frame.yc[1] = info->frame.uy;
+ info->frame.xc[2] = info->frame.ux; info->frame.yc[2] = info->frame.uy;
+ info->frame.xc[3] = info->frame.ux; info->frame.yc[3] = info->frame.ly;
+
+
+ fits_close_file (fptr, &status);
+ return ( (ImInfo *) info);
+}
+
+
+/**
+ * VOT_IMAGENEXTNS -- Get the number of extensions in an MEF file.
+ *
+ * @fn nextn = vot_imageNExtns (char *name)
+ *
+ * @brief Get the number of extensions in an MEF file.
+ * @param name name of FITS file to open
+ * @return number of extensions in an MEF file
+ */
+int
+vot_imageNExtns (char *image)
+{
+ fitsfile *fptr;
+ int nextns = -1, status = 0;
+
+
+ if (fits_open_file (&fptr, image, READONLY, &status) == 0) {
+ fits_get_num_hdus (fptr, &nextns, &status);
+ fits_close_file (fptr, &status);
+ }
+
+ return (nextns);
+}
+
+
+/**
+ * VOT_PRINTIMAGEINFO -- Print the image information.
+ *
+ * @fn vot_printImageInfo (FILE *fd, ImInfo *im)
+ *
+ * @brief Print the image information.
+ * @param fd output file descriptor (or stdout/stderr)
+ * @param im image information structure
+ * @return nothing
+ */
+void
+vot_printImageInfo (FILE *fd, ImInfo *im)
+{
+ register int i;
+
+ fprintf (fd, "Name: %s nextns = %d\n", im->imname, im->nextend);
+
+ fprintf (fd, "Frame:\n"); im->frame.extnum = -1;
+ vot_printFrameInfo (fd, &im->frame);
+
+ for (i=1; i < im->nextend; i++)
+ vot_printFrameInfo (fd, &im->extns[i]);
+}
+
+
+/**
+ * VOC_FREEIMAGEINFO -- Free the image information structure.
+ *
+ * @fn vot_freeImageInfo (ImInfo *im)
+ *
+ * @brief Free the image information structure.
+ * @param im image information structure
+ * @return nothing
+ */
+void
+vot_freeImageInfo (ImInfo *im)
+{
+ free ((void *) im->extns); /* extension structs */
+ free ((void *) im); /* main image structs */
+}
+
+
+
+/****************************************************************************
+ *** Private procedures
+ ****************************************************************************/
+
+/**
+ * VOT_PRINTFRAMEINFO -- Print information about a specific frame.
+ */
+static void
+vot_printFrameInfo (FILE *fd, frameInfo *im)
+{
+ if (im->extnum >= 0) {
+ fprintf (fd, "\nExt: %d dims[%d] = %d %d %d\t",
+ im->extnum, im->naxis, im->naxes[0], im->naxes[1], im->naxes[2]);
+ fprintf (fd, " image: %d table: %d has_wcs: %d flip: %d\n",
+ im->is_image, im->is_table, im->has_wcs, im->axflip);
+ }
+
+ fprintf (fd,
+ " center: %8.4f %8.4f ll: %8.4f %8.4f ur: %8.4f %8.4f\n",
+ im->cx, im->cy, im->lx, im->ly, im->ux, im->uy);
+ fprintf (fd, " corners: %8.4f %8.4f %8.4f %8.4f\n",
+ im->xc[1], im->yc[1], im->xc[2], im->yc[2]);
+ fprintf (fd, "\t %8.4f %8.4f %8.4f %8.4f\n",
+ im->xc[0], im->yc[0], im->xc[3], im->yc[3]);
+ fprintf (fd,
+ " crval: %8.4f %8.4f crpix: %8.4f %8.4f ctype: '%s'\n",
+ im->xrval, im->yrval, im->xrpix, im->yrpix, im->ctype);
+ fprintf (fd,
+ " w/h: %8.4f %8.4f radius: %8.4f rot: %8.4f scale: %8.4f\n",
+ dabs(im->width), dabs(im->height), im->radius, im->rotang, im->scale);
+}
+
+
+/**
+ * VOT_GETFRAMEWCS -- Get the WCS information for a given frame.
+ */
+static int
+vot_getFrameWcs (fitsfile *fptr, frameInfo *info)
+{
+ double xrval=0.0, yrval=0.0, xrpix=0.0, yrpix=0.0, xpix=0.0, ypix=0.0;
+ double xinc=0.0, yinc=0.0, rot=0.0, scale=0.0, xrot=0.0, yrot=0.0;
+ double cx=0.0, cy=0.0, lx=0.0, ly=0.0, ux=0.0, uy=0.0;
+ double cd11=0.0, cd12=0.0, cd21=0.0, cd22=0.0, cdelt1=0.0, cdelt2=0.0;
+ int i, axflip=0, status = 0;
+ char str[32], ctype[5], comment[80];
+
+
+ /* Get the header WCS keywords.
+ */
+ fits_read_img_coord (fptr, &xrval, &yrval, &xrpix,
+ &yrpix, &xinc, &yinc, &rot, ctype, &status);
+
+ info->xrval = xrval;
+ info->yrval = yrval;
+ info->xrpix = xrpix;
+ info->yrpix = yrpix;
+ info->has_wcs = 1;
+ info->is_image = 1;
+ strcpy (info->ctype, ctype);
+
+ xpix = (double) 0.5; /* Lower-left */
+ ypix = (double) 0.5;
+ status = 0;
+ fits_pix_to_world (xpix, ypix, xrval, yrval, xrpix, yrpix, xinc, yinc,
+ rot, ctype, &info->xc[0], &info->yc[0], &status);
+
+ xpix = (double) 0.5; /* Upper-left */
+ ypix = (double) info->naxes[1] - 0.5;
+ status = 0;
+ fits_pix_to_world (xpix, ypix, xrval, yrval, xrpix, yrpix, xinc, yinc,
+ rot, ctype, &info->xc[1], &info->yc[1], &status);
+
+ xpix = (double) info->naxes[0] - 0.5; /* Upper-right */
+ ypix = (double) info->naxes[1] - 0.5;
+ status = 0;
+ fits_pix_to_world (xpix, ypix, xrval, yrval, xrpix, yrpix, xinc, yinc,
+ rot, ctype, &info->xc[2], &info->yc[2], &status);
+
+ xpix = (double) info->naxes[0] - 0.5; /* Lower-right */
+ ypix = (double) 0.5;
+ status = 0;
+ fits_pix_to_world (xpix, ypix, xrval, yrval, xrpix, yrpix, xinc, yinc,
+ rot, ctype, &info->xc[3], &info->yc[3], &status);
+
+ xpix = (double) info->naxes[0] / 2. - 0.5; /* Center */
+ ypix = (double) info->naxes[1] / 2. - 0.5;
+ status = 0;
+ fits_pix_to_world (xpix, ypix, xrval, yrval, xrpix, yrpix, xinc, yinc,
+ rot, ctype, &info->cx, &info->cy, &status);
+ info->cx = xrval;
+ info->cy = yrval;
+
+ /* Get center and cone radius.
+ */
+ lx = info->lx = info->xc[0]; /* Lower-left */
+ ly = info->ly = info->yc[0];
+ ux = info->ux = info->xc[2]; /* Upper-right */
+ uy = info->uy = info->yc[2];
+ cx = info->cx;
+ cy = info->cy;
+ status = 0;
+ if ((i = fits_read_key_dbl(fptr, "CD1_1", &cd11, comment, &status))==0) {
+ fits_read_key_dbl (fptr, "CD1_2", &cd12, comment, &status);
+ fits_read_key_dbl (fptr, "CD2_1", &cd21, comment, &status);
+ fits_read_key_dbl (fptr, "CD2_2", &cd22, comment, &status);
+
+ scale = 3600.0 * sqrt ((cd11*cd11+cd21*cd21+cd12*cd12+cd22*cd22) / 2.);
+ xrot = dabs (atan2 ( cd21, cd11));
+ yrot = dabs (atan2 (-cd12, cd22));
+ rot = (xrot + yrot) / 2.0;
+ } else {
+ /* Old-style keywords.
+ */
+ status = 0;
+ if (!fits_read_key_dbl (fptr, "CDELT1", &cdelt1, comment, &status)) {
+ fits_read_key_dbl (fptr, "CDELT2", &cdelt2, comment, &status);
+
+ scale = 3600.0 * sqrt ((cdelt1*cdelt1 + cdelt2*cdelt2) / 2.);
+
+ if (!fits_read_key_dbl (fptr, "CROTA1", &xrot, comment, &status)) {
+ fits_read_key_dbl (fptr, "CROTA2", &yrot, comment, &status);
+ rot = (xrot + yrot) / 2.0;
+ }
+ } else
+ info->has_wcs = 0;
+ }
+
+ status = 0;
+ memset (str, 0, 32);
+ if ((i = fits_read_key_str(fptr, "CTYPE1", str, comment, &status))==0) {
+ if (strncasecmp (str,"DEC",3) == 0 || strncasecmp (str,"LAT",3) == 0)
+ axflip = 1;
+ }
+
+ /* For a bad/approximate WCS, compute in rough coords.
+ */
+ if ( (lx == cx) && (ly == cy) ) {
+ double s = (scale / 3600.0);
+
+ lx = info->lx = cx - (info->naxes[0]/2 * s); /* Lower-left */
+ ly = info->ly = cy - (info->naxes[1]/2 * s);
+ ux = info->ux = cx + (info->naxes[0]/2 * s); /* Upper-right */
+ uy = info->uy = cy + (info->naxes[1]/2 * s);
+
+ info->xc[0] = cx - (info->naxes[0]/2 * s); /* Lower-left */
+ info->yc[0] = cy - (info->naxes[1]/2 * s);
+
+ info->xc[1] = cx - (info->naxes[0]/2 * s); /* Upper-left */
+ info->yc[1] = cy + (info->naxes[1]/2 * s);
+
+ info->xc[2] = cx + (info->naxes[0]/2 * s); /* Upper-right */
+ info->yc[2] = cy + (info->naxes[1]/2 * s);
+
+ info->xc[3] = cx + (info->naxes[0]/2 * s); /* Lower-right */
+ info->yc[3] = cy - (info->naxes[1]/2 * s);
+ }
+
+ /* FIXME -- Doens't handle rotation properly. */
+ info->width = dabs((ux - lx)); /* in degrees */
+ info->height = dabs((uy - ly));
+ info->radius = sqrt ((cx - lx) * (cx - lx) + (cy - ly) * (cy - ly));
+ info->rotang = rot;
+ info->scale = scale;
+ info->axflip = axflip;
+
+ return (info->has_wcs);
+}
+
+
+/*****************************************************************************
+ * Program main.
+ ****************************************************************************/
+#ifdef UNIT_TEST
+int
+main (int argc, char *argv[])
+{
+ ImInfo *img = (ImInfo *) NULL;
+
+
+ if ( (img = vot_imageInfo (argv[1], 1)) ) {
+ vot_printImageInfo (stdout, img);
+ vot_freeImageInfo (img);
+ }
+
+ return (0);
+}
+#endif
diff --git a/vendor/voclient/voapps/lib/voHTML.c b/vendor/voclient/voapps/lib/voHTML.c
new file mode 100644
index 00000000..c50bdb54
--- /dev/null
+++ b/vendor/voclient/voapps/lib/voHTML.c
@@ -0,0 +1,131 @@
+/************************************************************************
+** VODALUTIL.C -- Utility procedures for the DAL interface worker
+** procedures.
+**
+** M. Fitzpatrick, NOAO, July 2007
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/ipc.h>
+#include <sys/sem.h>
+#include "VOClient.h"
+#include "voAppsP.h"
+
+
+extern int format, iportal;
+extern int html_border, html_color, html_header;
+
+void vot_initKML (FILE *fd, svcParams *pars);
+void vot_printHTMLRow (FILE *fd, char *line, int isHdr, int rownum);
+void vot_closeKML (FILE *fd);
+
+
+
+/************************************************************************
+** INITHTML -- Initialize the KML output file header.
+*/
+void
+vot_initHTML (FILE *fd, svcParams *pars)
+{
+ if (!fd)
+ return;
+
+ if (html_header)
+ fprintf (fd, "<html>\n<body>\n");
+
+ fprintf (fd, "<table border=\"%d\">\n",
+ (html_border ? 5 : 0));
+}
+
+
+/************************************************************************
+** PRINTHTMLROW -- Write a row in an HTML table.
+** file.
+*/
+void
+vot_printHTMLRow (FILE *fd, char *line, int isHdr, int rownum)
+{
+ char *ip, *hp, *sp, *dp, *vp, *tab, *col, delim, val[SZ_LINE];
+
+
+ if (!fd || !line)
+ return;
+
+ for (dp=line; *dp && *dp != '\n'; dp++) /* get the data line */
+ ;
+ dp++;
+ hp = line; /* get the header line */
+
+ sp = (isHdr ? hp : dp);
+ tab = (isHdr ? "th" : "td");
+ if (isHdr)
+ col = "eec";
+ else if (html_color)
+ col = ((rownum % 2) == 0) ? "ccc" : "eee";
+ else
+ col = "fff";
+
+ delim = ((format == F_CSV) ? ',' :
+ ((format == F_TSV) ? '\t' :
+ ((format == F_ASCII) ? ' ' : ',')));
+
+ fprintf (fd, "<tr>");
+
+ for (ip=sp; *ip; ) {
+ bzero (val, SZ_LINE);
+ for (vp=val; *ip && *ip != '\n' && *ip != delim; ) {
+ if (*ip == '>') {
+ strcpy (vp, "&gt;");
+ vp += 4, ip++;
+ } else if (*ip == '<') {
+ strcpy (vp, "&lt;");
+ vp += 4, ip++;
+ } else {
+ *vp++ = *ip++;
+ }
+ }
+
+ if (strncmp (val, "http://", 7) == 0) {
+ if (iportal && strstr (val, ".fits") == (char *) NULL) {
+ fprintf (fd, "<%s style=\"background:#%s\">", tab, col);
+ fprintf (fd, "<a href=\"javascript:render('%s');\">%s</a></%s>",
+ val, val, tab);
+ } else if (!iportal) {
+ fprintf (fd,
+ "<%s style=\"background:#%s\"><a href='%s'>%s</a></%s>",
+ tab, col, val, val, tab);
+ } else {
+ fprintf (fd, "<%s style=\"background:#%s\">%s</%s>",
+ tab, col, val, tab);
+ }
+ } else
+ fprintf (fd, "<%s style=\"background:#%s\">%s</%s>",
+ tab, col, val, tab);
+ if (*ip)
+ ip++;
+ else
+ break;
+ }
+
+ fprintf (fd, "</tr>\n");
+}
+
+
+/************************************************************************
+** CLOSEHTML -- Close the HTML output file.
+*/
+void
+vot_closeHTML (FILE *fd)
+{
+ if (!fd)
+ return;
+
+ fprintf (fd, "</table>\n");
+ if (html_header)
+ fprintf (fd, "</body>\n</html>\n");
+
+ fclose (fd);
+}
+
+
diff --git a/vendor/voclient/voapps/lib/voInv.c b/vendor/voclient/voapps/lib/voInv.c
new file mode 100644
index 00000000..e6d7cb98
--- /dev/null
+++ b/vendor/voclient/voapps/lib/voInv.c
@@ -0,0 +1,501 @@
+/**************************************************************************
+**
+*/
+
+/*
+** ra, dec, radius // double
+** sources, resources, id, return // string
+** sourceURL, resourceURL // file
+*/
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#ifdef VO_INVENTORY
+#include <curl/curl.h>
+#include <curl/types.h>
+#include <curl/easy.h>
+#include "VOClient.h"
+#include "voAppsP.h"
+
+
+
+char *base_url =
+ "http://irsa.ipac.caltech.edu/cgi-bin/VOInventory/nph-voInventory";
+
+#define SUBSET "subset" /* 1 pos, 1 resource */
+#define MATCHES "matches" /* N pos, 1 resource */
+#define REGION "region" /* 1 pos, [N resources] */
+#define TABLE "table" /* N pos, [N resources] */
+
+
+#ifdef UNIT_TEST
+int verbose = 0;
+int debug = 0;
+#endif
+char *id = NULL;
+char *action = NULL;
+char *rettype = "votable";
+double ra = 0.0;
+double dec = 0.0;
+double radius = 0.1;
+
+char *ofname = NULL;
+FILE *outfile = (FILE *) NULL;
+
+int nsources = 1;
+int nresources = 0;
+
+extern Object *objList;
+extern Service *svcList;
+extern char *sources;
+extern char *resources;
+extern double sr;
+extern int format, count, verbose, debug, ecols, nservices, nobjects;
+extern char *output, *tmpdir;
+
+
+char *vot_doInventory ();
+char *vot_execInv (double ra, double dec, double radius, char *sources,
+ char *resources, char *id, char *rettype, FILE *outfile);
+
+static size_t vot_invWrite (void *ptr, size_t size, size_t nmemb, FILE *stream);
+static size_t vot_invRead (void *ptr, size_t size, size_t nmemb, FILE *stream);
+static char *vot_dbl2str (double dval);
+static void vot_printRegionCount (char *file, int extra);
+static void vot_printMatchCount (char *file);
+
+extern char *vot_getTableCol (char *line, int col, int span);
+extern void ppMultiLine (char *result, int poffset, int pwidth, int maxch);
+
+
+
+#ifdef UNIT_TEST
+int
+main (int argc, char *argv[])
+{
+ register int i, j, len;
+
+ CURL *curl;
+ CURLcode res;
+ struct curl_httppost *form = NULL;
+ struct curl_httppost *last = NULL;
+
+
+ for (i=1; i < argc; i++) {
+ if (argv[i][0] == '-') {
+ len = strlen (argv[i]);
+ for (j=1; j < len; j++) {
+ switch (argv[i][j]) {
+ case 'h': /* help */
+ return (0);
+ case 'd': /* debug */
+ debug++;
+ break;
+ case 'v': /* verbose */
+ verbose++;
+ break;
+ case 't': /* test */
+ base_url = "http://iraf.noao.edu/scripts/tpost";
+ break;
+ case 'p': /* pos (ra dec) */
+ ra = atof (argv[i+1]);
+ dec = atof (argv[i+2]);
+ i += 2;
+ nsources = 1;
+ break;
+ case 'r': /* radius */
+ radius = atof (argv[++i]);
+ break;
+ case 'i': /* id */
+ id = argv[++i];
+ break;
+ case 'o': /* output file */
+ ofname = argv[++i];
+ outfile = fopen (ofname, "w+");
+ break;
+ case 'R': /* resource file */
+ resources = argv[++i];
+ nresources = 2;
+ break;
+ case 'S': /* source file */
+ sources = argv[++i];
+ nsources = 2;
+ break;
+
+ case 'A': rettype = "ascii"; break;
+ case 'C': rettype = "csv"; break;
+ case 'H': rettype = "HTML"; break; /* BROKE */
+ case 'T': rettype = "tsv"; break;
+ case 'V': rettype = "votable"; break;
+ default:
+ break;
+ }
+ }
+ }
+ }
+
+
+ if (debug) {
+ fprintf (stderr, "pos = (%f,%f) radius = %f\n", ra, dec, radius);
+ fprintf (stderr, "id = '%s'\n", id);
+ fprintf (stderr, "sources = '%s' N = %d\n", sources, nsources);
+ fprintf (stderr, "resources = '%s' N = %d\n", resources, nresources);
+ }
+
+ (void) vot_execInv (ra, dec, radius, sources, resources, id, rettype,
+ NULL);
+
+ return 0;
+}
+#endif
+
+
+/* VOT_EXECINV -- Execute the inventory service call.
+*/
+char *
+vot_doInventory ()
+{
+ double ra = objList->ra, dec = objList->dec, radius = sr;
+ char *id = (svcList ? svcList->identifier : NULL),
+ *rettype = "tsv", *action;
+ char tmpfile[SZ_LINE];
+ FILE *fd = (FILE *) NULL;
+
+ extern char *vot_mktemp();
+
+
+ /* Get a temporary file to be used for the votable output.
+ */
+ strcpy (tmpfile, (debug ? "/tmp/vod.tmp" : vot_mktemp ("vodi")));
+
+ if (! (fd = fopen (tmpfile, "w+")) ) {
+ fprintf (stderr, "Cannot open output file '%s'\n", tmpfile);
+ exit (1);
+ }
+
+ if (debug) {
+ fprintf (stderr, "ra '%f' '%f' radius '%f'....\n", ra, dec, radius);
+ fprintf (stderr, "id '%s' rettype '%s'....\n", id, rettype);
+ fprintf (stderr, "sources '%s' resources '%s'....\n",
+ sources, resources);
+ fprintf (stderr, "using file '%s'....\n", output);
+ }
+
+ /* Execute the query.
+ vot_execInv (ra, dec, radius, sources, resources, id, "tsv", fd);
+ */
+ action = vot_execInv (ra, dec, radius, sources, resources, id, "tsv", fd);
+
+ if (fd != stdout) {
+ fclose (fd);
+
+ if (debug) {
+ system("cat /tmp/vod.tmp");
+ printf ("\n\n");
+ }
+
+ if (count) {
+ if (strcmp (action, "region") == 0)
+ vot_printRegionCount (tmpfile, 0);
+ else if (strcmp (action, "table") == 0)
+ vot_printRegionCount (tmpfile, 1);
+ else if ((strcmp (action, "matches")) ||
+ (strcmp (action, "subset") == 0)) {
+ vot_printMatchCount (tmpfile);
+ }
+ }
+ }
+
+ if (!debug)
+ unlink (tmpfile);
+
+ return (action);
+}
+
+
+/* VOT_EXECINV -- Execute the inventory service call.
+*/
+char *
+vot_execInv (double ra, double dec, double radius, char *sources,
+ char *resources, char *id, char *rettype, FILE *outfile)
+{
+ CURL *curl;
+ CURLcode res;
+ struct curl_httppost *form = NULL;
+ struct curl_httppost *last = NULL;
+
+
+
+ nresources = nservices;
+ nsources = nobjects;
+
+ /* Initialize the CURL call.
+ */
+ curl_global_init (CURL_GLOBAL_ALL);
+
+ if ( (curl = curl_easy_init()) ) {
+
+ struct curl_slist *headerlist = NULL;
+
+
+ /* Fill in the fields.
+ */
+ if (radius > 0.0) {
+ curl_formadd (&form, &last, CURLFORM_COPYNAME, "radius",
+ CURLFORM_COPYCONTENTS, vot_dbl2str(radius), CURLFORM_END);
+ curl_formadd (&form, &last, CURLFORM_COPYNAME, "units",
+ CURLFORM_COPYCONTENTS, "degree", CURLFORM_END);
+ }
+
+ if (debug)
+ fprintf (stderr, "\n\nnsources=%d nresources=%d\n\n",
+ nsources, nresources);
+
+ switch ( nsources ) {
+ case 0:
+ perror ("Invalid NSources=0, no src file or posn specified\n");
+ exit(1);
+ case 1:
+ curl_formadd (&form, &last, CURLFORM_COPYNAME, "ra",
+ CURLFORM_COPYCONTENTS, vot_dbl2str(ra), CURLFORM_END);
+ curl_formadd (&form, &last, CURLFORM_COPYNAME, "dec",
+ CURLFORM_COPYCONTENTS, vot_dbl2str(dec), CURLFORM_END);
+ if (id) {
+ action = "subset";
+ curl_formadd (&form, &last, CURLFORM_COPYNAME, "id",
+ CURLFORM_COPYCONTENTS, id, CURLFORM_END);
+ } else if (resources)
+ action = "table";
+ else
+ action = "region";
+ break;
+ default:
+ if (sources) {
+ curl_formadd (&form, &last, CURLFORM_COPYNAME, "sources",
+ CURLFORM_FILE, sources, CURLFORM_END);
+ if (nresources < 0)
+ action = "table";
+ else if (nresources == 1 && id)
+ action = "matches";
+ else if (resources)
+ action = "table";
+ } else {
+ perror ("Invalid nsources=N, no source file specified\n");
+ exit (1);
+ }
+ break;
+ }
+
+
+ /* Set the matching resources.
+ */
+ if (nresources == 1 && id) {
+ curl_formadd (&form, &last, CURLFORM_COPYNAME, "id",
+ CURLFORM_COPYCONTENTS, id, CURLFORM_END);
+
+ } else if (nresources >= 1 && resources) {
+ curl_formadd (&form, &last, CURLFORM_COPYNAME, "resources",
+ CURLFORM_FILE, resources,
+ CURLFORM_CONTENTTYPE, "text/xml",
+ CURLFORM_END);
+
+ } else if (nresources > 0) {
+ perror ("Invalid NResources=2, no resource file specified\n");
+ exit (1);
+ }
+
+
+ /* Make sure we have a valid action to execute.
+ */
+ if (action) {
+ curl_formadd (&form, &last, CURLFORM_COPYNAME, "action",
+ CURLFORM_COPYCONTENTS, action, CURLFORM_END);
+ curl_formadd (&form, &last, CURLFORM_COPYNAME, "searchType",
+ CURLFORM_COPYCONTENTS, action, CURLFORM_END);
+ } else {
+ perror ("No action specified.");
+ exit (1);
+ }
+ curl_formadd (&form, &last, CURLFORM_COPYNAME, "return",
+ CURLFORM_COPYCONTENTS, rettype, CURLFORM_END);
+
+
+ /* Print some debug info.
+ */
+ if (debug) {
+ fprintf (stderr, "ACTION = '%s' ret = '%s'\n", action, rettype);
+
+ curl_easy_setopt (curl, CURLOPT_VERBOSE, 1);
+ curl_easy_setopt (curl, CURLOPT_HEADER, 1);
+ }
+
+ /* Setup the output file, if we have one.
+ */
+ if (outfile) {
+ curl_easy_setopt(curl, CURLOPT_WRITEDATA, outfile);
+ curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, vot_invWrite);
+ curl_easy_setopt(curl, CURLOPT_READFUNCTION, vot_invRead);
+ }
+
+ /* Setup the call to the base URL as an HTTP/POST.
+ headerlist = curl_slist_append (headerlist, expect);
+ */
+ curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headerlist);
+
+ curl_easy_setopt (curl, CURLOPT_HTTPPOST, form);
+ curl_easy_setopt (curl, CURLOPT_URL, base_url);
+
+ /* Execute the query.
+ */
+ res = curl_easy_perform (curl);
+
+ curl_slist_free_all (headerlist);
+ }
+
+ curl_easy_cleanup (curl); /* always cleanup */
+ if (form)
+ curl_formfree (form); /* then cleanup the formpost chain */
+ if (outfile)
+ fclose (outfile);
+
+ return (action);
+}
+
+
+/*
+*/
+static void
+vot_printRegionCount (char *file, int extra)
+{
+ FILE *fd;
+ int c_ivoid=1, c_sname=2, c_title=8, c_count=11, c_nrec=10, c_desc=9;
+ int c_corr=12;
+ char title[SZ_LINE], count[SZ_LINE], corr[SZ_LINE],
+ nrec[SZ_LINE], line[SZ_LINE], desc[SZ_LINE], *s;
+
+ extern char *delim;
+
+
+ delim = "\t";
+ if ((fd = fopen (file, "r"))) {
+
+ fgets (line, SZ_LINE, fd); /* skip header */
+
+ printf ("\n");
+ while (fgets (line, SZ_LINE, fd)) {
+ strcpy (title, ((s=vot_getTableCol(line, c_title, 1))?s:" "));
+ strcpy (count, ((s=vot_getTableCol(line, c_count, 1))?s:" "));
+ strcpy (nrec, ((s=vot_getTableCol(line, c_nrec, 1))?s:" "));
+ if (extra)
+ strcpy (corr, ((s=vot_getTableCol(line, c_corr, 1))?s:" "));
+
+ if (verbose > 1) {
+ s = vot_getTableCol(line, c_sname, 1);
+ printf (" ShortName: %s\n", s);
+
+ s = vot_getTableCol(line, c_ivoid, 1);
+ printf (" Identifier: %s\n", s);
+
+ printf (" Title: "); ppMultiLine (title, 15, 64, 1024);
+ printf ("\n");
+
+ strcpy (desc, ((s=vot_getTableCol(line, c_desc, 1))?s:" "));
+ printf (" Description: "); ppMultiLine (desc, 15, 64, 1024);
+ printf ("\n");
+
+ printf (" Count: %s of %s \n", count, nrec);
+
+ if (extra)
+ printf (" Corr: %s\n", corr);
+ printf ("-------------------------------------\n");
+
+ } else {
+ s = vot_getTableCol(line, c_ivoid, 1);
+ printf (" %-20.20s %4s %s ", s, count, "C");
+
+ s = (vot_getTableCol (line, c_title, 1))?s:" ";
+ ppMultiLine (s, 35, 45, 1024);
+ if (extra)
+ printf (" (Corr=%s)", corr);
+ printf (" (NRec=%s)\n", nrec);
+ }
+
+ bzero (line, SZ_LINE);
+ }
+
+ } else {
+ fprintf (stderr, "Cannot open votable '%s'\n", file);
+ exit (1);
+ }
+}
+
+
+/*
+*/
+static void
+vot_printMatchCount (char *file)
+{
+ FILE *fd;
+ int nrows = 0;
+ char line[SZ_LINE];
+
+
+ if ((fd = fopen (file, "r"))) {
+
+ fgets (line, SZ_LINE, fd); /* skip header */
+
+ printf ("\n");
+ while (fgets (line, SZ_LINE, fd))
+ nrows++;
+ }
+
+ if (verbose > 1) {
+ printf (" ShortName: %s\n", svcList->name);
+ printf (" Identifier: %s\n", svcList->identifier);
+ printf (" Title: ");
+ ppMultiLine (svcList->title, 15, 64, 1024);
+ printf ("\n");
+ printf (" Count: %d of %d objects from '%s' matched\n",
+ nrows, nobjects, sources);
+ printf ("-------------------------------------\n");
+
+ } else {
+ printf (" %-20.20s %4d %s ",
+ svcList->name, nrows, "C");
+ ppMultiLine(svcList->title,35,45,1024);
+ printf ("\n");
+ }
+}
+
+
+
+/* Local utility functions.
+*/
+
+static size_t
+vot_invWrite (void *ptr, size_t size, size_t nmemb, FILE *stream)
+{
+ return fwrite (ptr, size, nmemb, stream);
+}
+
+static size_t
+vot_invRead (void *ptr, size_t size, size_t nmemb, FILE *stream)
+{
+ return fread(ptr, size, nmemb, stream);
+}
+
+
+static char *
+vot_dbl2str (double dval)
+{
+ static char val[SZ_LINE];
+
+ bzero (val, SZ_LINE);
+ sprintf (val, "%f", dval);
+
+ return (val);
+}
+
+#endif
diff --git a/vendor/voclient/voapps/lib/voKML.c b/vendor/voclient/voapps/lib/voKML.c
new file mode 100644
index 00000000..23fd509f
--- /dev/null
+++ b/vendor/voclient/voapps/lib/voKML.c
@@ -0,0 +1,543 @@
+/************************************************************************
+** VOKML.C -- Utility procedures for writing Google KML files.
+**
+** M. Fitzpatrick, NOAO, July 2007
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/ipc.h>
+#include <sys/sem.h>
+#include <math.h>
+#include "VOClient.h"
+#include "voAppsP.h"
+
+
+extern int format, debug, errno, extract;
+extern int kml_max, kml_sample, kml_region, kml_label, kml_verbose;
+extern int kml_bySvc, kml_byObj, kml_byBoth;
+
+extern Service *svcList;
+extern Object *objList;
+
+void vot_initKML (FILE *fd, svcParams *pars);
+void vot_printKMLPlacemark (FILE *fd, char *id, double ra,
+ double dec, char *line, char *acref, svcParams *pars);
+void vot_mkPlaceDescr (FILE *fd, char *line, char *acref, svcParams *pars);
+void vot_closeKML (FILE *fd);
+
+void vot_concatKML (char *fname);
+void vot_concatKMLByService (FILE *fd);
+void vot_concatKMLByObject (FILE *fd);
+void vot_cleanKML ();
+int vot_copyKMLFile (char *root, char *sname, FILE *fd);
+
+char *vot_getSName (char *root);
+char *vot_getOName (char *root);
+
+
+
+/************************************************************************
+** INITKML -- Initialize the KML output file header.
+*/
+void
+vot_initKML (FILE *fd, svcParams *pars)
+{
+ float x = pars->ra - 180.0, /* query center coords */
+ y = pars->dec;
+ float llx, lly, urx, ury; /* bounding region box */
+
+
+ if (!fd)
+ return;
+
+ /* Compute the bounding box, remember the cos(delta) term so the
+ ** box scales properly.
+ */
+ llx = pars->ra - (pars->sr / cos(( y * M_PI / 180.0))) - 180.0,
+ lly = pars->dec - pars->sr,
+ urx = pars->ra + (pars->sr / cos(( y * M_PI / 180.0))) - 180.0,
+ ury = pars->dec + pars->sr;
+
+
+ fprintf (fd, "<kml xmlns=\"http://earth.google.com/kml/2.2\" ");
+ fprintf (fd, " hint=\"target=sky\">\n");
+ fprintf (fd, "<Document>\n");
+ fprintf (fd, " <Style id=\"VO-CLI-Query\">\n");
+ fprintf (fd, " <BalloonStyle>\n");
+ fprintf (fd, " <text><center><b>$[name]</b></center><br/>");
+ fprintf (fd, "$[description]</text>\n");
+ fprintf (fd, " </BalloonStyle>\n");
+ fprintf (fd, " <PolyStyle>\n");
+ fprintf (fd, " <color>ffffffff</color><fill>0</fill>\n");
+ fprintf (fd, " </PolyStyle>\n");
+ fprintf (fd, " </Style>\n");
+ fprintf (fd, " <Placemark>\n");
+ fprintf (fd, " <visibility>1</visibility>\n");
+ fprintf (fd, " <flyToView>1</flyToView>\n");
+ if (pars->oname[0])
+ fprintf (fd, " <name>%s</name>\n", pars->oname);
+ else
+ fprintf (fd, " <name>Query Center</name>\n");
+
+ fprintf (fd, " <description>\n");
+ fprintf (fd, " <![CDATA[VO-CLI Query parameters:\n");
+ fprintf (fd, " <table>\n");
+ fprintf (fd, " <tr><td><b>Service Name:</b></td><td>%s</td></tr>\n",
+ pars->name);
+ fprintf (fd, " <tr><td><b>Object Name:</b></td><td>%s</td></tr>\n",
+ pars->oname);
+ fprintf (fd, " <tr><td><b>Right Ascension:</b></td><td>%f</td></tr>\n",
+ (float)pars->ra - 180.0);
+ fprintf (fd, " <tr><td><b>Declination:</b></td><td>%f</td></tr>\n",
+ (float)pars->dec);
+ fprintf (fd, " <tr><td><b>Size:</b> </td><td>%.2f Deg</td></tr>\n",
+ pars->sr);
+ fprintf (fd, " </tr>\n");
+ fprintf (fd, " </table>\n");
+ fprintf (fd, " ]]>\n");
+
+ fprintf (fd, " </description>\n");
+ fprintf (fd, " <styleUrl>#VO-CLI-Query</styleUrl>\n");
+ fprintf (fd, " <Point><coordinates>%f,%f,0</coordinates></Point>\n",
+ x, y);
+
+
+ if (kml_region) {
+ fprintf (fd, " <Polygon><outerBoundaryIs><LinearRing>\n");
+ fprintf (fd, " <fill>0</fill>\n");
+ fprintf (fd, " <coordinates>\n");
+ fprintf (fd, " %f,%f,0\n", llx, lly);
+ fprintf (fd, " %f,%f,0\n", llx, ury);
+ fprintf (fd, " %f,%f,0\n", urx, ury);
+ fprintf (fd, " %f,%f,0\n", urx, lly);
+ fprintf (fd, " %f,%f,0\n", llx, lly);
+ fprintf (fd, " </coordinates>\n");
+ fprintf (fd, " </LinearRing></outerBoundaryIs></Polygon>\n");
+ }
+ fprintf (fd, " </Placemark>\n");
+}
+
+
+/************************************************************************
+** PRINTKMLPLACEMARK -- Write a placemark for the given point to the KML
+** file.
+*/
+void
+vot_printKMLPlacemark (FILE *fd, char *id, double ra, double dec,
+ char *line, char *acref, svcParams *pars)
+{
+ double x = ra - 180.0, /* Neet to convert to lat/lon */
+ y = dec;
+
+ if (!fd)
+ return;
+
+ fprintf (fd, " <Placemark>\n");
+ if (kml_label)
+ fprintf (fd, " <name>%s</name>\n", id);
+
+ fprintf (fd, " <styleUrl>#randomIcon</styleUrl>\n");
+
+ if (kml_verbose) {
+ fprintf (fd, " <description>\n");
+ vot_mkPlaceDescr (fd, line, acref, pars);
+ fprintf (fd, " </description>\n");
+ }
+
+ fprintf (fd, " <Point> <coordinates>%f,%f,0</coordinates> </Point>\n",
+ x, y);
+ fprintf (fd, " </Placemark>\n");
+}
+
+
+/************************************************************************
+** MKPLACEDESCR -- Make a placemark description from the query result.
+** We assume the 'line' is a header line and a data row; use this to make
+** a keyw/value table
+*/
+void
+vot_mkPlaceDescr (FILE *fd, char *line, char *acref, svcParams *pars)
+{
+ char *ip, *hp, *dp, *vp, delim, val[SZ_LINE];
+ extern char *toSexa (double pos);
+
+
+ if (!fd || !line)
+ return;
+
+ for (dp=line; *dp != '\n'; dp++) /* get the data line */
+ ;
+ dp++;
+ hp = line; /* get the header line */
+
+
+ delim = ((format == F_CSV) ? ',' :
+ ((format == F_TSV) ? '\t' :
+ ((format == F_ASCII) ? ' ' : ',')));
+
+
+ fprintf (fd, "<![CDATA[");
+ fprintf (fd, "<font size=\"+1\" color=\"#a00\">");
+ fprintf (fd, "<b>Resource:&nbsp; %s&nbsp;&nbsp;&nbsp;", pars->name);
+ fprintf (fd, "Object:&nbsp; %s&nbsp;&nbsp;&nbsp;\n", pars->oname);
+ fprintf (fd, "RA:&nbsp; %s&nbsp;&nbsp;&nbsp;\n", toSexa(pars->ra / 15.0));
+ fprintf (fd, "Dec:&nbsp; %s</b>\n", toSexa(pars->dec));
+ fprintf (fd, "</font>\n");
+ fprintf (fd, "<table border=\"1\" height=\"20\">\n");
+ fprintf (fd, "<tr>");
+
+ for (ip=hp; *ip; ) {
+ bzero (val, SZ_LINE);
+ for (vp=val; *ip && *ip != '\n' && *ip != delim; )
+ *vp++ = *ip++;
+ fprintf (fd, "<th>%s</th>", val);
+ if (!*ip || *ip == '\n')
+ break;
+ else if (*ip)
+ ip++;
+ }
+
+ fprintf (fd, "\n</tr><tr>\n");
+
+ for (ip=dp; *ip; ) {
+ bzero (val, SZ_LINE);
+ for (vp=val; *ip && *ip != delim; )
+ *vp++ = *ip++;
+ ip++;
+ fprintf (fd, "<td>%s</td>", val);
+ }
+
+ fprintf (fd, "</tr></table>\n");
+
+ if (acref[0] && (strstr(line,"image/g") || strstr(line,"image/j"))) {
+ fprintf (fd, "<hr noshade=\"5\"><font size=\"+1\">");
+ fprintf (fd, "Preview Image</font><br>\n");
+ fprintf (fd, "<img src=\"%s\" ", acref);
+ fprintf (fd, "width=\"300\" height=\"300\">\n");
+ } else if (acref[0] && (strstr(line,"image/fits"))) {
+ fprintf (fd, "<hr noshade=\"5\"><font size=\"+1\">");
+ fprintf (fd, "Preview Image Not Available</font><br>\n");
+ }
+
+
+ fprintf (fd, "]]>\n");
+}
+
+
+/************************************************************************
+** CLOSEKML -- Close the KML output file.
+*/
+void
+vot_closeKML (FILE *fd)
+{
+ if (!fd)
+ return;
+
+ fprintf (fd, "</Document>\n</kml>\n");
+ fclose (fd);
+}
+
+
+/************************************************************************
+** CONCATKML -- Concatenate the KML file generated by the query into a
+** single, hierarchical document grouped either by the service, the
+** object/position (default), or both.
+*/
+void
+vot_concatKML (char *fname)
+{
+ FILE *fd = (FILE *) NULL;
+ extern int nservices, nobjects;
+
+
+ if (fname[0] == '-')
+ fd = stdout;
+ else if ((fd = fopen (fname, "w+")) == (FILE *) NULL) {
+ fprintf (stderr, "ERROR: Cannot open KML file: '%s'\n", fname);
+ return;
+ }
+
+ /* Write the preamble to the file.
+ */
+ fprintf (fd, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
+ fprintf (fd, "<kml xmlns=\"http://earth.google.com/kml/2.2\" ");
+ fprintf (fd, " hint=\"target=sky\">\n"),
+ fprintf (fd, "<Folder id=\"Root\">\n");
+
+ fprintf (fd, " <Style id=\"randomIcon\">\n");
+ fprintf (fd, " <IconStyle>\n");
+ fprintf (fd, " <color>ffffffff</color>\n");
+ fprintf (fd, " <colorMode>random</colorMode>\n");
+ fprintf (fd, " <scale>1.2</scale>\n");
+ fprintf (fd, " <Icon>\n");
+ fprintf (fd,
+ " <href>http://maps.google.com/mapfiles/kml/paddle/ylw-blank.png</href>\n");
+ fprintf (fd, " </Icon>\n");
+ fprintf (fd, " </IconStyle>\n");
+ fprintf (fd, " </Style>\n");
+ fprintf (fd, " <open>1</open>\n");
+
+ if (nservices > 1 && nobjects > 1) {
+ if (kml_byObj) {
+ fprintf (stderr, "concat by Object\n");
+ vot_concatKMLByObject (fd);
+
+ } else if (kml_bySvc) {
+ vot_concatKMLByService (fd);
+
+ } else if (kml_byBoth) {
+ fprintf (fd, " <Folder id=\"byObj\">\n");
+ fprintf (fd, " <name>By Object</name>\n");
+ fprintf (fd, " <open>0</open>\n");
+ vot_concatKMLByObject (fd);
+ fprintf (fd, " </Folder>\n");
+
+ fprintf (fd, " <Folder id=\"bySvc\">\n");
+ fprintf (fd, " <name>By Service</name>\n");
+ fprintf (fd, " <open>0</open>\n");
+ vot_concatKMLByService (fd);
+ fprintf (fd, " </Folder>\n");
+ }
+
+ /* Clean up the intermediate files if needed.
+ */
+ if (format & F_KML || (extract & EX_KML && extract & EX_COLLECT))
+ vot_cleanKML ();
+ }
+
+ /* Write the end of the file to close it.
+ */
+ fprintf (fd, "\n</Folder>\n</kml>\n");
+
+ /* Close the file descriptors.
+ */
+ if (fd != stdout)
+ fclose (fd);
+}
+
+
+/************************************************************************
+** CONCATKMLBYOBJECT -- Concatenate the KML files for the query grouped
+** by the object/position
+*/
+void
+vot_concatKMLByObject (FILE *fd)
+{
+ Service *svc = svcList; /* the service list */
+ Proc *proc; /* process list in each service */
+ Proc *ps;
+ char sname[SZ_FNAME],
+ oname[SZ_FNAME],
+ obj[SZ_FNAME];
+
+
+ /* Loop over the "query matrix" by object. The process table will
+ ** have the same objects for each resource so we can use with the
+ ** first service's list of objects/positions.
+ */
+ for (proc=svcList->proc; proc; proc=proc->next) {
+ bzero (oname, SZ_FNAME);
+ strcpy (oname, vot_getOName (proc->root));
+
+ fprintf (fd, " <Folder id=\"o_%s\">\n", oname);
+ fprintf (fd, " <name>%s</name>\n", oname);
+ fprintf (fd, " <open>0</open>\n");
+
+ /* Go through the list of services to find this object. This is
+ ** known to be somewhat inefficient for the moment, but we don't
+ ** expect the query matrix to be large, and if it is this is still
+ ** a small overhead compared to the queries.
+ */
+ for (svc=svcList; svc; svc=svc->next) {
+
+ for (ps=svc->proc; ps; ps=ps->next) {
+ bzero (obj, SZ_FNAME);
+ strcpy (obj, vot_getOName (ps->root));
+
+ if (strcmp (oname, obj) == 0) {
+ bzero (sname, SZ_FNAME);
+ strcpy (sname, vot_getSName (svc->proc->root));
+
+ if (debug) {
+ fprintf (stderr, "\t\t%s.%s\t%s\n",
+ oname, sname, ps->root);
+ }
+
+ /* At this point we have the following:
+ **
+ ** oname - name of object we using to group
+ ** sname - name of the service we're processing
+ ** ps->root - name of root file associated w/ result
+ **
+ ** The job now is simply to concatenate any KML file onto
+ ** the final output.
+ */
+
+ vot_copyKMLFile (ps->root, sname, fd);
+ break;
+ }
+ }
+ }
+ fprintf (fd, " </Folder>\n");
+ }
+
+ return;
+}
+
+
+/************************************************************************
+** CONCATKMLBYSERVICE -- Concatenate the KML files for the query grouped
+** by the data service.
+*/
+void
+vot_concatKMLByService (FILE *fd)
+{
+ Service *svc = svcList; /* the service list */
+ Proc *proc; /* process list in each service */
+ char sname[SZ_FNAME];
+ char oname[SZ_FNAME];
+
+
+ for (svc=svcList; svc; svc=svc->next) {
+
+ bzero (sname, SZ_FNAME);
+ strcpy (sname, vot_getSName (svc->proc->root));
+
+ fprintf (fd, " <Folder id=\"o_%s\">\n", sname);
+ fprintf (fd, " <name>%s</name>\n", sname);
+ fprintf (fd, " <open>0</open>\n");
+
+ for (proc=svc->proc; proc; proc=proc->next) {
+ bzero (oname, SZ_FNAME);
+ strcpy (oname, vot_getOName (proc->root));
+ vot_copyKMLFile (proc->root, oname, fd);
+ }
+
+ fprintf (fd, " </Folder>\n");
+ }
+
+ return;
+}
+
+
+
+/************************************************************************
+** Utility routines to extract bits from the root filename.
+*/
+char *
+vot_getSName (char *root)
+{
+ char *ip, *op;
+ static char val[SZ_FNAME];
+
+ bzero (val, SZ_FNAME);
+ for (ip=root, op=val; *ip && *ip != '_'; )
+ *op++ = *ip++;
+
+ return (val);
+}
+
+char *
+vot_getOName (char *root)
+{
+ char *ip, *op;
+ static char val[SZ_FNAME];
+
+ bzero (val, SZ_FNAME);
+
+ /* skip service name and type.
+ */
+ for (ip=root; *ip && *ip != '_'; ) ip++; ip++;
+ for ( ; *ip && *ip != '_'; ) ip++; ip++;
+
+ /* get object name */
+ for (op=val; *ip && *ip != '.' && *ip != '_'; )
+ *op++ = *ip++;
+
+ return (val);
+}
+
+
+/************************************************************************
+** COPYKMLFILE -- Copy a KML file to the output file descriptor for inclusion
+** in a grander hierarchy. To do this we copy out only the inner part of
+** the <Document> in a single file.
+*/
+int
+vot_copyKMLFile (char *root, char *name, FILE *fd)
+{
+ char line[4096], fname[SZ_FNAME];
+ FILE *ifd;
+
+
+ bzero (fname, SZ_FNAME);
+ sprintf (fname, "%s.kml", root);
+
+ if (access (fname, R_OK) == 0) {
+ if ((ifd = fopen (fname, "r")) == (FILE *) NULL) {
+ fprintf (stderr, "Warning: Cannot open file '%s'\n", fname);
+ return (ERR);
+ }
+ } else {
+ /* A missing file just means there's no data, but we want to
+ ** reflect that in the file as an empty folder.
+ */
+ return (OK);
+ }
+
+ fprintf (fd, " <Folder id=\"s_%s\">\n", name);
+ fprintf (fd, " <name>%s</name>\n", name);
+ fprintf (fd, " <open>0</open>\n");
+ fprintf (fd, " <flyToView>1</flyToView>\n");
+ fprintf (fd, " <styleUrl>#randomIcon</styleUrl>\n");
+
+ /* Skip ahead to the start of the part we're interested in.
+ */
+ bzero (line, 4096);
+ while (fgets (line, 4096, ifd)) {
+ if (strstr (line, "<Document>"))
+ break;
+ bzero (line, 4096);
+ }
+
+ /* (Slow) Copy the file until the end of the Document.
+ */
+ bzero (line, 4096);
+ while (fgets (line, 4096, ifd)) {
+ if (strstr (line, "</Document>"))
+ break;
+ fprintf (fd, "%s", line);
+ bzero (line, 4096);
+ }
+
+ fprintf (fd, " </Folder>\n");
+
+ fclose (ifd);
+ return (OK);
+}
+
+
+/************************************************************************
+** CLEANKML -- Clean up the intermediate KML files.
+*/
+void
+vot_cleanKML ()
+{
+ Service *svc = svcList; /* the service list */
+ Proc *proc; /* process list in each service */
+ char fname[SZ_FNAME];
+
+
+ for (svc=svcList; svc; svc=svc->next) {
+ for (proc=svc->proc; proc; proc=proc->next) {
+ bzero (fname, SZ_FNAME);
+ sprintf (fname, "%s.kml", proc->root);
+ unlink (fname);
+
+ bzero (fname, SZ_FNAME);
+ sprintf (fname, "%s.csv", proc->root);
+ unlink (fname);
+ }
+ }
+}
diff --git a/vendor/voclient/voapps/lib/voLog.c b/vendor/voclient/voapps/lib/voLog.c
new file mode 100644
index 00000000..269340d5
--- /dev/null
+++ b/vendor/voclient/voapps/lib/voLog.c
@@ -0,0 +1,225 @@
+/**
+ * @file voLog.c
+ * @author Mike Fitzpatrick, NOAO
+ * @date 6/10/09
+ *
+ * @brief VOApps logging interface.
+ */
+/*****************************************************************************/
+
+
+#include <stdio.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+#include <pthread.h>
+#include <errno.h>
+
+#include "voApps.h"
+#include "voAppsP.h"
+
+
+#define SZ_FMTSPEC 25 /* max size single format spec */
+#define SZ_ARGVAL 128
+#define EOS 0
+
+#define TY_INT 0 /* the only types we support */
+#define TY_DOUBLE 1
+#define TY_CHAR 2
+
+
+/* Public methods.
+*/
+void vo_encodeString (char *buf, char *format, va_list *argp);
+char *vo_doarg (va_list **argp, int dtype);
+char *vo_logtime ();
+
+static char argVal[SZ_ARGVAL];
+
+
+
+/**
+ * VO_APPLOG -- VOApp message logger.
+ *
+ * @fn vo_appLog (char *format, ...)
+ *
+ * @brief VOApps message logger.
+ * @param fd logging file descriptor
+ * @param format message format string
+ * @return nothing
+ */
+void
+vo_appLog (FILE *fd, char *format, ...)
+{
+ int len;
+ char *buf;
+ va_list argp;
+
+
+ va_start (argp, format); /* encode as a single string */
+ buf = calloc (1, (4 * SZ_LINE) );
+ vo_encodeString (buf, format, &argp);
+ va_end (argp);
+
+ len = strlen (buf); /* ensure a newline */
+ if (strcmp ("\n", &buf[len-1]))
+ strcat (buf, "\n");
+
+ if (fd)
+ fprintf (fd, "%s %s", vo_logtime(), buf);
+
+ free ((void *) buf);
+}
+
+
+/**
+ * VO_ENCODESTRING -- Process the format to the output file, taking arguments
+ * from the list pointed to by argp as % format specs are encountered in
+ * the input.
+ *
+ * @fn vo_encodeString (char *buf, char *format, va_list *argp)
+ *
+ * @param buf formatted output buffer
+ * @param format format string
+ * @param argp variable-length arguments
+ * @return
+ */
+void
+vo_encodeString (char *buf, char *format, va_list *argp)
+{
+ register int ch; /* next format char reference */
+ char formspec[SZ_FMTSPEC]; /* copy of single format spec */
+ char *fsp; /* pointer into formspec */
+ char cbuf[10];
+ int done; /* one when at end of a format */
+ int nch = SZ_LINE; /* one when at end of a format */
+
+
+ while ((ch = *format++) && nch > 0) {
+ if (ch == '%') {
+ fsp = formspec;
+ *fsp++ = ch;
+ done = 0;
+
+ while (!done) {
+ ch = *fsp++ = *format++;
+
+ switch (ch) {
+ case EOS:
+ --format;
+ done++;
+ break;
+
+ case 'l':
+ fsp--; /* arg size modifier; ignored for now */
+ break;
+
+ case 'b': /* nonstandard UNIX */
+ case 'c':
+ case 'd':
+ case 'o':
+ case 'x':
+ case 'u':
+ *fsp = EOS;
+ strcat (buf, vo_doarg (&argp, TY_INT));
+ done++;
+ break;
+
+ case 'E': /* ANSI emulation */
+ *(fsp-1) = 'e';
+ goto rval;
+ case 'G': /* ANSI emulation */
+ *(fsp-1) = 'g';
+ goto rval;
+
+ case 'e':
+ case 'f':
+ case 'g':
+rval:
+ *fsp = EOS;
+ strcat (buf, vo_doarg (&argp, TY_DOUBLE));
+ done++;
+ break;
+
+ case 's':
+ *fsp = EOS;
+ strcat (buf, vo_doarg (&argp, TY_CHAR));
+ done++;
+ break;
+ }
+ }
+
+ } else {
+ memset (cbuf, 0, 10);
+ sprintf (cbuf, "%c", ch);
+ strcat (buf, cbuf);
+ }
+
+ nch = SZ_LINE - strlen (buf); /* prevent overflow */
+ }
+}
+
+
+/**
+ * VO_DOARG -- Encode a single argument acording to the data type.
+ *
+ * @fn static char *vo_doarg (va_list **argp, int dtype)
+ *
+ * @param argp argument list
+ * @param dtype data type
+ *
+ */
+char *
+vo_doarg (va_list **argp, int dtype)
+{
+ int ival;
+ double dval;
+ char *cptr;
+
+
+ memset (argVal, 0, SZ_ARGVAL);
+
+ /* Pass the data value to be encoded, bump argument pointer by the
+ ** size of the data object. If there is no data value the case
+ ** is a no-op.
+ */
+ switch (dtype) {
+ case TY_INT:
+ ival = va_arg ((**argp), int);
+ sprintf (argVal, "%d", ival);
+ break;
+ case TY_DOUBLE:
+ dval = va_arg ((**argp), double);
+ sprintf (argVal, "%g", dval);
+ break;
+ case TY_CHAR:
+ cptr = va_arg ((**argp), char *);
+ sprintf (argVal, "%s", cptr);
+ break;
+ }
+
+ return (argVal);
+}
+
+
+
+/**
+ * LOGTIME - Generate a time string for the log.
+ *
+ * @fn static char *vo_logtime()
+ */
+char *
+vo_logtime ()
+{
+ time_t t = time (NULL);
+ struct tm *tm = gmtime (&t);
+ static char tstr[128];
+
+ memset (tstr, 0, 128);
+ strftime (tstr, 128, "%m%d %T", tm);
+
+ return (tstr);
+}
diff --git a/vendor/voclient/voapps/lib/voObj.c b/vendor/voclient/voapps/lib/voObj.c
new file mode 100644
index 00000000..5915fb7e
--- /dev/null
+++ b/vendor/voclient/voapps/lib/voObj.c
@@ -0,0 +1,761 @@
+/****************************************************************************
+** VOARGS.C -- Procedures for commandline argument handling. We also do
+** some of the heavy lifting for registry and object resolution.
+**
+** M. Fitzpatrick, NOAO, June 2007
+*/
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <dirent.h>
+#include <unistd.h>
+#include <ctype.h>
+#include <string.h>
+#include <time.h>
+#include "VOClient.h"
+#include "votParse.h"
+#include "voAppsP.h"
+
+
+#define OBJ_DEBUG 0 /* local debug options */
+
+
+extern int nobjects, nservices;
+extern int verbose, quiet, debug, errno, force_svc, meta;
+extern int all_data, use_name, all_named, url_proc, obj_list;
+extern int force_read, table_hskip, table_nlines, table_sample;
+extern char *typestr, *bpass, *delim, *cols, *ecols, *output;
+
+extern Object *objList, *objTail;
+
+int objIndex = 0;
+
+int ra_col = 1; /* input table RA column default */
+int ra_span = 1; /* input table RA column span */
+int dec_col = 2; /* input table Dec column default */
+int dec_span = 1; /* input table Dec column span */
+int id_col = 0; /* input table ID column (0 => none) */
+int id_span = 0; /* input table ID column span */
+
+
+int vot_parseObjectList (char *list, int isCmdLine);
+int vot_printObjectList (FILE *fd);
+void vot_freeObjectList (void);
+void vot_readObjFile (char *fname);
+
+static int vot_objectResolver (char *idlist, int nwords, int isCmdLine);
+static int vot_loadVOTable (char *fname);
+static int vot_countWords (FILE *fd);
+static int vot_parseCmdLineObject (char *idlist);
+static void vot_getColumns ();
+
+static char *vot_parseTableLine (char *idlist, int nwords,
+ double *ra, double *dec);
+
+extern char *vot_copyStdin (void);
+extern char *vot_getTableCol (char *line, int col, int span);
+extern char *toSexa (double val);
+extern char *strcasestr ();
+extern char *vot_normalize (char *str);
+extern char *vot_normalizeCoord (char *coord);
+extern char *vot_mktemp (char *root);
+extern char *vot_getTableCell (int vot, int row, int col);
+
+extern int isVOTable (char *fname);
+extern void vot_skipHdr (FILE *fd);
+
+
+/* Utility procedures.
+*/
+extern int isSexagesimal (char *str);
+extern int isDecimal (char *str);
+extern float sexa (char *s);
+extern char *toSexa (double pos);
+extern char *toSexaTime (int nsec);
+
+
+
+
+/****************************************************************************
+** Parse a string containing object names or positions. The string may be a
+** single object, a comma-delimited list, or the name of a file containing
+** the same. Additionally, values positions specified as either sexagesimal
+** or decimal RA/Dec (assumed J2000). Positions may be whitespace or
+** comma-delimited.
+*/
+int
+vot_parseObjectList (char *list, int isCmdLine)
+{
+ FILE *fd;
+ char line[SZ_LINE];
+ int i, nl = 1, nwords;
+
+
+ if (access (list, R_OK) == 0) {
+
+ if (isVOTable (list)) {
+ nl = vot_loadVOTable (list);
+ return (0);
+ }
+
+ /* Process the file contents.
+ */
+ if ((fd = fopen (list, "r")) == (FILE *) NULL) {
+ fprintf (stderr, "ERROR: Cannot open file '%s'\n", list);
+ return (1);
+ }
+
+ /* Count the number of words (tokens) on each line of the list.
+ */
+ vot_skipHdr (fd);
+ if ((nwords = vot_countWords (fd)) < 0 && !force_read) {
+ fprintf (stderr,
+ "ERROR: Can't parse object/position table '%s' ", list);
+ fprintf (stderr, "(Variable number of columns).\n");
+ fclose (fd);
+ exit (1);
+ }
+
+ /* Parse the column description so we can properly read a table.
+ */
+ vot_getColumns ();
+ vot_skipHdr (fd); /* prepare */
+
+ while (fgets (line, SZ_LINE, fd)) { /* do it */
+
+ /* Resolve the object name.
+ */
+ vot_objectResolver (line, nwords, FALSE);
+
+ /* Enforce the max number of lines to read.
+ */
+ if (table_nlines > 0 && nl >= table_nlines)
+ break;
+ else
+ nl++;
+
+ /* Enforce the table sampling.
+ */
+ if (table_sample > 1) {
+ for (i=1; i < table_sample; i++) {
+ if (fgets (line, SZ_LINE, fd) == (char *)NULL)
+ break;
+ }
+ }
+ }
+
+ fclose (fd);
+ use_name = 0;
+
+ } else
+ vot_objectResolver (list, 1, isCmdLine);
+
+
+ if (debug)
+ vot_printObjectList (stderr);
+ if (obj_list) {
+ FILE *fd;
+ char listfile[SZ_FNAME];
+
+ memset (listfile, 0, SZ_FNAME);
+ sprintf (listfile, "%s.objects", output);
+ if ((fd = fopen (listfile, "w+")) != (FILE *) NULL) {
+ vot_printObjectList (fd);
+ fclose (fd);
+ }
+ }
+
+ return (0);
+}
+
+
+/****************************************************************************
+** LOADVOTABLE -- Read a VOTable and load the Object list with its contents.
+*/
+static int
+vot_loadVOTable (char *fname)
+{
+ int vot = 0, i;
+ int nr, nc, nresults = 0, nwords = 0;
+ int c_ra, c_dec, c_id;
+ char ra[SZ_FNAME], dec[SZ_FNAME], id[SZ_FNAME];
+ char buf[SZ_LINE];
+
+
+ if ((vot = vot_openVOTABLE (fname)) ) {
+
+ int res, tab, data, tdata;
+
+ res = vot_getRESOURCE (vot); /* get handles */
+ if ((tab = vot_getTABLE (res)) <= 0)
+ return (-1);
+ if ((data = vot_getDATA (tab)) <= 0)
+ return (-1);
+ if ((tdata = vot_getTABLEDATA (data)) <= 0)
+ return (-1);
+ nr = vot_getNRows (tdata);
+ nc = vot_getNCols (tdata);
+
+ c_ra = vot_colByUCD (tab, "POS_EQ_RA_MAIN", "pos.eq.ra");
+ c_dec = vot_colByUCD (tab, "POS_EQ_DEC_MAIN", "pos.eq.dec");
+ c_id = vot_colByUCD (tab, "ID_MAIN", "meta.id");
+ if (OBJ_DEBUG)
+ fprintf (stderr, "%d rows x %d cols ra:%d dec:%d id:%d\n",
+ nr, nc, c_ra, c_dec, c_id);
+
+ for (i=0; i < nr; i++) {
+ bzero (ra, SZ_FNAME);
+ strcpy (ra, vot_getTableCell(vot, i, c_ra));
+
+ bzero (dec, SZ_FNAME);
+ strcpy (dec, vot_getTableCell(vot, i, c_dec));
+
+ if (c_id >= 0) {
+ bzero (id, SZ_FNAME);
+
+ strcpy (id, vot_getTableCell(vot, i, c_id));
+ nwords = 3;
+ } else
+ nwords = 2;
+
+ if (OBJ_DEBUG)
+ fprintf (stderr, "%d: ra:%s dec:%s id:%s\n", i, ra, dec, id);
+
+ /* Build up a fake line of input containing the RA/Dec/ID on
+ ** a line. We do it this way so the normalize() procedures
+ ** don't overwrite a string.
+ */
+ bzero (buf, SZ_LINE);
+ strcpy (buf, vot_normalizeCoord (ra));
+ strcat (buf, " ");
+ strcat (buf, vot_normalizeCoord (dec));
+ strcat (buf, " ");
+ strcat (buf, (c_id >= 0 ? vot_normalize (id) : ""));
+
+ if (OBJ_DEBUG) fprintf (stderr, "resolve buf = '%s'\n", buf);
+
+ vot_objectResolver (buf, nwords, FALSE);
+ nresults++;
+ }
+ } else {
+ fprintf (stderr, "Cannot open votable '%s'\n", fname);
+ exit (1);
+ }
+
+ if (vot > 0)
+ vot_closeVOTABLE (vot);
+
+ return (nresults);
+}
+
+
+/****************************************************************************
+** GETCOLUMNS -- Parse the column description parameter to figure out how
+** to read a table properly. We only allow for ra/dec/id and the default is
+** that the 'id' column is not present (col=0). Otherwise, columns are
+** given as a comma-delimited, one-indexed list of integers. A range may
+** be specified to span multiple columns for reading e.g. multi-word ID tags
+** or whitespace-delimited sexagesimal.
+*/
+
+static void
+vot_getColumns ()
+{
+ char *ip = cols, *op, ra_c[SZ_FNAME], dec_c[SZ_FNAME], id_c[SZ_FNAME];
+ int first, last;
+
+
+ ip = (ecols ? ecols : cols);
+
+ bzero (ra_c, SZ_FNAME); /* get RA column */
+ for (op=ra_c; *ip && *ip != ','; )
+ *op++ = *ip++;
+ if (*ip) ip++;
+
+ bzero (dec_c, SZ_FNAME); /* get Dec column */
+ for (op=dec_c; *ip && *ip != ','; )
+ *op++ = *ip++;
+ if (*ip) ip++;
+
+ bzero (id_c, SZ_FNAME); /* get ID column */
+ if (*ip) {
+ for (op=id_c; *ip; )
+ *op++ = *ip++;
+ }
+
+
+ /* Now parse each of the column strings and create the col/span values.
+ */
+ if ((ip = strchr (ra_c, (int)'-'))) { /* set RA columns */
+ *ip++ = '\0';
+ first = ra_col = atoi (ra_c);
+ last = atoi (ip);
+ ra_span = (last - first + 1);
+ } else {
+ ra_col = atoi (ra_c);
+ ra_span = 1;
+ }
+
+ if ((ip = strchr (dec_c, (int)'-'))) { /* set Dec columns */
+ *ip++ = '\0';
+ first = dec_col = atoi (dec_c);
+ last = atoi (ip);
+ dec_span = (last - first + 1);
+ } else {
+ dec_col = atoi (dec_c);
+ dec_span = 1;
+ }
+
+ if (id_c[0]) {
+ if ((ip = strchr (id_c, (int)'-'))) { /* set ID columns */
+ *ip++ = '\0';
+ first = id_col = atoi (id_c);
+ last = atoi (ip);
+ id_span = (last - first + 1);
+ } else {
+ id_col = atoi (id_c);
+ id_span = 1;
+ }
+ }
+
+ if (OBJ_DEBUG) {
+ fprintf (stderr, "ra_c='%s' dec_c='%s' id_c='%s'\n",ra_c,dec_c,id_c);
+ fprintf (stderr, " ra: col=%d span=%d\n", ra_col, ra_span);
+ fprintf (stderr, " dec: col=%d span=%d\n", dec_col, dec_span);
+ fprintf (stderr, " id: col=%d span=%d\n", id_col, id_span);
+ }
+}
+
+
+/****************************************************************************
+** Free the service list and reset the counter.
+*/
+void
+vot_freeObjectList ()
+{
+ Object *cur, *next;
+
+ for (cur=objList; cur; cur=next) {
+ next = cur->next;
+ if (cur)
+ free ((void *) cur);
+ }
+ nobjects = 0;
+ objList = objTail = (Object *) NULL;
+}
+
+
+/****************************************************************************
+** Resolve a service name/list to the proper service URL and store the
+** result in the 'objList' global which we assume is declared in the caller.
+*/
+static int
+vot_objectResolver (char *idlist, int nwords, int isCmdLine)
+{
+ char *id = (char *)NULL, *name = (char *)NULL, *ip;
+ double ra, dec;
+ Object *obj;
+ Sesame sesame;
+
+
+ /* The task was originally written to allow comma-delimieted objects
+ ** to be specified on the command line, or as multiple objects in a
+ ** file. To preserve this functionality we'll call the old code when
+ ** given a command-line argument, otherwise we'll parse the file
+ ** according to more strict rules below.
+ */
+ if (isCmdLine) {
+ return ((int)vot_parseCmdLineObject (idlist));
+ }
+
+
+ /* If there is only a single item on the line then it can only be either
+ ** the name of a file to be processed, or an object to be resolved.
+ */
+ if (nwords == 1) {
+
+ if (access (idlist, R_OK) == 0) { /* file */
+ vot_parseObjectList (idlist, FALSE);
+ return (OK);
+
+ } else { /* resolve name */
+ /* Clobber the newline and do a poor-man's URL encoding of
+ ** embedded spaces.
+ */
+ for (ip=idlist; *ip; ip++) {
+ /* preserve spaces..... */
+ if (*ip == ' ') *ip = '+';
+ if (*ip == '\n') *ip = '\0';
+ }
+
+ sesame = voc_nameResolver (idlist);
+ ra = voc_resolverRA (sesame);
+ dec = voc_resolverDEC (sesame);
+ name = idlist;
+
+ /* If the positions are zero, make sure the errs are also zero
+ ** before deciding that the resolver failed. We won't bother
+ ** with this object but will print a warning.
+ */
+ if (ra == 0.0 && dec == 0.0) {
+ if (voc_resolverRAErr (sesame) == 0.0 &&
+ voc_resolverDECErr (sesame) == 0.0) {
+ fprintf (stderr,
+ "Warning: Cannot resolve '%s'....skipping\n", name);
+ return (ERR);
+ }
+ } else
+ all_named = 1;
+ }
+
+ if (verbose && id && !quiet) {
+ fprintf (stderr,"# Resolver: %-20s -> ", (name ? name : "(none)"));
+ fprintf (stderr," %11.11s", toSexa(ra));
+ fprintf (stderr," %12.12s", toSexa(dec));
+ fprintf (stderr,"\n");
+ }
+
+ } else {
+
+ /* The line represents a table of some kind. In the simplest form
+ ** this could just be the RA/Dec in a 2-column list but it could
+ ** also be a CSV file where the 'cols' parameter tell us where to
+ ** find the values. The 'id' string may be optional in the table,
+ ** if not specified we'll make something up.
+ */
+ id = vot_parseTableLine (idlist, nwords, &ra, &dec);
+
+ if (verbose > 1&& id && !quiet) {
+ fprintf (stderr,"# Resolver: %-16.16s", (id ? id : "(none)"));
+ fprintf (stderr," %11.11s", toSexa(ra));
+ fprintf (stderr," %12.12s", toSexa(dec));
+ fprintf (stderr,"\n");
+ }
+
+ if (OBJ_DEBUG)
+ fprintf (stderr, "ra=%f dec=%f id='%s'\n", ra, dec, (id?id:"null"));
+ }
+
+ /* Save results in the object list.
+ */
+ obj = (Object *)calloc (1,sizeof(Object));
+ if (!objList)
+ objList = objTail = obj;
+ else
+ objTail->next = (Object *)obj;
+
+ strcpy (obj->name, (name ? name : ""));
+ strcpy (obj->id, (id ? id : ""));
+ obj->ra = ra;
+ obj->dec = dec;
+ obj->index = objIndex++;
+
+ objTail = obj;
+
+
+ return (OK);
+}
+
+
+/****************************************************************************
+** PARSETABLELINE -- Parse a line of table input to extract the values for
+** the given ra/dec/id columns. Values that span multiple columns are
+** concatenated to a single space-delimited string.
+*/
+static char *
+vot_parseTableLine (char *idlist, int nwords, double *ra, double *dec)
+{
+ char *id = (char *) NULL, *sra = (char *) NULL, *sdec = (char *) NULL;
+
+
+
+ if (ecols == (char *)NULL && nwords == 3) {
+ /* No user-specified columns, see if we can figure it out.
+ */
+ char *c1 = calloc (1, SZ_LINE);
+ char *c2 = calloc (1, SZ_LINE);
+ char *c3 = calloc (1, SZ_LINE);
+
+ strcpy (c1, vot_getTableCol (idlist, 1, 1));
+ strcpy (c2, vot_getTableCol (idlist, 2, 1));
+ strcpy (c3, vot_getTableCol (idlist, 3, 1));
+
+ if ( (strchr(c1,(int)'.') && strchr(c2,(int)'.')) ||
+ (strchr(c1,(int)':') && strchr(c2,(int)':')) ) {
+
+ /* ID is column 3 */
+ sra = strdup (vot_normalizeCoord (c1));
+ sdec = strdup (vot_normalizeCoord (c2));
+ id = vot_normalize (c3);
+
+ } else if ( (strchr(c2,(int)'.') && strchr(c3,(int)'.')) ||
+ (strchr(c2,(int)':') && strchr(c3,(int)':')) ) {
+
+ /* ID is column 1 */
+ id = vot_normalize (c1);
+ sra = strdup (vot_normalizeCoord (c2));
+ sdec = strdup (vot_normalizeCoord (c3));
+
+ } else {
+ fprintf (stderr, "ERROR: Unable to parse table colummns\n");
+ *ra = *dec = 0.0;
+ free (c1); free (c2); free (c3);
+ return ((char *)NULL);
+ }
+ *ra = (strchr (sra, (int)':') ? (sexa (sra) * 15.) : atof (sra));
+ *dec = (strchr (sdec, (int)':') ? sexa (sdec) : atof (sdec));
+
+ free (c1); free (c2); free (c3);
+ free (sra); free (sdec);
+
+ } else {
+ sra = vot_normalizeCoord (vot_getTableCol (idlist, ra_col, ra_span));
+ *ra = (strchr (sra, (int)':') ? (sexa (sra) * 15.) : atof (sra));
+
+ sdec = vot_normalizeCoord (vot_getTableCol (idlist, dec_col, dec_span));
+ *dec = (strchr (sdec, (int)':') ? sexa (sdec) : atof (sdec));
+
+ if (nwords == 3 && id_col == 0)
+ id = vot_normalize (vot_getTableCol (idlist, 3, 1));
+ else
+ id = vot_normalize (vot_getTableCol (idlist, id_col, id_span));
+ }
+
+ return ((char *) id);
+}
+
+
+/****************************************************************************
+** Resolve a service name/list to the proper service URL and store the
+** result in the 'objList' global which we assume is declared in the caller.
+*/
+static int
+vot_parseCmdLineObject (char *idlist)
+{
+ char *ip, *op, *id, opos[SZ_LINE];
+ double ra, dec;
+ Object *obj;
+ Sesame sesame;
+ extern double sr;
+
+
+ /* Resolve the (list) of object names/positions and add them to the
+ ** service list to be processed.
+ */
+ ip = idlist;
+ while (*ip) {
+
+ /* Break up the input list into a single ID to resolve.
+ */
+ op = &opos[0];
+ bzero (opos, SZ_LINE);
+
+ /* We allow positions to be comma-delimited, but objects
+ ** list are processed individually.
+ */
+ while (*ip && *ip != '\n') {
+ if (*ip == ',') {
+ if (isDecimal(opos) || isSexagesimal(opos)) {
+ *op++ = ' '; ip++;
+ } else {
+ *ip++ = '\0';
+ break;
+ }
+ } else
+ *op++ = *ip++;
+ }
+ if (*ip && *(ip-1)) /* only advance on a position */
+ ip++;
+
+
+ /* Process the name, position or file.
+ */
+ if (access (opos, R_OK) == 0) { /* file */
+ vot_parseObjectList (opos, FALSE);
+ continue;
+
+ } if (isDecimal (opos)) { /* decimal */
+ for (op=opos; !isspace (*op); op++)
+ ;
+ ra = atof (opos);
+ dec = atof (op);
+ id = (char *) NULL;
+ all_named = 0;
+
+ } else if (isSexagesimal (opos)) { /* sexagesimal */
+ for (op=opos; !isspace (*op); op++)
+ ;
+ ra = sexa (opos) * 15.0;
+ dec = sexa (op);
+ id = (char *) NULL;
+ all_named = 0;
+
+ } else { /* resolve name */
+ char *ip = opos;
+
+ /* Clobber the newline and do a poor-man's URL encoding of
+ ** embedded spaces.
+ */
+ for (ip=opos; *ip; ip++) {
+ /* preserve spaces..... */
+ if (*ip == ' ') *ip = '+';
+ if (*ip == '\n') *ip = '\0';
+ }
+
+ sesame = voc_nameResolver (opos);
+ ra = voc_resolverRA (sesame);
+ dec = voc_resolverDEC (sesame);
+ id = opos;
+ all_named = 1;
+
+ /* If the positions are zero, make sure the errs are also zero
+ ** before deciding that the resolver failed. We won't bother
+ ** with this object but will print a warning.
+ */
+ if (ra == 0.0 && dec == 0.0) {
+ if (voc_resolverRAErr (sesame) == 0.0 &&
+ voc_resolverDECErr (sesame) == 0.0) {
+ fprintf (stderr,
+ "Warning: Cannot resolve '%s'....skipping\n", opos);
+ continue;
+ }
+ }
+ }
+
+ if (verbose && id && !quiet)
+ fprintf (stderr,"# Resolver: %-20s -> %-10.10s %.6f %.6f (%.2f)\n",
+ opos, (id ? id : "(none)"), ra, dec, (float)sr);
+
+ /* Save results in the object list.
+ */
+ obj = (Object *)calloc (1,sizeof(Object));
+ if (!objList)
+ objList = objTail = obj;
+ else
+ objTail->next = (Object *)obj;
+
+ strcpy (obj->name, (id ? id : ""));
+ obj->ra = ra;
+ obj->dec = dec;
+ obj->index = objIndex++;
+
+ objTail = obj;
+ }
+
+ return (0);
+}
+
+
+/****************************************************************************
+** Utility routines to print and count the object list.
+*/
+
+int
+vot_countObjectList ()
+{
+ register int i = 0;
+ Object *obj = objList;
+
+ if (!obj)
+ return (0);
+ else
+ while ((obj = obj->next)) i++;
+
+ return (i+1);
+}
+
+
+int
+vot_printObjectList (FILE *fd)
+{
+ register int i = 0;
+ Object *obj = objList;
+
+ fprintf (fd, "# Objects queried: %d\n#\n", vot_countObjectList());
+ fprintf (fd, "# %4s\t%-12.12s\t%11.11s\t%12.12s\n",
+ "Id", "Name", "RA", "Dec");
+ do {
+ fprintf (fd, "%4d\t%-12.12s\t%11.6f\t%12.6f\n", i++,
+ obj->name, obj->ra, obj->dec);
+ } while ((obj = obj->next));
+
+ return (0);
+}
+
+
+
+/******************************************************************************
+** COUNTWORDS -- Count the number of words (tokens) on each line of the list.
+** If the number varies for each line it's likely to be a table we can't
+** handle so throw an error, otherwise assume we have a single item or
+** a consistent table. Allowed delimiters include whitespace, tabs,
+** commas or '|'. Lines beginning with a '#' are ignored.
+*/
+static int
+vot_countWords (FILE *fd)
+{
+ char *tok, *line = (char *) NULL;
+ char *sep = delim, *del = (char *) NULL;
+ int ntok = -1, last_ntok = -1;
+
+ line = malloc(4096);
+
+ while (1) {
+
+ bzero (line, 4096); /* get a line of data */
+ if (fgets (line, SZ_FNAME, fd) == (char *)NULL)
+ break;
+
+ if (line[0] == '#' || line[0] == '\n') /* skip comments/blank */
+ continue;
+
+ if (last_ntok < 0) { /* first line only */
+ del = strpbrk (line, " \t,|");
+ if (del) {
+ sep = calloc (1,16);
+ sep[0] = del[0];
+ } else
+ sep = delim;
+ }
+
+ for (ntok=0, tok=strtok(line, sep); tok; tok=strtok(NULL, sep)) {
+ if (tok[0] != '\n')
+ ntok++;
+ }
+
+ if (last_ntok >= 0 && ntok != last_ntok) {
+ free ((void *) line);
+ return (-1);
+ }
+ last_ntok = ntok;
+ }
+
+ rewind (fd);
+ free ((void *) line);
+
+ return (ntok);
+}
+
+
+void
+vot_readObjFile (char *fname)
+{
+ char tmpfile[SZ_FNAME];
+
+
+ bzero (tmpfile, SZ_FNAME);
+
+ if (strcmp (fname, "-") == 0) { /* read from stdin */
+
+ strcpy (tmpfile, vot_copyStdin ());
+
+ /* Parse the input and unlink the temp file.
+ */
+ vot_parseObjectList (tmpfile, TRUE);
+ if (access (tmpfile, R_OK) == 0)
+ unlink (tmpfile);
+
+ } else if (access (fname, R_OK) == 0)
+ vot_parseObjectList (fname, TRUE);
+}
diff --git a/vendor/voclient/voapps/lib/voParams.c b/vendor/voclient/voapps/lib/voParams.c
new file mode 100644
index 00000000..bc6869a5
--- /dev/null
+++ b/vendor/voclient/voapps/lib/voParams.c
@@ -0,0 +1,189 @@
+/**
+ * VOPARAMS.C -- Interface to manage cmdline options or library parameters.
+ *
+ * @file voParams.c
+ * @author Mike Fitzpatrick
+ * @date 7/03/12
+ *
+ * @brief Interface to manage cmdline options or library parameters.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <getopt.h>
+#include <string.h>
+#include <errno.h>
+#include "voApps.h"
+#include "voAppsP.h"
+
+
+#define MAXARGS 256
+#define SZ_ARG 128
+
+
+
+/**
+ * VO_PARAMINIT -- Initialize the task parameter vector.
+ *
+ * @brief Initialize the task parameter vector.
+ * @fn char **vo_paramInit (int argc, char *argv[])
+ *
+ * @param argc argument count
+ * @param argv argument vector
+ * @returns modified argument vector
+ */
+char **
+vo_paramInit (int argc, char *argv[], char *opts, struct option long_opts[])
+{
+ static char *pargv[MAXARGS], arg[SZ_ARG];
+ int i, j, len = 0;
+
+ memset (&pargv[0], 0, MAXARGS);
+ for (i=0; i < argc; i++) {
+ /* Make a local copy of the arg so we can modify it w/out side
+ * effects.
+ */
+ memset (arg, 0, SZ_ARG);
+ strcpy (arg, argv[i]);
+ len = strlen (arg);
+
+ if (arg[0] != '-') {
+ pargv[i] = calloc (1, strlen (arg) + 6);
+ if (strchr (argv[i], (int) '='))
+ sprintf (pargv[i], "--%s", arg);
+ else if (argv[i][len-1] == '+') {
+ arg[len-1] = '\0';
+ sprintf (pargv[i], "--%s=1", arg);
+ } else if (argv[i][len-1] == '-') {
+ arg[len-1] = '\0';
+ sprintf (pargv[i], "--%s=0", arg);
+ } else
+ sprintf (pargv[i], "%s", arg);
+
+ } else {
+ if (arg[0] == '-' && arg[1] != '-') {
+ if (arg[2] == '=') {
+ /* Argument is of the form '-f=bar' instead of the form
+ * "--foo=bar" or "--foo bar" or "foo=bar". We need to
+ * rewrite it to be acceptable to getopt_long().
+ */
+ char new[SZ_ARG];
+
+ memset (new, 0, SZ_ARG);
+ for (j=0; (char *)long_opts[j].name; j++) {
+ if ((int) long_opts[j].val == (int) arg[1]) {
+ sprintf (new, "--%s=%s",long_opts[j].name, &arg[3]);
+ memset (arg, 0, SZ_ARG);
+ strcpy (arg, new);
+ len = strlen (arg);
+ }
+ }
+
+ } else if (arg[2] != '=' && strchr (arg, (int)'=')) {
+ fprintf (stderr, "Illegal flag '%s', skipping.\n", arg);
+ continue;
+ }
+ }
+
+ pargv[i] = calloc (1, strlen (arg) + 1);
+ sprintf (pargv[i], "%s", arg);
+ }
+ }
+
+#ifdef DEBUG
+ for (i=0; i < argc; i++)
+ fprintf (stderr, "argv[%d] = '%s'\n", i, pargv[i]);
+#endif
+ return (pargv);
+}
+
+
+/**
+ * VO_PARAMNEXT -- Get the next parameter value.
+ *
+ * @brief Get the next parameter value.
+ * @fn int vo_paramNext (char *opts, struct option long_opts[],
+ * int argc, char *argv[], char *optval, int *posindex)
+ *
+ * @param opts option string
+ * @param long_opts long options struct
+ * @param argc argument count
+ * @param argv argument vector
+ * @param optval optional parameter argument
+ * @param posindex positional parameter index (0-based)
+ * @returns nothing
+ */
+int
+vo_paramNext (char *opts, struct option long_opts[], int argc, char *argv[],
+ char *optval, int *posindex)
+{
+ int ch = 0, index;
+ static int pos = 0, apos = 0;
+
+
+ apos++;
+ memset (optval, 0, SZ_FNAME);
+#ifdef USE_GETOPT_LONG
+ ch = getopt_long (argc, argv, opts, long_opts, &index);
+#else
+ ch = getopt_long_only (argc, argv, opts, long_opts, &index);
+#endif
+ if (ch >= 0) {
+ if (ch > 0 && optarg) {
+ if ((strchr (optarg, (int)'=') != 0) && (optarg[0] != '-') &&
+ (argv[apos][0] == '-' && argv[apos][1] != '-') ) {
+ fprintf (stderr,
+ "Error: invalid argument = '%s' in vot_paramNext()\n",
+ argv[apos]);
+ return (PARG_ERR);
+ } else {
+ if (optarg[0] == '-') {
+ // optind--;
+ memset (optval, 0, SZ_FNAME);
+ } else
+ strcpy (optval, optarg);
+ }
+
+ } else if (ch == 0) {
+ *posindex = index;
+ if (optarg)
+ strcpy (optval, optarg);
+ }
+
+ } else {
+ if (argv[optind+pos]) {
+ strcpy (optval, argv[optind+pos]);
+ *posindex = pos++;
+ return (-pos);
+ } else
+ return (0);
+ }
+
+#ifdef DEBUG
+ fprintf (stderr, "ch = %d (%c) optval='%s' optarg='%s' index=%d\n",
+ ch, ch, optval, optarg, index);
+#endif
+ return (ch);
+}
+
+
+/**
+ * VO_PARAMFREE -- Free the allocated parameter vector.
+ *
+ * @brief Free the allocated parameter vector.
+ * @fn void vo_paramFree (int argc, char *argv[])
+ *
+ * @param argc argument count
+ * @param argv argument vector
+ * @returns nothing
+ */
+void
+vo_paramFree (int argc, char *argv[])
+{
+ register int i;
+
+ for (i=0; i < argc; i++) {
+ if (argv[i] && argv[i][0])
+ free ((void *)argv[i]);
+ }
+}
diff --git a/vendor/voclient/voapps/lib/voRanges.c b/vendor/voclient/voapps/lib/voRanges.c
new file mode 100644
index 00000000..0c1ed608
--- /dev/null
+++ b/vendor/voclient/voapps/lib/voRanges.c
@@ -0,0 +1,286 @@
+/******************************************************************************
+** RANGES -- Simple range-specification package to decode lists of numbers
+** or ranges of the form:
+**
+** <start> '-' <end> [ 'x' <stride>]
+**
+** Sample code using this package might look like:
+**
+**
+** #include <stdlib.h>
+** #include <ctype.h>
+**
+** int vot_decodeRanges(char *str, int *ranges, int max_ranges,int *nvalues);
+** int get_next_number (int *ranges, int number);
+**
+** int main (int argc, char **argv)
+** {
+** char *rtest[] = { "1-10,12,16", "1-7x2,12-14",
+** "1,3,5,7,9-12", "1,8",
+** "12-8", "12-8x-1",
+** NULL };
+** int i, *ranges, max_ranges=100, nvalues=0, val;
+**
+** ranges = (int *) malloc (1024);
+** for (i=0; rtest[i]; i++) {
+** printf ("vot_decodeRanges: '%s'\n\n ", rtest[i]);
+** val = vot_decodeRanges (rtest[i], ranges, max_ranges, &nvalues);
+** for (val=0; (val = get_next_number (ranges, val)) > 0; )
+** printf (" %d ", val);
+** }
+** }
+**
+** Assumes ranges are positive and always increasing, i.e. a range "3-1"
+** will not return (3,2,1) but (1,2,3). Default stride is 1, open-ended
+** ranges are not permitted.
+**
+** M. Fitzpatrick, NOAO, June 2007 (Translated from IRAF xtools$ranges.x)
+**
+******************************************************************************/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <dirent.h>
+#include <unistd.h>
+#include <ctype.h>
+#include "VOClient.h"
+#include "voAppsP.h"
+
+
+#define FIRST 1 /* Default starting range */
+#define LAST MAX_INT /* Default ending range */
+#define STEP 1 /* Default step */
+#define EOLIST 0 /* End of list */
+
+#define MAX_INT 65535
+#define INDEF 65534
+/*#define ERR -1*/
+#define EOS '\0'
+#define OK 0
+
+
+static int ctoi (char *str, int *ip, int *ival);
+
+/*************************************************************************
+** DECODERANGES -- Parse a string containing a list of integer numbers or
+** ranges, delimited by either spaces or commas. Return as output a list
+** of ranges defining a list of numbers, and the count of list numbers.
+** Range limits must be positive nonnegative integers. ERR is returned as
+** the function value if a conversion error occurs. The list of ranges is
+** delimited by EOLIST.
+*/
+int
+vot_decodeRanges (range_string, ranges, max_ranges, nvalues)
+
+char *range_string; /* Range string to be decoded */
+int ranges[]; /* Range array */
+int max_ranges; /* Maximum number of ranges */
+int *nvalues; /* The number of values in the ranges */
+
+{
+ int ip, nrange, first, last, step, diff, *ra = &ranges[0];
+
+ ip = 0;
+ *nvalues = 0;
+
+ for (nrange = 0; nrange < (max_ranges - 1); nrange += 3) {
+ /* Defaults to all nonnegative integers.
+ */
+ first = FIRST;
+ last = LAST;
+ step = STEP;
+
+ /* Skip delimiters.
+ */
+ while (isspace(range_string[ip]) || range_string[ip] == ',')
+ ip++;
+
+ /* Get first limit. Must be a number, '-', 'x', or EOS.
+ ** If not return ERR.
+ */
+ if (range_string[ip] == EOS) { /* end of list */
+ if (nrange == 0) {
+ ra[0] = first; /* null string defaults */
+ ra[1] = last;
+ ra[2] = step;
+ ra[3] = EOLIST;
+ *nvalues = MAX_INT;
+ return (OK);
+ } else {
+ ra[nrange] = EOLIST;
+ return (OK);
+ }
+ } else if (range_string[ip] == '-')
+ ;
+ else if (range_string[ip] == 'x')
+ ;
+ else if (isdigit((int)range_string[ip])) { /* ,n.. */
+ if (ctoi (range_string, &ip, &first) == 0)
+ return (ERR);
+ } else
+ return (ERR);
+
+ /* Skip delimiters.
+ */
+ while (isspace(range_string[ip]) || range_string[ip] == ',')
+ ip++;
+
+ /* Get last limit. Must be '-', or 'x' otherwise last = first.
+ */
+ if (range_string[ip] == 'x')
+ ;
+ else if (range_string[ip] == '-') {
+ ip++;
+ while (isspace(range_string[ip]) || range_string[ip] == ',')
+ ip++;
+ if (range_string[ip] == EOS)
+ ;
+ else if (isdigit((int)range_string[ip])) {
+ if (ctoi (range_string, &ip, &last) == 0)
+ return (ERR);
+ } else if (range_string[ip] == 'x')
+ ;
+ else
+ return (ERR);
+ } else
+ last = first;
+
+ /* Skip delimiters
+ */
+ while (isspace(range_string[ip]) || range_string[ip] == ',')
+ ip++;
+
+ /* Get step. Must be 'x' or assume default step.
+ */
+ if (range_string[ip] == 'x') {
+ ip++;
+ while (isspace(range_string[ip]) || range_string[ip] == ',')
+ ip++;
+ if (range_string[ip] == EOS)
+ ;
+ else if (isdigit((int)range_string[ip])) {
+ if (ctoi (range_string, &ip, &step) == 0)
+ ;
+ if (step == 0)
+ return (ERR);
+ } else if (range_string[ip] == '-')
+ ;
+ else
+ return (ERR);
+ }
+
+ /* Output the range triple.
+ */
+ ra[nrange ] = first;
+ ra[nrange+1] = last;
+ ra[nrange+2] = step;
+ diff = last - first;
+ if (diff < 0)
+ diff = - (diff);
+ *nvalues = *nvalues + diff / step + 1;
+ }
+
+ return (ERR); /* ran out of space */
+}
+
+
+/* GET_NEXT_NUMBER -- Given a list of ranges and the current file number,
+** find and return the next file number. Selection is done in such a way
+** that list numbers are always returned in monotonically increasing order,
+** regardless of the order in which the ranges are given. Duplicate entries
+** are ignored. EOF is returned at the end of the list.
+*/
+int
+get_next_number (int ranges[], int number)
+{
+ int a, b, ip, first, last, step, next_number, remainder;
+
+
+ /* If number+1 is anywhere in the list, that is the next number,
+ ** otherwise the next number is the smallest number in the list which
+ ** is greater than number+1.
+ */
+ number = number + 1;
+ next_number = MAX_INT;
+
+ for (ip=0; ranges[ip] != EOLIST; ip=ip+3) {
+ a = ranges[ip];
+ b = ranges[ip + 1];
+ first = (a < b) ? a : b;
+ last = (a > b) ? a : b;
+ step = ranges[ip+2];
+ if (step == 0) {
+ fprintf (stderr, "ERROR: Step size of zero in range list");
+ return (0);
+ }
+
+ if (number >= first && number <= last) {
+ remainder = (number - first) % step;
+ if (remainder == 0)
+ return (number);
+ if ((number - remainder + step) <= last)
+ next_number = number - remainder + step;
+ } else if (first > number)
+ next_number = (next_number < first) ? next_number : first;
+ }
+
+ if (next_number == MAX_INT)
+ return (EOF);
+ else {
+ number = next_number;
+ return (number);
+ }
+}
+
+
+/* IS_IN_RANGE -- Test number to see if it is in range.
+*/
+int
+is_in_range (int ranges[], int number)
+{
+ int a, b, ip, first, last, step, num = number;
+
+ for (ip=0; ranges[ip] != EOLIST; ip += 3) {
+ a = ranges[ip];
+ b = ranges[ip + 1];
+ first = (a < b) ? a : b;
+ last = (a > b) ? a : b;
+ step = ranges[ip+2];
+ if (num >= first && num <= last)
+ if (((num - first) % step) == 0)
+ return (1);
+ }
+
+ return (0);
+}
+
+
+/* CTOI -- Simple character to integer (decimal radix) that advances the
+** character pointer (index).
+*/
+static int
+ctoi (char *str, int *ip, int *ival)
+{
+ int neg, sum, ip_start;
+
+ while (isspace (str[*ip]))
+ *ip = *ip + 1;
+ ip_start = *ip;
+
+ if ((neg = (str[*ip] == '-')))
+ *ip = *ip + 1;
+
+ sum = 0;
+ while (isdigit ((int) str[*ip])) {
+ sum = sum * 10 + (int) (str[*ip] - '0');
+ *ip = *ip + 1;
+ }
+
+ if (neg)
+ *ival = -sum;
+ else
+ *ival = sum;
+
+ return (*ip - ip_start);
+}
diff --git a/vendor/voclient/voapps/lib/voSCS.c b/vendor/voclient/voapps/lib/voSCS.c
new file mode 100644
index 00000000..d248489e
--- /dev/null
+++ b/vendor/voclient/voapps/lib/voSCS.c
@@ -0,0 +1,265 @@
+/************************************************************************
+** VOSCS.C -- Worker procedure to query a Simple Cone Search service.
+**
+** M. Fitzpatrick, NOAO, July 2007
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/ipc.h>
+#include <sys/sem.h>
+#include "VOClient.h"
+#include "voAppsP.h"
+#include "samp.h"
+
+
+extern int errno;
+extern int debug, verbose, all_named, all_data, save_res, extract, quiet;
+extern int meta, dverbose, count, count_only, file_get, use_name, format;
+extern int id_col, samp, samp_p;
+
+extern char *output;
+
+int vot_callConeSvc (svcParams *pars);
+
+extern int vot_extractResults (char *result, char delim, svcParams *pars);
+extern int vot_printCount (Query query, svcParams *pars, int *count);
+extern int vot_countResults (char *result);
+extern char vot_svcTypeCode (int type);
+extern void vot_printCountHdr (void);
+extern void vot_printCountLine (int nrec, svcParams *pars);
+extern void vot_dalExit (int code, int count);
+extern void vot_printHdr (int fd, svcParams *pars);
+
+extern void vot_printAttrs (char *fname, Query query, char *id);
+extern char *vot_normalize (char *str);
+extern char *vot_getOFName (svcParams *pars, char *extn, int pid);
+extern char *vot_getOFIndex (svcParams *pars, char *extn, int pid);
+
+
+/************************************************************************
+** VOT_CALLCONESVC -- Call a Cone Search service.
+*/
+int
+vot_callConeSvc (svcParams *pars)
+{
+ char *result = (char *)NULL;
+ char *extn, fname[SZ_LINE], delim;
+ DAL cone; /* DAL Connection handle */
+ Query query; /* Query handle */
+ pid_t cpid;
+ int fd, res_count=0, code;
+
+
+ if (debug)
+ fprintf (stderr, "coneCaller(%s:%d): ra = %f dec = %f\n",
+ pars->name, getpid(), pars->ra, pars->dec);
+
+
+ if ((cpid = fork()) < 0) {
+ fprintf (stderr,
+ "vot_callConeSvc: Unable to create child process, exiting\n");
+ vot_dalExit (-1, 0);
+
+ } else if (cpid > 0) { /* Parent process */
+ return (cpid);
+
+ } else { /* Child process */
+
+ if (getenv ("VOC_NO_NETWORK"))
+ return (OK);
+
+ /* Initialize the VOClient code. Error messages are printed by the
+ ** interface so we just quit if there is a problem.
+ */
+ if (voc_initVOClient ((char *) NULL) == ERR)
+ vot_dalExit (E_VOCINIT, 0);
+
+ /* Get a new connection to the named service and form the query.
+ if (all_data || verbose > 1)
+ */
+ cone = voc_openConeConnection (pars->service_url);
+ query = voc_getConeQuery (cone, pars->ra, pars->dec,
+ (meta ? 0.0 : pars->sr));
+ if (verbose > 1)
+ (void) voc_addIntParam (query, "VERB", (all_data ? 3 : verbose));
+
+
+ /* Execute the query.
+ */
+ if (debug) {
+ fprintf (stderr, "coneCaller(%s:%d): executing query....\n",
+ pars->name, getpid());
+ fprintf (stderr, "Executing Cone Query:\n %s\n\n",
+ voc_getQueryString (query, CONE_CONN, 0));
+ }
+
+ if (count_only) {
+/*
+ if ((code = vot_printCount (query, pars, &res_count)) != E_NONE) {
+ vot_dalExit (code, res_count);
+ }
+*/
+ code = vot_printCount (query, pars, &res_count);
+ vot_dalExit (code, res_count);
+
+ } else if (meta) {
+ bzero (fname, SZ_FNAME);
+ if (output)
+ strcpy (fname, output);
+ else
+ sprintf (fname, "%s_%c.meta", vot_normalize (pars->name),
+ vot_svcTypeCode(pars->type));
+ vot_printAttrs (fname, query, pars->identifier);
+
+ } else {
+
+ switch (pars->fmt) {
+ case F_ASCII:
+ extn = "asv", delim = ' ';
+ result = voc_executeASCII (query);
+ break;
+ case F_RAW:
+ extn = "xml", delim = '\0';
+ result = voc_executeVOTable (query);
+ break;
+ case F_RAW | F_XML:
+ extract |= EX_XML;
+ extn = "xml"; delim = '\0';
+ result = voc_executeVOTable (query);
+ break;
+ case F_CSV:
+ extn = "csv", delim = ',';
+ result = voc_executeCSV (query);
+ break;
+ case F_CSV | F_HTML:
+ extract |= EX_HTML;
+ extn = "csv", delim = ',';
+ result = voc_executeCSV (query);
+ break;
+ case F_CSV | F_KML:
+ extract |= EX_KML;
+ extn = "csv", delim = ',';
+ result = voc_executeCSV (query);
+ break;
+ case F_TSV:
+ extn = "tsv", delim = '\t';
+ result = voc_executeTSV (query);
+ break;
+ default:
+ fprintf (stderr, "coneCaller: Unknown format: %d\n", pars->fmt);
+ vot_dalExit (-1, 0);
+ }
+
+ if (!result)
+ vot_dalExit (E_NODATA, 0);
+ else if (pars->fmt != F_RAW)
+ res_count = vot_extractResults (result, delim, pars);
+ else
+ res_count = vot_countResults (result);
+
+ if (count && (!output || (output && output[0] != '-')))
+ vot_printCountLine (res_count, pars);
+#ifdef EARLY_EXIT
+ if (res_count == 0) {
+ voc_closeConnection (siap);
+ voc_closeVOClient (0);
+ if (result) free ((char *) result);
+ vot_dalExit (E_NODATA, res_count);
+ }
+#endif
+
+
+ /* Check for a NULL result indicating an error in the call.
+ */
+ if (result == (char *)NULL) {
+ char *err;
+ extern char *voc_getErrMsg();
+
+ if (strncmp ((err = voc_getErrMsg()), "ERROR", 5) == 0) {
+ if (verbose > 1)
+ fprintf (stderr, "Pid %d: %s\n", getpid(), err);
+ vot_dalExit (E_REQFAIL, res_count);
+
+ } else
+ vot_dalExit (E_NODATA, res_count);
+ }
+
+ if (all_data && pars->type == SVC_VIZIER) {
+ char *vot_urlFname (char *url);
+
+ if (output) {
+ /*
+ */
+ if (output[0] == '-')
+ strcpy (fname, vot_getOFName(pars,extn,(int)getpid()));
+ else
+ sprintf (fname, "%s_%s.%s",
+ output, vot_urlFname(pars->service_url), extn);
+
+ } else
+ sprintf (fname, "%s%s.%s",
+ vot_normalize(pars->name),
+ vot_urlFname(pars->service_url), extn);
+
+ } else if (use_name || all_named || id_col) {
+ strcpy (fname, vot_getOFName (pars, extn, (int)getpid()));
+
+ } else {
+ strcpy (fname, vot_getOFIndex (pars, extn, (int)getpid()));
+ }
+
+ if (output && output[0] == '-' && (! extract & EX_COLLECT)) {
+ write (fileno(stdout), result, strlen (result)-1);
+
+ } else if (format != (F_CSV|F_HTML) && format != (F_CSV|F_KML)) {
+
+ if ((fd = open (fname, O_WRONLY|O_CREAT, 0644)) < 0){
+ fprintf (stderr, "Error opening file '%s'\n", fname);
+ vot_dalExit (E_FILOPEN, res_count);
+ }
+
+ /* Output the result.
+ if (pars->fmt = F_CSV || pars->fmt == F_TSV)
+ vot_printHdr (fd, pars);
+ */
+ write (fd, result, strlen (result)-1);
+ close (fd);
+ }
+ }
+
+ voc_closeConnection (cone); /* close the cone connection */
+ voc_closeVOClient (0); /* close VOClient connection */
+
+ if (result) free ((void *) result); /* free local storage */
+
+ if (debug)
+ fprintf (stderr, "coneCaller(%s:%d): exiting....\n",
+ pars->name, getpid());
+
+ if (samp) {
+ char url[SZ_FNAME], cwd[SZ_FNAME];
+ extern int samp_tableLoadVOTable ();
+
+ samp_p = sampInit ("VOData", "VOClient Data Access");
+ samp_setSyncMode (samp_p);
+ sampStartup (samp_p);
+
+ memset (cwd, 0, SZ_FNAME);
+ if (getcwd (cwd, SZ_FNAME) < 0)
+ strcpy (cwd, "./");
+
+ memset (url, 0, SZ_FNAME);
+ sprintf (url, "file://%s/%s", cwd, fname);
+ (void) samp_tableLoadVOTable (samp_p, "all", url, NULL, NULL);
+
+ samp_UnRegister (samp_p);
+ }
+
+ if (res_count == 0)
+ unlink (fname);
+ vot_dalExit (0, res_count);
+ }
+
+ return (OK);
+}
diff --git a/vendor/voclient/voapps/lib/voSIAP.c b/vendor/voclient/voapps/lib/voSIAP.c
new file mode 100644
index 00000000..74506183
--- /dev/null
+++ b/vendor/voclient/voapps/lib/voSIAP.c
@@ -0,0 +1,295 @@
+/************************************************************************
+** VOSIAP.C -- Worker procedure to make a query to an SIAP service.
+**
+** M. Fitzpatrick, NOAO, July 2007
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/ipc.h>
+#include <sys/sem.h>
+#include "VOClient.h"
+#include "voAppsP.h"
+#include "samp.h"
+
+
+extern int errno;
+extern int debug, verbose, all_named, all_data, save_res, extract, quiet;
+extern int meta, dverbose, count, count_only, file_get, use_name, format;
+extern int id_col, samp, samp_p;
+
+extern char *output;
+
+
+int vot_callSiapSvc (svcParams *pars);
+char *vot_validateFile (char *fname);
+
+extern int vot_extractResults (char *result, char delim, svcParams *pars);
+extern int vot_printCount (Query query, svcParams *pars, int *count);
+extern int vot_countResults (char *result);
+extern void vot_printCountHdr (void);
+extern void vot_printCountLine (int nrec, svcParams *pars);
+extern void vot_dalExit (int code, int count);
+extern void vot_printHdr (int fd, svcParams *pars);
+extern void vot_printAttrs (char *fname, Query query, char *id);
+extern char vot_svcTypeCode (int type);
+extern char *vot_normalize (char *str);
+extern char *vot_getOFName (svcParams *pars, char *extn, int pid);
+extern char *vot_getOFIndex (svcParams *pars, char *extn, int pid);
+
+
+
+/************************************************************************
+** VOT_CALLSIAPSVC -- Call a Simple Image Access service.
+*/
+int
+vot_callSiapSvc (svcParams *pars)
+{
+ char *result = (char *)NULL;
+ char *extn, fname[SZ_LINE];
+ DAL siap; /* DAL Connection handle */
+ Query query; /* Query handle */
+ pid_t cpid;
+ int fd, code, res_count = 0;
+
+
+
+ if (debug)
+ fprintf (stderr, "siapCaller(%s:%d): ra = %f dec = %f\n",
+ pars->name, getpid(), pars->ra, pars->dec);
+
+
+ if ((cpid = fork()) < 0) {
+ fprintf (stderr,
+ "vot_callSiapSvc: Unable to create child process, exiting\n");
+ exit (-1);
+
+ } else if (cpid > 0) { /* Parent process */
+ return (cpid);
+
+ } else { /* Child process */
+
+ if (getenv("VOC_NO_NETWORK"))
+ return (OK);
+
+ /* Initialize the VOClient code. Error messages are printed by the
+ ** interface so we just quit if there is a problem.
+ */
+ if (voc_initVOClient ((char *) NULL) == ERR)
+ vot_dalExit (E_VOCINIT, 0);
+
+ /* Get a new connection to the named service and form the query.
+ */
+ siap = voc_openSiapConnection (pars->service_url);
+
+ if (meta)
+ query = voc_getSiapQuery (siap, 0.0, 0.0, 0.0, 0.0, "METADATA");
+ else
+ query = voc_getSiapQuery (siap, pars->ra, pars->dec,
+ pars->sr, pars->sr, (char *)NULL);
+
+ /* Not all SIAP services support VERB, leave it out for now....
+ */
+ if (verbose > 1)
+ (void) voc_addIntParam (query, "VERB", (all_data ? 3 : verbose));
+
+
+ /* Execute the query.
+ */
+ if (debug) {
+ fprintf (stderr, "siapCaller(%s:%d): executing query....%d\n",
+ pars->name, getpid(), pars->fmt);
+ fprintf (stderr, "Executing SIAP Query(%d):\n %s\n\n", query,
+ voc_getQueryString (query, SIAP_CONN, 0));
+ }
+
+
+ if (count_only) {
+ if ((code = vot_printCount (query, pars, &res_count)) != E_NONE) {
+ vot_dalExit (code, res_count);
+ }
+
+ } else if (meta) {
+ memset (fname, 0, SZ_LINE);
+ if (output)
+ strcpy (fname, output);
+ else
+ sprintf (fname, "%s_%c.meta", vot_normalize (pars->name),
+ vot_svcTypeCode(pars->type));
+ vot_printAttrs (fname, query, pars->identifier);
+
+ } else {
+ char delim;
+
+ switch (pars->fmt) {
+ case F_ASCII:
+ extn = "asv"; delim = ' ';
+ result = voc_executeASCII (query);
+ break;
+ case F_RAW:
+ extn = "xml"; delim = '\0';
+ result = voc_executeVOTable (query);
+ break;
+ case F_RAW | F_XML:
+ extract |= EX_XML;
+ extn = "xml"; delim = '\0';
+ result = voc_executeVOTable (query);
+ break;
+ case F_CSV:
+ extn = "csv"; delim = ',';
+ result = voc_executeCSV (query);
+ break;
+ case F_CSV | F_HTML:
+ extract |= EX_HTML;
+ extn = "csv"; delim = ',';
+ result = voc_executeCSV (query);
+ break;
+ case F_CSV | F_KML:
+ extract |= EX_KML;
+ extn = "csv"; delim = ',';
+ result = voc_executeCSV (query);
+ break;
+ case F_TSV:
+ extn = "tsv"; delim = '\t';
+ result = voc_executeTSV (query);
+ break;
+ default:
+ fprintf (stderr, "siapCaller: Unknown format: %d\n", pars->fmt);
+ exit (-1);
+ }
+
+ if (!result) {
+ vot_dalExit (E_NODATA, 0);
+ } else if (pars->fmt != F_RAW) {
+ res_count = vot_extractResults (result, delim, pars);
+ } else if (pars->fmt == F_RAW) {
+ res_count = vot_countResults (result);
+ }
+
+ if (count && (!output || (output && output[0] != '-')))
+ vot_printCountLine (res_count, pars);
+#ifdef EARLY_EXIT
+ if (res_count == 0) {
+ voc_closeConnection (siap);
+ voc_closeVOClient (0);
+ if (result) free ((char *) result);
+ vot_dalExit (E_NODATA, res_count);
+ }
+#endif
+
+ /* Check for a NULL result indicating an error in the call.
+ */
+ if (result == (char *)NULL) {
+ char *err;
+ extern char *voc_getErrMsg();
+
+ err = voc_getErrMsg ();
+ if (err && strncmp (err, "ERROR", 5) == 0) {
+ if (verbose > 1)
+ fprintf (stderr, "Pid %d: %s\n", getpid(), err);
+ vot_dalExit (E_REQFAIL, res_count);
+ } else
+ vot_dalExit (E_NODATA, res_count);
+ }
+
+ if (use_name || all_named || id_col)
+ strcpy (fname, vot_getOFName (pars, extn, (int)getpid()));
+ else
+ strcpy (fname, vot_getOFIndex (pars, extn, (int)getpid()));
+
+
+ if (output && output[0] == '-' && (! extract & EX_COLLECT)) {
+ write (fileno(stdout), result, strlen (result)-1);
+
+ } else if (format != (F_CSV|F_HTML) && format != (F_CSV|F_KML)) {
+ if ((fd = open (fname, O_WRONLY|O_CREAT, 0644)) < 0){
+ fprintf (stderr, "Error opening file '%s'\n", fname);
+ vot_dalExit (E_FILOPEN, res_count);
+ }
+
+ /* Output the result.
+ if (pars->fmt = F_CSV || pars->fmt == F_TSV)
+ vot_printHdr (fd, pars);
+ */
+ if (result)
+ write (fd, result, strlen (result)-1);
+ close (fd);
+
+ }
+ }
+
+ voc_closeConnection (siap); /* close the siap connection */
+ voc_closeVOClient (0); /* close VOClient connection */
+
+ if (result) free ((void *) result); /* free local storage */
+
+ if (debug) {
+ fprintf (stderr, "siapCaller(%s:%d): exiting....\n",
+ pars->name, getpid());
+ }
+
+ if (samp) {
+ char url[SZ_FNAME], cwd[SZ_FNAME];
+ extern int samp_tableLoadVOTable ();
+
+ samp_p = sampInit ("VOData", "VOClient Data Access");
+ samp_setSyncMode (samp_p);
+ sampStartup (samp_p);
+
+ memset (cwd, 0, SZ_FNAME);
+ if (getcwd (cwd, SZ_FNAME) < 0)
+ strcpy (cwd, "./");
+
+ memset (url, 0, SZ_FNAME);
+ sprintf (url, "file://%s/%s", cwd, fname);
+ (void) samp_tableLoadVOTable (samp_p, "all", url, NULL, NULL);
+
+ samp_UnRegister (samp_p);
+ }
+
+ if (res_count == 0)
+ unlink (fname);
+ vot_dalExit (E_NONE, res_count); /* no error */
+ }
+
+ return (OK);
+}
+
+
+/************************************************************************
+**
+*/
+char *
+vot_validateFile (char *fname)
+{
+ int fd, size;
+ static char buf[10], new[SZ_FNAME], *extn;
+
+
+ if ((fd = open (fname, O_RDONLY, 0777)) <= 0) {
+ unlink (fname);
+ return (0);
+ }
+
+ if ((size = read (fd, buf, 10)))
+ close (fd);
+
+ if (strncmp ("SIMPLE", buf, 6) == 0) {
+ extn = "fits";
+ } else if (strncmp ("GIF8", buf, 4) == 0) {
+ extn = "gif";
+ } else if (strncmp ("PNG\r\n", &buf[1], 5) == 0) {
+ extn = "png";
+ } else if (buf[0] == '\377' && buf[1] == '\330' && buf[2] == '\377' &&
+ buf[3] == '\340') {
+ extn = "jpg";
+ } else if (buf[0] == '\037' && buf[1] == '\213') {
+ extn = "gz";
+ } else
+ return (fname);
+
+ sprintf (new, "%s.%s", fname, extn);
+ rename (fname, new);
+
+ return (new);
+}
diff --git a/vendor/voclient/voapps/lib/voSSAP.c b/vendor/voclient/voapps/lib/voSSAP.c
new file mode 100644
index 00000000..fa86d139
--- /dev/null
+++ b/vendor/voclient/voapps/lib/voSSAP.c
@@ -0,0 +1,233 @@
+/************************************************************************
+** VOSSAP.C -- Worker procedure to make a query to an SSAP service.
+**
+** M. Fitzpatrick, NOAO, Februaary 2009
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/ipc.h>
+#include <sys/sem.h>
+#include "VOClient.h"
+#include "voAppsP.h"
+
+
+extern int errno;
+extern int debug, verbose, all_named, all_data, save_res, extract, quiet;
+extern int meta, dverbose, count, count_only, file_get, use_name, format;
+extern int id_col;
+
+extern char *output, *d2_band, *d2_time, *d2_format, *d2_version;
+
+
+int vot_callSsapSvc (svcParams *pars);
+
+extern int vot_extractResults (char *result, char delim, svcParams *pars);
+extern int vot_printCount (Query query, svcParams *pars, int *count);
+extern int vot_countResults (char *result);
+extern char vot_svcTypeCode (int type);
+extern char *vot_normalize (char *str);
+extern char *vot_getOFName (svcParams *pars, char *extn, int pid);
+extern char *vot_getOFIndex (svcParams *pars, char *extn, int pid);
+extern void vot_printCountHdr (void);
+extern void vot_printCountLine (int nrec, svcParams *pars);
+extern void vot_dalExit (int code, int count);
+extern void vot_printHdr (int fd, svcParams *pars);
+extern void vot_printAttrs (char *fname, Query query, char *id);
+
+
+
+/************************************************************************
+** VOT_CALLSSAPSVC -- Call a Simple Image Access service.
+*/
+int
+vot_callSsapSvc (svcParams *pars)
+{
+ char *result = (char *)NULL;
+ char *extn, fname[SZ_LINE];
+ DAL ssap; /* DAL Connection handle */
+ Query query; /* Query handle */
+ pid_t cpid;
+ int fd, code, res_count = 0;
+
+
+
+ if (debug)
+ fprintf (stderr, "ssapCaller(%s:%d): ra = %f dec = %f\n",
+ pars->name, getpid(), pars->ra, pars->dec);
+
+
+ if ((cpid = fork()) < 0) {
+ fprintf (stderr,
+ "vot_callSsapSvc: Unable to create child process, exiting\n");
+ exit (-1);
+
+ } else if (cpid > 0) { /* Parent process */
+ return (cpid);
+
+ } else { /* Child process */
+
+ if (getenv("VOC_NO_NETWORK"))
+ return (OK);
+
+ /* Initialize the VOClient code. Error messages are printed by the
+ ** interface so we just quit if there is a problem.
+ */
+ if (voc_initVOClient ((char *) NULL) == ERR)
+ vot_dalExit (E_VOCINIT, 0);
+
+ /* Get a new connection to the named service and form the query.
+ */
+ ssap = voc_openSsapConnection (pars->service_url);
+ if (meta) {
+ query = voc_getSsapQuery (ssap, 0.0, 0.0, 0.0,
+ (char *) NULL, (char *) NULL, "METADATA");
+ } else {
+ query = voc_getSsapQuery (ssap, pars->ra, pars->dec, pars->sr,
+ (char *) d2_band, /* BAND */
+ (char *) d2_time, /* TIME */
+ (char *) d2_format); /* FORMAT */
+
+ if (d2_version)
+ (void) voc_addStringParam (query, "VERSION", d2_version);
+ (void) voc_addStringParam (query, "REQUEST", "queryData");
+ }
+
+
+ /* Execute the query.
+ */
+ if (debug) {
+ fprintf (stderr, "ssapCaller(%s:%d): executing query....%d\n",
+ pars->name, getpid(), pars->fmt);
+ fprintf (stderr, "Executing SSAP Query(%d):\n %s\n\n", query,
+ voc_getQueryString (query, SSAP_CONN, 0));
+ }
+
+
+ if (count_only) {
+ if ((code = vot_printCount (query, pars, &res_count)) != E_NONE) {
+ vot_dalExit (code, res_count);
+ }
+
+ } else if (meta) {
+ bzero (fname, SZ_FNAME);
+ if (output)
+ strcpy (fname, output);
+ else
+ sprintf (fname, "%s_%c.meta", vot_normalize (pars->name),
+ vot_svcTypeCode(pars->type));
+ vot_printAttrs (fname, query, pars->identifier);
+
+ } else {
+ char delim;
+
+ switch (pars->fmt) {
+ case F_ASCII:
+ extn = "asv"; delim = ' ';
+ result = voc_executeASCII (query);
+ break;
+ case F_RAW:
+ extn = "xml"; delim = '\0';
+ result = voc_executeVOTable (query);
+ break;
+ case F_RAW | F_XML:
+ extract |= EX_XML;
+ extn = "xml"; delim = '\0';
+ result = voc_executeVOTable (query);
+ break;
+ case F_CSV:
+ extn = "csv"; delim = ',';
+ result = voc_executeCSV (query);
+ break;
+ case F_CSV | F_HTML:
+ extract |= EX_HTML;
+ extn = "csv"; delim = ',';
+ result = voc_executeCSV (query);
+ break;
+ case F_CSV | F_KML:
+ extract |= EX_KML;
+ extn = "csv"; delim = ',';
+ result = voc_executeCSV (query);
+ break;
+ case F_TSV:
+ extn = "tsv"; delim = '\t';
+ result = voc_executeTSV (query);
+ break;
+ default:
+ fprintf (stderr, "ssapCaller: Unknown format: %d\n", pars->fmt);
+ exit (-1);
+ }
+
+ if (!result)
+ vot_dalExit (E_NODATA, 0);
+ else if (pars->fmt != F_RAW)
+ res_count = vot_extractResults (result, delim, pars);
+ else if (pars->fmt == F_RAW)
+ res_count = vot_countResults (result);
+
+ if (count && (!output || (output && output[0] != '-')))
+ vot_printCountLine (res_count, pars);
+#ifdef EARLY_EXIT
+ if (res_count == 0) {
+ voc_closeConnection (siap);
+ voc_closeVOClient (0);
+ if (result) free ((char *) result);
+ vot_dalExit (E_NODATA, res_count);
+ }
+#endif
+
+
+ /* Check for a NULL result indicating an error in the call.
+ */
+ if (result == (char *)NULL) {
+ char *err;
+ extern char *voc_getErrMsg();
+ if (strncmp ((err = voc_getErrMsg()), "ERROR", 5) == 0) {
+ if (verbose > 1)
+ fprintf (stderr, "Pid %d: %s\n", getpid(), err);
+ vot_dalExit (E_REQFAIL, res_count);
+ } else
+ vot_dalExit (E_NODATA, res_count);
+ }
+
+ if (use_name || all_named || id_col)
+ strcpy (fname, vot_getOFName (pars, extn, (int)getpid()));
+ else
+ strcpy (fname, vot_getOFIndex (pars, extn, (int)getpid()));
+
+
+ if (output && output[0] == '-' && (! extract & EX_COLLECT)) {
+ write (fileno(stdout), result, strlen (result)-1);
+
+ } else if (format != (F_CSV|F_HTML) && format != (F_CSV|F_KML)) {
+ if ((fd = open (fname, O_WRONLY|O_CREAT, 0644)) < 0){
+ fprintf (stderr, "Error opening file '%s'\n", fname);
+ vot_dalExit (E_FILOPEN, res_count);
+ }
+
+ /* Output the result.
+ if (pars->fmt = F_CSV || pars->fmt == F_TSV)
+ vot_printHdr (fd, pars);
+ */
+ if (result)
+ write (fd, result, strlen (result)-1);
+ close (fd);
+
+ }
+ }
+
+ voc_closeConnection (ssap); /* close the ssap connection */
+ voc_closeVOClient (0); /* close VOClient connection */
+
+ if (result) free ((void *) result); /* free local storage */
+
+ if (debug) {
+ fprintf (stderr, "ssapCaller(%s:%d): exiting....\n",
+ pars->name, getpid());
+ }
+
+ vot_dalExit (E_NONE, res_count); /* no error */
+ }
+
+ return (OK);
+}
diff --git a/vendor/voclient/voapps/lib/voSvc.c b/vendor/voclient/voapps/lib/voSvc.c
new file mode 100644
index 00000000..b0b56265
--- /dev/null
+++ b/vendor/voclient/voapps/lib/voSvc.c
@@ -0,0 +1,874 @@
+/****************************************************************************
+** VOARGS.C -- Procedures for commandline argument handling. We also do
+** some of the heavy lifting for registry and object resolution.
+**
+** M. Fitzpatrick, NOAO, June 2007
+*/
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <dirent.h>
+#include <unistd.h>
+#include <ctype.h>
+#include <string.h>
+#include <time.h>
+#include "VOClient.h"
+#include "votParse.h"
+#include "voAppsP.h"
+
+
+#define SVC_DEBUG 0
+
+
+extern int nobjects, nservices, inventory;
+extern int verbose, quiet, debug, errno, force_svc, meta;
+extern int all_data, use_name, all_named, url_proc, svc_list;
+extern int force_read, table_hskip, table_nlines, table_sample;
+#ifdef REG10_KLUDGE
+extern int reg10;
+#endif
+extern char *typestr, *bpass, *delim, *cols, *ecols, *output;
+
+extern Service *svcList, *svcTail;
+
+int svcIndex = 0;
+
+
+int vot_parseServiceList (char *list, int dalOnly);
+int vot_printServiceList (FILE *fd);
+int vot_printServiceVOTable (FILE *fd);
+int vot_isSupportedSvc (char *type);
+
+void vot_addToSvcList (char *name, char *ident,char *url, char *type,
+ char *title);
+void vot_freeServiceList (void);
+void vot_resetServiceCounters (void);
+void vot_readSvcFile (char *fname, int dalOnly);
+
+static int vot_serviceResolver (char *idlist, int dalOnly);
+static int isResourceVOTable (char *fname);
+static int vot_loadResourceVOTable (char *fname);
+
+static void vot_regCacheResults (char *fname, char *results, int nres);
+
+static char *vot_regGetCacheResults (char *fname, int *nres);
+static char *vot_regIsCached (char *id, char *type, char *bpass);
+static char *vot_regCacheName (char *id, char *type, char *bpass);
+
+extern int vot_callConeSvc (svcParams *pars);
+extern int vot_callSiapSvc (svcParams *pars);
+extern int vot_callSsapSvc (svcParams *pars);
+extern void vot_addToAclist (char *url, char *fname);
+extern char *vot_urlFname (char *url);
+extern char *vot_normalizeCoord (char *coord);
+extern char *vot_normalize (char *str);
+
+
+
+/* Utility procedures.
+*/
+extern char *strcasestr ();
+
+
+
+
+/****************************************************************************
+** Parse a string containing service names. The string may be a single
+** name, a comma-delimited list, or the name of a file containing the same.
+*/
+int
+vot_parseServiceList (char *list, int dalOnly)
+{
+ FILE *fd;
+ /*char name[SZ_FNAME];*/
+ char *name;
+
+ extern char *vot_getline (FILE *fd);
+
+
+ if (access (list, R_OK) == 0) {
+
+ if (isResourceVOTable (list)) {
+ nservices += vot_loadResourceVOTable (list);
+
+ } else {
+
+ /* Process the file contents.
+ */
+ if ((fd = fopen (list, "r")) == (FILE *) NULL) {
+ fprintf (stderr, "ERROR: Cannot open file '%s'\n", list);
+ return (1);
+ }
+
+ while ((name = vot_getline (fd)))
+ vot_serviceResolver (name, dalOnly);
+
+ fclose (fd);
+ }
+
+ } else
+ vot_serviceResolver (list, dalOnly);
+
+ if (debug)
+ vot_printServiceList (stderr);
+ if (svc_list) {
+ FILE *fd;
+ char listfile[SZ_FNAME];
+
+ memset (listfile, 0, SZ_FNAME);
+ sprintf (listfile, "%s.services", output);
+ if ((fd = fopen (listfile, "w+")) != (FILE *) NULL) {
+ vot_printServiceList (fd);
+ fclose (fd);
+ }
+ }
+
+ return (0);
+}
+
+
+/****************************************************************************
+** LOADRESOURCEVOTABLE -- Read a Resource VOTable and load the Service list
+** with its contents.
+*/
+static int
+vot_loadResourceVOTable (char *fname)
+{
+ int vot = 0, i;
+ int nr = 0, nc = 0, nresults = 0;
+ int c_url, c_name, c_id, c_type, c_title;
+ char url[SZ_LINE], name[SZ_FNAME], id[SZ_FNAME];
+ char type[SZ_FNAME], title[SZ_LINE];
+
+
+ if ((vot = vot_openVOTABLE (fname)) ) {
+
+ int res, tab, data, tdata;
+
+ res = vot_getRESOURCE (vot); /* get handles */
+ if ((tab = vot_getTABLE (res)) <= 0)
+ return (0);
+ if ((data = vot_getDATA (tab)) <= 0)
+ return (0);
+ if ((tdata = vot_getTABLEDATA (data)) <= 0)
+ return (0);
+ nr = vot_getNRows (tdata);
+ nc = vot_getNCols (tdata);
+
+ c_name = vot_colByName (tab, "shortName", "");
+ c_url = vot_colByName (tab, "serviceURL", "accessURL");
+ c_id = vot_colByName (tab, "identifier", "");
+ c_type = vot_colByName (tab, "type", "capabilityclass");
+ c_title = vot_colByName (tab, "title", "");
+
+ if (SVC_DEBUG)
+ fprintf (stderr, "name:%d url:%d id:%d type:%d title:%d\n",
+ c_name, c_url, c_id, c_type, c_title);
+
+ for (i=0; i < nr; i++) {
+ bzero (name, SZ_FNAME);
+ strcpy (name, vot_getTableCell (tdata, i, c_name));
+
+ bzero (url, SZ_LINE);
+ strcpy (url, vot_getTableCell (tdata, i, c_url));
+
+ bzero (id, SZ_FNAME);
+ strcpy (id, vot_getTableCell (tdata, i, c_id));
+
+ bzero (type, SZ_FNAME);
+ strcpy (type, vot_getTableCell (tdata, i, c_type));
+
+ if (strcasestr ("SimpleImageAccess", type))
+ strcpy (type, "SIAP");
+ if (strcasestr ("ConeSearch", type))
+ strcpy (type, "CONE");
+ if (strcasestr ("skyservice", type))
+ strcpy (type, "TABULARSKYSERVICE");
+
+ bzero (title, SZ_LINE);
+ strcpy (title, vot_getTableCell (tdata, i, c_title));
+
+ /* Skip services we don't yet support.
+ */
+ if (! vot_isSupportedSvc (type) && !meta && !inventory) {
+ if (!quiet && verbose > 1)
+ fprintf (stderr,
+ "# Unsupported type %s for '%s', skipping...\n", type,name);
+ } else {
+ vot_addToSvcList (name, id, url, type, title);
+ nresults++;
+ }
+ }
+ }
+
+ if (vot)
+ vot_closeVOTABLE (vot);
+
+ return (nresults);
+}
+
+
+/****************************************************************************
+** ISRESOURCEVOTABLE -- Test a file or string to see if it's a Resource
+** VOTable by looking for a <FIELD> element with a 'ShortName' attribute.
+*/
+static int
+isResourceVOTable (char *fname)
+{
+ int vot = 0, res, tab, field;
+ char name[SZ_FNAME], *attr = NULL;
+ extern int isVOTable (char *fname);
+
+
+ /* First, make sure that it's at least a VOTable.
+ */
+ if (isVOTable (fname) == 0)
+ return (0);
+
+
+ /* Open it, looking for something we'd only expect from a
+ ** Resource VOTable like the 'ShortName' field.
+ */
+ if ((vot = vot_openVOTABLE (fname)) ) {
+ res = vot_getRESOURCE (vot);
+ if ((tab = vot_getTABLE (res)) <= 0)
+ return (0);
+
+ for (field=vot_getFIELD(tab); field; field=vot_getNext(field)) {
+ bzero (name, SZ_FNAME);
+ if ((attr = vot_getAttr (field, "name")))
+ strcpy (name, attr);
+
+ if (name[0] && strcasecmp (name, "ShortName") == 0) {
+ vot_closeVOTABLE (vot);
+ return (1);
+ }
+ }
+ }
+
+ if (vot > 0)
+ vot_closeVOTABLE (vot);
+
+ return (0);
+}
+
+
+
+/****************************************************************************
+** Free the service list and reset the counter.
+*/
+void
+vot_freeServiceList ()
+{
+ Service *cur, *next;
+
+ for (cur=svcList; cur; cur=next) {
+ next = cur->next;
+ if (cur)
+ free ((void *) cur);
+ }
+ nservices = 0;
+ svcList = svcTail = (Service *) NULL;
+}
+
+
+/****************************************************************************
+** Reset the service counters.
+*/
+void
+vot_resetServiceCounters ()
+{
+ Service *svc;
+
+ for (svc=svcList; svc; svc=svc->next)
+ svc->count = svc->nfailed = svc->nnodata = 0;
+}
+
+
+/****************************************************************************
+** Resolve a service name/list to the proper service URL and store the
+** result in the 'svcList' global which we assume is declared in the caller.
+*/
+static int
+vot_serviceResolver (char *idlist, int dalOnly)
+{
+ char *ip, *rp, *np, *id;
+ char sname[SZ_LINE], ident[SZ_LINE], title[SZ_LINE];
+ char name[SZ_LINE], url[SZ_URL], type[SZ_LINE], *result;
+ int i, len, use_any = 0, nres=0, vot_regResolver ();
+
+ extern int svcNumber;
+
+
+ /* Resolve the (list) of service names and add them to the
+ ** service list to be processed.
+ */
+ ip = idlist;
+
+ while (*ip) {
+
+ /* Break up the input list into a single ID to resolve.
+ */
+ id = ip;
+ while (*ip) {
+ if (*ip == ',' || *ip == '\n') {
+ *ip++ = '\0';
+ break;
+ } else
+ ip++;
+ }
+
+ if (access (id, R_OK) == 0) { /* file */
+ vot_parseServiceList (id, dalOnly);
+ continue;
+ } else { /* service name */
+
+ if (url_proc && strncmp (id, "http", 4) == 0) {
+ /* A URL. This may be a user-defined service URL if the
+ ** the -s flag was given, otherwise we assume it's an
+ ** access reference we want to download.
+ */
+ if (force_svc) {
+ sprintf (result, "%s\tUserSvc%d\tivo://user\t%s\n",
+ id, nres++, typestr);
+
+ } else {
+ /* Argument was a URL but we're not asked to treat it
+ ** as a service URL, so just add it to the access list
+ ** and move on. When given on the command-line this is
+ ** handled by the argument parsing, here we do it mostly
+ ** to process URLs given in a file.
+ */
+ vot_addToAclist (id, NULL);
+ url_proc++;
+ break;
+ }
+
+ } else {
+ /* Try to resolve the id to a service URL. This may be
+ ** a substring of a ShortName or Identifier field and in
+ ** some cases may resolve to more than one resource. For
+ ** 'all_data' mode we assume the id is a ShortName that may
+ ** resolve to multiple tables having unique IVORNs so we
+ ** require an exact match of the name and add expand the
+ ** service list with each resolved identifier.
+ */
+
+ char *c_name = vot_regIsCached (id, typestr, bpass);
+
+ if (c_name) {
+ result = vot_regGetCacheResults (c_name, &nres);
+ nservices += nres;
+ if (strcasecmp ("any", id) == 0) {
+ if (inventory)
+ nservices = -1;
+ else if (all_data)
+ use_any = 1;
+ }
+
+ } else {
+ char *fields =
+ "AccessURL,ShortName,Identifier,CapabilityStandardID,Title";
+
+ if (strcasecmp ("any", id) == 0) {
+ if (typestr) {
+ use_any = 1;
+ nres = vot_regResolver ("%", typestr, bpass, "",
+ NULL, fields, -1, all_data, dalOnly, &result);
+ nservices += nres;
+ } else if (inventory) {
+ nservices = -1;
+ } else {
+ fprintf (stderr,
+ "Must specify service type for 'any' query\n");
+ break;
+ }
+ } else {
+ /* If we're supporting Registry 1.0 then we need to
+ ** transform the VizieR ivorns before doing to search.
+ */
+ if (strncasecmp("ivo://CDS.VizieR",id,16) == 0)
+ all_data++;
+#ifdef REG10_KLUDGE
+ if (reg10 ||
+ strncasecmp("ivo://CDS.VizieR",id,16) == 0) {
+ char ivorn[SZ_LINE];
+
+ bzero (ivorn, SZ_LINE);
+ strcpy (ivorn, id);
+ strcat (ivorn, "%");
+ ivorn[9] = '/';
+ all_data++;
+ nres = vot_regResolver (ivorn, typestr, bpass, "",
+ NULL, fields, -1, !all_data, dalOnly, &result);
+
+ } else {
+#endif
+ if (strncasecmp("ivo://CDS/VizieR",id,16) == 0) {
+ char ivorn[SZ_LINE];
+
+ bzero (ivorn, SZ_LINE);
+ strcpy (ivorn, id);
+ strcat (ivorn, "%");
+ ivorn[9] = '.';
+ nres = vot_regResolver (ivorn, typestr, bpass,
+ NULL, "", fields, -1, !all_data, 0, &result);
+ if (nres == 0) {
+ int len = strlen (ivorn);
+ char *ip = &ivorn[len-1];
+
+ for ( ; *ip != '/'; ip--) *ip = '\0';
+ nres = vot_regResolver (ivorn, typestr,
+ bpass, "", NULL, fields, -1, !all_data,
+ 0, &result);
+ }
+
+ } else {
+ nres = vot_regResolver (id, typestr, bpass, "",
+ NULL, fields, -1, !all_data, dalOnly,
+ &result);
+ if (nres == 0 && !all_data) {
+ /* No results for exact match, try again by
+ ** being a little more liberal with matching
+ */
+ all_data++;
+ nres = vot_regResolver (id, typestr, bpass,
+ NULL, "", fields, -1, 0, dalOnly,
+ &result);
+ }
+ }
+#ifdef REG10_KLUDGE
+ }
+#endif
+ if (nres == 0) {
+ /* For no results from the registry, assume
+ ** any 'http' URI is instead a file to download.
+ */
+ if (!url_proc && strncmp (id, "http", 4) == 0) {
+ vot_addToAclist (id, NULL);
+ url_proc++;
+ break;
+ }
+ }
+ nservices += nres;
+ }
+ if ((nres > 1 && verbose) && !all_data && !use_any) {
+ fprintf (stderr,
+ "# Service query '%s' non-unique (%d found)...\n",
+ id, nres);
+ }
+
+ /* Cache the result.
+ */
+ c_name = vot_regCacheName (id, typestr, bpass);
+ vot_regCacheResults (c_name, result, nres);
+ }
+ }
+ }
+
+ /* Replace problem characters in the name so it can be used in
+ ** a filename.
+ */
+ for (np=id; *np; np++)
+ if (*np == ' ' || *np == '/' || *np == '(' || *np == ')')
+ *np = '_';
+
+
+ /* Loop over each of the resources found, parsing the result string
+ ** and adding each service in turn. If we're not doing all the data,
+ ** use the first result found and break.
+ */
+ rp = &result[0];
+ for (i=0; i < nres; i++) {
+
+ /* Split the resolved string to the url and type.
+ */
+ memset (url, 0, SZ_URL);
+ memset (sname, 0, SZ_LINE);
+ memset (ident, 0, SZ_LINE);
+ memset (type, 0, SZ_LINE);
+ memset (title, 0, SZ_LINE);
+
+ for (np=url, len=SZ_URL; *rp && *rp != '\t' && len; len--)
+ *np++ = *rp++;
+ rp++;
+ for (np=sname, len=SZ_LINE; *rp && *rp != '\t' && len; len--)
+ *np++ = *rp++;
+ rp++;
+ for (np=ident, len=SZ_LINE; *rp && *rp != '\t' && len; len--)
+ *np++ = *rp++;
+ rp++;
+ for (np=type, len=SZ_LINE; *rp && *rp != '\t' && len; len--)
+ *np++ = *rp++;
+ rp++;
+ for (np=title, len=SZ_LINE; *rp && *rp != '\n' && len; len--)
+ *np++ = *rp++;
+ rp++;
+
+ /* Skip services we don't yet support.
+ if (! vot_isSupportedSvc (type) && !meta) {
+ */
+ if (! vot_isSupportedSvc (type)) {
+ if (!quiet && verbose > 1)
+ fprintf (stderr,
+ "# Unsupported service type '%s' for '%s', skipping...\n",
+ type, sname);
+ continue;
+ }
+
+ /* Check for a specifically requested service number.
+ */
+ if (svcNumber > 0) {
+ char *ip, *op, num[SZ_FNAME];
+
+ bzero (num, SZ_FNAME);
+ for (ip=sname; *ip && ! isdigit(*ip); ip++) ;
+ for (op=num; *ip && isdigit(*ip); ip++)
+ *op++ = *ip;
+
+ if (atoi(num) != svcNumber)
+ continue;
+ }
+
+ if (verbose && !quiet && !use_any && nres > 1) {
+ if (all_data)
+ fprintf (stderr, "# Using %s Resource %s_%s -> %s\n",
+ type, id, vot_urlFname(url), ident);
+ else
+ fprintf (stderr, "# Using %s Resource %s -> %s\n",
+ type, sname, ident);
+ if (debug) {
+ fprintf (stderr, "%d url = '%s'\n", i, url);
+ fprintf (stderr, "%d type = '%s'\n", i, type);
+ }
+ }
+
+ /* Save results in the service list.
+ */
+ bzero (name, SZ_LINE);
+ strcpy (name, (use_any || all_data ? sname : id));
+
+ vot_addToSvcList (name, ident, url, type, title);
+
+ if (!all_data && !use_any)
+ break;
+ }
+
+ if (result)
+ free ((char *)result);
+ }
+
+ return (0);
+}
+
+
+/****************************************************************************
+** Utility routine to add a URL to the service list.
+*/
+void
+vot_addToSvcList (char *name, char *ident, char *url, char *type, char *title)
+{
+ Service *svc;
+ char *ip, *op;
+
+
+ if (url == (char *)NULL || strcasecmp ("NOT PROVIDED", url) == 0) {
+ fprintf (stderr,
+ "Warning: Empty ServiceURL for '%s', skipping...\n", name);
+ return;
+ }
+
+ /* Save results in the service list.
+ */
+ svc = (Service *)calloc (1,sizeof(Service));
+ if (!svcList)
+ svcList = svcTail = svc;
+ else
+ svcTail->next = (Service *)svc;
+
+
+ /* Clean up any '&amp;' encodings in the URL.
+ */
+ for (ip = op = url; *ip; ) {
+ if (*ip == '&' && strncmp (ip, "&amp", 4) == 0) {
+ ip += ((strncmp (ip, "&amp;", 5) == 0) ? 5 : 4);
+ *op++ = '&';
+ } else
+ *op++ = *ip++;
+ }
+ *op = '\0';
+
+
+ strcpy (svc->name, name);
+ strcpy (svc->service_url, url);
+ strcpy (svc->identifier, ident);
+ strcpy (svc->title, title);
+ if (strncasecmp (type, "cone", 4) == 0 ||
+ strncasecmp (type, "catalog", 7) == 0) {
+ svc->func = &vot_callConeSvc;
+ if (strstr (url, "vizier")) {
+ svc->type = SVC_VIZIER;
+ } else
+ svc->type = SVC_CONE;
+ } else if (strncasecmp (type, "sia", 3) == 0 ||
+ strncasecmp (type, "simpleimage", 9) == 0) {
+ svc->func = &vot_callSiapSvc;
+ svc->type = SVC_SIAP;
+ } else if (strncasecmp (type, "ssap", 4) == 0 ||
+ strncasecmp (type, "simplespec", 9) == 0) {
+ svc->func = &vot_callSsapSvc;
+ svc->type = SVC_SSAP;
+ } else if (strncasecmp (type, "tabularsky", 8) == 0 ||
+ strstr (url, "vizier")) {
+ svc->func = &vot_callConeSvc;
+ svc->type = SVC_VIZIER;
+ } else {
+ svc->func = NULL;
+ svc->type = SVC_OTHER;
+ }
+ svc->index = svcIndex++;
+
+ svcTail = svc;
+}
+
+
+int
+vot_isSupportedSvc (char *type)
+{
+ if (strncasecmp (type, "cone", 4) == 0 ||
+ strncasecmp (type, "catalog", 7) == 0)
+ return (1);
+ else if (strncasecmp (type, "sia", 3) == 0 ||
+ strncasecmp (type, "simpleimage", 10) == 0)
+ return (1);
+ else if (strncasecmp (type, "ssap", 4) == 0 ||
+ strncasecmp (type, "simplespec", 9) == 0)
+ return (1);
+ else if (strncasecmp (type, "tabularsky", 10) == 0)
+ return (1);
+
+ if (type && (*type) == (char) 0)
+ return (0);
+
+ return (0);
+}
+
+
+/****************************************************************************
+** Utility routines to print and count the service list.
+*/
+
+int
+vot_countServiceList ()
+{
+ register int i = 0;
+ Service *svc = svcList;
+
+ if (nservices < 0)
+ return (nservices);
+ else if (!svc)
+ return (0);
+ else
+ while ((svc = svc->next)) i++;
+
+ return (i+1);
+}
+
+int
+vot_printServiceList (FILE *fd)
+{
+ register int i = 0;
+ Service *svc = svcList;
+
+ if (!svc)
+ return (0);
+
+ fprintf (fd, "# Services queried: %d\n#\n", vot_countServiceList());
+ fprintf (fd, "# %4s\t%-16.16s\t%s\n", "Id", "Name", "Title");
+ do {
+ fprintf (fd, "%4d\t%-16.16s\t%s\n", i++, svc->name, svc->title);
+ } while ((svc = svc->next));
+
+ return (0);
+}
+
+int
+vot_printServiceVOTable (FILE *fd)
+{
+ Service *svc = svcList;
+
+ if (!svc)
+ return (0);
+
+
+ /* Print the VOTable header.
+ */
+ fprintf (fd, "\
+ <?xml version=\"1.0\" encoding=\"utf-8\"?>\
+ <VOTABLE ID=\"ID\" xmlns=\"http://www.ivoa.net/xml/VOTable/v1.1\">\
+ <RESOURCE><TABLE>");
+
+ fprintf (fd, "\
+ <FIELD datatype=\"char\" name=\"shortName\" arraysize=\"*\"/>\
+ <FIELD datatype=\"char\" name=\"identifier\" arraysize=\"*\"/>\
+ <FIELD datatype=\"char\" name=\"accessURL\" arraysize=\"*\"/>\
+ <FIELD datatype=\"char\" name=\"title\" arraysize=\"*\"/>");
+
+ fprintf (fd, "<DATA><TABLEDATA>");
+
+ do {
+ fprintf(stderr,"<TR><TD>%s</TD><TD>%s</TD><TD>%s</TD><TD>%s</TD></TR>",
+ svc->name, svc->service_url, svc->identifier, svc->title);
+ } while ((svc = svc->next));
+
+ /* Close off the table output.
+ */
+ fprintf (fd, "</TABLEDATA></DATA></TABLE></RESOURCE></VOTABLE>\n");
+
+ return (0);
+}
+
+
+
+/******************************************************************************
+** Registry cache handling routines.
+**
+** *********** FIXME *************
+*/
+
+#define C_EXPIRE 2592000 /* 30 days */
+
+
+/* Create the cache name from the resolver terms.
+*/
+static char *
+vot_regIsCached (char *id, char *type, char *bpass)
+{
+ char *fname = vot_regCacheName (id, type, bpass);
+ char *s, *line[SZ_LINE];
+ struct stat st;
+ time_t now = time ((time_t)NULL);
+ FILE *fd;
+
+
+return ((char *) NULL); /** FIXME -- CURRENTLY DISABLED */
+
+ if ((s = getenv("VOC_NO_CACHE")))
+ return ((char *) NULL);
+
+ if (access (fname, F_OK) == 0) {
+ /* Check first for an expired entry.
+ */
+ stat (fname, &st);
+ if ((st.st_ctime - now) > C_EXPIRE) {
+ unlink (fname);
+ return ((char *) NULL);
+ }
+
+ /* Now see whether the contents look valid.
+ */
+ if ((fd = fopen (fname, "r")) != (FILE *) NULL) {
+ (void) fgets ((char *)line, SZ_LINE, fd);
+ (void) fgets ((char *)line, SZ_LINE, fd);
+ if (strncasecmp ("INDEF", (char *)line, 5) == 0) {
+ fclose (fd);
+ unlink (fname);
+ return ((char *)NULL);
+ }
+ fclose (fd);
+ }
+
+ return ((char *) fname);
+ }
+
+ return ((char *) NULL);
+}
+
+
+/* Fetch the cached data.
+*/
+static char *
+vot_regGetCacheResults (char *fname, int *nres)
+{
+ FILE *fd;
+ int nr, size;
+ char line[SZ_LINE], *results;
+
+ memset (line, 0, SZ_LINE);
+ if ((fd = fopen (fname, "r")) != (FILE *) NULL) {
+ (void) fgets ((char *)line, SZ_LINE, fd);
+ sscanf ((char *)line, "%d %d\n", &nr, &size);
+ results = (char *) calloc (1, size+2);
+
+ while (fgets ((char *)line, SZ_LINE, fd))
+ strcat ((char *)results, (char *)line);
+ }
+ fclose (fd);
+
+ *nres = nr;
+ return ((char *)results);
+}
+
+
+/* Create the cache name from the resolver terms.
+*/
+static void
+vot_regCacheResults (char *fname, char *results, int nres)
+{
+ FILE *fd;
+
+ if (access (fname, F_OK) == 0)
+ unlink (fname);
+ if ((fd = fopen (fname, "w+")) != (FILE *) NULL) {
+ fprintf (fd, "%d %d\n%s", nres, (int)strlen(results), results);
+ fclose (fd);
+ }
+}
+
+
+/****************************************************************************
+** Create the cache name from the resolver terms.
+*/
+static char *
+vot_regCacheName (char *id, char *type, char *bpass)
+{
+ static char name[SZ_FNAME];
+ char s1[SZ_FNAME], s2[SZ_FNAME], s3[SZ_FNAME];
+ extern char *voc_getCacheDir (char *s);
+
+ bzero (name, SZ_FNAME); /* Initialize strings */
+
+ strcpy (s1, vot_normalize (id));
+ strcpy (s2, vot_normalize (type));
+ strcpy (s3, vot_normalize (bpass));
+
+ sprintf (name, "%s/%s_%s_%s", voc_getCacheDir("regResolver"), s1, s2, s3);
+
+ return (name);
+}
+
+
+
+void
+vot_readSvcFile (char *fname, int dalOnly)
+{
+ char tmpfile[SZ_FNAME];
+ extern char *vot_copyStdin();
+
+
+ bzero (tmpfile, SZ_FNAME);
+
+ if (strcmp (fname, "-") == 0) { /* read from stdin */
+
+ strcpy (tmpfile, vot_copyStdin ());
+
+ /* Parse the input and unlink the temp file.
+ */
+ vot_parseServiceList (tmpfile, dalOnly);
+ unlink (tmpfile);
+
+ } else if (access (fname, R_OK) == 0)
+ vot_parseServiceList (fname, dalOnly);
+}
+
diff --git a/vendor/voclient/voapps/lib/voTask.c b/vendor/voclient/voapps/lib/voTask.c
new file mode 100644
index 00000000..df9f039e
--- /dev/null
+++ b/vendor/voclient/voapps/lib/voTask.c
@@ -0,0 +1,856 @@
+/**
+ * VOTASK.C -- Utilities to run a VOApps task as a connected subprocess.
+ *
+ * @file voTask.c
+ * @author Mike Fitzpatrick
+ * @date 6/23/12
+ *
+ * @brief Utilities to run a VOApps task as a connected subprocess.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <setjmp.h>
+#include <sys/wait.h>
+#include <sys/stat.h>
+#include <sys/select.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include "voApps.h"
+
+
+#define PARENT_READ rpipe[0] /* read from parent */
+#define CHILD_WRITE rpipe[1] /* write to parent */
+#define CHILD_READ wpipe[0] /* read from child */
+#define PARENT_WRITE wpipe[1] /* write to parent */
+
+#ifdef ERR
+#undef ERR
+#endif
+#ifdef OK
+#undef OK
+#endif
+#define ERR 1
+#define OK 0
+
+#define MAX_TASK_ARGS 64
+
+
+static int rpipe[2] = {-1, -1}; /* subprocess read pipes */
+static int wpipe[2] = {-1, -1}; /* subprocess write pipes */
+static int nr = 0;
+
+
+
+/* Internal procedures.
+ */
+static pid_t vo_taskExec (char *method, Task *apps, int argc, char *argv[]);
+static int vo_taskWait (pid_t pid, size_t *len);
+static void *vo_taskResult (pid_t pid, size_t len);
+static void vo_taskReaper (int sig, int *arg1, int *arg2);
+static size_t vo_taskRead (int fd, void *data, size_t len);
+static size_t vo_taskWrite (int fd, void *data, size_t len);
+
+typedef void (*SIGFUNC)();
+
+
+
+
+/*****************************************************************************/
+/** Public procedures **/
+/*****************************************************************************/
+
+
+/**
+ * VO_RUNTASK -- Run a VOApps task as a connected subprocess.
+ *
+ * @brief Run a VOApps task as a connected subprocess.
+ * @fn int vo_runTask (char *method, Task *apps, int argc, char *argv[],
+ * size_t *len, void **result)
+ *
+ * @param method task name to call
+ * @param apps application table
+ * @param argc argument count
+ * @param argv argument vector
+ * @param len length of result object
+ * @param result pointer to result object
+ * @return status (0=OK, 1=ERR)
+ */
+
+static int vo_signal_status = 0;
+static int vo_exit_status = 0;
+sigjmp_buf vo_env;
+
+int
+vo_runTask (char *method, Task *apps, int argc, char **argv, size_t *len, void **result)
+{
+ pid_t pid;
+ int status = 0, retStatus = EXIT_SUCCESS;
+ size_t resLen = 0;
+ void *res = (void *) NULL;
+ static SIGFUNC old_sigcld;
+ char err[128];
+
+
+ memset (err, 0, 128);
+
+ old_sigcld = (SIGFUNC) signal (SIGCHLD, (SIGFUNC) vo_taskReaper);
+ vo_signal_status = 0;
+ vo_exit_status = 0;
+
+ sigsetjmp (vo_env, 1);
+ if (vo_signal_status || vo_exit_status) {
+ if (vo_signal_status)
+ sprintf (err, "Child exited with SIGNAL %d", vo_signal_status);
+ else if (vo_exit_status > 1)
+ sprintf (err, "Child exited with status %d", vo_exit_status);
+ *len = strlen (err);
+ *result = (void *) strdup (err);
+
+ return (EXIT_FAILURE);
+ }
+
+ if ((pid = vo_taskExec (method, apps, argc, argv)) > 0) {
+
+ if ((status = vo_taskWait (pid, &resLen)) == EXIT_SUCCESS) {
+
+ if (resLen && (res = vo_taskResult (pid, resLen)))
+ *result = res; /* save result from client */
+ else
+ *result = (void *) NULL; /* no result from client */
+ *len = resLen;
+
+ } else {
+ sprintf (err, "Child exited with status %d", status);
+ *len = strlen (err);
+ *result = (void *) strdup (err);
+ return ( status ); /* child exits with error */
+ }
+
+ close (CHILD_WRITE); /* Close descriptors */
+ close (CHILD_READ);
+
+ } else {
+ fprintf (stderr, "Error executing task\n");
+ retStatus = EXIT_FAILURE;
+ }
+
+ signal (SIGCHLD, old_sigcld); /* reset the SIGCHLD handler */
+ return (retStatus);
+}
+
+
+/**
+ * VO_TASKTEST -- Execute a task as a unit test.
+ *
+ * @brief Execute a task as a unit test.
+ * @fn int vo_taskTest (Task *self, char *arg, ...)
+ *
+ * @param self task struct pointer
+ * @param arg first of variable arg list
+ * @return status (0=OK, 1=ERR)
+ */
+int
+vo_taskTest (Task *self, char *arg, ...)
+{
+ int i, status = OK, argc = 0;
+ char *argv[MAX_TASK_ARGS], *aval = NULL;
+ size_t reslen = 0;
+ void *result = (void *) NULL;
+ va_list argp;
+
+ extern int optind;
+#ifdef Darwin
+ extern int optreset;
+#endif
+
+ va_start (argp, arg); /* initialize */
+ memset (argv, 0, sizeof (char *) * MAX_TASK_ARGS);
+
+ optind = 0; /* required for unit test */
+#ifdef Darwin
+ optreset = 1; /* required for unit test */
+#endif
+
+ /* Turn the varargs list into an argv[] we can pass to the task.
+ */
+ argc = 1;
+ argv[0] = strdup (self->name);
+
+ if (arg) {
+ argv[1] = strdup (arg);
+ for (i=2; (aval = (char *)va_arg(argp,char *)) != NULL; i++) {
+ if (aval)
+ argv[i] = strdup (aval);
+ }
+ argc = i;
+ va_end (argp);
+ }
+
+
+ /* Initialize the test output....
+ */
+ fprintf (stderr, "\n=======================================");
+ fprintf (stderr, "======================================\n");
+ fprintf (stderr, "== Test Cmd: %s ", self->name);
+ for (i=1; i < argc; i++)
+ fprintf (stderr, "%s ", argv[i]);
+ fprintf (stderr, "\n\n");
+
+
+ /* Execute the task, throw away any returned value.
+ */
+ if (!getenv ("VOAPP_CONNECTED"))
+ status = vo_runTask (self->name, self, argc, argv, &reslen, &result);
+ else
+ status = (*(self->func)) (argc, argv, &reslen, &result);
+
+ fprintf (stderr, "===================================");
+ fprintf (stderr, "============================= status = %2d\n", status);
+
+vo_taskDbg();
+
+ /* Clean up.
+ */
+ for (i=0; i < argc; i++) {
+ if (argv[i])
+ free (argv[i]);
+ }
+
+ if (status && result) /* print the error message */
+ fprintf (stderr, "%s\n", (char *) result);
+ if (reslen && result) /* free result pointer */
+ free (result);
+
+ self->ntests++; /* update testing struct */
+ if (status)
+ self->nfail++;
+ else
+ self->npass++;
+
+ return (status);
+}
+
+
+/**
+ * VO_TASKDBG -- Tasking debug breakpoint.
+ *
+ * @brief Tasking debug breakpoint.
+ * @fn void vo_taskDbg (void)
+ *
+ * @return nothing
+ */
+void vo_taskDbg (void)
+{
+ static int i = 0;
+
+ i++;
+}
+
+
+/**
+ * VO_TASKTESTREPORT -- Report from the task testing interface.
+ *
+ * @brief Report from the task testing interface.
+ * @fn void vo_taskTestReport (self)
+ *
+ * @param self task struct pointer
+ * @return status (0=OK, 1=ERR)
+ */
+void
+vo_taskTestReport (Task self)
+{
+ fprintf (stderr, "\n");
+ fprintf (stderr,
+ "Task: %-12.12s No. of Tests: %d Passed: %d Failed: %d\n",
+ self.name, self.ntests, self.npass, self.nfail);
+
+ fprintf (stderr, "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@");
+ fprintf (stderr, "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@\n");
+}
+
+
+/**
+ * VO_TASKTESTFILE -- Create a small named test file.
+ *
+ * @brief Create a small named test file.
+ * @fn void vo_taskTestFile (char *str, char *fname)
+ *
+ * @param str test string
+ * @param fname test filename
+ * @return status (0=OK, 1=ERR)
+ */
+void
+vo_taskTestFile (char *str, char *fname)
+{
+ FILE *fd = (FILE *) NULL;
+
+ if (access (fname, F_OK) == 0)
+ unlink (fname);
+ if ((fd = fopen (fname, "w+"))) {
+ fprintf (fd, "%s", str);
+ fclose (fd);
+ }
+}
+
+
+/**
+ * VO_SETRESULTFROMFILE -- Set a result object to a file's contents.
+ *
+ * @brief Set a result object to a file's contents.
+ * @fn int vo_setResultFromFile (char *fname, size_t *len, void **data)
+ *
+ * @param fname file name to read
+ * @param len length of result object
+ * @param data pointer to result object
+ * @return status (0=OK, 1=ERR)
+ */
+int
+vo_setResultFromFile (char *fname, size_t *len, void **data)
+{
+ struct stat st;
+ int fd = 0;
+
+
+ if (stat (fname, &st) < 0)
+ return (ERR);
+
+ if ((fd = open (fname, O_RDONLY)) > 0) {
+ *len = st.st_size;
+ *data = calloc (1, st.st_size + 1);
+ if (vo_taskRead (fd, *data, *len) < *len)
+ return (ERR);
+ close (fd);
+ } else
+ return (ERR);
+
+ return (OK);
+}
+
+
+/**
+ * VO_SETRESULTFROMINT -- Set a result object to an int value.
+ *
+ * @brief Set a result object to an int value.
+ * @fn int vo_setResultFromInt (int value, size_t *len, void **data)
+ *
+ * @param value value to set
+ * @param len length of result object
+ * @param data pointer to result object
+ * @return status (0=OK, 1=ERR)
+ */
+int
+vo_setResultFromInt (int value, size_t *len, void **data)
+{
+ char buf[SZ_FNAME];
+
+ memset (buf, 0, SZ_FNAME);
+ sprintf (buf, "%d", value);
+
+ *len = strlen (buf);
+ *data = (char *) calloc (1, *len + 1);
+ strcpy ((char *) data, buf);
+ return (OK);
+}
+
+
+/**
+ * VO_SETRESULTFROMREAL -- Set a result object to a real value.
+ *
+ * @brief Set a result object to a real value.
+ * @fn int vo_setResultFromReal (float value, size_t *len, void **data)
+ *
+ * @param value value to set
+ * @param len length of result object
+ * @param data pointer to result object
+ * @return status (0=OK, 1=ERR)
+ */
+int
+vo_setResultFromReal (float value, size_t *len, void **data)
+{
+ char buf[SZ_FNAME];
+
+ memset (buf, 0, SZ_FNAME);
+ sprintf (buf, "%g", value);
+
+ *len = strlen (buf);
+ *data = (char *) calloc (1, *len + 1);
+ strcpy ((char *) data, buf);
+ return (OK);
+}
+
+
+/**
+ * VO_SETRESULTFROMSTRING -- Set a result object to a string value.
+ *
+ * @brief Set a result object to a string value.
+ * @fn int vo_setResultFromString (char *str, size_t *len, void **data)
+ *
+ * @param value value to set
+ * @param len length of result object
+ * @param data pointer to result object
+ * @return status (0=OK, 1=ERR)
+ */
+int
+vo_setResultFromString (char *str, size_t *len, void **data)
+{
+ if (str) {
+ *len = strlen (str);
+ *data = (char *) calloc (1, *len + 1);
+ strcpy ((char *) *data, str);
+ } else {
+ *len = 0;
+ *data = NULL;
+ }
+ return (OK);
+}
+
+
+/**
+ * VO_APPENDRESULTFROMSTRING -- Append a result object to a string value.
+ *
+ * @brief Append a result object to a string value.
+ * @fn int vo_appendResultFromString (char *str, size_t *len,
+ * void **data, size_t *maxlen)
+ *
+ * @param value value to set
+ * @param len length of result object
+ * @param data pointer to result object
+ * @param maxlen max length of result object
+ * @return status (0=OK, 1=ERR)
+ */
+int
+vo_appendResultFromString (char *str, size_t *len, void **data, size_t *maxlen)
+{
+ int slen = strlen (str);
+
+ if (str) {
+ *len += slen;
+
+ /* Reallocate in case we overrun the data buffer.
+ */
+ if ((*len) > (*maxlen)) {
+ char *new = (char *) calloc (1, (*maxlen) + SZ_LINE);
+ strcpy (new, *data);
+ free ((void *) *data);
+ *data = new;
+ }
+
+ strcat ((char *) *data, str);
+ }
+ return (OK);
+}
+
+
+
+
+/*****************************************************************************/
+/** Private procedures **/
+/*****************************************************************************/
+
+
+static void
+vo_taskReaper (
+ int sig, /* signal which was trapped */
+ int *arg1, /* not used */
+ int *arg2 /* not used */
+)
+{
+ int status = 0, pid = 0;
+
+
+ vo_signal_status = vo_exit_status = 0;
+
+ while ((pid = (int) waitpid ((pid_t) 0, &status, WNOHANG)) > 0)
+ if (status) {
+ if (status & 0xFF)
+ vo_signal_status = (status & 0xFF);
+ else if (status >> 8)
+ vo_exit_status = (status >> 8);
+ siglongjmp (vo_env, 1);
+ }
+}
+
+
+/**
+ * VO_TASKEXEC -- Execute a task as a connected subprocess.
+ *
+ * @brief Get the result object (if any) from the task.
+ * @fn Task *vo_taskExec (char *method, Task *apps, int argc, char *argv[])
+ *
+ * @param method task name to call
+ * @param apps task application table
+ * @param argc argument count
+ * @param argv argument vector
+ * @return pid of child process
+ */
+
+#define GO_MSG "__go__"
+#define GO_LEN 6
+#define E_NOTFOUND "Task not found"
+
+static pid_t
+vo_taskExec (char *method, Task *apps, int argc, char **argv)
+{
+ Task *app = (Task *) NULL;
+ int status = 0;
+ pid_t cpid;
+ size_t resLen = 0;
+ void *result = (void *) NULL;
+ char msg[128];
+
+
+ /* Create the pipes to/from the child process.
+ */
+ if (pipe (rpipe) < 0 || pipe (wpipe) < 0) {
+ perror ("pipe failure");
+ _exit (EXIT_FAILURE);
+ }
+
+
+ /* Fork so the child does all the work.
+ */
+ if ( (cpid = fork ()) < 0 )
+ return (cpid);
+
+ if (cpid == 0) { /* Child */
+
+ close (CHILD_WRITE); /* Close unused descriptors */
+ close (CHILD_READ);
+
+ /* Wait for the '_go_' message.
+ */
+ do {
+ memset (msg, 0, 128);
+ nr = vo_taskRead (PARENT_READ, msg, GO_LEN);
+ } while (strncmp (msg, GO_MSG, GO_LEN) != 0);
+
+
+ /* Loop through the application table. If the names match, call
+ * the entry-point function.
+ */
+ for (app = apps; app->name; app++) {
+ if (strcmp (app->name, method) == 0) {
+ status = (*app->func)(argc, argv, &resLen, &result);
+
+ /* Send the parent the status reply,result length and
+ * the result object, if there is one.
+ */
+ vo_taskWrite (PARENT_WRITE, &status, sizeof (int));
+ vo_taskWrite (PARENT_WRITE, &resLen, sizeof (size_t));
+ if (resLen)
+ vo_taskWrite (PARENT_WRITE, result, resLen);
+ break;
+ }
+ }
+
+
+ /* If we get here, the task wasn't found.
+ */
+ if (app->name == NULL) {
+ status = -1;
+ vo_taskWrite (PARENT_WRITE, &status, sizeof (int));
+ vo_taskWrite (PARENT_WRITE, E_NOTFOUND, strlen (E_NOTFOUND));
+ }
+
+ /* Exit the child process.
+ */
+ close (PARENT_READ); /* Close descriptors */
+ close (PARENT_WRITE);
+ _exit (EXIT_SUCCESS); /* child exits */
+
+ } else { /* Parent */
+ close (PARENT_READ); /* Close unneded descriptors */
+ close (PARENT_WRITE);
+
+ vo_taskWrite (CHILD_WRITE, GO_MSG, GO_LEN);
+
+ return (cpid);
+ }
+}
+
+
+/**
+ * VO_TASKWAIT -- Wait for a child process to complete.
+ *
+ * @brief Wait for a child process to complete.
+ * @fn int vo_taskWait (pid_t pid, int *len)
+ *
+ * @param pid child process pid
+ * @param len length of result object
+ * @return exit status of child process
+ */
+static int
+vo_taskWait (pid_t pid, size_t *len)
+{
+ int status = 0;
+
+
+ /* Wait for status message.
+ */
+ vo_taskRead (CHILD_READ, &status, sizeof (int));
+ vo_taskRead (CHILD_READ, len, sizeof (size_t));
+
+ wait (NULL); /* Wait for child */
+ return (status);
+}
+
+
+/**
+ * VO_TASKRESULT -- Get the result object (if any) from the task.
+ *
+ * @brief Get the result object (if any) from the task.
+ * @fn void *vo_taskResult (pid_t pid, size_t len)
+ *
+ * @return (allocated) pointer to the Task
+ */
+static void *
+vo_taskResult (pid_t pid, size_t len)
+{
+ void *result = (void *) calloc (1, len);
+
+ vo_taskRead (CHILD_READ, result, len);
+
+ return (result);
+}
+
+
+#define SELWIDTH 32
+
+/**
+ * VO_TASKREAD -- Read exactly "n" bytes from a task descriptor.
+ *
+ * @brief Read exactly "n" bytes from a task descriptor.
+ * @fn size_t vo_taskRead (int fd, void *vptr, size_t nbytes)
+ *
+ * @param fd file descriptor
+ * @param vptr data buffer to be written
+ * @param nbytes number of bytes to write
+ * @return number of bytes written
+ */
+static size_t
+vo_taskRead (int fd, void *vptr, size_t nbytes)
+{
+ char *ptr = vptr;
+ int nread = 0, nleft = nbytes, nb = 0, flags = 0;
+ fd_set allset, fds;
+ struct timeval tm = { 2, 0 };
+
+
+ /* Set non-blocking mode on the descriptor.
+ */
+ if ((flags = fcntl (fd, F_GETFL, 0)) == 0)
+ if (fcntl (fd, F_SETFL, flags | O_NONBLOCK) < 0)
+ ; /* ignore error */
+
+ FD_ZERO (&allset);
+ FD_SET (fd, &allset);
+
+ while (nleft > 0) {
+ memcpy (&fds, &allset, sizeof(allset));
+ if (select (SELWIDTH, &fds, NULL, NULL, &tm)) {
+ if ( (nb = read (fd, ptr, nleft)) < 0) {
+ if (errno == EINTR || errno == EAGAIN)
+ nb = 0; /* and call recv() again */
+ else
+ return (-1);
+ } else if (nb == 0)
+ break; /* EOF */
+ nleft -= nb;
+ ptr += nb;
+ nread += nb;
+ }
+ }
+
+ return (nread); /* return no. of bytes read */
+}
+
+
+/**
+ * VO_TASKWRITE -- Write exactly "n" bytes to a task descriptor.
+ *
+ * @brief Send exactly "n" bytes to a task descriptor.
+ * @fn size_t vo_taskWrite (int fd, void *vptr, size_t nbytes)
+ *
+ * @param fd file descriptor
+ * @param vptr data buffer to be written
+ * @param nbytes number of bytes to write
+ * @return number of bytes written
+ */
+static size_t
+vo_taskWrite (int fd, void *vptr, size_t nbytes)
+{
+ char *ptr = vptr;
+ int nwritten = 0, nleft = nbytes, nb = 0, flags = 0;
+ fd_set allset, fds;
+ struct timeval tm = { 2, 0 };
+
+
+ /* Set non-blocking mode on the descriptor.
+ */
+ if ((flags = fcntl (fd, F_GETFL, 0)) == 0)
+ if (fcntl (fd, F_SETFL, flags | O_NONBLOCK) < 0)
+ ; /* ignore error */
+
+ FD_ZERO (&allset);
+ FD_SET (fd, &allset);
+
+ while (nleft > 0) {
+ memcpy (&fds, &allset, sizeof(allset));
+ if (select (SELWIDTH, NULL, &fds, NULL, &tm)) {
+ if ( (nb = write (fd, ptr, nleft)) <= 0) {
+ if (errno == EINTR || errno == EAGAIN)
+ nb = 0; /* and call write() again */
+ else
+ return (-1);
+ }
+ nleft -= nb;
+ ptr += nb;
+ nwritten += nb;
+ }
+ }
+
+ return (nwritten);
+}
+
+
+
+#ifdef VO_UNIT_TESTS
+
+/************************************************************************/
+ * Test Task declarations.
+ */
+int test_0 (int argc, char **argv, size_t *len, void **result);
+int test_1 (int argc, char **argv, size_t *len, void **result);
+int test_2 (int argc, char **argv, size_t *len, void **result);
+int test_3 (int argc, char **argv, size_t *len, void **result);
+int test_4 (int argc, char **argv, size_t *len, void **result);
+int test_5 (int argc, char **argv, size_t *len, void **result);
+int test_6 (int argc, char **argv, size_t *len, void **result);
+int test_7 (int argc, char **argv, size_t *len, void **result);
+
+Task testApps[] = {
+ { "test0", test_0 }, /* test applications */
+ { "test1", test_1 },
+ { "test2", test_2 },
+ { "test3", test_3 },
+ { "test4", test_4 },
+ { "test5", test_5 },
+ { "test6", test_6 },
+ { "test7", test_7 },
+ { NULL, NULL },
+};
+
+
+/* Child doesn't return a result.
+ */
+int test_0 (int argc, char **argv, size_t *len, void **result)
+{
+ return (0);
+}
+
+/* Child returns an error code.
+ */
+int test_1 (int argc, char **argv, size_t *len, void **result)
+{
+ return (1);
+}
+
+/* Child returns a result.
+ */
+int test_2 (int argc, char **argv, size_t *len, void **result)
+{
+ char *str = strdup ("this is a test reply object");
+
+ *len = strlen (str);
+ if (*result == NULL)
+ *result = calloc (1, strlen (str) + 1);
+ strcpy ((char *) *result, str);
+
+ free (str);
+ return (0);
+}
+
+/* Child exits with status code
+ */
+int test_3 (int argc, char **argv, size_t *len, void **result)
+{
+ _exit (5);
+}
+
+/* Child exits w/ FPE
+ */
+int test_4 (int argc, char **argv, size_t *len, void **result)
+{
+ int i=1, j=0, k = 0;
+ k = i / j;
+}
+
+/* Child exits w/ segfault
+ */
+int test_5 (int argc, char **argv, size_t *len, void **result)
+{
+ char *foo = NULL;
+ strcpy (foo, "bar");
+}
+
+/* Child exits w/ SIGINT
+ */
+int test_6 (int argc, char **argv, size_t *len, void **result)
+{
+ raise (SIGINT);
+}
+
+/* Multiple children....
+ */
+int test_7 (int argc, char **argv, size_t *len, void **result)
+{
+ pid_t pid;
+
+ if ((pid = fork()) < 0)
+ perror ("fork fails");
+ else if (pid == 0)
+ raise (SIGILL); /* child */
+ else {
+ sleep (1); wait (NULL); return (0);
+ }
+}
+
+
+/**
+ * Program entry point.
+ */
+int
+main (int argc, char *argv[])
+{
+ runTest ("test0", argc, argv);
+ runTest ("test1", argc, argv);
+ runTest ("test2", argc, argv);
+ runTest ("test3", argc, argv);
+ runTest ("test4", argc, argv);
+ runTest ("test5", argc, argv);
+ runTest ("test6", argc, argv);
+ runTest ("test7", argc, argv);
+
+ return (0);
+}
+
+int runTest (char *task, int argc, char **argv)
+{
+ int status = 0, len = 0;
+ void *res = (void *) NULL;
+
+ fprintf (stderr, "Running '%s' .... ", task);
+ status = vo_runTask (task, argc, argv, &len, &res);
+ fprintf (stderr, "status=%d len=%d res='%s'\n", status, len, (char *)res);
+ if (res)
+ free (res);
+}
+
+#endif /* VO_UNIT_TESTS */
diff --git a/vendor/voclient/voapps/lib/voUtil.c b/vendor/voclient/voapps/lib/voUtil.c
new file mode 100644
index 00000000..d367cf54
--- /dev/null
+++ b/vendor/voclient/voapps/lib/voUtil.c
@@ -0,0 +1,2389 @@
+/****************************************************************************
+** VOUTIL.C -- Utility procedures for the VO-CLI tasks.
+**
+** M. Fitzpatrick, NOAO, June 2007
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <dirent.h>
+#include <unistd.h>
+#include <ctype.h>
+#include <string.h>
+#include <time.h>
+
+#include <curl/curl.h>
+#include <curl/types.h>
+#include <curl/easy.h>
+
+#include "VOClient.h"
+#include "votParse.h"
+#include "voAppsP.h"
+#include "voApps.h"
+
+
+#define SZ_RESBUF (256*256)
+#define SZ_QUERY 40960
+#define SZ_QSTRING 40960
+
+#define DEF_RESATTR "ServiceURL"
+#define MAX_ATTRS 32
+
+static int reg_nresolved = 0;
+
+
+extern int verbose, count, debug, errno, meta, res_all, quiet, do_votable;
+extern int group, nterms, table_hskip, ecols;
+extern char *terms[], *delim;
+
+
+int vot_regResolver (char *id, char *svctype, char *bpass, char *subject,
+ char *clevel, char *fields, int index, int exact,
+ int dalOnly, char **result);
+int vot_regSearch (char **ids, int nids, char *svctype, char *bpass,
+ char *subject, char *clevel, int orValues,
+ int votable, FILE *vot_fd,
+ int dalOnly, int sortRes, int terse);
+
+
+void pretty_print (char *result, int nresults);
+void pretty_print_table (char *result, int nresults, char *fields);
+void ppMultiLine (char *result, int poffset, int pwidth, int maxchars);
+void ppResSummary (char *result, int nresults);
+
+void vot_skipHdr (FILE *fd);
+char *vot_getTableCol (char *line, int col, int span);
+int vot_isNumericField (handle_t field);
+int vot_fileType (char *fname);
+
+char *vot_urlFname (char *url);
+void vot_printAttrs (char *fname, Query query, char *id);
+
+char *vot_parseSvcType (char *svctype, int exact);
+char *vot_parseBandpass (char *bpass);
+char *vot_parseSubject (char *subject);
+char *vot_parseCLevel (char *level);
+char *vot_mktemp (char *root);
+char *vot_copyStdin (void);
+
+/* Utility procedures.
+*/
+int isVOTable (char *fname);
+int isSexagesimal (char *str);
+int isDecimal (char *str);
+float sexa (char *s);
+char *toSexa (double pos);
+char *toSexaTime (int nsec);
+char *xmlEncode (char *in);
+
+int vot_atoi (char *val);
+long vot_atol (char *val);
+double vot_atof (char *val);
+
+void vot_setArg (char **argv, int *argc, char *value);
+void vot_printRegVOTableHdr (FILE *fd);
+void vot_printRegVOTableRec (FILE *fd, RegResult resource, int recnum);
+void vot_printRegVOTableTail (FILE *fd);
+
+extern char *strcasestr ();
+
+
+
+
+/****************************************************************************
+** Resolve a (presumed) ShortName or Identifier string to one or more
+** Registry resource attributes. By default we assume we are interested
+** only in the ServiceURL, however optional arguments allow us to narrow
+** the search to particular service types or individual records. Examples:
+**
+** 1) Find the ServiceURL for the GSC2.2 catalog
+**
+** cl> =regResolver ("GSC2.2")
+** http://chart.stsci.edu/GSCVO/GSC22VO.jsp?
+** cl> =nresolved()
+** 2 # found more than one resource
+**
+** 2) Print the Title and ServiceType for each record found for USNO-B1:
+**
+** cl> print (regResolver ("USNO-B1","","ServiceType,Title",-1))
+** CONE USNO-B1 Catalogue
+** SKYNODE USNO-B1 SkyNode from VizieR
+**
+** Note that in usage such as this we are still limited by the length
+** of output permitted by the print() function (currently 32*SZ_LINE).
+**
+** 3) Get the ServiceURL for the USNO-B1 Skynode service:
+**
+** cl> =regResolver ("USNO-B1","skynode")
+** http://cdsws.u-strasbg.fr/USNO-B1BasicSkyNode/services/BasicSkyNode
+**
+*/
+
+int
+vot_regResolver (char *term, char *svctype, char *bpass, char *subject,
+ char *clevel, char *fields, int index, int exact,
+ int dalOnly, char **res)
+{
+ int i, j, nreturns=0, nattrs=0, ret_attr_start=0, try_again=1;
+ int match=-1, istart, iend, recnum, alen, blen, bsize;
+ char *ip, *field_str = (char *)NULL;
+ char *attr_val=NULL, *attr_list[MAX_ATTRS], id[SZ_LINE];
+ char qstring[SZ_QSTRING], *svcstr, *bpstr, *substr, *conlev, *buf;
+ char attr_str[SZ_LINE], sbuf[SZ_RESBUF];
+ RegQuery query = 0;
+ RegResult resource = 0;
+
+
+ if (term[0]) {
+ bzero (id, SZ_LINE);
+ strcpy (id, term);
+ }
+ if (debug)
+ fprintf (stderr, "regResolver init: id='%s' type='%s'\n",
+ (id[0] ? id : "null"), (svctype ? svctype : "null"));
+
+ /* Sanity checks.
+ */
+ if (!id[0] && !svctype && !svctype[0]) {
+ fprintf (stderr, "regResolver(): Must specify 'id' or 'svctype'\n");
+ return (0);
+ }
+
+ bzero (qstring, SZ_QSTRING);
+ bzero (sbuf, SZ_RESBUF);
+ strcpy (attr_str, DEF_RESATTR);
+
+
+ /* Set the default attribute list we want from the query.
+ */
+ attr_list[0] = "ShortName";
+ attr_list[1] = "Identifier";
+ attr_list[2] = "Title";
+ attr_list[3] = "AccessUrl";
+ nattrs = 4;
+
+ /* Parse the fields argument if any.
+ */
+ if (fields && fields[0]) {
+ /* If we were given a list of fields, assume we want only those
+ ** and in that particular order.
+ */
+ ret_attr_start = nattrs;
+
+ /* Split up the input 'fields' string for use in the attr_list.
+ */
+ field_str = strdup (fields);
+ for (ip=field_str; *ip && nattrs < MAX_ATTRS; ) {
+ attr_list[nattrs++] = ip;
+ while (*ip && *ip != ',')
+ ip++;
+ if (*ip == ',')
+ *ip++ = '\0';
+ else
+ break;
+ }
+ } else
+ ret_attr_start = nattrs - 1; /* return ServiceURL only */
+
+
+ /* Now parse the service type and bandpass for extra constraints.
+ */
+ svcstr = vot_parseSvcType (svctype, !res_all);
+ bpstr = vot_parseBandpass (bpass);
+ substr = vot_parseSubject (subject);
+ conlev = vot_parseCLevel (clevel);
+
+ if (strcmp (id, "%") == 0) {
+ if (bpass || svctype || subject) {
+
+ /* Protect against a French overload.
+ */
+ if (!(subject || bpass) &&
+ (strcasestr(svctype,"table") ||
+ strcasestr(svctype,"tabular") ||
+ strcasestr(svctype,"vizier"))) {
+ fprintf (stderr, "Warning: Query too large to process.\n");
+ return (0);
+ }
+
+ bzero (qstring, SZ_QSTRING);
+ if (bpstr) { /* add bandpass constraint */
+ strcpy (qstring, bpstr);
+ }
+ if (svcstr) { /* add service constraint */
+ if (qstring[0])
+ strcat (qstring, " AND ");
+ strcat (qstring, svcstr);
+ }
+ if (substr) { /* add subject constraint */
+ if (qstring[0])
+ strcat (qstring, " AND ");
+ strcat (qstring, substr);
+ }
+ if (conlev) { /* add content constraint */
+ if (qstring[0])
+ strcat (qstring, " AND ");
+ strcat (qstring, conlev);
+ }
+
+ /* Execute the query. */
+ if (strcasestr (svcstr, "catalog"))
+ resource = voc_regSearch (qstring, "catalog", 0);
+ else
+ resource = voc_regSearch (qstring, NULL, 0);
+
+ } else {
+ fprintf (stderr, "Warning: Query too large to process.\n");
+ return (0);
+ }
+
+ } else {
+
+ /* Lastly, set the query string we'll be using.
+ */
+retry:
+ if (group) {
+ for (i=0; i < nterms; i++) {
+ strcat (qstring, terms[i]);
+ if (i < (nterms -1))
+ strcat (qstring, " OR ");
+ }
+ } else if (id[0]) {
+ char term[SZ_LINE], *ip, *op;
+
+ memset (term, 0, SZ_LINE);
+ for (ip=id, op=term; *ip && *ip != '#'; )
+ *op++ = *ip++;
+
+ if (exact) {
+ sprintf (qstring,
+ "((Identifier like '%s') OR (ShortName like '%s'))",
+ term, term);
+ } else {
+ sprintf (qstring,
+ "((Identifier like '%%%s%%') OR (ShortName like '%%%s%%'))",
+ term, term);
+ }
+ }
+
+ /* Do the registry query. Add the service-specific part of the query
+ ** once we get a handle.
+ */
+ query = voc_regQuery (qstring, 0);
+ if (bpass && bpass[0]) {
+ voc_regAddSearchTerm (query, bpstr, 0);
+ voc_regConstWaveband (query, bpass);
+ }
+ if (svctype && svctype[0]) {
+ voc_regAddSearchTerm (query, svcstr, 0);
+ voc_regConstSvcType (query, svctype);
+ }
+ if (substr && substr[0])
+ voc_regAddSearchTerm (query, substr, 0);
+ if (conlev && conlev[0])
+ voc_regAddSearchTerm (query, conlev, 0);
+ if (dalOnly)
+ voc_regDALOnly (query, dalOnly);
+
+ if (debug) {
+ printf ("regResolver: id='%s' type='%s' fields='%s' index=%d\n",
+ (id[0] ? id : "null"),
+ (svctype ? svctype : "null"),
+ (fields ? fields : "null"), index);
+ printf ("query string:\n\n%s\n\n", voc_regGetQueryString (query));
+ }
+
+ /* Execute the query.
+ */
+ resource = voc_regExecute (query);
+ }
+
+ blen = 0; /* length of result buffer used */
+
+ /* Save the number of resolved resources and get the requested attribute
+ * (or the default service URL).
+ */
+ reg_nresolved = voc_resGetCount (resource);
+ if (reg_nresolved > 0) {
+ int isVizier = 0;
+
+ bsize = (reg_nresolved * SZ_LINE); /* max size of result buffer */
+ buf = (char *) calloc (1, bsize);
+
+ if (do_votable) {
+ for (i=0; i < reg_nresolved; i++)
+ vot_printRegVOTableRec (stdout, resource, i);
+
+ return (reg_nresolved); /* return number of matches found */
+ }
+
+ nreturns = (index >= 0 ? 1 : reg_nresolved);
+
+ match = 0;
+ if (index >= 0 && reg_nresolved > 1) {
+ /* We didn't specify a record number but have more than one
+ * result. Look for an exact match in the ShortName or
+ * Identified which was a hidden part of the query.
+ */
+ for (i=0; i < reg_nresolved; i++) {
+ for (j=0; j < 2; j++) {
+ if ((attr_val = voc_resGetStr(resource, attr_list[j], i))) {
+ if (strncasecmp (id, attr_val, strlen(attr_val)) == 0) {
+ reg_nresolved = 1;
+ nreturns = 1;
+ match = i;
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ if (index >= 0) {
+ istart = index;
+ iend = index + 1;
+ reg_nresolved = 1;
+ } else if (match >= 0 && nreturns == 1) {
+ istart = match;
+ iend = match + 1;
+ reg_nresolved = 1;
+ } else {
+ istart = 0;
+ iend = nreturns;
+ }
+
+ /* For a negative index we list the attr for all records.
+ */
+ recnum = 0;
+ if (dalOnly)
+ reg_nresolved = 0;
+ for (i=istart; i < iend; i++) {
+ isVizier = 0;
+
+ if (dalOnly) {
+ int valid = 1;
+ for (j=ret_attr_start; j < nattrs; j++) {
+ if (strcmp (attr_list[j], "CapabilityStandardID") == 0) {
+ attr_val = voc_resGetStr (resource, attr_list[j], i);
+ if (attr_val) {
+ char *a = attr_val;
+ if (! (strncasecmp (a, "cone", 4) == 0 ||
+ strncasecmp (a, "sia", 3) == 0 ||
+ strncasecmp (a, "simpleimage", 10) == 0 ||
+ strncasecmp (a, "ssap", 4) == 0 ||
+ strncasecmp (a, "simplespec", 9) == 0)) {
+ valid = 0;
+ } else
+ reg_nresolved++;
+ }
+ break;
+ }
+ }
+ if (!valid)
+ continue;
+ }
+
+ for (j=ret_attr_start; j < nattrs; j++) {
+ attr_val = voc_resGetStr (resource, attr_list[j], i);
+ if (strncasecmp (attr_list[j], "identifier", 10) == 0)
+ isVizier = (attr_val && strcasestr (attr_val, "vizier"));
+ if (attr_val) {
+ alen = strlen (attr_val);
+ strcat (buf, attr_val);
+ if (j < (nattrs-1))
+ strcat (buf, "\t");
+ voc_freePointer ((char *) attr_val);
+ } else {
+ alen = 0;
+ strcat (buf, (isVizier ? "Catalog\t" : "INDEF\t"));
+ }
+
+ blen += max (alen, 10);
+ }
+ //if (nreturns > 1 && i < (reg_nresolved-1))
+ if (nreturns > 1)
+ strcat (buf, "\n");
+
+ recnum++;
+ }
+
+ attr_val = (char *) NULL;
+
+ } else {
+
+ if (try_again) {
+ if (strncasecmp("ivo://CDS.VizieR",id,16) == 0) {
+ char *ip, ivorn[SZ_LINE];
+ int len = strlen (id);
+
+ bzero (ivorn, SZ_LINE);
+ strcpy (ivorn, id);
+ for (ip = &ivorn[len-1]; *ip != '/'; ip--)
+ *ip = '\0';
+ *ip = '\0';
+
+ strcpy (id, ivorn);
+ try_again = 0;
+ goto retry;
+ }
+ }
+
+ buf = (char *) calloc (1, SZ_RESBUF);
+ for (j=0; j < nattrs; j++) {
+ strcpy (buf, "INDEF");
+ if (j < (nattrs-1))
+ strcat (buf, "\t");
+ }
+ }
+
+ if (field_str) free ((char *) field_str); /* free local memory */
+
+ /* Push the result operand on the return variable. We assume the result
+ ** is large enough for the value.
+ */
+ *res = buf;
+
+ if (bpstr) free (bpstr);
+ if (svcstr) free (svcstr);
+ if (substr) free (substr);
+
+ if (debug)
+ printf ("regResolver: reg_nresolved = %d\n", reg_nresolved);
+
+ return (reg_nresolved); /* return number of matches found */
+}
+
+
+/****************************************************************************
+** Search the registry for the given phrase and constraints.
+*/
+int
+vot_regSearch (char **ids, int nids, char *svctype, char *bpass,
+ char *subject, char *clevel, int orValues, int votable,
+ FILE *vot_fd, int dalOnly, int sortRes, int terse)
+{
+ int i, nresults=0, nattrs=0, keywOnly = 1, haveADQL;
+ char *attr_val=NULL, *attr_list[MAX_ATTRS];
+ char qstring[SZ_QUERY], keyws[SZ_RESBUF], *svcstr, *bpstr, *substr;
+ char term2[SZ_QUERY], *conlev;
+ char attr_str[SZ_LINE], *results, buf[SZ_LINE], cname[SZ_LINE];
+ RegResult res = 0;
+
+
+ strcpy (attr_str, DEF_RESATTR);
+
+ /* Set the default attribute list we want from the query.
+ */
+ attr_list[0] = "Title";
+ attr_list[1] = "CapabilityStandardID";
+ attr_list[2] = "ShortName";
+ attr_list[3] = "Subject";
+ attr_list[4] = "Identifier";
+ attr_list[5] = "ServiceUrl";
+ attr_list[6] = "Description";
+
+ switch (verbose) {
+ case 0: nattrs = 4; break;
+ case 1: nattrs = 5; break;
+ case 2: nattrs = 7; break;
+ }
+
+
+ /* Now parse the service type and bandpass for extra constraints.
+ */
+ svcstr = vot_parseSvcType (svctype, !res_all);
+ bpstr = vot_parseBandpass (bpass);
+ substr = vot_parseSubject (subject);
+ conlev = vot_parseCLevel (clevel);
+
+ /* Begin forming the SQL query term we'll use
+ */
+ bzero (qstring, SZ_QUERY);
+ bzero (term2, SZ_QUERY);
+ bzero (keyws, SZ_RESBUF);
+
+
+ /* Extract any terms that may be ADQL strings.
+ */
+ for (i=0; i < nids; i++) {
+ if (strcasestr (ids[i], "like") ||
+ strcasestr (ids[i], "<") ||
+ strcasestr (ids[i], ">") ||
+ strcasestr (ids[i], "=")) {
+ if (qstring[0] && orValues)
+ strcat (qstring, " OR ");
+ else if (qstring[0])
+ strcat (qstring, " AND ");
+ sprintf (buf, "(%s)", ids[i]);
+ strcat (qstring, buf);
+ keywOnly = 0;
+ haveADQL = 1;
+ }
+ }
+ for (i=1; i < nids; i++) {
+ strcat (term2, ids[i]);
+ if (i < (nids-1))
+ strcat (term2, " ");
+ }
+
+ if (nids == 0 || (nids == 1 && strcmp ("any", *ids) == 0)) {
+ strcpy (qstring, "(Identifier like '%')");
+ keywOnly = 0;
+ }
+
+
+ if (!keywOnly || nids == 0) {
+ if (svcstr) { /* add service constraint */
+ if (qstring[0]) {
+ sprintf (buf, "(%s) AND (%s)", qstring, svcstr);
+ strcpy (qstring, buf);
+ } else {
+ strcat (qstring, svcstr);
+ }
+ }
+ if (bpstr) { /* add bandpass constraint */
+ if (qstring[0]) {
+ sprintf (buf, "(%s) AND (%s)", qstring, bpstr);
+ strcpy (qstring, buf);
+ } else {
+ strcat (qstring, bpstr);
+ }
+ }
+ if (substr) { /* add subject constraint */
+ if (qstring[0]) {
+ sprintf (buf, "(%s) AND (%s)", qstring, substr);
+ strcpy (qstring, buf);
+ } else {
+ strcat (qstring, substr);
+ }
+ }
+ if (conlev) { /* add subject constraint */
+ if (qstring[0]) {
+ sprintf (buf, "(%s) AND (%s)", qstring, conlev);
+ strcpy (qstring, buf);
+ } else {
+ strcat (qstring, conlev);
+ }
+ }
+ }
+
+
+ /* Build a string arrays of the keyword terms.
+ */
+ if (ids[0] && keywOnly) {
+ RegQuery query = (RegQuery) 0;
+
+ if (nids == 0 || (nids == 1 && strcmp ("any", *ids) == 0)) {
+ strcpy (qstring, "(Identifier like '%')");
+ query = voc_regQuery (qstring, FALSE); /* get a query object */
+
+ } else {
+ for (i=0; i < nids; i++) {
+ if (keyws[0])
+ strcat (keyws, " ");
+ if (!strcasestr (ids[i], "like") &&
+ !strcasestr (ids[i], "<") &&
+ !strcasestr (ids[i], ">") &&
+ !strcasestr (ids[i], "="))
+ strcat (keyws, ids[i]);
+ }
+ query = voc_regQuery (keyws, orValues); /* get a query object */
+ }
+
+#ifdef USE_CONSTRAINTS
+ if (svctype) /* set constraints */
+ voc_regConstSvcType (query, svctype);
+ if (bpass)
+ voc_regConstWaveband (query, bpass);
+#else
+ if (svcstr && svcstr[0])
+ voc_regAddSearchTerm (query, svcstr, 0);
+ if (bpstr && bpstr[0])
+ voc_regAddSearchTerm (query, bpstr, 0);
+#endif
+
+ if (substr && substr[0])
+ voc_regAddSearchTerm (query, substr, 0);
+ if (conlev && conlev[0])
+ voc_regAddSearchTerm (query, conlev, 0);
+ if (dalOnly)
+ voc_regDALOnly (query, dalOnly);
+ voc_regSortRes (query, sortRes);
+
+ res = voc_regExecute (query); /* execute it */
+
+ } else {
+/*
+ res = voc_regSearch (qstring, NULL, orValues);
+*/
+ res = voc_regSearch (qstring, term2, orValues);
+ bzero (keyws, SZ_RESBUF);
+ }
+ nresults = voc_resGetCount (res);
+
+
+ /* If no response, see if it was a ShortName used as a keyword term...
+ */
+ if (nresults == 0 && !(svcstr || bpstr || substr || conlev) && !haveADQL) {
+ bzero (qstring, SZ_QUERY);
+ if (ids[0]) {
+ for (i=0; i < nids; i++) {
+ if (qstring[0])
+ strcat (qstring, " OR ");
+ if (!strcasestr (ids[i], "like") &&
+ !strcasestr (ids[i], "<") &&
+ !strcasestr (ids[i], ">") &&
+ !strcasestr (ids[i], "=")) {
+ sprintf (buf,
+ "(ShortName like '%s') OR (Identifier like '%s')",
+ ids[i], ids[i]);
+ strcat (qstring, buf);
+ }
+ }
+ }
+
+ res = voc_regSearch (qstring, (nids ? keyws : NULL), 1);
+
+ nresults = voc_resGetCount (res);
+ if (nresults && !count) {
+ verbose = 2;
+ } else if (nresults == 0) {
+ res = voc_regSearch (qstring, NULL, orValues);
+ nresults = voc_resGetCount (res);
+ }
+ }
+
+ if (debug)
+ printf ("regSearch: qstr='%s' keyws='%s' nres = %d\n",
+ qstring, keyws, nresults);
+
+
+ /* No longer need the query buffers so free them here.
+ */
+ if (svcstr) free (svcstr);
+ if (bpstr) free (bpstr);
+ if (substr) free (substr);
+
+
+ /* Return the result count if that's all we wanted.
+ */
+ if (count) {
+ results = (char *)calloc (1, (nresults * 30));
+ strcpy (results, " \t");
+ for (i=0; i < nresults; i++) {
+ attr_val = voc_resGetStr (res, attr_list[1], i); /* SvcType */
+ strcat (results, (attr_val ? attr_val : " "));
+ strcat (results, "\t \n\t");
+ voc_freePointer ((char *) attr_val);
+ }
+ if (keyws[0])
+ printf ("%-20s %3d\t", keyws, nresults);
+ else
+ printf ("%d ", nresults);
+ if (verbose && !bpstr)
+ ppResSummary (results, nresults);
+ printf ("\n");
+
+ free ((char *) results);
+ return (nresults);
+ }
+
+
+ if (votable) {
+ for (i=0; i < nresults; i++) {
+ vot_printRegVOTableRec (vot_fd, res, i);
+ }
+ return (nresults); /* return number of matches found */
+ }
+
+ /* Print out the results for each resource based on the verbosity
+ ** level.
+ **
+ ** Title: <title> ServiceType: <type> verb = 0
+ ** ShortName: <name> Subject: <id> verb = 0
+ ** Identifier: <id> ServiceURL: <url> verb = 1
+ ** Description: <descr> verb = 2
+ **
+ */
+ for (i=0; i < nresults; i++) {
+
+ if (i > 0 && !terse)
+ printf ("-----------------------------------------------\n");
+
+ if (dalOnly) { /* CapName */
+ attr_val = voc_resGetStr (res, "CapabilityName", i);
+ bzero (cname, SZ_LINE);
+ strcpy (cname, (attr_val ? attr_val : ""));
+ voc_freePointer ((char *) attr_val);
+ }
+
+ if (terse) {
+ /*
+ int idx = voc_resGetInt (res, "index", i),
+ rank = voc_resGetInt (res, "rank", i);
+
+ printf ("%2d(%2d) ", rank, idx);
+ */
+ if (sortRes)
+ printf ("%3d %3d ", i, voc_resGetInt(res, "index", i) );
+
+ if (terse > 1) {
+ /* "Tweet" format.
+ */
+ char *ip;
+
+ printf ("New VO Resource: ");
+
+ attr_val = voc_resGetStr (res, "Title", i);
+ printf ("\"%-s\" ", attr_val);
+ voc_freePointer ((char *) attr_val);
+
+ attr_val = voc_resGetStr (res, "Waveband", i);
+ printf ("W:%s ", attr_val);
+ voc_freePointer ((char *) attr_val);
+
+ attr_val = voc_resGetStr (res, "CapabilityStandardID", i);
+ printf ("T:%s ", attr_val);
+ voc_freePointer ((char *) attr_val);
+
+ attr_val = voc_resGetStr (res, "Subject", i);
+ if (attr_val && (ip = strchr (attr_val, (int)':')))
+ *ip = '\0'; /* kill qualifiers */
+ printf ("S:%-s\n", attr_val);
+ voc_freePointer ((char *) attr_val);
+
+ } else {
+ attr_val = voc_resGetStr (res, attr_list[1], i);/* SvcType */
+ printf ("%-7.7s ", attr_val);
+ voc_freePointer ((char *) attr_val);
+
+ attr_val = voc_resGetStr (res, attr_list[0], i);/* Title */
+ printf ((sortRes ? "%-63.63s\n" : "%-71.71s\n"), attr_val);
+ voc_freePointer ((char *) attr_val);
+ }
+
+ continue;
+
+ } else {
+ attr_val = voc_resGetStr (res, attr_list[1], i); /* SvcType */
+ printf (" Type: %-s\n", attr_val);
+ voc_freePointer ((char *) attr_val);
+
+ attr_val = voc_resGetStr (res, attr_list[0], i); /* Title */
+ printf (" Title: ");
+ ppMultiLine (attr_val, 13, 67, 1024);
+ printf ("\n");
+ voc_freePointer ((char *) attr_val);
+ }
+
+ attr_val = voc_resGetStr (res, attr_list[2], i); /* ShortName */
+ if (dalOnly && verbose == 0) {
+ printf (" ShortName: %-s\n", attr_val);
+ printf ("ServiceName: %s\n", cname);
+ } else
+ printf (" ShortName: %-s\n", attr_val);
+ voc_freePointer ((char *) attr_val);
+
+ attr_val = voc_resGetStr (res, attr_list[3], i); /* Subject */
+ printf (" Subject: ");
+ ppMultiLine (attr_val, 13, 67, 1024);
+ printf ("\n");
+ voc_freePointer ((char *) attr_val);
+
+ if (verbose == 0)
+ continue;
+
+ attr_val = voc_resGetStr (res, attr_list[4], i); /* Identifier */
+ if (dalOnly)
+ printf (" Identifier: %-s#%s\n", attr_val, cname);
+ else
+ printf (" Identifier: %-s\n", attr_val);
+ voc_freePointer ((char *) attr_val);
+
+ attr_val = voc_resGetStr (res, attr_list[5], i); /* ServiceUrl */
+ printf (" ServiceURL: %-s\n", attr_val);
+ voc_freePointer ((char *) attr_val);
+
+ if (verbose == 1)
+ continue;
+
+ attr_val = voc_resGetStr (res, attr_list[6], i); /* Descr. */
+ printf ("Description: ");
+ ppMultiLine (attr_val, 13, 67, 1024);
+ printf ("\n");
+ voc_freePointer ((char *) attr_val);
+ }
+
+ return (nresults); /* return number of matches found */
+}
+
+
+/************************************************************************
+** PRETTY_PRINT -- Pretty-print a table for verbose resolution output.
+*/
+void
+pretty_print (char *result, int nresults)
+{
+ int i, j, ncols, col;
+ char *ip, value[SZ_RESULT];
+
+
+ /* pretty-print the table using the defined widths.
+ */
+ if (verbose) {
+ ip = result;
+ ncols = 3;
+ for (i=0; i < nresults; i++) {
+ j = 0;
+ for (col=0; col < ncols; ) {
+ bzero (value, SZ_RESULT);
+ while (*ip && (*ip != '\t' && *ip != '\n'))
+ value[j++] = *ip++;
+
+ if (col == (ncols-1)) {
+ ppMultiLine (value, PP_OFFSET, PP_WIDTH, PP_MAXCHARS);
+ break;
+ } else
+ printf ("%-20s", value);
+
+ j = 0;
+ col++;
+ ip++;
+ }
+ printf ("\n");
+ ip++;
+ }
+ } else {
+ printf ("%s\n", result);
+ return;
+ }
+
+}
+
+
+/************************************************************************
+** PPRESSUMMARY -- Print a summary of the resources found. Assumes the
+** ServiceType is the second column of the result string.
+*/
+
+void
+ppResSummary (char *result, int nresults)
+{
+ register int i, j;
+ int Ni = 0, /* image count */
+ Nc = 0, /* catalog count */
+ Nt = 0, /* table count */
+ Ns = 0, /* spectra count */
+ Nsn = 0, /* SkyNode count */
+ Nother = 0; /* 'other' count */
+ char *ip, value[SZ_RESULT];
+
+
+ if (nresults == 0 || verbose == 1)
+ return;
+
+ ip = result;
+ for (i=0; i < nresults; i++) {
+ bzero (value, SZ_RESULT);
+ while (*ip != '\t') ip++; /* skip first column */
+ for (++ip, j=0; *ip != '\t';) /* gather the value */
+ value[j++] = tolower (*ip++);
+ while (*ip && *ip != '\n') ip++; /* skip last column */
+ ip++;
+
+ if (strstr (value, "siap"))
+ Ni++;
+ else if (strstr (value, "cone"))
+ Nc++;
+ else if (strstr (value, "tabular"))
+ Nt++;
+ else if (strstr (value, "ssap"))
+ Ns++;
+ else if (strstr (value, "skynode") || strstr (value, "skyservice"))
+ Nsn++;
+ else
+ Nother++;
+ }
+
+ printf ("(");
+ if (Nc) printf ("Cat: %-2d ", Nc);
+ if (Nt) printf ("Tab: %-2d ", Nt);
+ if (Ni) printf ("Img: %-2d ", Ni);
+ if (Ns) printf ("Spec: %-2d ", Ns);
+ if (Nsn) printf ("SNode: %-2d ", Nsn);
+ if (Nother) printf ("Other: %-2d", Nother);
+ printf (")");
+}
+
+
+
+/************************************************************************
+** PPMULTILINE -- Print a lengthy string on multiple lines. Used to print
+** the last column of a table where we indent the carried-over lines to the
+** specified offset. No effort is made to break lines at a 'nice' spot
+** since long URLs and such won't fit anyway, so we just cut the line and
+** continue.
+*/
+
+void
+ppMultiLine (char *result, int poffset, int pwidth, int maxchars)
+{
+ register int i, j, ellipses = 0;
+ int len = strlen((result ? result : ""));
+ char *ip;
+ extern int longlines;
+
+ if (result)
+ len = strlen (result);
+ else
+ return;
+
+
+ for (i=0; i < len-1; i++ ) {
+ if (result[i] == '\n' && result[i+1] != '\n')
+ result[i] = ' ';
+ }
+
+ ip = &result[len-1]; /* strip trailing w/s */
+ while ((isspace(*ip) || *ip == '\n') && ip > result)
+ *ip-- = '\0';
+
+ if (longlines) {
+ printf ("%s", result);
+ return;
+ }
+
+ if (len > maxchars) {
+ result[maxchars] = '\0';
+ len = maxchars;
+ ellipses++;
+ }
+
+ if (len < pwidth) {
+ for (ip=result; *ip && isspace(*ip); )
+ ip++;
+ printf ("%s", ip);
+ } else {
+ j = pwidth;
+ for (i=0; i < len; ) {
+ while (isspace (result[i])) i++;
+
+ printf ("%-*.*s\n", pwidth, pwidth, &result[i]);
+ i = j + 1;
+ j += pwidth;
+ printf ("%*s", poffset, " ");
+ if (j > len) {
+ while (isspace (result[i])) i++;
+ printf ("%s", &result[i]);
+ if (ellipses)
+ printf (" (read more)....");
+ break;
+ }
+ }
+ }
+}
+
+
+/************************************************************************
+** PRETTY_PRINT_TABLE -- Pretty-print a table with computed column widths.
+*/
+void
+pretty_print_table (char *result, int nresults, char *fields)
+{
+ int i, j, w, ncols, col, width[256];
+ char *ip, value[SZ_RESULT];
+
+
+ if (!result)
+ return;
+ if (!verbose && !fields) {
+ printf ("%s\n", result);
+ return;
+ }
+
+
+ /* Figure out how many columns there are.
+ */
+ for (ip=result, ncols=1; *ip && *ip != '\n'; ip++) {/* do only 1st line */
+ if (*ip && *ip == '\t')
+ ncols++;
+ }
+
+ /* Calculate the column widths needed to align the columns.
+ */
+ bzero (width, 256 * sizeof(int));
+ ip = result;
+ for (i=0; i < nresults; i++) {
+ for (w=0, col=0; *ip; ) {
+ if (*ip == '\t' || *ip == '\n') {
+ if (w >= width[col])
+ width[col] = w + 3;
+ w = 0;
+ col++;
+ } else
+ w++;
+ if (*ip++ == '\n')
+ break;
+ }
+ }
+
+
+ /* Now print the table using the computed widths.
+ */
+ ip = result;
+ for (i=0; i < nresults; i++) {
+ j = 0;
+ bzero (value, SZ_RESULT);
+ for (col=0; col < ncols; ) {
+ if (!*ip || (*ip == '\t' || *ip == '\n')) {
+ value[j++] = '\0';
+ if (col == (ncols-1))
+ printf ("%-s", value);
+ else
+ printf ("%-*s", width[col], value);
+ j = 0;
+ col++;
+ } else
+ value[j++] = *ip;
+ if (*ip && *ip == '\n')
+ break;
+ ip++;
+ }
+ printf ("\n");
+ ip++;
+ }
+}
+
+
+
+/****************************************************************************
+** VOT_PARSESVCTYPE -- Parse the service type specification. Allow for
+** synonyms like 'catalog' for 'cone', 'image' for 'siap', etc.
+*/
+char *
+vot_parseSvcType (char *svctype, int exact)
+{
+ char *ip, *op, val[SZ_FNAME], buf[SZ_FNAME];
+ char *svcstr = NULL, *like = NULL;
+ int not = 0, more = 0;
+
+
+ like = (exact ? "" : "%"); /* initialize */
+
+ if (svctype && svctype[0]) {
+ svcstr = calloc (1, 4*SZ_LINE);
+
+ strcat (svcstr, "(");
+ for (ip=svctype; *ip; ) {
+ more = 0; /* re-initialize */
+ not = 0;
+ bzero (val, SZ_FNAME);
+
+ for (op=val; *ip; ) {
+ if (*ip == '-') {
+ not++, ip++;
+ } else if (*ip == ',') {
+ more++, ip++;
+ break;
+ } else
+ *op++ = *ip++;
+ }
+
+ /* Aliases for service type include:
+ **
+ ** Cone -> catalog
+ ** SIAP -> image
+ ** TABULARSKYSERVICE -> table
+ ** SSAP -> spectrum
+ ** TAP -> query
+ */
+ if (not) strcat (svcstr, "(!");
+
+ if (strncasecmp (val,"catalog",3) == 0)
+ strcat (svcstr, "(Tag like '%catalog%')");
+ else if (strncasecmp (val,"image",5) == 0)
+ strcat (svcstr, "(Tag like '%image%')");
+ else if (strncasecmp (val,"spectr",6) == 0)
+ strcat (svcstr, "(Tag like '%spec%')");
+ else if (strncasecmp (val,"table",5) == 0)
+ strcat (svcstr, "(Identifier like '%Vizier%')");
+ else {
+ bzero (buf, SZ_FNAME);
+ sprintf (buf, "(Tag like '%s%s%s')", like, val, like);
+ strcat (svcstr, buf);
+ }
+
+ if (not) strcat (svcstr, ")");
+ if (more) strcat (svcstr, " OR ");
+ }
+ strcat (svcstr, ")");
+
+ return (svcstr);
+ }
+
+ return ((char *)NULL);
+}
+
+
+
+/****************************************************************************
+** VOT_PARSEBANDPASS -- Convert a bandpass specification to an ADQL query. We
+** map things like 'x-ray' and 'xray' here to expand the query on behalf of
+** the user.
+**
+** Permitted values include:
+** "Radio", "Millimeter", "Infrared" (IR), "Optical", "Ultraviolet" (UV),
+** "X-Ray" (XRay), and "Gamma-Ray" (GR).
+*/
+char *
+vot_parseBandpass (char *bpass)
+{
+ char *ip, *op, val[SZ_FNAME], buf[SZ_FNAME];
+ char *bpstr = NULL;
+ int not = 0, more = 0;
+
+
+ if (bpass && bpass[0]) {
+ bpstr = calloc (1, 6*SZ_LINE);
+
+ strcat (bpstr, "(");
+ for (ip=bpass; *ip; ) {
+ more = 0; /* re-initialize */
+ not = 0;
+ bzero (val, SZ_FNAME);
+
+ for (op=val; *ip; ) {
+ if (*ip == '-' && strncasecmp(ip,"-ray",4)) {
+ not++, ip++;
+ } else if (*ip == ',') {
+ more++, ip++;
+ break;
+ } else
+ *op++ = *ip++;
+ }
+
+ if (not) strcat (bpstr, "(!");
+
+ if (strncasecmp (val, "radio",3) == 0)
+ strcat (bpstr, "([coverage/waveband] like '%radio%')");
+ else if (strncasecmp (val,"millimeter",9) == 0)
+ strcat (bpstr, "([coverage/waveband] like '%millimeter%')");
+ else if (strncasecmp (val,"infrared",5) == 0 ||
+ strncasecmp (val,"ir",2) == 0)
+ strcat (bpstr, "([coverage/waveband] like '%infrared%')");
+ else if (strncasecmp (val,"optical",8) == 0)
+ strcat (bpstr, "([coverage/waveband] like '%optical%')");
+ else if (strncasecmp (val,"ultraviolet",5) == 0 ||
+ strncasecmp (val,"uv",2) == 0)
+ strcat (bpstr,"([coverage/waveband] like '%ultraviolet%')");
+ else if (strncasecmp (val,"x-ray",5) == 0 ||
+ strncasecmp (val,"xray",4) == 0)
+ strcat (bpstr, "([coverage/waveband] like '%x-ray%')");
+ else if (strncasecmp (val,"gamma-ray",9) == 0 ||
+ strncasecmp (val,"gammaray",8) == 0)
+ strcat (bpstr, "([coverage/waveband] like '%gamma-ray%')");
+ else {
+ bzero (buf, SZ_FNAME);
+ sprintf (buf, "([coverage/waveband] like '%%%s%%')", val);
+ strcat (bpstr, buf);
+ }
+
+ if (not) strcat (bpstr, ")");
+ if (more) strcat (bpstr, " OR ");
+ }
+ strcat (bpstr, ")");
+
+ return (bpstr);
+ }
+
+ return ((char *)NULL);
+}
+
+
+/****************************************************************************
+** VOT_PARSESUBJECT -- Convert a subject specification to an ADQL query
+** string. We don't impose a vocabulary on the allowed Subject string, but
+** do allow the string to be a comma-delimited list of subjects.
+*/
+char *
+vot_parseSubject (char *subject)
+{
+ char *ip, *op, val[SZ_FNAME], buf[SZ_FNAME];
+ char *substr;
+ int more = 0;
+
+
+ substr = calloc (1, 6*SZ_LINE);
+ if (subject && subject[0]) {
+ strcat (substr, "(");
+ for (ip=subject; *ip; ) {
+ more = 0; /* re-initialize */
+ bzero (val, SZ_FNAME);
+
+ for (op=val; *ip; ) {
+ if (*ip == ',') {
+ more++, ip++;
+ break;
+ } else
+ *op++ = *ip++;
+ }
+
+ bzero (buf, SZ_FNAME);
+ sprintf (buf, "([content/subject] like '%%%s%%')", val);
+ strcat (substr, buf);
+
+ if (more) strcat (substr, " OR ");
+ }
+ strcat (substr, ")");
+
+ return (substr);
+ }
+
+ return ((char *)NULL);
+}
+
+
+/****************************************************************************
+** VOT_PARSECLEVEL -- Convert a ContentLevel specification to an ADQL query
+** string.
+*/
+char *
+vot_parseCLevel (char *level)
+{
+ char *ip, *op, *str, val[SZ_FNAME], buf[SZ_FNAME];
+ int more = 0;
+
+ str = calloc (1, 6*SZ_LINE);
+ if (level && level[0]) {
+ strcat (str, "(");
+ for (ip=level; *ip; ) {
+ more = 0; /* re-initialize */
+ memset (val, 0, SZ_FNAME);
+
+ for (op=val; *ip; ) {
+ if (*ip == ',') {
+ more++, ip++;
+ break;
+ } else
+ *op++ = *ip++;
+ }
+
+ memset (buf, 0, SZ_FNAME);
+ sprintf (buf, "([content/contentLevel] like '%%%s%%')", val);
+ strcat (str, buf);
+ if (more)
+ strcat (str, " OR ");
+ }
+ strcat (str, ")");
+ return (str);
+ }
+
+ return ((char *)NULL);
+}
+
+
+/************************************************************************
+** Return the filename part of a URL.
+*/
+char *
+vot_urlFname (char *url)
+{
+ char *ip;
+ int len = strlen (url);
+
+ for (ip=&url[len-1]; ip >= url; ip--) {
+ if (*ip == '&' || *ip == '?')
+ *ip = '\0';
+ if (*ip == '/')
+ return (ip+1);
+ }
+
+ return (ip);
+}
+
+
+/******************************************************************************
+** Print the resource attributes.
+*/
+void
+vot_printAttrs (char *fname, Query query, char *ident)
+{
+ char *result = (char *) NULL, *qstring = (char *) NULL;
+ int i=0, nrec, nattr;
+#ifdef OLD_ATTRS
+ char *ip, *attrList = (char *) NULL;
+ QRecord rec = (QRecord) NULL; /* Query record */
+ QResponse qr = (QResponse) NULL; /* Query response */
+#else
+ int vot = 0, nbytes = 0;
+ FILE *fd = stdout;
+ char *ip, *op;
+#endif
+
+
+
+ if (!query) {
+ fprintf (stderr, "# Query failed, returning\n");
+ return;
+ }
+
+#ifdef OLD_ATTRS
+ if ((qr = voc_executeQuery (query))) {
+ rec = voc_getRecord (qr, 0); /* get a row in the table */
+ nrec = voc_getRecordCount (qr);
+ }
+ nattr = (rec ? voc_getAttrCount (rec) : 0);
+
+ if (nattr > 0) {
+ printf ("\n# --- Identifier: %s\n#\n", ident);
+
+ if (!meta)
+ printf ("# returns %d records containing %d attributes each\n",
+ nrec, nattr);
+
+ attrList = voc_getAttrList (rec);
+ printf ("# Col UCD\n");
+ printf ("# --- ---\n# %2d ", (i=1));
+ for (i++, ip=attrList; *ip; ip++) {
+ if (isspace (*ip))
+ printf ("\n# %2d ", i++);
+ else
+ putchar (*ip);
+ }
+ printf ("\n#\n");
+
+ if (attrList) free ((void *) attrList);
+ } else
+ printf ("# --- No Attributes Found ---\n#\n");
+
+#else
+
+ if (query > 0) {
+ if (! (qstring = voc_getQueryString (query, DAL_CONN, 0)))
+ return;
+ } else
+ return;
+
+ while (isspace (*qstring))
+ qstring++;
+
+ if ((ip = strcasestr (qstring, "format=image"))) {
+ op = ip;
+ while (*ip && *ip != '&')
+ ip++;
+ if (*ip) {
+ for (ip++; *ip ;)
+ *op++ = *ip++;
+ }
+ *op = '\0';
+ }
+
+ if ((result = voc_getRawURL (qstring, &nbytes)) == NULL)
+ return;
+
+ /* FIXME -- rawURL still returns garbage at the end.....
+ result[nbytes] = '\0';
+ */
+
+ if ( nbytes > 0 && (vot = vot_openVOTABLE (result)) > 0 ) {
+
+ char ucd[SZ_FNAME], name[SZ_FNAME], desc[SZ_LINE], id[SZ_FNAME], *at;
+ extern char *vot_getFieldName(), *vot_getFieldDesc();
+ extern char *vot_getFieldUCD(), *vot_getFieldID();;
+
+ handle_t res, tab, data, tdata, field, handle;
+
+
+ res = vot_getRESOURCE (vot); /* get handles */
+ if ((tab = vot_getTABLE (res)) <= 0) {
+ if ((data = vot_getDATA (tab)) <= 0) {
+ if ((tdata = vot_getTABLEDATA (data))) {
+ nrec = vot_getNRows (tdata);
+ nattr = vot_getNCols (tdata);
+ }
+ }
+ }
+
+
+ if (!fname || strcmp (fname, "-") == 0) {
+ fd = stdout;
+ } else {
+ if ((fd = fopen (fname, "w+")) == (FILE *) NULL)
+ return ;
+ }
+
+ fprintf (fd, "\n Service: %s\n NAttrs: %d\n\n",
+ (ident ? ident : "N/A"), nattr);
+ fprintf (fd,
+ " Col UCD Name Description\n");
+ fprintf (fd,
+ " --- --- ---- -----------------------\n");
+
+ for (i=1, field=vot_getFIELD (tab); field; field=vot_getNext (field)) {
+
+ fprintf (fd, " %3d ", i++);
+
+ memset (ucd, 0, SZ_FNAME);
+ memset (name, 0, SZ_FNAME);
+ memset (id, 0, SZ_FNAME);
+ memset (desc, 0, SZ_LINE);
+
+ strcpy (ucd, ((at=vot_getAttr (field, "ucd")) ? at : ""));
+ strcpy (name, ((at=vot_getAttr (field, "name")) ? at : ""));
+ strcpy (id, ((at=vot_getAttr (field, "id")) ? at : ""));
+
+ if ((handle = vot_getDESCRIPTION (field)))
+ strcpy (desc, vot_getValue (handle));
+ else
+ strcpy (desc, " ");
+
+/*
+ strcpy (desc, ((at=vot_getAttr (field, "description")) ? at : ""));
+
+ fprintf (fd, "%-27.27s ", (ucd[0] ? ucd :
+ (name[0] ? name :
+ (id[0] ? id : " "))) );
+*/
+ fprintf (fd, "%-16.16s %-10.10s ", ucd, name);
+
+ if (desc[0]) {
+ ppMultiLine (desc, 34, 45, 1024);
+ } else {
+ if (name[0] && strcmp (name, id) == 0)
+ fprintf (fd, "name=id='%s'", name);
+ else {
+ if (name[0])
+ fprintf (fd, "name='%s'%s", name, (id[0] ? ", ":" "));
+ if (id[0])
+ fprintf (fd, "id='%s'", id);
+ }
+ }
+
+
+ fprintf (fd, "\n");
+ }
+ vot_closeVOTABLE (vot);
+
+ if (fd != stdout)
+ fclose (fd);
+
+ } else if (!quiet)
+ fprintf (stderr, " %-50s Error\n", ident);
+
+
+/* FIXME -- causes a segfault
+ if (result)
+ voc_freePointer ((char *) result);
+*/
+#endif
+}
+
+
+/**
+ * VOT_SETARG -- Set a value in an argv vector, update the count.
+ */
+void
+vot_setArg (char **argv, int *argc, char *value)
+{
+ int i = *argc;
+
+ argv[i] = strdup (value);
+ *argc += 1;
+}
+
+
+/************************************************************************
+** PRINTVOTABLEHDR -- Print the prolog to the VOTable output.
+*/
+void
+vot_printRegVOTableHdr (FILE *fd)
+{
+fprintf (fd, "\
+<?xml version=\"1.0\" encoding=\"utf-8\"?>\
+<VOTABLE ID=\"ID\" xmlns=\"http://www.ivoa.net/xml/VOTable/v1.1\">\
+<DESCRIPTION>REGISTRY SEARCH RESULTS</DESCRIPTION>\
+<RESOURCE>\
+<INFO name=\"QUERY_STATUS\" value=\"OK\"></INFO>\
+<TABLE>");
+
+if (verbose == 0) {
+
+fprintf (fd, "\
+<FIELD datatype=\"char\" name=\"title\" arraysize=\"*\"/>\
+<FIELD datatype=\"char\" name=\"shortName\" arraysize=\"*\"/>\
+<FIELD datatype=\"char\" name=\"identifier\" arraysize=\"*\"/>\
+<FIELD datatype=\"char\" name=\"accessURL\" arraysize=\"*\"/>\
+<FIELD datatype=\"char\" name=\"referenceURL\" arraysize=\"*\"/>\
+<FIELD datatype=\"char\" name=\"capabilityClass\" arraysize=\"*\"/>\
+<FIELD datatype=\"char\" name=\"contentLevel\" arraysize=\"*\"/>\
+<FIELD datatype=\"char\" name=\"type\" arraysize=\"*\"/>\
+<FIELD datatype=\"char\" name=\"waveband\" arraysize=\"*\"/>\
+<FIELD datatype=\"char\" name=\"publisher\" arraysize=\"*\"/>\
+<FIELD datatype=\"char\" name=\"subject\" arraysize=\"*\"/>\
+<FIELD datatype=\"char\" name=\"version\" arraysize=\"*\"/>");
+
+} else {
+
+fprintf (fd, "\
+<FIELD ID=\"tags\" datatype=\"char\" name=\"categories\" arraysize=\"*\"/>\
+<FIELD ID=\"shortName\" datatype=\"char\" name=\"shortName\" arraysize=\"*\"/>\
+<FIELD ID=\"title\" datatype=\"char\" name=\"title\" arraysize=\"*\"/>\
+<FIELD ID=\"description\" datatype=\"char\" name=\"description\" arraysize=\"*\"/>\
+<FIELD ID=\"publisher\" datatype=\"char\" name=\"publisher\" arraysize=\"*\"/>\
+<FIELD ID=\"waveband\" datatype=\"char\" name=\"waveband\" arraysize=\"*\"/>\
+<FIELD ID=\"identifier\" datatype=\"char\" name=\"identifier\" ucd=\"ID_MAIN\" arraysize=\"*\"/>\
+<FIELD ID=\"updated\" datatype=\"char\" name=\"descriptionUpdated\" arraysize=\"*\"/>\
+<FIELD ID=\"subject\" datatype=\"char\" name=\"subject\" arraysize=\"*\"/>\
+<FIELD ID=\"type\" datatype=\"char\" name=\"type\" arraysize=\"*\"/>\
+<FIELD ID=\"contentLevel\" datatype=\"char\" name=\"contentLevel\" arraysize=\"*\"/>\
+<FIELD ID=\"regionOfRegard\" unit=\"arcsec\" datatype=\"int\" name=\"typicalRegionSize\"/>\
+<FIELD ID=\"version\" datatype=\"char\" name=\"version\" arraysize=\"*\"/>\
+<FIELD ID=\"capabilityClass\" datatype=\"char\" name=\"capabilityClass\" arraysize=\"*\"/>\
+<FIELD ID=\"capabilityID\" datatype=\"char\" name=\"capabilityStandardID\" arraysize=\"*\"/>\
+<FIELD ID=\"capabilityValidationLevel\" datatype=\"char\" name=\"capabilityValidationLevel\" arraysize=\"*\"/>\
+<FIELD ID=\"interfaceClass\" datatype=\"char\" name=\"interfaceClass\" arraysize=\"*\"/>\
+<FIELD ID=\"interfaceVersion\" datatype=\"char\" name=\"interfaceVersion\" arraysize=\"*\"/>\
+<FIELD ID=\"interfaceRole\" datatype=\"char\" name=\"interfaceRole\" arraysize=\"*\"/>\
+<FIELD ID=\"accessURL\" datatype=\"char\" name=\"accessURL\" arraysize=\"*\"/>\
+<FIELD ID=\"supportedInputParam\" datatype=\"char\" name=\"supportedInputParam\" arraysize=\"*\"/>\
+<FIELD ID=\"maxRadius\" datatype=\"int\" name=\"maxSearchRadius\"/>\
+<FIELD ID=\"maxRecords\" datatype=\"int\" name=\"maxRecords\"/>\
+<FIELD ID=\"publisherID\" datatype=\"char\" name=\"publisherIdentifier\" arraysize=\"*\"/>\
+<FIELD ID=\"referenceURL\" datatype=\"char\" name=\"referenceURL\" arraysize=\"*\"/>");
+}
+fprintf (fd, "<DATA><TABLEDATA>");
+
+fflush (fd);
+}
+
+
+/************************************************************************
+** PRINTVOTABLEREC -- Print an individual record in the search results
+** as a VOTable row.
+*/
+void
+vot_printRegVOTableRec (FILE *fd, RegResult resource, int recnum)
+{
+ register int i;
+ char *attr_val, *fmt, *attr;
+
+ static char *resAttr[] = {
+ "Title", "ShortName", "Identifier",
+ "AccessURL", "ReferenceURL", "CapabilityClass",
+ "ContentLevel", "Type", "Waveband",
+ "Creator", "Subject", "Version",
+ NULL
+ };
+
+ static char *resAttrVerbose[] = {
+ "tags", "shortName", "title",
+ "description", "publisher", "waveband",
+ "identifier", "updated", "subject",
+ "type", "contentLevel", "regionOfRegard",
+ "version", "capabilityClass", "capabilityID",
+ "capabilityValidationLevel", "interfaceClass",
+ "interfaceVersion", "interfaceRole", "accessURL",
+ "supportedInputParam", "maxRadius", "maxRecords",
+ "publisherID", "referenceURL",
+ NULL
+ };
+
+
+
+ fprintf (fd, "<TR>");
+ for (i=0; 1; i++) {
+ attr = (verbose ? resAttrVerbose[i] : resAttr[i]);
+ if (attr == NULL)
+ break;
+
+ attr_val = xmlEncode (voc_resGetStr (resource, attr, recnum));
+
+ /* Escape any URLs to take care of special chars.
+ */
+ fmt = (*attr_val && strstr(attr,"URL") ?
+ "<TD><![CDATA[%s]]></TD>" : "<TD>%s</TD>");
+
+ if (!(*attr_val) &&
+ (strcmp (attr, "regionOfRegard") == 0 ||
+ strcmp (attr, "maxRadius") == 0 ||
+ strcmp (attr, "maxRecords") == 0)) {
+ fprintf (fd, fmt, "0");
+
+ } else if (attr_val && *attr_val) {
+ fprintf (fd, fmt, attr_val);
+
+ } else
+ fprintf (fd, "<TD/>");
+
+ if (attr_val)
+ voc_freePointer ((char *) attr_val);
+ }
+ fprintf (fd, "</TR>");
+ fflush (fd);
+}
+
+
+
+/************************************************************************
+** PRINTVOTABLETAIL -- Print the epilog to the VOTable output.
+*/
+void
+vot_printRegVOTableTail (FILE *fd)
+{
+fprintf (fd, "\
+</TABLEDATA>\
+</DATA>\
+</TABLE>\
+</RESOURCE>\
+</VOTABLE>\n");
+}
+
+
+
+/****************************************************************************
+** Lexical utility procedures.
+*/
+
+char *
+xmlEncode (char *in)
+{
+ char *ip, *op, *out;
+
+ if (in == (char *) NULL)
+ return (calloc(1,2)); /* caller will free this pointer */
+
+ out = calloc (1, strlen(in) * 2);
+ ip = in;
+ op = out;
+
+ while (*ip) {
+ if (*ip == '<') {
+ strncpy (op, "&gt;", 4);
+ op += 4;
+ } else if (*ip == '>') {
+ strncpy (op, "&gt;", 4);
+ op += 4;
+ } else if (*ip == '&') {
+ strncpy (op, "&amp;", 5);
+ op += 5;
+ } else if (*ip == '\'') {
+ strncpy (op, "&quot;", 6);
+ op += 6;
+ } else if (*ip == '\"') {
+ strncpy (op, "&dquot;", 7);
+ op += 7;
+ } else
+ *op++ = *ip;
+
+ ip++;
+ }
+
+
+ if (in)
+ voc_freePointer ((char *) in);
+
+ return (out);
+}
+
+
+
+/************************************************************************
+** VOT_GETLINE -- Get the next line in a file/stdin. We use this procedure
+** to allow for parsing input that may be piped in where newlines are
+** expressed as the string "\n".
+*/
+char *
+vot_getline (FILE *fd)
+{
+ int i, ch, peek;
+ static char cmdline[SZ_LINE];
+
+
+ bzero (cmdline, SZ_LINE);
+
+ for (i=ch=0; ch != EOF; i++) {
+ cmdline[i] = ch = (char) fgetc (fd);
+ if (i == 0 && ch == EOF)
+ return (NULL);
+ else if (i > 0 && (ch == EOF || ch == '\n')) {
+ cmdline[i] = '\0';
+ break;
+ } else if (ch == (int) '\\') {
+ if ((peek = fgetc (fd)) == (int)'n') {
+ cmdline[i] = '\0';
+ break;
+ } else
+ ungetc (peek, fd);
+ }
+ }
+
+ return (cmdline);
+}
+
+
+/****************************************************************************
+** NORMALIZECOORD -- Normalize a coordinate string, i.e. strip whitespace
+** from the ends and replace internal whitespace with a ':' in the case of
+** sexagesimal values.
+*/
+char *
+vot_normalizeCoord (char *coord)
+{
+ static char *ip, *op, norm[SZ_LINE];
+
+
+ bzero (norm, SZ_LINE);
+
+ /* Remove trailing whitespace */
+ for (ip=&coord[strlen(coord)-1]; isspace(*ip) && ip > coord; )
+ *ip = '\0';
+
+ /* Skip leading whitespace */
+ for (ip=coord; *ip && isspace(*ip); ip++)
+ ;
+
+ for (op=norm; *ip; ) {
+ if (isspace (*ip)) {
+ *op++ = ':';
+ while (*ip && isspace(*ip)) /* collapse multiple space */
+ ip++;
+ } else
+ *op++ = *ip++;
+ }
+
+ return (norm);
+}
+
+
+/****************************************************************************
+** Normalize the names, i.e. replace anything other than [.+-] with '-'.
+*/
+char *
+vot_normalize (char *str)
+{
+ char *ip, *op;
+ static char name[SZ_FNAME];
+
+ if (str == (char *)NULL)
+ return ("");
+
+ bzero (name, SZ_FNAME);
+ for (ip=str, op=name; *ip; ) {
+ if (strchr (".+-", (int)*ip))
+ *op++ = *ip++;
+ else if (!isalnum ((int)*ip))
+ *op++ = '-', ip++;
+ else
+ *op++ = *ip++;
+ }
+
+ return (name);
+}
+
+
+
+/* UTILITY FUNCTIONS.
+*/
+
+/****************************************************************************
+** ISVOTABLE -- Test a file or string to see if it's a VOTable.
+*/
+int
+isVOTable (char *fname)
+{
+ int i;
+ FILE *fd = (FILE *) NULL;
+ char line[SZ_LINE];
+
+ if (fname[0] == '-') {
+ (void) fgets (line, SZ_LINE, stdin);
+ if (line[0] == '<')
+ return (1);
+
+ } else if (access (fname, R_OK) == 0) {
+
+ /* Process the file contents.
+ */
+ if ((fd = fopen (fname, "r")) == (FILE *) NULL) {
+ fprintf (stderr, "ERROR: Cannot open file '%s'\n", fname);
+ return (0);
+ }
+
+ for (i=0; i < 10 && fgets (line, SZ_LINE, fd); i++) {
+ if (strcasestr (line, "VOTABLE")) {
+ fclose (fd);
+ return (1);
+ }
+ }
+
+ if (fd)
+ fclose (fd);
+ }
+
+ return (0);
+}
+
+
+int
+isSexagesimal (char *str)
+{
+ register int i;
+
+ /* Allow only numbers, colons, decimal point, whitespace, and sign. */
+ for (i=(strlen(str)-1); i >= 0; i--)
+ if (!isdigit(str[i]) && strchr("/:+- .\t,", (int)str[i])==(char *)NULL)
+ return (0);
+
+ return (1);
+}
+
+int
+isDecimal (char *str)
+{
+ register int i;
+
+ /* Allow only numbers, decimal point, whitespace, and sign. */
+ for (i=(strlen(str)-1); i >= 0; i--)
+ if (!isdigit(str[i]) && strchr("/+- .\t,", (int)str[i])==(char *)NULL)
+ return (0);
+
+ return (1);
+}
+
+float
+sexa (char *s)
+{
+ int n, sign;
+ int hr, minutes;
+ float sec, val;
+ extern double atof();
+
+ while (isspace (*s)) /* skip leading whitespace */
+ s++;
+ sign = (*s == '-') ? (s++, -1) : 1; /* get the sign */
+
+ minutes = 0;
+ sec = 0.;
+ n = sscanf (s, "%d:%d:%f", &hr, &minutes, &sec);
+ if (n < 1 || minutes < 0 || sec < 0)
+ val = -999.0;
+ else
+ /* Beware: Evaluation here can produce roundoff errors!
+ */
+ val = sign * (hr + ((float)minutes)/60. + sec/3600.);
+
+ return (val);
+}
+
+
+char *
+toSexa (double pos)
+{
+ static char str[SZ_LINE];
+ int d, m;
+ float s, frac;
+ char sign = (pos < 0.0 ? '-' : 0);
+
+
+ pos = (pos < 0.0 ? -pos : pos);
+
+ d = (int) pos;
+ frac = (pos - d);
+ m = frac * 60.0;
+ s = ((frac * 60.0) - m) * 60.0;
+
+ if (sign)
+ sprintf (str, "%c%02d:%02d:%04.1f", sign, d, m, s);
+ else
+ sprintf (str, "%02d:%02d:%04.1f", d, m, s);
+
+ return (str);
+}
+
+
+char *
+toSexaTime (int nsec)
+{
+ char tstr[SZ_LINE];
+ int m, s;
+
+ m = nsec / 60;
+ s = nsec % 60;
+
+ sprintf (tstr, "%02d:%02d", m, s);
+
+ return (strdup (tstr)); /* note potential memory leak! */
+}
+
+
+char *
+vot_mktemp (char *root)
+{
+ char *tmp;
+ static char tmpfile[SZ_LINE];
+ char *tmpdir = "/tmp";
+
+
+ /* Get a temporary file name based on the pid.
+ */
+ bzero (tmpfile, SZ_LINE);
+ if ((tmp = getenv ("TMP")) != NULL)
+ tmpdir = tmp;
+ sprintf (tmpfile, "%s/%s%d", tmpdir, root, (int)(getpid()+time((time_t)0)));
+
+ return (tmpfile);
+}
+
+
+/* Copy the standard input to a temp file we can parse more easily.
+*/
+char *
+vot_copyStdin ()
+{
+ static char *line, tmpfile[SZ_FNAME];
+ FILE *fd;
+ extern char *vot_getline();
+
+
+ /* Open a temp file and copy the stdin to it.
+ */
+ strcpy (tmpfile, vot_mktemp ("vodo"));
+ if ((fd = fopen (tmpfile, "w+")) == (FILE *) NULL) {
+ fprintf (stderr, "Error opening tmp file '%s'\n", tmpfile);
+ return ((char *)NULL);
+ }
+
+ while ( (line = vot_getline (stdin)) )
+ fprintf (fd, "%s\n", line);
+ fclose (fd);
+
+ return (tmpfile);
+}
+
+
+/* Skip header lines of a table.
+*/
+void
+vot_skipHdr (FILE *fd)
+{
+ register int i;
+ char line[SZ_LINE];
+
+
+ if (fd && table_hskip) { /* Skip header lines */
+ rewind (fd);
+ for (i=0; i < table_hskip; i++) {
+ if (fgets (line, SZ_LINE, fd) == NULL) {
+ break;
+ }
+ }
+ }
+}
+
+
+
+/****************************************************************************
+** GETTABLECOL -- Get the requested column value from the table line.
+** Column numbers are assumed to be one-indexed.
+*/
+char *
+vot_getTableCol (char *line, int col, int span)
+{
+ int i, nsp = span;
+ char sep[6], *ip, *op, *del = (char *)NULL;
+ static char value[SZ_LINE];
+
+
+ bzero (value, SZ_LINE);
+ bzero (sep, 6);
+
+ /* If we're doing exact columns, copy whatever is in those columns
+ ** to the output file. Otherwise, parse the line based on delimiters.
+ */
+ if (ecols) {
+ strncpy (value, (char *)&line[col-1], span);
+ for (i=span-1; i && isspace(value[i]); i--) /* trailing space */
+ value[i] = '\0';
+ for (i=0; isspace(value[i]); i++) /* leading space */
+ ;
+ return (&value[i]);
+ }
+
+ if ((del = strpbrk(line, " \t,|;"))) /* get delimiter */
+ sep[0] = del[0];
+ else
+ strcpy (sep, delim);
+
+ op = value;
+ for (i=1, ip=line; *ip; ip++) {
+ if (strchr (sep, (int)*ip) || *ip == '\n') {
+ if (sep[0] == ' ') {
+ while ( *ip == sep[0] ) /* skip multiple spaces */
+ ip++;
+ if (*ip != '\n')
+ ip--; /* reposition for next */
+ }
+ if (i++ == col) {
+ if (--nsp == 0) {
+ return (value);
+ } else {
+ *op++ = ' '; /* add a space for span */
+ i--;
+ }
+ } else
+ bzero ((op=value), SZ_LINE);
+ } else
+ *op++ = *ip;
+ }
+
+ return ( (i == col) ? value : (char *)NULL );
+}
+
+
+/**
+ * VOT_ISNUMERICFIELD -- Determine if a <FIELD> is a numeric datatype.
+ */
+int
+vot_isNumericField (handle_t field)
+{
+ char *dtype = vot_getAttr (field, "datatype");
+ char *asize = vot_getAttr (field, "arraysize");
+
+
+ if (asize && asize[0]) {
+ return (0);
+
+ } else {
+ if ((strncasecmp (dtype, "floatComplex", 12) == 0) ||
+ (strncasecmp (dtype, "doubleComplex", 13) == 0))
+ return (0);
+
+ if ((strncasecmp (dtype, "short", 5) == 0) ||
+ (strncasecmp (dtype, "int", 3) == 0) ||
+ (strncasecmp (dtype, "long", 4) == 0) ||
+ (strncasecmp (dtype, "float", 5) == 0) ||
+ (strncasecmp (dtype, "double", 6) == 0))
+ return (1);
+ }
+ return (0);
+}
+
+
+/**
+ * VOT_FILETYPE -- Determine what type of file we have.
+ */
+int
+vot_fileType (char *fname)
+{
+ FILE *fd = (FILE *) NULL;
+ char buf[1024];
+ int nread, ftype = -1;
+
+ if ((fd = fopen (fname, "r")) != NULL) {
+ memset (buf, 0, 1024);
+ nread = fread (buf, 1023, 1, fd);
+ if (strncasecmp ("SIMPLE", buf, 6) == 0) {
+ /* FIXME -- Need to add spectrum serialization. */
+ ftype = VOT_FITS;
+ } else if (strcasestr (buf, "VOTABLE")) {
+ /* FIXME -- Need to add spectrum serialization. */
+ ftype = VOT_VOTABLE;
+ }
+ fclose (fd);
+ } else
+ fprintf (stderr, "fileType: cannot open '%s'\n", fname);
+
+ return (ftype);
+}
+
+
+/**
+ * VOT_SUM32 -- Internet checksum, 32 bit unsigned integer version.
+ */
+int
+vot_sum32 (char *str)
+{
+ register int i;
+ unsigned int *iarray;
+ unsigned long lsum = 0;
+ int sum = 0;
+ int len, carry=0, newcarry=0;
+
+ iarray = (unsigned int *) str;
+ len = strlen (str) / 4;
+
+ for (i=0; i<len; i++) {
+ if (iarray[i] > ~ lsum)
+ carry++;
+ lsum += iarray[i];
+ }
+
+ while (carry) {
+ if (carry > ~ lsum)
+ newcarry++;
+ lsum += carry;
+ carry = newcarry;
+ newcarry = 0;
+ }
+
+ return (abs(sum = lsum));
+}
+
+
+/**
+ * STRDIC -- Search a dictionary string for a match with an input string.
+ * The input string may be an abbreviation of a dictionary entry, however,
+ * it is an error if the abbreviation is not unique. The entries in the
+ * dictionary string are separated by a delimiter character which is the
+ * first character of the dictionary string. The full name of the matched
+ * dictionary entry found is returned in out_str; the function value is
+ * the word index of the dictionary entry. The output string may be the
+ * same as the input string.
+ */
+
+#include <ctype.h>
+
+int strdic (
+ char *in_str, /* Input string, always lower case */
+ char *out_str, /* Output string as found in dictionary */
+ int maxchars, /* Maximum length of output string */
+ char *dict /* Dictionary string */
+)
+{
+ char ch, fch;
+ int start, len, ip, i, match, entry;
+
+
+ if (dict == NULL || dict[0] == '\0')
+ return (0);
+
+ for (i=0; isspace(in_str[i]); i++)
+ ;
+
+ start = i;
+ match = -1;
+ ip = 1;
+ len = strlen (&in_str[start]);
+ fch = in_str[start];
+
+
+ /* Search the dictionary string. If the input string matches a
+ * dictionary entry it is either an exact match (len = dictionary
+ * entry length) or a legal abbreviation. If an abbreviation
+ * matches two entries it is ambiguous and an error.
+ */
+ for (entry=0; dict[ip] != '\0'; entry=entry+1) {
+ if (dict[ip] == fch) {
+ if (strncmp (&dict[ip], &in_str[start], len) == 0) {
+ for (i=0; i < maxchars; i++) {
+ ch = dict[ip+i-1];
+ if ((ch == dict[0]) || (ch == '\0'))
+ break;
+ out_str[i] = ch;
+ }
+ out_str[i] = '\0';
+
+ if ((dict[ip+len] == dict[0]) || (dict[ip+len] == '\0'))
+ return (entry); /* exact match */
+ else {
+ /* If we already have a match and the new match is not
+ * exact, then the abbreviation is ambiguous.
+ */
+ if (match != 0)
+ return (0);
+ else
+ match = entry;
+ }
+ }
+ }
+
+ do {
+ ip = ip + 1;
+ } while (dict[ip-1] != dict[0] && dict[ip] != '\0');
+ }
+
+ if (match <= 0)
+ strcpy (out_str, in_str);
+ return (match);
+}
+
+
+/*****************************************************************************
+****** URL String Encode / Decode ******
+*****************************************************************************/
+
+/* Converts a hex character to its integer value */
+static char from_hex (char ch)
+{
+ return (isdigit(ch) ? ch - '0' : tolower(ch) - 'a' + 10);
+}
+
+/* Converts an integer value to its hex character*/
+static char to_hex (char code)
+{
+ static char hex[] = "0123456789abcdef";
+ return (hex[code & 15]);
+}
+
+
+/**
+ * VO_URLENCODE -- Returns a url-encoded version of str. Call must free()
+ * the pointer that is returned.
+ */
+char *
+vo_urlEncode (char *str)
+{
+ char *pstr = str, *buf = malloc(strlen(str) * 3 + 1), *pbuf = buf;
+
+ while (*pstr) {
+ if (isalnum(*pstr) ||
+ *pstr == '-' ||
+ *pstr == '_' ||
+ *pstr == '.' ||
+ *pstr == '~')
+ *pbuf++ = *pstr;
+ else if (*pstr == ' ')
+ *pbuf++ = '+';
+ else {
+ *pbuf++ = '%';
+ *pbuf++ = to_hex (*pstr >> 4);
+ *pbuf++ = to_hex (*pstr & 15);
+ }
+ pstr++;
+ }
+ *pbuf = '\0';
+ return buf;
+}
+
+
+/**
+ * VO_URLDECODE -- Returns a url-decoded version of str. Call must free()
+ * the pointer that is returned.
+ */
+char *
+vo_urlDecode (char *str)
+{
+ char *pstr = str, *buf = malloc(strlen(str) + 1), *pbuf = buf;
+
+ while (*pstr) {
+ if (*pstr == '%') {
+ if (pstr[1] && pstr[2]) {
+ *pbuf++ = from_hex(pstr[1]) << 4 | from_hex(pstr[2]);
+ pstr += 2;
+ }
+ } else if (*pstr == '+') {
+ *pbuf++ = ' ';
+ } else {
+ *pbuf++ = *pstr;
+ }
+ pstr++;
+ }
+ *pbuf = '\0';
+
+ return buf;
+}
+
+
+/**
+ * VOT_TOURL -- Convert a filename to a URL.
+ */
+char *
+vot_toURL (char *arg)
+{
+ /* If we have an existing protocol simply return the argument.
+ */
+ if ((strncmp (arg, "http:", 5) == 0) ||
+ (strncmp (arg, "file:", 5) == 0) ||
+ (strncmp (arg, "ftp:", 4) == 0))
+ return (arg);
+
+ if (access (arg, F_OK) == 0) {
+ char cwd[SZ_LINE];
+ static char buf[SZ_LINE];
+
+ memset (cwd, 0, SZ_LINE);
+ getcwd (cwd, (unsigned long) SZ_LINE);
+
+ memset (buf, 0, SZ_LINE);
+ if (arg[0] == '/')
+ sprintf (buf, "file://%s", arg);
+ else
+ sprintf (buf, "file://%s/%s", cwd, arg);
+
+ return (buf);
+ }
+
+ return (arg);
+}
+
+
+/**
+ * VOT_ISVALIDFORMAT -- Check whether we have a supported format request.
+ */
+int
+vot_isValidFormat (char *fmt)
+{
+ char format[SZ_LINE];
+ extern int strdic ();
+
+ return ( (strdic (fmt, format, SZ_FORMAT, FORMATS) >= 0) );
+}
+
+
+/**
+ * VOT_ATOI -- System atoi() with lexical argument checking.
+ */
+int
+vot_atoi (char *val)
+{
+ char *ip;
+
+ for (ip = val; *ip; ip++) {
+ if (isalpha ((int) *ip)) {
+ fprintf (stderr, "Warning: value '%s' is not an integer\n", val);
+ break;
+ }
+ }
+ return (atoi (val));
+}
+
+
+/**
+ * VOT_ATOL -- System atol() with lexical argument checking.
+ */
+long
+vot_atol (char *val)
+{
+ char *ip;
+
+ for (ip = val; *ip; ip++) {
+ if (isalpha ((int) *ip) && *ip != '-' && *ip != '+') {
+ fprintf (stderr, "Warning: value '%s' is not an integer\n", val);
+ break;
+ }
+ }
+ return (atol (val));
+}
+
+
+/**
+ * VOT_ATOF -- System atoi() with lexical argument checking.
+ */
+double
+vot_atof (char *val)
+{
+ char *ip, c;
+
+ for (ip = val; *ip; ip++) {
+ c = *ip;
+ if (! (tolower(c) == 'e' || tolower(c) == 'd' || isspace(c) ||
+ (c == '-' || c == '+' || c == '.') || isdigit(c))) {
+ fprintf (stderr,
+ "Warning: value '%s' is not a floating point value\n", val);
+ break;
+ }
+ }
+ return (atof (val));
+}
diff --git a/vendor/voclient/voapps/lib/voXML.c b/vendor/voclient/voapps/lib/voXML.c
new file mode 100644
index 00000000..dbe01ff6
--- /dev/null
+++ b/vendor/voclient/voapps/lib/voXML.c
@@ -0,0 +1,166 @@
+/************************************************************************
+** VOXML.C -- Utility procedures for writing XML files, i.e. the raw
+** VOTable output wrapped in a proprietary XML document.
+**
+** M. Fitzpatrick, NOAO, July 2007
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/ipc.h>
+#include <sys/sem.h>
+#include <string.h>
+#include <math.h>
+#include "VOClient.h"
+#include "voAppsP.h"
+
+extern int format, debug, errno, extract;
+extern char *output;
+
+extern Service *svcList;
+extern Object *objList;
+
+extern char *vot_getSName (char *root);
+extern char *vot_getOName (char *root);
+extern char *vot_procTimestamp (void);
+
+void vot_concatXML (char *fname);
+int vot_copyXMLFile (char *root, char *sname, FILE *fd);
+void vot_cleanXML (void);
+
+
+/************************************************************************
+** CONCATXML -- Concatenate the XML file generated by the query into a
+** single, hierarchical document grouped by the service.
+*/
+void
+vot_concatXML (char *fname)
+{
+ FILE *fd = (FILE *) NULL;
+ Service *svc = svcList; /* the service list */
+ Proc *proc; /* process list in each service */
+ int index = 0;
+ char sname[SZ_LINE], oname[SZ_LINE];
+
+
+ if (fname[0] == '-')
+ fd = stdout;
+ else if ((fd = fopen (fname, "w+")) == (FILE *) NULL) {
+ fprintf (stderr, "ERROR: Cannot open XML file: '%s'\n", fname);
+ return;
+ }
+
+ fprintf (fd, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
+ fprintf (fd, "<VOTABLES date=\"%s\">\n", vot_procTimestamp());
+
+ for (svc=svcList; svc; svc=svc->next) {
+
+ bzero (sname, SZ_FNAME);
+ strcpy (sname, vot_getSName (svc->proc->root));
+
+ for (proc=svc->proc; proc; proc=proc->next) {
+
+ bzero (oname, SZ_FNAME);
+ strcpy (oname, vot_getOName (proc->root));
+
+ fprintf (fd, "<VOTABLE_ENTRY index=\"%d\"", index);
+ fprintf (fd, " svc=\"%s\" ",
+ (strcmp ("tmp",sname) == 0 ? svc->name : sname));
+ if (!oname[0]) {
+ fprintf (fd, "pos=\"(%f,%f)\" ",
+ proc->obj->ra, proc->obj->dec);
+ }
+ fprintf (fd, "obj=\"%s\">\n", oname);
+
+ vot_copyXMLFile (proc->root, oname, fd);
+
+ fprintf (fd, "\n</VOTABLE_ENTRY>\n");
+ index++;
+ }
+ }
+
+ fprintf (fd, "</VOTABLES>\n");
+
+ /* Clean up the intermediate files if needed.
+ if (format & F_XML || (extract & EX_XML && extract & EX_COLLECT))
+ */
+ if (format & F_XML && (extract & EX_COLLECT))
+ vot_cleanXML ();
+
+ /* Close the file descriptors.
+ */
+ if (fd != stdout)
+ fclose (fd);
+}
+
+
+/************************************************************************
+** COPYXMLFILE -- Copy a VOTable to the output XML file.
+*/
+int
+vot_copyXMLFile (char *root, char *name, FILE *fd)
+{
+ char *ip, line[4096], fname[SZ_FNAME];
+ FILE *ifd;
+ extern char *strcasestr();
+
+
+ bzero (fname, SZ_FNAME);
+ sprintf (fname, "%s.xml", root);
+
+ if (access (fname, R_OK) == 0) {
+ if ((ifd = fopen (fname, "r")) == (FILE *) NULL) {
+ fprintf (stderr, "Warning: Cannot open file '%s'\n", fname);
+ return (ERR);
+ }
+ } else {
+ return (OK);
+ }
+
+ /* Skip ahead to the start of the part we're interested in.
+ */
+ bzero (line, 4096);
+ while (fgets (line, 4096, ifd)) {
+ if ((ip = strcasestr (line, "<VOTABLE"))) {
+ fprintf (fd, "%s", ip);
+ break;
+ }
+ bzero (line, 4096);
+ }
+
+ /* (Slow) Copy the file until the end of the Document.
+ */
+ bzero (line, 4096);
+ while (fgets (line, 4096, ifd)) {
+ if (strcasestr (line, "</VOTABLE>")) {
+ fprintf (fd, "%s", line);
+ break;
+ }
+ fprintf (fd, " %s", line);
+ bzero (line, 4096);
+ }
+
+ fclose (ifd);
+ return (OK);
+}
+
+
+/************************************************************************
+** CLEANXML -- Clean up the intermediate VOTable files when producing
+** the compiled XML doc..
+*/
+void
+vot_cleanXML ()
+{
+ Service *svc = svcList; /* the service list */
+ Proc *proc; /* process list in each service */
+ char fname[SZ_FNAME];
+
+ for (svc=svcList; svc; svc=svc->next) {
+ for (proc=svc->proc; proc; proc=proc->next) {
+ bzero (fname, SZ_FNAME);
+ sprintf (fname, "%s.vot", proc->root);
+ unlink (fname);
+ }
+ }
+}
diff --git a/vendor/voclient/voapps/lib/vosUtil.c b/vendor/voclient/voapps/lib/vosUtil.c
new file mode 100644
index 00000000..732daf45
--- /dev/null
+++ b/vendor/voclient/voapps/lib/vosUtil.c
@@ -0,0 +1,998 @@
+/**
+ * VOSUTIL - Utility routines for the VOSAMP tools.
+ *
+ * @file vosUtil.c
+ * @author Mike Fitzpatrick
+ * @date 6/03/11
+ *
+ * @brief Utility routines for the VOSAMP tools.
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <ctype.h>
+#include <fcntl.h>
+#include <time.h>
+
+#include <netdb.h>
+#include <sys/errno.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#include <curl/curl.h>
+#include <curl/types.h>
+#include <curl/easy.h>
+
+
+#include "samp.h" /* LIBSAMP interface */
+#include "voApps.h" /* voApps interface */
+
+
+#define SZ_MTYPE 64
+#define SZ_BUF 128
+#define SZ_HOSTIP 16
+#define SZ_APPNAME 16
+
+#define VOS_DEBUG (getenv("VOS_DBG")!=NULL||access("/tmp/VOS_DBG",F_OK)==0)
+
+
+typedef struct {
+ int nbytes; /* length of msg body */
+ int mode; /* sync, async, notify */
+ int type; /* SAMP cmd, data, result */
+ char fname[SZ_FNAME]; /* upload data name */
+ int fsize; /* data file size */
+ char session[SZ_APPNAME]; /* session name */
+ int sessionPort; /* session port number */
+ char recipient[SZ_APPNAME]; /* recipient app name */
+ char senderIP[SZ_HOSTIP]; /* sender's IP address */
+ int senderPort; /* sender's port */
+
+ int verbose; /* verbose flag */
+ int debug; /* debug flag */
+} cmdHdr, *cmdHdrP;
+
+cmdHdr msgHdr;
+
+
+extern char *to, senderIP[SZ_HOSTIP];
+
+
+char *vos_toURL (char *arg);
+char *vos_optArg (char *arg);
+char *vos_getLocalIP (void);
+char *vos_getFName (char *path);
+char *vos_typeName (int type);
+
+int *vos_toIntArray (char *arg, int *nrows);
+int vos_urlType (char *url);
+int vos_getURL (char *url, char *fname);
+
+
+
+/* Private socket routines.
+ */
+int vos_openServerSocket (int port);
+int vos_openClientSocket (char *host, int port, int retry);
+int vos_sockRead (int fd, void *vptr, int nbytes);
+int vos_sockWrite (int fd, void *vptr, int nbytes);
+void vos_setNonBlock (int sock);
+int vos_sockWriteHdr (int fd, int len, char *name, int type, int mode,
+ char *to);
+int vos_sockReadHdr (int fd, int *len, char *name, int *type, int *mode);
+void vos_sockPrintHdr (char *msg, int fd);
+struct hostent *vos_getHostByName (char *lhost);
+struct hostent *vos_dupHostent (struct hostent *hentry);
+
+
+
+
+/****************************************************************************
+ */
+
+
+/**
+ * VOS_URLTYPE -- Determine the type of a URL parameter
+ */
+int
+vos_urlType (char *url)
+{
+ if (strncasecmp (url, "http://127.0.0.1", 16) == 0)
+ return (VOS_LOCALURL);
+ else if (strncasecmp (url, "file://", 7) == 0)
+ return (VOS_LOCALURI);
+ else if (strncasecmp (url, "http://", 7) == 0)
+ return (VOS_REMOTE);
+ else if (access (url, F_OK) == 0)
+ return (VOS_LOCALFILE);
+
+ return (-1);
+}
+
+
+/**
+ * VOS_GETFNAME -- Get a filename from a path or URL.
+ */
+char *
+vos_getFName (char *path)
+{
+ static char fname[SZ_FNAME];
+ static int filenum = 0;
+
+ memset (fname, 0, SZ_FNAME);
+ if (access (path, R_OK) == 0) {
+ int i, len = strlen (path);
+
+ for (i=len-1; i >=0 && path[i] != '/'; i--) ; /* get filename */
+ strcpy (fname, &path[i+1]);
+ }
+
+ if (!fname[0])
+ sprintf (fname, "vos%d_%03d", (int)getpid(), filenum++);
+
+ return (fname);
+}
+
+
+/**
+ * VOS_TYPENAME -- Convert a message type code to a string.
+ */
+char *
+vos_typeName (int type)
+{
+ switch (type) {
+ case SAMP_DATA: return ("SAMP_DATA");
+ case SAMP_CMD: return ("SAMP_CMD");
+ case SAMP_RELAY: return ("SAMP_RELAY");
+ case SAMP_TEST: return ("SAMP_TEST");
+ case SAMP_QUIT: return ("SAMP_QUIT");
+ default: return ("unknown");
+ }
+}
+
+
+/**
+ * VOS_GETURL -- Utility routine to do a simple URL download to the file.
+ */
+int
+vos_getURL (char *url, char *fname)
+{
+ int stat = 0;
+ char errBuf[SZ_LINE];
+ FILE *fd;
+ CURL *curl_handle;
+
+
+ if (access (fname, F_OK) == 0) /* see if file already exists */
+ unlink (fname);
+
+
+ /* For the CURL operation to download the file.
+ */
+ curl_global_init (CURL_GLOBAL_ALL); /* init curl session */
+ curl_handle = curl_easy_init ();
+
+ /* Open the output file.
+ */
+ if ((fd = fopen (fname, "wb")) == NULL) {
+ fprintf (stderr, "Error: cannot open output file '%s'\n", fname);
+ curl_easy_cleanup (curl_handle);
+ return -1;
+ }
+
+ /* Set cURL options
+ */
+ curl_easy_setopt (curl_handle, CURLOPT_URL, url);
+ curl_easy_setopt (curl_handle, CURLOPT_NOPROGRESS, 1L);
+ curl_easy_setopt (curl_handle, CURLOPT_WRITEDATA, fd);
+ curl_easy_setopt (curl_handle, CURLOPT_ERRORBUFFER, errBuf);
+ curl_easy_setopt (curl_handle, CURLOPT_FOLLOWLOCATION, 1);
+ curl_easy_setopt (curl_handle, CURLOPT_FAILONERROR, 1);
+
+ /* Do the download.
+ */
+ if ((stat = curl_easy_perform (curl_handle)) != 0) {
+ /* Error in download, clean up.
+ */
+ fprintf (stderr, "Error: can't download '%s' : %s\n", url, errBuf);
+ unlink (fname);
+ fclose (fd); /* close the file */
+ curl_easy_cleanup (curl_handle); /* cleanup curl stuff */
+ return (-1);
+ }
+
+ fflush (fd);
+ fclose (fd); /* close the file */
+ curl_easy_cleanup (curl_handle); /* cleanup curl stuff */
+
+ return (1);
+}
+
+
+/**
+ * VOS_OPTARG -- Input command arguments are allowed to be of the form
+ * 'param=value', but the SAMP interface only wants the value string.
+ * Skip past the '=' and return the value, or just return the value if
+ * there is no parameter name.
+ */
+char *
+vos_optArg (char *arg)
+{
+ char *ip, first = (arg ? *arg : 0);
+
+ if (!arg || !first) return ("");
+ return ( ((ip = strchr (arg, (int) '=')) ? ++ip : arg) );
+}
+
+
+/**
+ * VOS_TOURL -- Convert the argument to a URL suitable for a message.
+ */
+char *
+vos_toURL (char *arg)
+{
+ /* If we have an existing protocol simply return the argument.
+ */
+ if ((strncmp (arg, "http:", 5) == 0) ||
+ (strncmp (arg, "file:", 5) == 0) ||
+ (strncmp (arg, "ftp:", 4) == 0))
+ return (arg);
+
+ if (access (arg, F_OK) == 0) {
+ static char buf[SZ_FNAME];
+
+ memset (buf, 0, SZ_FNAME);
+ if (arg[0] != '/') {
+ char cwd[SZ_FNAME];
+
+ memset (cwd, 0, SZ_FNAME);
+ getcwd (cwd, (unsigned long) SZ_FNAME);
+ sprintf (buf, "file://%s/%s", cwd, arg);
+ } else
+ sprintf (buf, "file://%s", arg);
+
+ return (buf);
+ }
+
+ return (arg);
+}
+
+
+/**
+ * VOS_TOINTARRAY -- Convert a range string to an unpacked array of ints.
+ */
+#define MAX_RANGES 256
+#define SZ_ROW 16
+
+int *
+vos_toIntArray (char *arg, int *nrows)
+{
+ int i, val, nvalues;
+ static int ranges[MAX_RANGES], values[MAX_ROWS];
+ extern int vot_decodeRanges(), get_next_number();
+
+
+ memset (values, 0, (sizeof(int) * MAX_ROWS));
+ memset (ranges, 0, (sizeof(int) * MAX_RANGES));
+
+ if (vot_decodeRanges (arg, ranges, MAX_RANGES, &nvalues) < 0)
+ fprintf (stderr, "Error decoding range string.\n");
+
+ for (i=0, val=0; (val = get_next_number (ranges, val)) > 0; i++ )
+ values[i] = val;
+
+ *nrows = nvalues;
+ return (values);
+}
+
+
+
+/*****************************************************************************
+**** Socket Utilities
+*****************************************************************************/
+
+
+#define SELWIDTH 32
+#define SOCK_MAX_TRY 3
+
+/**
+ * VOS_OPENSERVERSOCKET -- Open a socket to be used on the 'server' side.
+ *
+ * @brief Open a socket to be used on the 'server' side
+ * @fn int vos_openServerSocket (int port)
+ *
+ * @param port port number to open
+ * @return socket descriptor
+ *
+ */
+int
+vos_openServerSocket (int port)
+{
+ struct sockaddr_in servaddr; /* server address */
+ int ps = 0; /* parallel socket descriptor */
+ int32_t yes = 1, ntries = 5;
+
+
+ /* Create a socket.
+ */
+ if ((ps = socket (AF_INET, SOCK_STREAM, 0)) < 0) {
+ fprintf (stderr, "openServerSocket(%d): %s\n", port, strerror(errno));
+ return (-1);
+ }
+ setsockopt (ps, SOL_SOCKET, SO_REUSEADDR, (void *)&yes, sizeof(yes));
+
+ if (VOS_DEBUG)
+ fprintf (stderr, "server socket %d on %s:%d\n", ps,
+ vos_getLocalIP(), port );
+
+
+ /* Set server address.
+ */
+ memset (&servaddr, 0, sizeof servaddr);
+ servaddr.sin_family = AF_INET;
+ servaddr.sin_port = htons(port);
+ servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
+
+ /* Bind to the server socket and listen for a connection.
+ */
+ while (ntries--) {
+ if (bind (ps, (struct sockaddr*)&servaddr, sizeof servaddr) < 0) {
+ if (!ntries)
+ return (-1);
+ } else {
+ if ((listen (ps, SOMAXCONN)) < 0) {
+ fprintf (stderr,
+ "serverSock: listen(%d:%s)", port, strerror(errno));
+ if (!ntries)
+ return (-1);
+ } else {
+ break;
+ }
+ }
+ sleep (1);
+ }
+
+ return (ps);
+}
+
+
+/**
+ * VOS_OPENCLIENTSOCKET -- Open a socket to be used on the 'client' side.
+ *
+ * @brief Open a socket to be used on the 'client' side
+ * @fn int vos_openClientSocket (char *host, int port, int retry)
+ *
+ * @param host host name
+ * @param port port number to open
+ * @param retry attempt to reconnect?
+ * @return socket descriptor
+ *
+ */
+int
+vos_openClientSocket (char *host, int port, int retry)
+{
+ char *ip, lhost[SZ_LINE];
+ struct sockaddr_in servaddr; /* server address */
+ int ps = 0; /* parallel socket descriptor */
+ socklen_t ctry = 0, yes = 1;
+
+
+ /* Remove any server port information from the host specification.
+ */
+ memset (lhost, 0, SZ_LINE);
+ strcpy (lhost, host);
+ if ( (ip = strchr (lhost, (int) ':')) )
+ *ip = '\0';
+
+ /* Create a socket.
+ */
+ if ((ps = socket (AF_INET, SOCK_STREAM, 0)) < 0) {
+ fprintf (stderr, "openClientSocket(%s:%d): %s\n",
+ host, port, strerror(errno));
+ return (-1);
+ }
+ setsockopt (ps, SOL_SOCKET, SO_REUSEADDR, (void *)&yes, sizeof(yes));
+
+
+ /* Set server address.
+ */
+ memset (&servaddr, 0, sizeof (struct sockaddr_in));
+ servaddr.sin_family = AF_INET;
+ servaddr.sin_port = htons(port);
+
+ /* Connect to server.
+ */
+ for (ctry = (retry ? 0 : SOCK_MAX_TRY); ctry <= SOCK_MAX_TRY; ctry++) {
+
+ if ( !inet_aton(lhost, &servaddr.sin_addr) ) {
+ struct hostent *he = vos_getHostByName ( lhost );
+
+ if (!he) {
+ fprintf (stderr, "Cannot resolve address.\n");
+ exit (2);
+ }
+ if (he->h_addrtype != AF_INET ||
+ he->h_length != sizeof (servaddr.sin_addr)) {
+ fprintf (stderr, "Cannot handle addr type %d, length %d.\n",
+ he->h_addrtype, he->h_length);
+ exit(2);
+ }
+ memcpy (&servaddr.sin_addr, he->h_addr_list[0],
+ sizeof (servaddr.sin_addr) );
+ }
+
+ if (connect (ps, (struct sockaddr *)&servaddr, sizeof servaddr) < 0) {
+ if (!retry || ctry == SOCK_MAX_TRY) {
+ fprintf (stderr,
+ "client connect() failed to %s:%d, try %d, retry %d\n",
+ lhost, port, ctry, retry);
+ close (ps);
+ ps = -1;
+ break;
+ } else
+ sleep (1);
+ } else
+ break;
+ }
+
+ return (ps);
+}
+
+
+/**
+ * VOS_TESTCLIENTSOCKET -- Test a socket to be used on the 'client' side.
+ *
+ * @brief Test a socket to be used on the 'client' side
+ * @fn int vos_testClientSocket (char *host, int port)
+ *
+ * @param host host name
+ * @param port port number to open
+ * @return socket descriptor or -1 if connect fails
+ *
+ */
+int
+vos_testClientSocket (char *host, int port)
+{
+ char *ip, lhost[SZ_LINE];
+ struct sockaddr_in servaddr; /* server address */
+ int sock = 0; /* socket descriptor */
+ socklen_t yes = 1;
+
+
+ /* Remove any server port information from the host specification.
+ */
+ memset (lhost, 0, SZ_LINE);
+ strcpy (lhost, host);
+ if ( (ip = strchr (lhost, (int) ':')) )
+ *ip = '\0';
+
+ /* Create a socket.
+ */
+ if ((sock = socket (AF_INET, SOCK_STREAM, 0)) < 0)
+ return (-1);
+ setsockopt (sock, SOL_SOCKET, SO_REUSEADDR, (void *)&yes, sizeof(yes));
+
+
+ /* Set server address.
+ */
+ memset (&servaddr, 0, sizeof (struct sockaddr_in));
+ servaddr.sin_family = AF_INET;
+ servaddr.sin_port = htons(port);
+
+ /* Connect to server.
+ */
+ if ( !inet_aton(lhost, &servaddr.sin_addr) ) {
+ struct hostent *he = vos_getHostByName ( lhost );
+
+ if (!he)
+ return (-1);
+ if (he->h_addrtype != AF_INET ||
+ he->h_length != sizeof (servaddr.sin_addr)) {
+ return (-1);
+ }
+ memcpy (&servaddr.sin_addr, he->h_addr_list[0],
+ sizeof (servaddr.sin_addr) );
+ }
+
+ if (connect (sock, (struct sockaddr *)&servaddr, sizeof servaddr) < 0) {
+ close (sock);
+ sock = -1;
+ }
+ return (sock);
+}
+
+
+/**
+ * VOS_SOCKWRITEHDR -- Write the socket message header.
+ */
+int
+vos_sockReadHdr (int fd, int *len, char *name, int *type, int *mode)
+{
+ int nread = 0;
+
+ memset (&msgHdr, 0, sizeof (msgHdr));
+ if ((nread = vos_sockRead (fd, &msgHdr, sizeof (msgHdr))) > 0) {
+ *len = msgHdr.nbytes;
+ *type = msgHdr.type;
+ *mode = msgHdr.mode;
+ to = strdup (msgHdr.recipient);
+ strcpy (senderIP, msgHdr.senderIP);
+ if (name)
+ strcpy (name, msgHdr.fname); /* must be at least SZ_FNAME */
+ }
+
+ if (VOS_DEBUG)
+ vos_sockPrintHdr ("Read Hdr", fd);
+
+ return (nread);
+}
+
+
+/**
+ * VOS_SOCKWRITEHDR -- Write the socket message header.
+ */
+int
+vos_sockWriteHdr (int fd, int len, char *name, int type, int mode, char *to)
+{
+ int nwrite = 0;
+
+ memset (&msgHdr, 0, sizeof (msgHdr));
+ msgHdr.nbytes = len;
+ msgHdr.type = type;
+ msgHdr.mode = mode;
+ if (name && name[0]) {
+ struct stat st;
+ stat (name, &st);
+ strcpy (msgHdr.fname, name);
+ msgHdr.fsize = st.st_size;
+ }
+ strcpy (msgHdr.recipient, (to ? to : "all"));
+ strcpy (msgHdr.senderIP, vos_getLocalIP());
+
+ if (VOS_DEBUG)
+ vos_sockPrintHdr ("Write Hdr", fd);
+
+ return ((nwrite = vos_sockWrite (fd, &msgHdr, sizeof(msgHdr))));
+}
+
+
+/**
+ * VOS_SOCKPRINTHDR -- Debug utility to print a message header.
+ */
+void
+vos_sockPrintHdr (char *msg, int fd)
+{
+ fprintf (stderr, "%s: fd=%d\n", msg, fd);
+ fprintf (stderr, " { 'type' : %d, 'mode' : %d,\n",
+ msgHdr.type, msgHdr.mode);
+ fprintf (stderr, " 'fname' : '%s', 'nbytes' : %d, 'fsize' : %d,\n",
+ msgHdr.fname, msgHdr.nbytes, msgHdr.fsize);
+ fprintf (stderr, " 'session' : '%s', 'port' : %d,\n",
+ msgHdr.session, msgHdr.sessionPort);
+ fprintf (stderr, " 'sender' : '%s', 'port' : %d, 'to' : '%s'\n",
+ msgHdr.senderIP, msgHdr.senderPort, msgHdr.recipient);
+ fprintf (stderr, " }\n");
+}
+
+
+/**
+ * VOS_SOCKREAD -- Read exactly "n" bytes from a socket descriptor.
+ *
+ * @brief Recv exactly "n" bytes from a socket descriptor.
+ * @fn int vos_sockRead (int fd, void *vptr, int nbytes)
+ *
+ * @param fd file descriptor
+ * @param vptr data buffer to be written
+ * @param nbytes number of bytes to write
+ * @return number of bytes written
+ */
+int
+vos_sockRead (int fd, void *vptr, int nbytes)
+{
+ char *ptr = vptr;
+ int nread = 0, nleft = nbytes, nb = 0;
+ fd_set allset, fds;
+
+
+ /* Set non-blocking mode on the descriptor.
+ */
+ vos_setNonBlock (fd);
+
+ FD_ZERO (&allset);
+ FD_SET (fd, &allset);
+
+ while (nleft > 0) {
+ fds = allset;
+ if (select (SELWIDTH, &fds, NULL, NULL, NULL)) {
+ if ( (nb = recv (fd, ptr, nleft, 0)) < 0) {
+ if (errno == EINTR || errno == EAGAIN)
+ nb = 0; /* and call recv() again */
+ else {
+ fprintf (stderr, "[%d] vos_sockRead:[%d] %s\n",
+ (int) getpid(), fd, strerror(errno));
+ return (-1);
+ }
+ } else if (nb == 0)
+ break; /* EOF */
+ nleft -= nb;
+ ptr += nb;
+ nread += nb;
+ }
+ }
+
+ if (VOS_DEBUG)
+ fprintf (stderr, "sockRead: %d bytes on fd=%d\n", nread, fd);
+
+ return (nread); /* return no. of bytes read */
+}
+
+
+/**
+ * VOS_SOCKWRITE -- Write exactly "n" bytes to a socket descriptor.
+ *
+ * @brief Send exactly "n" bytes to a socket descriptor.
+ * @fn int vos_sockWrite (int fd, void *vptr, int nbytes)
+ *
+ * @param fd file descriptor
+ * @param vptr data buffer to be written
+ * @param nbytes number of bytes to write
+ * @return number of bytes written
+ */
+int
+vos_sockWrite (int fd, void *vptr, int nbytes)
+{
+ char *ptr = vptr;
+ int nwritten = 0, nleft = nbytes, nb = 0;
+ fd_set allset, fds;
+
+
+ /* Set non-blocking mode on the descriptor.
+ */
+ vos_setNonBlock (fd);
+
+ FD_ZERO (&allset);
+ FD_SET (fd, &allset);
+
+ while (nleft > 0) {
+ fds = allset;
+ if (select (SELWIDTH, NULL, &fds, NULL, NULL)) {
+ if ( (nb = send (fd, ptr, nleft, 0)) <= 0) {
+ if (errno == EINTR || errno == EAGAIN)
+ nb = 0; /* and call send() again */
+ else {
+ /*
+ fprintf (stderr, "[%d] vos_sockWrite[%d]: %s\n",
+ (int) getpid(), fd, strerror (errno));
+ */
+ return (-1);
+ }
+ }
+ nleft -= nb;
+ ptr += nb;
+ nwritten += nb;
+ }
+ }
+
+ if (VOS_DEBUG)
+ fprintf (stderr, "sockWrite: %d bytes on fd=%d\n", nwritten, fd);
+
+ return (nwritten);
+}
+
+
+/**
+ * VOS_FILEREAD -- Read exactly "n" bytes from a socket descriptor.
+ *
+ * @brief Recv exactly "n" bytes from a socket descriptor.
+ * @fn int vos_sockRead (int fd, void *vptr, int nbytes)
+ *
+ * @param fd file descriptor
+ * @param vptr data buffer to be written
+ * @param nbytes number of bytes to write
+ * @return number of bytes written
+ */
+int
+vos_fileRead (int fd, void *vptr, int nbytes)
+{
+ char *ptr = vptr;
+ int nread = 0, nleft = nbytes, nb = 0;
+
+ while (nleft > 0) {
+ if ( (nb = read(fd, ptr, nleft)) < 0) {
+ if (errno == EINTR)
+ nb = 0; /* and call read() again */
+ else
+ return(-1);
+ } else if (nb == 0)
+ break; /* EOF */
+ nleft -= nb;
+ ptr += nb;
+ nread += nb;
+ }
+ return (nread); /* return no. of bytes read */
+}
+
+
+/**
+ * VOS_FILEWRITE -- Write exactly "n" bytes to a file descriptor.
+ *
+ * @brief Send exactly "n" bytes to a file descriptor.
+ * @fn int vos_fileWrite (int fd, void *vptr, int nbytes)
+ *
+ * @param fd file descriptor
+ * @param vptr data buffer to be written
+ * @param nbytes number of bytes to write
+ * @return number of bytes written
+ */
+int
+vos_fileWrite (int fd, void *vptr, int nbytes)
+{
+ char *ptr = vptr;
+ int nwritten = 0, nleft = nbytes, nb = 0;
+
+ while (nleft > 0) {
+ if ( (nb = write(fd, ptr, nleft)) <= 0) {
+ if (errno == EINTR)
+ nb = 0; /* and call write() again */
+ else
+ return(-1); /* error */
+ }
+ nleft -= nb;
+ ptr += nb;
+ nwritten += nb;
+ }
+ return (nwritten);
+}
+
+
+/**
+ * VOS_SETNONBLOCK -- Set a non-blocking mode on the socket descriptor.
+ */
+void
+vos_setNonBlock (int sock)
+{
+ int flags;
+
+
+ /* Set socket to non-blocking.
+ */
+ if ((flags = fcntl (sock, F_GETFL, 0)) < 0) {
+ /* Handle error */
+ return;
+ }
+ if (fcntl (sock, F_SETFL, flags | O_NONBLOCK) < 0) {
+ /* Handle error */
+ return;
+ }
+}
+
+
+/**
+ * VOS_GETLOCALIP -- Get the IP address of the local machine.
+ */
+char *
+vos_getLocalIP (void)
+{
+ const char *kGoogleDnsIp = "8.8.8.8"; /* Google's public DNS server */
+ unsigned short kDnsPort = 53;
+ struct sockaddr_in serv;
+ int sock, err;
+ const char *p;
+ char buffer[SZ_BUF];
+ static int initialized = 0;
+ static char localIP[SZ_BUF];
+
+
+ /* Only get the IP once, afterwards just return the value.
+ */
+ if (initialized++)
+ return (localIP);
+
+ memset (buffer, 0, SZ_BUF);
+ memset (localIP, 0, SZ_BUF);
+
+ if ((sock = socket (AF_INET, SOCK_DGRAM, 0)) < 0)
+ return ("127.0.0.1"); /* cannot get socket, punt */
+
+ memset (&serv, 0, sizeof (serv));
+ serv.sin_family = AF_INET;
+ serv.sin_addr.s_addr = inet_addr(kGoogleDnsIp);
+ serv.sin_port = htons(kDnsPort);
+
+ if ((err = connect(sock, (struct sockaddr*)&serv, sizeof(serv))) >= 0) {
+ struct sockaddr_in name;
+ socklen_t namelen = sizeof(name);
+
+ if ((err=getsockname(sock, (struct sockaddr*)&name, &namelen)) < 0)
+ strcpy (buffer, "127.0.0.1"); /* cannot connect socket */
+ else
+ if ((p=inet_ntop(AF_INET, &name.sin_addr, buffer, SZ_BUF)) == NULL)
+ strcpy (buffer, "127.0.0.1"); /* cannot get IP buffer name */
+ } else
+ strcpy (buffer, "127.0.0.1"); /* cannot get IP buffer name */
+
+ if (strncmp (buffer, "192.168.", 8) == 0)
+ strcpy (buffer, "127.0.0.1"); /* cannot get IP buffer name */
+
+ close(sock);
+
+ strcpy (localIP, buffer);
+ return (localIP);
+}
+
+
+/**
+ * VOS_GETHOSTBYNAME -- Get the host entry associated with a (cached) name.
+ *
+ * @fn char *vos_getHostByName (char *name)
+ *
+ * @param name host name
+ * @return host entry structure pointer
+ */
+typedef struct {
+ char name[SZ_LINE];
+ char ip[SZ_LINE];
+ struct hostent *host;
+} hostTab, *hostTabP;
+
+struct hostent_wrapper {
+ struct hostent hentry;
+ int status;
+};
+
+static hostTab hostab[MAX_CLIENTS];
+
+
+struct hostent *
+vos_getHostByName (char *name)
+{
+ static int initialized = 0;
+ struct in_addr x_addr;
+ struct hostent *hp = (struct hostent *) NULL;
+ hostTab *h = (hostTabP) hostab;
+ int i, len;
+
+
+ if (!initialized) {
+ memset (hostab, 0, sizeof (hostab));
+ initialized++;
+ }
+
+ for (i=0; i < MAX_CLIENTS; i++, h++) {
+ if (h && h->name[0]) {
+ len = min (strlen (name), strlen (h->name));
+ if (strncmp (name, h->name, len) == 0)
+ return (h->host);
+ } else
+ break; /* end of cache list */
+ }
+
+ /* If we overflow the cache use a DNS lookup.
+ */
+ if (i >= MAX_CLIENTS) {
+ fprintf (stderr, "vos_getHostByName(): cache overflow on '%s'", name);
+ hp = gethostbyname (name);
+ return (hp);
+ }
+
+ /* Host not found, resolve and add it to the cache.
+ */
+ hp = gethostbyname (name);
+ if (hp == (struct hostent *) NULL) {
+ fprintf (stderr, "vos_getHostByName: cannot resolve '%s'\n", name);
+ exit (0);
+ }
+
+ strcpy (h->name, name);
+ x_addr.s_addr = *((unsigned long *) hp->h_addr_list[0]);
+ strcpy (h->ip, inet_ntoa (x_addr));
+
+ h->host = vos_dupHostent (hp);
+ return (h->host);
+}
+
+
+/**
+ * VOS_DUPHOSTENT -- Duplicate a hostent structure via a deep copy.
+ */
+struct hostent *
+vos_dupHostent (struct hostent *hentry)
+{
+ struct hostent_wrapper *oldhw = NULL;
+ struct hostent_wrapper *newhw = NULL;
+ int i = 0;
+ int aliascount=0;
+ int addrcount=0;
+
+
+ if (!hentry)
+ return NULL;
+
+ oldhw = (struct hostent_wrapper *) hentry;
+ newhw = (struct hostent_wrapper *) malloc (sizeof (struct hostent_wrapper));
+ bzero(newhw, sizeof (struct hostent_wrapper));
+
+ newhw->hentry.h_addrtype = hentry->h_addrtype;
+ newhw->hentry.h_length = hentry->h_length;
+ newhw->status = oldhw->status;
+
+ if (hentry->h_name)
+ newhw->hentry.h_name = strdup(hentry->h_name);
+
+ if (hentry->h_aliases) {
+ for (i=0; hentry->h_aliases[i] != 0; i++)
+ aliascount++;
+ aliascount++;
+
+ newhw->hentry.h_aliases = (char **)malloc (aliascount * sizeof (char*));
+ bzero(newhw->hentry.h_aliases, aliascount * sizeof(char*));
+
+ for (i=0; hentry->h_aliases[i] != 0; i++) {
+ if (hentry->h_aliases[i])
+ newhw->hentry.h_aliases[i] = strdup (hentry->h_aliases[i]);
+ }
+ }
+
+ if (hentry->h_addr_list) {
+ for (i=0; hentry->h_addr_list[i] != 0; i++)
+ addrcount++;
+ addrcount++;
+
+ newhw->hentry.h_addr_list =
+ (char **) malloc (addrcount * sizeof (char *));
+ bzero (newhw->hentry.h_addr_list, addrcount * sizeof (char *));
+
+ for (i=0; hentry->h_addr_list[i] != 0; i++) {
+ if (hentry->h_addr_list[i])
+ newhw->hentry.h_addr_list[i] = strdup (hentry->h_addr_list[i]);
+ }
+ }
+
+ return (struct hostent *) newhw;
+}
+
+/**
+ * VOS_STRSUB -- Do a string subsitution.
+ */
+int
+vos_strsub (char *in, char *from, char *to, char *outstr, int maxch)
+{
+ int flen = strlen (from);
+ int nsub = 0;
+ char *ip, *op;
+
+ if (!from || !to)
+ return (0);
+
+ for (ip=in, op=outstr; *ip; ip++) {
+ if (! *ip || (ip - in) > maxch)
+ break;
+ if (*ip == '$') {
+ /* Start of a macro.
+ */
+ if (strncasecmp (ip, from, flen) == 0) {
+ /* Our macro, do the substitution.
+ */
+ char *tp = to;
+
+ ip += flen - 1; /* skip the input macro */
+ while (*tp) /* copy replacement string */
+ *op++ = *tp++;
+ nsub++;
+ } else {
+ /* Not our macro, just pass it through.
+ */
+ *op++ = *ip;
+ }
+ } else {
+ *op++ = *ip;
+ }
+ }
+ *op = '\0';
+
+ return (nsub);
+}
diff --git a/vendor/voclient/voapps/session_cmd.c b/vendor/voclient/voapps/session_cmd.c
new file mode 100644
index 00000000..41b70451
--- /dev/null
+++ b/vendor/voclient/voapps/session_cmd.c
@@ -0,0 +1,171 @@
+/**
+ * SESSION_CMD -- Session Manager test client.
+ *
+ * @file session_cmd.c
+ * @author Mike Fitzpatrick
+ * @date 6/03/12
+ *
+ * @brief Session Manager test client.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <ctype.h>
+#include <fcntl.h>
+#include <time.h>
+
+#include <netdb.h>
+#include <sys/errno.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#include "samp.h" /* SAMP interface */
+#include "voApps.h" /* voApps interface */
+
+
+#define SZ_BUF 1024
+#define SELWIDTH 4
+
+
+/* Utility socket routines.
+ */
+extern int vos_uploadFiles (int sock, char *cmd);
+extern int vos_openClientSocket (char *host, int port, int retry);
+extern int vos_sockRead (int fd, void *vptr, int nbytes);
+extern int vos_sockWrite (int fd, void *vptr, int nbytes);
+extern int vos_sockWriteHdr (int fd, int len, char *name, int type,
+ int mode, char *to);
+extern int vos_sockReadHdr (int fd, int *len, char *name, int *type,
+ int *mode);
+
+extern int vos_openSession (char *host, int port, char *session_name);
+extern int vos_closeSession (int sock);
+
+extern void vos_setNonBlock (int sock);
+extern struct hostent *vos_getHostByName (char *lhost);
+
+
+
+/****************************************************************************
+ * Program entry point.
+ */
+int
+main (int argc, char **argv)
+{
+ int i, j, rc, debug=0, len=0, nw=0, cb_sock=0, nfiles=0;
+ int mgr_port = SESS_DEFPORT;
+ char *mgr_host = SESS_DEFHOST;
+ char *sname = "test";
+ char buf[SZ_BUF];
+
+ fd_set allset, fds;
+
+
+ /* Process cmdline args.
+ */
+ for (i=1; i < argc; i++) {
+ for (j=1; j < argc; j++) {
+ switch ( argv[i][j] ) {
+ case 'd': debug++; break;
+
+ default:
+ fprintf (stderr, "Invalid option '%c'\n", argv[i][0]);
+ return (1);
+ }
+ }
+ }
+
+
+
+ /* Open a client connection to the VOSAMP Session Manager.
+ */
+ if ((cb_sock = vos_openSession (mgr_host, mgr_port, sname)) == 0) {
+ fprintf (stderr, "Cannot open connection to session manager\n");
+ return (1);
+ }
+
+ /* Take commands from the stdin, write results to stdout.
+ */
+ printf ("vosession> "); fflush (stdout);
+
+ FD_ZERO (&allset);
+ FD_SET (cb_sock, &allset); vos_setNonBlock (cb_sock);
+ FD_SET (fileno(stdin), &allset); vos_setNonBlock (fileno(stdin));
+
+
+ /* Process input either from the stdin or the session manager.
+ */
+ while (1) {
+ /* Initialize the input file descriptor set.
+ */
+ memcpy (&fds, &allset, sizeof(allset));
+ rc = select (SELWIDTH, &fds, NULL, NULL, NULL);
+
+ for (i=0; i < SELWIDTH+1; i++) {
+ if (FD_ISSET(i, &fds)) {
+ if (i == fileno(stdin)) {
+ if (fgets (buf, SZ_BUF, stdin) == NULL)
+ goto done_; /* EOF, time to quit */
+ buf[strlen(buf)-1] = '\0'; /* kill newline */
+
+ } else {
+ int nread, nbytes, type, mode;
+ char fname[SZ_FNAME];
+
+ if (vos_sockReadHdr (i, &nbytes, fname, &type, &mode))
+ nread = vos_sockRead (i, buf, nbytes);
+ else
+ goto done_;
+
+ switch (type) {
+ case SAMP_QUIT:
+ goto done_;
+ case SAMP_RESULT:
+ printf ("\r\n%s\n", buf);
+ goto next_cmd;
+ case SAMP_CMD:
+ printf ("Got cmd: '%s'\n", buf);
+ goto next_cmd;
+ case SAMP_TEST:
+ printf ("Got test cmd: '%s'\n", buf);
+ goto next_cmd;
+ case SAMP_RELAY:
+ printf ("Got relayed cmd: '%s'\n", buf);
+ goto next_cmd;
+ default:
+ printf ("Got msg type: %d\n", type);
+ goto next_cmd;
+ }
+ }
+ }
+ }
+
+ /* If we want to quit, let the vos_closeSession() send the 'quit'.
+ */
+ if (strncasecmp (buf, "quit", 4) == 0)
+ break;
+
+ /* Upload any local files to the session manager.
+ */
+ nfiles = vos_uploadFiles (cb_sock, buf);
+ if (debug)
+ if (nfiles) fprintf (stderr, "sent %d data files....\n", nfiles);
+
+ /* Send the command string.
+ */
+ len = strlen (buf);
+ if (vos_sockWriteHdr(cb_sock, len, NULL, SAMP_CMD, SAMP_NOTIFY, "smgr"))
+ nw = vos_sockWrite (cb_sock, buf, len);
+
+next_cmd:
+ memset (buf, 0, SZ_BUF);
+ printf ("vosession> "); fflush (stdout);
+ }
+
+done_:
+ vos_closeSession (cb_sock);
+ return (0);
+}
diff --git a/vendor/voclient/voapps/spp/README b/vendor/voclient/voapps/spp/README
new file mode 100644
index 00000000..3b7a7688
--- /dev/null
+++ b/vendor/voclient/voapps/spp/README
@@ -0,0 +1,9 @@
+
+ This directory contains tasks written or designed for use with
+IRAF SPP. In some cases these will simply be example tasks to exercise
+or demonstrate the language support.
+
+
+Current Tasks include:
+
+ [None at this time]
diff --git a/vendor/voclient/voapps/task/Makefile b/vendor/voclient/voapps/task/Makefile
new file mode 100644
index 00000000..afd04b38
--- /dev/null
+++ b/vendor/voclient/voapps/task/Makefile
@@ -0,0 +1,169 @@
+#///////////////////////////////////////////////////////////////////////////////
+#//
+#// Makefile for the VOClient Tasking Interface
+#//
+#///////////////////////////////////////////////////////////////////////////////
+
+# primary dependencies
+
+NAME = voTask
+VERSION = 1.0
+PLATFORM := $(shell uname -s)
+PLMACH := $(shell uname -m)
+HERE := $(shell /bin/pwd)
+BINDIR := ../bin/
+LIBDIR := ../lib/
+INCDIR := ../include/
+PYVER := $(shell csh -c "python --version |& cut -c8-10")
+
+# secondary dependencies
+LIBBASE = lib$(NAME)
+STATICLIB = $(HERE)/$(LIBBASE).a
+SHAREDLIB = $(HERE)/$(LIBBASE).so.$(VERSION)
+
+
+# stuff that's precious to keep
+.PRECIOUS: $(STATICLIB) $(SHAREDLIB)
+.KEEP_STATE:
+
+
+# includes, flags and libraries
+CC = gcc
+CINCS = -I$(INCDIR) -I.
+
+ifeq ($(PLATFORM),Darwin)
+ ifeq ($(PLMACH),x86_64)
+ CARCH = -m64 -mmacosx-version-min=10.5
+ else
+ #CARCH = -arch i386 -arch ppc -m32 -mmacosx-version-min=10.4
+ CARCH = -mmacosx-version-min=10.4
+ endif
+ PYFLAGS = -dynamiclib -I/usr/include/python$(PYVER)/ -lpython$(PYVER)
+else
+ CARCH =
+ PYFLAGS = -DLINUX
+endif
+
+CLIBS = -lm -lc -lcurl -lpthread -lm
+CFLAGS = -g -Wall $(CARCH) -D$(PLATFORM) $(CINCS) -L./
+
+
+
+# includes, flags and libraries
+CC = gcc
+CINCS = -I$(HERE) -I../ -I../include -L../ -L../lib/ -L../
+
+#F77 = g77
+F77 = gfortran
+FFLAGS = -g -Wall
+
+# list of source and include files
+C_SRCS = voParam.c voPkg.c voTask.c voTaskMethod.c voTaskUtil.c
+C_OBJS = voParam.o voPkg.o voTask.o voTaskMethod.o voTaskUtil.o
+C_INCS = voTask.h voTaskP.h
+
+C_TASKS =
+TARGETS = $(C_TASKS)
+
+SRCS = $(C_SRCS)
+OBJS = $(C_OBJS)
+HOST_LIBS = -lcurl -lcfitsio -lpthread -lm
+LIBS = -L../../lib $(HOST_LIBS) -lvotable -lsamp -lVOClient -lcfitsio
+
+
+all:
+ make lib
+
+World: lib
+
+install: all
+ cp lib$(NAME).a $(LIBDIR)
+ mv $(TARGETS) $(BINDIR)
+
+objs: $(OBJS)
+
+
+# Targets
+
+#all: $(TARGETS)
+
+progs: $(C_TASKS)
+
+votools: pkgMain.o
+ $(CC) $(CFLAGS) -o votools.vop pkgMain.c ../libVOApps.a $(LIBS)
+ /bin/rm -rf *.dSYM
+
+pylib:
+ $(CC) $(PYFLAGS) -o voPackage.so voPackage.c
+
+clean:
+ /bin/rm -rf .make.state .nse_depinfo *.[aeo] *.dSYM
+ /bin/rm -rf $(TARGETS)
+
+everything:
+ make clean
+ make all
+ make install
+
+help: HELP
+
+install: all
+
+
+
+####################################
+# LIBVOTASK dependency libraries.
+####################################
+
+lib: objs
+ ar rv lib$(NAME).a $(OBJS)
+ $(RM) $(OBJS)
+
+
+
+###############################################################################
+# Unit test programs to be built.
+###############################################################################
+
+zztest: zztest.c
+ $(CC) $(CFLAGS) -o zztest zztest.c $(LIBS)
+
+
+###########################
+# C Test programs
+###########################
+
+
+###########################
+# SPP Test programs
+###########################
+
+
+###########################
+# Fortran Test programs.
+###########################
+
+
+
+
+
+
+###############################################################################
+# Leave this stuff alone.
+###############################################################################
+
+$(STATICLIB): $(C_SRCS:%.c=Static/%.o)
+ /usr/bin/ar rv $@ $?
+Static/%.o: %.c $(C_INCS)
+ /usr/bin/gcc $(CINCS) $(CFLAGS) -g -c $< -o $@
+Static:
+ /bin/mkdir $@
+ chmod 777 $@
+
+$(SHAREDLIB): $(C_SRCS:%.c=Shared/%.o)
+ /usr/bin/ld -shared -o $@ $? -lc -ldl
+Shared/%.o: %.c $(C_INCS)
+ /usr/bin/gcc $(CINCS) $(CFLAGS) -fpic -shared -c $< -o $@
+Shared:
+ /bin/mkdir $@
+ chmod 777 $@
diff --git a/vendor/voclient/voapps/task/Notes.fitz b/vendor/voclient/voapps/task/Notes.fitz
new file mode 100644
index 00000000..fe36e903
--- /dev/null
+++ b/vendor/voclient/voapps/task/Notes.fitz
@@ -0,0 +1,99 @@
+ Client Interface:
+ =================
+
+ Package/Task Management:
+ ------------------------
+
+ vo_setPkgDir (path) # set package dir
+ path = vo_getPkgDir () # get package dir
+
+ pkg = vo_pkgList (pattern) # Get available packages
+ len = vo_pkgLen (pkg)
+ pkg = vo_pkgNext (pkg)
+ str = vo_pkgAttr (pkg, attr)
+
+ task = vo_taskList (taskName) # Get tasks in package
+ len = vo_taskLen (task)
+ str = vo_taskNext (task)
+ task = vo_taskAttr (task, attr)
+
+ pp = vo_taskParams (pkgName, taskName) # Input param defs
+ ( see parameter handling below )
+
+ xml = vo_pkgXML (pattern) # XML serializations (opt)
+ xml = vo_taskXML (pkgName)
+ xml = vo_paramXML (pkgName, taskName)
+
+
+ Task Execution:
+ ---------------
+
+ tp = vo_taskInit (pkgName, taskName) # Initialize a task
+
+ vo_taskSetStringParam (tp, pname, sval) # Set input params
+ vo_taskSetBoolParam (tp, pname, bval)
+ vo_taskSetIntParam (tp, pname, ival)
+ vo_taskSetRealParam (tp, pname, dval)
+ vo_taskSetDictParam (tp, pname, dict)
+ vo_taskSetListParam (tp, pname, list)
+ vo_taskSetPtrParam (tp, pname, ptr, size)
+
+ vo_taskSetCallback (tp, type, &func) # Set param callback
+ rp = vo_taskExecuteSync (tp, status, msg) # Execute sync
+ vo_taskExecuteAsync (tp) # Execute async
+ rp = vo_taskWait (tp) # Wait for task, get RP
+ status = vo_taskCheckError (tp, msg) # Check for any error
+
+ vo_taskClose (tp) # Free task resources
+
+ Parameter Handling:
+ -------------------
+
+ Directed parameter access:
+
+ int = vo_taskParamCount (rp)
+ vo_taskGetParamInfo (rp, pnum, *name, *type, *encoding,
+ *description)
+ str = vo_taskGetStringParam (rp, pname, pnum) # pnum used if pname=null
+ ival = vo_taskGetBoolParam (rp, pname, pnum)
+ ival = vo_taskGetIntParam (rp, pname, pnum)
+ dval = vo_taskGetRealParam (rp, pname, pnum)
+ dict = vo_taskGetDictParam (rp, pname, pnum)
+ dict = vo_taskGetListParam (rp, pname, pnum)
+ void = vo_taskGetParamValue (rp, pname, pnum, size)
+
+ Iterated parameter access:
+
+ pp = vo_taskGetParam (rp, pname, pnum)
+ len = vo_paramLen (pp, [typ|enc])
+ pp = vo_paramNext (pp, [typ|enc])
+ str = vo_paramAttr (pp, attr)
+
+
+Notes:
+======
+
+ - Added set/get methods for the package directory to be searched for
+ packages. This allows a client to point to different dirs depending
+ on which package is being 'loaded'.
+ - The pkgList() takes a 'pattern' param to select only files matching a
+ specific pattern (e.g. "*.e" or "*.pkg") from the working directory.
+ Only files matching the pattern (or all files if NULL) will be queried
+ for metadata. This also allows for a directory to contain single-task
+ binaries and not require a single binary for all tasks in a package.
+ - Made pkg/task/param listings optionally XML, these are manageable by
+ many languages but not always 'natural'. The use of iterators allows
+ a client to traverse the metadata and request attributes w/out depending
+ on an XML parser.
+ - Added 'pname' to the setParam() methods to set specific params.
+ - Added status/msg returns from sync execution
+ - Input and output parameters share the same data structure and interface
+ methods work on either. This means a 'blob' can now be an input param,
+ e.g. an in-memory object (e.g. a target list or TAP ADQL string) from a
+ client can be posted over IPC to the task. Note however this may not be
+ implemented for current tasks.
+ - Parameter callbacks can be set for specific parameter types
+ - Parameter iterators allow a 'type' or 'encoding' option to find the
+ next param of the same typ/enc. This allows a client to skip through
+ output params to find e.g. only FITS objects or only the stdout text
+ strings and means the callback can be tied to a parameter type easily.
diff --git a/vendor/voclient/voapps/task/Notes.tody b/vendor/voclient/voapps/task/Notes.tody
new file mode 100644
index 00000000..52b0d514
--- /dev/null
+++ b/vendor/voclient/voapps/task/Notes.tody
@@ -0,0 +1,164 @@
+VoClient Expanded Tasking Interface
+------------------------------------
+
+
+Current Interface
+--------------------------
+
+There is a single VOClient "VO" package consisting of a set of tasks
+implemented as library functions indexed as an "apps" array of function
+pointers. vo_runTask forks a subprocess to execute each task.
+Parameters are passed Unix-style as strings (argc,argv[]). A single
+result object is returned as a binary byte-counted blob.
+
+Client:
+ status = vo_runTask (method, apps[], argc, argv[], *len,
+**result)
+
+Task:
+ status = vo_setResultFromInt (value, *len, **data)
+ status = vo_setResultFromReal (value, *len, **data)
+ status = vo_setResultFromString (value, *len, **data)
+
+This is ok, a straightforward mapping of the original host CLI task
+interface into a programmatic API. However with a little more work we
+can generalize this to make the interface self-describing, allowing
+generic tasking code to be implemented (all the way up the client
+language layer eg Python) and allow new packages/tasks to be addded.
+
+
+Expanded Interface
+--------------------------
+
+This is an attempt to define the simplest possible interface which is still
+general enough to support the package/task paradigm, providing a self
+describing capability to allow generic/reusable software to be written to
+manipulate and run tasks. The main simplification is that a "package" is
+implemented as an executable (a single self contained file) which may
+contain multiple tasks and which can be queried to determine its
+capabilities. This limits "packages" to implementations which can be self
+contained enough to be runnable from a single runtime file, which is
+adequate for now to support the VOClient CLI tasks and which can be
+generalized later if necessary.
+
+A "package" is a precompiled executable with a defined API which can be
+queried with standard CLI arguments to get package metadata as well as to
+run the individual tasks. Metadata queries include user help as in
+"-help", plus programatic information such as the package name and
+description, list of tasks, task interfaces, builtin help, etc. "Package"
+executables are installed in a standard directory which can be examined by
+the tasking layer to determine what packages are available. The file names
+of package executables follow a simple naming convention so that they can
+be easily referenced at runtime.
+
+Client Interface:
+
+ xml = vo_pkgList () # Available packages
+ xml = vo_taskList (pkgName) # Tasks in package
+ xml = vo_taskParams (pkgName, taskName) # Input param set defs
+
+ tp = vo_taskInit (pkgName, taskName) # Prepare to run a task
+
+ vo_taskSetStringParam (tp, sval) # Set input parameters
+ vo_taskSetBoolParam (tp, sval)
+ vo_taskSetIntParam (tp, ival)
+ vo_taskSetRealParam (tp, dval)
+
+ vo_taskSetCallback (tp, &func) # Set callback for output param
+ rp = vo_taskExecuteSync (tp) # Execute synchronous; returns
+ # output pset pointer
+ vo_taskExecuteAsync (tp) # Execute async
+ rp = vo_taskWait (tp) # Wait for task, get RP
+ status = vo_taskCheckError (tp, *msg) # Check for any error posted
+ # to TP or RP
+
+ int = vo_taskOutputParamsCount (rp) # Access output params
+ vo_taskGetOutputParamInfo (rp, pnum, *name, *type, *encoding,
+ *description)
+
+ # pnum used if paramName=null
+ *void = vo_taskGetOutputParamValue (rp, paramName, pnum)
+*char = vo_taskGetStringOutputParam (rp, paramName, pnum)
+ ival = vo_taskGetBoolOutputParam (rp, paramName, pnum)
+ ival = vo_taskGetIntOutputParam (rp, paramName, pnum)
+ dval = vo_taskGetRealOutputParam (rp, paramName, pnum)
+
+ vo_taskClose (tp) # Free task resources
+
+Notes:
+ 1. vo_pkglist essentially just lists the valid package files in the
+ package directory. Simple since each package is a single file in
+ this scheme.
+ 2. vo_taskInit sets a task context and creates a default/empty param
+ list. The client sets the params it cares about. When the task
+ is executed the params are serialized in whatever way the tasking
+ layer wants to do it internally, e.g. argc/argv.
+ 3. Tasks can execute either sync or async. In async mode the client
+ may post a callback handler for output parameters. This is called
+ during task execution whenever any output parameter (of any name
+ or type) is set. We can have standard system params stdout (dump
+ text to stdout), status (running, done), warning (like stderr),
+ error (task aborted), etc. It is up to the task what parameters
+ to output. Custom parameters, normally of a standard type/encoding,
+ are used to return data.
+ 4. In sync task mode the client waits for completion and gets a
+ pointer to an output param set which it can walk to process the
+ output params. Output params can also be retrieved by name if the
+ client knows what params it expects back.
+ 5. The client should call vo_taskClose when done to free up task
+ resources such as output parameters. Otherwise they are retained
+ indefinitely.
+ 6. We should define standard values for the param TYPE and ENCODING
+ e.g., "bool", "int", "image", "fits", "votable", etc.), however
+ he task may return custom object types or encodings as well which
+ he client may or may not recognize.
+
+
+Task Interface: # Called by the task itself at runtime
+
+ tp = vo_taskStart ()
+ char *vo_taskGetPackageName (tp)
+ char *vo_taskGetTaskName (tp)
+ *char = vo_taskGetStringParam (tp, paramName)
+ ival = vo_taskGetBoolParam (tp, paramName)
+ ival = vo_taskGetIntParam (tp, paramName)
+ dval = vo_taskGetBoolParam (tp, paramName)
+
+ status = vo_setIntOutputParam (tp, paramName, ival)
+ status = vo_setRealOutputParam (tp, paramName, dval)
+ status = vo_setStringOutputParam (tp, paramName, sval)
+ status = vo_setOutputParam (tp, paramName, paramType, paramEncoding,
+ *len, **void)
+ tp = vo_taskEnd (tp)
+
+
+Notes:
+ 1. Task should call vo_taskStart initially to get a runtime context,
+ and vo_taskEnd when done to free resources, flush any output, and
+ so forth.
+ 2. When a task is run in a "connected" (remote) fashion it is passed
+ a keyword table of parameter values, via argc/argv or whatever.
+ True host level, CLI (argc/argv) mode can be provided as
+ well in which case all the -help etc. generics can be provided by
+ the task main (container).
+ Defaulting can be performed task-side if provided.
+ 3. Input parameters can be retrieved by name (do we need to walk a
+ list as well? probably not in this case).
+ 4. Output parameters are flushed through to the client in each
+ setOutputParam call, allowing interactive output at runtime. A
+ single output parameter may be set multiple times, e.g.,
+ for stdout, warning, status, etc. this could be normal. The
+ client tasking code accumulates output parameters in an output
+ param set during execution. Whether or not parameters are passed
+ on to a client callback is up to the client.
+
+Whether or not a task executes directly in the client process or in a
+separate process is transparent to the client; normally tasks will execute
+in a subprocess.
+
+The main limitation here is the assumption that a "package" is input to the
+system as a file. This is simple enough for C code where tasks are just
+functions linked into a single executable with a common main. In the
+simplest case there is no support for things like task dependencies.
+However the single file paradigm can be extended in the future should we
+need to do so.
diff --git a/vendor/voclient/voapps/task/_pkgbin b/vendor/voclient/voapps/task/_pkgbin
new file mode 100644
index 00000000..920b9086
--- /dev/null
+++ b/vendor/voclient/voapps/task/_pkgbin
@@ -0,0 +1,31 @@
+/**
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+
+int main (int argc, char *argv[])
+{
+
+ /* Process arguments.
+ */
+ for (i=1; i < argc; i++) {
+ switch (argv[i]) {
+ case 'h': // help
+ case 'd': // debug
+ case 'v': // verbose
+
+ case 'a': // package attributes
+ case 't': // package task list
+ case 'p': // task parameters ("-p <task>")
+
+ case 'S': // task parameters ("-p <task>")
+ default:
+ taskName = argv[i] // execute task ....
+ }
+ }
+
+
+}
diff --git a/vendor/voclient/voapps/task/mkpy b/vendor/voclient/voapps/task/mkpy
new file mode 100755
index 00000000..c8fd62c0
--- /dev/null
+++ b/vendor/voclient/voapps/task/mkpy
@@ -0,0 +1,5 @@
+#!/bin/csh -f
+
+set PKG = voPackage
+
+gcc -dynamiclib -I/usr/include/python2.6/ -lpython2.6 -o $PKG.so $PKG.c
diff --git a/vendor/voclient/voapps/task/pkgMain.c b/vendor/voclient/voapps/task/pkgMain.c
new file mode 100644
index 00000000..6b616f63
--- /dev/null
+++ b/vendor/voclient/voapps/task/pkgMain.c
@@ -0,0 +1,117 @@
+/**
+ * PKG_MAIN -- VOPackage task main().
+ *
+ * @file pkgMain.c
+ * @author Mike Fitzpatrick
+ * @date 12/13/12
+ *
+ * @brief VOPackage task main().
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include "votools.h" /* package task declarations */
+
+
+static int help = 0; /* help flag */
+static int debug = 0; /* debug flag */
+static int verbose = 0; /* verbose flag */
+static int interactive = 0; /* interactive */
+static int connected = 0; /* connected subprocess */
+static int detached = 0; /* detached subprocess */
+
+static int do_attrs = 0; /* print package attrs */
+static int do_taskList = 0; /* print task list */
+static int do_taskParams = 0; /* print package attrs */
+
+static char *taskName = NULL; /* name of task to execute */
+static char *cbsocket = NULL; /* callback socket */
+
+
+static void vopHelp(void);
+
+
+static char *opts = "hNno:r%:";
+static struct option long_opts[] = {
+ { "Number", 2, 0, 'N'}, /* task option */
+ { "number", 2, 0, 'n'}, /* task option */
+ { "output", 1, 0, 'o'}, /* task option */
+ { "return", 2, 0, 'r'}, /* task option */
+ { "help", 2, 0, 'h'}, /* required */
+ { "test", 1, 0, '%'}, /* required */
+ { NULL, 0, 0, 0 }
+};
+
+
+
+/**
+ * Application entry point.
+ */
+int main (int argc, char *argv[])
+{
+ char **pargv, optval[SZ_FNAME], ch;
+ int pos = 0;
+
+
+ /* Process arguments.
+ */
+ pargv = vo_paramInit (argc, argv);
+ while ((ch = vo_paramNext (opts,long_opts,argc,pargv,optval,&pos)) != 0) {
+ if (ch > 0) {
+ switch (ch) {
+ case 'h': vopHelp (); break;
+ case 'd': debug++; break;
+ case 'v': verbose++; break;
+
+ case 'a': /* package attributes */
+ do_attrs++;
+ break;
+ case 't': /* package task list */
+ do_taskList++;
+ break;
+ case 'p': /* task parameters ("-p <task>") */
+ do_taskParams++;
+ break;
+ case 'S': /* callback socket ("-S <sock>") */
+ cbsocket = strdup (optval);
+ break;
+ }
+ } else {
+ taskName = strdup (optval);/* execute task .... */
+ }
+ }
+
+ if (!cbsocket) {
+ cbsocket = (char *) calloc (1, SZ_FNAME);
+ sprintf (cbsocket, "/tmp/voPkg_%d", (int) getuid());
+ }
+
+ if (!connected && !detached) { /* run interactively */
+ interactive++;
+ } else if (connected) { /* run as a connected process */
+
+ } else if (detached) { /* run as a detached (bkg) process */
+ }
+
+
+ if (cbsocket)
+ free ((void *) cbsocket);
+ return (0);
+}
+
+
+/**
+ * VOPHELP -- Task help summary.
+ */
+static void
+vopHelp ()
+{
+ printf ("\n\
+ Usage: %s [-dhiv] [-a] | [-t] | [-p <task>] -S <cbsock> [<task>]]\n\
+ \n\
+ ", PKG_NAME);
+}
+
+
diff --git a/vendor/voclient/voapps/task/test.py b/vendor/voclient/voapps/task/test.py
new file mode 100644
index 00000000..0007da70
--- /dev/null
+++ b/vendor/voclient/voapps/task/test.py
@@ -0,0 +1,4 @@
+
+from voPackage import *
+
+print vop_taskList ("/tmp/test.vop")
diff --git a/vendor/voclient/voapps/task/vaopackage.py b/vendor/voclient/voapps/task/vaopackage.py
new file mode 100644
index 00000000..a894e612
--- /dev/null
+++ b/vendor/voclient/voapps/task/vaopackage.py
@@ -0,0 +1,453 @@
+"""
+The VAO Package and Tasking Interfaces.
+
+The tasking interface defines the python-side classes needed to manage and
+execute host processes that implement the "VAO Package" binary interface.
+These classes load the package (i.e. execute the binary as a connected
+processes and interogate it for a list of available tasks). The VOTask
+interface is used to set the input parameters, execute the task and process
+the result parameter set (PSet).
+
+The VOPSet interface manages a collection of VOParam parameter objects:
+input parameters will typically define options for the host task (e.g.
+input file, processing options, etc), while output parameters may contain
+arbitrary objects returned by the task (e.g. a FITS file or VOTable) or
+strings which make up the stdout/stderr streams of the task. A VOParam has
+attributes needed to describe the type of parameter, by selecting
+parameters of the same name from a PSet (e.g. 'msgs') an application can
+process multiple output objects as needed.
+
+A 'task' is a computational component which can be executed as a process by
+the host operating system (or a related environment such as a cluster).
+Tasks may be written in any language so long as the defined tasking
+interface is observed. The 'package' refered to here should not be
+confused with a Python package. A Python package is an element of Python,
+a 'package' as referred to here is a collection of tasks and their
+associated metadata.
+
+"""
+
+import sys
+import os
+import re
+import glob
+
+
+
+# Module Globals and Functions
+
+""" The Package search path.
+"""
+vopkg_path = ['.'] # always include the cwd
+vopkg_extn = ".vop"
+
+pkg_list = [] # scan package dirs to get list of packages
+pkg_struct = None # dictionary of package data in the form
+ # key = pkgname
+ # value = tuple(<path>, [<tasklist>])
+
+
+def setPkgDirs (dirs):
+ ''' Set the VO package search path as an absolute list of directories.
+ @param dirs list of directory to use as search path
+
+ Returns: Nothing
+ '''
+ vopkg_path = [.] + dirs
+
+
+def addPkgDir (dir):
+ ''' Append the given directory to the package search path.
+ @param dir the directory to add to the search path
+
+ Returns: Nothing
+ '''
+ vopkg_path.append(dir)
+
+
+def getPkgDirs ():
+ ''' Get the VO package search path as a list of directories.
+
+ Returns: Nothing
+ '''
+ return (vopkg_path)
+
+
+def pkgList (pattern=None):
+ ''' Get the list of available packages.
+ @param pattern the package name pattern to match
+
+ Returns: A list available package names.
+ '''
+
+ pat = pattern # construct the pattern string
+ if (pattern == None):
+ pat = "*"
+
+ pkg_list = [] # scan package dirs to get list of packages
+ for dir in vopkg_path:
+ if os.path.isdir(dir):
+ pfiles = glob.glob(dir + "/" + pat + vopkg_extn)
+ for f in pfiles:
+ root,ext = os.path.splitext(os.path.basename(f))
+ pkg_list.append(root)
+ pkg_struct[root] = [ f ]
+ else:
+ root,ext = os.path.splitext(os.path.basename(dir))
+ if (re.search(pattern,root)):
+ pkg_list.append(root)
+ pkg_struct[root] = [ dir ]
+
+ # Save just the package names as a valid list.
+ pkg_list = pkg_struct.keys()
+
+ # Scan the package list, to get a list of tasks in each package.
+ for pkg in pkg_list:
+ tlist = vop_taskList (pkg_struct[pkg][0]) # get task list
+ pkg_struct[pkg].append(tlist) # save in struct
+
+
+
+def scan ():
+ ''' Force a re-scan of the package search path for available package
+ files. Each directory in the path is searched for a ".vop" file
+ indicating a VO package executable, this file is then interrogated
+ for a list of tasks. This allows new package files to be installed
+ (or removed) as the module is running.
+
+ Returns: Nothing
+ '''
+ lst = pkgList ("*") # scan all packages
+
+
+def loadPackage (name, file=None):
+ ''' Load the package. Effectively all this does is create a VOPackage
+ object from the metadata for the named package, this requires
+ that we start the package binary to get the metadata information.
+ If a 'file' parameter is specified we open that file regardless of
+ the name, allowing any VOPackage file to be used dynamically.
+
+ When a package is loaded, bindings for each of the tasks are generated
+ automatically in order to allow direct access to the task. As an
+ example:
+
+ >>> vop = loadPackage ("vo-cli") # from search path
+ >>> results = vop.voregistry (searchTerm="quasar")
+ >>> printResultPset (results) # user-defined function
+
+ When developing a package or when an app needs to explicitly include
+ a new package, it may be accessed directly as:
+
+ >>> vop = loadPackage ("vo-cli",file="/path/devpkg.e")
+
+ @param name the package name
+ @param file the package binary file to execute
+
+ Returns: The loaded VOPackage object
+ '''
+ pass
+
+def taskList (pkg, pattern=None):
+ ''' List the tasks available in a package.
+ @param pkg the package name
+ @param pattern the task pattern name to match
+
+ Returns: A list of tasks available in the package who's name
+ matches the 'pattern' string.
+ '''
+ pass
+
+def pkgAttrs (pkg):
+ ''' Get the attributes for the named package, i.e. create a dictionary
+ of package metadata.
+ @param pkg the package name
+
+ Returns: A dictionary of the package attributes.
+ '''
+ pass
+
+def taskAttrs (pkg, task):
+ ''' Get the attributes for the named task in the package, i.e. create
+ a dictionary of task metadata.
+ @param pkg the package name
+ @param task the task name
+
+ Returns: A dictionary of the task attributes.
+ '''
+ pass
+
+
+class VOPackageError (Exception):
+ ''' A base class for VO Package errors. Use of this exception is TBD.
+ '''
+ pass
+
+
+class VOPackage:
+ ''' A class defining a VOPackage object. A VOPackage is a collection
+ of tasks as well as metadata about the package itself. The
+ functional part of the package is implemented in a binary file
+ executing as a connected process, task discovery and execution are
+ implemented as commands sent to the package binary, results are
+ returned over the IPC channel as a stream of parameter objects.
+ '''
+
+ # Class attributes
+ name = None # package name
+ descr = None # description string
+ author = None # package author
+ contact = None # contact email address
+ iconUrl = None # URL to package icon
+ version = None # package version string
+ dir = None # the directory containing the package
+ binfile = None # the name of the package binary
+
+ def __init__ (self, dirs):
+ pass
+
+ def __iter__ (self, dirs): # get next task in the package
+ pass
+
+ def taskList (self, pattern=None):
+ ''' Get the list of tasks in the package which match a pattern string.
+ If no pattern is specified, all tasks are returned.
+ @param pattern the parameter name to match
+
+ Returns: A list of available tasks who's name matches
+ the pattern string.
+ '''
+ pass
+
+ def pkgAttrs (self):
+ ''' Get the attributes for the VO Package as a dictionary string.
+
+ Returns: A dictionary of the package attributes
+ '''
+ pass
+
+
+class VOTaskError (Exception):
+ ''' A base class for Task execution errors.
+ '''
+ pass
+
+class VOTaskParameterError (VOTaskError):
+ ''' an exception indicating an error in the task calling parameters
+ '''
+ pass
+
+class VOTaskExecutionError (VOTaskError):
+ ''' an exception indicating an error when executing the task
+ '''
+ pass
+
+
+class VOTask:
+ ''' A class defining a VO Task object.
+ '''
+
+ name = None # task name
+ pkg = None # parent package name
+ descr = None # task description string
+ params = None # task input parameter set
+
+ status = None # task execution return status (OK or ERROR)
+ msg = None # task execution return error message
+
+
+ def __init__ (self, name, pkg, descr, params):
+ ''' create the VOTask instance
+ '''
+ pass
+
+ def taskAttrs (self):
+ ''' Get the attributes of the task as a dictionary.
+
+ Returns: A dictionary of the task attributes
+ '''
+ pass
+
+ def setParams (pset):
+ ''' Set the task parameter pset. Parameters in the pset argument
+ will be used set the values for the task parameter pset, i.e.
+ the argument pset can be just a subset of the task parameters,
+ we'll match the names and set the values for only those params.
+ If the argument pset contains a parameter not already in the
+ task input pset, it will be added as a new parameter.
+ @param pset parameter set to load
+
+ Returns: A dictionary of the task attributes
+ '''
+ pass
+
+ def getParams ():
+ ''' Set the task parameter pset.
+
+ Returns: The task parameter pset.
+ '''
+ pass
+
+ def setCallback (pattern, func):
+ ''' Set a callback function to be run whenever a parameter name
+ that matches the pattern is encountered. Pattern applies only
+ to the output parameter set.
+ @param pattern the parameter name to match
+ @param func the function to be called when parameter encountered
+
+ Returns: nothing
+ '''
+ pass
+
+ def executeSync (self):
+ ''' Execute the task as a synchronous process.
+ @throws VOTaskParameterError thrown when parameters are invalid
+ @throws VOTaskExecutionError thrown when there is an error is
+ executing a task, e.g. a segfault.
+
+ Returns: The result pset.
+ '''
+ pass
+
+ def executeASync (self):
+ ''' Execute the task as a asynchronous process.
+
+ Returns: Nothing
+ '''
+ pass
+
+ def wait (self):
+ ''' Wait for the exit of an asynchronous execution
+ @throws VOTaskParameterError thrown when parameters are invalid
+ @throws VOTaskExecutionError thrown when there is an error is
+ executing a task, e.g. a segfault.
+
+ Returns: The result pset.
+ '''
+ pass
+
+ def status (self):
+ ''' Get the status of an executing asynchronous task.
+
+ Returns: Task exec status ('Pending','Running','Done','Error')
+ '''
+ pass
+
+
+class VOPset:
+ ''' A class defining a PSet object.
+ '''
+
+ name = None # pset name
+ pkg = None # package name
+ task = None # task name associated with pset
+ description = None # pset description name
+
+ def __init__ (self, name, type, descr, encoding):
+ ''' create the VOPset instance
+ '''
+ pass
+
+ def loadPset (pkg=None, task=None, saveFile=None):
+ ''' Load the pset from the named task in the package. If 'saveFile'
+ is specified the pset is restored from that file.
+ @param pkg package name
+ @param task task name
+ @param saveFile name of the saved parameter file to load
+
+ Returns: The loaded PSet
+ '''
+ pass
+
+ def savePset (saveFile):
+ ''' Save the PSet to the named file. Serialization of the PSet is
+ TBD, probably some sort of simple XML schema.
+ @param saveFile name of the saved parameter file
+
+ Returns: Nothing
+ '''
+ pass
+
+ def paramSet (pattern=None):
+ ''' Create pset from params who's name matches the 'pattern' string.
+ If no pattern is specified, all parameters are returned.
+ @param pattern parameter pattern name to match
+
+ Returns: The constructed PSet
+ '''
+ pass
+
+ def paramList (pattern=None):
+ ''' Get list of params who's name matches the 'pattern' string. If
+ no pattern is specified, all parameters are returned.
+ @param pattern parameter pattern name to match
+
+ Returns: Nothing
+ '''
+ pass
+
+ def addParam (name, type, description, encoding=None):
+ ''' Add a new parameter with the specified attributes to the pset.
+ @param name name of the parameter to add
+ @param type parameter type value
+ @param descr parameter description string
+ @param encoding parameter encoding
+
+ Returns: The created parameter
+ '''
+ pass
+
+ def delParam (name):
+ ''' Delete the named parameter from the pset.
+ @param name name of the parameter to delete
+
+ Returns: Nothing
+ '''
+ pass
+
+ def getParam (name):
+ ''' Get the parameter with the given name.
+ @param name name of the parameter to retrieve
+
+ Returns: Requested parameter
+ '''
+ pass
+
+
+class VOParam:
+ ''' A class defining a Parameter object.
+ '''
+
+ name = None # parameter name
+ type = None # parameter type (string/int/real/bool/blob)
+ desc = None # parameter description string
+ encoding = None # encoding of param (i.e. mime type)
+
+
+ def __init__ (self, name, type, descr, encoding):
+ ''' create the VOParam instance
+ '''
+ pass
+
+ def paramAttrs ():
+ ''' Get the parameter attributes.
+
+ Returns: A dictionary of parameter attrbutes
+ '''
+ pass
+
+ def getValue ():
+ ''' Get the value of the parameter (may be a list)
+
+ Returns: The parameter's value
+ '''
+ pass
+
+ def setValue (val):
+ ''' Set the value of a parameter.
+ @param val the value of the paramter (arbitrary type)
+
+ Returns: Nothing
+ '''
+ pass
+
+
diff --git a/vendor/voclient/voapps/task/voPackage.c b/vendor/voclient/voapps/task/voPackage.c
new file mode 100644
index 00000000..2b53c575
--- /dev/null
+++ b/vendor/voclient/voapps/task/voPackage.c
@@ -0,0 +1,78 @@
+/**
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <Python.h>
+
+
+typedef struct {
+} voPackage;
+
+
+
+/**
+ * VOP_TASKLIST -- List the tasks in the named package.
+ */
+static PyObject*
+vop_taskList (PyObject* self, PyObject* args) /* pkg,pattern=None */
+{
+ const char *binpath;
+ int status;
+
+ if (!PyArg_ParseTuple (args, "s", &binpath))
+ return NULL;
+
+
+ sts = system(command);
+
+ return Py_BuildValue("s", args);
+}
+
+
+/**
+ * VOP_PKGLIST -- List the packages in the search directory.
+ */
+static PyObject*
+vop_pkgList (PyObject* self, PyObject* args) /* pattern=None */
+{
+ char *s = "Hello from vop_pkgList";
+ return Py_BuildValue("s", s);
+}
+
+static PyObject*
+vop_scan (PyObject* self, PyObject* args)
+{
+ char *s = "Hello from vop_scan";
+ return Py_BuildValue("s", s);
+}
+
+static PyObject*
+vop_loadPackage (PyObject* self, PyObject* args) /* name, file=None */
+{
+ char *s = "Hello from vop_loadPackage";
+ return Py_BuildValue("s", s);
+}
+
+/** ************************************************************************ */
+
+/*
+ * Bind Python function names to our C functions
+ */
+static PyMethodDef voPackage_methods[] = {
+ { "vop_taskList", vop_taskList, METH_VARARGS },
+ { "vop_pkgList", vop_pkgList, METH_VARARGS },
+ { "vop_scan", vop_scan, METH_VARARGS },
+ { "vop_loadPackage", vop_loadPackage, METH_VARARGS },
+ { NULL, NULL, 0 }
+};
+
+
+/**
+ * INITVOPACKAGE -- Python calls this to let us initialize our module
+ */
+void initvoPackage()
+{
+ (void) Py_InitModule("voPackage", voPackage_methods);
+}
diff --git a/vendor/voclient/voapps/task/voParam.c b/vendor/voclient/voapps/task/voParam.c
new file mode 100644
index 00000000..e5d108ee
--- /dev/null
+++ b/vendor/voclient/voapps/task/voParam.c
@@ -0,0 +1,418 @@
+/**
+ *
+ * VOTASK.C -- Utilities to run a VOApps task as a connected subprocess.
+ *
+ *
+ * Expanded Interface
+ * --------------------------
+ *
+ * This is an attempt to define the simplest possible interface which is still
+ * general enough to support the package/task paradigm, providing a self
+ * describing capability to allow generic/reusable software to be written to
+ * manipulate and run tasks. The main simplification is that a "package" is
+ * implemented as an executable (a single self contained file) which may
+ * contain multiple tasks and which can be queried to determine its
+ * capabilities. This limits "packages" to implementations which can be self
+ * contained enough to be runnable from a single runtime file, which is
+ * adequate for now to support the VOClient CLI tasks and which can be
+ * generalized later if necessary.
+ *
+ * A "package" is a precompiled executable with a defined API which can be
+ * queried with standard CLI arguments to get package metadata as well as to
+ * run the individual tasks. Metadata queries include user help as in
+ * "-help", plus programatic information such as the package name and
+ * description, list of tasks, task interfaces, builtin help, etc. "Package"
+ * executables are installed in a standard directory which can be examined by
+ * the tasking layer to determine what packages are available. The file names
+ * of package executables follow a simple naming convention so that they can
+ * be easily referenced at runtime.
+ *
+ *
+ * Client Interface:
+ * =================
+ *
+ * Parameter Handling:
+ * -------------------
+ *
+ * Directed parameter access:
+ *
+ * int = vo_taskParamCount (rp)
+ * vo_taskGetParamInfo (rp, pnum, *name, *type, *encoding,
+ * *description)
+ * str = vo_taskGetStringParam (rp, pname, pnum) # pnum used if pname=null
+ * ival = vo_taskGetBoolParam (rp, pname, pnum)
+ * ival = vo_taskGetIntParam (rp, pname, pnum)
+ * dval = vo_taskGetRealParam (rp, pname, pnum)
+ * void = vo_taskGetParamValue (rp, pname, pnum, size)
+ *
+ * Iterated parameter access:
+ *
+ * pp = vo_taskGetParam (rp, pname, pnum)
+ * len = vo_paramLen (pp, [typ|enc])
+ * pp = vo_paramNext (pp, [typ|enc])
+ * str = vo_paramAttr (pp, attr)
+ *
+ *
+ *
+ * @file voParam.c
+ * @author Mike Fitzpatrick
+ * @date 9/24/12
+ *
+ * @brief VOClient Tasking Interface.
+ */
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <setjmp.h>
+#include <sys/wait.h>
+#include <sys/stat.h>
+#include <sys/select.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include "voTask.h"
+
+
+
+
+/**************************************************************************/
+/*** Package Introspection Methods ***/
+/**************************************************************************/
+
+/**
+ * VO_PKGLIST -- List packages available in the working directory..
+ *
+ * @brief List packages available in the working directory.
+ * @fn xml = vo_pkgList (char *pattern)
+ *
+ * @param pattern Package executable filename pattern (or NULL for all)
+ * @returns XML description of the package list.
+ */
+char *
+vo_pkgList (char *pattern)
+{
+ return (NULL);
+}
+
+
+/**
+ * VO_TASKLIST -- List tasks in package.
+ *
+ * @brief List tasks in package.
+ * @fn handle = vo_taskList (char *pkgName)
+ *
+ * @param pkgName Package name
+ * @returns XML description of the task list
+ */
+char *
+vo_taskList (char *pkgName)
+{
+ return (NULL);
+}
+
+
+/**
+ * VO_TASKPARAMS -- List parameters for a task.
+ *
+ * @brief List parameters for a task.
+ * @fn xml = vo_taskParams (char *pkgName, char *taskName)
+ *
+ * @param pkgName Package name
+ * @param taskName Task name
+ * @returns XML description of the parameter list
+ */
+char *
+vo_taskParams (char *pkgName, char *taskName)
+{
+ return (NULL);
+}
+
+
+/**
+ * VO_SETPKGDIR -- Set the working package directory.
+ *
+ * @brief Set the working package directory.
+ * @fn vo_setPkgDir (char *path)
+ *
+ * @param path Path to current working package directory
+ * @returns nothing
+ */
+void
+vo_setPkgDir (char *path)
+{
+}
+
+
+/**
+ * VO_GETPKGDIR -- Get the working package directory.
+ *
+ * @brief Get the working package directory.
+ * @fn path = vo_getPkgDir (void)
+ *
+ * @returns path to current working package directory
+ */
+char *
+vo_getPkgDir (void)
+{
+ return (NULL);
+}
+
+
+
+/**************************************************************************/
+/*** Task Execution Methods ***/
+/**************************************************************************/
+
+/**
+ * VO_TASKINIT -- Prepare to run a task.
+ *
+ * @brief Prepare to run a task.
+ * @fn handle = vo_taskInit (char *pkgName, char *taskName)
+ *
+ * @param pkgName Package name
+ * @param taskName Task name
+ * @returns handle to the task descriptor
+ */
+handle_t
+vo_taskInit (char *pkgName, char *taskName)
+{
+ return (0);
+}
+
+
+/**
+ * VO_TASKSETSTRINGPARAM -- Set a string-valued param.
+ *
+ * @brief Set a string-valued param.
+ * @fn str = vo_taskSetStringParam (handle_t tp, char *paramName,
+ * char *sval)
+ *
+ * @param tp Task handle
+ * @param paramName Parameter name
+ * @param sval Parameter value
+ * @returns nothing
+ */
+void
+vo_taskSetStringParam (handle_t tp, char *paramName, char *sval)
+{
+}
+
+
+/**
+ * VO_TASKSETBOOLPARAM -- Set a bool-valued param.
+ *
+ * @brief Set a bool-valued param.
+ * @fn str = vo_taskSetBoolParam (handle_t tp, char *paramName, int bval)
+ *
+ * @param tp Task handle
+ * @param paramName Parameter name
+ * @param bval Parameter value (0=false, 1=true)
+ * @returns nothing
+ */
+void
+vo_taskSetBoolParam (handle_t tp, char *paramName, int bval)
+{
+}
+
+
+/**
+ * VO_TASKSETINTPARAM -- Set a int-valued param.
+ *
+ * @brief Set a int-valued param.
+ * @fn str = vo_taskSetIntParam (handle_t tp, char *paramName, int ival)
+ *
+ * @param tp Task handle
+ * @param paramName Parameter name
+ * @param ival Parameter value
+ * @returns nothing
+ */
+void
+vo_taskSetIntParam (handle_t tp, char *paramName, int ival)
+{
+}
+
+
+/**
+ * VO_TASKSETREALPARAM -- Set a real-valued param.
+ *
+ * @brief Set a real-valued param.
+ * @fn str = vo_taskSetRealParam (handle_t tp, char *paramName,
+ * double rval)
+ *
+ * @param tp Task handle
+ * @param paramName Parameter name
+ * @param dval Parameter value
+ * @returns nothing
+ */
+void
+vo_taskSetRealParam (handle_t tp, char *paramName, double dval)
+{
+}
+
+
+#ifdef FOO
+
+ vo_taskSetCallback (tp, &func) # Set output param callback
+ rp = vo_taskExecuteSync (tp) # Execute synchronous; returns
+ # output pset pointer
+ vo_taskExecuteAsync (tp) # Execute async
+ rp = vo_taskWait (tp) # Wait for task, get RP
+ tatus = vo_taskCheckError (tp, *msg) # Check for any error posted
+ # to TP or RP
+#endif
+
+
+
+/**************************************************************************/
+/*** Output Parameters ***/
+/**************************************************************************/
+
+/**
+ * VO_TASKPARAMCOUNT -- Return the number of available output params.
+ *
+ * @brief Return the number of available output params.
+ * @fn status = vo_taskParamCount (handle_t rp)
+ *
+ * @param rp Return handle
+ * @returns Number of available output params
+ */
+int
+vo_taskParamCount (handle_t rp)
+{
+ return (0);
+}
+
+
+/**
+ * VO_TASKGETPARAMINFO -- Get information about an indexed parameter.
+ *
+ * @brief Get information about an indexed parameter.
+ * @fn status = vo_taskGetParamInfo (handle_t rp, int pnum,
+ * char *name, char *type, char *encoding,
+ * char *description)
+ *
+ * @param rp Return handle
+ * @param pnum Parameter index (0-based, used if paramName=NULL)
+ * @param name Parameter name
+ * @returns pointer to parameter value
+ */
+void
+vo_taskGetParamInfo (handle_t rp, int pnum, char *name, char *type,
+ char *encoding, char *description)
+{
+ return;
+}
+
+
+/**
+ * VO_TASKGETPARAMVALUE -- Get a value of the named/indexed output parameter.
+ *
+ * @brief Get a value of the named/indexed output parameter.
+ * @fn status = vo_taskGetParamValue (handle_t rp, char *paramName,
+ * int pnum)
+ *
+ * @param rp Return handle
+ * @param paramName Parameter name
+ * @param pnum Parameter index (0-based, used if paramName=NULL)
+ * @returns pointer to parameter value
+ */
+void *
+vo_taskGetParamValue (handle_t rp, char *paramName, int pnum)
+{
+ return ((void *) NULL);
+}
+
+
+/**
+ * VO_TASKGETSTRINGPARAM -- Get a string-valued output parameter.
+ *
+ * @brief Get a string-valued output parameter.
+ * @fn str = vo_taskGetStringParam (handle_t rp, char *paramName,
+ * int pnum)
+ *
+ * @param rp Return handle
+ * @param paramName Parameter name
+ * @param pnum Parameter index (0-based, used if paramName=NULL)
+ * @returns parameter value as a character string
+ */
+char *
+vo_taskGetStringParam (handle_t rp, char *paramName, int pnum)
+{
+ return ((char *) NULL);
+}
+
+
+/**
+ * VO_TASKGETBOOLPARAM -- Get a bool-valued output parameter.
+ *
+ * @brief Get a bool-valued output parameter.
+ * @fn bval = vo_taskGetBoolParam (handle_t rp, char *paramName, int pnum)
+ *
+ * @param rp Return handle
+ * @param paramName Parameter name
+ * @param pnum Parameter index (0-based, used if paramName=NULL)
+ * @returns parameter value as a bool (0=false, 1=true)
+ */
+int
+vo_taskGetBoolParam (handle_t rp, char *paramName, int pnum)
+{
+ return (0);
+}
+
+
+/**
+ * VO_TASKGETINTPARAM -- Get a int-valued output parameter.
+ *
+ * @brief Get a int-valued output parameter.
+ * @fn ival = vo_taskGetIntParam (handle_t rp, char *paramName, int pnum)
+ *
+ * @param rp Return handle
+ * @param paramName Parameter name
+ * @param pnum Parameter index (0-based, used if paramName=NULL)
+ * @returns parameter value and an integer
+ */
+int
+vo_taskGetIntParam (handle_t rp, char *paramName, int pnum)
+{
+ return (0);
+}
+
+
+/**
+ * VO_TASKGETREALPARAM -- Get a real-valued output parameter.
+ *
+ * @brief Get a real-valued output parameter.
+ * @fn dval = vo_taskGetRealParam (handle_t rp, char *paramName, int pnum)
+ *
+ * @param rp Return handle
+ * @param paramName Parameter name
+ * @param pnum Parameter index (0-based, used if paramName=NULL)
+ * @returns parameter value as a double-precision
+ */
+double
+vo_taskGetRealParam (handle_t rp, char *paramName, int pnum)
+{
+ return ((double) 0.0);
+}
+
+
+/**
+ * VO_TASKCLOSE -- Free task resources.
+ *
+ * @brief Free task resources.
+ * @fn status = vo_taskClose (handle_t tp)
+ *
+ * @param tp Task handle
+ * @returns zero if OK, one on ERROR
+ */
+int
+vo_taskClose (handle_t tp)
+{
+ return (OK);
+}
diff --git a/vendor/voclient/voapps/task/voPkg.c b/vendor/voclient/voapps/task/voPkg.c
new file mode 100644
index 00000000..9442783b
--- /dev/null
+++ b/vendor/voclient/voapps/task/voPkg.c
@@ -0,0 +1,333 @@
+/**
+ *
+ * VOPKG.C -- Task and package management.
+ *
+ * This file provides the introspection methods for a callable package.
+ * These routines are used to call a package binary to get the metadata
+ * for packages, tasks and parameters.
+ *
+ *
+ * Package/Task Management:
+ * ------------------------
+ *
+ * vo_setPkgDir (path) # set package dir
+ * path = vo_getPkgDir () # get package dir
+ *
+ * pkg = vo_pkgList (pattern) # Get available packages
+ * len = vo_pkgLen (pkg)
+ * pkg = vo_pkgNext (pkg)
+ * str = vo_pkgAttr (pkg, attr)
+ *
+ * pp = vo_pkgParams (pkg)
+ * pp = vo_taskParams (pkgName, taskName) # Input param defs
+ * ( see parameter handling below )
+ *
+ * task = vo_taskList (taskName) # Get tasks in package
+ * len = vo_taskLen (task)
+ * str = vo_taskNext (task)
+ * task = vo_taskAttr (task, attr)
+ *
+ *
+ * xml = vo_pkgListXML (pattern) # XML serializations (opt)
+ * xml = vo_taskListXML (pkgName)
+ * xml = vo_paramListXML (pkgName, taskName)
+ *
+ *
+ * @file voPkg.c
+ * @author Mike Fitzpatrick
+ * @date 9/24/12
+ *
+ * @brief Package and task management methods
+ */
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <setjmp.h>
+#include <sys/wait.h>
+#include <sys/stat.h>
+#include <sys/select.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include "voTask.h"
+
+
+
+
+/**************************************************************************/
+/*** Package Introspection Methods ***/
+/**************************************************************************/
+
+
+/**
+ * VO_SETPKGDIR -- Set the working package directory.
+ *
+ * @brief Set the working package directory.
+ * @fn vo_setPkgDir (char *path)
+ *
+ * @param path Path to current working package directory
+ * @returns nothing
+ */
+void
+vo_setPkgDir (char *path)
+{
+}
+
+
+/**
+ * VO_GETPKGDIR -- Get the working package directory.
+ *
+ * @brief Get the working package directory.
+ * @fn path = vo_getPkgDir (void)
+ *
+ * @returns path to current working package directory
+ */
+char *
+vo_getPkgDir (void)
+{
+}
+
+
+/**************************************************************************/
+/*** Package Management ***/
+/**************************************************************************/
+
+/**
+ * VO_PKGLIST -- List packages available in the working directory..
+ *
+ * @brief List packages available in the working directory.
+ * @fn xml = vo_pkgList (char *pattern)
+ *
+ * @param pattern Package executable filename pattern (or NULL for all)
+ * @returns XML description of the package list.
+ */
+handle_t
+vo_pkgList (char *pattern)
+{
+ return (NULL);
+}
+
+
+/**
+ * VO_PKGLIST -- List packages available in the working directory..
+ *
+ * @brief List packages available in the working directory.
+ * @fn xml = vo_pkgList (char *pattern)
+ *
+ * @param pattern Package executable filename pattern (or NULL for all)
+ * @returns XML description of the package list.
+ */
+int
+vo_pkgLen (handle_t pkg)
+{
+ Package *pkgP = (Package *) task_H2P (pkg);
+
+ return ( (pkgP ? pkgP->npkgs : 0) );
+}
+
+
+/**
+ * VO_PKGNEXT -- Get the next package in the list.
+ *
+ * @brief Get the next package in the list.
+ * @fn pkg = vo_pkgNext (handle_t pkg)
+ *
+ * @param pkg Handle to package
+ * @returns Handle to next package in the list (0 at end of list)
+ */
+handle_t
+vo_pkgNext (handle_t pkg)
+{
+ Package *pkgP = (Package *) task_H2P (pkg);
+
+ return ( (pkgP ? task_P2H (pkgP->next) : 0) );
+}
+
+
+/**
+ * VO_PKGATTR -- Get a package metadata by attribute name.
+ *
+ * @brief Get a package metadata by attribute name.
+ * @fn pkg = vo_pkgAttr (handle_t pkg, char *attr)
+ *
+ * @param pattern Package executable filename pattern (or NULL for all)
+ * @returns Requested attribute string (or NULL if not found)
+ */
+char *
+vo_pkgAttr (handle_t pkg, char *attr)
+{
+ Package *pkgP = (Package *) task_H2P (pkg);
+
+ return (NULL);
+}
+
+
+/**************************************************************************/
+/*** Task Management ***/
+/**************************************************************************/
+
+/**
+ * VO_TASKLIST -- List tasks in package.
+ *
+ * @brief List tasks in package.
+ * @fn handle = vo_taskList (char *pkgName)
+ *
+ * @param pkgName Package name
+ * @returns XML description of the task list
+ */
+char *
+vo_taskList (char *pkgName)
+{
+ return (NULL);
+}
+
+
+/**
+ * VO_TASKLEN -- Get length of task list.
+ *
+ * @brief Get length of task list.
+ * @fn len = vo_taskLen (handle_t task)
+ *
+ * @param task Handle to task descriptor
+ * @returns Number of tasks in the list.
+ */
+int
+vo_taskLen (handle_t task)
+{
+ Package *taskP = (Package *) task_H2P (task);
+
+ return ( (taskP ? taskP->ntasks : 0) );
+}
+
+
+/**
+ * VO_TASKNEXT -- Get the next task in the list.
+ *
+ * @brief Get the next task in the list.
+ * @fn task = vo_taskNext (handle_t task)
+ *
+ * @param task Handle to task
+ * @returns Handle to next task in the list (0 at end of list)
+ */
+handle_t
+vo_taskNext (handle_t task)
+{
+ Package *taskP = (Package *) task_H2P (task);
+
+ return ( (taskP ? task_P2H (taskP->next) : 0) );
+}
+
+
+/**
+ * VO_TASKATTR -- Get a task metadata by attribute name.
+ *
+ * @brief Get a task metadata by attribute name.
+ * @fn task = vo_taskAttr (handle_t task, char *attr)
+ *
+ * @param task Handle to task
+ * @param attr Attribute to retrieve
+ * @returns Requested attribute string (or NULL if not found)
+ */
+char *
+vo_taskAttr (handle_t task, char *attr)
+{
+ Package *taskP = (Package *) task_H2P (task);
+
+ return (NULL);
+}
+
+
+
+/**************************************************************************/
+/*** Task and Package Parameters ***/
+/**************************************************************************/
+
+/**
+ * VO_PKGPARAMS -- List parameters for a package.
+ *
+ * @brief List parameters for a package.
+ * @fn xml = vo_pkgParams (handle_t pkg)
+ *
+ * @param pkg Package handle
+ * @returns XML description of the parameter list
+ */
+handle_t
+vo_pkgParams (handle_t pkg)
+{
+ return (0);
+}
+
+
+/**
+ * VO_TASKPARAMS -- List parameters for a task.
+ *
+ * @brief List parameters for a task.
+ * @fn xml = vo_taskParams (char *pkgName, char *taskName)
+ *
+ * @param pkgName Package name
+ * @param taskName Task name
+ * @returns XML description of the parameter list
+ */
+handle_t
+vo_taskParams (char *pkgName, char *taskName)
+{
+ return (0);
+}
+
+
+
+/**************************************************************************/
+/*** XML Serializations ***/
+/**************************************************************************/
+
+/**
+ * VO_PKGLISTXML -- Get the package list as an XML document.
+ *
+ * @brief Get the package list as an XML document.
+ * @fn xml = vo_pkgListXML (char *pattern)
+ *
+ * @param pattern Package executable pattern
+ * @returns XML description of the available packages.
+ */
+char *
+vo_pkgListXML (char *pattern)
+{
+}
+
+
+/**
+ * VO_TASKLISTXML -- Get the task list as an XML document.
+ *
+ * @brief Get the task list as an XML document.
+ * @fn xml = vo_taskListXML (char *pkgName)
+ *
+ * @param pkgName Package name
+ * @returns XML description of the tasks in a package.
+ */
+char *
+vo_taskListXML (char *pkgName)
+{
+}
+
+
+/**
+ * VO_PARAMLISTXML -- Get the task parameter list as an XML document.
+ *
+ * @brief Get the task parameter list as an XML document.
+ * @fn xml = vo_paramListXML (char *pkgName, char *taskName)
+ *
+ * @param pkgName Package name
+ * @param taskName Task name
+ * @returns XML description of the task parameters.
+ */
+char *
+vo_paramListXML (char *pkgName, char *taskName)
+{
+}
+
diff --git a/vendor/voclient/voapps/task/voTask.c b/vendor/voclient/voapps/task/voTask.c
new file mode 100644
index 00000000..01de7af1
--- /dev/null
+++ b/vendor/voclient/voapps/task/voTask.c
@@ -0,0 +1,258 @@
+/**
+ *
+ * VOTASK.C -- Utilities to run a VOApps task as a connected subprocess.
+ *
+ *
+ * Client Interface:
+ * =================
+ *
+ * Task Execution:
+ * ---------------
+ *
+ * tp = vo_taskInit (pkgName, taskName) # Initialize a task
+ *
+ * vo_taskSetStringParam (tp, pname, sval) # Set input params
+ * vo_taskSetBoolParam (tp, pname, bval)
+ * vo_taskSetIntParam (tp, pname, ival)
+ * vo_taskSetRealParam (tp, pname, dval)
+ * vo_taskSetPtrParam (tp, pname, ptr, size)
+ *
+ * vo_taskSetCallback (tp, type, &func) # Set param callback
+ * rp = vo_taskExecuteSync (tp, status, msg) # Execute sync
+ * vo_taskExecuteAsync (tp) # Execute async
+ * rp = vo_taskWait (tp) # Wait for task, get RP
+ * status = vo_taskCheckError (tp, msg) # Check for any error
+ *
+ * vo_taskClose (tp) # Free task resources
+ *
+ *
+ * @file voTask.c
+ * @author Mike Fitzpatrick & Doug Tody
+ * @date 9/24/12
+ *
+ * @brief VOClient Tasking Interface.
+ */
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <setjmp.h>
+#include <sys/wait.h>
+#include <sys/stat.h>
+#include <sys/select.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include "voTask.h"
+
+
+
+
+/**************************************************************************/
+/*** Task Execution Methods ***/
+/**************************************************************************/
+
+/**
+ * VO_TASKINIT -- Prepare to run a task.
+ *
+ * @brief Prepare to run a task.
+ * @fn handle = vo_taskInit (char *pkgName, char *taskName)
+ *
+ * @param pkgName Package name
+ * @param taskName Task name
+ * @returns handle to the task descriptor
+ */
+handle_t
+vo_taskInit (char *pkgName, char *taskName)
+{
+}
+
+
+/**
+ * VO_TASKSETSTRINGPARAM -- Set a string-valued param.
+ *
+ * @brief Set a string-valued param.
+ * @fn vo_taskSetStringParam (handle_t tp, char *paramName, char *sval)
+ *
+ * @param tp Task handle
+ * @param paramName Parameter name
+ * @param sval Parameter value
+ * @returns nothing
+ */
+void
+vo_taskSetStringParam (handle_t tp, char *paramName, char *sval)
+{
+}
+
+
+/**
+ * VO_TASKSETBOOLPARAM -- Set a bool-valued param.
+ *
+ * @brief Set a bool-valued param.
+ * @fn vo_taskSetBoolParam (handle_t tp, char *paramName, int bval)
+ *
+ * @param tp Task handle
+ * @param paramName Parameter name
+ * @param bval Parameter value (0=false, 1=true)
+ * @returns nothing
+ */
+void
+vo_taskSetBoolParam (handle_t tp, char *paramName, int bval)
+{
+}
+
+
+/**
+ * VO_TASKSETINTPARAM -- Set a int-valued param.
+ *
+ * @brief Set a int-valued param.
+ * @fn vo_taskSetIntParam (handle_t tp, char *paramName, int ival)
+ *
+ * @param tp Task handle
+ * @param paramName Parameter name
+ * @param ival Parameter value
+ * @returns nothing
+ */
+void
+vo_taskSetIntParam (handle_t tp, char *paramName, int ival)
+{
+}
+
+
+/**
+ * VO_TASKSETREALPARAM -- Set a real-valued param.
+ *
+ * @brief Set a real-valued param.
+ * @fn vo_taskSetRealParam (handle_t tp, char *paramName, double rval)
+ *
+ * @param tp Task handle
+ * @param paramName Parameter name
+ * @param dval Parameter value
+ * @returns nothing
+ */
+void
+vo_taskSetRealParam (handle_t tp, char *paramName, double dval)
+{
+}
+
+
+/**
+ * VO_TASKSETRAWPARAM -- Set a raw-valued param.
+ *
+ * @brief Set a raw-valued param.
+ * @fn vo_taskSetRawParam (handle_t tp, char *paramName, void *ptr,
+ * size_t size)
+ *
+ * @param tp Task handle
+ * @param paramName Parameter name
+ * @param ptr Pointer to raw data block
+ * @param size Size of data block
+ * @returns nothing
+ */
+void
+vo_taskSetRawParam (handle_t tp, char *paramName, void *ptr, size_t size)
+{
+}
+
+
+/**
+ * VO_TASKSETCALLBACK -- Set a callback for a parameter type.
+ *
+ * @brief Set a callback for a parameter type.
+ * @fn vo_taskSetCallback (handle_t tp, int type, void *func)
+ *
+ * @param tp Task handle
+ * @param type Parameter type
+ * @param func Callback function
+ */
+void
+vo_taskSetCallback (handle_t tp, int type, void *func)
+{
+}
+
+
+/**
+ * VO_TASKEXECUTESYNC -- Execute a task synchronously.
+ *
+ * @brief Execute a task synchronously.
+ * @fn rp = vo_taskExecuteSync (handle_t tp, int *status, char *msg)
+ *
+ * @param tp Task handle
+ * @param status Task exit status
+ * @param msg Buffer for returned error message string
+ * @returns Handle to output param list
+ */
+handle_t
+vo_taskExecuteSync (handle_t tp, int status, char *msg)
+{
+}
+
+
+/**
+ * VO_TASKEXECUTEASYNC -- Execute a task asynchronously.
+ *
+ * @brief Execute a task asynchronously.
+ * @fn rp = vo_taskExecuteAsync (handle_t tp)
+ *
+ * @param tp Task handle
+ * @returns Handle to output param list
+ */
+void
+vo_taskExecuteAsync (handle_t tp)
+{
+}
+
+
+/**
+ * VO_TASKWAIT -- Wait for an asynchronous task to complete.
+ *
+ * @brief Wait for an asynchronous task to complete.
+ * @fn rp = vo_taskWait (handle_t tp, int *status, char *msg)
+ *
+ * @param tp Task handle
+ * @param status Task exit status
+ * @param msg Buffer for returned error message string
+ * @returns Handle to output param list
+ */
+handle_t
+vo_taskWait (handle_t tp, int *status, char *msg)
+{
+}
+
+
+/**
+ * VO_TASKCHECKERROR -- Get the task exit status and (any) error message.
+ *
+ * @brief Get the task exit status and (any) error message.
+ * @fn status = vo_taskCheckError (handle_t tp, char *msg)
+ *
+ * @param tp Task handle
+ * @param msg Buffer for returned error message string
+ * @returns Task exit status
+ */
+int
+vo_taskCheckError (handle_t tp, char *msg)
+{
+}
+
+
+
+/**
+ * VO_TASKCLOSE -- Free task resources.
+ *
+ * @brief Free task resources.
+ * @fn status = vo_taskClose (handle_t tp)
+ *
+ * @param tp Task handle
+ * @returns zero if OK, one on ERROR
+ */
+int
+vo_taskClose (handle_t tp)
+{
+ return (OK);
+}
diff --git a/vendor/voclient/voapps/task/voTask.h b/vendor/voclient/voapps/task/voTask.h
new file mode 100644
index 00000000..6bedc35e
--- /dev/null
+++ b/vendor/voclient/voapps/task/voTask.h
@@ -0,0 +1,133 @@
+/**
+ * VOTASK.h -- Tasking interface declarations for the VOClient Package.
+ *
+ * @file voTask.h
+ * @author Mike Fitzpatrick
+ * @date 9/24/12
+ *
+ * @brief Tasking interface declarations for the VOClient Package.
+ */
+
+
+#include <stdio.h>
+#include <stdlib.h>
+
+
+typedef int handle_t;
+
+#ifdef OK
+#undef OK
+#endif
+#define OK 0
+
+#ifdef ERR
+#undef ERR
+#endif
+#define ERR 1
+
+#ifdef SZ_FORMAT
+#undef SZ_FORMAT
+#endif
+#define SZ_FORMAT 32
+
+#ifdef SZ_FNAME
+#undef SZ_FNAME
+#endif
+#define SZ_FNAME 256
+
+#ifdef SZ_LINE
+#undef SZ_LINE
+#endif
+#define SZ_LINE 4096
+
+
+#define MAX_TASKS 128
+
+
+/* Debug and verbose flags.
+ */
+#define VOTASK_DEBUG (getenv("VOTASK_DBG")||access("/tmp/VOTASK_DBG",F_OK)==0)
+#define VOTASK_VERB (getenv("VOTASK_VERB")||access("/tmp/VOTASK_VERB",F_OK)==0)
+
+/**
+ * Output parameter types.
+ */
+#define FORMATS "|int|rel|string|bool|raw|votable|xml|fits|html|"
+
+#define TY_INT 1 /* integer */
+#define TY_REAL 2 /* double-precision */
+#define TY_STRING 3 /* string */
+#define TY_BOOL 4 /* bool */
+#define TY_RAW 5 /* blob */
+
+#define TY_VOTABLE 6 /* A VOTable */
+#define TY_XML 7 /* A raw XML doc */
+#define TY_FITS 8 /* A FITS file */
+#define TY_HTML 9 /* A HTML doc */
+
+
+
+/* Parameter structure.
+ */
+typedef struct {
+ char name[SZ_FNAME]; /* parameter name */
+ char descr[SZ_FNAME]; /* parameter description */
+
+ int type; /* parameter type (int, etc) */
+ int encoding; /* parameter encoding */
+ int numValues; /* number of parameter values */
+
+ void *defaultValue; /* default value */
+ void *value; /* ptr to value */
+ size_t valueLen; /* size of value */
+
+ void *next; /* next linked-list param */
+} Param, *ParamP;
+
+typedef struct {
+ int nParams; /* number of params */
+ Param *param; /* parameter itself */
+} PSet, *PSetP;
+
+
+
+/* Task structure.
+ */
+typedef struct {
+ char name[SZ_FNAME]; /* package name */
+ char descr[SZ_FNAME]; /* package description */
+
+ Param *inParams; /* input params */
+ int nInParams; /* number of input params */
+ Param *outParams; /* output params */
+ int nOutParams; /* number of output params */
+
+ int status; /* task return status */
+ char *msg; /* task return err message */
+
+ int ntasks; /* number of tasks in list */
+ void *next; /* next linked-list task */
+} Task, *TaskP;
+
+
+
+/* Package structure.
+ */
+typedef struct {
+ char name[SZ_FNAME]; /* package name */
+ char descr[SZ_FNAME]; /* package description */
+ char author[SZ_FNAME]; /* package author */
+ char contact[SZ_FNAME]; /* package contact email */
+ char iconUrl[SZ_FNAME]; /* package icon URL */
+ char version[SZ_FNAME]; /* package version string */
+
+ Task tasks[MAX_TASKS]; /* task list */
+ int ntasks; /* number of tasks in package */
+ Param *params; /* package params */
+ int nparams; /* number of package params */
+
+ char cwd[SZ_FNAME]; /* current working directory */
+
+ int npkgs; /* number of packages in list */
+ void *next; /* next linked-list pkg */
+} Package, *PackageP;
diff --git a/vendor/voclient/voapps/task/voTaskMethod.c b/vendor/voclient/voapps/task/voTaskMethod.c
new file mode 100644
index 00000000..555d5c96
--- /dev/null
+++ b/vendor/voclient/voapps/task/voTaskMethod.c
@@ -0,0 +1,49 @@
+/**
+ *
+ *
+ * Task Interface: # Called by the task itself at runtime
+ *
+ * tp = vo_taskStart ()
+ * char *vo_taskGetPackageName (tp)
+ * char *vo_taskGetTaskName (tp)
+ * *char = vo_taskGetStringParam (tp, paramName)
+ * ival = vo_taskGetBoolParam (tp, paramName)
+ * ival = vo_taskGetIntParam (tp, paramName)
+ * dval = vo_taskGetBoolParam (tp, paramName)
+ *
+ * status = vo_setIntOutputParam (tp, paramName, ival)
+ * status = vo_setRealOutputParam (tp, paramName, dval)
+ * status = vo_setStringOutputParam (tp, paramName, sval)
+ * status = vo_setOutputParam (tp, paramName, paramType, paramEncoding,
+ * *len, **void)
+ * tp = vo_taskEnd (tp)
+ *
+ *
+ * Notes:
+ * 1. Task should call vo_taskStart initially to get a runtime context,
+ * and vo_taskEnd when done to free resources, flush any output, and
+ * so forth.
+ * 2. When a task is run in a "connected" (remote) fashion it is passed
+ * a keyword table of parameter values, via argc/argv or whatever.
+ * True host level, CLI (argc/argv) mode can be provided as
+ * well in which case all the -help etc. generics can be provided by
+ * the task main (container).
+ * Defaulting can be performed task-side if provided.
+ * 3. Input parameters can be retrieved by name (do we need to walk a
+ * list as well? probably not in this case).
+ * 4. Output parameters are flushed through to the client in each
+ * setOutputParam call, allowing interactive output at runtime. A
+ * single output parameter may be set multiple times, e.g.,
+ * for stdout, warning, status, etc. this could be normal. The
+ * client tasking code accumulates output parameters in an output
+ * param set during execution. Whether or not parameters are passed
+ * on to a client callback is up to the client.
+ *
+ * Whether or not a task executes directly in the client process or in a
+ * separate process is transparent to the client; normally tasks will execute
+ * in a subprocess.
+ *
+ */
+
+#include "voTask.h"
+
diff --git a/vendor/voclient/voapps/task/voTaskUtil.c b/vendor/voclient/voapps/task/voTaskUtil.c
new file mode 100644
index 00000000..0664da6e
--- /dev/null
+++ b/vendor/voclient/voapps/task/voTaskUtil.c
@@ -0,0 +1,133 @@
+/**
+ * VOTASKUTIL.C -- Utility methods to convert pointers to user handles.
+ *
+ * @brief Utility methods to convert pointers to user handles.
+ *
+ * @file voTaskUtil.c
+ * @author Mike Fitzpatrick
+ * @date 9/24/12
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include <time.h>
+#include <ctype.h>
+#include "voTask.h"
+
+
+#define MAX_HANDLES 128
+
+
+int numHandles = 0;
+long taskHandles[MAX_HANDLES];
+
+/* Public procedures
+*/
+handle_t task_P2H (void *ptr);
+void *task_H2P (handle_t handle);
+handle_t task_newHandle (void *ptr);
+void task_freeHandle (handle_t handle);
+
+
+
+/* Utility routines for keep track of handles.
+*/
+
+/**
+ * TASK_NEWHANDLE -- Get an unused object handle.
+ *
+ * @brief Get an unused object handle
+ * @fn handle_t task_newHandle (void *ptr)
+ *
+ * @param ptr pointer to object to be stored
+ * @return new object handle
+ */
+handle_t
+task_newHandle (void *ptr)
+{
+ /* Initialize the handle-to-ptr converter the first time we're called,
+ ** or whenever we've restarted.
+ */
+ if (numHandles == 0)
+ memset (taskHandles, 0, sizeof (taskHandles));
+ taskHandles[++numHandles] = (long) ptr;
+
+ return (numHandles);
+}
+
+
+/**
+ * TASK_FREEHANDLE -- Free the handle for later re-use.
+ *
+ * @brief Free the handle for later re-use.
+ * @fn task_freeHandle (handle_t handle)
+ *
+ * @param handle object handle
+ * @return nothing
+ */
+void
+task_freeHandle (handle_t handle)
+{
+ register int i, j;
+ void *ptr = task_H2P (handle);
+
+
+ if (handle <= 0) {
+ fprintf (stderr, "Error: Attempt to free zero handle!\n");
+ return;
+ }
+
+ for (i=1; i < MAX_HANDLES; i++) {
+ if ((void *) ptr == (void *) taskHandles[i]) {
+ for (j=i+1; j < MAX_HANDLES; j++) {
+ if (taskHandles[j])
+ taskHandles[i++] = taskHandles[j];
+ else
+ break;
+ }
+ numHandles = ((numHandles-1) >= 0 ? (numHandles-1) : 0);
+ break;
+ }
+ }
+}
+
+
+/**
+ * TASK_P2H -- Convert a pointer to a handle
+ *
+ * @brief Convert a pointer to a handle
+ * @fn handle_t task_P2H (void *ptr)
+ *
+ * @param ptr pointer to object
+ * @return handle to object, < 0 on error
+ */
+handle_t
+task_P2H (void *ptr)
+{
+ register int i;
+
+ for (i=1; i < MAX_HANDLES; i++) {
+ if ((void *) ptr == (void *) taskHandles[i])
+ return ((int) i);
+ }
+
+ return (-1);
+}
+
+
+/**
+ * TASK_H2P -- Convert a handle to a pointer
+ *
+ * @brief Convert a handle to a pointer
+ * @fn void *task_H2P (int handle)
+ *
+ * @param handle object handle
+ * @return pointer to object or NULL
+ */
+void *
+task_H2P (handle_t handle)
+{
+ return ((void *) taskHandles[handle]);
+}
diff --git a/vendor/voclient/voapps/task/votools.h b/vendor/voclient/voapps/task/votools.h
new file mode 100644
index 00000000..3e39ef8d
--- /dev/null
+++ b/vendor/voclient/voapps/task/votools.h
@@ -0,0 +1,79 @@
+/**
+ * VOTOOLS.H -- VOTools Package Declarations.
+ *
+ * @file votools.h
+ * @author Mike Fitzpatrick
+ * @date 12/13/12
+ *
+ * @brief VOTools Package Declarations.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+/* Run as a detached child process?
+*/
+#define RUN_DETACHED 0
+
+
+#define PKG_NAME "votools"
+
+#include "voApps.h"
+
+Task *app = (Task *) NULL;
+
+
+/* Task entry-point declarations.
+ */
+extern int vosamp (int argc, char **argv, size_t *len, void **result);
+
+extern int votcat (int argc, char **argv, size_t *len, void **result);
+extern int votcnv (int argc, char **argv, size_t *len, void **result);
+extern int votget (int argc, char **argv, size_t *len, void **result);
+extern int votinfo (int argc, char **argv, size_t *len, void **result);
+extern int votjoin (int argc, char **argv, size_t *len, void **result);
+extern int votpos (int argc, char **argv, size_t *len, void **result);
+extern int votsort (int argc, char **argv, size_t *len, void **result);
+extern int votsplit (int argc, char **argv, size_t *len, void **result);
+extern int votstat (int argc, char **argv, size_t *len, void **result);
+
+extern int vosesame (int argc, char **argv, size_t *len, void **result);
+
+extern int vodata (int argc, char **argv, size_t *len, void **result);
+extern int voatlas (int argc, char **argv, size_t *len, void **result);
+extern int voiminfo (int argc, char **argv, size_t *len, void **result);
+extern int vosloanspec (int argc, char **argv, size_t *len, void **result);
+
+extern int voregistry (int argc, char **argv, size_t *len, void **result);
+
+
+/* Task application table. Applications must be declared here to be found
+ * and used with the generic main().
+ */
+
+Task voApps[] = {
+ { "votcat", votcat }, /* VOTable apps */
+ { "votcnv", votcnv },
+ { "votget", votget },
+ { "votinfo", votinfo },
+ { "votjoin", votjoin },
+ { "votpos", votpos },
+ { "votsort", votsort },
+ { "votsplit", votsplit },
+ { "votstat", votstat },
+
+ { "vosamp", vosamp }, /* SAMP messaging */
+
+ { "vosesame", vosesame }, /* VO Name Resolution */
+
+ { "vodata", vodata }, /* VO Data access apps */
+ { "voatlas", voatlas },
+ { "voiminfo", voiminfo },
+ { "vosloanspec", vosloanspec },
+
+ { "voregistry", voregistry }, /* VO Registry apps */
+ { NULL, NULL }
+};
+
+
diff --git a/vendor/voclient/voapps/task/zz.c b/vendor/voclient/voapps/task/zz.c
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/vendor/voclient/voapps/task/zz.c
diff --git a/vendor/voclient/voapps/task/zz.py b/vendor/voclient/voapps/task/zz.py
new file mode 100644
index 00000000..81b61f80
--- /dev/null
+++ b/vendor/voclient/voapps/task/zz.py
@@ -0,0 +1,60 @@
+import sys
+import os
+import re
+import glob
+
+
+vopkg_path = ['.', "/tmp"]
+
+pkg_list = []
+pkg_struct = {}
+
+
+def pkgList (pattern=None):
+ ''' Get the list of available packages.
+ @param pattern the package name pattern to match
+
+ Returns: A list of available package names.
+ '''
+
+ pat = pattern
+ if (pattern == None):
+ pat = "*"
+
+ for dir in vopkg_path:
+ if os.path.isdir(dir):
+ pfiles = glob.glob(dir + "/" + pat + ".c")
+ print pfiles
+ for f in pfiles:
+ root,ext = os.path.splitext(os.path.basename(f))
+ pkg_struct[root] = [ f ]
+ print f
+ else:
+ root,ext = os.path.splitext(os.path.basename(dir))
+ if (re.search(pattern,root)):
+ pkg_struct[root] = [ dir ]
+ print dir
+
+ # Save just the package names as a valid list.
+ pkg_list = pkg_struct.keys()
+
+ print pkg_list
+ print pkg_struct
+
+
+print "vo*"
+pkgList("vo*")
+print " "
+
+print "z*"
+pkgList("z*")
+print " "
+
+print "None"
+pkgList()
+print " "
+
+print "zz"
+pkgList("zz")
+print " "
+
diff --git a/vendor/voclient/voapps/task/zztest.c b/vendor/voclient/voapps/task/zztest.c
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/vendor/voclient/voapps/task/zztest.c
diff --git a/vendor/voclient/voapps/test.xml b/vendor/voclient/voapps/test.xml
new file mode 100644
index 00000000..7acb2cd5
--- /dev/null
+++ b/vendor/voclient/voapps/test.xml
@@ -0,0 +1,137 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE VOTABLE SYSTEM "http://us-vo.org/xml/VOTable.dtd">
+<VOTABLE version="v1.1">
+<DEFINITIONS>
+ <COOSYS ID="myJ2000" system="eq_FK5" equinox="2000." epoch="2000."/>
+</DEFINITIONS>
+<RESOURCE type="results">
+ <DESCRIPTION>
+ Multimission Archive at STScI (MAST) archive.stsci.edu
+ send questions to: archive@stsci.edu
+ </DESCRIPTION>
+<INFO name="QUERY_STATUS" value="OK"></INFO>
+<PARAM ID="id" name="id" value=""></PARAM>
+<PARAM name="pos" value="202.468,47.1947" datatype="char" arraysize="*" unit="degrees">
+<DESCRIPTION>Search position in form ra,dec in decimal degrees</DESCRIPTION>
+</PARAM>
+<PARAM name="size" value="0.2" datatype="double" unit="degrees">
+<DESCRIPTION>Search diameter in decimal degrees</DESCRIPTION>
+</PARAM>
+<PARAM ID="max_records" name="max_records" value="2000"></PARAM>
+<PARAM ID="project" name="project" value="sgal"></PARAM>
+<PARAM ID="ra" name="ra" value="202.320834952 .. 202.615165048"></PARAM>
+<PARAM ID="dec" name="dec" value="47.0947 .. 47.2947"></PARAM>
+<PARAM ID="verb" name="verb" value="1"></PARAM>
+<PARAM ID="mission" name="mission" value="siap_keywords"></PARAM>
+<PARAM ID="found_rows" name="found_rows" value="20"></PARAM>
+<TABLE name="SIAP_KEYWORDS">
+<DESCRIPTION>MAST SIAP_KEYWORDS Search: 6 row(s) returned!</DESCRIPTION>
+<FIELD name="filename" datatype="char" ucd="VOX:Image_Title" arraysize="*" ><DESCRIPTION>For HST previews this column contains the dataset name. For HLSP, this column contains the actual filename.
+ </DESCRIPTION>
+</FIELD>
+<FIELD name="id" datatype="char" ucd="INST_ID" arraysize="*" ><DESCRIPTION>The instrument ID follows the convention: Archive.Satellite.Instrument
+ </DESCRIPTION>
+</FIELD>
+<FIELD name="ra_j2000" datatype="double" ucd="POS_EQ_RA_MAIN" unit="degrees" ref="myJ2000" ><DESCRIPTION>Should be center of image. May not match the Target RA in the FITS header of some HST observations.
+ </DESCRIPTION>
+</FIELD>
+<FIELD name="dec_j2000" datatype="double" ucd="POS_EQ_DEC_MAIN" unit="degrees" ref="myJ2000" ><DESCRIPTION>Should be center of image. May not match the Target Dec in the FITS header of some HST observations.
+ </DESCRIPTION>
+</FIELD>
+<FIELD name="url" datatype="char" ucd="VOX:Image_AccessReference" arraysize="*" ><DESCRIPTION>URL of image file
+ </DESCRIPTION>
+</FIELD>
+<FIELD name="filesize" datatype="int" ucd="VOX:Image_FileSize" unit="bytes" ><DESCRIPTION>File size in bytes
+ </DESCRIPTION>
+</FIELD>
+<FIELD name="mjdmean" datatype="double" ucd="VOX:Image_MJDateObs" unit="days" ><DESCRIPTION>Observation midpoint as Modifed Julian Date
+ </DESCRIPTION>
+</FIELD>
+<FIELD name="naxes" datatype="int" ucd="VOX:Image_Naxes" ><DESCRIPTION>Number of axes
+ </DESCRIPTION>
+</FIELD>
+<FIELD name="naxis" datatype="int" ucd="VOX:Image_Naxis" unit="pixels" arraysize="*" ><DESCRIPTION>image size in pixels
+ </DESCRIPTION>
+</FIELD>
+<FIELD name="scale" datatype="double" ucd="VOX:Image_Scale" unit="degrees/pixel" arraysize="*" ><DESCRIPTION>Image scale in deg/pixel for each axis (as a concatenated string)
+ </DESCRIPTION>
+</FIELD>
+<FIELD name="cd" datatype="double" ucd="VOX:WCS_CDMatrix" unit="degrees/pixel" arraysize="*" ><DESCRIPTION>CD matrix (values concatenated into a single character field)
+ </DESCRIPTION>
+</FIELD>
+<FIELD name="format" datatype="char" ucd="VOX:Image_Format" arraysize="*" ><DESCRIPTION>Mime type of file
+ </DESCRIPTION>
+</FIELD>
+<FIELD name="ref_frame" datatype="char" ucd="VOX:STC_CoordRefFrame" arraysize="*" ><DESCRIPTION>coordinate system reference frame
+ </DESCRIPTION>
+</FIELD>
+<FIELD name="equinox" datatype="float" ucd="VOX:STC_CoordEquinox" unit="years" ><DESCRIPTION>Equinox
+ </DESCRIPTION>
+</FIELD>
+<FIELD name="coord_projection" datatype="char" ucd="VOX:WCS_CoordProjection" arraysize="3" ><DESCRIPTION>celestial projection used
+ </DESCRIPTION>
+</FIELD>
+<FIELD name="crpix" datatype="double" ucd="VOX:WCS_CoordRefPixel" unit="pixels" arraysize="*" ><DESCRIPTION>image coordinates of WCS reference pixel (crpix)
+ </DESCRIPTION>
+</FIELD>
+<FIELD name="crval" datatype="double" ucd="VOX:WCS_CoordRefValue" unit="pixels" arraysize="*" ><DESCRIPTION>world coordinates of WCS reference pixel (crval)
+ </DESCRIPTION>
+</FIELD>
+<FIELD name="ctype" datatype="char" ucd="ID_FIELD" arraysize="*" ><DESCRIPTION>Axes labels (ctype)
+ </DESCRIPTION>
+</FIELD>
+<FIELD name="bandpass_id" datatype="char" ucd="VOX:BandPass_ID" arraysize="*" ><DESCRIPTION>Filter Designation
+ </DESCRIPTION>
+</FIELD>
+<FIELD name="bandpass_refvalue" datatype="double" ucd="VOX:BandPass_RefValue" unit="meters" ><DESCRIPTION>approximate central wavelength or frequency
+ </DESCRIPTION>
+</FIELD>
+<FIELD name="bandpass_unit" datatype="char" ucd="VOX:BandPass_Unit" unit="meters" arraysize="*" ><DESCRIPTION>VLAFIRST uses frequencies (hertz), other missions use wavelengths (meters)
+ </DESCRIPTION>
+</FIELD>
+<FIELD name="bandpass_hilimit" datatype="double" ucd="VOX:BandPass_HiLimit" unit="meters" ><DESCRIPTION>bandpass upper limit
+ </DESCRIPTION>
+</FIELD>
+<FIELD name="bandpass_lolimit" datatype="double" ucd="VOX:BandPass_LoLimit" unit="meters" ><DESCRIPTION>bandpass lower limit
+ </DESCRIPTION>
+</FIELD>
+<FIELD name="processing" datatype="char" ucd="VOX:Image_PixFlags" arraysize="*" ><DESCRIPTION>level of processing
+ </DESCRIPTION>
+</FIELD>
+<FIELD name="project" datatype="char" ucd="ID_GROUP" arraysize="*" ><DESCRIPTION>hlsp indicator
+ </DESCRIPTION>
+</FIELD>
+<FIELD name="preview" datatype="char" ucd="ID_GROUP" arraysize="*" ><DESCRIPTION>indicates a preview is available
+ </DESCRIPTION>
+</FIELD>
+<FIELD name="representative" datatype="char" ucd="ID_GROUP" arraysize="*" ><DESCRIPTION>indicates a scrapbook selection
+ </DESCRIPTION>
+</FIELD>
+<FIELD name="object_id" datatype="char" ucd="ID_TARGET" arraysize="*" ><DESCRIPTION>Target name
+ </DESCRIPTION>
+</FIELD>
+<DATA>
+<TABLEDATA>
+<TR>
+<TD>dpix1.fits</TD><TD>MAST.HST.WFPC2</TD><TD>202.504583333</TD><TD>47.22861</TD><TD><![CDATA[http://iraf.noao.edu/votest/dpix1.fits]]></TD><TD>16777216</TD><TD></TD><TD>2</TD><TD>512 512</TD><TD>-9.929466E-7 9.871683E-7</TD><TD>-9.929466E-7 1.379957E-5 1.378579E-5 9.871683E-7</TD><TD>image/fits</TD><TD>FK4</TD><TD>2000.000</TD><TD>TAN</TD><TD>1069.018 1065.018</TD><TD>202.5111118072 47.24408628</TD><TD>RA---TAN DEC--TAN</TD><TD>F814W</TD><TD>8.002e-7</TD><TD>meters</TD><TD>8.326e-7</TD><TD>7.677e-7</TD><TD>Z</TD><TD>sgal</TD><TD></TD><TD>n</TD><TD>M51-ULX2</TD>
+</TR>
+<TR>
+<TD>dpix2.fits</TD><TD>MAST.HST.WFPC2</TD><TD>202.504583333</TD><TD>47.22861</TD><TD><![CDATA[http://iraf.noao.edu/votest/dpix2.fits]]></TD><TD>16777216</TD><TD></TD><TD>2</TD><TD>512 512</TD><TD>6.303785E-6 -6.301675E-6</TD><TD>6.303785E-6 4.861660E-7 4.971642E-7 -6.301675E-6</TD><TD>image/fits</TD><TD>FK4</TD><TD>2000.000</TD><TD>TAN</TD><TD>1063.037 1072.028</TD><TD>202.5045833333 47.22861111111</TD><TD>RA---TAN DEC--TAN</TD><TD>F555W</TD><TD>5.443e-7</TD><TD>meters</TD><TD>5.704e-7</TD><TD>5.182e-7</TD><TD>Z</TD><TD>sgal</TD><TD></TD><TD>n</TD><TD>M51-ULX2</TD>
+</TR>
+<TR>
+<TD>dpix3.fits</TD><TD>MAST.HST.WFPC2</TD><TD>202.504583333</TD><TD>47.22861</TD><TD><![CDATA[http://iraf.noao.edu/votest/dpix3.fits]]></TD><TD>16777216</TD><TD></TD><TD>2</TD><TD>512 512</TD><TD>6.302246E-6 -6.300137E-6</TD><TD>6.302246E-6 4.860486E-7 4.970415E-7 -6.300137E-6</TD><TD>image/fits</TD><TD>FK4</TD><TD>2000.000</TD><TD>TAN</TD><TD>1063.047 1072.041</TD><TD>202.5045833333 47.22861111111</TD><TD>RA---TAN DEC--TAN</TD><TD>F814W</TD><TD>7.996e-7</TD><TD>meters</TD><TD>8.319e-7</TD><TD>7.673e-7</TD><TD>Z</TD><TD>sgal</TD><TD></TD><TD>n</TD><TD>M51-ULX2</TD>
+</TR>
+<TR>
+<TD>dpix4.fits</TD><TD>MAST.HST.WFPC2</TD><TD>202.504583333</TD><TD>47.22861</TD><TD><![CDATA[http://iraf.noao.edu/votest/dpix4.fits]]></TD><TD>16777216</TD><TD></TD><TD>2</TD><TD>512 512</TD><TD>-1.377966E-5 1.376732E-5</TD><TD>-1.377966E-5 -1.125826E-6 -1.133609E-6 1.376732E-5</TD><TD>image/fits</TD><TD>FK4</TD><TD>2000.000</TD><TD>TAN</TD><TD>1095.02 1072.024</TD><TD>202.479449437 47.24240418885</TD><TD>RA---TAN DEC--TAN</TD><TD>F814W</TD><TD>8.012e-7</TD><TD>meters</TD><TD>8.339e-7</TD><TD>7.685e-7</TD><TD>Z</TD><TD>sgal</TD><TD></TD><TD>n</TD><TD>M51-ULX2</TD>
+</TR>
+<TR>
+<TD>dpix5.fits</TD><TD>MAST.HST.WFPC2</TD><TD>202.504583333</TD><TD>47.22861</TD><TD><![CDATA[http://iraf.noao.edu/votest/dpix5.fits]]></TD><TD>16777216</TD><TD></TD><TD>2</TD><TD>512 512</TD><TD>1.206699E-6 -1.201142E-6</TD><TD>1.206699E-6 -1.377713E-5 -1.376330E-5 -1.201142E-6</TD><TD>image/fits</TD><TD>FK4</TD><TD>2000.000</TD><TD>TAN</TD><TD>1070.015 1051.016</TD><TD>202.482657254 47.22173504583</TD><TD>RA---TAN DEC--TAN</TD><TD>F814W</TD><TD>7.983e-7</TD><TD>meters</TD><TD>8.303e-7</TD><TD>7.664e-7</TD><TD>Z</TD><TD>sgal</TD><TD></TD><TD>n</TD><TD>M51-ULX2</TD>
+</TR>
+<TR>
+<TD>dpix6.fits</TD><TD>MAST.HST.WFPC2</TD><TD>202.504583333</TD><TD>47.22861</TD><TD><![CDATA[http://iraf.noao.edu/votest/dpix6.fits]]></TD><TD>67108864</TD><TD></TD><TD>2</TD><TD>4096 4096</TD><TD>-1.376853E-5 1.376211E-5</TD><TD>-1.376853E-5 -1.112365E-6 -1.136848E-6 1.376211E-5</TD><TD>image/fits</TD><TD>FK4</TD><TD>2000.000</TD><TD>TAN</TD><TD>1772.441 1803.596</TD><TD>202.5045833333 47.22861111111</TD><TD>RA---TAN DEC--TAN</TD><TD>F814W</TD><TD>7.996e-7</TD><TD>meters</TD><TD>8.319e-7</TD><TD>7.673e-7</TD><TD>Z</TD><TD>sgal</TD><TD></TD><TD>n</TD><TD>M51-ULX2</TD>
+</TR>
+</TABLEDATA>
+</DATA>
+</TABLE>
+</RESOURCE>
+</VOTABLE>
diff --git a/vendor/voclient/voapps/test/_tasks b/vendor/voclient/voapps/test/_tasks
new file mode 100644
index 00000000..0e779b26
--- /dev/null
+++ b/vendor/voclient/voapps/test/_tasks
@@ -0,0 +1,17 @@
+voatlas
+vocatalog
+vodata
+voimage
+voiminfo
+voregistry
+vosamp
+vosesame
+vosloanspec
+vospectra
+votcnv
+votget
+votinfo
+votopic
+votpos
+votsort
+votstat
diff --git a/vendor/voclient/voapps/test/_tests b/vendor/voclient/voapps/test/_tests
new file mode 100644
index 00000000..9f169eb6
--- /dev/null
+++ b/vendor/voclient/voapps/test/_tests
@@ -0,0 +1,167 @@
+# voatlas -- done
+ voatlas -S m83 or
+ voatlas --samp m83
+
+ voatlas -o gal.jpg -n 256 --graphic sombrero
+ voatlas -s 20m --survey=wise22 m101
+ voatlas --band=radio 3c273
+ voatlas --survey=list -v ngc1234
+
+# vocatalog -- done
+ vocatalog gsc2.3 ngc1234 (a)
+ vocatalog gsc2.3 pos.txt (b)
+ vocatalog gsc2.3 m31,m51,m93 (c)
+ vocatalog svcs.txt pos.txt (d)
+ vocatalog hst,chandra,gsc2.3 pos.txt (e)
+ vocatalog -count -b x-ray any abell2712\n\
+
+# vodata -- done, need to verify results
+ vodata gsc2.3 ngc1234 (a)
+ vodata gsc2.3 pos.txt (b)
+ vodata gsc2.3 m31,m51,m93 (c)
+ vodata svcs.txt pos.txt (d)
+ vodata hst,chandra,gsc2.3 pos.txt (e)
+
+ vodata -c -t image any IC10
+ vodata --count --type=image any IC10
+ vodata -c -t catalog -b x-ray any abell2712
+ vodata --count --type=catalog --bandpass=x-ray any abell2712
+
+ vodata --meta rc3 or vodata -m rc3
+
+ voregistry cooling flow
+ vodata -O white97 -all J/MNRAS/292/419
+ vodata --output=white97 --all J/MNRAS/292/419
+
+ voregistry -rv -t image xmm
+ vodata -cq xmm-newton 3c273
+ vodata --count --quiet xmm-newton 3c273
+ vodata --get xmm-newton 3c273
+
+ vodata -e -O 2mass -t image 2mass 12:34:56.7 -23:12:45.2
+ vodata -e --output=2mass --type=image 2mass 12:34:56.7 -23:12:45.2
+ grep fits 2mass_I_001_15998.urls > images.txt
+ vodata images.txt
+ grep fits 2mass_I_001_15998.urls | vodata -i -
+
+ vodata -t image -s http://localhost/siap.pl 180.0 0.0
+ vodata --type=image --svc=http://localhost/siap.pl 180.0 0.0
+
+ voregistry -v -v --type=catalog abell | less
+ vodata -e ivo://nasa.heasarc/abell 0.0 0.0 180.0
+ vodata --extract ivo://nasa.heasarc/abell 0.0 0.0 180.0
+
+ cut -c6- *.pos | vodata ivo://nasa.heasarc/chanmaster -p -
+ cut -c6- *.pos | vodata ivo://nasa.heasarc/chanmaster --pos=-
+ vodata -cq chandra -i -
+ stilts tpipe ifmt=votable qso_survey.vot \
+
+ wcsinfo *.fits | vodata 2mass-psc -i -
+ wcsinfo -pos_only *.fits > centers.txt
+ vodata --sr=25m 2mass-psc centers.txt
+
+ cat cmds.txt
+ vodata -i cmds.txt
+
+ vodata -a galex M51
+ vodata --all galex M51
+
+ vodata gsc2.3 positions.txt
+ vodata --cols=2,3,1 --hskip=5 gsc2.3 positions.txt
+
+# voimage -- done
+ voimage -b x-ray any m51
+ voimage -c HSTAEC IC10
+
+# voiminfo -- done
+ votiminfo -n mef.fits
+ voiminfo -b -s image.fits
+ voiminfo -c image.fits\n"
+ voiminfo -b -f pos.txt mef.fits\n"
+
+# voregistry -- done, need to verify results
+ voregistry -count -t image
+ voregistry -rv -t image
+ voregistry -t catalog radio galaxies
+ voregistry -list GSC2.2
+ voregistry -b radio abell
+ voregistry -rvv -n 1 J/A+A/446/97/tab
+ voregistry -v -t image wfpc
+ voregistry -cv keck
+ voregistry -c chandra hst spitzer
+ voregistry -co chandra hst spitzer
+ voregistry -meta gsc2.2
+ voregistry "Facility like 'HST'"
+ voregistry "Title like '%Keck%'"
+ cat query.txt
+ cat query.txt | voregistry
+ voregistry --new 3m
+ voregistry --new 3m cool stars
+ voregistry --updated 12m --count
+
+# vosamp -- done
+ vosamp load /path/example.xml
+ vosamp load http://foo.edu/example.xml
+ vosamp load http://foo.edu/query?RA=0.0&DEC=0.0&SR=0.1
+ vosamp -t iraf exec "display dev$pix 1"
+ vosamp list
+
+# vosesame -- done
+ vosesame ngc4456
+ vosesame -s ngc4456
+ vosesame -st m31 m51 m99
+ vosesame -CHndt myobjs.txt
+ cut -c17-25 data.txt | vosesame -ns
+ vosesame -a
+ vosesame -sd -c 12:30:0.0 -45:00:0.0 -c 187.5 2.05
+
+# vosloanspec -- done, service is unreliable though
+ vosloanspec -s 0.1 -t galaxy 'Hubble Deep Field'
+ vosloanspec --size=0.1 --type=galaxy 'Hubble Deep Field'
+ vosloanspec -m -d m51
+ vosloanspec --meta --delete m51
+ vosloanspec -l 5 --samp 3c273 # as a spectrum msg
+ vosloanspec -l 5 --samp --table 3c273 # as a table msg
+ vosloanspec --redshift=0.3-1.0
+
+# vospectra -- done, need more examples
+ vospectra any 3c273
+
+# votcnv -- done
+ votcnv --fmt=csv test.xml
+ votcnv -f vot -i 2 test.xml
+ votcnv -f vot -i 0 test.xml
+
+# votget -- done
+ votget -N 3 results.xml
+ votget -b foo -e fits -S
+ votget -b foo urls.txt
+ votget -x results.xml
+
+# votinfo -- done
+ votinfo -v test.xml
+ votinfo -p test.xml
+ votinfo --numberOf=param test.xml
+ votinfo -q test.xml
+
+# votopic -- done, needs more examples
+ votopic -t catalog lens A2712
+ voregistry -t catalog -d -o lens.xml lens
+ vodata lens.xml A2712
+
+# votpos -- done
+ votpos test.xml
+ votpos -n test.xml
+ cat test.xml | votpos
+ votpos -o pos.txt test.xml
+
+# votsort -- done
+ votsort test.xml
+ votsort http://generic.edu/test.xml
+ cat test.xml | votsort -o sort_test.xml
+ votsort --name=V test.xml
+ votsort --name=V --desc --top=10 test.xml
+ votsort -s -f csv test.xml
+ votsort --string --fmt=csv test.xml
+ votstat test.xml
+ votsort -a -o stats test.xml
diff --git a/vendor/voclient/voapps/test/gal.jpg b/vendor/voclient/voapps/test/gal.jpg
new file mode 100644
index 00000000..1e769c79
--- /dev/null
+++ b/vendor/voclient/voapps/test/gal.jpg
Binary files differ
diff --git a/vendor/voclient/voapps/test/test.voatlas b/vendor/voclient/voapps/test/test.voatlas
new file mode 100755
index 00000000..16601464
--- /dev/null
+++ b/vendor/voclient/voapps/test/test.voatlas
@@ -0,0 +1,10 @@
+#!/bin/csh -fx
+
+ voatlas -S m83
+ voatlas --samp m83
+
+ voatlas -o gal.jpg -n 256 --graphic sombrero
+ voatlas -s 20m --survey=wise22 m101
+ voatlas --band=radio 3c273
+ voatlas --survey=list -v ngc1234
+
diff --git a/vendor/voclient/voapps/voApps.c b/vendor/voclient/voapps/voApps.c
new file mode 100644
index 00000000..b48d974f
--- /dev/null
+++ b/vendor/voclient/voapps/voApps.c
@@ -0,0 +1,137 @@
+/**
+ * VOAPPS.C -- Generic task main() for the VOClient Package applications.
+ *
+ * @file voApps.c
+ * @author Mike Fitzpatrick
+ * @date 6/03/11
+ *
+ * @brief Generic task main() for the VOClient Package applications.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+/* Run as a detached child process?
+*/
+#define RUN_DETACHED 0
+
+
+#include "voApps.h"
+
+Task *app = (Task *) NULL;
+
+
+/* Task entry-point declarations.
+ */
+extern int vosamp (int argc, char **argv, size_t *len, void **result);
+
+/*** NOT YET IMPLEMENTED ***
+extern int votcat (int argc, char **argv, size_t *len, void **result);
+extern int votjoin (int argc, char **argv, size_t *len, void **result);
+extern int votselect (int argc, char **argv, size_t *len, void **result);
+extern int votsplit (int argc, char **argv, size_t *len, void **result);
+****/
+extern int votcnv (int argc, char **argv, size_t *len, void **result);
+extern int votget (int argc, char **argv, size_t *len, void **result);
+extern int votinfo (int argc, char **argv, size_t *len, void **result);
+extern int votpos (int argc, char **argv, size_t *len, void **result);
+extern int votsort (int argc, char **argv, size_t *len, void **result);
+extern int votstat (int argc, char **argv, size_t *len, void **result);
+
+extern int vosesame (int argc, char **argv, size_t *len, void **result);
+
+extern int voatlas (int argc, char **argv, size_t *len, void **result);
+extern int vocatalog (int argc, char **argv, size_t *len, void **result);
+extern int vodata (int argc, char **argv, size_t *len, void **result);
+extern int voimage (int argc, char **argv, size_t *len, void **result);
+extern int voiminfo (int argc, char **argv, size_t *len, void **result);
+extern int vospectra (int argc, char **argv, size_t *len, void **result);
+extern int votopic (int argc, char **argv, size_t *len, void **result);
+
+extern int voregistry (int argc, char **argv, size_t *len, void **result);
+
+
+/* Task application table. Applications must be declared here to be found
+ * and used with the generic main().
+ */
+
+Task voApps[] = {
+ /*** NOT YET IMPLEMENTED ****
+ { "votcat", votcat },
+ { "votjoin", votjoin },
+ { "votselect", votselect },
+ { "votsplit", votsplit },
+ ****/
+
+ { "votcnv", votcnv }, /* VOTable apps */
+ { "votget", votget },
+ { "votinfo", votinfo },
+ { "votpos", votpos },
+ { "votsort", votsort },
+ { "votstat", votstat },
+
+ { "vosamp", vosamp }, /* SAMP messaging */
+
+ { "vosesame", vosesame }, /* VO Name Resolution */
+
+ { "voatlas", voatlas }, /* VO Data access apps */
+ { "vocatalog", vocatalog },
+ { "vodata", vodata },
+ { "voimage", voimage },
+ { "voiminfo", voiminfo },
+ { "vospectra", vospectra },
+ { "votopic", votopic },
+
+ { "voregistry", voregistry }, /* VO Registry apps */
+ { NULL, NULL }
+};
+
+
+
+/**
+ * Program main().
+ */
+int
+main (int argc, char *argv[])
+{
+ char *task = (char *) NULL;
+ int status = 0;
+ size_t reslen = 0;
+ void *result = (void *) NULL;
+
+
+ /* Get the task name minus any leading path prefix.
+ */
+ task = argv[0] + strlen (argv[0]) - 1;
+ while (task > argv[0]) {
+ if ( *(task - 1) != '/')
+ task--;
+ else
+ break;
+ }
+
+ /* Loop through the application table. If the names match, call
+ * the entry-point function.
+ */
+ if (getenv ("VOAPP_CONNECTED") || (! RUN_DETACHED) ) {
+ for (app = voApps; app->name; app++) {
+ if (strcmp (app->name, task) == 0) {
+ status = (*app->func) (argc, argv, &reslen, &result);
+ break;
+ }
+ }
+ } else {
+ /* Run as a detached sub-process.
+ */
+ status = vo_runTask (task, voApps, argc, argv, &reslen, &result);
+ }
+
+
+ if (status && result) /* print the error message */
+ fprintf (stderr, "%s\n", (char *) result);
+ if (reslen && result) /* free result pointer */
+ free (result);
+
+ return (status);
+}
diff --git a/vendor/voclient/voapps/voApps.h b/vendor/voclient/voapps/voApps.h
new file mode 100644
index 00000000..f5ad6cca
--- /dev/null
+++ b/vendor/voclient/voapps/voApps.h
@@ -0,0 +1,180 @@
+/**
+ * VOAPPS.h -- Task declarations for the VOClient Package applications.
+ *
+ * @file voApps.h
+ * @author Mike Fitzpatrick
+ * @date 6/03/11
+ *
+ * @brief Task declarations for the VOClient Package applications.
+ */
+
+
+#include <getopt.h>
+
+
+#ifdef SZ_FORMAT
+#undef SZ_FORMAT
+#endif
+#define SZ_FORMAT 32
+
+#ifdef SZ_FNAME
+#undef SZ_FNAME
+#endif
+#define SZ_FNAME 256
+
+#ifdef SZ_PATH
+#undef SZ_PATH
+#endif
+#define SZ_PATH 512
+
+#ifdef SZ_LINE
+#undef SZ_LINE
+#endif
+#define SZ_LINE 4096
+
+#define PARG_ERR -127
+
+#define dabs(x) ((x<0.0?-x:x))
+
+/* Debug and verbose flags.
+ */
+#define VOAPP_DEBUG (getenv("VOAPP_DBG")||access("/tmp/VOAPP_DBG",F_OK)==0)
+#define VOAPP_VERB (getenv("VOAPP_VERB")||access("/tmp/VOAPP_VERB",F_OK)==0)
+
+/**
+ * Output formats.
+ */
+#define FORMATS "|vot|asv|bsv|csv|tsv|html|shtml|fits|ascii|xml|raw|"
+
+#define VOT 0 /* A new VOTable */
+#define ASV 1 /* ascii separated values */
+#define BSV 2 /* bar separated values */
+#define CSV 3 /* comma separated values */
+#define TSV 4 /* tab separated values */
+#define HTML 5 /* standalone HTML document */
+#define SHTML 6 /* single HTML <table> */
+#define FITS 7 /* FITS binary table */
+#define ASCII 8 /* ASV alias */
+#define XML 9 /* VOTable alias */
+#define RAW 10 /* " " */
+
+
+
+/* SAMP Definitions.
+ */
+#define SESS_CALLBACK 0 /* mgr sends callback port */
+#define SESS_QUIT 1 /* mgr sends quit/client quits */
+#define SESS_SEND 2 /* mgr/client forwards cmd */
+#define SESS_READY 3 /* mgr ready on port */
+
+#define SESS_DEFPORT 3000 /* default session mgr port */
+#define SESS_DEFHOST "140.252.1.86" /* default session mgr host */
+
+#define SAMP_CMD 000 /* message is a command */
+#define SAMP_DATA 001 /* message is data file */
+#define SAMP_RESULT 002 /* message is cmd result */
+#define SAMP_QUIT 004 /* message is quit request */
+#define SAMP_RELAY 010 /* message is relayed */
+#define SAMP_TEST 020 /* message is a test connect */
+
+
+/* File Formats.
+ */
+#define VOT_FITS 0
+#define VOT_VOTABLE 1
+#define VOT_FITS_SPEC 2
+#define VOT_VOTABLE_SPEC 3
+
+/* URL Formats.
+ */
+#define VOS_LOCALURL 0 /* e.g. http://127.0.0.1/foo */
+#define VOS_LOCALURI 1 /* e.g. file:///path/foo */
+#define VOS_LOCALFILE 2 /* e.g. /path/foo */
+#define VOS_REMOTE 3 /* e.g. http://foo.bar/junk */
+
+
+
+/******************************************************************************
+ * Image information structure. Note that although we can report 3-D
+ * images, we're really only setup to deal with equatorial sky coord
+ * systems.
+ *****************************************************************************/
+typedef struct {
+ char *imname; /* image name */
+ int is_image; /* is it an image? */
+ int is_table; /* is it a table? */
+ int has_wcs; /* image has wcs */
+
+ int extnum; /* extension number */
+ int naxis; /* number of axes */
+ int naxes[3]; /* axis dimensions */
+ int bitpix; /* pixel size */
+ int axflip; /* are axes flipped? */
+
+ double xc[4], yc[4]; /* corner positions (wcs) */
+ double cx, cy; /* center position (wcs) */
+ double lx, ly; /* LL corner (wcs) */
+ double ux, uy; /* UR corner (wcs) */
+ double xrval, yrval; /* CRVAL values */
+ double xrpix, yrpix; /* CRPIX values */
+
+ double width, height; /* image width/height (deg) */
+ double radius; /* cone radius (deg) */
+ double rotang; /* rotation angle (deg) */
+ double scale; /* plate scale (""/pix) */
+ char ctype[5]; /* coordinate type */
+} frameInfo, *frameInfoP;
+
+typedef struct {
+ char imname[SZ_PATH]; /* full image name */
+ int nextend; /* number of extensions */
+
+ frameInfo frame; /* full frame information */
+ frameInfo *extns; /* image extn information */
+} ImInfo, *ImInfoP;
+
+
+ImInfo *vot_imageInfo (char *name, int do_all);
+void vot_printImageInfo (FILE *fd, ImInfo *im);
+int vot_imageNExtns (char *image);
+void vot_freeImageInfo (ImInfo *img);
+
+
+
+/* Task structure.
+ */
+typedef struct {
+ char *name; /* task name */
+ int (*func)(int argc, char **argv, size_t *len, void **result);
+
+ int ntests; /* number of unit tests */
+ int npass; /* number of passed tests */
+ int nfail; /* number of failed tests */
+} Task;
+
+
+/* Tasking execution procedure.
+ */
+int vo_runTask (char *method, Task *apps, int argc, char **argv, size_t *len,
+ void **result);
+int vo_taskTest (Task *self, char *arg, ...);
+void vo_taskTestFile (char *str, char *fname);
+void vo_taskTestReport (Task self);
+void vo_taskDbg (void);
+
+int vo_setResultFromFile (char *fname, size_t *len, void **data);
+int vo_setResultFromString (char *str, size_t *len, void **data);
+int vo_setResultFromInt (int value, size_t *len, void **data);
+int vo_setResultFromReal (float value, size_t *len, void **data);
+int vo_appendResultFromString (char *str, size_t *len, void **data,
+ size_t *maxlen);
+
+
+
+/* Tasking parameter procedures.
+ */
+char **vo_paramInit (int argc, char *argv[],
+ char *opts, struct option long_opts[]);
+int vo_paramNext (char *opts, struct option long_opts[],
+ int argc, char *argv[], char *optval, int *posindex);
+void vo_paramFree (int argc, char *argv[]);
diff --git a/vendor/voclient/voapps/voApps.i b/vendor/voclient/voapps/voApps.i
new file mode 100644
index 00000000..b1ae3e7c
--- /dev/null
+++ b/vendor/voclient/voapps/voApps.i
@@ -0,0 +1,90 @@
+/**
+ * VOAPPS.I -- SWIG Interface definition file.
+ *
+ * @file voApps.i
+ * @author Mike Fitzpatrick
+ * @date 6/03/12
+ *
+ * @brief SWIG Interface definition file.
+ */
+
+%module voapps
+%{
+
+/* SAMP messaging
+ */
+extern int vosamp (int argc, char **argv, size_t *len, void **result);
+
+
+/* VOTable manipulation tasks.
+ */
+extern int votcnv (int argc, char **argv, size_t *len, void **result);
+extern int votget (int argc, char **argv, size_t *len, void **result);
+extern int votinfo (int argc, char **argv, size_t *len, void **result);
+extern int votpos (int argc, char **argv, size_t *len, void **result);
+extern int votsort (int argc, char **argv, size_t *len, void **result);
+extern int votstat (int argc, char **argv, size_t *len, void **result);
+/*
+extern int votcat (int argc, char **argv, size_t *len, void **result);
+extern int votjoin (int argc, char **argv, size_t *len, void **result);
+extern int votsplit (int argc, char **argv, size_t *len, void **result);
+*/
+
+
+/* VO Data Access tasks.
+ */
+extern int vodata (int argc, char **argv, size_t *len, void **result);
+extern int voatlas (int argc, char **argv, size_t *len, void **result);
+
+
+/* VO Registry query tasks.
+ */
+extern int voregistry (int argc, char **argv, size_t *len, void **result);
+
+
+/* VO Name Resolution Tasks.
+ */
+extern int vosesame (int argc, char **argv, size_t *len, void **result);
+
+%}
+
+
+
+
+
+/* SAMP messaging
+ */
+extern int vosamp (int argc, char **argv, size_t *len, void **result);
+
+
+/* VOTable manipulation tasks.
+ */
+extern int votcnv (int argc, char **argv, size_t *len, void **result);
+extern int votget (int argc, char **argv, size_t *len, void **result);
+extern int votinfo (int argc, char **argv, size_t *len, void **result);
+extern int votpos (int argc, char **argv, size_t *len, void **result);
+extern int votsort (int argc, char **argv, size_t *len, void **result);
+extern int votstat (int argc, char **argv, size_t *len, void **result);
+/*
+extern int votcat (int argc, char **argv, size_t *len, void **result);
+extern int votjoin (int argc, char **argv, size_t *len, void **result);
+extern int votsplit (int argc, char **argv, size_t *len, void **result);
+*/
+
+
+/* VO Data Access tasks.
+ */
+extern int vodata (int argc, char **argv, size_t *len, void **result);
+extern int voatlas (int argc, char **argv, size_t *len, void **result);
+
+
+/* VO Registry query tasks.
+ */
+extern int voregistry (int argc, char **argv, size_t *len, void **result);
+
+
+/* VO Name Resolution Tasks.
+ */
+extern int vosesame (int argc, char **argv, size_t *len, void **result);
+
+
diff --git a/vendor/voclient/voapps/voAppsP.h b/vendor/voclient/voapps/voAppsP.h
new file mode 100644
index 00000000..268bf3d6
--- /dev/null
+++ b/vendor/voclient/voapps/voAppsP.h
@@ -0,0 +1,255 @@
+/**
+ * VOAPPSP.h -- Internal declarations for the VOClient Package applications.
+ *
+ * @file voAppsP.h
+ * @author Mike Fitzpatrick
+ * @date 6/03/11
+ *
+ * @brief Internal declarations for the VOClient Package applications.
+ */
+
+
+#ifndef SZ_LINE
+#define SZ_LINE 4096
+#endif
+#ifndef SZ_URL
+#define SZ_URL 1024
+#endif
+#define DEF_SR 0.1
+
+
+
+/* Local processing definitions.
+*/
+#define MAX_DOWNLOADS 8 /* max downloads to run */
+#define MAX_THREADS 128 /* max threads to run */
+#define MAX_PROCS 64 /* max processes to run */
+#define DEF_DOWNLOADS 1 /* default no. downloads to run */
+#define DEF_NTHREADS 16 /* default num threads to run */
+#define DEF_NPROCS 10 /* default num processes to run */
+#define DEF_PGID 6200 /* default process group id */
+
+#define SZ_TARGET 64 /* size of target name */
+#define DEF_SIZE 0.1 /* default search size (deg) */
+
+#ifndef FAILED_ONLY
+#define FAILED_ONLY 1 /* summarize only failed procs? */
+#endif
+
+/* NVO tool contexts.
+*/
+#define CX_DATA 0001 /* DAL data access */
+#define CX_REGISTRY 0002 /* Registry resolution */
+#define CX_SESAME 0004 /* Object name resolution */
+#define CX_INVENTORY 0010 /* Data Inventory */
+
+/* Output file formats.
+*/
+#define F_ASCII 0001 /* ASCII table */
+#define F_RAW 0002 /* Raw VOTable */
+#define F_CSV 0004 /* Comma-separated-values */
+#define F_TSV 0010 /* Tab-separated-values */
+#define F_FITS 0020 /* FITS binary table */
+#define F_HTML 0040 /* HTML table */
+#define F_KML 0100 /* KML placemark table */
+#define F_XML 0200 /* XML document */
+#define F_META 0400 /* Metadata listing */
+
+/* Service Types.
+*/
+#define SVC_CONE 0001 /* Cone search service type */
+#define SVC_SIAP 0002 /* SIAP service */
+#define SVC_SSAP 0004 /* SSAP service */
+#define SVC_VIZIER 0010 /* Vizier TabularSkyService */
+#define SVC_SKYNODE 0020 /* Skynode */
+#define SVC_OTHER 0040 /* Other type of service */
+
+/* Table pretty-print defs
+*/
+#define PP_WIDTH 40
+#define PP_OFFSET 40
+#define PP_MAXCHARS 256
+
+/* Registry query buffers
+*/
+#define SZ_SQL_TERM 4096
+#define SZ_RESULT 40960
+
+/* Range constants.
+*/
+#define RANGE_ALL -1
+#define RANGE_NONE -2
+#define MAX_RANGES 1024
+
+/* Data type codes.
+*/
+#define DT_ANY 000 /* Any or not-specified */
+#define DT_CATALOG 001 /* Catalog data */
+#define DT_IMAGE 002 /* Image data */
+#define DT_SPECTRA 004 /* Spectral data */
+#define DT_RADIO 010 /* Radio data */
+#define DT_EVENT 020 /* Event-based data */
+
+
+/* Extraction types
+*/
+#define EX_NONE 0000 /* No extractions */
+#define EX_ALL 0777 /* Generate all files */
+#define EX_BOTH 0001 /* Get positions and acrefs */
+#define EX_SAVE 0002 /* Save intermediate results */
+#define EX_COLLECT 0004 /* Collect intermediate results */
+#define EX_POS 0010 /* Get positions only */
+#define EX_ACREF 0020 /* Get acrefs only */
+#define EX_HTML 0040 /* Generate HTML table */
+#define EX_KML 0100 /* Generate KML file */
+#define EX_XML 0200 /* Generate XML document */
+
+/* Error codes
+*/
+#define E_NONE 0 /* No Error */
+#define E_NODATA 1 /* No Data Returned */
+#define E_REQFAIL 2 /* Request Failed */
+#define E_FILOPEN 3 /* File Open Error */
+#define E_VOCINIT 4 /* VOClient init failed */
+
+
+
+
+/* Utility macros.
+*/
+#define VOT_NEXTARG(argc,argv,i) {if(i+1>=argc||(strlen(argv[i+1])>1&&argv[i+1][0]=='-'&&(!isdigit(argv[i+1][1])))){fprintf(stderr,"Error: Option '%s' requires an argument\n",argv[i]);break;}}
+
+
+typedef int (*PFI)(); /* ptr to func returning an int */
+
+#ifdef max
+#undef max
+#endif
+#define max(a,b) (((a)>(b))?(a):(b))
+
+#ifdef min
+#undef min
+#endif
+#define min(a,b) (((a)<(b))?(a):(b))
+
+#ifdef abs
+#undef abs
+#endif
+#define abs(a) (((a)<0)?-(a):(a))
+
+
+/*************************************************************************
+** Service calling params.
+*/
+typedef struct {
+ /* Input params. */
+ char service_url[SZ_LINE]; /* base service URL */
+ char identifier[SZ_LINE]; /* service identifier */
+ char name[SZ_LINE]; /* service short name */
+ char oname[SZ_LINE]; /* object name */
+ char title[SZ_LINE]; /* object name */
+ char band[SZ_LINE]; /* BAND param (SSA) */
+ char time[SZ_LINE]; /* TIME param (SSA) */
+ int type; /* service type */
+ int etype; /* extraction type */
+ double ra; /* J2000 RA (dec. degrees) */
+ double dec; /* J2000 Dec (dec. degrees) */
+ float sr; /* search radius (degrees) */
+ int fmt; /* output format */
+ int index; /* output index */
+ int svc_index; /* output service index */
+ int obj_index; /* output object index */
+} svcParams;
+
+
+/*************************************************************************
+** Object/Position params.
+*/
+typedef struct {
+ char name[SZ_FNAME]; /* object name */
+ char id[SZ_FNAME]; /* object ID */
+ double ra; /* Right Ascension (J200) */
+ double dec; /* Declination (J200) */
+ int index; /* list index */
+ void *next; /* linked list pointer */
+} Object;
+
+
+/*************************************************************************
+** Range specification used for row/column selection.
+*/
+typedef struct {
+ char rstring[SZ_FNAME]; /* range string */
+ int ranges[MAX_RANGES]; /* expanded range array */
+ int nvalues; /* num. values in range string */
+} Range;
+
+Range colRange; /* column selection range */
+Range rowRange; /* row selection range */
+Range fileRange; /* acref selection range */
+
+
+/*************************************************************************
+** AccessReference or URL params.
+*/
+
+#define AC_PENDING 1
+#define AC_WORKING 2
+#define AC_COMPLETE 3
+#define AC_ERROR -1
+
+typedef struct {
+ char url[SZ_LINE]; /* AcRef or URL */
+ char fname[SZ_FNAME]; /* saved output file name */
+ long nbytes; /* size of result */
+ int status; /* error status */
+ int index; /* list index */
+ void *next; /* linked list pointer */
+} Acref;
+
+
+/*************************************************************************
+** Process call list for results summary.
+*/
+typedef struct {
+ pid_t pid; /* process pid */
+ Object *obj; /* Object */
+ int status; /* return status */
+ int count; /* query result count */
+ char root[SZ_FNAME]; /* root file name */
+ void *svc; /* back-pointer */
+ void *next; /* linked list pointer */
+} Proc;
+
+
+/*************************************************************************
+** DAL Service params. Each service is comprised of a service URL that
+** represents a specific type of DAL service. Once processed, the 'proc'
+** list will contain summary information on each request and the 'acList'
+** will contain all the images that need to be downloaded. Column and
+** row selection are applied to each request, the download are done following
+** the queries so we can parallelize them across all requested services.
+*/
+typedef struct {
+ char name[SZ_FNAME]; /* service short name */
+ char service_url[SZ_LINE]; /* base service URL */
+ char identifier[SZ_LINE]; /* service identifier */
+ char title[SZ_LINE]; /* service title string */
+ int type; /* service type */
+ int (*func)(svcParams *p); /* function to call */
+ int cached; /* cached resource (NYI) */
+
+ int count; /* query result total count */
+ int index; /* list index */
+
+ Proc *proc; /* process results list */
+ int nfailed; /* no. of failed requests */
+ int nnodata; /* no. of failed requests */
+
+ Acref *acList; /* acref list for service */
+ int nrefs; /* no. of acrefs to download */
+
+ void *next; /* linked list pointer */
+} Service;
+
+
diff --git a/vendor/voclient/voapps/voApps_spp.c b/vendor/voclient/voapps/voApps_spp.c
new file mode 100644
index 00000000..21cf4145
--- /dev/null
+++ b/vendor/voclient/voapps/voApps_spp.c
@@ -0,0 +1,255 @@
+/**
+ * VOTAPP_SPP.C -- SPP Interface routines to applications code.
+ *
+ * @file votApp_spp.c
+ * @author Mike Fitzpatrick
+ * @date 6/03/11
+ *
+ * @brief SPP Interface routines to applications code.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+#include <unistd.h>
+#include <ctype.h>
+#include <errno.h>
+
+/*
+#include "votParseP.h"
+*/
+#include "votParse.h"
+
+
+/* SPP Type definitions.
+*/
+#define XCHAR short
+#define PKCHAR char
+#define XINT int
+#define XEOS 0
+
+
+/* SPP Interface Definitions.
+ *
+ * SPP compilers on various platforms may append one or more trailing
+ * underscores to symbol names, we'll use macros for the interface names
+ * and use defines to see what the symbol name is.
+*/
+#ifdef _NO_US_
+
+#define VX_VODATA vxvoda
+#define VX_VODIRECTORY vxvody
+#define VX_VOSESAME vxvose
+
+#define VX_VOCOPY vxvocy
+#define VX_VOGET vxvogt
+#define VX_VOINFO vxvoio
+
+#else
+
+#define VX_VODATA vxvoda_
+#define VX_VODIRECTORY vxvody_
+#define VX_VOSESAME vxvose_
+
+#define VX_VOCOPY vxvocy_
+#define VX_VOGET vxvogt_
+#define VX_VOINFO vxvoio_
+
+#endif
+
+typedef void (*PFV)();
+typedef int (*PFI)();
+
+
+
+/**
+ * Local interface declarations.
+ */
+static PKCHAR *spp2c (XCHAR *instr, int maxch);
+static int spplen (XCHAR *str);
+static void func_exec (PFV func, char *name, int *argc, XCHAR *firstArg,
+ va_list argp);
+
+
+
+/*****************************************************************************
+ * Application Interfaces
+ ****************************************************************************/
+
+#define MAX_ARGS 64
+
+void vodata (int argc, char **argv);
+void voregistry (int argc, char **argv);
+void vosesame (int argc, char **argv);
+
+void votcnv (int argc, char **argv);
+void votget (int argc, char **argv);
+void votinfo (int argc, char **argv);
+
+void voc_debug (void);
+
+
+
+/**
+ * FUNC_EXEC -- Execute a VOClient function from the SPP binding.
+ */
+static void
+func_exec (PFV func, char *name, int *argc, XCHAR *firstArg, va_list argp)
+{
+ int i, _argc = *argc;
+ char *_argv[MAX_ARGS];
+ XCHAR *arg;
+
+ if (firstArg == NULL) /* must pass in at least one arg */
+ return;
+
+
+ /* Process the argument list.
+ */
+ _argc = *argc + 1;
+ _argv[0] = strdup (name);
+ _argv[1] = spp2c (firstArg, spplen (firstArg));
+
+ for (i=2; i < _argc && (arg=(XCHAR *)va_arg(argp,XCHAR *)) != NULL; i++)
+ if (arg)
+ _argv[i] = spp2c (arg, spplen (arg));
+
+ /* Debug output.
+ */
+ if (access ("/tmp/VOC_DEBUG", F_OK) == 0) {
+ for (i=0; i < _argc; i++)
+ fprintf (stderr, "%s ", _argv[i]);
+ fprintf (stderr, "\n");
+ }
+
+
+ (*func) (_argc, _argv); /* call the task */
+
+ for (i=0; i < *argc; i++) /* free the arg pointers */
+ if (_argv[i])
+ free ((char *) _argv[i]);
+
+ return;
+}
+
+
+/****************************************************************************
+ * Task wrappers
+ ****************************************************************************/
+
+/**
+ * VX_VOCOPY -- Application interface to the VOCOPY task.
+ */
+void VX_VOCOPY (int *argc, XCHAR *firstArg, ...)
+{
+ va_list argp;
+
+ va_start (argp, firstArg);
+ func_exec (votcnv, "votcopy", argc, firstArg, argp);
+ va_end (argp);
+}
+
+
+/**
+ * VX_VODATA -- Application interface to the VODATA task.
+ */
+void VX_VODATA (int *argc, XCHAR *firstArg, ...)
+{
+ va_list argp;
+
+ va_start (argp, firstArg);
+ func_exec (vodata, "vodata", argc, firstArg, argp);
+ va_end (argp);
+}
+
+
+/**
+ * VX_VODIRECTORY -- Application interface to the VODIRECTORY task.
+ */
+void VX_VODIRECTORY (int *argc, XCHAR *firstArg, ...)
+{
+ va_list argp;
+
+ va_start (argp, firstArg);
+ func_exec (voregistry, "vodirectory", argc, firstArg, argp);
+ va_end (argp);
+}
+
+
+/**
+ * VX_VOGET -- Application interface to the VOGET task.
+ */
+void VX_VOGET (int *argc, XCHAR *firstArg, ...)
+{
+ va_list argp;
+
+ va_start (argp, firstArg);
+ func_exec (votget, "votget", argc, firstArg, argp);
+ va_end (argp);
+}
+
+/**
+ * VX_VOINFO -- Application interface to the VOTINFO task.
+ */
+void VX_VOINFO (int *argc, XCHAR *firstArg, ...)
+{
+ va_list argp;
+
+ va_start (argp, firstArg);
+ func_exec (votinfo, "votinfo", argc, firstArg, argp);
+ va_end (argp);
+}
+
+
+/**
+ * VX_VOSESAME -- Application interface to the VOSESAME task.
+ */
+void VX_VOSESAME (int *argc, XCHAR *firstArg, ...)
+{
+ va_list argp;
+
+ va_start (argp, firstArg);
+ func_exec (vosesame, "vosesame", argc, firstArg, argp);
+ va_end (argp);
+}
+
+
+
+/****************************************************************************
+ * Private utility procedures
+ ****************************************************************************/
+
+/**
+ * SPP2C -- Convert an SPP string to a host C string.
+ */
+static char *
+spp2c (XCHAR *instr, int maxch)
+{
+ XCHAR *ip = instr;
+ char *outstr = (char *) calloc (1, maxch+1);
+ char *op = (char *) outstr;
+ int n = maxch;
+
+ while ((*op++ = (char)*ip++) != (char)XEOS && --n >= 0)
+ ;
+ *--op = (char) XEOS;
+
+ return (outstr);
+}
+
+
+/**
+ * SPPLEN -- Get the length of an SPP string.
+ */
+static int
+spplen (XCHAR *str)
+{
+ int len = 0;
+
+ for (len=0; str[len] != (XCHAR) XEOS; len++)
+ ;
+ return (len);
+}
+
+void voc_debug () { int junk; junk = 1; }
diff --git a/vendor/voclient/voapps/voatlas.c b/vendor/voclient/voapps/voatlas.c
new file mode 100644
index 00000000..a72f4422
--- /dev/null
+++ b/vendor/voclient/voapps/voatlas.c
@@ -0,0 +1,660 @@
+/**
+ * VOATLAS -- Query the SkyView Image service for an all-sky image.
+ *
+ * Usage: voatlas [<opts>] <name> | <ra dec>
+ *
+ * Where
+ * -%%,--test run unit tests
+ * -h,--nelp this message
+ * -d,--debug enable debug messages
+ * -r,--return return result from method
+ *
+ * -b,--band <bpass> Bandpass
+ * -l,--list List available surveys for position
+ * -p,--survey <survey> Survey program name
+ * -g,--graphic Get a graphic image (i.e. JPEG)
+ * -n,--naxis <npix> Set returned image size
+ *
+ * -s,--size <size> Field size
+ * <size>s Field size (arcsec)
+ * <size>m Field size (arcmin)
+ * <size>d Field size (degrees, default)
+ * -F,--field <field> Resolve query field name
+ * -R,--ra <ra> Set query RA position
+ * -D,--dec <dec> Set query Dec position
+ * -P,--pos <ra,dec> Set query as a POS string
+ * -S,--samp Broadcast as SAMP message
+ * -o <name> Save image to named file
+ *
+ * <name> Target name to be resolved to position
+ * <ra> <dec> Position to query (dec. deg or Eq. sexagesimal)
+ *
+ *
+ * @file voatlas.c
+ * @author Mike Fitzpatrick
+ * @date 7/03/12
+ *
+ * @brief Query the SkyView Image service for an all-sky image.
+ */
+
+
+#define _GNU_SOURCE /* for strcasestr() on linux */
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <ctype.h>
+#include "VOClient.h"
+#include "voApps.h"
+#include "samp.h"
+
+
+static double ra = 0.0; /* default values */
+static double dec = 0.0;
+static double size = 0.25;
+
+static int debug = FALSE; /* debug output */
+static int do_samp = FALSE; /* broadcast SAMP msg? */
+static int graphic = FALSE; /* get graphics format? */
+static int list_surveys = FALSE; /* list results? */
+static int verbose = FALSE; /* verbose output? */
+static char *field = NULL; /* Input field name */
+static char *pos = NULL; /* Input position */
+static char *bpass = NULL; /* Bandpass */
+
+static char svc_url[SZ_URL], survey[SZ_FNAME];
+
+
+static char *base_url = "http://skyview.gsfc.nasa.gov/cgi-bin/vo/sia.pl?";
+
+static int voa_resolveField (char *field, double *ra, double *dec);
+static int voa_resolvePos (char *pos, double *ra, double *dec);
+static double voa_getSize (char *arg);
+static int voa_callService (char *url, double ra, double dec, double size,
+ char *ofname, char *format, int maximages);
+
+extern double sexa (char *s);
+extern char *strcasestr ();
+extern int vot_atoi (char *v);
+extern double vot_atof (char *v);
+
+
+#ifdef USE_RESBUF
+static char *resbuf; /* result buffer */
+#endif
+
+
+/* Task specific option declarations.
+ */
+int voatlas (int argc, char **argv, size_t *len, void **result);
+
+static int do_return = 0;
+static Task self = { "voatlas", voatlas, 0, 0, 0 };
+static char *opts = "%hF:R:D:P:b:dgs:o:Srlp:n:v";
+static struct option long_opts[] = {
+ { "field", 1, 0, 'F'}, /* query field name */
+ { "ra", 1, 0, 'R'}, /* RA of position */
+ { "dec", 1, 0, 'D'}, /* Dec of position */
+ { "pos", 1, 0, 'P'}, /* POS position */
+ { "graphics", 2, 0, 'g'}, /* graphics format? */
+ { "band", 1, 0, 'b'}, /* bandpass */
+ { "list", 2, 0, 'l'}, /* list surveys */
+ { "survey", 1, 0, 'p'}, /* survey name */
+ { "naxis", 1, 0, 'n'}, /* image size */
+ { "size", 1, 0, 's'}, /* query size */
+ { "output", 1, 0, 'o'}, /* set output name */
+ { "samp", 2, 0, 'S'}, /* broadcast SAMP */
+ { "verbose", 2, 0, 'v'}, /* required */
+ { "help", 2, 0, 'h'}, /* required */
+ { "debug", 2, 0, 'd'}, /* required (debug) */
+ { "test", 2, 0, '%'}, /* required */
+ { "return", 1, 0, 'r'}, /* required */
+ { NULL, 0, 0, 0 }
+};
+
+static void Usage (void);
+static void Tests (char *input);
+
+
+
+/**
+ * Application entry point.
+ */
+int
+voatlas (int argc, char **argv, size_t *reslen, void **result)
+{
+ char **pargv, optval[SZ_FNAME], ch;
+ char *iname = NULL, *oname = NULL, *dlname = NULL;
+ char tmp[SZ_FNAME], buf[SZ_FNAME];
+ int i=1, status = OK, apos = 0, samp = -1, naxis = 512;
+
+
+ /* Initialize.
+ */
+ memset (buf, 0, SZ_FNAME);
+ memset (tmp, 0, SZ_FNAME);
+ memset (survey, 0, SZ_FNAME);
+ memset (svc_url, 0, SZ_URL);
+
+ *reslen = 0;
+ *result = NULL;
+
+
+ /* Parse the argument list.
+ */
+ pargv = vo_paramInit (argc, argv, opts, long_opts);
+ while ((ch = vo_paramNext (opts,long_opts,argc,pargv,optval,&apos)) != 0) {
+ i++;
+ if (ch > 0) {
+ switch (ch) {
+ case '%': Tests (optval); return (self.nfail);
+ case 'h': Usage (); return (OK);
+ case 'd': debug++; break;
+ case 'r': do_return++; break;
+
+ case 'b': bpass = strdup (optval); i++; break;
+ case 'g': graphic++; break;
+ case 'l': list_surveys++;
+ strcpy (survey, "list"); break;
+ case 'p': strcpy (survey, optval); i++; break;
+ case 'n': naxis = vot_atoi (optval); i++; break;
+
+ case 'F': field = strdup (optval); i++; break;
+ case 'R': if (strchr (optval, (int)':'))
+ ra = (15. * (double) sexa (optval));
+ else
+ ra = (double) vot_atof (optval);
+ i++;
+ break;
+ case 'D': if (strchr (optval, (int)':'))
+ dec = (double) sexa (optval);
+ else
+ dec = (double) vot_atof (optval);
+ i++;
+ break;
+ case 'P': sscanf (optval, "%lf,%lf", &ra, &dec);
+ i++;
+ break;
+
+ case 's': size = voa_getSize(optval); i++; break;
+ case 'o': oname = strdup (optval); i++; break;
+
+ case 'S': do_samp = 1; break;
+ case 'v': verbose = 1; break;
+
+ default:
+ fprintf (stderr, "Invalid argument '%c'\n", ch);
+ return (ERR);
+ }
+
+ } else if (ch == PARG_ERR) {
+ return (ERR);
+
+ } else {
+ if (i == (argc-2)) {
+ sprintf (buf, "%s %s", optval, argv[i+1]);
+ pos = strdup (buf);
+ sscanf (pos, "%lf %lf", &ra, &dec);
+ } else
+ field = strdup (optval);
+ break;
+ }
+ }
+
+
+ /* Sanity checks.
+ */
+ if (!field && !pos && (ra == 0.0 && dec == 0.0)) {
+ fprintf (stderr, "Error: no field/position specified.\n");
+ return (ERR);
+ }
+
+ if (!survey[0]) {
+ /* No survey specified so go by the bandpass.
+ */
+ if (!bpass)
+ strcpy (survey, "dss2b");
+ else {
+ if (strncasecmp (bpass, "optical", 3) == 0)
+ strcpy (survey, "dss");
+ else if (strncasecmp (bpass, "infrared", 3) == 0 ||
+ strncasecmp (bpass, "ir", 2) == 0)
+ strcpy (survey, "2massk");
+ else if (strncasecmp (bpass, "x-ray", 1) == 0)
+ strcpy (survey, "pspc2int");
+ else if (strncasecmp (bpass, "euv", 3) == 0)
+ strcpy (survey, "euve83");
+ else if (strncasecmp (bpass, "gamma-ray", 5) == 0)
+ strcpy (survey, "egret1000");
+ else if (strncasecmp (bpass, "radio", 3) == 0)
+ strcpy (survey, "4850mhz");
+ }
+ } else if (strcasecmp (survey, "list") == 0) {
+ list_surveys = 1;
+ memset (survey, 0, SZ_FNAME);
+ }
+
+
+ /* Setup the output name.
+ */
+ if (oname) {
+ dlname = oname; /* output name specified */
+ } else if (do_samp) {
+ strcpy (tmp, "/tmp/voatlasXXXXXX"); /* temp download name */
+ mktemp (tmp);
+ dlname = tmp;
+ } else {
+ if (field)
+ sprintf (buf, "%s.%s", field, (graphic ? "jpg" : "fits"));
+
+ else if (pos) {
+ char *ip, *op;
+
+ memset (buf, 0, SZ_FNAME);
+ for (op=buf, ip=pos; *ip; ip++)
+ *op++ = (*ip == ' ' ? '_' : *ip);
+ strcat (buf, ".");
+ strcat (buf, (graphic ? "jpg" : "fits"));
+
+ } else if (list_surveys) {
+ if (verbose)
+ fprintf (stderr,
+ "Warning: no field/position specified, using (0.,0.).\n");
+
+ } else {
+ fprintf (stderr, "Error: no output name specified.\n");
+ status = ERR;
+ goto done_;
+ }
+ dlname = oname = strdup (buf);
+ }
+
+
+ if (debug) {
+ fprintf (stderr, "field='%s' pos='%s' ra=%g dec=%g\n",
+ field, pos, ra, dec);
+ fprintf (stderr, "bpass='%s' survey='%s'\n", bpass, survey);
+ fprintf (stderr, "oname='%s'\n", oname);
+ }
+
+ /* Initialize the VOClient code. Error messages are printed by the
+ * interface so we just quit if there is a problem.
+ */
+ if (voc_initVOClient ("runid=voc.voatlas") == ERR)
+ return (ERR);
+
+ /* Sanity checks
+ */
+ if (iname == NULL) iname = strdup ("stdin");
+ if (oname == NULL) oname = strdup ("stdout");
+ if (strcmp (iname, "-") == 0) { free (iname), iname = strdup ("stdin"); }
+ if (strcmp (oname, "-") == 0) { free (oname), oname = strdup ("stdout"); }
+
+ if (field && pos) {
+ fprintf (stderr,
+ "Error: only one of 'field' or 'pos' may be specified.\n");
+ status = ERR;
+ goto done_;
+ } else if (field) {
+ if (voa_resolveField (field, &ra, &dec) == OK) {
+ fprintf (stderr, "Error: cannot resolve object '%s'\n", field);
+ status = ERR;
+ goto done_;
+ }
+ } else if (pos) {
+ if (voa_resolvePos (pos, &ra, &dec) != OK) {
+ fprintf (stderr, "Error: cannot convert position '%s'\n", pos);
+ status = ERR;
+ goto done_;
+ }
+ }
+
+
+ /* Form the service URL.
+ */
+ memset (svc_url, 0, SZ_URL);
+ sprintf (svc_url, "%snaxis=%d&", base_url, naxis);
+ if (survey[0]) {
+ strcat (svc_url, "survey=");
+ strcat (svc_url, survey);
+ strcat (svc_url, "&");
+ }
+ if (debug)
+ fprintf (stderr, "ra = %g dec = %g\nurl='%s'\n", ra, dec, svc_url);
+
+
+ /* Call the SkyView SIA service.
+ */
+ if (voa_callService (svc_url, ra, dec, size, dlname,
+ (graphic ? "jpeg" : "fits"), 1) == ERR) {
+ fprintf (stderr, "Error: cannot contact SkyView service\n");
+ status = ERR;
+ goto done_;
+ }
+
+ /* Broadcast the image as a message if requested.
+ */
+ if (do_samp) {
+ if ((samp = sampInit ("voatlas", "VOClient Task")) >= 0) {
+ char url[SZ_LINE], cwd[SZ_LINE];
+
+ samp_setSyncMode (samp); /* use asynchronous mode */
+ sampStartup (samp); /* register w/ Hub */
+
+ memset (url, 0, SZ_LINE);
+ memset (cwd, 0, SZ_LINE);
+ getcwd (cwd, SZ_LINE);
+ if (tmp[0])
+ sprintf (url, "file://%s", dlname);
+ else
+ sprintf (url, "file://%s/%s", cwd, oname);
+
+ if (verbose)
+ printf ("Displaying image %s ...\n", url);
+ (void) samp_imageLoadFITS (samp, "all", url, "", field);
+
+ if (tmp[0])
+ unlink (dlname);
+ sampShutdown (samp);
+ }
+ }
+
+
+ /* See if we're returning the image.
+ */
+ if (do_return) {
+ vo_setResultFromFile (dlname, reslen, result);
+ unlink (dlname);
+ }
+
+
+ /* Clean up and shutdown.
+ */
+done_:
+ if (pos) free (pos);
+ if (field) free (field);
+ if (iname) free (iname);
+ if (oname) free (oname);
+
+ voc_closeVOClient (1);
+ vo_paramFree (argc, pargv);
+
+ sleep (2); /* FIXME -- SkyView seems to have a reset issue... */
+
+ return (status);
+}
+
+
+/**
+ * USAGE -- Print task help summary.
+ */
+static void
+Usage (void)
+{
+ fprintf (stderr, "\n Usage:\n\t"
+ "voatlas [<opts>] [<field> | <pos>]\n\n"
+ " where\n"
+ " -%%,--test run unit test\n"
+ " -d,--debug enable debugging\n"
+ " -h,--nelp this messag\n"
+ " -r,--return return result from metho\n"
+ "\n"
+ " -b,--band <bpass> Bandpas\n"
+ " -p,--survey <survey> Survey program nam\n"
+ " -g,--graphic Get a graphic image (i.e. JPEG\n"
+ " -n,--naxis <npix> Set returned image size\n"
+ "\n"
+ " -s,--size <size> Field siz\n"
+ " <size>s Field size (arcsec\n"
+ " <size>m Field size (arcmin\n"
+ " <size>d Field size (degrees, default\n"
+ " -F,--field <field> Resolve query field nam\n"
+ " -R,--ra <ra> Set query RA positio\n"
+ " -D,--dec <dec> Set query Dec positio\n"
+ " -P,--pos <ra,dec> Set query as a POS strin\n"
+ " -S,--samp Broadcast as SAMP messag\n"
+ " -v,--verbose Verbose output\n"
+ " -o <name> Save image to named fil\n"
+ "\n"
+ " <name> Target name to be resolved\n"
+ " <ra> <dec> Position to query\n"
+ "\n"
+ "Examples:\n\n"
+ " 1) Display an image of M83 on Aladin using SAMP\n\n"
+ " %% voatlas --samp m83\n"
+ "\n"
+ " 2) Get a 256x256 JPEG image of the Sombrero galaxy\n\n"
+ " %% voatlas -o gal.jpg -n 256 --graphic sombrero\n"
+ "\n"
+ " 3) Get a 20 arcmin Wise 2.2micron survey image of m101\n\n"
+ " %% voatlas -s 20m --survey=wise22 m101\n"
+ "\n"
+ " 4) Get a radio image of 3c273, image will be '3c273.fits'\n\n"
+ " %% voatlas --band=radio 3c273\n"
+ "\n"
+ " 5) List (verbose) the survey images available for ngc1234\n\n"
+ " %% voatlas --survey=list -v ngc1234\n"
+ "\n"
+ );
+}
+
+
+/**
+ * Tests -- Task unit tests.
+ */
+static void
+Tests (char *input)
+{
+ Task *task = &self;
+
+ vo_taskTest (task, "--help", NULL);
+ vo_taskTest (task, "-S", "m83", NULL); // Ex 1
+ vo_taskTest (task, "--samp", "m83", NULL);
+
+ vo_taskTest (task, "-o", "gal.jpg", "-n", "256", // Ex 2
+ "--graphic", "sombrero", NULL);
+
+ vo_taskTest (task, "-s", "20m", "--survey=wise22", "m101", NULL); // Ex 3
+
+ vo_taskTest (task, "--band=radio", "3c273", NULL); // Ex 4
+
+ vo_taskTest (task, "--survey=list", "-v", "ngc1234", NULL); // Ex 5
+
+ vo_taskTest (task, "m51", NULL);
+ vo_taskTest (task, "-o", "m51.fits", "m51", NULL);
+ vo_taskTest (task, "--ra=202.47", "--dec=47.195", "--samp", NULL);
+
+ /* Clean up any files we created.
+ */
+ if (access ("m51.fits", F_OK) == 0) unlink ("m51.fits");
+ if (access ("m101.fits", F_OK) == 0) unlink ("m101.fits");
+ if (access ("3c273.fits", F_OK) == 0) unlink ("3c273.fits");
+ if (access ("gal.jpg", F_OK) == 0) unlink ("gal.jpg");
+
+ vo_taskTestReport (self);
+}
+
+
+
+/**
+ * Simple test routine to call a Siap search service and summarize results.
+ */
+static int
+voa_callService (char *svc_url, double ra, double dec, double size,
+ char *ofname, char *format, int maximages)
+{
+ char *acref = NULL, *fmt = NULL, *program = NULL;
+ double dra, ddec;
+ int i, nrec = 0, recnum = 0;
+ FILE *fd = (FILE *) NULL;
+
+
+ DAL siap; /* DAL Connection */
+ Query query; /* query handle */
+ QResponse qr; /* query response handle */
+ QRecord rec; /* result record handle */
+ QRAttribute v; /* dataset attribute */
+
+
+ /* Get a new connection to the named service.
+ */
+ siap = voc_openSiapConnection (svc_url); /* open a connection */
+
+ /* Form a query. Here we'll use the one search size we're given for
+ * both the RA,DEC sizes, and specify a null format.
+ */
+ query = voc_getSiapQuery (siap, ra, dec, size, size,
+ (list_surveys ? NULL : (graphic ? "image/jpeg" : "image/fits")));
+
+
+ if (VOAPP_DEBUG) {
+ fprintf (stderr, "Executing Query:\n %s\n\n",
+ voc_getQueryString (query, SIAP_CONN, 0));
+ }
+
+
+ /* Execute the query.
+ */
+ qr = voc_executeQuery (query); /* execute the query */
+ if ((nrec = voc_getRecordCount (qr)) <= 0)
+ return (ERR);
+
+ if (do_return && list_surveys)
+ fd = fopen (ofname, "w+");
+ else
+ fd = stdout;
+
+
+ /* Download the first 'maximages' images.
+ */
+ for (i=0; i < nrec && i < nrec; i++) {
+ rec = voc_getRecord (qr, i); /* get a row in the table */
+
+ v = voc_getAttribute (rec, "Format"); /* get the right format */
+ if (!(fmt = voc_stringValue(v)) || strcasestr (fmt, format) == NULL)
+ if (!list_surveys)
+ continue;
+
+ v = voc_getAttribute (rec, "Title"); /* get the survey */
+ program = voc_stringValue(v);
+ if (list_surveys) {
+ v = voc_getAttribute (rec, "Ra"); dra = voc_floatValue (v);
+ v = voc_getAttribute (rec, "Dec"); ddec = voc_floatValue (v);
+ if (verbose)
+ fprintf (fd, "%3d %12.12s %g %g %s\n",
+ (i+1), program, dra, ddec, fmt);
+ else
+ fprintf (fd, "%3d %12.12s %s\n", (i+1), program, fmt);
+
+ } else if (program) {
+ int plen = strlen (program);
+ int slen = strlen (survey);
+
+ if (strncasecmp (program, survey, min(plen,slen)) == 0) {
+ if ((v = voc_getAttribute (rec, "AccessReference"))) {
+ acref = voc_stringValue (v);
+ if (verbose) {
+ printf ("Downloading %d of %d: '%s' ....",
+ i, nrec, ofname);
+ fflush (stdout);
+ }
+ if ( voc_getDataset (rec, acref, ofname) != OK ) {
+ if (verbose)
+ printf ("error downloading file\n");
+ return (ERR);
+ }
+ if (verbose)
+ printf ("done\n");
+
+ if ( ++recnum >= maximages )
+ break;
+ }
+ }
+ }
+ }
+
+ if (fd != stdout)
+ fclose (fd);
+
+ voc_closeConnection (siap); /* close the siap connection */
+ return (OK);
+}
+
+
+/**
+ * VOA_RESOLVEPOS -- Resolve a position string to decimal degrees.
+ */
+static int
+voa_resolvePos (char *pos, double *ra, double *dec)
+{
+ char *ip = NULL, *s1 = NULL, *s2 = NULL;
+
+
+ if ( (ip = strchr (pos, (int)' '))) {
+ *ip = '\0';
+ s1 = pos;
+ s2 = ip + 1;
+
+ if (strchr (s1, (int)':'))
+ *ra = (15. * (double) sexa (s1));
+ else
+ *ra = (double) vot_atof (s1);
+ *dec = (strchr (s2,(int)':') ?
+ (double) sexa (s2) : (double) vot_atof (s2));
+
+ return (OK);
+ } else
+ return (ERR);
+
+}
+
+
+/**
+ * VOA_RESOLVEFIELD -- Resolve an object field name to a position in decimal
+ * degrees.
+ */
+static int
+voa_resolveField (char *field, double *ra, double *dec)
+{
+ Sesame sr;
+ extern char *vo_urlEncode();
+
+
+ if ((sr = voc_nameResolver (vo_urlEncode (field))) != 0) {
+ *ra = (double) voc_resolverRA (sr);
+ *dec = (double) voc_resolverDEC (sr);
+ }
+ return ((sr > 0) ? OK : ERR);
+}
+
+
+/**
+ * VOA_GETSIZE -- Convert an argument size spec into a decimal degree value.
+ */
+static double
+voa_getSize (char *arg)
+{
+ int len = strlen (arg);
+ int unit = 'd';
+ double size = (double) 0.0;
+
+
+ if (isalpha ((int) arg[len-1]) && arg[len-1] != '.') {
+ unit = tolower (arg[len-1]);
+ if (strchr ("mdsMDS", unit) == NULL) {
+ fprintf (stderr, "Error: Invalid size unit '%c'\n", unit);
+ return (size);
+ }
+ arg[len-1] = '\0';
+ }
+
+ /* Convert to decimal degrees for the query.
+ */
+ switch (unit) {
+ case 'd': return ( vot_atof (arg) );
+ case 'm': return ( vot_atof (arg) / 60. );
+ case 's': return ( vot_atof (arg) / 3600. );
+ }
+
+ return ((double) 0.0);
+}
diff --git a/vendor/voclient/voapps/vocatalog.c b/vendor/voclient/voapps/vocatalog.c
new file mode 100644
index 00000000..9e0b303b
--- /dev/null
+++ b/vendor/voclient/voapps/vocatalog.c
@@ -0,0 +1,155 @@
+/**
+ * VOCATALOG -- Query all VO Catalog services
+ *
+ * Usage:
+ * vocatalog [<opts>] [ <object> | <ra> <dec> ] [ <size> ]
+ *
+ * @file vocatalog.c
+ * @author Mike Fitzpatrick
+ * @date 2/03/13
+ *
+ * @brief Query all VO Image services.
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+
+#include "votParse.h" /* keep these in order! */
+#include "voApps.h"
+
+
+/* Task specific option declarations. Task options are declared using the
+ * getopt_long(3) syntax.
+ */
+int vodata (int argc, char **argv, size_t *len, void **result);
+int vocatalog (int argc, char **argv, size_t *len, void **result);
+
+static Task self = { "vocatalog", vocatalog, 0, 0, 0 };
+
+extern void vot_setArg (char **argv, int *argc, char *value);
+
+static void Usage (void);
+static void Tests (char *input);
+
+
+/**
+ * Application entry point. All VOApps tasks MUST contain this
+ * method signature.
+ */
+int
+vocatalog (int argc, char **argv, size_t *reslen, void **result)
+{
+ char *pargv[argc+2];
+ int i, narg = 0, status = OK;
+
+
+ /* Initialize result object whether we return an object or not.
+ */
+ *reslen = 0;
+ *result = NULL;
+
+ /* Do a quick check of the args so we can provide a task-local
+ * help and test option. Otherwise, we simply pass thru all the
+ * args to VODATA for processing.
+ */
+ if (strncmp (argv[1],"-h",2) == 0 || strncmp (argv[1],"--help",6) == 0) {
+ Usage (); return (OK);
+ }
+ if (strncmp (argv[1],"-%",2) == 0 || strncmp (argv[1],"--test",6) == 0) {
+ Tests (NULL); return (self.nfail);
+ }
+
+ /* Initialize the new argument vector.
+ */
+ vot_setArg (pargv, &narg, argv[0]);
+ vot_setArg (pargv, &narg, "--type=catalog");
+ for (i=1; i < argc; i++)
+ vot_setArg (pargv, &narg, argv[i]);
+
+
+ /**
+ * The VODATA task does all the real work, we effectively just set the
+ * "-t catalog" option to force the service type as a logical naming
+ * convenience for the user. Note that return parameters are handled
+ * by vodata as well so there is no processing required here.
+ */
+ status = vodata (narg, pargv, reslen, result);
+
+
+ /* Clean up. Rememebr to free whatever pointers were created when
+ * parsing arguments.
+ */
+ for (i=0; i < (argc + 2); i++)
+ free ((void *) pargv[i]);
+
+ return (status);
+}
+
+
+/**
+ * USAGE -- Print task help summary.
+ */
+static void
+Usage (void)
+{
+ fprintf (stderr, "\n Usage:\n\t"
+ "vocatalog [<opts>] votable.xml\n\n"
+ " where\n"
+ " -%%,--test run unit tests\n"
+ " -h,--help this message\n"
+ "\n"
+ " <opts> includes all valid VODATA options\n"
+ "\n"
+ " Examples:\n\n"
+ " 1) Query the GSC 2.3 catalog for stars a) within the 0.1 \n"
+ " degree default search size around NGC 1234: b) around all\n"
+ " positions contained in file 'pos.txt': c) for the list \n"
+ " of objects given on the command line: d) query a list of\n"
+ " services for a list of positions: e) print a count of \n"
+ " results that would be returned from 3 services for each\n"
+ " position in a file:\n\n"
+ " %% vocatalog gsc2.3 ngc1234 (a)\n"
+ " %% vocatalog gsc2.3 pos.txt (b)\n"
+ " %% vocatalog gsc2.3 m31,m51,m93 (c)\n"
+ " %% vocatalog svcs.txt pos.txt (d)\n"
+ " %% vocatalog hst,chandra,gsc2.3 pos.txt (e)\n"
+ "\n"
+ " 2) Print a count of X-ray catalog data around Abell2712:\n\n"
+ " %% vocatalog -c -b x-ray any abell2712\n"
+ " %% vocatalog --count -b x-ray any abell2712\n"
+ "\n"
+ );
+}
+
+
+/**
+ * Tests -- Task unit tests.
+ */
+static void
+Tests (char *input)
+{
+ Task *task = &self;
+
+ vo_taskTest (task, "--help", NULL);
+
+ vo_taskTestFile ("m31\nm51\nm93\n", "pos.txt");
+ vo_taskTestFile ("hst\nchandra\ngsc2.3\n", "svcs.txt");
+
+ vo_taskTest (task, "gsc2.3", "ngc1234", NULL); // Ex 1
+ vo_taskTest (task, "gsc2.3", "pos.txt", NULL);
+ vo_taskTest (task, "gsc2.3", "m31,m51,m93", NULL);
+ vo_taskTest (task, "svcs.txt", "pos.txt", NULL);
+ vo_taskTest (task, "hst,chandra,gsc2.3", "pos.txt", NULL);
+
+ vo_taskTest (task, "-c", "-b", "x-ray", "any", "abell2712", NULL); // Ex 2
+ vo_taskTest (task, "--count", "-b", "x-ray", "any", "abell2712", NULL);
+
+
+ if (access ("pos.txt", F_OK) == 0) unlink ("pos.txt");
+ if (access ("svcs.txt", F_OK) == 0) unlink ("svcs.txt");
+
+ vo_taskTestReport (self);
+}
diff --git a/vendor/voclient/voapps/voclient_test b/vendor/voclient/voapps/voclient_test
new file mode 100755
index 00000000..7f056f9b
--- /dev/null
+++ b/vendor/voclient/voapps/voclient_test
@@ -0,0 +1,29 @@
+#!/bin/csh -f
+
+set nf = 0
+
+date
+
+voatlas -% ; set nf = `expr $nf + $status`
+vocatalog -% ; set nf = `expr $nf + $status`
+vodata -% ; set nf = `expr $nf + $status`
+voimage -% ; set nf = `expr $nf + $status`
+voiminfo -% ; set nf = `expr $nf + $status`
+voregistry -% ; set nf = `expr $nf + $status`
+vosamp -% ; set nf = `expr $nf + $status`
+vosesame -% ; set nf = `expr $nf + $status`
+vosloanspec -% ; set nf = `expr $nf + $status`
+vospectra -% ; set nf = `expr $nf + $status`
+votcnv -% data/ned.xml ; set nf = `expr $nf + $status`
+votget -% data/sia.xml ; set nf = `expr $nf + $status`
+votinfo -% data/ned.xml ; set nf = `expr $nf + $status`
+votopic -% ; set nf = `expr $nf + $status`
+votpos -% data/ned.xml ; set nf = `expr $nf + $status`
+votsort -% data/sort.xml ; set nf = `expr $nf + $status`
+
+echo ""
+echo ""
+echo "NFailed = $nf"
+echo ""
+
+date
diff --git a/vendor/voclient/voapps/vodata.c b/vendor/voclient/voapps/vodata.c
new file mode 100644
index 00000000..71614133
--- /dev/null
+++ b/vendor/voclient/voapps/vodata.c
@@ -0,0 +1,2387 @@
+/**
+ * VODATA -- Query VO Data services (Cone, SIAP, etc)
+ *
+ * Usage: vodata [-<flags>] [<service>] [object|file|position]
+ *
+ * Where
+ * -%%,--test run unit tests
+ * -h,--nelp this message
+ * -d,--debug enable debug messages
+ * -r,--return return result from method
+ *
+ *
+ *
+ *
+ * @file vodata.c
+ * @author Mike Fitzpatrick
+ * @date 7/13/07
+ *
+ * @brief Query VO Data services (Cone, SIAP, etc)
+ */
+
+#include <pthread.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+#include <string.h>
+#include <ctype.h>
+#include <getopt.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <sys/ipc.h>
+#include <sys/sem.h>
+#include <sys/time.h>
+#include <time.h>
+#include "VOClient.h"
+#include "voAppsP.h"
+#include "samp.h"
+
+
+
+
+#define VOD_DEBUG (getenv("VOD_DBG")||access("/tmp/VOD_DBG",F_OK)==0)
+
+
+/* Task structure.
+ */
+typedef struct {
+ char *name; /* task name */
+ int (*func)(int argc, char **argv, size_t *len, void **result);
+
+ int ntests; /* number of unit tests */
+ int npass; /* number of passed tests */
+ int nfail; /* number of failed tests */
+} Task;
+
+
+
+/* Local processing definitions.
+*/
+svcParams pars[MAX_THREADS]; /* parameter array */
+
+int format = F_CSV; /* output format */
+int apos = 0; /* argv position */
+int sv_apos = -1; /* saved argv position */
+int nservices = 0; /* num. of cone services */
+int nobjects = 0; /* num. objects to query */
+int filenum = 0; /* download file number */
+int rd_stdin = 0; /* reading from stdin? */
+int wr_stdout = 0; /* writing to stdout? */
+int do_votable = 0; /* output a Resource VOTable */
+int svcNumber = -1; /* service number to call */
+int dalOnly = 1; /* only query DAL services? */
+int simple_out = 0; /* use simple output name? */
+
+int inventory = FALSE; /* do inventory? */
+int quiet = FALSE; /* no output at all? */
+int verbose = TRUE; /* DAL verbose level */
+int all_data = FALSE; /* get all the data? */
+int file_get = FALSE; /* file number to get */
+#ifdef REG10_KLUDGE
+int reg10 = FALSE; /* use Registry 1.0 scheme? */
+#endif
+int raw_vizier = FALSE; /* use Registry 1.0 scheme? */
+int count = TRUE; /* return count of results */
+int meta = FALSE; /* metadata return? */
+int extract = EX_NONE; /* extract pos/acrefs? */
+int count_only = FALSE; /* print only matched records? */
+int save_res = TRUE; /* save results? */
+int all_named = FALSE; /* all objects named? */
+int use_name = FALSE; /* use object name in output? */
+int url_proc = FALSE; /* processing URLs only? */
+int force_svc = FALSE; /* assume URLs are ServiceURLs? */
+int svc_list = FALSE; /* list services queried */
+int obj_list = FALSE; /* list objects queried */
+int fixed_svc = FALSE; /* service is fixed on cmdline */
+int fixed_obj = FALSE; /* object is fixed on cmdline */
+int fixed_pos = FALSE; /* position is fixed on cmdline */
+int data_type = DT_ANY; /* data type */
+int proxy = FALSE; /* use proxy server */
+int res_all = FALSE; /* print all results? */
+int force_read = FALSE; /* force reading of input table */
+int longlines = FALSE; /* output long lines? */
+int iportal = FALSE; /* iportal support? */
+int numout = FALSE; /* numeric output sorting? */
+int samp = FALSE; /* broadcast table via SAMP */
+
+int max_download= DEF_DOWNLOADS; /* max download procs to run */
+int max_procs = DEF_NPROCS; /* max children to run */
+int max_threads = DEF_NTHREADS; /* max threads to run */
+
+int table_hskip = 0; /* no. of table eeader to skip */
+int table_nlines= 0; /* max lines of table to read */
+int table_sample= 1; /* table sample */
+
+int group = 0; /* resolve identifiers in groups*/
+int nterms = 0; /* No. of terms */
+char *terms[128]; /* search terms */
+
+char *typestr = (char *) NULL; /* service type string */
+char *bpass = (char *) NULL; /* bandpass type string */
+char *output = (char *) NULL; /* root output filename */
+char *delim = " \t,|;"; /* input table delimiter */
+char *cols = "1,2"; /* input table columns */
+char *ecols = (char *) NULL; /* input table exact columns */
+char *sources = (char *) NULL; /* source file */
+char *resources = (char *) NULL; /* resource file */
+char *sampName = (char *) NULL; /* SAMP appName */
+
+char *d2_band = (char *) NULL; /* DAL2 BAND parameter */
+char *d2_time = (char *) NULL; /* DAL2 TIME parameter */
+char *d2_format = (char *) NULL; /* DAL2 FORMAT parameter */
+char *d2_version = (char *) NULL; /* DAL2 VERSION parameter */
+
+char *tmpdir = "/tmp/"; /* temp directory */
+char wrkdir[SZ_FNAME]; /* working directory */
+
+double sr = DEF_SR; /* default search radius */
+
+int dverbose = 0; /* verbose debug output? */
+int debug = 0; /* debug output? */
+int samp_p = 0; /* SAMP interface handler */
+
+static int status = OK; /* return status */
+
+
+time_t rs_time = (time_t) 0,
+ re_time = (time_t) 0; /* reg/obj resolution times */
+time_t qs_time = (time_t) 0,
+ qe_time = (time_t) 0; /* data query times */
+time_t as_time = (time_t) 0,
+ ae_time = (time_t) 0; /* data access times */
+
+Service *svcList, *svcTail; /* Service linked list */
+Object *objList, *objTail; /* Obj/Posn linked list */
+Acref *acList, *acTail; /* Acref linked list */
+int nacrefs = 0; /* no. of acrefs */
+
+FILE *arg_fd = (FILE *) NULL; /* argument-file descriptor */
+
+
+/* KML Options.
+*/
+int kml_max = 50, /* max placemarks to write */
+ kml_sample = 0, /* output sample step */
+ kml_region = TRUE, /* draw bounding region poly */
+ kml_verbose = TRUE, /* verbose labels */
+ kml_label = TRUE, /* draw placemark labels */
+ kml_byObj = TRUE, /* group by object/position */
+ kml_bySvc = FALSE, /* group by service name */
+ kml_byBoth = FALSE; /* group by both */
+
+/* HTML Options.
+*/
+int html_header = TRUE, /* print a HTML header on page */
+ html_border = TRUE, /* put a border on the table? */
+ html_color = TRUE; /* colorize the table */
+
+
+extern int errno; /* system error code */
+
+extern int ra_col, ra_span, /* table input */
+ dec_col, dec_span,
+ id_col, id_span;
+extern int svcIndex, objIndex;
+
+extern int isDecimal (char *s);
+extern int isSexagesimal (char *s);
+
+extern int vot_parseObjectList (char *list, int isCmdLine);
+extern int vot_countObjectList (void);
+extern int vot_parseServiceList (char *list, int dalOnly);
+extern int vot_countServiceList (void);
+extern int vot_decodeRanges (char *range_string, int *ranges, int max_ranges,
+ int *nvalues);
+extern int is_in_range (int ranges[], int number);
+extern int vot_atoi (char *v);
+
+extern void vot_addToAclist (char *url, char *fname);
+extern void vot_procAclist (void);
+extern void vot_freeAclist (void);
+extern void vot_freeServiceList (void);
+extern void vot_resetServiceCounters (void);
+extern void vot_freeObjectList (void);
+extern void vot_printCountHdr (void);
+extern void vot_readObjFile (char *fname);
+extern void vot_readSvcFile (char *fname, int dalOnly);
+
+extern double vot_atof (char *v);
+
+/* Tasking execution procedure.
+ */
+extern int vo_runTask (char *method, Task *apps, int argc, char **argv,
+ size_t *len, void **result);
+extern int vo_taskTest (Task *self, char *arg, ...);
+extern void vo_taskTestFile (char *str, char *fname);
+extern void vo_taskTestReport (Task self);
+
+extern int vo_setResultFromFile (char *fname, size_t *len, void **data);
+extern int vo_setResultFromString (char *str, size_t *len, void **data);
+extern int vo_setResultFromInt (int value, size_t *len, void **data);
+extern int vo_setResultFromReal (float value, size_t *len, void **data);
+extern int vo_appendResultFromString (char *str, size_t *len, void **data,
+ size_t *maxlen);
+
+
+#ifdef VO_INVENTORY
+extern char *vot_doInventory (void);
+#endif
+extern char *vot_urlFname (char *url);
+extern char *vot_getOFName (svcParams *pars, char *extn, int pid);
+extern char *vot_getOFIndex (svcParams *pars, char *extn, int pid);
+extern char *vot_normalize (char *str);
+extern char *vot_svcTypeCode (int type);
+
+static int vot_parseArgToken (char *arg, char *next, int pos, int *inc);
+static int vot_validateOptions (void);
+static int vot_getNextCmdline (void);
+static void vot_runSvcThreads (void);
+static void vot_printProcStat (Proc *procList, char *svc_name, int fail_only);
+static void vot_setProcStat (Service *svc, int pid, int status);
+
+static void vot_printProcTime ();
+static char *vot_requiredArg (char *arg);
+static char *vot_optionalArg (char *arg);
+static char vot_setArgWord (char *arg, char *val);
+static char *vot_stat2code (int status);
+static char *vizPatch (char *url);
+/*
+static char *vot_cnvType (char *intype);
+*/
+
+static void vot_printUsage (void);
+static void vot_printExamples (void);
+
+void *vot_procObjs (void *arg);
+void vot_printSvcList (Service *sl);
+void vot_printSvcHdr (void);
+
+
+pthread_mutex_t svc_mutex = PTHREAD_MUTEX_INITIALIZER;
+
+
+/* Task specific option declarations.
+ */
+int vodata (int argc, char **argv, size_t *len, void **result);
+
+static int mf = 0;
+static Task self = { "vodata", vodata, 0, 0, 0 };
+
+/* Note: the leading ':' in the opts string is required to suppress errors
+ */
+static char *opts = ":%hrNSACFHIKMO:RTVXab:ce:fgi:mno:p:qr:s:t:uv";
+
+static struct option long_opts[] = {
+ { "test", 2, 0, '%' }, /* test (std) */
+ { "help", 2, 0, 'h' }, /* help (std) */
+ { "return", 2, 0, 'r' }, /* return (std) */
+
+ { "numeric", 2, 0, 'N' }, /* numeric output name */
+ { "simple", 2, 0, 'S' }, /* simple output name */
+
+ { "ascii", 2, 0, 'A' }, /* ASCII output */
+ { "csv", 2, 0, 'C' }, /* CSV output */
+ { "fits", 2, 0, 'F' }, /* FITS table output */
+ { "html", 2, 0, 'H' }, /* HTML output */
+ { "inventory", 2, 0, 'I' }, /* inventory (not used) */
+ { "kml", 2, 0, 'K' }, /* KML output */
+ { "verbmeta", 2, 0, 'M' }, /* verbose metadata */
+ { "output", 2, 0, 'O' }, /* root output name */
+ { "raw", 2, 0, 'R' }, /* Raw output */
+ { "tsv", 2, 0, 'T' }, /* TSV output */
+ { "votable", 2, 0, 'V' }, /* VOTable output */
+ { "xml", 2, 0, 'X' }, /* XML output */
+
+ { "all", 0, 0, 'a' }, /* all data */
+ { "bandpass", 1, 0, 'b' }, /* bandpass */
+ { "count", 2, 0, 'c' }, /* count results */
+ { "debug", 2, 0, 'd' }, /* debug */
+ { "extract", 1, 0, 'e' }, /* extract */
+ { "force", 2, 0, 'f' }, /* force table read */
+ { "get", 2, 0, 'g' }, /* get specific results */
+ { "input", 1, 0, 'i' }, /* get args from input file */
+ { "meta", 2, 0, 'm' }, /* metadata */
+ { "nosave", 2, 0, 'n' }, /* no-save results */
+ { "object", 1, 0, 'o' }, /* query object name */
+ { "pos", 1, 0, 'p' }, /* query position */
+ { "quiet", 2, 0, 'q' }, /* suppress output */
+ { "sr", 1, 0, 'r' }, /* search radius */
+ { "svc", 1, 0, 's' }, /* data service */
+ { "type", 1, 0, 't' }, /* type string */
+ { "url", 2, 0, 'u' }, /* url download */
+ { "verbose", 2, 0, 'v' }, /* verbose */
+
+ { "bandpass", 1, &mf, 1 }, /* req'd arg word */
+ { "cols", 1, &mf, 2 }, /* req'd arg word */
+ { "ecols", 1, &mf, 3 }, /* req'd arg word */
+ { "delim", 1, &mf, 4 }, /* req'd arg word */
+ { "kml", 1, &mf, 5 }, /* req'd arg word */
+ { "max", 1, &mf, 6 }, /* req'd arg word */
+ { "nlines", 1, &mf, 7 }, /* req'd arg word */
+ { "object", 1, &mf, 8 }, /* req'd arg word */
+ { "output", 1, &mf, 9 }, /* req'd arg word */
+ { "pos", 1, &mf, 10 }, /* req'd arg word */
+ { "sample", 1, &mf, 11 }, /* req'd arg word */
+ { "svc", 1, &mf, 12 }, /* req'd arg word */
+ { "type", 1, &mf, 13 }, /* req'd arg word */
+ { "web", 1, &mf, 15 }, /* req'd arg word */
+ { "band", 1, &mf, 16 }, /* req'd arg word */
+ { "time", 1, &mf, 17 }, /* req'd arg word */
+ { "format", 1, &mf, 18 }, /* req'd arg word */
+ { "version", 1, &mf, 19 }, /* req'd arg word */
+
+ { "onefile", 2, &mf, 20 }, /* one-file output */
+ { "extract", 2, &mf, 21 }, /* opt arg word */
+ { "ep", 2, &mf, 22 }, /* opt arg word */
+ { "eu", 2, &mf, 23 }, /* opt arg word */
+ { "eh", 2, &mf, 24 }, /* opt arg word */
+ { "ek", 2, &mf, 25 }, /* opt arg word */
+ { "eK", 2, &mf, 26 }, /* opt arg word */
+ { "hskip", 2, &mf, 27 }, /* opt arg word */
+
+ { "wh", 2, &mf, 30 }, /* opt arg word */
+ { "wb", 2, &mf, 31 }, /* opt arg word */
+ { "wc", 2, &mf, 32 }, /* opt arg word */
+
+ { "webborder", 2, &mf, 40 }, /* no arg word */
+ { "webheader", 2, &mf, 41 }, /* no arg word */
+ { "webcolor", 2, &mf, 42 }, /* no arg word */
+ { "webnoborder", 2, &mf, 43 }, /* no arg word */
+ { "webnoheader", 2, &mf, 44 }, /* no arg word */
+ { "webnocolor", 2, &mf, 45 }, /* no arg word */
+ { "vverbose", 0, &mf, 46 }, /* no arg word */
+
+ { "debug", 0, &mf, 99 }, /* no arg word */
+
+ { NULL, 0, 0, 0 }
+};
+
+extern char **vo_paramInit (int argc, char *argv[],
+ char *opts, struct option long_opts[]);
+extern int vo_paramNext (char *opts, struct option long_opts[],
+ int argc, char *argv[], char *optval, int *posindex);
+extern void vo_paramFree (int argc, char *argv[]);
+
+
+static void Usage (void);
+static void Tests (char *input);
+
+
+
+
+
+/************************************************************************
+** Program main()
+*/
+int
+vodata (int argc, char *argv[], size_t *reslen, void **result)
+{
+ int i, ch, pos=0;
+ char *eval, *argfile, *next_arg, posn[SZ_LINE];
+ char **pargv, optval[SZ_FNAME];
+
+
+ /* Initialize the VOClient code. Error messages are printed by the
+ ** interface so we just quit if there is a problem.
+ */
+ if (voc_initVOClient ("runid=voc.vodata") == ERR) {
+ fprintf (stderr, "Error: cannot connect to VOClient daemon\n");
+ return (ERR);
+ }
+
+
+ /* Initialize the global structs.
+ */
+ memset (&colRange, 0, sizeof (Range));
+ memset (&rowRange, 0, sizeof (Range));
+ memset (&fileRange, 0, sizeof (Range));
+ colRange.nvalues = RANGE_ALL;
+ rowRange.nvalues = RANGE_ALL;
+ fileRange.nvalues = RANGE_NONE;
+
+
+ /* Get some environment definitions. We allow the command-line flags
+ ** to override these values.
+ */
+ if ((eval = getenv("VOC_MAX_DOWNLOADS")))
+ max_download = vot_atoi (eval);
+ if ((eval = getenv("VOC_MAX_PROCS")))
+ max_procs = vot_atoi (eval);
+ if ((eval = getenv("VOC_MAX_THREADS")))
+ max_threads = vot_atoi (eval);
+
+
+ /* Initializations.
+ */
+ *reslen = 0;
+ *result = NULL;
+ apos = 0;
+ svcIndex = 0;
+ objIndex = 0;
+ all_data = 0;
+
+
+ rs_time = time ((time_t) NULL);
+
+ /* Now process the command line arguments.
+ */
+ if (VOD_DEBUG) {
+ fprintf (stderr, "Command:");
+ for (i=0; i < argc; i++) fprintf (stderr, " '%s'", argv[i]);
+ fprintf (stderr, "\n");
+ for (i=0; i < argc; i++) fprintf (stderr, "%s ", argv[i]);
+ fprintf (stderr, "\n\n");
+ }
+
+
+
+ /* Parse the argument list.
+ */
+ pargv = vo_paramInit (argc, argv, opts, long_opts);
+ for (i=1; i < argc; i++) {
+
+ memset (optval, 0, SZ_FNAME);
+ ch = vo_paramNext (opts, long_opts, argc, pargv, optval, &pos);
+#ifdef PARAM_DBG
+ fprintf (stderr, "ch = '%c' %d optval = '%s'\n",
+ ch, ch, (optval[0] ? optval : "N/A"));
+#endif
+
+ if (ch > 0) {
+ switch (ch) {
+ case '?': /* unknown */
+ break;
+
+ case 'h': /* help */
+ Usage ();
+ voc_closeVOClient (0);
+ return (OK);
+
+ case '%': /* unit tests */
+ voc_closeVOClient (0);
+ Tests (optval);
+ return (self.nfail);
+
+ case 'N': /* numeric output name */
+ numout++;
+ break;
+ case 'S': /* simple output name */
+ simple_out++;
+ break;
+
+ case 'A': /* ASCII output */
+ format = F_ASCII;
+ break;
+ case 'C': /* CSV output */
+ format = F_CSV;
+ break;
+ case 'F': /* FITS table output */
+ fprintf (stderr,
+ "FITS tables not yet implemented, using ASCII\n");
+ format = F_ASCII;
+ break;
+ case 'H': /* HTML output */
+ extract |= EX_HTML;
+ format = F_CSV | F_HTML;
+ if (output && output[0] == '-')
+ extract |= EX_COLLECT;
+ break;
+#ifdef VO_INVENTORY
+ case 'I': /* inventory count */
+ inventory++;
+ count++;
+ break;
+#endif
+ case 'K': /* KML output */
+ extract |= EX_KML;
+ format = F_CSV | F_KML;
+ break;
+ case 'R': /* RAW output */
+ case 'V': /* VOTable output */
+ format = F_RAW;
+ if (output && output[0] == '-')
+ extract |= EX_COLLECT;
+ break;
+ case 'T': /* TSV output */
+ format = F_TSV;
+ break;
+ case 'X': /* XML output */
+ extract |= EX_XML;
+ format = F_RAW | F_XML;
+ if (output && output[0] == '-')
+ extract |= EX_COLLECT;
+ break;
+
+ case 'O': /* root output name */
+ //VOT_NEXTARG(argc,argv,i);
+ output = strdup (optval);
+ if (output[0] == '-') {
+ wr_stdout++;
+ quiet++;
+ if ((extract & EX_XML) || (extract & EX_KML))
+ extract |= EX_COLLECT;
+
+ memset (wrkdir, 0, SZ_FNAME);
+ sprintf (wrkdir, "%s/vod%d", tmpdir, (int)getpid());
+ if (access (wrkdir, R_OK|W_OK) != 0)
+ mkdir (wrkdir, (mode_t)0666);
+ chdir (wrkdir);
+ }
+ break;
+
+ case 'a': /* all data */
+ all_data++;
+ res_all++;
+ /*sr = -1.0; */ /* flag to get all data */
+ break;
+ case 'b': /* forced type string */
+ if (optval[0] == '/' || isdigit(optval[0]))
+ d2_band = strdup (optval);
+ else
+ if (strncasecmp (optval, "any", 3) != 0)
+ bpass = strdup (optval);
+ break;
+ case 'c':
+ count++;
+ count_only = TRUE;
+ break;
+
+ case 'e': /* extract pos/acrefs? */
+ if (strncmp (optval, "pos", 3) == 0)
+ extract |= EX_POS;
+ else if (strncmp (optval, "url", 3) == 0)
+ extract |= EX_ACREF;
+ else if (strncmp (optval, "head", 4) == 0)
+ extract |= EX_HTML;
+ else if (strncmp (optval, "kml", 3) == 0)
+ extract |= EX_KML;
+ else if (strncmp (optval, "xml", 3) == 0)
+ extract |= EX_XML;
+ else if (strncmp (optval, "all", 3) == 0)
+ extract = EX_ALL;
+ else
+ extract = EX_ALL, i++;
+ break;
+
+ case 'f': /* force table read */
+ force_read++;
+ break;
+
+ case 'g': /* get specific results */
+ extract |= EX_ACREF;
+ fileRange.nvalues = RANGE_ALL;
+ file_get = RANGE_ALL;
+ break;
+
+ case 'i': /* take remaining args from file */
+ VOT_NEXTARG(argc,argv,i);
+ sv_apos = apos;
+ argfile = strdup (argv[++i]);
+ if (argfile[0] == '-') {
+ if (strlen (argfile) > 1) {
+ fprintf (stderr, "ERROR: the '-i' flag requires ");
+ fprintf (stderr, "a filename or '-' for stdin\n");
+ exit (1);
+ } else if (rd_stdin) {
+ fprintf (stderr,
+ "ERROR: stdin can only be used once\n");
+ exit (1);
+ } else {
+ rd_stdin++;
+ arg_fd = stdin;
+ }
+
+ } else {
+ if (access (argfile, R_OK) == 0) {
+ /* Open the file, we'll process it below.
+ */
+ if ((arg_fd = fopen(argfile,"r")) == (FILE *)NULL) {
+ fprintf (stderr,
+ "ERROR: Cannot open file '%s'\n", argfile);
+ return (ERR);
+ }
+ }
+ }
+ break;
+
+ case 'M': /* verbose meta */
+ meta++, verbose = 3;
+ res_all++;
+ break;
+ case 'm': /* meta flag */
+ meta++;
+ res_all++;
+ break;
+
+ case 'n': /* no-save results */
+ save_res = FALSE;
+ count_only = TRUE;
+ break;
+
+ case 'o': /* query object name */
+ VOT_NEXTARG(argc,argv,i);
+ use_name++;
+ next_arg = argv[i+1];
+ if (next_arg[0] == '-') {
+ if (rd_stdin) {
+ fprintf (stderr,
+ "ERROR: stdin can only be used once\n");
+ exit (1);
+
+ } else {
+ rd_stdin++;
+ fixed_obj++;
+ vot_readObjFile ("-");
+ }
+ i++; /* advance argv */
+ } else if (inventory) {
+ vot_parseObjectList (argv[++i], TRUE);
+ sources = strdup (argv[i]);
+ if (debug)
+ fprintf (stderr, "setting 'obj' sources = '%s'\n",
+ sources);
+ apos++;
+ } else
+ vot_parseObjectList (argv[++i], TRUE);
+ if (svcList)
+ apos++;
+ break;
+
+ case 'p': /* query position */
+ //VOT_NEXTARG(argc,argv,i);
+ next_arg = argv[i+1];
+ memset (posn, 0, SZ_LINE);
+ if (next_arg[0] == '-') {
+ if (strlen (next_arg) > 1) {
+ fprintf (stderr,"ERROR: the '-p' flag requires");
+ fprintf (stderr," coords or '-' for stdin\n");
+ return (ERR);
+ } else if (rd_stdin) {
+ fprintf(stderr, "ERROR: stdin can only be used once\n");
+ exit (1);
+ } else {
+ rd_stdin++, fixed_pos++;
+ vot_readObjFile ("-");
+ }
+ i++; /* advance argv */
+ } else {
+ if (isSexagesimal(optval) || isDecimal(optval)) {
+ vot_parseObjectList (optval, TRUE);
+ } else if (inventory) {
+ vot_parseObjectList (optval, TRUE);
+ sources = strdup (optval);
+ if (debug)
+ fprintf (stderr,
+ "setting pos sources='%s'\n", sources);
+ } else
+ vot_parseObjectList (optval, TRUE);
+ fixed_pos++;
+ }
+ break;
+
+ case 'q':
+ quiet++;
+ break;
+
+ case 'r': /* search radius */
+ VOT_NEXTARG(argc,argv,i);
+ sr = vot_atof (argv[++i]);
+ break;
+
+ case 's': /* data service */
+ VOT_NEXTARG(argc,argv,i);
+ if (strncmp (argv[i+1], "http", 4) == 0)
+ force_svc++;
+ next_arg = argv[i+1];
+ if (next_arg[0] == '-') {
+ if (strlen (next_arg) > 1) {
+ fprintf(stderr,"ERROR: the '-s' flag requires ");
+ fprintf(stderr,"a service name or '-' for stdin\n");
+ exit (1);
+ } else
+ vot_readSvcFile ("-", dalOnly);
+ i++; /* advance argv */
+ } else if (isdigit (argv[i+1][0])) {
+ svcNumber = vot_atoi (argv[++i]);
+ vot_parseServiceList ((resources = strdup (argv[++i])),
+ dalOnly);
+ if (debug)
+ fprintf (stderr, "setting resources = '%s'\n",
+ resources);
+ } else {
+ vot_parseServiceList ((resources = strdup (argv[++i])),
+ dalOnly);
+ if (debug)
+ fprintf (stderr, "setting resources = '%s'\n",
+ resources);
+ }
+ fixed_svc++;
+ apos++;
+ break;
+
+ case 't': /* forced type string */
+ //VOT_NEXTARG(argc,argv,i);
+ if (strncasecmp (optval, "any", 3) != 0)
+ typestr = strdup (optval), i++;
+ break;
+
+ case 'u': /* forced url download */
+ url_proc++;
+ break;
+
+ case 'v': /* verbose flag */
+ verbose = min(3,(verbose+1));
+ break;
+ }
+
+ } else if (ch == 0) {
+ if ((ch=vot_setArgWord((char *)long_opts[pos].name, optval)) == 0) {
+ fprintf (stderr, "unknown long option '%s'\n",
+ long_opts[pos].name);
+ status = ERR;
+ goto cleanup_;
+ }
+
+
+#ifdef ENG_FLAGS
+ } else if (argv[i][0] == '+') {
+ len = strlen (argv[i]); /* "Engineering" flags. */
+ for (j=1; j < len; j++) {
+ switch (argv[i][j]) {
+ case 's':
+ table_hskip = vot_atoi (argv[++i]);
+ break;
+ case 'S':
+ samp++;
+ sampName = strdup (argv[++i]);
+ break;
+ case 'i':
+ iportal++;
+ break;
+ case 'd':
+ debug++;
+ break;
+ case 'l':
+ svc_list = 1;
+ obj_list = 1;
+ break;
+ case 'q':
+ quiet = 0;
+ break;
+ case 'a': /* null all flag */
+ break;
+ case 'n': /* null flag */
+ break;
+
+#ifdef REG10_KLUDGE
+ case 'r':
+ reg10++;
+ break;
+#endif
+ case 'r':
+ raw_vizier = TRUE;
+ break;
+ case 't':
+ tmpdir = strdup (argv[++i]);
+ break;
+ case 'v':
+ dverbose++;
+ break;
+ }
+ }
+#endif
+
+ } else {
+ /* Parse the arguments according to an assumed calling
+ ** order, e.g.
+ **
+ ** vodata [ url_list | [ resource [obj | ra dec] [sr] ]
+ **
+ ** By default we assume 'sr' is in degrees, the ra/dec will
+ ** be assumed to be ICRS J200 and may be sexagesimal or decimal.
+ ** Since we're parsing the argv[], be sure to take into account
+ ** any increments added because of consumed arguments.
+ */
+ int inc = 0;
+
+ for ( ; i < argc; i++) {
+//if (i > 2 && apos == 0) i--;
+//fprintf (stderr, "pos: '%s' '%s' apos=%d i=%d\n", argv[i], argv[i+1], apos, i);
+ if (vot_parseArgToken (argv[i], argv[i+1], apos, &inc) != OK) {
+ exit (1);
+ } else
+ i += inc; /* add the argv[] increment */
+
+ apos++; /* update arg position */
+ }
+ }
+ }
+ re_time = time ((time_t) NULL);
+
+
+ /* Close VOClient connection. Each child process will need to reopen
+ ** their own connection, and if we're processing an argument file we'll
+ ** open/close it again as needed.
+ */
+ voc_closeVOClient (0);
+
+
+ /* If we're broadcasting the result tables, open the SAMP connection
+ ** now and let the child processes simply send the message.
+ if (samp) {
+ samp_p = sampInit ((sampname ? sampName : "VOData"),
+ "VOClient Data Access");
+ samp_setSyncMode (samp_p);
+ sampStartup (samp_p);
+ }
+ */
+
+
+ /* The control logic below allows us to process more than one
+ ** "command-line". If we got our services and objects from the
+ ** true command-line the loop will break at the bottom and we only
+ ** execute once. The service and object lists were created when
+ ** processing the arguments above. OTOH, if we're using an argument
+ ** file, those lists are now NULL and we'll read each line of the
+ ** argfile and create them now. In either case, we clean up and
+ ** reset the lists at the bottom of the loop.
+ */
+
+ while (1) {
+
+ /* If we're processing from the stdin or an argument file,
+ ** get the next line of the file and fake the commandline to
+ ** set the resource and object lists. Note we clean up and
+ ** reset below to permit each iteration to process a different
+ ** number of resources or objects.
+ */
+ if (arg_fd) {
+ if (vot_getNextCmdline () != OK)
+ break;
+ }
+
+
+ /* Tally up the the number of services and objects to be queried.
+ */
+ if ((nservices = vot_countServiceList()) == 1)
+ svc_list = 0;
+ if ((nobjects = vot_countObjectList()) == 1)
+ obj_list = 0;
+
+#ifdef VO_INVENTORY
+ /* If we're calling the Inventory service, branch to do it here and
+ ** then continue with the loop.
+ */
+ if (inventory) {
+ if (debug)
+ fprintf (stderr, "inventory nserv = %d nobj = %d\n",
+ nservices, nobjects);
+
+ if (nobjects == 0 && sources == NULL) {
+ fprintf (stderr, "No object position(s) specified.\n");
+ exit (1);
+
+ } else {
+ vot_printSvcHdr ();
+ qs_time = time ((time_t) NULL);
+ (void) vot_doInventory ();
+ qe_time = time ((time_t) NULL);
+ }
+
+ vot_printProcTime ();
+ break;
+ }
+#endif
+
+ /* If we have services to call and aren't simply downloading URLs,
+ ** process the service queries first.
+ */
+ if (svcList && !url_proc) {
+
+ /* See whether any flags negate other options.
+ */
+ if (vot_validateOptions() == ERR)
+ break;
+
+ /* Print header information.
+ */
+ vot_printSvcHdr ();
+
+ /* Now run the serice queries. Each service is run on a separate
+ ** thread, we'll handle summary output and any postprocessing later.
+ */
+ vot_runSvcThreads ();
+ }
+
+ /* Process the access reference list to download any pending data.
+ */
+ if (acList && nacrefs)
+ vot_procAclist ();
+
+ /* Free up any memory we may have allocated. Counters and pointers
+ ** are reset in each routine.
+ */
+ vot_freeAclist (); /* access reference list */
+ vot_freeObjectList (); /* object list */
+ if (sv_apos < 0)
+ vot_freeServiceList (); /* VO resource list */
+ else
+ vot_resetServiceCounters ();
+
+
+ /* Print an approximate summary of the processing time required.
+ */
+ vot_printProcTime ();
+
+ /* If we're not processing from an argument file or the
+ ** stdin, we've processed the argv from the commandline, so
+ ** break here.
+ */
+ if (!arg_fd)
+ break;
+ }
+
+
+cleanup_:
+ if (arg_fd && arg_fd != stdin) /* close the argument file */
+ fclose (arg_fd);
+
+ if (wr_stdout && wrkdir[0] && access (wrkdir, R_OK|W_OK) == 0)
+ rmdir (wrkdir); /* clean up wrkdirs */
+
+ /*
+ if (samp)
+ samp_UnRegister (samp_p);
+ */
+
+ if (bpass) free ( (void *) bpass);
+ if (typestr) free ( (void *) typestr);
+
+ if (d2_band) free ( (void *) d2_band);
+ if (d2_time) free ( (void *) d2_time);
+ if (d2_format) free ( (void *) d2_format);
+ if (d2_version) free ( (void *) d2_version);
+
+ return ( status );
+}
+
+
+
+
+/* Set an argument that may optionally be specified as an entire word.
+*/
+
+#define ARG_DONE -1
+
+static char
+vot_setArgWord (char *arg, char *val)
+{
+#ifdef PARAM_DBG
+ fprintf (stderr, "setArg = '%s' val = '%s'\n", arg, val);
+#endif
+
+ if (arg[0] == '-') {
+ fprintf (stderr, "Invalid argument string '--'\n");
+ return (0);
+ /* '--' only FLAGS */
+ } else if (strncmp (arg, "debug", 5) == 0) {
+ debug++;
+ } else if (strncmp (arg, "vdebug", 6) == 0) {
+ debug=3;
+ } else if (strncmp (arg, "bandpass", 8) == 0) {
+ bpass = vot_requiredArg (val);
+
+ } else if (strncmp (arg, "cols", 4) == 0) {
+ cols = vot_requiredArg (val);
+
+ } else if (strncmp (arg, "delim", 5) == 0) {
+ delim = vot_requiredArg (val);
+ switch (delim[0]) {
+ case 's': delim = " "; break;
+ case 'c': delim = ","; break;
+ case 't': delim = "\t"; break;
+ case 'b': delim = "|"; break;
+ }
+
+ } else if (strncmp (arg, "extract", 7) == 0) {
+
+ if (!val) { /* just "--extract" */
+ extract |= EX_ALL;
+
+ } else {
+ switch (*val) {
+ case 'h': extract |= EX_HTML; break; /* html */
+ case 'k': extract |= EX_KML; break; /* KML */
+ case 'K': extract |= EX_KML;
+ extract |= EX_COLLECT; break; /* one-file KML */
+ case 'p': extract |= EX_POS; break; /* positions */
+ case 'u': extract |= EX_ACREF; break; /* urls */
+ case 'X': extract |= EX_XML;
+ format = (F_RAW | F_XML);
+ extract |= EX_COLLECT; break; /* one-file XML */
+ default: extract = EX_BOTH; break; /* all */
+ }
+ }
+
+ } else if (strncmp (arg, "ecols", 5) == 0) {
+ ecols = vot_requiredArg (val);
+
+ } else if (strncmp (arg, "get", 3) == 0) {
+ char *ip = vot_optionalArg (val);
+
+ extract |= EX_ACREF;
+ if (ip == NULL || !(isdigit(*ip)) ) {
+ /* No option implies we get all rows.
+ */
+ fileRange.nvalues = RANGE_ALL;
+ file_get = RANGE_ALL;
+ } else {
+ /* Next arg is a range string.
+ */
+ strcpy (fileRange.rstring, ip);
+ if (vot_decodeRanges (fileRange.rstring,
+ fileRange.ranges, MAX_RANGES, &fileRange.nvalues) < 0) {
+ fprintf (stderr, "Error decoding range string.\n");
+ }
+ file_get = fileRange.nvalues;
+
+ free ( (void *) ip);
+ }
+
+ } else if (strncmp (arg, "hskip", 5) == 0) {
+ char *ip = vot_optionalArg (val);
+ if (ip) {
+ table_hskip = vot_atoi ( ip );
+ free ( (void *) ip);
+ }
+
+ } else if (strncmp (arg, "kml", 3) == 0) {
+ char *ip = vot_requiredArg (val);
+
+ switch (arg[3]) {
+ case 'm': /* max placemarks --kmlmax=N */
+ kml_max = vot_atoi(val);
+ break;
+ case 'g': /* grouping --kmlgroup=type */
+ switch (*val) {
+ case 'b': /* group by both */
+ kml_byBoth = TRUE;
+ kml_byObj = FALSE, kml_bySvc = FALSE;
+ break;
+ case 'o': /* group by object */
+ kml_byObj = TRUE;
+ kml_byBoth = FALSE, kml_bySvc = FALSE;
+ break;
+ case 's': /* group by service */
+ kml_bySvc = TRUE;
+ kml_byObj = FALSE, kml_byBoth = FALSE;
+ break;
+ }
+ break;
+ case 's': /* sample placemarks --kmlsample=N */
+ kml_sample = vot_atoi(ip);
+ break;
+
+ case 'n': /* sample placemarks --kmlno<opt> */
+ switch (arg[5]) {
+ case 'l': /* disable labels */
+ kml_label = FALSE;
+ break;
+ case 'r': /* disable region box */
+ kml_region = FALSE;
+ break;
+ case 'v': /* disable verbose label*/
+ kml_verbose = FALSE;
+ break;
+ }
+ }
+
+ if (strncmp (val, "kmlgroup", 8) == 0)
+ extract |= EX_KML;
+ if (ip)
+ free ((void *) ip);
+
+ } else if (strncmp (arg, "max", 3) == 0) {
+ char *ip = vot_requiredArg (val);
+
+ switch (arg[3]) {
+ case 'd': /* --maxdownloads=<N> */
+ max_download = vot_atoi(ip);
+ max_download = min(MAX_DOWNLOADS,max_download);
+ break;
+ case 'p': /* --maxprocs=<N> */
+ max_procs = vot_atoi(ip);
+ max_procs = min(MAX_PROCS,max_procs);
+ break;
+ case 't': /* --maxthreads=<N> */
+ max_threads = vot_atoi(ip);
+ max_threads = min(MAX_THREADS,max_threads);
+ break;
+ }
+
+ } else if (strncmp (arg, "nlines", 6) == 0) {
+ char *ip = vot_requiredArg (val);
+ table_nlines = vot_atoi ( ip );
+ if (ip)
+ free ((void *) ip);
+
+ } else if (strncmp (arg, "object", 6) == 0) {
+ char *ip = vot_requiredArg (val);
+
+ use_name++;
+ if (!ip || ip[0] == '-') {
+ if (rd_stdin) {
+ fprintf (stderr, "ERROR: stdin can only be used once\n");
+ exit (1);
+
+ } else {
+ rd_stdin++;
+ fixed_obj++;
+ vot_readObjFile ("-");
+ }
+ } else if (inventory) {
+ vot_parseObjectList (ip, TRUE);
+ sources = ip;
+ if (debug)
+ fprintf (stderr, "setting 'obj' sources = '%s'\n", sources);
+ apos++;
+ } else
+ vot_parseObjectList (ip, TRUE);
+ if (svcList)
+ apos++;
+ if (ip)
+ free ((void *) ip);
+
+ } else if (strncmp (arg, "output", 6) == 0) {
+ char *ip = vot_requiredArg (arg);
+
+ output = (ip ? ip : "=");
+ if (output[0] == '-') {
+ wr_stdout++;
+ quiet++;
+ if ((extract & EX_XML) || (extract & EX_KML))
+ extract |= EX_COLLECT;
+
+ memset (wrkdir, 0, SZ_FNAME);
+ sprintf (wrkdir, "%s/vod%d", tmpdir, (int)getpid());
+ if (access (wrkdir, R_OK|W_OK) != 0)
+ mkdir (wrkdir, (mode_t)0666);
+ chdir (wrkdir);
+ }
+ if (ip)
+ free ((void *) ip);
+
+ } else if (strncmp (arg, "pos", 3) == 0) {
+ char posn[SZ_LINE];
+ char *ip = vot_requiredArg (val);
+
+ if (ip[0] == '-') {
+ if (strlen (ip) > 1) {
+ fprintf (stderr,"ERROR: the '--pos' flag requires ");
+ fprintf (stderr,"coords or '-' for stdin\n");
+ exit (1);
+ } else if (rd_stdin) {
+ fprintf (stderr, "ERROR: stdin can only be used once\n");
+ exit (1);
+ rd_stdin++, fixed_pos++;
+ } else {
+ vot_readObjFile ("-");
+ }
+ } else {
+ char v1[SZ_FNAME], v2[SZ_FNAME], *op;
+
+ op = strchr (val, (int)','); /* find delimiter */
+ memset (v1, 0, SZ_FNAME); /* clear arrays */
+ memset (v2, 0, SZ_FNAME);
+ if (op) {
+ *op = '\0';
+ strcpy (v1, ip); /* first arg */
+ strcpy (v2, op+1); /* second arg */
+ } else {
+ fprintf (stderr, "ERROR: Invalid '--pos' argument\n");
+ exit (1);
+ }
+
+ if (isSexagesimal(v1) || isDecimal(v1)) {
+ sprintf (posn, "%s %s", v1, v2);
+ fixed_pos++;
+ vot_parseObjectList (posn, TRUE);
+ } else if (inventory) {
+ vot_parseObjectList ((sources = ip), TRUE);
+ apos++;
+ } else
+ vot_parseObjectList (ip, TRUE);
+ }
+ if (fixed_svc)
+ apos++;
+ if (ip)
+ free ((void *) ip);
+
+ } else if (strncmp (arg, "sample", 6) == 0) {
+ table_sample = vot_atoi ( vot_requiredArg (arg) );
+
+ } else if (strncmp (arg, "sr", 2) == 0) {
+ char *ip = vot_requiredArg (val);
+ int len = strlen(ip);
+ char units = ip[len-1];
+
+ if (!isdigit(units))
+ ip[len-1] = '\0';
+ else
+ units = 'd';
+ switch (units) {
+ case 's': sr = vot_atof (ip) / 3600.; break;
+ case 'm': sr = vot_atof (ip) / 60.; break;
+ case 'd': sr = vot_atof (ip); break;
+ }
+ if (ip)
+ free ((void *) ip);
+
+
+ } else if (strncmp (arg, "svc", 3) == 0) {
+ char *ip = vot_requiredArg (val);
+
+ if (strncmp (ip, "http", 4) == 0)
+ force_svc++;
+ if (ip[0] == '-') {
+ if (strlen (ip) > 1) {
+ fprintf (stderr,"ERROR: the '-s' flag requires ");
+ fprintf (stderr,"a service name or '-' for stdin\n");
+ exit (1);
+ } else
+ vot_readSvcFile ("-", dalOnly);
+ } else {
+ vot_parseServiceList ((resources = ip), dalOnly);
+ if (debug)
+ fprintf (stderr, "setting resources = '%s'\n", resources);
+ if (inventory)
+ apos++;
+ }
+ fixed_svc++;
+ apos++;
+ if (fixed_pos)
+ apos++;
+ if (ip)
+ free ((void *) ip);
+
+ } else if (strncmp (arg, "type", 4) == 0) {
+ typestr = vot_requiredArg (val);
+
+ } else if (strncmp (arg, "verbose", 7) == 0) {
+ verbose = 2;
+ } else if (strncmp (arg, "vverbose", 8) == 0) {
+ verbose = 3;
+
+ } else if (strncmp (arg, "onefile", 7) == 0) {
+ extract |= EX_COLLECT; /* one-file output */
+
+ } else if (strncmp (arg, "wb", 2) == 0 ||
+ strncmp (arg, "webnoborder", 9) == 0) {
+ html_border = FALSE; /* disable table border */
+ } else if (strncmp (arg, "webborder", 7) == 0) {
+ html_border = TRUE; /* enable table border */
+
+ } else if (strncmp (arg, "wc", 2) == 0 ||
+ strncmp (arg, "webnocolor", 9) == 0) {
+ html_color = FALSE; /* disable border color */
+ } else if (strncmp (arg, "webcolor", 9) == 0) {
+ html_color = TRUE; /* enable border color */
+
+ } else if (strncmp (arg, "wh", 2) == 0 ||
+ strncmp (arg, "webnoheader", 9) == 0) {
+ html_header = FALSE; /* disable table header */
+ } else if (strncmp (arg, "webheader", 7) == 0) {
+ html_header = TRUE; /* enable table header */
+
+
+ } else if (strncmp (arg, "web", 3) == 0) {
+ char *ip = vot_requiredArg (val);
+ switch (ip[0]) {
+ case 'b': html_border = FALSE; break; /* disable table border */
+ case 'c': html_color = FALSE; break; /* disable verbose label */
+ case 'h': html_header = FALSE; break; /* disable region box */
+ }
+ if (ip)
+ free ((void *) ip);
+ /* DAL2 OPTION FLAGS */
+ } else if (strncmp (arg, "band", 4) == 0) {
+ d2_band = vot_requiredArg (val);
+ } else if (strncmp (arg, "time", 4) == 0) {
+ d2_time = vot_requiredArg (val);
+ } else if (strncmp (arg, "format", 6) == 0) {
+ d2_format = vot_requiredArg (val);
+ } else if (strncmp (arg, "version", 7) == 0) {
+ d2_version = vot_requiredArg (val);
+ }
+
+ return (ARG_DONE);
+}
+
+
+static char *
+vot_requiredArg (char *arg)
+{
+ if (! arg) {
+ fprintf (stderr, "ERROR: Missing '--%s' argument.\n", arg);
+ exit (1);
+ }
+
+ return ( strdup (arg) );
+}
+
+static char *
+vot_optionalArg (char *arg)
+{
+ return ( (arg ? strdup (arg) : NULL) );
+}
+
+
+
+/************************************************************************
+** PARSEARGTOKEN -- Parse the argument based on it's position on the
+** command line. Some actions will require the next argument in the
+** command, otherwise the 'next' pointer will usually be NULL. This
+** routine can be used to parse either the argv commands or those from
+** a file. The 'inc' variable will indicate how far to advance the
+** argument counter as a result of this procedure.
+*/
+static int
+vot_parseArgToken (char *arg, char *next, int pos, int *inc)
+{
+ char posn[64];
+
+ *inc = 0;
+
+ /* Parse the arguments according to an assumed calling
+ ** order, i.e.
+ **
+ ** vodata [ url_list | [ resource [obj | ra dec] [sr] ]
+ **
+ ** By default we assume size is in degrees, the ra/dec will
+ ** be assumed to be ICRS J200 and may be sexagesimal or decimal.
+ */
+//fprintf (stderr, "parseArg: '%s' '%s' %d apos=%d\n", arg, next, pos, apos);
+ switch (apos) {
+ case 0: /* <resource> | <url> */
+
+ if (arg[0] != '/' && (isSexagesimal (arg) || isDecimal (arg))) {
+ fprintf (stderr,
+ "\nERROR: First argument required to be resource or url.\n");
+ return (ERR);
+ }
+
+ if (strncmp (arg, "http", 4) == 0 && !force_svc && url_proc) {
+ /* If this is a simple URL, simply download the result. */
+ vot_addToAclist (arg, NULL);
+ if (!fixed_pos)
+ apos--;
+ url_proc++;
+
+#ifdef VO_INVENTORY
+ } else if (inventory) {
+ /* If we're doing an incentory call, the first arg is only
+ ** allowed to be either 'any', and 'ivorn', or (eventually) a
+ ** file of resources to be uploads.
+ */
+ if (strcasecmp ("any",arg) == 0 ||
+ strncmp (arg, "ivo://", 6) == 0 ||
+ access (arg, R_OK) == 0) {
+ if (strncmp (arg, "ivo://", 6) == 0) {
+ extern char *id;
+ id = arg;
+ }
+ if (access (arg, R_OK) == 0)
+ resources = arg;
+ vot_parseServiceList (arg, 0);
+
+ } else {
+ fprintf (stderr, "Invalid resource type for Inventory, '%s'\n",
+ arg);
+ exit (1);
+ }
+#endif
+
+ } else if (raw_vizier && strncmp ("ivo://CDS", arg, 9) == 0) {
+ char url[SZ_LINE];
+ char *res = &arg[17];
+ char *base =
+ "http://vizier.u-strasbg.fr/viz-bin/votable/-dtd/-A?-source=";
+
+ sprintf (url, "%s%s", base, res);
+
+ /*
+ */
+ vot_parseServiceList (url, 0);
+ if (!fixed_pos)
+ apos--;
+ url_proc++;
+
+ } else {
+ /* Restrict 'any' searches to DAL only to save time.
+ */
+ if (strncasecmp ("any", arg, 3) == 0)
+ dalOnly = 1;
+ vot_parseServiceList (arg, dalOnly);
+ if (fixed_pos)
+ apos++;
+ }
+
+ break;
+
+ case 1: /* <obj> | <pos>*/
+ /* Sanity checks. */
+ if (force_svc && typestr && strchr(typestr,(int)',')) {
+ fprintf (stderr,
+ "\nERROR: Only one type may be given to used-defined service.\n");
+ return (ERR);
+
+ } else if (force_svc && !typestr && !fixed_svc) {
+ fprintf (stderr,
+ "\nERROR: No type specified for used-defined service.\n");
+ return (ERR);
+
+ } else if (!url_proc && !svcList && !inventory) {
+ fprintf (stderr,
+ "\nERROR: No supported DAL service types found.\n");
+ return (ERR);
+ }
+
+ /* Parse the object or position. */
+ if (fixed_pos) {
+ *inc = 1;
+ } else if (isSexagesimal (arg) || isDecimal (arg)) {
+ memset (posn, 0, 64);
+ sprintf (posn, "%s %s", arg, next);
+ vot_parseObjectList (posn, TRUE);
+ *inc = 1;
+ } else {
+ use_name++;
+ if (inventory && access (arg, R_OK) == 0)
+ sources = arg;
+ vot_parseObjectList (arg, TRUE);
+ }
+ break;
+
+ case 2: /* <size> (degrees) */
+ sr = vot_atof (arg);
+ break;
+
+ default:
+ fprintf (stderr, "Warning: Unknown argument syntax\n");
+ vot_printUsage ();
+ return (ERR);
+ }
+
+ return (OK);
+}
+
+
+/************************************************************************
+** GETNEXTCMDLINE -- Process the next command line from the argument
+** file. We do this by reading a line of the file and tokenizing it
+** as if the values were given to us on the command-line. For the
+** moment we don't allow options to be set and permit only the positional
+** arguments (e.g. resource, object, coords).
+*/
+static int
+vot_getNextCmdline ()
+{
+ int i, inc;
+ char *tok, *sep = " ", *line, cmdline[SZ_LINE];
+ int a_argc = 0;
+ char a_argv[4][SZ_LINE];
+
+ extern char *vot_getline (FILE *fd);
+
+
+ memset (a_argv, 0, (4 * SZ_LINE));
+ memset (cmdline, 0, SZ_LINE);
+
+ if (( line = vot_getline (arg_fd)))
+ strcpy (cmdline, line);
+ else
+ return (ERR);
+
+
+ for (tok = strtok(cmdline, sep); tok; tok = strtok(NULL, sep)) {
+ strcpy (a_argv[a_argc++], tok);
+ }
+
+ if (voc_initVOClient ("runid=voc.vodata") == ERR)
+ exit (-1);
+
+ apos = sv_apos;
+ for (i=0; i < a_argc; i++) {
+ if (vot_parseArgToken (a_argv[i], a_argv[i+1], apos, &inc) != OK) {
+ exit (1);
+ } else
+ i += inc; /* add the argv[] increment */
+
+ apos++; /* update arg position */
+ }
+
+
+ /* Close the VOClient connection since each child will use its own.
+ */
+ voc_closeVOClient (0); /* close VOClient connection */
+
+ return (OK);
+}
+
+
+/************************************************************************
+** VALIDATEOPTIONS -- Verify that all the commandline options make sense
+** before we begin processing. Some options will require others and we
+** can only check after all the options have been set and parsed from
+** the command line.
+*/
+static int
+vot_validateOptions ()
+{
+ if (count)
+ fileRange.nvalues = RANGE_NONE;
+
+ if (nobjects < 1) {
+ if (apos && !meta && !all_data) {
+ /* User provided an object, but it was invalid.
+ */
+ fprintf (stderr, "Error: No valid position or object found.\n");
+ return (ERR);
+
+ } else {
+ /* No position/object supplied, use default.
+ */
+ if (!quiet && !meta)
+ fprintf (stderr, "# Using default position: 0.0 0.0\n");
+ vot_parseObjectList ("0.0 0.0", TRUE);
+ nobjects = vot_countObjectList();
+ }
+ }
+
+ if (output && output[0] == '-')
+ extract |= EX_COLLECT;
+
+ if (kml_sample)
+ kml_max *= kml_sample;
+
+ if (meta && nservices == 0) {
+ fprintf (stderr, "ERROR: No service specified.\n");
+ return (ERR);
+ } else if (meta && nservices == 1) {
+ output = "-";
+ wr_stdout++;
+ quiet++;
+ }
+
+ return (OK);
+}
+
+
+
+/************************************************************************
+** PRINTSVCHDR -- Print a header for service output.
+*/
+void
+vot_printSvcHdr ()
+{
+ if (!quiet) {
+ printf ("\n");
+ if (meta) {
+ if (nservices == 1)
+ fprintf (stderr, "# Service: %s\n", svcList->name);
+ fprintf (stderr, "# No. of Services: %d\n", nservices);
+ } else {
+ if (nservices == 1) {
+ fprintf (stderr, "# Service: %s\n", svcList->name);
+ fprintf (stderr, "# Title: %s\n", svcList->title);
+ }
+ fprintf (stderr, "# No. of Objects: %d\n", nobjects);
+ fprintf (stderr, "# No. of Services: %d\n", nservices);
+ }
+ fprintf (stderr, "# Search size: %f (degrees)\n#\n", sr);
+ if (count || inventory)
+ vot_printCountHdr ();
+ }
+
+ fflush (stdout);
+}
+
+
+/************************************************************************
+** RUNSVCTHREADS -- Begin a processing thread for each data service. We
+** split the object list over each service in parallel threads.
+*/
+static void
+vot_runSvcThreads ()
+{
+ int t, tc, rc, status, t_start, t_end, nthreads;
+/*
+ pthread_t thread[nservices];
+*/
+ static pthread_t thread[10000];
+ Service *svc = svcList;
+ Proc *new = (Proc *)NULL;
+ Proc *cur = (Proc *)NULL;
+ pthread_attr_t attr; /* thread attributes */
+
+
+ qs_time = time ((time_t) NULL);
+
+ if (verbose && !count && !meta && nservices > 1)
+ fprintf (stderr, "# Creating service processing threads...\n");
+
+ /* Pre-allocate the process lists so they're in the global memory
+ ** space.
+ */
+ for (svc=svcList; svc; svc=svc->next) {
+ for (t=0; t < nobjects; t++) {
+ new = (Proc *) calloc (1, sizeof (Proc));
+ new->svc = (Service *) svc; /* set back pointer */
+ if (t == 0) {
+ svc->proc = new;
+ cur = svc->proc;
+ } else {
+ cur->next = new;
+ cur = cur->next;
+ }
+ }
+ }
+
+ nthreads = min (nservices, max_threads);
+ t_start = 0;
+ t_end = nthreads;
+
+
+ /* Spawn the processing threads.
+ */
+ svc = svcList;
+ for (tc=0; tc < nservices; tc += nthreads) {
+ t_end = min((nservices-tc),nthreads);
+
+ /* Initialize the service processing thread attributes and run 'em.
+ */
+ pthread_attr_init (&attr);
+ pthread_attr_setdetachstate (&attr, PTHREAD_CREATE_JOINABLE);
+
+ for (t=0; t < t_end; t++, svc=svc->next) {
+ if ((rc = pthread_create (&thread[t], &attr, vot_procObjs,
+ (void *)svc))) {
+ fprintf (stderr,
+ "ERROR: pthread_create() fails, code: %d\n", rc);
+ exit (-1);
+ }
+ }
+
+ /* Free attribute and wait for the threads to complete.
+ */
+ for (t=0; t < t_end; t++) {
+ if ((rc = pthread_join (thread[t], (void **)&status)) ) {
+ /*
+ fprintf (stderr, "ERROR: pthread_join() fails, code: %d\n", rc);
+ exit (-1);
+ */
+ ;
+ }
+ }
+
+ pthread_attr_destroy (&attr);
+ }
+ qe_time = time ((time_t) NULL);
+
+ if ((debug && verbose > 1)) {
+ fprintf (stderr, "\n\n..........THREAD PROCS COMPLETED.....\n");
+ vot_printSvcList (svcList);
+ fprintf (stderr, "..........THREAD PROCS COMPLETED.....\n\n\n");
+ }
+
+
+ /* If we're only writing a KML file and not simply extracting them
+ ** as an extra, concatenate the results from each query to a single
+ ** file for easier browsing.
+ */
+ if (format & F_KML || (extract & EX_KML && extract & EX_COLLECT)) {
+ char fname[SZ_FNAME];
+ extern void vot_concatKML (char *fname);
+
+ memset (fname, 0, SZ_FNAME);
+ if (output && output[0] != '-')
+ sprintf (fname, "Query_%d.kml", (int)getpid());
+ else
+ strcpy (fname, "-");
+ if (nservices > 1 && nobjects > 1)
+ vot_concatKML (fname);
+
+ } else if (format & F_XML || (extract & EX_XML && extract & EX_COLLECT)) {
+ char fname[SZ_FNAME];
+ extern void vot_concatXML (char *fname);
+
+ memset (fname, 0, SZ_FNAME);
+ if (output && output[0] != '-')
+ sprintf (fname, "Query_%d.xml", (int)getpid());
+ else
+ strcpy (fname, "-");
+
+ if (nservices > 1 && nobjects > 1)
+ vot_concatXML (fname);
+
+ } else if (extract & EX_COLLECT) {
+ extern void vot_concat (void);
+
+ vot_concat (); /* concatenate results */
+ }
+
+
+ /* For verbose output, print a summary of the processing history.
+ */
+ if (!quiet && count && !meta) {
+ Proc *curproc = (Proc *) NULL;
+ Proc *proc = (Proc *) NULL;
+ char *pad, *lpad;
+
+ int tot_rec = 0; /* Total records found */
+ int tot_fail = 0; /* No. failed service calls */
+ int tot_nodata= 0; /* No. of no-data results */
+ int tot_query = 0; /* No. of queries */
+
+ tot_query = (nservices * nobjects);/* Total No. queries made */
+
+ for (svc=svcList; svc; svc=svc->next) {
+ tot_rec += (svc->count > 0 ? svc->count : 0);
+ tot_fail += svc->nfailed;
+ tot_nodata += svc->nnodata;
+ }
+
+ pad = (nobjects == 1) ? "\t\t\t" : "\t\t\t\t\t";
+ lpad = (nobjects == 1) ? "---------------" : "";
+ printf ("\n");
+ printf ("#%s-------------------------------------%s\n", pad, lpad);
+/*
+ printf ("#%s%4d (Records Found)\n", pad, tot_rec);
+ printf ("#%s%4d (Resources Queried)\n", pad, tot_query);
+ printf ("#%s%4d (Failed Requests)\n", pad, tot_fail);
+ printf ("#%s%4d (Completed Requests)\n", pad, (tot_query-tot_fail));
+ printf ("#%s\t (%d Results w/ Data)\n", pad,
+ (tot_query - tot_fail - tot_nodata));
+*/
+ fprintf (stderr, "#%s%4d (Records Found)\n", pad, tot_rec);
+ fprintf (stderr, "#%s%4d (Resources Queried)\n", pad, tot_query);
+ fprintf (stderr, "#%s%4d (Failed Requests)\n", pad, tot_fail);
+ fprintf (stderr, "#%s%4d (Completed Requests)\n", pad,
+ (tot_query - tot_fail));
+ fprintf (stderr, "#%s\t (%d Results w/ Data)\n", pad,
+ (tot_query - tot_fail - tot_nodata));
+ if (tot_nodata)
+ printf ("#%s\t (%d Results w/ No Data)\n", pad, tot_nodata);
+ printf ("#\n");
+
+ if (verbose < 3)
+ return;
+
+ svc = svcList;
+ for (t=0; t < nservices; t++, svc=svc->next) {
+ if (svc->nfailed || !FAILED_ONLY)
+ vot_printProcStat (svc->proc, svc->name, FAILED_ONLY);
+
+ /* Free the proctable structure.
+ */
+ for (curproc=svc->proc; curproc; curproc=proc) {
+ proc = curproc->next;
+ if (curproc)
+ free ((void *) curproc);
+ }
+ }
+ }
+}
+
+
+/************************************************************************
+** PRINTSVCLIST -- Debug routine to print the SvcList.
+*/
+void
+vot_printSvcList (Service *sl)
+{
+ Service *s;
+ Proc *p;
+
+ for (s=sl; s; s=s->next) {
+ fprintf (stderr, "%15s: nfail=%d nrefs=%d type=%d\ts=%ld\n",
+ s->name, s->nfailed, s->nrefs, s->type, (long)s);
+
+ for (p=s->proc; p; p=p->next) {
+ fprintf (stderr, "\t\tpid=%d status=%d obj=%s\t p=%ld\n",
+ p->pid, p->status, p->obj->name, (long)p);
+ }
+ }
+}
+
+
+/************************************************************************
+** PROCOBJS -- Create threads to process the object list. Our only
+** argument is the Service object to run.
+*/
+void *
+vot_procObjs (void *arg)
+{
+ int nobj, nprocs, nrunning, nremaining, nupdate;
+ int lock, nrep, status;
+ pid_t r_pid, pid;
+
+ Object *obj = objList;
+ Service *svc = (Service *)arg;
+ Proc *curproc = (Proc *) svc->proc;
+ svcParams pars;
+
+
+ /* Figure out how many threads to run at a time.
+ */
+ nprocs = ( (nobjects > max_threads) ? max_threads : nobjects );
+ nupdate = 10;
+
+ nrep = nrunning = 0;
+ nremaining = nobjects;
+
+ for (nobj=1; nremaining > 0; ) {
+
+ if (debug)
+ fprintf (stderr, "procObjs(%s): n=%d/%d nprocs=%d nrun=%d sr=%f\n",
+ svc->name, nobj, nobjects, nprocs, nrunning, sr);
+
+ /* Spawn a process thread for each object/position.
+ */
+ if (nrunning < nprocs && nobj <= nobjects) {
+
+ /* Set up the service parameter struct. Each thread gets its
+ ** own instance.
+ */
+ strcpy (pars.service_url, vizPatch(svc->service_url));
+ strcpy (pars.identifier, svc->identifier);
+ strcpy (pars.name, svc->name);
+ if (id_col && obj->id && obj->id[0])
+ strcpy (pars.oname, obj->id);
+ else
+ strcpy (pars.oname, obj->name);
+ strcpy (pars.title, svc->title);
+ pars.ra = obj->ra;
+ pars.dec = obj->dec;
+
+ /* Prior to Registry 1.0 we didn't have a real cone capability
+ ** for Vizier tables and needed to set flags to download the
+ ** entire table. This is no longer necessary, the user can set
+ ** a negative search radius to get the entire table if they choose.
+
+ pars.sr = sr;
+ */
+ if (all_data && svc->type == SVC_VIZIER)
+ pars.sr = -1.0;
+ else
+ pars.sr = sr;
+ pars.fmt = format;
+ pars.type = svc->type;
+ pars.index = nobj;
+ pars.obj_index = nobj - 1; /* zero-indexed */
+ pars.svc_index = svc->index;
+
+ if ((pid = (*(PFI)(*svc->func))((void *)&pars)) < 0) {
+ fprintf (stderr,"ERROR: process fork() fails\n");
+ pthread_exit ((void *) NULL);
+ }
+ nrunning++;
+ nobj++;
+
+ /* Allocate the process summary struct. Only save the status if
+ ** we'll be printing a summary later.
+ */
+ if ((extract & EX_COLLECT) || !quiet) {
+
+ /* Lock the thread to protect us from messing with the
+ ** service list data.
+ */
+ lock = pthread_mutex_lock (&svc_mutex);
+ curproc->pid = pid; /* load the process struct */
+ curproc->obj = obj;
+ curproc->status = 0;
+ memset (curproc->root, 0, SZ_FNAME);
+ if (use_name || all_named || id_col)
+ strcpy (curproc->root, vot_getOFName(&pars,NULL,(int)pid));
+ else
+ strcpy (curproc->root, vot_getOFIndex(&pars,NULL,(int)pid));
+
+
+ curproc = curproc->next; /* move on */
+ lock = pthread_mutex_unlock (&svc_mutex);
+ }
+
+ if (debug)
+ fprintf (stderr, "procObjs(%s): %d ra=%f dec=%f pid=%d\n",
+ svc->name, nobj, obj->ra, obj->dec, pid);
+
+ if (obj)
+ obj = obj->next;
+
+ } else {
+
+ /* Process table full, wait for any child processes to complete.
+ */
+ if (debug)
+ fprintf (stderr, "procObjs(%s:%d): waiting %d remaining....\n",
+ svc->name, getpid(), nremaining);
+
+ if ((r_pid = waitpid ((pid_t)-1, &status, (int) 0)) < 0 ) {
+ /* FIXME
+ if (verbose || debug)
+ fprintf (stderr, "ERROR: waitpid() fails, code[%d] %s\n",
+ (int)errno, strerror(errno));
+ pthread_exit ((void *) NULL);
+ */
+ }
+
+ status = WEXITSTATUS(status);
+ if (debug)
+ fprintf (stderr, "pid = %d stat = %d\n", r_pid, status);
+
+ lock = pthread_mutex_lock (&svc_mutex);
+ vot_setProcStat (svc, (int)r_pid, status);
+ lock = pthread_mutex_unlock (&svc_mutex);
+
+ nrunning--;
+ nremaining--;
+ }
+
+ if (!quiet && nobj < nobjects && (nobj % nupdate) == 0 &&
+ !count && !file_get && nrep == 0) {
+ fprintf (stderr,
+ "# Service %15s: Completed %3d of %4d objects (%d running)\n",
+ svc->name, nobj, nobjects, nrunning);
+ nrep = 1;
+ } else if (nrep == 1)
+ nrep = 0;
+ }
+
+ if (!quiet && !count && !file_get && !meta) {
+ fprintf (stderr, "# Service %25s: ", svc->name);
+ fprintf (stderr, "Finished processing (%d of %d succeeded).\n",
+ (nobjects - (svc->nfailed + svc->nnodata)),
+ nobjects);
+ }
+ if (debug)
+ fprintf (stderr, "procObjs done (%s).\n", svc->name);
+
+
+ pthread_exit (NULL);
+}
+
+
+static char *
+vizPatch (char *url)
+{
+ static char new[SZ_LINE], *ip, *op;
+
+ memset (new, 0, SZ_LINE);
+ for (ip=url, op=new; *ip; ) {
+ if (*ip == '&' && *(ip+1) == '/')
+ ip++;
+ *op++ = *ip++;
+ }
+
+ return (new);
+}
+
+
+/************************************************************************
+** SETPROCSTAT -- Set the process return status. 'procList' is the
+** process list running on this particular thread.
+*/
+static void
+vot_setProcStat (Service *svc, int pid, int status)
+{
+ Service *s = svcList;
+ Proc *pp;
+ int i, rc, sem_id, n = nservices;
+
+ if (svcList == (Service *) NULL)
+ return;
+
+ for (s=svcList; s; s=s->next, n--) {
+ for (pp=s->proc; pp; pp=pp->next) {
+ if (pp->pid == pid) {
+ /* Set the status for this svc/obj process.
+ */
+ pp->status = status;
+ if (status == E_REQFAIL)
+ s->nfailed++;
+ if (status == E_NODATA)
+ s->nnodata++;
+
+ /* If we created a URL extraction, add the URLS to the
+ ** access list.
+ */
+ if (extract == EX_ACREF || extract == EX_BOTH) {
+ char fname[SZ_FNAME], url[SZ_URL];
+ FILE *fd;
+ int nf = 1;
+
+ /* Get the filename of the URLs we'll get.
+ */
+ memset (fname, 0, SZ_FNAME);
+ sprintf (fname, "%s.urls", pp->root);
+
+ /* Construct a template for each file.
+ */
+ if (access (fname, R_OK) == 0) {
+ fd = fopen (fname, "r");
+ for (i=1; fgets (url, SZ_URL, fd); i++) {
+ url[strlen(url)-1] = '\0'; /* kill newline */
+
+ memset (fname, 0, SZ_FNAME);
+ if (file_get > 1)
+ sprintf (fname, "%s.%03d", pp->root, i);
+ else
+ sprintf (fname, "%s", pp->root);
+
+ if (file_get && is_in_range(fileRange.ranges,i)) {
+ vot_addToAclist (url, fname);
+ nf++;
+ }
+ }
+ fclose (fd);
+ }
+ }
+
+ /* Get the semaphore set by the child indicating the
+ ** result count.
+ */
+ sem_id = semget (pid, 0, 0);
+ pp->count = semctl (sem_id, 0, GETVAL, 0); /* get value */
+ s->count += pp->count;
+ rc = semctl (sem_id, 0, IPC_RMID, NULL); /* release it */
+ if (status != E_NODATA && s->count == 0)
+ s->nnodata++;
+
+ break;
+ }
+ }
+ }
+ if (s == (Service *) NULL && n) { /* no matching service found */
+ fprintf (stderr, "Warning: NO SERVICE FOUND....pid=%d status=%d\n",
+ pid, status);
+ return;
+ }
+}
+
+
+
+/************************************************************************
+** PRINTPROCSTAT -- Print a summary of the processing results. If
+** 'failed_only' is set this is an error summary only.
+*/
+static void
+vot_printProcStat (Proc *procList, char *svc_name, int failed_only)
+{
+ Proc *pp = procList;
+ FILE *fd = (failed_only ? stderr : stdout);
+
+ if (procList == (Proc *) NULL)
+ return;
+
+ fprintf (fd, "\nError Summary for '%s' :\n", svc_name);
+ while (pp) {
+ if (!failed_only || pp->status) {
+ fprintf (fd, " Pid %6d: Source: %-12.12s (%.6f,%.6f) %s\n",
+ pp->pid,
+ (pp->obj->name ? pp->obj->name : "(none)"),
+ pp->obj->ra, pp->obj->dec, vot_stat2code(pp->status));
+ }
+ pp = pp->next;
+ }
+}
+
+
+/************************************************************************
+** STAT2CODE -- Convert an error code to a text string for printing.
+*/
+static char *
+vot_stat2code (int status)
+{
+ switch (status) {
+ case E_NONE: return ("OK"); break;
+ case E_NODATA: return ("No Data Returned"); break;
+ case E_REQFAIL: return ("Request Failed"); break;
+ case E_FILOPEN: return ("File Open Error"); break;
+ case E_VOCINIT: return ("VOClient init fails"); break;
+ default: return ("Unknown Error"); break;
+ }
+
+ return (NULL);
+}
+
+
+/************************************************************************
+** CNVTYPE -- Convert an error code to a text string for printing.
+static char *
+vot_cnvType (char *intype)
+{
+ if (strcasecmp ("image", intype) == 0)
+ return ("siap");
+ else if (strcasecmp ("catalog", intype) == 0)
+ return ("cone");
+ else if (strcasecmp ("table", intype) == 0)
+ return ("tabularskyservice");
+ else
+ return (intype);
+}
+*/
+
+
+/************************************************************************
+** PRINTPROCTIME -- Print a summary of the processing times.
+*/
+static void
+vot_printProcTime ()
+{
+ if (!quiet) {
+ int r = ((int)re_time - (int)rs_time),
+ q = ((int)qe_time - (int)qs_time),
+ a = ((int)ae_time - (int)as_time);
+ int tot = (r + q + a);
+
+ extern char *toSexaTime (int n);
+
+
+ printf ("#\n");
+ printf ( "# Approx Time: %02d:%02d:%02d\t",
+ (tot / 3600), (tot / 60), (tot % 60));
+ printf ("(%02d:%02d Resolution, %02d:%02d Query, %02d:%02d Access)\n",
+ r / 60, r % 60,
+ q / 60, q % 60,
+ a / 60, a % 60);
+ }
+}
+
+
+/************************************************************************
+** USAGE -- Print a summary of the help options.
+*/
+static void
+Usage()
+{
+ vot_printUsage();
+
+ printf ("Where:\n");
+ printf ("\n");
+ printf (" <resource> ShortName/Identifier of data service \n");
+ printf (" <obj> Name of object to be resolved\n");
+ printf (" <ra> <dec> Decimal or Sexagesimal coords for query \n");
+ printf (" <url> URL to access or ServiceURL to query \n");
+ printf (" <sr> Search radius in degrees (def: 0.1) \n");
+ printf ("\n");
+ printf (" These values may optionally be in a file containing them.\n");
+ printf (" Resource and object names may be comma-delimited lists\n");
+ printf ("\n");
+ printf ("\n");
+ printf (" -h Print this help summary\n");
+ printf (" -v, --vverbose Verbose or very-verbose mode\n");
+ printf ("\n\tTask Behavior Flags:\n");
+ printf (" -a, --all Query all data for the resource\n");
+ printf (" -c, --count Print a count\n");
+ printf (" -g, --get <rng> Get the files associated with a query\n");
+ printf (" -m, --meta Print the column metadata for the resource\n");
+
+ printf ("\n\tQuery Options:\n");
+ printf (" -b <bandpass> Constrain by bandpass\n");
+ printf (" -i <file> Take arguments from file (or stdin)\n");
+ printf (" -o <obj> Specify object list\n");
+ printf (" -p <pos> Specify position list\n");
+ printf (" -r Set search radius\n");
+ printf (" -rs Set radius in arc-seconds\n");
+ printf (" -rm Set radius in arc-minutes\n");
+ printf (" -rd Set radius in degrees (default: 0.1)\n");
+ printf (" -s <svc> Specify the service name or url\n");
+ printf (" -t <type> Constrain by service type\n");
+
+ printf ("\n\tOutput Options:\n");
+ printf (" -A,--ascii ASCII table output (.txt extension)\n");
+ printf (" -C,--csv CSV table output (.csv extension)\n");
+ printf (" -H,--html HTML table output (.html extension)\n");
+#ifdef VO_INVENTORY
+ printf (" -I Output results from the Inventory Service\n");
+#endif
+ printf (" -K,--kml KML output (.kml extension)\n");
+ printf (" -R,--raw Raw (VOTable) output (.xml extension)\n");
+ printf (" -V,--votable VOTable output (.xml extension)\n");
+ printf (" -T,--tsv Tab-separated table output (.tsv extension)\n");
+ printf (" -O <root> Set the root part of output name\n");
+ printf ("\n");
+ printf (" -e,--extract Extract results to separate file\n");
+ printf (" --ep Extract only positions (to <file>.pos)\n");
+ printf (" --eu Extract only access urls (to <file>.urls)\n");
+ printf (" --eh Extract table to HTML (to <file>.html)\n");
+ printf (" --ek Extract table to individual KML (to <file>.kml)\n");
+ printf (" --eK Extract table to aggregate KML (to <file>.kml)\n");
+ printf (" -n,--nosave No-save results, print a count only\n");
+ printf (" -q,--quiet Suppress output to the screen\n");
+
+ printf ("\n\tFormat-specific Options:\n");
+ printf (" --km <N> Set max downloads (def: 100)\n");
+ printf (" --kgb Group KML output by both object and service\n");
+ printf (" --kgo Group KML output by object\n");
+ printf (" --kgs Group KML output by service\n");
+ printf (" --ks <N> Set result sample\n");
+ printf (" --kl Disable Placemark labels\n");
+ printf (" --kr Disable region box\n");
+ printf (" --kv Disable verbose labels\n");
+ printf ("\n");
+ printf (" --wb Disable HTML table borders\n");
+ printf (" --wc Disable HTML table verbose label\n");
+ printf (" --wh Disable HTML page header\n");
+
+ printf ("\n\tProcessing Options:\n");
+ printf (" --md <N> Set max downloads (def: 1)\n");
+ printf (" --mp <N> Set max number of processes per obj query\n");
+ printf (" --mt <N> Set max number of resource threads to run\n");
+ printf (" \n");
+
+ printf ("\n Notes:\n");
+ printf ("\t- Data Services may be listed by Registry ShortName of ");
+ printf ("Identifier\n");
+ printf ("\t- Sources may be object name, positions in decimal or sexages");
+ printf ("imal\n\t coords, or a file containing either.\n");
+
+ printf ("\n\n");
+ printf ("Resource Type Strings:\n");
+ printf (" catalog Cone search services\n");
+ printf (" image Simple Image Access services\n");
+ printf (" spectra Simple Spectral Access services\n");
+ printf (" table Vizier services\n");
+ printf (" <literal> ResourceType from registry record\n");
+ printf ("\n");
+ printf ("Allowed Bandpass Strings:\n");
+ printf (" Radio Millimeter Infrared (IR)\n");
+ printf (" Optical Ultraviolet (UV) X-Ray (xray)\n");
+ printf (" Gamma-Ray (GR)\n");
+ printf ("\n");
+
+ printf ("\n\n");
+ vot_printExamples();
+ printf ("\n\n");
+}
+
+
+static void
+vot_printExamples()
+{
+
+ printf ("Examples:\n---------\n\n");
+
+
+ printf ("\
+ 1) Query the GSC 2.3 catalog for stars a) within the 0.1 degree \n\
+ default search size around NGC 1234: b) around all positions \n\
+ contained in file 'pos.txt': c) for the list of objects given \n\
+ on the command line: d) query a list of services for a list \n\
+ of positions: e) print a count of results that would be returned\n\
+ from 3 services for each position in a file:\n\
+\n\
+ %% vodata gsc2.3 ngc1234 (a)\n\
+ %% vodata gsc2.3 pos.txt (b)\n\
+ %% vodata gsc2.3 m31,m51,m93 (c)\n\
+ %% vodata svcs.txt pos.txt (d)\n\
+ %% vodata hst,chandra,gsc2.3 pos.txt (e)\n\
+\n\
+ 2) Find all images by HST of NGC 4258, create a KML file for Google Sky:\n\
+\n\
+ %% vodata -K -t image -all hst ngc4258\n\
+\n\
+ 3) Query all (142) image services having data of the subdwarf\n\
+ galaxy IC 10, print a count of the results only:\n\
+\n\
+ %% vodata -c -t image any IC10\n\
+\n\
+ 4) Print a count of X-ray catalog data around Abell2712:\n\
+\n\
+ %% vodata -count -t catalog -b x-ray any abell2712\n\
+\n\
+ 5) Print the column metadata returned by the RC3 catalog service:\n\
+\n\
+ %% vodata -meta -t catalog rc3\n\
+\n\
+ 6) Use the Registry to query for resources using the search terms\n\
+ 'cooling flow'. Upon examining the output the user notices a\n\
+ Vizier paper titled 'Cooling Flows in 207 clusters of Galaxies'\n\
+ that looks interesting. Use the vodata task to download all\n\
+ tables associated with this paper, save tables in the default\n\
+ CSV format:\n\
+\n\
+ %% voregistry cooling flow\n\
+ %% vodata -O white97 -all J/MNRAS/292/419\n\n\n\
+ ");
+
+}
+
+
+static void
+vot_printUsage()
+{
+ printf ("\n");
+ printf ("Usage:\n");
+ printf ("\n");
+ printf (" vodata <flags> [[ <resource> [<obj> | <ra> <dec>] [<sr>] | [<url>]]\n");
+ printf ("\n");
+}
+
+
+
+/**
+ * Tests -- Task unit tests.
+ */
+static void
+Tests (char *input)
+{
+ Task *task = &self;
+
+ vo_taskTest (task, "--help", NULL);
+
+ vo_taskTestFile ("m31\nm51\nm99\n", "pos.txt");
+ vo_taskTestFile ("hst\nchandra\ngsc2.3\n", "svcs.txt");
+
+ vo_taskTest (task, "gsc2.3", "ngc1234", NULL);
+ vo_taskTest (task, "gsc2.3", "pos.txt", NULL);
+ vo_taskTest (task, "gsc2.3", "m31,m51,m93", NULL);
+ vo_taskTest (task, "svcs.txt", "pos.txt", NULL);
+ vo_taskTest (task, "hst,chandra,gsc2.3", "pos.txt", NULL);
+
+ vo_taskTest (task, "-c", "-t", "image", "any", "IC10", NULL);
+ vo_taskTest (task, "--count", "--type=image", "any", "IC10", NULL);
+ vo_taskTest (task, "-c", "-t", "catalog", "-b", "x-ray",
+ "any", "abell2712", NULL);
+ vo_taskTest (task, "--count", "--type=image", "--bandpass=x-ray",
+ "any", "abell2712", NULL);
+
+ vo_taskTest (task, "--meta", "rc3", NULL);
+
+ vo_taskTest (task, "-O", "white97", "-all", "J/MNRAS/292/419", NULL);
+
+ vo_taskTest (task, "-rv", "-t", "image", "xmm", NULL);
+ vo_taskTest (task, "-cq", "xmm-newton", "3c273", NULL);
+ vo_taskTest (task, "--count", "--quiet", "xmm-newton", "3c273", NULL);
+ vo_taskTest (task, "--get", "xmm-newton", "3c273", NULL);
+
+ vo_taskTest (task, "-e", "-O", "2mass", "-t", "image", "2mass",
+ "12:34:56.7", "-23:12:45.2", NULL);
+ vo_taskTest (task, "-e", "--output=2mass", "--type=image", "2mass",
+ "12:34:56.7", "-23:12:45.2", NULL);
+
+ vo_taskTest (task, "-e", "ivo://nasa.heasarc/abell",
+ "0.0", "0.0", "180.0", NULL);
+
+ vo_taskTest (task, "-a", "galex", "m51", NULL);
+ vo_taskTest (task, "--all", "galex", "m51", NULL);
+
+
+ if (access ("pos.txt", F_OK) == 0) unlink ("pos.txt");
+ if (access ("svcs.txt", F_OK) == 0) unlink ("svcs.txt");
+
+ vo_taskTestReport (self);
+}
+
diff --git a/vendor/voclient/voapps/vodata.c.bak b/vendor/voclient/voapps/vodata.c.bak
new file mode 100644
index 00000000..15f82343
--- /dev/null
+++ b/vendor/voclient/voapps/vodata.c.bak
@@ -0,0 +1,2256 @@
+/************************************************************************
+** VODATA -- Query a VO Data service (Cone or SIAP)
+**
+** Usage: vodata [-<flags>] [<service>] [object|file|position]
+**
+** M. Fitzpatrick, NOAO, July 2007
+*/
+
+#include <pthread.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <sys/ipc.h>
+#include <sys/sem.h>
+#include <sys/time.h>
+#include <time.h>
+#include "VOClient.h"
+#include "voAppsP.h"
+#include "samp.h"
+
+
+
+
+#define VOD_DEBUG (getenv("VOD_DBG")||access("/tmp/VOD_DBG",F_OK)==0)
+
+
+/* Task structure.
+ */
+typedef struct {
+ char *name; /* task name */
+ int (*func)(int argc, char **argv, size_t *len, void **result);
+
+ int ntests; /* number of unit tests */
+ int npass; /* number of passed tests */
+ int nfail; /* number of failed tests */
+} Task;
+
+
+
+/* Local processing definitions.
+*/
+svcParams pars[MAX_THREADS]; /* parameter array */
+
+int format = F_CSV; /* output format */
+int apos = 0; /* argv position */
+int sv_apos = -1; /* saved argv position */
+int nservices = 0; /* num. of cone services */
+int nobjects = 0; /* num. objects to query */
+int filenum = 0; /* download file number */
+int rd_stdin = 0; /* reading from stdin? */
+int wr_stdout = 0; /* writing to stdout? */
+int do_votable = 0; /* output a Resource VOTable */
+int svcNumber = -1; /* service number to call */
+int dalOnly = 1; /* only query DAL services? */
+int simple_out = 0; /* use simple output name? */
+
+int inventory = FALSE; /* do inventory? */
+int quiet = FALSE; /* no output at all? */
+int verbose = TRUE; /* DAL verbose level */
+int all_data = FALSE; /* get all the data? */
+int file_get = FALSE; /* file number to get */
+#ifdef REG10_KLUDGE
+int reg10 = FALSE; /* use Registry 1.0 scheme? */
+#endif
+int raw_vizier = FALSE; /* use Registry 1.0 scheme? */
+int count = TRUE; /* return count of results */
+int meta = FALSE; /* metadata return? */
+int extract = EX_NONE; /* extract pos/acrefs? */
+int count_only = FALSE; /* print only matched records? */
+int save_res = TRUE; /* save results? */
+int all_named = FALSE; /* all objects named? */
+int use_name = FALSE; /* use object name in output? */
+int url_proc = FALSE; /* processing URLs only? */
+int force_svc = FALSE; /* assume URLs are ServiceURLs? */
+int svc_list = FALSE; /* list services queried */
+int obj_list = FALSE; /* list objects queried */
+int fixed_svc = FALSE; /* service is fixed on cmdline */
+int fixed_obj = FALSE; /* object is fixed on cmdline */
+int fixed_pos = FALSE; /* position is fixed on cmdline */
+int data_type = DT_ANY; /* data type */
+int proxy = FALSE; /* use proxy server */
+int res_all = FALSE; /* print all results? */
+int force_read = FALSE; /* force reading of input table */
+int longlines = FALSE; /* output long lines? */
+int iportal = FALSE; /* iportal support? */
+int numout = FALSE; /* numeric output sorting? */
+int samp = FALSE; /* broadcast table via SAMP */
+
+int max_download= DEF_DOWNLOADS; /* max download procs to run */
+int max_procs = DEF_NPROCS; /* max children to run */
+int max_threads = DEF_NTHREADS; /* max threads to run */
+
+int table_hskip = 0; /* no. of table eeader to skip */
+int table_nlines= 0; /* max lines of table to read */
+int table_sample= 1; /* table sample */
+
+int group = 0; /* resolve identifiers in groups*/
+int nterms = 0; /* No. of terms */
+char *terms[128]; /* search terms */
+
+char *typestr = (char *) NULL; /* service type string */
+char *bpass = (char *) NULL; /* bandpass type string */
+char *output = (char *) NULL; /* root output filename */
+char *delim = " \t,|;"; /* input table delimiter */
+char *cols = "1,2"; /* input table columns */
+char *ecols = (char *) NULL; /* input table exact columns */
+char *sources = (char *) NULL; /* source file */
+char *resources = (char *) NULL; /* resource file */
+char *sampName = (char *) NULL; /* SAMP appName */
+
+char *d2_band = (char *) NULL; /* DAL2 BAND parameter */
+char *d2_time = (char *) NULL; /* DAL2 TIME parameter */
+char *d2_format = (char *) NULL; /* DAL2 FORMAT parameter */
+char *d2_version = (char *) NULL; /* DAL2 VERSION parameter */
+
+char *tmpdir = "/tmp/"; /* temp directory */
+char wrkdir[SZ_FNAME]; /* working directory */
+
+double sr = DEF_SR; /* default search radius */
+
+int dverbose = 0; /* verbose debug output? */
+int debug = 0; /* debug output? */
+int samp_p = 0; /* SAMP interface handler */
+
+static int status = OK; /* return status */
+
+
+time_t rs_time = (time_t) 0,
+ re_time = (time_t) 0; /* reg/obj resolution times */
+time_t qs_time = (time_t) 0,
+ qe_time = (time_t) 0; /* data query times */
+time_t as_time = (time_t) 0,
+ ae_time = (time_t) 0; /* data access times */
+
+Service *svcList, *svcTail; /* Service linked list */
+Object *objList, *objTail; /* Obj/Posn linked list */
+Acref *acList, *acTail; /* Acref linked list */
+int nacrefs = 0; /* no. of acrefs */
+
+FILE *arg_fd = (FILE *) NULL; /* argument-file descriptor */
+
+
+/* KML Options.
+*/
+int kml_max = 50, /* max placemarks to write */
+ kml_sample = 0, /* output sample step */
+ kml_region = TRUE, /* draw bounding region poly */
+ kml_verbose = TRUE, /* verbose labels */
+ kml_label = TRUE, /* draw placemark labels */
+ kml_byObj = TRUE, /* group by object/position */
+ kml_bySvc = FALSE, /* group by service name */
+ kml_byBoth = FALSE; /* group by both */
+
+/* HTML Options.
+*/
+int html_header = TRUE, /* print a HTML header on page */
+ html_border = TRUE, /* put a border on the table? */
+ html_color = TRUE; /* colorize the table */
+
+
+extern int errno; /* system error code */
+
+extern int ra_col, ra_span, /* table input */
+ dec_col, dec_span,
+ id_col, id_span;
+extern int svcIndex, objIndex;
+
+extern int isDecimal (char *s);
+extern int isSexagesimal (char *s);
+
+extern int vot_parseObjectList (char *list, int isCmdLine);
+extern int vot_countObjectList (void);
+extern int vot_parseServiceList (char *list, int dalOnly);
+extern int vot_countServiceList (void);
+extern int vot_decodeRanges (char *range_string, int *ranges, int max_ranges,
+ int *nvalues);
+extern int is_in_range (int ranges[], int number);
+extern int vot_atoi (char *v);
+
+extern void vot_addToAclist (char *url, char *fname);
+extern void vot_procAclist (void);
+extern void vot_freeAclist (void);
+extern void vot_freeServiceList (void);
+extern void vot_resetServiceCounters (void);
+extern void vot_freeObjectList (void);
+extern void vot_printCountHdr (void);
+extern void vot_readObjFile (char *fname);
+extern void vot_readSvcFile (char *fname, int dalOnly);
+
+extern double vot_atof (char *v);
+
+/* Tasking execution procedure.
+ */
+extern int vo_runTask (char *method, Task *apps, int argc, char **argv,
+ size_t *len, void **result);
+extern int vo_taskTest (Task *self, char *arg, ...);
+extern void vo_taskTestFile (char *str, char *fname);
+extern void vo_taskTestReport (Task self);
+
+extern int vo_setResultFromFile (char *fname, size_t *len, void **data);
+extern int vo_setResultFromString (char *str, size_t *len, void **data);
+extern int vo_setResultFromInt (int value, size_t *len, void **data);
+extern int vo_setResultFromReal (float value, size_t *len, void **data);
+extern int vo_appendResultFromString (char *str, size_t *len, void **data,
+ size_t *maxlen);
+
+
+#ifdef VO_INVENTORY
+extern char *vot_doInventory (void);
+#endif
+extern char *vot_urlFname (char *url);
+extern char *vot_getOFName (svcParams *pars, char *extn, int pid);
+extern char *vot_getOFIndex (svcParams *pars, char *extn, int pid);
+extern char *vot_normalize (char *str);
+extern char *vot_svcTypeCode (int type);
+
+static int vot_parseArgToken (char *arg, char *next, int pos, int *inc);
+static int vot_validateOptions (void);
+static int vot_getNextCmdline (void);
+static void vot_runSvcThreads (void);
+static void vot_printProcStat (Proc *procList, char *svc_name, int fail_only);
+static void vot_setProcStat (Service *svc, int pid, int status);
+
+static void vot_printProcTime ();
+static char *vot_requiredArg (char *arg);
+static char *vot_optionalArg (char *arg);
+static char vot_setArgWord (char *arg, char *next, char **argv, int argc);
+static char *vot_stat2code (int status);
+static char *vizPatch (char *url);
+/*
+static char *vot_cnvType (char *intype);
+*/
+
+static void vot_printUsage (void);
+static void vot_printExamples (void);
+
+void *vot_procObjs (void *arg);
+void vot_printSvcList (Service *sl);
+void vot_printSvcHdr (void);
+
+
+pthread_mutex_t svc_mutex = PTHREAD_MUTEX_INITIALIZER;
+
+
+/* Task specific option declarations.
+ */
+int vodata (int argc, char **argv, size_t *len, void **result);
+
+static Task self = { "vodata", vodata, 0, 0, 0 };
+
+static void Usage (void);
+static void Tests (char *input);
+
+
+/* For getopt_long() option parsing.
+*/
+int opt_index;
+#ifdef USE_GETOPT
+static char *opt_string = ""; /* not used */
+static struct option long_options[] = { /* not used */
+ { NULL, 0, 0, 0 }
+};
+#endif
+
+
+
+
+/************************************************************************
+** Program main()
+*/
+int
+vodata (int argc, char *argv[], size_t *reslen, void **result)
+{
+ register int i, j, len, ch;
+ char *eval, *argfile, *next_arg, posn[SZ_LINE];
+
+
+ /* Initialize the VOClient code. Error messages are printed by the
+ ** interface so we just quit if there is a problem.
+ */
+ if (voc_initVOClient ("runid=voc.vodata") == ERR) {
+ fprintf (stderr, "Error: cannot connect to VOClient daemon\n");
+ return (ERR);
+ }
+
+
+ /* Initialize the global structs.
+ */
+ memset (&colRange, 0, sizeof (Range));
+ memset (&rowRange, 0, sizeof (Range));
+ memset (&fileRange, 0, sizeof (Range));
+ colRange.nvalues = RANGE_ALL;
+ rowRange.nvalues = RANGE_ALL;
+ fileRange.nvalues = RANGE_NONE;
+
+
+ /* Get some environment definitions. We allow the command-line flags
+ ** to override these values.
+ */
+ if ((eval = getenv("VOC_MAX_DOWNLOADS")))
+ max_download = vot_atoi (eval);
+ if ((eval = getenv("VOC_MAX_PROCS")))
+ max_procs = vot_atoi (eval);
+ if ((eval = getenv("VOC_MAX_THREADS")))
+ max_threads = vot_atoi (eval);
+
+
+ /* Initializations.
+ */
+ *reslen = 0;
+ *result = NULL;
+ apos = 0;
+ svcIndex = 0;
+ objIndex = 0;
+ all_data = 0;
+
+
+ rs_time = time ((time_t) NULL);
+
+ /* Now process the command line arguments.
+ */
+ if (VOD_DEBUG) {
+ fprintf (stderr, "Command:");
+ for (i=0; i < argc; i++) fprintf (stderr, " '%s'", argv[i]);
+ fprintf (stderr, "\n");
+ for (i=0; i < argc; i++) fprintf (stderr, "%s ", argv[i]);
+ fprintf (stderr, "\n\n");
+ }
+
+ for (i=1; i < argc; i++) {
+
+ if (argv[i][0] == '-') {
+ len = strlen (argv[i]);
+ for (j=1; j < len; j++) {
+
+ if (argv[i][j] == '-') {
+ ch = vot_setArgWord (&argv[i][j+1], argv[i+1], argv, argc);
+ j += len - 1;
+ if (ch < 0) /* handled in vot_setArgWord() */
+ continue;
+ } else
+ ch = argv[i][j];
+
+ switch (ch) {
+ case 'h': /* help */
+ Usage ();
+ voc_closeVOClient (0);
+ return (OK);
+
+ case '%': /* unit tests */
+ voc_closeVOClient (0);
+ Tests (NULL);
+ return (self.nfail);
+
+ case '1': /* one-file output */
+ extract |= EX_COLLECT;
+ break;
+ case 'N': /* numeric output name */
+ numout++;
+ break;
+ case 'S': /* simple output name */
+ simple_out++;
+ break;
+
+ case 'A': /* ASCII output */
+ format = F_ASCII;
+ break;
+ case 'C': /* CSV output */
+ format = F_CSV;
+ break;
+ case 'F': /* FITS table output */
+ fprintf (stderr,
+ "FITS tables not yet implemented, using ASCII\n");
+ format = F_ASCII;
+ break;
+ case 'H': /* HTML output */
+ extract |= EX_HTML;
+ format = F_CSV | F_HTML;
+ if (output && output[0] == '-')
+ extract |= EX_COLLECT;
+ break;
+#ifdef VO_INVENTORY
+ case 'I': /* inventory count */
+ inventory++;
+ count++;
+ break;
+#endif
+ case 'K': /* KML output */
+ extract |= EX_KML;
+ format = F_CSV | F_KML;
+ break;
+ case 'R': /* RAW output */
+ case 'V': /* VOTable output */
+ format = F_RAW;
+ if (output && output[0] == '-')
+ extract |= EX_COLLECT;
+ break;
+ case 'T': /* TSV output */
+ format = F_TSV;
+ break;
+ case 'X': /* XML output */
+ extract |= EX_XML;
+ format = F_RAW | F_XML;
+ if (output && output[0] == '-')
+ extract |= EX_COLLECT;
+ break;
+
+ case 'O': /* root output name */
+ VOT_NEXTARG(argc,argv,i);
+ output = argv[++i];
+ if (output[0] == '-') {
+ wr_stdout++;
+ quiet++;
+ if ((extract & EX_XML) || (extract & EX_KML))
+ extract |= EX_COLLECT;
+
+ memset (wrkdir, 0, SZ_FNAME);
+ sprintf (wrkdir, "%s/vod%d", tmpdir, (int)getpid());
+ if (access (wrkdir, R_OK|W_OK) != 0)
+ mkdir (wrkdir, (mode_t)0666);
+ chdir (wrkdir);
+ }
+ break;
+
+ case 'a': /* all data */
+ all_data++;
+ res_all++;
+ /*sr = -1.0; */ /* flag to get all data */
+ break;
+ case 'b': /* forced type string */
+ if (argv[i+1][0] == '/' || isdigit(argv[i+1][0]))
+ d2_band = argv[++i];
+ else
+ if (strncasecmp (argv[++i], "any", 3) != 0)
+ bpass = argv[i];
+ break;
+ case 'c':
+ count++;
+ count_only = TRUE;
+ break;
+
+ case 'e': /* extract pos/acrefs? */
+ if (strncmp (argv[i+1], "pos", 3) == 0)
+ extract |= EX_POS, i++;
+ else if (strncmp (argv[i+1], "url", 3) == 0)
+ extract |= EX_ACREF, i++;
+ else if (strncmp (argv[i+1], "head", 4) == 0)
+ extract |= EX_HTML, i++;
+ else if (strncmp (argv[i+1], "kml", 3) == 0)
+ extract |= EX_KML, i++;
+ else if (strncmp (argv[i+1], "xml", 3) == 0)
+ extract |= EX_XML, i++;
+ else
+ extract = EX_ALL;
+ break;
+
+ case 'f': /* force table read */
+ force_read++;
+ break;
+
+ case 'g': /* get specific results */
+ extract |= EX_ACREF;
+ fileRange.nvalues = RANGE_ALL;
+ file_get = RANGE_ALL;
+ break;
+
+ case 'i': /* take remaining args from file */
+ VOT_NEXTARG(argc,argv,i);
+ sv_apos = apos;
+ argfile = argv[++i];
+ if (argfile[0] == '-') {
+ if (strlen (argfile) > 1) {
+ fprintf (stderr, "ERROR: the '-i' flag requires ");
+ fprintf (stderr, "a filename or '-' for stdin\n");
+ exit (1);
+ } else if (rd_stdin) {
+ fprintf (stderr,
+ "ERROR: stdin can only be used once\n");
+ exit (1);
+ } else {
+ rd_stdin++;
+ arg_fd = stdin;
+ }
+
+ } else {
+
+ if (access (argfile, R_OK) == 0) {
+ /* Open the file, we'll process it below.
+ */
+ if ((arg_fd = fopen(argfile,"r")) == (FILE *)NULL) {
+ fprintf (stderr,
+ "ERROR: Cannot open file '%s'\n", argfile);
+ return (ERR);
+ }
+ }
+
+
+ }
+ break;
+
+ case 'M': /* verbose meta */
+ meta++, verbose = 3;
+ res_all++;
+ break;
+ case 'm': /* meta flag */
+ meta++;
+ res_all++;
+ break;
+
+ case 'n': /* no-save results */
+ save_res = FALSE;
+ count_only = TRUE;
+ break;
+
+ case 'o': /* query object name */
+ VOT_NEXTARG(argc,argv,i);
+ use_name++;
+ next_arg = argv[i+1];
+ if (next_arg[0] == '-') {
+ if (rd_stdin) {
+ fprintf (stderr,
+ "ERROR: stdin can only be used once\n");
+ exit (1);
+
+ } else {
+ rd_stdin++;
+ fixed_obj++;
+ vot_readObjFile ("-");
+ }
+ i++; /* advance argv */
+ } else if (inventory) {
+ vot_parseObjectList (argv[++i], TRUE);
+ sources = argv[i];
+ if (debug)
+ fprintf (stderr, "setting 'obj' sources = '%s'\n",
+ sources);
+ apos++;
+ } else
+ vot_parseObjectList (argv[++i], TRUE);
+ if (svcList)
+ apos++;
+ break;
+
+ case 'p': /* query position */
+ VOT_NEXTARG(argc,argv,i);
+ next_arg = argv[i+1];
+ memset (posn, 0, SZ_LINE);
+ if (next_arg[0] == '-') {
+ if (strlen (next_arg) > 1) {
+ fprintf (stderr,"ERROR: the '-p' flag requires");
+ fprintf (stderr," coords or '-' for stdin\n");
+ exit (1);
+ } else if (rd_stdin) {
+ fprintf (stderr,
+ "ERROR: stdin can only be used once\n");
+ exit (1);
+ } else {
+ rd_stdin++, fixed_pos++;
+ vot_readObjFile ("-");
+ }
+ i++; /* advance argv */
+ } else {
+ if (isSexagesimal(argv[i+1]) || isDecimal(argv[i+1])) {
+ sprintf (posn, "%s %s", argv[i+1], argv[i+2]);
+ vot_parseObjectList (posn, TRUE);
+ i += 2;
+ } else if (inventory) {
+ vot_parseObjectList (argv[++i], TRUE);
+ sources = argv[i];
+ if (debug)
+ fprintf (stderr,
+ "setting pos sources='%s'\n", sources);
+ } else
+ vot_parseObjectList (argv[++i], TRUE);
+ fixed_pos++;
+ }
+ break;
+
+ case 'q':
+ quiet++;
+ break;
+
+ case 'r': /* search radius */
+ VOT_NEXTARG(argc,argv,i);
+ sr = vot_atof (argv[++i]);
+ break;
+
+ case 's': /* data service */
+ VOT_NEXTARG(argc,argv,i);
+ if (strncmp (argv[i+1], "http", 4) == 0)
+ force_svc++;
+ next_arg = argv[i+1];
+ if (next_arg[0] == '-') {
+ if (strlen (next_arg) > 1) {
+ fprintf(stderr,"ERROR: the '-s' flag requires ");
+ fprintf(stderr,"a service name or '-' for stdin\n");
+ exit (1);
+ } else
+ vot_readSvcFile ("-", dalOnly);
+ i++; /* advance argv */
+ } else if (isdigit (argv[i+1][0])) {
+ svcNumber = vot_atoi (argv[++i]);
+ vot_parseServiceList ((resources = argv[++i]), dalOnly);
+ if (debug)
+ fprintf (stderr, "setting resources = '%s'\n",
+ resources);
+ } else {
+ vot_parseServiceList ((resources = argv[++i]), dalOnly);
+ if (debug)
+ fprintf (stderr, "setting resources = '%s'\n",
+ resources);
+ }
+ fixed_svc++;
+ apos++;
+ break;
+
+ case 't': /* forced type string */
+ VOT_NEXTARG(argc,argv,i);
+ if (strncasecmp (argv[++i], "any", 3) != 0)
+ typestr = argv[i];
+ break;
+
+ case 'u': /* forced url download */
+ url_proc++;
+ break;
+
+ case 'v': /* verbose flag */
+ verbose = min(3,(verbose+1));
+ break;
+ }
+
+
+ /* If we have a 'ch' we used a long flag, break now.
+ */
+ if (ch > 0)
+ break;
+ }
+
+ } else if (argv[i][0] == '+') {
+ len = strlen (argv[i]); /* "Engineering" flags. */
+ for (j=1; j < len; j++) {
+ switch (argv[i][j]) {
+ case 's':
+ table_hskip = vot_atoi (argv[++i]);
+ break;
+ case 'S':
+ samp++;
+ sampName = argv[++i];
+ break;
+ case 'i':
+ iportal++;
+ break;
+ case 'd':
+ debug++;
+ break;
+ case 'l':
+ svc_list = 1;
+ obj_list = 1;
+ break;
+ case 'q':
+ quiet = 0;
+ break;
+ case 'a': /* null all flag */
+ break;
+ case 'n': /* null flag */
+ break;
+
+#ifdef REG10_KLUDGE
+ case 'r':
+ reg10++;
+ break;
+#endif
+ case 'r':
+ raw_vizier = TRUE;
+ break;
+ case 't':
+ tmpdir = argv[++i];
+ break;
+ case 'v':
+ dverbose++;
+ break;
+ }
+ }
+
+ } else {
+ /* Parse the arguments according to an assumed calling
+ ** order, e.g.
+ **
+ ** vodata [ url_list | [ resource [obj | ra dec] [sr] ]
+ **
+ ** By default we assume 'sr' is in degrees, the ra/dec will
+ ** be assumed to be ICRS J200 and may be sexagesimal or decimal.
+ ** Since we're parsing the argv[], be sure to take into account
+ ** any increments added because of consumed arguments.
+ */
+ int inc = 0;
+
+ if (vot_parseArgToken (argv[i], argv[i+1], apos, &inc) != OK) {
+ exit (1);
+ } else
+ i += inc; /* add the argv[] increment */
+
+ apos++; /* update arg position */
+ }
+ }
+ re_time = time ((time_t) NULL);
+
+
+ /* Close VOClient connection. Each child process will need to reopen
+ ** their own connection, and if we're processing an argument file we'll
+ ** open/close it again as needed.
+ */
+ voc_closeVOClient (0);
+
+
+ /* If we're broadcasting the result tables, open the SAMP connection
+ ** now and let the child processes simply send the message.
+ if (samp) {
+ samp_p = sampInit ((sampname ? sampName : "VOData"),
+ "VOClient Data Access");
+ samp_setSyncMode (samp_p);
+ sampStartup (samp_p);
+ }
+ */
+
+
+ /* The control logic below allows us to process more than one
+ ** "command-line". If we got our services and objects from the
+ ** true command-line the loop will break at the bottom and we only
+ ** execute once. The service and object lists were created when
+ ** processing the arguments above. OTOH, if we're using an argument
+ ** file, those lists are now NULL and we'll read each line of the
+ ** argfile and create them now. In either case, we clean up and
+ ** reset the lists at the bottom of the loop.
+ */
+
+ while (1) {
+
+ /* If we're processing from the stdin or an argument file,
+ ** get the next line of the file and fake the commandline to
+ ** set the resource and object lists. Note we clean up and
+ ** reset below to permit each iteration to process a different
+ ** number of resources or objects.
+ */
+ if (arg_fd) {
+ if (vot_getNextCmdline () != OK)
+ break;
+ }
+
+
+ /* Tally up the the number of services and objects to be queried.
+ */
+ if ((nservices = vot_countServiceList()) == 1)
+ svc_list = 0;
+ if ((nobjects = vot_countObjectList()) == 1)
+ obj_list = 0;
+
+#ifdef VO_INVENTORY
+ /* If we're calling the Inventory service, branch to do it here and
+ ** then continue with the loop.
+ */
+ if (inventory) {
+ if (debug)
+ fprintf (stderr, "inventory nserv = %d nobj = %d\n",
+ nservices, nobjects);
+
+ if (nobjects == 0 && sources == NULL) {
+ fprintf (stderr, "No object position(s) specified.\n");
+ exit (1);
+
+ } else {
+ vot_printSvcHdr ();
+ qs_time = time ((time_t) NULL);
+ (void) vot_doInventory ();
+ qe_time = time ((time_t) NULL);
+ }
+
+ vot_printProcTime ();
+ break;
+ }
+#endif
+
+ /* If we have services to call and aren't simply downloading URLs,
+ ** process the service queries first.
+ */
+ if (svcList && !url_proc) {
+
+ /* See whether any flags negate other options.
+ */
+ if (vot_validateOptions() == ERR)
+ break;
+
+ /* Print header information.
+ */
+ vot_printSvcHdr ();
+
+ /* Now run the serice queries. Each service is run on a separate
+ ** thread, we'll handle summary output and any postprocessing later.
+ */
+ vot_runSvcThreads ();
+ }
+
+ /* Process the access reference list to download any pending data.
+ */
+ if (acList && nacrefs)
+ vot_procAclist ();
+
+ /* Free up any memory we may have allocated. Counters and pointers
+ ** are reset in each routine.
+ */
+ vot_freeAclist (); /* access reference list */
+ vot_freeObjectList (); /* object list */
+ if (sv_apos < 0)
+ vot_freeServiceList (); /* VO resource list */
+ else
+ vot_resetServiceCounters ();
+
+
+ /* Print an approximate summary of the processing time required.
+ */
+ vot_printProcTime ();
+
+ /* If we're not processing from an argument file or the
+ ** stdin, we've processed the argv from the commandline, so
+ ** break here.
+ */
+ if (!arg_fd)
+ break;
+ }
+
+
+ if (arg_fd && arg_fd != stdin) /* close the argument file */
+ fclose (arg_fd);
+
+ if (wr_stdout && wrkdir[0] && access (wrkdir, R_OK|W_OK) == 0)
+ rmdir (wrkdir); /* clean up wrkdirs */
+
+ /*
+ if (samp)
+ samp_UnRegister (samp_p);
+ */
+
+ return ( status );
+}
+
+
+
+
+/* Set an argument that may optionally be specified as an entire word.
+*/
+
+#define ARG_DONE -1
+
+static char
+vot_setArgWord (char *arg, char *next, char **argv, int argc)
+{
+fprintf (stderr, "setArg: arg = '%s'\n", arg);
+
+ if (arg[0] == '-') {
+ fprintf (stderr, "Invalid argument string '--'\n");
+ exit(1);
+
+ /* '--' only FLAGS */
+ } else if (strncmp (arg, "bandpass", 8) == 0) {
+ bpass = vot_requiredArg (arg);
+
+ } else if (strncmp (arg, "cols", 4) == 0) {
+ cols = vot_requiredArg (arg);
+
+ } else if (strncmp (arg, "delim", 5) == 0) {
+ delim = vot_requiredArg (arg);
+ switch (delim[0]) {
+ case 's': delim = " "; break;
+ case 'c': delim = ","; break;
+ case 't': delim = "\t"; break;
+ case 'b': delim = "|"; break;
+ }
+
+ } else if (strncmp (arg, "extract", 7) == 0) {
+
+ if (arg[7] != '=') /* just "--extract" */
+ extract |= EX_ALL;
+
+ else {
+ (void) vot_requiredArg (arg);
+ switch (arg[8]) {
+ case 'h': extract |= EX_HTML; break; /* html */
+ case 'k': extract |= EX_KML; break; /* KML */
+ case 'K': extract |= EX_KML;
+ extract |= EX_COLLECT; break; /* one-file KML */
+ case 'p': extract |= EX_POS; break; /* positions */
+ case 'u': extract |= EX_ACREF; break; /* urls */
+ case 'X': extract |= EX_XML;
+ format = (F_RAW | F_XML);
+ extract |= EX_COLLECT; break; /* one-file XML */
+ default: extract = EX_BOTH; break; /* all */
+ }
+ }
+
+ } else if (strncmp (arg, "ecols", 5) == 0) {
+ ecols = vot_requiredArg (arg);
+
+ } else if (strncmp (arg, "get", 3) == 0) {
+ char *ip = vot_optionalArg (arg);
+
+ extract |= EX_ACREF;
+ if (ip == NULL || !(isdigit(*ip)) ) {
+ /* No option implies we get all rows.
+ */
+ fileRange.nvalues = RANGE_ALL;
+ file_get = RANGE_ALL;
+ } else {
+ /* Next arg is a range string.
+ */
+ strcpy (fileRange.rstring, ip);
+ if (vot_decodeRanges (fileRange.rstring,
+ fileRange.ranges, MAX_RANGES, &fileRange.nvalues) < 0) {
+ fprintf (stderr, "Error decoding range string.\n");
+ }
+ file_get = fileRange.nvalues;
+ }
+
+ } else if (strncmp (arg, "hskip", 5) == 0) {
+ table_hskip = vot_atoi ( vot_requiredArg (arg) );
+
+ } else if (strncmp (arg, "kml", 3) == 0) {
+
+ (void) vot_requiredArg (arg);
+ switch (arg[3]) {
+ case 'm': /* max placemarks --kmlmax=N */
+ kml_max = vot_atoi(&arg[7]);
+ break;
+ case 'g': /* grouping --kmlgroup=type */
+ switch (arg[9]) {
+ case 'b': /* group by both */
+ kml_byBoth = TRUE;
+ kml_byObj = FALSE, kml_bySvc = FALSE;
+ break;
+ case 'o': /* group by object */
+ kml_byObj = TRUE;
+ kml_byBoth = FALSE, kml_bySvc = FALSE;
+ break;
+ case 's': /* group by service */
+ kml_bySvc = TRUE;
+ kml_byObj = FALSE, kml_byBoth = FALSE;
+ break;
+ }
+ break;
+ case 's': /* sample placemarks --kmlsample=N */
+ kml_sample = vot_atoi(&arg[10]);
+ break;
+
+ case 'n': /* sample placemarks --kmlno<opt */
+ switch (arg[5]) {
+ case 'l': /* disable labels */
+ kml_label = FALSE;
+ break;
+ case 'r': /* disable region box */
+ kml_region = FALSE;
+ break;
+ case 'v': /* disable verbose label*/
+ kml_verbose = FALSE;
+ break;
+ }
+ }
+
+ if (strncmp (arg, "kmlgroup", 8) == 0)
+ extract |= EX_KML;
+
+ } else if (strncmp (arg, "max", 3) == 0) {
+ char *ip = vot_requiredArg (arg);
+
+ switch (arg[3]) {
+ case 'd': /* --maxdownloads=<N> */
+ max_download = vot_atoi(ip);
+ max_download = min(MAX_DOWNLOADS,max_download);
+ break;
+ case 'p': /* --maxprocs=<N> */
+ max_procs = vot_atoi(ip);
+ max_procs = min(MAX_PROCS,max_procs);
+ break;
+ case 't': /* --maxthreads=<N> */
+ max_threads = vot_atoi(ip);
+ max_threads = min(MAX_THREADS,max_threads);
+ break;
+ }
+
+ } else if (strncmp (arg, "nlines", 6) == 0) {
+ table_nlines = vot_atoi ( vot_requiredArg (arg) );
+
+ } else if (strncmp (arg, "object", 6) == 0) {
+ char *ip = vot_requiredArg (arg);
+
+ use_name++;
+ if (!ip || ip[0] == '-') {
+ if (rd_stdin) {
+ fprintf (stderr, "ERROR: stdin can only be used once\n");
+ exit (1);
+
+ } else {
+ rd_stdin++;
+ fixed_obj++;
+ vot_readObjFile ("-");
+ }
+ } else if (inventory) {
+ vot_parseObjectList (ip, TRUE);
+ sources = ip;
+ if (debug)
+ fprintf (stderr, "setting 'obj' sources = '%s'\n", sources);
+ apos++;
+ } else
+ vot_parseObjectList (ip, TRUE);
+ if (svcList)
+ apos++;
+
+ } else if (strncmp (arg, "output", 6) == 0) {
+ char *ip = vot_requiredArg (arg);
+
+ output = (ip ? ip : "=");
+ if (output[0] == '-') {
+ wr_stdout++;
+ quiet++;
+ if ((extract & EX_XML) || (extract & EX_KML))
+ extract |= EX_COLLECT;
+
+ memset (wrkdir, 0, SZ_FNAME);
+ sprintf (wrkdir, "%s/vod%d", tmpdir, (int)getpid());
+ if (access (wrkdir, R_OK|W_OK) != 0)
+ mkdir (wrkdir, (mode_t)0666);
+ chdir (wrkdir);
+ }
+
+ } else if (strncmp (arg, "pos", 3) == 0) {
+ char posn[SZ_LINE];
+ char *ip = vot_requiredArg (arg);
+
+ if (ip[0] == '-') {
+ if (strlen (ip) > 1) {
+ fprintf (stderr,"ERROR: the '--pos' flag requires ");
+ fprintf (stderr,"coords or '-' for stdin\n");
+ exit (1);
+ } else if (rd_stdin) {
+ fprintf (stderr, "ERROR: stdin can only be used once\n");
+ exit (1);
+ rd_stdin++, fixed_pos++;
+ } else {
+ vot_readObjFile ("-");
+ }
+ } else {
+ char v1[SZ_FNAME], v2[SZ_FNAME], *op;
+
+ op = strchr (arg, (int)','); /* find delimiter */
+ memset (v1, 0, SZ_FNAME); /* clear arrays */
+ memset (v2, 0, SZ_FNAME);
+ if (op) {
+ *op = '\0';
+ strcpy (v1, ip); /* first arg */
+ strcpy (v2, op+1); /* second arg */
+ } else {
+ fprintf (stderr, "ERROR: Invalid '--pos' argument\n");
+ exit (1);
+ }
+
+ if (isSexagesimal(v1) || isDecimal(v1)) {
+ sprintf (posn, "%s %s", v1, v2);
+ fixed_pos++;
+ vot_parseObjectList (posn, TRUE);
+ } else if (inventory) {
+ vot_parseObjectList ((sources = ip), TRUE);
+ apos++;
+ } else
+ vot_parseObjectList (ip, TRUE);
+ }
+ if (fixed_svc)
+ apos++;
+
+ } else if (strncmp (arg, "proxy", 5) == 0) {
+ proxy++;
+
+ } else if (strncmp (arg, "sample", 6) == 0) {
+ table_sample = vot_atoi ( vot_requiredArg (arg) );
+
+ } else if (strncmp (arg, "sr", 2) == 0) {
+ char *ip = vot_requiredArg (arg);
+ int len = strlen(ip);
+ char units = ip[len-1];
+
+ if (!isdigit(units))
+ ip[len-1] = '\0';
+ else
+ units = 'd';
+ switch (units) {
+ case 's': sr = vot_atof (ip) / 3600.; break;
+ case 'm': sr = vot_atof (ip) / 60.; break;
+ case 'd': sr = vot_atof (ip); break;
+ }
+
+
+ } else if (strncmp (arg, "svc", 3) == 0) {
+ char *ip = vot_requiredArg (arg);
+
+ if (strncmp (ip, "http", 4) == 0)
+ force_svc++;
+ if (ip[0] == '-') {
+ if (strlen (ip) > 1) {
+ fprintf (stderr,"ERROR: the '-s' flag requires ");
+ fprintf (stderr,"a service name or '-' for stdin\n");
+ exit (1);
+ } else
+ vot_readSvcFile ("-", dalOnly);
+ } else {
+ vot_parseServiceList ((resources = ip), dalOnly);
+ if (debug)
+ fprintf (stderr, "setting resources = '%s'\n", resources);
+ if (inventory)
+ apos++;
+ }
+ fixed_svc++;
+ apos++;
+ if (fixed_pos)
+ apos++;
+
+ } else if (strncmp (arg, "type", 4) == 0) {
+ typestr = vot_requiredArg (arg);
+
+ } else if (strncmp (arg, "verbose", 7) == 0) {
+ verbose = min (3, vot_atoi ( vot_optionalArg (arg)) );;
+
+ } else if (strncmp (arg, "vverbose", 8) == 0) {
+ verbose = 3;
+
+
+ } else if (strncmp (arg, "web", 3) == 0) {
+ char *val = vot_requiredArg (arg);
+ switch (val[0]) {
+ case 'b': html_border = FALSE; break; /* disable table border */
+ case 'c': html_color = FALSE; break; /* disable verbose label */
+ case 'h': html_header = FALSE; break; /* disable region box */
+ }
+
+ /* DAL2 OPTION FLAGS */
+ } else if (strncmp (arg, "band", 4) == 0) {
+ d2_band = vot_requiredArg (arg);
+ } else if (strncmp (arg, "time", 4) == 0) {
+ d2_time = vot_requiredArg (arg);
+ } else if (strncmp (arg, "format", 6) == 0) {
+ d2_format = vot_requiredArg (arg);
+ } else if (strncmp (arg, "version", 7) == 0) {
+ d2_version = vot_requiredArg (arg);
+
+ /* MISC OPTION FLAGS */
+ } else if (strncmp (arg, "all", 3) == 0) { return ('a');
+ } else if (strncmp (arg, "count", 5) == 0) { return ('c');
+ } else if (strncmp (arg, "force", 5) == 0) { return ('f');
+/* } else if (strncmp (arg, "get", 3) == 0) { return ('g'); */
+ } else if (strncmp (arg, "help", 4) == 0) { return ('h');
+ } else if (strncmp (arg, "inventory",9) == 0) { return ('I');
+ } else if (strncmp (arg, "nosave", 6) == 0) { return ('n');
+ } else if (strncmp (arg, "one", 3) == 0) { return ('1');
+ } else if (strncmp (arg, "quiet", 5) == 0) { return ('q');
+ } else if (strncmp (arg, "url", 3) == 0) { return ('u');
+
+ /* OUTPUT FORMAT FLAGS */
+ } else if (strncmp (arg, "ascii", 5) == 0) { return ('A');
+ } else if (strncmp (arg, "csv", 3) == 0) { return ('C');
+ } else if (strncmp (arg, "tsv", 3) == 0) { return ('T');
+ } else if (strncmp (arg, "fits", 4) == 0) { return ('F');
+ } else if (strncmp (arg, "kml", 3) == 0) { return ('K');
+ } else if (strncmp (arg, "html", 4) == 0) { return ('H');
+ } else if (strncmp (arg, "raw", 3) == 0) { return ('R');
+ } else if (strncmp (arg, "xml", 3) == 0) { return ('X');
+ } else if (strncmp (arg, "votable", 7) == 0) { return ('V');
+
+ }
+
+fprintf (stderr, "setArg: ARG_DONE\n");
+ return (ARG_DONE);
+}
+
+
+static char *
+vot_requiredArg (char *arg)
+{
+ char *ip = strchr (arg, (int)'=');
+
+ if (!ip) {
+ fprintf (stderr, "ERROR: Missing '--%s' argument.\n", arg);
+ exit (1);
+ }
+
+ return (++ip);
+}
+
+static char *
+vot_optionalArg (char *arg)
+{
+ char *ip = strchr (arg, (int)'=');
+
+ if (!ip)
+ return (NULL);
+ else
+ return (++ip);
+}
+
+
+
+
+/************************************************************************
+** PARSEARGTOKEN -- Parse the argument based on it's position on the
+** command line. Some actions will require the next argument in the
+** command, otherwise the 'next' pointer will usually be NULL. This
+** routine can be used to parse either the argv commands or those from
+** a file. The 'inc' variable will indicate how far to advance the
+** argument counter as a result of this procedure.
+*/
+static int
+vot_parseArgToken (char *arg, char *next, int pos, int *inc)
+{
+ char posn[64];
+
+ *inc = 0;
+
+ /* Parse the arguments according to an assumed calling
+ ** order, i.e.
+ **
+ ** vodata [ url_list | [ resource [obj | ra dec] [sr] ]
+ **
+ ** By default we assume size is in degrees, the ra/dec will
+ ** be assumed to be ICRS J200 and may be sexagesimal or decimal.
+ */
+ switch (apos) {
+ case 0: /* <resource> | <url> */
+ if (arg[0] != '/' && (isSexagesimal (arg) || isDecimal (arg))) {
+ fprintf (stderr,
+ "\nERROR: First argument required to be resource or url.\n");
+ return (ERR);
+ }
+
+ if (strncmp (arg, "http", 4) == 0 && !force_svc && url_proc) {
+ /* If this is a simple URL, simply download the result. */
+ vot_addToAclist (arg, NULL);
+ if (!fixed_pos)
+ apos--;
+ url_proc++;
+
+#ifdef VO_INVENTORY
+ } else if (inventory) {
+ /* If we're doing an incentory call, the first arg is only
+ ** allowed to be either 'any', and 'ivorn', or (eventually) a
+ ** file of resources to be uploads.
+ */
+ if (strcasecmp ("any",arg) == 0 ||
+ strncmp (arg, "ivo://", 6) == 0 ||
+ access (arg, R_OK) == 0) {
+ if (strncmp (arg, "ivo://", 6) == 0) {
+ extern char *id;
+ id = arg;
+ }
+ if (access (arg, R_OK) == 0)
+ resources = arg;
+ vot_parseServiceList (arg, 0);
+
+ } else {
+ fprintf (stderr, "Invalid resource type for Inventory, '%s'\n",
+ arg);
+ exit (1);
+ }
+#endif
+
+ } else if (raw_vizier && strncmp ("ivo://CDS", arg, 9) == 0) {
+ char url[SZ_LINE];
+ char *res = &arg[17];
+ char *base =
+ "http://vizier.u-strasbg.fr/viz-bin/votable/-dtd/-A?-source=";
+
+ sprintf (url, "%s%s", base, res);
+
+ /*
+ */
+ vot_parseServiceList (url, 0);
+ if (!fixed_pos)
+ apos--;
+ url_proc++;
+
+ } else {
+ /* Restrict 'any' searches to DAL only to save time.
+ */
+ if (strncasecmp ("any", arg, 3) == 0)
+ dalOnly = 1;
+ vot_parseServiceList (arg, dalOnly);
+ if (fixed_pos)
+ apos++;
+ }
+
+ break;
+
+ case 1: /* <obj> | <pos>*/
+ /* Sanity checks. */
+ if (force_svc && typestr && strchr(typestr,(int)',')) {
+ fprintf (stderr,
+ "\nERROR: Only one type may be given to used-defined service.\n");
+ return (ERR);
+
+ } else if (force_svc && !typestr && !fixed_svc) {
+ fprintf (stderr,
+ "\nERROR: No type specified for used-defined service.\n");
+ return (ERR);
+
+ } else if (!url_proc && !svcList && !inventory) {
+ fprintf (stderr,
+ "\nERROR: No supported DAL service types found.\n");
+ return (ERR);
+ }
+
+ /* Parse the object or position. */
+ if (isSexagesimal (arg) || isDecimal (arg)) {
+ memset (posn, 0, 64);
+ sprintf (posn, "%s %s", arg, next);
+ vot_parseObjectList (posn, TRUE);
+ *inc = 1;
+ } else {
+ use_name++;
+ if (inventory && access (arg, R_OK) == 0)
+ sources = arg;
+ vot_parseObjectList (arg, TRUE);
+ }
+ break;
+
+ case 2: /* <size> (degrees) */
+ sr = vot_atof (arg);
+ break;
+
+ default:
+ fprintf (stderr, "Warning: Unknown argument syntax\n");
+ vot_printUsage ();
+ return (ERR);
+ }
+
+ return (OK);
+}
+
+
+/************************************************************************
+** GETNEXTCMDLINE -- Process the next command line from the argument
+** file. We do this by reading a line of the file and tokenizing it
+** as if the values were given to us on the command-line. For the
+** moment we don't allow options to be set and permit only the positional
+** arguments (e.g. resource, object, coords).
+*/
+static int
+vot_getNextCmdline ()
+{
+ int i, inc;
+ char *tok, *sep = " ", *line, cmdline[SZ_LINE];
+ int a_argc = 0;
+ char a_argv[4][SZ_LINE];
+
+ extern char *vot_getline (FILE *fd);
+
+
+ memset (a_argv, 0, (4 * SZ_LINE));
+ memset (cmdline, 0, SZ_LINE);
+
+ if (( line = vot_getline (arg_fd)))
+ strcpy (cmdline, line);
+ else
+ return (ERR);
+
+
+ for (tok = strtok(cmdline, sep); tok; tok = strtok(NULL, sep)) {
+ strcpy (a_argv[a_argc++], tok);
+ }
+
+ if (voc_initVOClient ("runid=voc.vodata") == ERR)
+ exit (-1);
+
+ apos = sv_apos;
+ for (i=0; i < a_argc; i++) {
+ if (vot_parseArgToken (a_argv[i], a_argv[i+1], apos, &inc) != OK) {
+ exit (1);
+ } else
+ i += inc; /* add the argv[] increment */
+
+ apos++; /* update arg position */
+ }
+
+
+ /* Close the VOClient connection since each child will use its own.
+ */
+ voc_closeVOClient (0); /* close VOClient connection */
+
+ return (OK);
+}
+
+
+/************************************************************************
+** VALIDATEOPTIONS -- Verify that all the commandline options make sense
+** before we begin processing. Some options will require others and we
+** can only check after all the options have been set and parsed from
+** the command line.
+*/
+static int
+vot_validateOptions ()
+{
+ if (count)
+ fileRange.nvalues = RANGE_NONE;
+
+ if (nobjects < 1) {
+ if (apos && !meta && !all_data) {
+ /* User provided an object, but it was invalid.
+ */
+ fprintf (stderr, "Error: No valid position or object found.\n");
+ return (ERR);
+
+ } else {
+ /* No position/object supplied, use default.
+ */
+ if (!quiet && !meta)
+ fprintf (stderr, "# Using default position: 0.0 0.0\n");
+ vot_parseObjectList ("0.0 0.0", TRUE);
+ nobjects = vot_countObjectList();
+ }
+ }
+
+ if (output && output[0] == '-')
+ extract |= EX_COLLECT;
+
+ if (kml_sample)
+ kml_max *= kml_sample;
+
+ if (meta && nservices == 0) {
+ fprintf (stderr, "ERROR: No service specified.\n");
+ return (ERR);
+ } else if (meta && nservices == 1) {
+ output = "-";
+ wr_stdout++;
+ quiet++;
+ }
+
+ return (OK);
+}
+
+
+
+/************************************************************************
+** PRINTSVCHDR -- Print a header for service output.
+*/
+void
+vot_printSvcHdr ()
+{
+ if (!quiet) {
+ printf ("\n");
+ if (meta) {
+ if (nservices == 1)
+ fprintf (stderr, "# Service: %s\n", svcList->name);
+ fprintf (stderr, "# No. of Services: %d\n", nservices);
+ } else {
+ if (nservices == 1) {
+ fprintf (stderr, "# Service: %s\n", svcList->name);
+ fprintf (stderr, "# Title: %s\n", svcList->title);
+ }
+ fprintf (stderr, "# No. of Objects: %d\n", nobjects);
+ fprintf (stderr, "# No. of Services: %d\n", nservices);
+ }
+ fprintf (stderr, "# Search size: %f (degrees)\n#\n", sr);
+ if (count || inventory)
+ vot_printCountHdr ();
+ }
+
+ fflush (stdout);
+}
+
+
+/************************************************************************
+** RUNSVCTHREADS -- Begin a processing thread for each data service. We
+** split the object list over each service in parallel threads.
+*/
+static void
+vot_runSvcThreads ()
+{
+ int t, tc, rc, status, t_start, t_end, nthreads;
+/*
+ pthread_t thread[nservices];
+*/
+ static pthread_t thread[10000];
+ Service *svc = svcList;
+ Proc *new = (Proc *)NULL;
+ Proc *cur = (Proc *)NULL;
+ pthread_attr_t attr; /* thread attributes */
+
+
+ qs_time = time ((time_t) NULL);
+
+ if (verbose && !count && !meta && nservices > 1)
+ fprintf (stderr, "# Creating service processing threads...\n");
+
+ /* Pre-allocate the process lists so they're in the global memory
+ ** space.
+ */
+ for (svc=svcList; svc; svc=svc->next) {
+ for (t=0; t < nobjects; t++) {
+ new = (Proc *) calloc (1, sizeof (Proc));
+ new->svc = (Service *) svc; /* set back pointer */
+ if (t == 0) {
+ svc->proc = new;
+ cur = svc->proc;
+ } else {
+ cur->next = new;
+ cur = cur->next;
+ }
+ }
+ }
+
+ nthreads = min (nservices, max_threads);
+ t_start = 0;
+ t_end = nthreads;
+
+
+ /* Spawn the processing threads.
+ */
+ svc = svcList;
+ for (tc=0; tc < nservices; tc += nthreads) {
+ t_end = min((nservices-tc),nthreads);
+
+ /* Initialize the service processing thread attributes and run 'em.
+ */
+ pthread_attr_init (&attr);
+ pthread_attr_setdetachstate (&attr, PTHREAD_CREATE_JOINABLE);
+
+ for (t=0; t < t_end; t++, svc=svc->next) {
+ if ((rc = pthread_create (&thread[t], &attr, vot_procObjs,
+ (void *)svc))) {
+ fprintf (stderr,
+ "ERROR: pthread_create() fails, code: %d\n", rc);
+ exit (-1);
+ }
+ }
+
+ /* Free attribute and wait for the threads to complete.
+ */
+ for (t=0; t < t_end; t++) {
+ if ((rc = pthread_join (thread[t], (void **)&status)) ) {
+ /*
+ fprintf (stderr, "ERROR: pthread_join() fails, code: %d\n", rc);
+ exit (-1);
+ */
+ ;
+ }
+ }
+
+ pthread_attr_destroy (&attr);
+ }
+ qe_time = time ((time_t) NULL);
+
+ if ((debug && verbose > 1)) {
+ fprintf (stderr, "\n\n..........THREAD PROCS COMPLETED.....\n");
+ vot_printSvcList (svcList);
+ fprintf (stderr, "..........THREAD PROCS COMPLETED.....\n\n\n");
+ }
+
+
+ /* If we're only writing a KML file and not simply extracting them
+ ** as an extra, concatenate the results from each query to a single
+ ** file for easier browsing.
+ */
+ if (format & F_KML || (extract & EX_KML && extract & EX_COLLECT)) {
+ char fname[SZ_FNAME];
+ extern void vot_concatKML (char *fname);
+
+ memset (fname, 0, SZ_FNAME);
+ if (output && output[0] != '-')
+ sprintf (fname, "Query_%d.kml", (int)getpid());
+ else
+ strcpy (fname, "-");
+ if (nservices > 1 && nobjects > 1)
+ vot_concatKML (fname);
+
+ } else if (format & F_XML || (extract & EX_XML && extract & EX_COLLECT)) {
+ char fname[SZ_FNAME];
+ extern void vot_concatXML (char *fname);
+
+ memset (fname, 0, SZ_FNAME);
+ if (output && output[0] != '-')
+ sprintf (fname, "Query_%d.xml", (int)getpid());
+ else
+ strcpy (fname, "-");
+
+ if (nservices > 1 && nobjects > 1)
+ vot_concatXML (fname);
+
+ } else if (extract & EX_COLLECT) {
+ extern void vot_concat (void);
+
+ vot_concat (); /* concatenate results */
+ }
+
+
+ /* For verbose output, print a summary of the processing history.
+ */
+ if (!quiet && count && !meta) {
+ Proc *curproc = (Proc *) NULL;
+ Proc *proc = (Proc *) NULL;
+ char *pad, *lpad;
+
+ int tot_rec = 0; /* Total records found */
+ int tot_fail = 0; /* No. failed service calls */
+ int tot_nodata= 0; /* No. of no-data results */
+ int tot_query = 0; /* No. of queries */
+
+ tot_query = (nservices * nobjects);/* Total No. queries made */
+
+ for (svc=svcList; svc; svc=svc->next) {
+ tot_rec += (svc->count > 0 ? svc->count : 0);
+ tot_fail += svc->nfailed;
+ tot_nodata += svc->nnodata;
+ }
+
+ pad = (nobjects == 1) ? "\t\t\t" : "\t\t\t\t\t";
+ lpad = (nobjects == 1) ? "---------------" : "";
+ printf ("\n");
+ printf ("#%s-------------------------------------%s\n", pad, lpad);
+/*
+ printf ("#%s%4d (Records Found)\n", pad, tot_rec);
+ printf ("#%s%4d (Resources Queried)\n", pad, tot_query);
+ printf ("#%s%4d (Failed Requests)\n", pad, tot_fail);
+ printf ("#%s%4d (Completed Requests)\n", pad, (tot_query-tot_fail));
+ printf ("#%s\t (%d Results w/ Data)\n", pad,
+ (tot_query - tot_fail - tot_nodata));
+*/
+ fprintf (stderr, "#%s%4d (Records Found)\n", pad, tot_rec);
+ fprintf (stderr, "#%s%4d (Resources Queried)\n", pad, tot_query);
+ fprintf (stderr, "#%s%4d (Failed Requests)\n", pad, tot_fail);
+ fprintf (stderr, "#%s%4d (Completed Requests)\n", pad,
+ (tot_query - tot_fail));
+ fprintf (stderr, "#%s\t (%d Results w/ Data)\n", pad,
+ (tot_query - tot_fail - tot_nodata));
+ if (tot_nodata)
+ printf ("#%s\t (%d Results w/ No Data)\n", pad, tot_nodata);
+ printf ("#\n");
+
+ if (verbose < 3)
+ return;
+
+ svc = svcList;
+ for (t=0; t < nservices; t++, svc=svc->next) {
+ if (svc->nfailed || !FAILED_ONLY)
+ vot_printProcStat (svc->proc, svc->name, FAILED_ONLY);
+
+ /* Free the proctable structure.
+ */
+ for (curproc=svc->proc; curproc; curproc=proc) {
+ proc = curproc->next;
+ if (curproc)
+ free ((void *) curproc);
+ }
+ }
+ }
+}
+
+
+/************************************************************************
+** PRINTSVCLIST -- Debug routine to print the SvcList.
+*/
+void
+vot_printSvcList (Service *sl)
+{
+ Service *s;
+ Proc *p;
+
+ for (s=sl; s; s=s->next) {
+ fprintf (stderr, "%15s: nfail=%d nrefs=%d type=%d\ts=%ld\n",
+ s->name, s->nfailed, s->nrefs, s->type, (long)s);
+
+ for (p=s->proc; p; p=p->next) {
+ fprintf (stderr, "\t\tpid=%d status=%d obj=%s\t p=%ld\n",
+ p->pid, p->status, p->obj->name, (long)p);
+ }
+ }
+}
+
+
+/************************************************************************
+** PROCOBJS -- Create threads to process the object list. Our only
+** argument is the Service object to run.
+*/
+void *
+vot_procObjs (void *arg)
+{
+ int nobj, nprocs, nrunning, nremaining, nupdate;
+ int lock, nrep, status;
+ pid_t r_pid, pid;
+
+ Object *obj = objList;
+ Service *svc = (Service *)arg;
+ Proc *curproc = (Proc *) svc->proc;
+ svcParams pars;
+
+
+ /* Figure out how many threads to run at a time.
+ */
+ nprocs = ( (nobjects > max_threads) ? max_threads : nobjects );
+ nupdate = 10;
+
+ nrep = nrunning = 0;
+ nremaining = nobjects;
+
+ for (nobj=1; nremaining > 0; ) {
+
+ if (debug)
+ fprintf (stderr, "procObjs(%s): n=%d/%d nprocs=%d nrun=%d sr=%f\n",
+ svc->name, nobj, nobjects, nprocs, nrunning, sr);
+
+ /* Spawn a process thread for each object/position.
+ */
+ if (nrunning < nprocs && nobj <= nobjects) {
+
+ /* Set up the service parameter struct. Each thread gets its
+ ** own instance.
+ */
+ strcpy (pars.service_url, vizPatch(svc->service_url));
+ strcpy (pars.identifier, svc->identifier);
+ strcpy (pars.name, svc->name);
+ if (id_col && obj->id && obj->id[0])
+ strcpy (pars.oname, obj->id);
+ else
+ strcpy (pars.oname, obj->name);
+ strcpy (pars.title, svc->title);
+ pars.ra = obj->ra;
+ pars.dec = obj->dec;
+
+ /* Prior to Registry 1.0 we didn't have a real cone capability
+ ** for Vizier tables and needed to set flags to download the
+ ** entire table. This is no longer necessary, the user can set
+ ** a negative search radius to get the entire table if they choose.
+
+ pars.sr = sr;
+ */
+ if (all_data && svc->type == SVC_VIZIER)
+ pars.sr = -1.0;
+ else
+ pars.sr = sr;
+ pars.fmt = format;
+ pars.type = svc->type;
+ pars.index = nobj;
+ pars.obj_index = nobj - 1; /* zero-indexed */
+ pars.svc_index = svc->index;
+
+ if ((pid = (*(PFI)(*svc->func))((void *)&pars)) < 0) {
+ fprintf (stderr,"ERROR: process fork() fails\n");
+ pthread_exit ((void *) NULL);
+ }
+ nrunning++;
+ nobj++;
+
+ /* Allocate the process summary struct. Only save the status if
+ ** we'll be printing a summary later.
+ */
+ if ((extract & EX_COLLECT) || !quiet) {
+
+ /* Lock the thread to protect us from messing with the
+ ** service list data.
+ */
+ lock = pthread_mutex_lock (&svc_mutex);
+ curproc->pid = pid; /* load the process struct */
+ curproc->obj = obj;
+ curproc->status = 0;
+ memset (curproc->root, 0, SZ_FNAME);
+ if (use_name || all_named || id_col)
+ strcpy (curproc->root, vot_getOFName(&pars,NULL,(int)pid));
+ else
+ strcpy (curproc->root, vot_getOFIndex(&pars,NULL,(int)pid));
+
+
+ curproc = curproc->next; /* move on */
+ lock = pthread_mutex_unlock (&svc_mutex);
+ }
+
+ if (debug)
+ fprintf (stderr, "procObjs(%s): %d ra=%f dec=%f pid=%d\n",
+ svc->name, nobj, obj->ra, obj->dec, pid);
+
+ if (obj)
+ obj = obj->next;
+
+ } else {
+
+ /* Process table full, wait for any child processes to complete.
+ */
+ if (debug)
+ fprintf (stderr, "procObjs(%s:%d): waiting %d remaining....\n",
+ svc->name, getpid(), nremaining);
+
+ if ((r_pid = waitpid ((pid_t)-1, &status, (int) 0)) < 0 ) {
+ /* FIXME
+ if (verbose || debug)
+ fprintf (stderr, "ERROR: waitpid() fails, code[%d] %s\n",
+ (int)errno, strerror(errno));
+ pthread_exit ((void *) NULL);
+ */
+ }
+
+ status = WEXITSTATUS(status);
+ if (debug)
+ fprintf (stderr, "pid = %d stat = %d\n", r_pid, status);
+
+ lock = pthread_mutex_lock (&svc_mutex);
+ vot_setProcStat (svc, (int)r_pid, status);
+ lock = pthread_mutex_unlock (&svc_mutex);
+
+ nrunning--;
+ nremaining--;
+ }
+
+ if (!quiet && nobj < nobjects && (nobj % nupdate) == 0 &&
+ !count && !file_get && nrep == 0) {
+ fprintf (stderr,
+ "# Service %15s: Completed %3d of %4d objects (%d running)\n",
+ svc->name, nobj, nobjects, nrunning);
+ nrep = 1;
+ } else if (nrep == 1)
+ nrep = 0;
+ }
+
+ if (!quiet && !count && !file_get && !meta) {
+ fprintf (stderr, "# Service %25s: ", svc->name);
+ fprintf (stderr, "Finished processing (%d of %d succeeded).\n",
+ (nobjects - (svc->nfailed + svc->nnodata)),
+ nobjects);
+ }
+ if (debug)
+ fprintf (stderr, "procObjs done (%s).\n", svc->name);
+
+
+ pthread_exit (NULL);
+}
+
+
+static char *
+vizPatch (char *url)
+{
+ static char new[SZ_LINE], *ip, *op;
+
+ memset (new, 0, SZ_LINE);
+ for (ip=url, op=new; *ip; ) {
+ if (*ip == '&' && *(ip+1) == '/')
+ ip++;
+ *op++ = *ip++;
+ }
+
+ return (new);
+}
+
+
+/************************************************************************
+** SETPROCSTAT -- Set the process return status. 'procList' is the
+** process list running on this particular thread.
+*/
+static void
+vot_setProcStat (Service *svc, int pid, int status)
+{
+ Service *s = svcList;
+ Proc *pp;
+ int i, rc, sem_id, n = nservices;
+
+ if (svcList == (Service *) NULL)
+ return;
+
+ for (s=svcList; s; s=s->next, n--) {
+ for (pp=s->proc; pp; pp=pp->next) {
+ if (pp->pid == pid) {
+ /* Set the status for this svc/obj process.
+ */
+ pp->status = status;
+ if (status == E_REQFAIL)
+ s->nfailed++;
+ if (status == E_NODATA)
+ s->nnodata++;
+
+ /* If we created a URL extraction, add the URLS to the
+ ** access list.
+ */
+ if (extract == EX_ACREF || extract == EX_BOTH) {
+ char fname[SZ_FNAME], url[SZ_URL];
+ FILE *fd;
+ int nf = 1;
+
+ /* Get the filename of the URLs we'll get.
+ */
+ memset (fname, 0, SZ_FNAME);
+ sprintf (fname, "%s.urls", pp->root);
+
+ /* Construct a template for each file.
+ */
+ if (access (fname, R_OK) == 0) {
+ fd = fopen (fname, "r");
+ for (i=1; fgets (url, SZ_URL, fd); i++) {
+ url[strlen(url)-1] = '\0'; /* kill newline */
+
+ memset (fname, 0, SZ_FNAME);
+ if (file_get > 1)
+ sprintf (fname, "%s.%03d", pp->root, i);
+ else
+ sprintf (fname, "%s", pp->root);
+
+ if (file_get && is_in_range(fileRange.ranges,i)) {
+ vot_addToAclist (url, fname);
+ nf++;
+ }
+ }
+ fclose (fd);
+ }
+ }
+
+ /* Get the semaphore set by the child indicating the
+ ** result count.
+ */
+ sem_id = semget (pid, 0, 0);
+ pp->count = semctl (sem_id, 0, GETVAL, 0); /* get value */
+ s->count += pp->count;
+ rc = semctl (sem_id, 0, IPC_RMID, NULL); /* release it */
+ if (status != E_NODATA && s->count == 0)
+ s->nnodata++;
+
+ break;
+ }
+ }
+ }
+ if (s == (Service *) NULL && n) { /* no matching service found */
+ fprintf (stderr, "Warning: NO SERVICE FOUND....pid=%d status=%d\n",
+ pid, status);
+ return;
+ }
+}
+
+
+
+/************************************************************************
+** PRINTPROCSTAT -- Print a summary of the processing results. If
+** 'failed_only' is set this is an error summary only.
+*/
+static void
+vot_printProcStat (Proc *procList, char *svc_name, int failed_only)
+{
+ Proc *pp = procList;
+ FILE *fd = (failed_only ? stderr : stdout);
+
+ if (procList == (Proc *) NULL)
+ return;
+
+ fprintf (fd, "\nError Summary for '%s' :\n", svc_name);
+ while (pp) {
+ if (!failed_only || pp->status) {
+ fprintf (fd, " Pid %6d: Source: %-12.12s (%.6f,%.6f) %s\n",
+ pp->pid,
+ (pp->obj->name ? pp->obj->name : "(none)"),
+ pp->obj->ra, pp->obj->dec, vot_stat2code(pp->status));
+ }
+ pp = pp->next;
+ }
+}
+
+
+/************************************************************************
+** STAT2CODE -- Convert an error code to a text string for printing.
+*/
+static char *
+vot_stat2code (int status)
+{
+ switch (status) {
+ case E_NONE: return ("OK"); break;
+ case E_NODATA: return ("No Data Returned"); break;
+ case E_REQFAIL: return ("Request Failed"); break;
+ case E_FILOPEN: return ("File Open Error"); break;
+ case E_VOCINIT: return ("VOClient init fails"); break;
+ default: return ("Unknown Error"); break;
+ }
+
+ return (NULL);
+}
+
+
+/************************************************************************
+** CNVTYPE -- Convert an error code to a text string for printing.
+static char *
+vot_cnvType (char *intype)
+{
+ if (strcasecmp ("image", intype) == 0)
+ return ("siap");
+ else if (strcasecmp ("catalog", intype) == 0)
+ return ("cone");
+ else if (strcasecmp ("table", intype) == 0)
+ return ("tabularskyservice");
+ else
+ return (intype);
+}
+*/
+
+
+/************************************************************************
+** PRINTPROCTIME -- Print a summary of the processing times.
+*/
+static void
+vot_printProcTime ()
+{
+ if (!quiet) {
+ int r = ((int)re_time - (int)rs_time),
+ q = ((int)qe_time - (int)qs_time),
+ a = ((int)ae_time - (int)as_time);
+ int tot = (r + q + a);
+
+ extern char *toSexaTime (int n);
+
+
+ printf ("#\n");
+ printf ( "# Approx Time: %02d:%02d:%02d\t",
+ (tot / 3600), (tot / 60), (tot % 60));
+ printf ("(%02d:%02d Resolution, %02d:%02d Query, %02d:%02d Access)\n",
+ r / 60, r % 60,
+ q / 60, q % 60,
+ a / 60, a % 60);
+ }
+}
+
+
+/************************************************************************
+** USAGE -- Print a summary of the help options.
+*/
+static void
+Usage()
+{
+ vot_printUsage();
+
+ printf ("Where:\n");
+ printf ("\n");
+ printf (" <resource> ShortName/Identifier of data service \n");
+ printf (" <obj> Name of object to be resolved\n");
+ printf (" <ra> <dec> Decimal or Sexagesimal coords for query \n");
+ printf (" <url> URL to access or ServiceURL to query \n");
+ printf (" <sr> Search radius in degrees (def: 0.1) \n");
+ printf ("\n");
+ printf (" These values may optionally be in a file containing them.\n");
+ printf (" Resource and object names may be comma-delimited lists\n");
+ printf ("\n");
+ printf ("\n");
+ printf (" -h Print this help summary\n");
+ printf (" -v, -vv Verbose or very-verbose mode\n");
+ printf ("\n\tTask Behavior Flags:\n");
+ printf (" -a, -all Query all data for the resource\n");
+ printf (" -c, -count Print a count\n");
+ printf (" -g, -get <rng> Get the files associated with a query\n");
+ printf (" -m, -meta Print the column metadata for the resource\n");
+
+ printf ("\n\tQuery Options:\n");
+ printf (" -b <bandpass> Constrain by bandpass\n");
+ printf (" -i <file> Take arguments from file (or stdin)\n");
+ printf (" -o <obj> Specify object list\n");
+ printf (" -p <pos> Specify position list\n");
+ printf (" -r Set search radius\n");
+ printf (" -rs Set radius in arc-seconds\n");
+ printf (" -rm Set radius in arc-minutes\n");
+ printf (" -rd Set radius in degrees (default: 0.1)\n");
+ printf (" -s <svc> Specify the service name or url\n");
+ printf (" -t <type> Constrain by service type\n");
+
+ printf ("\n\tOutput Options:\n");
+ printf (" -A ASCII table output (.txt extension)\n");
+ printf (" -C CSV table output (.csv extension)\n");
+ printf (" -H HTML table output (.html extension)\n");
+#ifdef VO_INVENTORY
+ printf (" -I Output results from the Inventory Service\n");
+#endif
+ printf (" -K KML output (.kml extension)\n");
+ printf (" -R Raw (VOTable) output (.xml extension)\n");
+ printf (" -V VOTable output (.xml extension)\n");
+ printf (" -T Tab-separated table output (.tsv extension)\n");
+ printf (" -O <root> Set the root part of output name\n");
+ printf ("\n");
+ printf (" -e Extract results to separate file\n");
+ printf (" -ep Extract only positions (to <file>.pos)\n");
+ printf (" -eu Extract only access urls (to <file>.urls)\n");
+ printf (" -eh Extract table to HTML (to <file>.html)\n");
+ printf (" -ek Extract table to individual KML (to <file>.kml)\n");
+ printf (" -eK Extract table to aggregate KML (to <file>.kml)\n");
+ printf (" -n No-save results, print a count only\n");
+ printf (" -q Suppress output to the screen\n");
+
+ printf ("\n\tFormat-specific Options:\n");
+ printf (" -km <N> Set max downloads (def: 100)\n");
+ printf (" -kgb Group KML output by both object and service\n");
+ printf (" -kgo Group KML output by object\n");
+ printf (" -kgs Group KML output by service\n");
+ printf (" -ks <N> Set result sample\n");
+ printf (" -kl Disable Placemark labels\n");
+ printf (" -kr Disable region box\n");
+ printf (" -kv Disable verbose labels\n");
+ printf ("\n");
+ printf (" -wb Disable HTML table borders\n");
+ printf (" -wc Disable HTML table verbose label\n");
+ printf (" -wh Disable HTML page header\n");
+
+ printf ("\n\tProcessing Options:\n");
+ printf (" -md <N> Set max downloads (def: 1)\n");
+ printf (" -mp <N> Set max number of processes per obj query\n");
+ printf (" -mt <N> Set max number of resource threads to run\n");
+ printf (" \n");
+
+ printf ("\n Notes:\n");
+ printf ("\t- Data Services may be listed by Registry ShortName of ");
+ printf ("Identifier\n");
+ printf ("\t- Sources may be object name, positions in decimal or sexages");
+ printf ("imal\n\t coords, or a file containing either.\n");
+
+ printf ("\n\n");
+ printf ("Resource Type Strings:\n");
+ printf (" catalog Cone search services\n");
+ printf (" image Simple Image Access services\n");
+ printf (" spectra Simple Spectral Access services\n");
+ printf (" table Vizier services\n");
+ printf (" <literal> ResourceType from registry record\n");
+ printf ("\n");
+ printf ("Allowed Bandpass Strings:\n");
+ printf (" Radio Millimeter Infrared (IR)\n");
+ printf (" Optical Ultraviolet (UV) X-Ray (xray)\n");
+ printf (" Gamma-Ray (GR)\n");
+ printf ("\n");
+
+ printf ("\n\n");
+ vot_printExamples();
+ printf ("\n\n");
+}
+
+
+static void
+vot_printExamples()
+{
+
+ printf ("Examples:\n---------\n\n");
+
+
+ printf ("\
+ 1) Query the GSC 2.3 catalog for stars a) within the 0.1 degree \n\
+ default search size around NGC 1234: b) around all positions \n\
+ contained in file 'pos.txt': c) for the list of objects given \n\
+ on the command line: d) query a list of services for a list \n\
+ of positions: e) print a count of results that would be returned\n\
+ from 3 services for each position in a file:\n\
+\n\
+ %% vodata gsc2.3 ngc1234 (a)\n\
+ %% vodata gsc2.3 pos.txt (b)\n\
+ %% vodata gsc2.3 m31,m51,m93 (c)\n\
+ %% vodata svcs.txt pos.txt (d)\n\
+ %% vodata hst,chandra,gsc2.3 pos.txt (e)\n\
+\n\
+ 2) Find all images by HST of NGC 4258, create a KML file for Google Sky:\n\
+\n\
+ %% vodata -K -t image -all hst ngc4258\n\
+\n\
+ 3) Query all (142) image services having data of the subdwarf\n\
+ galaxy IC 10, print a count of the results only:\n\
+\n\
+ %% vodata -c -t image any IC10\n\
+\n\
+ 4) Print a count of X-ray catalog data around Abell2712:\n\
+\n\
+ %% vodata -count -t catalog -b x-ray any abell2712\n\
+\n\
+ Or to get a count of all catalog data for that position:\n\
+\n\
+ %% vodata -I abell2712\n\
+\n\
+ 5) Print the column metadata returned by the RC3 catalog service:\n\
+\n\
+ %% vodata -meta -t catalog rc3\n\
+\n\
+ 6) Use the Registry to query for resources using the search terms\n\
+ 'cooling flow'. Upon examining the output the user notices a\n\
+ Vizier paper titled 'Cooling Flows in 207 clusters of Galaxies'\n\
+ that looks interesting. Use the vodata task to download all\n\
+ tables associated with this paper, save tables in the default\n\
+ CSV format:\n\
+\n\
+ %% voregistry cooling flow\n\
+ %% vodata -O white97 -all J/MNRAS/292/419\n\n\n\
+ ");
+
+}
+
+
+static void
+vot_printUsage()
+{
+ printf ("\n");
+ printf ("Usage:\n");
+ printf ("\n");
+ printf (" vodata <flags> [[ <resource> [<obj> | <ra> <dec>] [<sr>] | [<url>]]\n");
+ printf ("\n");
+}
+
+
+
+/**
+ * Tests -- Task unit tests.
+ */
+static void
+Tests (char *input)
+{
+ Task *task = &self;
+
+ vo_taskTest (task, "--help", NULL);
+
+ vo_taskTestFile ("m31\nm51\nm99\n", "pos.txt");
+ vo_taskTestFile ("hst\nchandra\ngsc2.3\n", "svcs.txt");
+
+ vo_taskTest (task, "gsc2.3", "ngc1234", NULL);
+ vo_taskTest (task, "gsc2.3", "pos.txt", NULL);
+ vo_taskTest (task, "gsc2.3", "m31,m51,m93", NULL);
+ vo_taskTest (task, "svcs.txt", "pos.txt", NULL);
+ vo_taskTest (task, "hst,chandra,gsc2.3", "pos.txt", NULL);
+
+ vo_taskTest (task, "-c", "-t", "image", "any", "IC10", NULL);
+ vo_taskTest (task, "--count", "--type=image", "any", "IC10", NULL);
+ vo_taskTest (task, "-c", "-t", "catalog", "-b", "x-ray",
+ "any", "abell2712", NULL);
+ vo_taskTest (task, "--count", "--type=image", "--bandpass=x-ray",
+ "any", "abell2712", NULL);
+
+ vo_taskTest (task, "--meta", "rc3", NULL);
+
+ vo_taskTest (task, "-O", "white97", "-all", "J/MNRAS/292/419", NULL);
+
+ vo_taskTest (task, "-rv", "-t", "image", "xmm", NULL);
+ vo_taskTest (task, "-cq", "xmm-newton", "3c273", NULL);
+ vo_taskTest (task, "--count", "--quiet", "xmm-newton", "3c273", NULL);
+ vo_taskTest (task, "--get", "xmm-newton", "3c273", NULL);
+
+ vo_taskTest (task, "-e", "-O", "2mass", "-t", "image", "2mass",
+ "12:34:56.7", "-23:12:45.2", NULL);
+ vo_taskTest (task, "-e", "--output=2mass", "--type=image", "2mass",
+ "12:34:56.7", "-23:12:45.2", NULL);
+
+ vo_taskTest (task, "-e", "ivo://nasa.heasarc/abell",
+ "0.0", "0.0", "180.0", NULL);
+
+ vo_taskTest (task, "-a", "galex", "m51", NULL);
+ vo_taskTest (task, "--all", "galex", "m51", NULL);
+
+
+ if (access ("pos.txt", F_OK) == 0) unlink ("pos.txt");
+ if (access ("svcs.txt", F_OK) == 0) unlink ("svcs.txt");
+
+ vo_taskTestReport (self);
+}
+
diff --git a/vendor/voclient/voapps/voimage.c b/vendor/voclient/voapps/voimage.c
new file mode 100644
index 00000000..4bb1e520
--- /dev/null
+++ b/vendor/voclient/voapps/voimage.c
@@ -0,0 +1,133 @@
+/**
+ * VOIMAGE -- Query all VO Image services
+ *
+ * Usage:
+ * voimage [<opts>] [ <object> | <ra> <dec> ] [ <size> ]
+ *
+ * @file voimage.c
+ * @author Mike Fitzpatrick
+ * @date 2/03/13
+ *
+ * @brief Query all VO Image services.
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+
+#include "votParse.h" /* keep these in order! */
+#include "voApps.h"
+
+
+/* Task specific option declarations. Task options are declared using the
+ * getopt_long(3) syntax.
+ */
+int vodata (int argc, char **argv, size_t *len, void **result);
+int voimage (int argc, char **argv, size_t *len, void **result);
+
+static Task self = { "voimage", voimage, 0, 0, 0 };
+
+extern void vot_setArg (char **argv, int *argc, char *value);
+
+static void Usage (void);
+static void Tests (char *input);
+
+
+/**
+ * Application entry point. All VOApps tasks MUST contain this
+ * method signature.
+ */
+int
+voimage (int argc, char **argv, size_t *reslen, void **result)
+{
+ char *pargv[argc+2];
+ int i, narg = 0, status = OK;
+
+
+ /* Initialize result object whether we return an object or not.
+ */
+ *reslen = 0;
+ *result = NULL;
+
+ /* Do a quick check of the args so we can provide a task-local
+ * help and test option. Otherwise, we simply pass thru all the
+ * args to VODATA for processing.
+ */
+ if (strncmp (argv[1],"-h",2) == 0 || strncmp (argv[1],"--help",6) == 0) {
+ Usage (); return (OK);
+ }
+ if (strncmp (argv[1],"-%",2) == 0 || strncmp (argv[1],"--test",6) == 0) {
+ Tests (NULL); return (self.nfail);
+ }
+
+ /* Initialize the new argument vector.
+ */
+ vot_setArg (pargv, &narg, argv[0]);
+ vot_setArg (pargv, &narg, "--type=image");
+ for (i=1; i < argc; i++)
+ vot_setArg (pargv, &narg, argv[i]);
+
+
+ /**
+ * The VODATA task does all the real work, we effectively just set the
+ * "-t image" option to force the service type as a logical naming
+ * convenience for the user. Note that return parameters are handled
+ * by vodata as well so there is no processing required here.
+ */
+ status = vodata (narg, pargv, reslen, result);
+
+
+ /* Clean up. Rememebr to free whatever pointers were created when
+ * parsing arguments.
+ */
+ for (i=0; i < (argc + 2); i++)
+ free ((void *) pargv[i]);
+
+ return (status);
+}
+
+
+/**
+ * USAGE -- Print task help summary.
+ */
+static void
+Usage (void)
+{
+ fprintf (stderr, "\n Usage:\n\t"
+ "voimage [<opts>] votable.xml\n\n"
+ " where\n"
+ " -%%,--test run unit tests\n"
+ " -h,--help this message\n"
+ "\n"
+ " <opts> includes all valid VODATA options\n"
+ "\n"
+ " Examples:\n\n"
+ " 1) Query for all X-ray image data of M51:\n\n"
+ " %% voimage -b x-ray any m51\n"
+ "\n"
+ " 2) Query an HST service having data of the subdwarf galaxy\n"
+ " IC 10, print a count of the results only:\n\n"
+ " %% voimage -c CADC/HST IC10\n"
+ "\n"
+ );
+}
+
+
+/**
+ * Tests -- Task unit tests.
+ */
+static void
+Tests (char *input)
+{
+ Task *task = &self;
+
+
+ vo_taskTest (task, "--help", NULL);
+
+ vo_taskTest (task, "-b", "x-ray", "any", "m51", NULL); // Ex 1
+ vo_taskTest (task, "-c", "CADC/HST", "IC10", NULL); // Ex 2
+
+ vo_taskTestReport (self);
+}
diff --git a/vendor/voclient/voapps/voiminfo.c b/vendor/voclient/voapps/voiminfo.c
new file mode 100644
index 00000000..fe2baa8d
--- /dev/null
+++ b/vendor/voclient/voapps/voiminfo.c
@@ -0,0 +1,493 @@
+/*
+ * VOIMINFO -- Get the WCS information for a FITS image.
+ *
+ * Usage:
+ * voiminfo [<otps>] image.fits
+ *
+ * @file voiminfo.c
+ * @author Mike Fitzpatrick
+ * @date 11/03/12
+ *
+ * @brief Get the WCS information for a FITS image.
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <math.h>
+
+#include "votParse.h" /* keep these in order! */
+#include "voApps.h"
+#include "fitsio.h"
+
+
+
+#define MAX_IMAGES 20480 /* max images to process */
+#define SZ_RESBUF 819200
+
+#define OPT_ALL 0001
+#define OPT_BOX 0002
+#define OPT_CORNERS 0004
+#define OPT_EXTNS 0010
+#define OPT_FRAME 0020
+#define OPT_NAXES 0040
+
+
+static int do_return = 0; /* return result? */
+
+/* Global task declarations. These should all be defined as 'static' to
+ * avoid namespace collisions.
+ */
+static int do_all = 0; /* print global values */
+static int do_sex = 0; /* print sexagesimal values */
+
+static int do_box = 0; /* print box coordinates */
+static int do_corners = 0; /* print image corners */
+static int do_extns = 0; /* print extension values */
+static int do_info = 0; /* print image info */
+static int do_naxis = 0; /* print NAXIS values */
+
+static int debug = 0; /* debug flag */
+static int verbose = 1; /* verbose flag */
+
+
+/* Task specific option declarations. Task options are declared using the
+ * getopt_long(3) syntax.
+ */
+int voiminfo (int argc, char **argv, size_t *len, void **result);
+
+static Task self = { "voiminfo", voiminfo, 0, 0, 0 };
+static char *opts = "%:habcdvnseio:r";
+static struct option long_opts[] = {
+ { "test", 1, 0, '%'}, /* --test is std */
+ { "help", 2, 0, 'h'}, /* --help is std */
+ { "return", 2, 0, 'r'}, /* --return is std */
+ { "debug", 2, 0, 'd'}, /* debug flag */
+ { "verbose", 2, 0, 'v'}, /* verbose flag */
+
+ { "all", 2, 0, 'a'}, /* print global value */
+ { "box", 2, 0, 'b'}, /* print box values */
+ { "corners", 2, 0, 'c'}, /* print image corner */
+ { "extns", 2, 0, 'e'}, /* print each extn */
+ { "info", 2, 0, 'i'}, /* print image info */
+ { "naxes", 2, 0, 'n'}, /* print NEXIS values */
+ { "output", 1, 0, 'o'}, /* output filename */
+ { "sex", 2, 0, 's'}, /* sexagesimal values */
+ { NULL, 0, 0, 0 }
+};
+
+
+/**
+ * Private procedures.
+ */
+static void Usage (void);
+static void Tests (char *input);
+static char *fmt (double pos, int is_ra);
+static char *fmt_naxis (char *imname, ImInfo *im, int do_all);
+static char *fmt_box (char *imname, ImInfo *im, int do_all);
+static char *fmt_corners (char *imname, ImInfo *im, int do_all);
+
+extern int vos_getURL (char *url, char *name);
+
+
+
+/**
+ * Application entry point.
+ */
+int
+voiminfo (int argc, char **argv, size_t *reslen, void **result)
+{
+ /* These declarations are required for the VOApps param interface.
+ */
+ char **pargv, optval[SZ_FNAME], resbuf[SZ_RESBUF];
+ char imname[SZ_LINE];
+
+
+ /* These declarations are specific to the task.
+ */
+ char *oname = NULL, *imlist[MAX_IMAGES], *nimlist[MAX_IMAGES];
+ int i, ch = 0, status = OK, pos = 0, nfiles = 0, narg = 0;;
+ size_t maxlen = SZ_RESBUF;
+ FILE *fd = (FILE *) NULL;
+ ImInfo *im;
+
+
+ /* Initialize result object whether we return an object or not.
+ */
+ *reslen = 0;
+ *result = NULL;
+ memset (imlist, 0, MAX_IMAGES);
+ memset (nimlist, 0, MAX_IMAGES);
+
+
+ /* Parse the argument list. The use of vo_paramInit() is required to
+ * rewrite the argv[] strings in a way vo_paramNext() can be used to
+ * parse them. The programmatic interface allows "param=value" to
+ * be passed in, but the getopt_long() interface requires these to
+ * be written as "--param=value" so they are not confused with
+ * positional parameters (i.e. any param w/out a leading '-').
+ */
+ pargv = vo_paramInit (argc, argv, opts, long_opts);
+ while ((ch = vo_paramNext(opts,long_opts,argc,pargv,optval,&pos)) != 0) {
+ if (ch > 0) {
+ /* If the 'ch' value is > 0 we are parsing a single letter
+ * flag as defined in the 'opts string.
+ */
+ switch (ch) {
+ case '%': Tests (optval); return (self.nfail);
+ case 'h': Usage (); return (OK);
+ case 'r': do_return=1; break;
+ case 'd': debug++; break;
+ case 'v': verbose++; break;
+
+ case 'a': do_all++; break;
+ case 'b': do_box++; break;
+ case 'c': do_corners++; break;
+ case 'e': do_extns++; break;
+ case 'i': do_info++; break;
+ case 's': do_sex++; break;
+ case 'n': do_naxis++; break;
+ case 'o': oname = strdup (optval); break;
+ default:
+ fprintf (stderr, "Invalid option '%s'\n", optval);
+ return (1);
+ }
+
+ } else if (ch == PARG_ERR) {
+ return (ERR);
+
+ } else {
+ /* This code processes the positional arguments. The 'optval'
+ * string contains the value but since this string is
+ * overwritten w/ each arch we need to make a copy (and must
+ * remember to free it later.
+ */
+ imlist[nfiles++] = strdup (optval);
+ narg++;
+ }
+
+ if (narg > MAX_IMAGES) {
+ fprintf (stderr, "ERROR: Too many images to process\n");
+ return (1);
+ }
+ }
+
+
+ /* Sanity checks.
+ */
+ if (imlist[0] == NULL || strcmp (imlist[0], "-") == 0) {
+ free (imlist[0]);
+ imlist[0] = strdup ("stdin");
+ nfiles = 1;
+ }
+ if (do_all && strcasecmp (imlist[0], "stdin") == 0) {
+ fprintf (stderr, "Error: Option not supported with standard input\n");
+ return (ERR);
+ }
+ if (oname == NULL) oname = strdup ("stdout");
+ if (strcmp (oname, "-") == 0) { free (oname), oname = strdup ("stdout"); }
+
+
+ /* Open the output file.
+ */
+ if (strcmp (oname, "stdout") != 0) {
+ if ((fd = fopen (oname, "w+")) == (FILE *) NULL) {
+ fprintf (stderr, "Error: Cannot open output file '%s'\n", oname);
+ return (ERR);
+ }
+ } else
+ fd = stdout;
+
+ /* Default to printing all info if we're not given a specific option.
+ if (!do_box && !do_corners && !do_info && !do_naxis)
+ do_info = 1;
+ */
+
+
+ /**
+ * Main body of task
+ */
+ for (i=0; i < nfiles; i++) {
+
+ memset (imname, 0, SZ_LINE);
+ if (strncmp ("http://", imlist[i], 7) == 0) {
+ if (access ("/tmp/voiminfo.fits", F_OK) == 0)
+ unlink ("/tmp/voiminfo.fits");
+ strcpy (imname, "/tmp/voiminfo.fits");
+ if (vos_getURL (imlist[i], imname) <= 0)
+ continue;
+ } else
+ strcpy (imname, imlist[i]);
+
+ if ((im = vot_imageInfo (imname, do_all)) ) {
+ memset (resbuf, 0, SZ_RESBUF);
+ if (do_info) {
+ vot_printImageInfo (fd, im);
+ } else if (do_naxis) {
+ strcpy (resbuf, fmt_naxis (imname, im, do_all));
+ } else if (do_box) {
+ strcpy (resbuf, fmt_box (imname, im, do_all));
+ } else if (do_corners) {
+ strcpy (resbuf, fmt_corners (imname, im, do_all));
+ } else {
+ sprintf (resbuf, "%s\t%s\t%s\t%s\n", imlist[i],
+ fmt (im->frame.cx,1), fmt (im->frame.cy,0),
+ fmt (im->frame.radius,0));
+ }
+
+ if (do_return)
+ vo_appendResultFromString (resbuf, reslen, result, &maxlen);
+ else
+ fprintf (fd, "%s", resbuf);
+
+ vot_freeImageInfo (im);
+
+ if (strncmp ("http://", imlist[i], 7) == 0)
+ unlink (imname);
+ }
+ }
+
+
+ /* Clean up. Rememebr to free whatever pointers were created when
+ * parsing arguments.
+ */
+ for (i=0; i < MAX_IMAGES; i++) {
+ if (imlist[i])
+ free (imlist[i]);
+ if (nimlist[i])
+ free (nimlist[i]);
+ else
+ break;
+ }
+ if (oname) free (oname);
+ if (fd != stdout)
+ fclose (fd);
+
+ vo_paramFree (argc, pargv);
+
+ return (status); /* status must be OK or ERR (i.e. 0 or 1) */
+}
+
+
+/**
+ * USAGE -- Print task help summary.
+ */
+static void
+Usage (void)
+{
+ fprintf (stderr, "\n Usage:\n\t"
+ "voiminfo [<opts>] votable.xml\n\n"
+ " where\n"
+ " -%%,--test run unit tests\n"
+ " -h,--help this message\n"
+ "\n"
+ " -a,--all print all extns\n"
+ " -i,--info print image info\n"
+ " -b,--box print box values\n"
+ " -c,--corners print image corners\n"
+ " -n,--naxes print NAXIS values\n"
+ " -o,--output output filename\n"
+ " -s,--sex sexagesimal values\n"
+ "\n"
+ " -o,--output=<file> output file\n"
+ "\n"
+ "\n"
+ " Examples:\n\n"
+ " 1) Print the size of each image extension in an MEF file:\n\n"
+ " %% voiminfo -n mef.fits\n"
+ "\n"
+ " 2) Print the LL and UR positions of an image as sexigesimal:\n\n"
+ " %% voiminfo -b -s image.fits\n"
+ "\n"
+ " 3) Print the corner positions of an image as decimal degrees:\n\n"
+ " %% voiminfo -c image.fits\n"
+ "\n"
+ " 4) Print the box values for an entire mosaic MEF file:\n\n"
+ " %% voiminfo -b mef.fits\n"
+ "\n"
+ );
+}
+
+
+/**
+ * Tests -- Task unit tests.
+ */
+static void
+Tests (char *input)
+{
+ Task *task = &self;
+ char *mef = "data/mef.fits";
+ char *sif = "data/sif.fits";
+ char *opts[] = { "-a", "-i", "-b", "-c", "-n", "-s", NULL };
+ register int i;
+
+
+ vo_taskTest (task, "--help", NULL);
+
+ if (access (input, F_OK) == 0) {
+ vo_taskTest (task, "-n", input, NULL); // Ex 1
+ vo_taskTest (task, "-b", "-s", input, NULL); // Ex 2
+ vo_taskTest (task, "-c", input, NULL); // Ex 3
+ vo_taskTest (task, "-b", input, NULL); // Ex 4
+ } else
+ fprintf (stderr, "Warning: input file '%s' not found...\n", input);
+
+ if (access (sif, F_OK) == 0)
+ for (i=0; opts[i]; i++)
+ vo_taskTest (task, opts[i], sif, NULL);
+
+ if (access (mef, F_OK) == 0)
+ for (i=0; opts[i]; i++)
+ vo_taskTest (task, opts[i], mef, NULL);
+
+ vo_taskTestReport (self);
+}
+
+
+
+/***************************************************************************/
+/**** Private Procedures ****/
+/***************************************************************************/
+
+/**
+ * FMT -- Output formatter.
+ */
+static char *
+fmt (double pos, int is_ra)
+{
+ static char strbuf[10][SZ_LINE];
+ static int bufnum = 0;
+
+
+ bufnum = (bufnum + 1) % 10;
+ memset (strbuf[bufnum], 0, SZ_LINE);
+
+ pos = (pos < 0.0 ? -pos : pos);
+
+ if (do_sex) {
+ int d, m;
+ float s, frac;
+ char sign = (pos < 0.0 ? '-' : ' ');
+
+ pos = (is_ra ? (pos / 15.0) : pos);
+ d = (int) pos;
+ frac = (pos - d);
+ m = frac * 60.0;
+ s = ((frac * 60.0) - m) * 60.0;
+
+ sprintf (strbuf[bufnum], "%c%02d:%02d:%04.1f", sign, d, m, s);
+
+ } else
+ sprintf (strbuf[bufnum], "%f", pos);
+
+ return (strbuf[bufnum]);
+}
+
+
+/**
+ * FMT_NAXIS -- Print the size of pixels of an image.
+ */
+static char *
+fmt_naxis (char *imname, ImInfo *im, int do_all)
+{
+ static char line[SZ_RESBUF];
+
+ memset (line, 0, SZ_RESBUF);
+ if (im->nextend && !do_all) {
+ register int i = 0;
+ char buf[SZ_RESBUF];
+
+ for (i=0; i < im->nextend; i++) {
+ memset (buf, 0, SZ_RESBUF);
+ if (im->frame.naxis == 3)
+ sprintf (buf, "%s[%d]\t%d %d %d\n", imname, i,
+ im->extns[i].naxes[0],
+ im->extns[i].naxes[1],
+ im->extns[i].naxes[2]);
+ else
+ sprintf (buf, "%s[%d]\t%d %d\n", imname, i,
+ im->extns[i].naxes[0], im->extns[i].naxes[1]);
+ strcat (line, buf);
+ }
+
+ } else {
+ if (im->frame.naxis == 3)
+ sprintf (line, "%s\t%d %d %d\n", imname,
+ im->frame.naxes[0], im->frame.naxes[1], im->frame.naxes[2]);
+ else
+ sprintf (line, "%s\t%d %d\n", imname,
+ im->frame.naxes[0], im->frame.naxes[1]);
+ }
+
+ return (line);
+}
+
+
+/**
+ * FMT_BOX -- Print the corners of a box and rotation angle.
+ */
+static char *
+fmt_box (char *imname, ImInfo *im, int do_all)
+{
+ static char line[SZ_RESBUF];
+
+ memset (line, 0, SZ_RESBUF);
+ if (im->nextend && !do_all) {
+ register int i = 0;
+ char buf[SZ_RESBUF];
+
+ for (i=0; i < im->nextend; i++) {
+ memset (buf, 0, SZ_RESBUF);
+ sprintf (buf, "%s[%d]\t%s %s\t%s %s\t%s\n", imname, i,
+ fmt (im->extns[i].lx,1), fmt (im->extns[i].ly,0),
+ fmt (im->extns[i].ux,1), fmt (im->extns[i].uy,0),
+ fmt (im->extns[i].rotang,0));
+ strcat (line, buf);
+ }
+
+ } else {
+ sprintf (line, "%s\t%s %s\t%s %s\t%s\n", imname,
+ fmt (im->frame.lx,1), fmt (im->frame.ly,0),
+ fmt (im->frame.ux,1), fmt (im->frame.uy,0),
+ fmt (im->frame.rotang,0));
+ }
+
+ return (line);
+}
+
+
+/**
+ * FMT_CORNERS -- Print the explicit corners of an image footprint.
+ */
+static char *
+fmt_corners (char *imname, ImInfo *im, int do_all)
+{
+ static char line[SZ_RESBUF];
+
+ memset (line, 0, SZ_RESBUF);
+ if (im->nextend && !do_all) {
+ register int i = 0;
+ char buf[SZ_RESBUF];
+
+ for (i=0; i < im->nextend; i++) {
+ memset (buf, 0, SZ_RESBUF);
+
+ sprintf (buf, "%s\t%s %s\t%s %s\t%s %s\t%s %s\n", imname,
+ fmt (im->extns[0].xc[0],1), fmt (im->extns[0].yc[0],0),
+ fmt (im->extns[0].xc[1],1), fmt (im->extns[0].yc[1],0),
+ fmt (im->extns[0].xc[2],1), fmt (im->extns[0].yc[2],0),
+ fmt (im->extns[0].xc[3],1), fmt (im->extns[0].yc[3],0));
+ strcat (line, buf);
+ }
+
+ } else {
+ sprintf (line, "%s\t%s %s\t%s %s\t%s %s\t%s %s\n", imname,
+ fmt (im->frame.xc[0],1), fmt (im->frame.yc[0],0),
+ fmt (im->frame.xc[1],1), fmt (im->frame.yc[1],0),
+ fmt (im->frame.xc[2],1), fmt (im->frame.yc[2],0),
+ fmt (im->frame.xc[3],1), fmt (im->frame.yc[3],0));
+ }
+ return (line);
+}
diff --git a/vendor/voclient/voapps/voregistry.c b/vendor/voclient/voapps/voregistry.c
new file mode 100644
index 00000000..a99c058f
--- /dev/null
+++ b/vendor/voclient/voapps/voregistry.c
@@ -0,0 +1,1291 @@
+/**
+ * VOREGISTRY -- Registry resolution, query, and browsing
+ *
+ *
+ * Usage: voregistry [-<flags>] [ [<keyword>] | [<term>] ]
+ *
+ * -h,--help print this help
+ * -v,--verbose verbose mode
+ * --vverbose very-verbose mode
+ *
+ * -c,--count print a count of matching records
+ * -e,--exact print exactly matching records (resolve)
+ * -l,--list list full resource record
+ * -m,--meta list table metadata
+ * -r,--resolve resolution mode
+
+ * -b,--bandpass <bandpass> constrain by bandpass
+ * -C,--clevel <level> constrain by content level
+ * -d,--dal constrain to only DAL services
+ * -g,--group group search terms
+ * -s,--subject <subject> constrain by subject string
+ * -t,--type <type> constrain by service type
+ * -N,--new <time> get only newly registered svcs
+ * -U,--updated <time> get only newly updated entries
+ *
+ * -a,--all print all results (default)
+ * -f,--fields <fields> output only specified fields
+ * -O,--or logically OR the search terms
+ * -n,--index <index> set index of result (-1 => list, 0 => all)
+ * -o,--output <oname> save results to <oname> as votable
+ * -B,--samp broadcast results as a SAMP message
+ * -V,--votable save results as VOTable
+ * -X,--xml save results as VOTable
+ *
+ * -I,--Id print only the Identifier (resolve mode)
+ * -L,--long print long lines of output (no wrapping)
+ * -R,--Resolve print the ShortName, ServiceType and ID
+ * -S,--SName print only the ShortName (resolve mode)
+ * -T,--Title print only the Title string (resolve mode)
+ *
+ *
+ * Resource Type Strings:
+ * catalog Cone search services
+ * image Simple Image Access services
+ * spectra Simple Spectral Access services
+ * table Vizier services
+ * <literal> ResourceType from Registry record
+ *
+ * Allowed Bandpass Strings:
+ * Radio Millimeter Infrared (IR)
+ * Optical Ultraviolet (UV) X-Ray (xray)
+ * Gamma-Ray (GR)
+ *
+ * Allowed Resource Fields (for -f flag):
+ * Title ShortName Identifier
+ * ServiceURL ReferenceURL Description
+ * Subject ResourceType Type
+ * Creator Publisher CoverageSpatial
+ * CoverageTemporal Waveband ContentLevel
+ * Version
+ *
+ *
+ * @file voregistry.c
+ * @author Mike Fitzpatrick, NOAO
+ * @date 8/03/07
+ *
+ * @brief Registry resolution, query, and browsing
+ */
+
+#include <pthread.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <getopt.h>
+#define _GNU_SOURCE
+#include <string.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include "VOClient.h"
+#include "voApps.h"
+#include "voAppsP.h"
+#include "samp.h"
+
+
+/* Local processing definitions.
+*/
+#define M_RESOLVE 001 /* resolve to record field */
+#define M_SEARCH 002 /* search registry */
+#define M_FULL 004 /* print full record */
+#define M_METALIST 010 /* print table metadata */
+
+#define MAX_TERMS 128 /* max search terms */
+
+#define TIME_NEW 0 /* time-search types */
+#define TIME_UPDATE 1
+
+#define TUNIT_HOURS 0 /* units of search */
+#define TUNIT_DAY 1
+#define TUNIT_MONTH 2
+
+
+
+int mode = M_SEARCH; /* program mode */
+
+
+extern int count; /* return count of results */
+extern int verbose; /* verbose output? */
+extern int meta; /* print meta results */
+extern int proxy; /* use proxy server */
+extern int res_all; /* print all results */
+extern int longlines; /* don't format output */
+extern int group; /* group terms */
+extern int exact; /* exact match only? */
+extern int debug; /* debug output? */
+extern int nterms; /* number of search terms */
+
+int exact = 0; /* exact match only? */
+int res_index = -1; /* index of result */
+int nresults = 0; /* no. of results */
+int user_fields = 0; /* uer-defined fields? */
+int orValues = 0; /* OR search terms? */
+int out_votable = 0; /* output a Resource VOTable */
+#ifdef REG10_KLUDGE
+int reg10 = 0; /* Registry 1.0 support? */
+#endif
+int dal_only = 0; /* DAL services only */
+int sortRes = 0; /* sort results? */
+int terse = 0; /* terse results? */
+int cset = 0; /* constraints set? */
+int do_samp = 0; /* broadcast SAMP result? */
+int timeSearch = 0; /* search by create/update time */
+
+
+char *fields = (char *) NULL; /* output fields */
+char *ofname = (char *) NULL; /* output filename */
+char *bandpass = (char *) NULL; /* bandpass constraint */
+char *subject = (char *) NULL; /* subject constraint */
+char *stype = (char *) NULL; /* service type constraint */
+char *clevel = (char *) NULL; /* content level constraint */
+char *terms[MAX_TERMS]; /* search words/terms */
+
+char outname[SZ_FNAME]; /* output filename */
+
+
+
+/* Task specific option declarations.
+ */
+int voregistry (int argc, char **argv, size_t *len, void **result);
+
+static Task self = { "voregistry", voregistry, 0, 0, 0 };
+
+static void Usage (void);
+static void Tests (char *input);
+
+
+/* For getopt_long() option parsing.
+*/
+int opt_index;
+static char *opt_string = "aBb:C:cdef:ghn:IlLmOo:rRs:St:TvVX123789%";
+
+static struct option long_options[] = {
+
+ /* OUTPUT TYPES */
+ { "count", 2, 0, 'c'}, /* count results */
+ { "exact", 2, 0, 'e'}, /* exact results */
+ { "list", 2, 0, 'l'}, /* list full record */
+ { "meta", 2, 0, 'm'}, /* print metadata */
+ { "resolve", 2, 0, 'r'}, /* resolve mode */
+
+ /* CONVENIENCE OPTS */
+ { "id", 2, 0, 'I'}, /* ID Resolve mode */
+ { "long", 2, 0, 'L'}, /* output long lines */
+ { "Resolve", 2, 0, 'R'}, /* Resolve mode */
+ { "SName", 2, 0, 'S'}, /* SName Resolve mode */
+ { "Title", 2, 0, 'T'}, /* Title Resolve mode */
+
+ /* CONSTRAINT OPTS */
+ { "bandpass", 1, 0, 'b'}, /* bandpass constraint */
+ { "clevel", 1, 0, 'C'}, /* content level cons. */
+ { "dal", 2, 0, 'd'}, /* DAL-only results */
+ { "group", 2, 0, 'g'}, /* group terms */
+ { "new", 1, 0, 'N'}, /* newly registered */
+ { "updated", 1, 0, 'U'}, /* updated entried */
+ { "subject", 1, 0, 's'}, /* subject constraint */
+ { "type", 1, 0, 't'}, /* svctype constraint */
+
+ /* OUTPUT CONTROL OPTS */
+ { "all", 2, 0, 'a'}, /* print all results */
+ { "fields", 1, 0, 'f'}, /* set output fields */
+ { "or", 2, 0, 'O'}, /* logically OR keyws */
+ { "index", 1, 0, 'n'}, /* result index */
+ { "output", 1, 0, 'o'}, /* output filename */
+ { "samp", 2, 0, 'B'}, /* broadcase SAMP result */
+ { "votable", 2, 0, 'V'}, /* output VOTable */
+ { "xml", 2, 0, 'X'}, /* output XML */
+
+ /* STANDARD OPTS */
+ { "help", 2, 0, 'h'}, /* print help */
+ { "test", 2, 0, '%'}, /* unit tests */
+ { "verbose", 2, 0, 'v'}, /* verbose flag */
+
+ /* ENGINEERING OPTS */
+ { "debug", 2, 0, '1'}, /* debug output */
+ { "dverb", 2, 0, '2'}, /* verbose debug output */
+ { "reg10", 2, 0, '3'}, /* Registry 1.0 kludge */
+
+ { "tweet", 2, 0, '7'}, /* tweet output */
+ { "sort", 2, 0, '8'}, /* */
+ { "terse", 2, 0, '9'}, /* */
+
+ { NULL, 0, 0, 0 }
+};
+
+
+/* The following is the full list of metadata available given the
+** Registry query method we are using. This list will change when
+** VOClient moves to a new Registry schema.
+
+char *resList[] = { // v0.4 output
+ "Title", "ShortName", "Identifier",
+ "ServiceURL", "ReferenceURL", "Description",
+ "Subject", "ResourceType", "Type",
+ "Creator", "Facility", "Instrument",
+ "Contributor", "CoverageSpatial", "CoverageTemporal",
+ "Waveband", "ContentLevel", "Version",
+ NULL
+};
+*/
+char *resList[] = { /* resource fields (full print) */
+ "Title", "ShortName", "Identifier",
+ "CapabilityStandardID", "Subject", "Type",
+ "ServiceURL", "ReferenceURL", "Description",
+ "Creator", "Publisher", "CoverageSpatial",
+ "CoverageTemporal", "Waveband", "ContentLevel",
+ "Version", "CapabilityName",
+ NULL
+};
+
+#define SZ_GBUF 256
+char gbuf[SZ_GBUF];
+/*
+char *gfmt = "(ShortName like '%%%s%%' OR Identifier like '%%%s%%')";
+char *gfmt = "(Identifier like '%%%s%%')";
+*/
+char *gfmt = "(Identifier like '%s')";
+
+
+extern int errno;
+extern int isSexagesimal (char *s), isDecimal (char *s);
+extern int vot_regResolver (char *id, char *svctype, char *bpass,
+ char *subject, char *clevel, char *fields, int index,
+ int exact, int dal_only, char **result);
+extern int vot_regSearch (char **ids, int nids, char *svctype,
+ char *bpass, char *subject, char *clevel, int orValues,
+ int votable, FILE *vot_fd, int dal_only, int sortRes,
+ int terse);
+extern int vot_atoi (char *v);
+extern char *strcasestr();
+
+
+static void printResolveRecord (void);
+static void printResolveHdr (void);
+static void printFullRecord (char *term);
+static void printSvcMetadata (char *svc);
+
+static char *vot_getTime (int type, char *arg);
+double vot_calJD (int mn, double dy, int yr, int hrs, int min, int sec);
+
+extern char *vot_toURL (char *arg);
+extern void vot_printRegVOTableHdr (FILE *fd);
+extern void vot_printRegVOTableRec (FILE *fd, RegResult resource, int recnum);
+extern void vot_printRegVOTableTail (FILE *fd);
+
+extern void pretty_print (char *result, int nresults);
+extern void pretty_print_table (char *result, int nresults, char *fields);
+extern void ppMultiLine (char *result, int poffset, int pwidth, int maxchars);
+extern void ppResSummary (char *result, int nresults);
+extern void vot_printAttrs (char *fname, Query query, char *id);
+
+
+
+
+
+/************************************************************************
+** Program main()
+*/
+int
+voregistry (int argc, char *argv[], size_t *reslen, void **result)
+{
+ register int i=0, ch=0, arg_index=0, narg=0;
+ char vot_name[SZ_FNAME];
+ int use_groups = 1;
+ int status = OK;
+ FILE *vot_fd = (FILE *) NULL;
+
+
+ *reslen = 0;
+ *result = NULL;
+ count = 0;
+ meta = 0;
+ vot_fd = stdout;
+
+ memset (vot_name, 0, SZ_FNAME);
+ memset (outname, 0, SZ_FNAME);
+
+ /* Process command line arguments.
+ */
+ while (1) {
+ ch = getopt_long (argc, argv, opt_string, long_options, &opt_index);
+
+ if (ch > 0) {
+ switch (ch) {
+ case 'h':
+ Usage ();
+ return (OK);
+ case '%':
+ Tests (NULL);
+ return (self.nfail);
+
+ case 'a': /* print all results */
+ res_all = 1;
+ break;
+ case 'c': /* count results */
+ count++;
+ break;
+ case 'd': /* DAL-only results */
+ dal_only++;
+ cset++;
+ break;
+
+
+ /* EXPERIMENTAL FLAGS */
+ case '7': /* EXPERIMENTAL */
+ terse += 2;;
+ break;
+ case '8': /* EXPERIMENTAL */
+ sortRes++, terse++;
+ break;
+ case '9': /* EXPERIMENTAL */
+ terse++;
+ break;
+ /* EXPERIMENTAL FLAGS */
+
+
+ case 'e': /* exact results */
+ exact++;
+ mode = M_RESOLVE;
+ break;
+
+ case 'l': /* list full record */
+ mode = M_FULL;
+ verbose = 2;
+ break;
+ case 'I': /* ID Resolve mode */
+ mode = M_RESOLVE;
+ fields = "Identifier";
+ user_fields++;
+ break;
+ case 'T': /* Title Resolve mode */
+ mode = M_RESOLVE;
+ fields = "Title";
+ user_fields++;
+ break;
+ case 'R': /* Resolve mode */
+ mode = M_RESOLVE;
+ dal_only++;
+ fields =
+ "ShortName,CapabilityStandardID,Identifier,CapabilityName";
+ user_fields++;
+ break;
+ case 'S': /* SName Resolve mode */
+ mode = M_RESOLVE;
+ fields = "ShortName";
+ user_fields++;
+ break;
+ case 'L': /* output long lines */
+ longlines++;
+ break;
+ case 'g': /* group terms */
+ mode = M_RESOLVE;
+ group++;
+ orValues++;
+ break;
+ case 'r': /* resolve mode */
+ mode = M_RESOLVE;
+ break;
+ case 'm':
+ mode = M_METALIST;
+ dal_only++;
+ meta++;
+ break;
+
+ case 'b': /* bandpass constraint */
+ if (bandpass) {
+ fprintf (stderr,"Warning: Bandpass already specified.");
+ fprintf (stderr," Ignoring '%s'\n", optarg);
+ } else {
+ if (!optarg || (optarg && optarg[0] == '-')) {
+ fprintf (stderr,
+ "Error: the '-b' flag requires an argument\n");
+ return (ERR);
+ }
+ bandpass = optarg;
+ }
+ cset++;
+ break;
+ case 's': /* subject constraint */
+ if (subject) {
+ fprintf (stderr,"Warning: Subject already specified.");
+ fprintf (stderr," Ignoring '%s'\n", optarg);
+ } else {
+ if (!optarg || (optarg && optarg[0] == '-')) {
+ fprintf (stderr,
+ "Error: the '-s' flag requires an argument\n");
+ return (ERR);
+ }
+ subject = optarg;
+ }
+ cset++;
+ break;
+ case 't': /* svctype constraint */
+ if (stype) {
+ fprintf (stderr, "Warning: ServiceType already specified.");
+ fprintf (stderr, " Ignoring '%s'\n", optarg);
+ } else {
+ if (!optarg || (optarg && optarg[0] == '-')) {
+ fprintf (stderr,
+ "Error: the '-t' flag requires an argument\n");
+ return (ERR);
+ }
+ stype = optarg;
+ }
+ cset++;
+ break;
+ case 'C': /* content level cons. */
+ if (clevel) {
+ fprintf (stderr,"Warning: ContentLevel already specified.");
+ fprintf (stderr," Ignoring '%s'\n", optarg);
+ } else {
+ if (!optarg || (optarg && optarg[0] == '-')) {
+ fprintf (stderr,
+ "Error: the '-C' flag requires an argument\n");
+ return (ERR);
+ }
+ clevel = optarg;
+ }
+ cset++;
+ break;
+
+ case 'n': /* result index */
+ res_index = vot_atoi (optarg);
+ break;
+ case 'o': /* logically OR keyws */
+ out_votable++;
+ verbose = 2;
+ strcpy (outname, optarg);
+ break;
+ case 'O': /* logically OR keyws */
+ orValues++;
+ break;
+ case 'f': /* set output fields */
+ fields = optarg;
+ user_fields++;
+ break;
+
+ case 'B': /* broadcase SAMP table */
+ do_samp++;
+ out_votable++;
+ verbose = 2;
+ break;
+ case 'V': /* output VOTable */
+ case 'X': /* output XML */
+ out_votable++;
+ verbose = 2;
+ break;
+
+ case 'v': /* verbose flag */
+ verbose++;
+ break;
+
+ case 'N': /* new resources */
+ timeSearch++;
+ terms[nterms++] = vot_getTime (TIME_NEW, optarg);
+ break;
+ case 'U': /* updated entried */
+ timeSearch++;
+ terms[nterms++] = vot_getTime (TIME_UPDATE, optarg);
+ break;
+
+ /* "Engineering" flags. */
+ case '1': /* debug */
+ debug++;
+ break;
+ case '2': /* verbose debug */
+ verbose++;
+ break;
+#ifdef REG10_KLUDGE
+ case '3': /* Registry 1.0 kludge */
+ reg10++;
+ break;
+#endif
+ }
+
+ } else if (ch == PARG_ERR) {
+ return (ERR);
+
+ } else {
+ /* Parse the arguments.
+ **
+ ** voregistry <keyw> [ <keyw> .... ]
+ **
+ */
+ char *arg, sql[SZ_SQL_TERM];
+ int len, start, end;
+
+ if ( (arg_index = optind + narg) >= argc)
+ break;
+
+ arg = argv[arg_index];
+ len = strlen (arg);
+ if (arg[0] == '\"') {
+ /* Capture all args forming a quoted string.
+ */
+ bzero (sql, SZ_SQL_TERM);
+ do {
+ start = ((arg[0] == '\"') ? 1 : 0);
+ end = ((arg[len-1] == '\"') ? len-2 : len-1);
+ strncat (sql, &arg[start], end-start+1);
+ if (arg[len-1] == '\"')
+ break;
+ strcat (sql, " ");
+ arg = argv[++arg_index], narg++;
+ len = strlen (arg);
+ } while (arg);
+ terms[nterms++] = strdup (sql);
+
+ } else if (access(arg, R_OK) == 0) {
+ FILE *fd;
+ char *name = calloc (1, SZ_FNAME);
+
+ /* Process the file contents.
+ */
+ if ((fd = fopen (arg, "r")) == (FILE *) NULL) {
+ fprintf (stderr, "ERROR: Cannot open file '%s'\n", arg);
+ exit (1);
+ }
+ while (fgets (name, SZ_FNAME, fd)) {
+ name[strlen(name)-1] = '\0'; /* kill newline */
+ if (group) {
+ bzero (gbuf, SZ_GBUF);
+ sprintf (gbuf, gfmt, name, name);
+ terms[nterms++] = strdup (gbuf);
+ } else {
+ terms[nterms++] = strdup (name);
+ }
+ bzero (name, SZ_FNAME);
+ }
+
+ fclose (fd);
+ free (name);
+
+ } else {
+ if (strncasecmp("ivo://CDS/VizieR", arg, 16) == 0) {
+ char ivorn[SZ_LINE];
+
+ /* If we're using an 'old-style' Vizier ivorn, try
+ ** converting it to a a Registry 1.0 flavor. We'll
+ ** worry about further modifying the term if this fails
+ ** later on.
+ */
+ bzero (ivorn, SZ_LINE);
+ strcpy (ivorn, strdup (arg));
+ ivorn[9] = '.';
+ terms[nterms++] = strdup (ivorn);
+
+ } else
+ terms[nterms++] = strdup (arg);
+ }
+
+ narg++;
+
+ /* When we're done processing the arguments, break....
+ */
+ if (arg_index == (argc - 1))
+ break;
+ }
+ }
+
+ if (cset && nterms == 0) {
+ /* terms[nterms++] = "%"; */
+ orValues = 0;
+ }
+
+
+ /* Initialize the VOClient code. Error messages are printed by the
+ * interface so we just quit if there is a problem.
+ */
+ if (voc_initVOClient ("runid=voc.voregistry") == ERR)
+ return (ERR);
+
+
+ /* See whether any flags negate other options, or imply values for
+ ** other fields.
+ */
+ if (res_all)
+ res_index = -1;
+ if (nterms == 0 && !out_votable) {
+ if (mode == M_RESOLVE)
+ terms[nterms++] = strdup ("%");
+ else {
+ mode = ((stype||clevel||subject||bandpass) ? M_SEARCH : M_RESOLVE);
+
+ if (stype || clevel || subject || bandpass)
+ mode = M_SEARCH;
+ else {
+ if (! (stype || clevel || subject || bandpass))
+ mode = M_SEARCH;
+ else
+ mode = M_RESOLVE;
+ }
+ if (stype && strcasestr (stype, "catalog"))
+ terms[nterms++] = strdup ("catalog");
+ }
+ }
+#ifdef FOO
+ if (fields && mode != M_RESOLVE) {
+ fprintf (stderr, "ERROR: 'fields' can only be used in Resolve Mode\n");
+ voc_closeVOClient (0); /* close VOClient connection */
+ return (ERR);
+ }
+#endif
+ if (nterms == 0 && !stype && !bandpass && !clevel && !subject) {
+ char *name = calloc (1, SZ_FNAME);
+
+ /* Process the arguments from the standard input.
+ */
+ while (fgets (name, SZ_FNAME, stdin)) {
+ name[strlen(name)-1] = '\0'; /* kill newline */
+ terms[nterms++] = strdup (name);
+ bzero (name, SZ_FNAME);
+ }
+ free (name);
+ }
+ if (mode == M_RESOLVE)
+ sortRes = 0;
+
+
+ /* If all of the terms appears to be Identfiers, try to optimize the
+ ** query, or reset the search mode.
+ */
+ if (!stype && !clevel && !bandpass && !subject) {
+
+ for (i=0; i < nterms; i++) {
+ if (strncmp("ivo:", terms[i], 4) || strncmp("htt:", terms[i], 4)) {
+ use_groups = 0;
+ break;
+ }
+ }
+ if (use_groups && mode == M_SEARCH)
+ mode = M_RESOLVE;
+ if (use_groups && nterms <= 20) {
+ group++;
+ orValues++;
+ for (i=0; i < nterms; i++) {
+ bzero (gbuf, SZ_GBUF);
+ sprintf (gbuf, gfmt, terms[i], terms[i]);
+ free (terms[i]);
+ terms[i] = strdup (gbuf);
+ }
+ }
+ }
+
+
+ /* If we're printing a VOTable, output the prolog.
+ */
+ if (!meta && out_votable) {
+ strcpy (vot_name, (outname[0] ? outname : "/tmp/vot.xml"));
+ if (access (vot_name, F_OK) == 0)
+ unlink (vot_name);
+ if ((vot_fd = fopen (vot_name, "w+")) == (FILE *) NULL) {
+ fprintf (stderr, "Error opening SAMP result file.\n");
+ return (ERR);
+ }
+
+ vot_printRegVOTableHdr (vot_fd);
+ }
+
+ switch (mode) {
+ case M_RESOLVE:
+ printResolveRecord ();
+ voc_closeVOClient (0); /* close VOClient connection */
+ if (!meta && out_votable)
+ vot_printRegVOTableTail (vot_fd);
+ return ( (nresults == 0) );
+
+ case M_SEARCH:
+ if (!count) {
+ nresults = vot_regSearch (terms, nterms, stype, bandpass,
+ subject, clevel, orValues, out_votable, vot_fd, dal_only,
+ sortRes, terse);
+ } else {
+ if (orValues) {
+ for (i=0; i < nterms; i++) {
+ nresults = vot_regSearch (&terms[i], 1, stype, bandpass,
+ subject, clevel, 1, out_votable, vot_fd, dal_only,
+ sortRes, terse);
+ }
+ } else {
+ nresults = vot_regSearch (terms, nterms, stype, bandpass,
+ subject, clevel, 0, out_votable, vot_fd, dal_only,
+ sortRes, terse);
+ }
+ }
+ break;
+
+ case M_FULL:
+ for (i=0; i < nterms; i++)
+ printFullRecord (terms[i]);
+ break;
+
+ case M_METALIST:
+ if (nterms == 0) {
+ terms[nterms++] = "%";
+ }
+ for (i=0; i < nterms; i++)
+ printSvcMetadata (terms[i]);
+ break;
+
+ default:
+ fprintf (stderr, "Invalid mode.\n");
+ exit (1);
+ }
+
+
+ /* Close the VOTable.
+ */
+ if (!meta && out_votable) {
+ vot_printRegVOTableTail (vot_fd);
+ if (vot_fd != stdout)
+ fclose (vot_fd);
+ }
+
+ /* If we're asked to print the output VOTable to the screen print it
+ * here. If an output name was specified it will have already been
+ * written, if the 'samp' flag was set assume that is the only desired
+ * output.
+ */
+ if (!do_samp && out_votable && strcmp (vot_name, "/tmp/vot.xml") == 0) {
+ char line[SZ_LINE];
+
+ if ((vot_fd = fopen (vot_name, "r")) == (FILE *) NULL) {
+ fprintf (stderr, "Error opening VOTable result file.\n");
+ return (ERR);
+ }
+
+ memset (line, 0, SZ_LINE);
+ while (fgets (line, 4096, vot_fd)) {
+ fputs (line, stdout);
+ memset (line, 0, SZ_LINE);
+ }
+
+ fclose (vot_fd);
+ }
+
+ /* Broadcast the image as a message if requested.
+ */
+ if (do_samp) {
+ int sampH = 0;
+
+ if ((sampH = sampInit ("voatlas", "VOClient Task")) >= 0) {
+ char url[SZ_LINE];
+
+ memset (url, 0, SZ_LINE);
+ strcpy (url, vot_toURL (vot_name));
+
+ samp_setSyncMode (sampH);
+ sampStartup (sampH); /* initialize SAMP interface */
+
+ (void) samp_tableLoadVOTable (sampH, "all", url, NULL, NULL);
+
+ sampShutdown (sampH); /* clean up */
+ sampClose (sampH);
+ if (strcmp (vot_name, "/tmp/vot.xml") == 0)
+ unlink (vot_name);
+ }
+ }
+
+
+ return ( status );
+}
+
+
+/************************************************************************
+** PRINTRESOLVERECORD -- Print a "complete" record for the resources
+** matching the query string.
+*/
+static void
+printResolveRecord ()
+{
+ char *result = (char *)NULL;
+ register int i;
+
+
+ /* Determine the fields we'll need.
+ */
+ if (verbose == 1 && !fields)
+ fields = "ShortName,CapabilityStandardID,Title";
+ if (verbose == 2 && !fields)
+ fields = "ShortName,CapabilityStandardID,Description";
+
+ if (out_votable)
+ fields = "";
+
+ if (out_votable)
+ fields = "Title,ShortName,Identifier,ServiceURL,ReferenceURL,CapabilityStandardID,ContentLevel,Type,Waveband,Creator,Subject,Version";
+
+ if (! out_votable)
+ printResolveHdr ();
+
+ if (nterms == 0) {
+ terms[nterms++] = "%";
+ exact = 1;
+ }
+
+ for (i=0; i < nterms; i++) {
+#ifdef REG10_KLUDGE
+ if (reg10 || strncasecmp("ivo://CDS.VizieR",terms[i],16) == 0) {
+ char ivorn[SZ_LINE];
+
+ bzero (ivorn, SZ_LINE);
+ strcpy (ivorn, terms[i]);
+ strcat (ivorn, "%");
+ ivorn[9] = '/';
+
+ nresults = vot_regResolver (ivorn, stype, bandpass, subject,
+ clevel, fields, res_index, 0, dal_only, &result);
+ } else {
+#endif
+ nresults = vot_regResolver (terms[i], stype, bandpass, subject,
+ clevel, fields, res_index, exact, dal_only, &result);
+#ifdef REG10_KLUDGE
+ }
+#endif
+
+ if (! out_votable) {
+ if (count) {
+ if (nterms > 0 && terms[i][0] != '%')
+ printf ("%-20s %5d\t", terms[i], nresults);
+ else
+ printf ("%d", nresults);
+ if (verbose)
+ ppResSummary (result, nresults);
+ printf ("\n");
+ } else if (user_fields) {
+ pretty_print_table (result, nresults, fields);
+ } else {
+ pretty_print (result, nresults);
+ }
+ }
+
+ if (group)
+ break;
+ }
+ if (result)
+ free ((char *) result);
+}
+
+
+/************************************************************************
+** PRINTRESOLVEHDR -- Print the header information for Resolve mode.
+*/
+static void
+printResolveHdr ()
+{
+ if (nterms == 0)
+ return;
+ if (count) {
+ if (verbose) {
+ printf ("\nShortName \t\tMatching Resources\n");
+ printf ("-------------------------------------------");
+ printf ("------------------------------------");
+ } else {
+ printf ("\nShortName Matching Resources\n");
+ printf ("-------------------------------------------");
+ }
+ printf ("\n");
+
+ } else if (fields && !user_fields) {
+ printf("\nShortName ResourceType\t%s\n",
+ (verbose > 1 ? "Description" : "Title"));
+ printf("----------------------------------------");
+ printf("----------------------------------------\n");
+ }
+}
+
+
+/************************************************************************
+** PRINTFULLRECORD -- Print a "complete" recordfor the resources matching
+** the query string.
+*/
+static void
+printFullRecord (char *term)
+{
+ RegResult resource = 0;
+ int i, j, nresults;
+ char *attr_val, sql[SZ_LINE];
+
+
+ if (debug)
+ fprintf (stderr, "printFullRec: term='%s'\n", term);
+
+ if (res_all)
+ sprintf (sql, "(ShortName like '%%%s%%') OR (Identifier like '%%%s%%')",
+ term, term);
+ else
+ sprintf (sql, "(ShortName like '%s') OR (Identifier like '%s')",
+ term, term);
+
+ resource = voc_regExecute (voc_regQuery (sql, 0));
+ nresults = voc_resGetCount (resource);
+
+ if (nresults == 0 && !res_all) {
+
+ if (strncasecmp("ivo://CDS.VizieR",term,16) == 0) {
+ char *ip, ivorn[SZ_LINE];
+
+ bzero (ivorn, SZ_LINE);
+ strcpy (ivorn, term);
+ for (ip = &ivorn[strlen(term)-1]; *ip != '/'; ip--)
+ *ip = '\0';
+ *ip = '\0';
+
+ sprintf (sql,
+ "(ShortName like '%%%s%%') OR (Identifier like '%%%s%%')",
+ ivorn, ivorn);
+ } else
+ sprintf (sql,
+ "(ShortName like '%%%s%%') OR (Identifier like '%%%s%%')",
+ term, term);
+
+ resource = voc_regExecute (voc_regQuery (sql, 0));
+ nresults = voc_resGetCount (resource);
+
+ if (nresults == 0) {
+ fprintf (stderr, "No results found for '%s'\n", term);
+ return;
+ }
+ }
+
+ for (i=0; i < nresults; i++) {
+ if (out_votable) {
+ vot_printRegVOTableRec (stdout, resource, i);
+
+ } else {
+ for (j=0; resList[j]; j++) {
+ if ((attr_val = voc_resGetStr (resource, resList[j], i))) {
+ if (strstr (resList[j], "StandardID"))
+ printf ("%16.16s: ", "ResourceType");
+ else
+ printf ("%16.16s: ", resList[j]);
+ ppMultiLine((attr_val ? attr_val : "(none)"), 18, 61, 8192);
+ printf ("\n");
+ }
+ }
+ if (nresults > 1 && i < (nresults - 1))
+ printf ("------------------------------------------\n");
+ }
+ }
+}
+
+
+/************************************************************************
+** PRINTSVCMETADATA -- Print the column metadata for the named service.
+*/
+static void
+printSvcMetadata (char *svc)
+{
+ RegResult resource = 0;
+ RegQuery rquery = 0;
+ int i, nresults;
+ char *type, *url, sql[SZ_LINE];
+ DAL dal;
+ Query query;
+
+
+ if (res_all)
+ sprintf (sql, "(ShortName like '%%%s%%') OR (Identifier like '%%%s%%')",
+ svc, svc);
+ else
+ sprintf (sql, "(ShortName like '%s') OR (Identifier like '%s')",
+ svc, svc);
+
+ if (debug) fprintf (stderr, "metalist sql = '%s'\n", sql);
+
+ rquery = voc_regQuery (sql, 0);
+
+ if (bandpass && bandpass[0])
+ voc_regConstWaveband (rquery, bandpass);
+ if (stype && stype[0])
+ voc_regConstSvcType (rquery, stype);
+ if (dal_only)
+ voc_regDALOnly (rquery, dal_only);
+ voc_regSortRes (rquery, sortRes);
+
+ resource = voc_regExecute (rquery);
+ nresults = voc_resGetCount (resource);
+
+ if (debug) fprintf (stderr, "query nres = %d\n", nresults);
+
+ for (i=0; i < nresults; i++) {
+ if ((type = voc_resGetStr (resource, "CapabilityStandardID", i))) {
+ int len;
+
+ url = voc_resGetStr (resource, "ServiceURL", i);
+
+ /* Clean up any dangling '&amp;' in the URL.
+ */
+ len = strlen (url);
+ if (strcmp(&url[len-5], "&amp;") == 0)
+ url[len-5] = '\0';
+
+ /* Form a dummy query for the metadata.
+ */
+ if (strcasecmp ("CONE", type) == 0 ||
+ strncasecmp ("TABULAR", type, 7) == 0) {
+ dal = voc_openConeConnection (url);
+
+ /* As of 1/28/09 the Vizier SCS doesn't respond properly
+ ** to SR=0 for a metadata query, however if we leave off
+ ** the query params entirely we do get a valid response.
+ ** This is just a kludge.
+ **
+ query = voc_getConeQuery (dal, 0.0, 0.0,
+ (strstr (url, "vizier")) ? -1.0 : 0.0);
+ ** FIXME */
+ /* FIXME */
+
+ /* This is the standard SCS way to get metadata. For now
+ ** we'll do as the spec says and broken services will
+ ** have to be fixed.
+ */
+ query = voc_getConeQuery (dal, 0.0, 0.0, 0.001);
+
+ (void) voc_addIntParam (query, "VERB",
+ (meta ? 3 : min(3,verbose+1)) );
+
+ if (debug) {
+ fprintf (stderr, "Executing Metadata Query:\n %s\n\n",
+ voc_getQueryString (query, CONE_CONN, 0));
+ }
+
+ /*
+ printf (
+ "\n# ---- Svc: %s (%s) ---------------------------\n\n",
+ svc, type);
+ */
+ vot_printAttrs (NULL, query, svc);
+
+ } else if (strncasecmp ("SIAP", type, 4) == 0) {
+ dal = voc_openSiapConnection (url);
+ query = voc_getSiapQuery (dal, 0.0, 0.0, 0.0, 0.0, "METADATA");
+ (void) voc_addIntParam (query, "VERB", verbose);
+
+ /*
+ printf ("\n# ---- Svc: %s (%s) ---------------------------\n\n",
+ svc, type);
+ */
+ vot_printAttrs (NULL, query, svc);
+ }
+ }
+ }
+}
+
+
+/************************************************************************
+** GETLONGLINES -- Utility procedure to return the value of the 'longlines'
+** flag.
+*/
+int
+vot_getLonglines ()
+{
+ return (longlines);
+}
+
+
+/************************************************************************
+** GETTME -- Cteate a time-constrainst string for the search.
+*/
+#define SZ_TSTR 32
+#define SZ_TQUERY 256
+
+static char *
+vot_getTime (int type, char *arg)
+{
+ char unit = arg[strlen (arg) - 1];
+ long diff, val;
+ time_t now = time((time_t)NULL), then;
+ struct tm *start, *end;
+ static char t1[SZ_TSTR], t2[SZ_TSTR], tquery[SZ_TQUERY];
+
+
+ val = atoi (arg);
+ if (!isdigit(unit)) { /* get units of search */
+ if (strchr ("hH", (int) unit))
+ diff = val * 3600;
+ else if (strchr ("dD", (int) unit))
+ diff = val * (3600 * 24);
+ else if (strchr ("wW", (int) unit))
+ diff = val * (3600 * 24 * 7);
+ else if (strchr ("mM", (int) unit))
+ diff = val * (3600 * 24 * 30);
+ } else
+ diff = val * (3600 * 24);
+
+ then = now - diff;
+
+ memset (t1, 0, SZ_TSTR);
+ start = localtime (&then);
+ sprintf (t1, "%4d-%02d-%02dT%02d:%02d:%02d",
+ (start->tm_year+1900), start->tm_mon+1, start->tm_mday,
+ start->tm_hour, start->tm_min, start->tm_sec);
+
+ memset (t2, 0, SZ_TSTR);
+ end = localtime (&now);
+ sprintf (t2, "%4d-%02d-%02dT%02d:%02d:%02d",
+ (end->tm_year+1900), end->tm_mon+1, end->tm_mday,
+ end->tm_hour, end->tm_min, end->tm_sec);
+
+ sprintf (tquery,
+ "[@%s] >= '%s' AND [@%s] <= '%s'",
+ (type == TIME_NEW ? "created" : "updated"), t1,
+ (type == TIME_NEW ? "created" : "updated"), t2);
+ /*
+ sprintf (tquery, "[@%s] >= '%s'",
+ (type == TIME_NEW ? "created" : "updated"), t1);
+ */
+ return ( strdup(tquery) );
+}
+
+
+/* Get JD from date. Not entirely accurate, but good enough for what we need.
+*/
+double
+vot_calJD (int mn, double dy, int yr, int hrs, int min, int sec)
+{
+ int a, b, d, m, y;
+ long c;
+ double mjp;
+
+
+ m = mn;
+ y = (yr < 0) ? yr + 1 : yr;
+ if (mn < 3)
+ m += 12, y -= 1;
+
+ if (yr < 1582 || (yr == 1582 && (mn < 10 || (mn == 10 && dy < 15))))
+ b = 0;
+ else
+ a = y/100, b = 2 - a + a/4;
+
+ c = ((y < 0) ?
+ (long)((365.25*y) - 0.75) - 694025L : (long)(365.25*y) - 694025L);
+ d = (int)(30.6001*(m+1));
+
+ mjp = b + c + d + dy - 0.5;
+
+ mjp += (((double)hrs / 24.) + ((double)min / 60.) + ((double)sec / 3600.));
+ return (mjp);
+}
+
+
+
+
+/************************************************************************
+** USAGE -- Print a help summary for the task.
+*/
+static void
+Usage ()
+{
+ printf ("\n\
+ Usage: voregistry [-<flags>] [ [<keyword>] | [<term>] ]\n\
+ \n\
+ -h,--help print this help\n\
+ -v,--verbose verbose mode\n\
+ --vverbose very-verbose mode\n\
+ \n\
+ -c,--count print a count of matching records\n\
+ -e,--exact print exactly matching records (resolve)\n\
+ -l,--list list full resource record\n\
+ -m,--meta list table metadata\n\
+ -r,--resolve resolution mode\n\
+ \n\
+ -b,--bandpass <bandpass> constrain by bandpass\n\
+ -C,--clevel <level> constrain by content level\n\
+ -d,--dal constrain to only DAL services\n\
+ -g,--group group search terms\n\
+ -s,--subject <subject> constrain by subject string\n\
+ -t,--type <type> constrain by service type\n\
+ -N,--new <time> get only newly registered svcs\n\
+ -U,--updated <time> get only newly updated entries\n\
+ \n\
+ -a,--all print all results (default)\n\
+ -f,--fields <fields> output only specified fields\n\
+ -O,--or logically OR the search terms\n\
+ -n,--index <index> set index of result (-1 => list, 0 => all)\n\
+ -o,--output <oname> save results to <oname> as votable\n\
+ -B,--samp broadcast results as a SAMP message\n\
+ -V,--votable save results as VOTable\n\
+ -X,--xml save results as VOTable\n\
+ \n\
+ -I,--Id print only the Identifier (resolve mode)\n\
+ -L,--long print long lines of output (no wrapping)\n\
+ -R,--Resolve print the ShortName, ServiceType and ID\n\
+ -S,--SName print only the ShortName (resolve mode)\n\
+ -T,--Title print only the Title string (resolve mode)\n\
+ \n\
+ \n\
+ Resource Type Strings:\n\
+ catalog Cone search services\n\
+ image Simple Image Access services\n\
+ spectra Simple Spectral Access services\n\
+ table Vizier services\n\
+ <literal> ResourceType from Registry record\n\
+ \n\
+ Allowed Bandpass Strings:\n\
+ Radio Millimeter Infrared (IR)\n\
+ Optical Ultraviolet (UV) X-Ray (xray)\n\
+ Gamma-Ray (GR)\n\
+ \n\
+ Allowed Resource Fields (for -f flag):\n\
+ Title ShortName Identifier\n\
+ ServiceURL ReferenceURL Description\n\
+ Subject ResourceType Type\n\
+ Creator Publisher CoverageSpatial\n\
+ CoverageTemporal Waveband ContentLevel\n\
+ Version\n\
+ \n\
+ \n\
+ \n\
+ Examples:\n ---------\n\n\
+ \n\
+ 1) Get a count of all the SIAP services available in the,\n\
+ Registry, then list more information about each:\n\
+ \n\
+ %% voregistry --count --type=image\n\
+ 171\n\
+ %% voregistry -rv -t image\n\
+ \n\
+ 2) Find all catalog (i.e. Cone) services using the search\n\
+ words 'radio' and 'galaxies':\n\
+ \n\
+ %% voregistry -t catalog radio galaxies\n\
+ \n\
+ 3) Print the full resource record of the GSC2.3 catalog at STScI:\n\
+ \n\
+ %% voregistry --list GSC2.3\n\
+ ");
+
+ printf ("\n\n");
+}
+
+
+/**
+ * Tests -- Task unit tests.
+ */
+static void
+Tests (char *input)
+{
+ Task *task = &self;
+
+ vo_taskTest (task, "--help", NULL);
+
+ vo_taskTest (task, "--count", "--type=image", NULL); // Ex 1
+ vo_taskTest (task, "-rv", "-t", "image", NULL); // Ex 1
+ vo_taskTest (task, "-t", "catalog", "radio", "galaxies", NULL); // Ex 2
+ vo_taskTest (task, "--list", "GSC2.3", NULL); // Ex 3
+
+ vo_taskTest (task, "-b", "radio", "abell", NULL);
+ vo_taskTest (task, "-rvv", "-n", "1", "J/A+A/446/97", NULL);
+ vo_taskTest (task, "-v", "-t", "image", "wfpc", NULL);
+ vo_taskTest (task, "-cv", "keck", NULL);
+ vo_taskTest (task, "-c", "chandra", "hst", "spitzer", NULL);
+ vo_taskTest (task, "-co", "chandra", "hst", "spitzer", NULL);
+ vo_taskTest (task, "Facility like 'HST'", NULL);
+ vo_taskTest (task, "Title like '%Keck%'", NULL);
+ vo_taskTest (task, "--new", "3m", NULL);
+ vo_taskTest (task, "--new", "3m", "cool", "stars", NULL);
+ vo_taskTest (task, "--updated", "12m", "--count", NULL);
+
+ vo_taskTestReport (self);
+}
diff --git a/vendor/voclient/voapps/vosamp.c b/vendor/voclient/voapps/vosamp.c
new file mode 100644
index 00000000..4cc49d08
--- /dev/null
+++ b/vendor/voclient/voapps/vosamp.c
@@ -0,0 +1,2298 @@
+/**
+ * VOSAMP - Example task to send a single SAMP message for the cmdline.
+ *
+ * Usage:
+ *
+ * vosamp [<opts>] <cmd> [args ...]
+ *
+ * Where
+ * <cmd> command to process
+ * -%,--test run unit tests
+ * -h,--help print help summary
+ * -d,--debug debug output
+ * -v,--verbose verbose output
+ * -q,--quiet suppress all output
+ *
+ * -i,--interactive interactive mode
+ * -m,--many handle multiple messages
+ * -s,--sender <sender> handle only messages from <sender>
+ *
+ * -t,--to <to> send to specified application (or all)
+ * -p,--pattern <pattern> message pattern: sync|async|notify
+ * -f,--file <file> send all commands in the file
+ * -n,--nokeepalive disable keep_alive feature
+ *
+ * -P,--proxy <pattern> proxy process connection
+ * -T,--timeout <N> keepalive timeout
+ * -S,--session <name> session name
+ *
+ * -r,--return return result to API
+ *
+ *
+ * Subcommands:
+ *
+ * snoop print all received messages
+ *
+ * session list list all nodes in current session
+ * session leave|exit|logout leave the current session
+ * session <name> join the named session
+ *
+ * status print Hub availability
+ * list list all registered clients
+ * access <appName> print <appName> availability
+ * handle <mtype> wait for <mtype> message
+ *
+ * send <mtype> [<args> ...] generalized <mtype> message send
+ * exec <cmd> execute a client command
+ * pointAt <ra> <dec> point at given coords
+ * setenv <name> <value> set an environment value
+ * getenv <name> get an environment value
+ * setparam <name> <value> set a parameter value
+ * getparam <name> get a parameter value
+ *
+ * load <url> load the named image/table file
+ * loadImage <url> load the named image
+ * loadVOTable <url> load the named VOTable
+ * loadFITS <url> load the named FITS bintable
+ * showRow [<tblId>] [<url>] <row> highlight specified row
+ * selectRows [<tblId>] [<url>] <rows> select specified rows
+ * bibcode <bibcode> load the named bibcode
+ *
+ *
+ * @file vosamp.c
+ * @author Mike Fitzpatrick
+ * @date 6/03/12
+ *
+ * @brief Desktop SAMP messaging utility.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <ctype.h>
+#include <fcntl.h>
+#include <time.h>
+
+#include <netdb.h>
+#include <sys/errno.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+
+#include "samp.h" /* LIBSAMP interface */
+#include "voApps.h" /* voApps interface */
+
+
+#define SZ_MTYPE 64
+#define SZ_BUF 128
+#define SZ_HOSTIP 16
+#define SZ_APPNAME 16
+#define SZ_BLOCK 4096
+
+#define HUB_TIMEOUT /* allow timeout */
+
+#define ENV_PROXY "VOSAMP_PROXY"
+
+
+#define MAX_ARGS 8
+#define VOS_TIMEOUT 600 /* 10-min proxy timeout */
+#define VOS_DEFPORT 3999
+#define VOS_HUBWAIT 3
+
+#define MATCH(s) (strcasecmp(cmd,s)==0)
+
+
+char senderIP[SZ_HOSTIP];
+char fname[SZ_FNAME];
+char *to = NULL;
+
+static int sampH = 0; /* samp struct handle */
+
+ /* task options */
+static int verbose = 0; /* verbose output */
+static int quiet = 0; /* suppress all output */
+static int debug = 0; /* verbose output */
+static int interact = 0; /* interactive shell */
+static int multiple = 0; /* accept multiple msgs */
+static int xml_trace = 0; /* trace XML_RPC */
+static int keep_alive = 1; /* lingering connection */
+static int proxy_pid = 0; /* proxy vosamp pid */
+static int proxy_port = VOS_DEFPORT; /* proxy vosamp port */
+
+static int svr_sock = 0; /* child server socket */
+static int ipc_sock = 0; /* IPC sock (parent/child) */
+static int session_sock = 0; /* session mgr socket */
+static int input_sock = 0; /* cmd input socket */
+static int use_ipc = 1; /* use IPC */
+static int have_dotfile = 0; /* have a valid .vosamp? */
+static int in_parent = 1; /* are we parent process? */
+static int do_return = 1; /* return result to API */
+static int return_stat = OK; /* return status */
+static int numargs = 0; /* number of cmdline args */
+static int timeout = VOS_TIMEOUT; /* child timeout */
+
+static int hub_connected = 0; /* connected to SAMP hub */
+static int sess_connected = 0; /* connected to session mgr */
+
+char *session_host = SESS_DEFHOST; /* session manager host IP */
+int session_port = SESS_DEFPORT; /* session manager port */
+
+static char *proxy = NULL; /* proxy connection string */
+static char *session = NULL; /* session name */
+static char *pattern = NULL; /* SAMP msg pattern */
+static char *cmdfile = NULL; /* input command file */
+static char *filt_mtype = NULL; /* snoop filter mtype */
+static char *filt_sender = NULL; /* snoop sender name */
+static char cmd[SZ_CMD]; /* command name */
+static char cmdline[SZ_CMD]; /* full command line */
+static char proxy_host[SZ_FNAME]; /* proxy vosamp host name */
+static char dotfile[SZ_FNAME]; /* path to local dotfile */
+static char psession[SZ_FNAME]; /* proxy file session name */
+static char *args[MAX_ARGS]; /* command args buffer */
+
+static FILE *fd = (FILE *) NULL;
+static fd_set allset, fds;
+static struct timeval tm;
+
+
+static int vos_sendToProxy (char *cmdline);
+static int vos_startProxy (void);
+static int vos_sampInit (void);
+static int vos_sendCmd (int sock, char *cmdline);
+static int vos_invalidArg (int argc, char *argv[], int nargs, int exist);
+static void vos_sampShutdown (void);
+static void vos_cmdHelp (char *cmd);
+static void vos_procCmd(int sampH, char *to, char *cmd, char **argv, int argc);
+static void vos_handleCmdInput (void);
+static void vos_msgHandler (char *sender, char *mtype, char *msg_id, Map map);
+static void vos_sessionHandler (char *sender, char *mtype, char *id, Map map);
+static void vos_forwardCmd (char *sess_cmd);
+static void vos_printMessage (char *mtype, char *sender, Map map);
+
+static void vos_rewriteCmd (char *line, char *fname);
+static void vosDebug (char *format, ...);
+static char *vos_rewriteURL (char *in);
+static char *vos_dotFile ();
+
+int vos_uploadFiles (int fd, char *cmdline);
+int vos_recvFile (int sock, int size, char *fname);
+int vos_sendFile (int sock, char *path, char *fname);
+int vos_openSession (char *host, int port, char *session_name);
+int vos_closeSession (int sock);
+
+
+extern char *vos_toURL (char *arg);
+extern char *vos_optArg (char *arg);
+extern char *vos_getLocalIP (void);
+extern char *vos_getFName (char *url);
+extern char *vos_typeName (int type);
+extern int *vos_toIntArray (char *arg, int *nrows);
+extern int vot_atoi (char *v);
+
+
+/* Utility socket routines.
+ */
+extern int vos_fileRead (int fd, void *vptr, int nbytes);
+extern int vos_fileWrite (int fd, void *vptr, int nbytes);
+extern int vos_openServerSocket (int port);
+extern int vos_openClientSocket (char *host, int port, int retry);
+extern int vos_testClientSocket (char *host, int port);
+extern int vos_sockRead (int fd, void *vptr, int nbytes);
+extern int vos_sockWrite (int fd, void *vptr, int nbytes);
+extern int vos_sockWriteHdr (int fd, int len, char *name, int type,
+ int mode, char *to);
+extern int vos_sockReadHdr (int fd, int *len, char *name, int *type,
+ int *mode);
+extern int vos_urlType (char *url);
+extern int vos_getURL (char *url, char *fname);
+
+extern double vot_atof (char *v);
+
+extern void vos_setNonBlock (int sock);
+extern struct hostent *vos_getHostByName (char *lhost);
+extern struct hostent *vos_dupHostent (struct hostent *hentry);
+
+
+
+/* Task specific option declarations.
+ */
+int vosamp (int argc, char **argv, size_t *len, void **result);
+
+static Task self = { "vosamp", vosamp, 0, 0, 0 };
+static char *opts = "%:hnrdif:mps:t:vP:T:S:";
+static struct option long_opts[] = {
+ { "return", 0, 0, 'r'}, /* task option */
+ { "help", 2, 0, 'h'}, /* required */
+ { "test", 1, 0, '%'}, /* required */
+ { "debug", 2, 0, 'd'}, /* debug */
+ { "verbose", 2, 0, 'v'}, /* verbose output */
+ { "quiet", 2, 0, 'q'}, /* suppress output */
+ { "many", 2, 0, 'm'}, /* multiple msgs */
+ { "sender", 1, 0, 's'}, /* sender filter */
+ { "interactive", 2, 0, 'i'}, /* interactive mode */
+ { "file", 1, 0, 'f'}, /* cmd file */
+ { "pattern", 1, 0, 'p'}, /* msg pattern */
+ { "proxy", 1, 0, 'P'}, /* proxy connection */
+ { "session", 1, 0, 'S'}, /* session name */
+ { "to", 1, 0, 't'}, /* recipient name */
+ { "nokeepalive", 2, 0, 'n'}, /* keep connection */
+ { "timeout", 1, 0, 'T'}, /* connection timeout */
+ { NULL, 0, 0, 0 }
+};
+
+static void Usage (void);
+static void Tests (char *input);
+
+
+
+/****************************************************************************
+ * Program entry point.
+ */
+int
+vosamp (int argc, char **argv, size_t *reslen, void **result)
+{
+ char **pargv, optval[SZ_FNAME], ch, *env_proxy = NULL;
+ int i, pos = 0, len = 0;
+ time_t expiry;
+
+
+ /* Initialize.
+ */
+ memset (cmd, 0, SZ_CMD);
+ memset (cmdline, 0, SZ_CMD);
+ memset (dotfile, 0, SZ_FNAME);
+ memset (psession, 0, SZ_FNAME);
+ memset (proxy_host, 0, SZ_FNAME);
+
+ strcpy (proxy_host, vos_getLocalIP ());
+ strcpy (dotfile, vos_dotFile ());
+ for (i=0; i < MAX_ARGS; i++)
+ args[i] = calloc (1, SZ_LINE);
+
+ *reslen = 0;
+ *result = NULL;
+ return_stat = OK;
+
+
+ /* Parse the argument list.
+ */
+ pargv = vo_paramInit (argc, argv, opts, long_opts);
+ i = 0;
+ while ((ch = vo_paramNext (opts,long_opts,argc,pargv,optval,&pos)) != 0) {
+ i++;
+ if (ch > 0) {
+ switch (ch) {
+ case '%': Tests (optval); return (self.nfail);
+ case 'h': Usage (); return (OK);
+
+ case 'd': debug++; break;
+ case 'v': verbose++; break;
+ case 'q': quiet++; break;
+ case 'n': keep_alive = 0; break;
+ case 'm': multiple++; break;
+ case 'i': interact++; break;
+
+ case 's': filt_sender = strdup (optval); i++; break;
+ case 'f': cmdfile = strdup (optval); i++; break;
+ case 't': to = strdup (optval); i++; break;
+ case 'p': pattern = strdup (optval); i++; break;
+ case 'P': proxy = strdup (optval); i++; break;
+ case 'S': session = strdup (optval); i++; break;
+ case 'T': timeout = vot_atoi (optval); i++; break;
+
+ case 'r': do_return=1; break;
+ default:
+ fprintf (stderr, "Invalid option '%s'\n", optval);
+ return (1);
+ }
+
+ } else if (ch == PARG_ERR) {
+ return (ERR);
+
+ } else {
+ /* Remainder of argv is the subcommand and its arguments.
+ */
+ if (pargv[i] == NULL)
+ break;
+ if (!cmd[0]) {
+ strcpy (cmd, optval);
+ } else {
+ if (strcasecmp (cmd, "exec") == 0 ||
+ strcasecmp (cmd, "echo") == 0) {
+ strcat (args[0], optval);
+ strcat (args[0], " ");
+ } else {
+ char *ip;
+
+ while (pargv[i]) {
+ if (strstr (pargv[i], "://") == NULL) {
+ /* replace ':' w/ '=' */
+ for (ip=pargv[i]; *ip; ip++)
+ *ip = ((*ip == ':') ? '=' : *ip);
+ }
+ strcpy (args[numargs++], pargv[i++]);
+ }
+ break;
+ }
+ }
+ }
+ }
+
+
+ /* Print command help if that's all we're asked.
+ */
+ if (strncmp (cmd, "?", 1) == 0 || strncasecmp (cmd, "help", 4) == 0) {
+ Usage ();
+ return (OK);
+ }
+ if (strncmp(args[0], "?", 1) == 0 || strncasecmp(args[0], "help", 4) == 0) {
+ vos_cmdHelp (cmd);
+ return (OK);
+ }
+ if (strncmp(cmd, "access", 6) == 0 && strncasecmp(args[0], "hub", 3) == 0) {
+ int hub_connected = vos_sampInit ();
+
+ printf ("%s\n", (hub_connected ? "yes" : "no"));
+ if (hub_connected)
+ vos_sampShutdown ();
+ return ( (hub_connected ? OK : ERR) );
+ }
+ if (strcmp (cmd, "handle") == 0 || strcmp (cmd, "snoop") == 0)
+ keep_alive = 0;
+
+
+ /* Sanity checks.
+ */
+ if (interact || argc <= 1)
+ cmdfile = strdup ("-");
+ if (to == NULL)
+ to = strdup ("all");
+ if (pattern == NULL)
+ pattern = strdup ("async");
+
+
+ /* Initialize the SAMP interface.
+ tm.tv_sec = VOS_HUBWAIT;
+ */
+ tm.tv_sec = timeout;
+ tm.tv_usec = 0;
+ session_sock = 0;
+
+
+ /* Check for environment definitions.
+ */
+ if ((env_proxy = getenv (ENV_PROXY)))
+ proxy = strdup (env_proxy);
+
+ if (proxy) {
+ /* We've been asked to send the command to a particular proxy, just
+ * send the command line and any required data.
+ */
+ char *cp = strchr (proxy, (int)':');
+
+ vosDebug ("Using proxy '%s'\n", proxy);
+ if (cp) {
+ proxy_port = vot_atoi (cp+1);
+ *cp = '\0';
+ strcpy (proxy_host, proxy);
+ } else {
+ proxy_port = VOS_DEFPORT;
+ strcpy (proxy_host, proxy);
+ }
+ use_ipc++;
+ have_dotfile++;
+ ipc_sock = vos_openClientSocket (proxy_host, proxy_port, 1);
+
+ } else {
+ /* See if we have a local proxy running we can use instead of starting
+ * a new connection. Data references remain local unless being
+ * passed on to the session manager service.
+ */
+ FILE *fd = (FILE *) NULL;
+
+ if (keep_alive && access (dotfile , R_OK) == 0) {
+ if ((fd = fopen (dotfile, "r+")) != (FILE *) NULL) {
+ time_t now = time ((time_t) 0);
+ int test = 0;
+
+ /* Read the dotfile contents.
+ */
+ fscanf (fd, "%s %d %d %ld %s",
+ proxy_host, &proxy_port, &proxy_pid, &expiry, psession);
+ fclose (fd);
+
+
+ /* Make sure we can reach the running proxy, otherwise
+ * assume it is a stale dotfile.
+ */
+ if ((test = vos_testClientSocket(proxy_host, proxy_port)) < 0) {
+ if (verbose)
+ fprintf (stderr, "Removing stale .vosamp file ...\n");
+ unlink (dotfile);
+ goto samp_init;
+ } else {
+ vos_sockWriteHdr (test, 0, NULL, SAMP_TEST, 0, "proxy");
+ close (test);
+ }
+
+ /* Check for a stale dotfile. */
+ if (now <= (expiry - 2)) {
+ use_ipc++;
+ have_dotfile++;
+ } else {
+ if (verbose)
+ fprintf (stderr, "Removing stale .vosamp file ...\n");
+ unlink (dotfile);
+ goto samp_init;
+ }
+ }
+ } else {
+ /* First do some sanity checks on the command. If we're asked
+ * to quit, then simply don't connect.
+ */
+ if (strncasecmp ("quit", cmd, 4) == 0) {
+ return (OK);
+ }
+
+ /* No remote command specified, no local connection, so connect to
+ * the Hub as a new application.
+ *
+ * Start the keep-alive proxy server.
+ */
+samp_init:
+ if (keep_alive) {
+ vos_startProxy ();
+ use_ipc = 1;
+ } else {
+ if (! (hub_connected = vos_sampInit ())) {
+ fprintf (stderr, "Error: cannot connect to Hub.\n");
+ return (ERR);
+ }
+ use_ipc = 0;
+ }
+ }
+ }
+
+
+ /* Process a single command if we're not in keep_alive mode.
+ */
+ if (!keep_alive) {
+ vos_procCmd (sampH, to, cmd, args, numargs);
+ goto cleanup_;
+ }
+
+ /* Open an IPC socket to the proxy.
+ */
+ while (in_parent && ipc_sock <= 0) {
+ vosDebug ("opening ipc socket to %s:%d\n", proxy_host, proxy_port);
+ ipc_sock = vos_openClientSocket (proxy_host, proxy_port, 1);
+ if (ipc_sock < 0) {
+ if (verbose)
+ fprintf (stderr, "Cannot open client ipc_sock\n");
+ sleep (1);
+ }
+ }
+ vosDebug ("ipc socket %d\n", ipc_sock);
+
+
+ /* Process the messages in the named file, or from the cmdline. Since
+ * there is some overhead in connecting to the hub, this is an efficient
+ * way to send multiple messages from a single connection.
+ */
+
+ if (cmdfile) {
+ fd = (cmdfile[0] == '-' ? stdin : fopen (cmdfile, "r"));
+
+ /* Send the command string from the stdin or the cmd file.
+ */
+ fprintf (stderr, "vosamp> ");
+#ifdef FGETS
+ while (fgets (cmdline, SZ_CMD, fd) && !feof (fd) && !ferror (fd)) {
+#else
+ FD_ZERO (&allset);
+ FD_SET (fileno (stdin), &allset);
+ while (1) {
+ memcpy (&fds, &allset, sizeof(allset));
+ if (select (8, &fds, NULL, NULL, NULL) == 0)
+ continue;
+
+ if (fgets (cmdline, SZ_CMD, stdin) == NULL)
+ continue;
+#endif
+ len = strlen (cmdline);
+ if (cmdline[len-1] == '\n')
+ cmdline[len-1] = '\0';
+
+ if (strncasecmp (cmdline, "quit", 4) == 0 ||
+ strncasecmp (cmdline, "logo", 4) == 0)
+ break;
+ else if (cmdline[0]) {
+ vos_sendToProxy (cmdline);
+ fprintf (stderr, "vosamp> ");
+ }
+ }
+
+ if (fd != stdin)
+ fclose (fd);
+
+ } else if (cmd[0]) {
+ /* Send the command string from the commandline.
+ */
+ int i, len = 0;
+
+ memset (cmdline, 0, SZ_CMD);
+ sprintf (cmdline, "%s %s ", cmd, args[0]);
+ for (i=1; i < numargs; i++) {
+ strcat (cmdline, args[i]);
+ strcat (cmdline, " ");
+ }
+ len = strlen (cmdline); cmdline[len-1] = '\0';
+
+ vos_sendToProxy (cmdline);
+ }
+ close (ipc_sock);
+
+
+ /* Close down and clean up.
+ */
+cleanup_:
+ if (!keep_alive)
+ vos_sampShutdown ();
+
+ if (to) free ((void *) to);
+ if (proxy) free ((void *) proxy);
+ if (cmdfile) free ((void *) cmdfile);
+ if (pattern) free ((void *) pattern);
+ if (session) free ((void *) session);
+ if (filt_sender) free ((void *) filt_sender);
+
+ return (return_stat);
+}
+
+
+/**
+ * VOS_SENDTOPROXY -- Send a cmdline to the proxy.
+ */
+static int
+vos_sendToProxy (char *cmdline)
+{
+ /* See if we need to join a session before processing the cmd.
+ */
+ if (session && psession[0] != '\0') {
+ /* Have session param and running a proxy.
+ */
+ memset (cmdline, 0, SZ_CMD);
+ sprintf (cmdline, "session %s", session);
+
+ } else if (strcasecmp (cmd, "session") == 0 &&
+ (psession[0] && strcasecmp (psession, "none") == 0)) {
+ /* Have session command and not running a proxy.
+ */
+ memset (cmdline, 0, SZ_CMD);
+ sprintf (cmdline, "session %s", args[0]);
+ }
+
+ if (strcasecmp (proxy_host, vos_getLocalIP())) {
+ int nfiles = vos_uploadFiles (ipc_sock, cmdline);
+ vosDebug ("....sent %d data files....\n", nfiles);
+ }
+
+
+ if (strncmp (cmd, "?", 1) == 0 || strncmp (cmd, "help", 4) == 0) {
+ vos_cmdHelp (cmd);
+ return (0);
+ }
+
+ /* Send the command string.
+ */
+ vosDebug ("sending to proxy: '%s'\n", cmdline);
+ if (vos_sendCmd (ipc_sock, cmdline) == 0) {
+ vosDebug ("sending to proxy fails: '%s'\n", cmdline);
+ if (verbose)
+ fprintf (stderr, "Error writing command '%s'\n", cmdline);
+
+ return (0);
+
+ } else {
+ short nread, len;
+
+ vosDebug ("reading ipc response ....\n");
+ nread = vos_sockRead (ipc_sock, &len, sizeof (short));
+ vosDebug ("ipc response len = %d....\n", len);
+ if (len > 0) {
+ char *res = calloc (1, (len+1));
+ nread = vos_sockRead (ipc_sock, res, len);
+ vosDebug ("ipc response nread = %d....res = '%s'\n", nread, res);
+ if ((nread > 0 && strcmp (res, "OK") != 0) || verbose)
+ printf ("%s\n", res);
+ if (res) free ((void *) res);
+ }
+ return (1);
+ }
+
+ return (0);
+}
+
+
+/**
+ * VOS_STARTPROXY -- Start the VOSAMP proxy process.
+ */
+static int
+vos_startProxy (void)
+{
+ /* Start the keep-alive proxy server.
+ */
+ if (keep_alive && in_parent && !have_dotfile) {
+ switch ( fork() ) {
+ case 0: /* start child proxy */
+ vosDebug ("child pid\n");
+
+ /* Open server socket, read future input from socket.
+ */
+ vosDebug ("child opening server port %d...\n", proxy_port);
+ if ((svr_sock = vos_openServerSocket (proxy_port)) < 0) {
+ fprintf (stderr, "Cannot open VOSAMP port %d\n", proxy_port);
+ if (have_dotfile) unlink (dotfile);
+ }
+
+ FD_ZERO (&allset);
+ FD_SET (svr_sock, &allset); vos_setNonBlock (svr_sock);
+ vosDebug ("child svr_sock %d...\n", svr_sock);
+
+ if (session) {
+ /* Open a client connection to the VOSAMP Session Manager.
+ */
+ vosDebug ("initializing session '%s' on %s:%d\n", session,
+ session_host, session_port);
+ if ((session_sock = vos_openSession (session_host,
+ session_port, session)) < 2) {
+ vosDebug ("session open fails...\n");
+ session_sock = 0;
+ session = NULL;
+ } else {
+ vosDebug ("child session sock %d...\n", session_sock);
+ FD_SET (session_sock, &allset);
+ vos_setNonBlock (session_sock);
+ sess_connected = 1;
+ }
+ }
+
+ /* Now initialize the SAMP interface.
+ */
+ vosDebug ("initializing SAMP connection\n");
+#ifdef HUB_BLOCKS
+ while (vos_sampInit () == 0) {
+ /* Wait for a Hub connection.
+ */
+ if (debug || verbose) {
+ fprintf (stderr, "Waiting for Hub ....");
+ sleep (VOS_HUBWAIT);
+ }
+ }
+#else
+ hub_connected = vos_sampInit ();
+#endif
+
+ in_parent = 0;
+ vos_handleCmdInput ();
+
+ /* Child never returns from this point .....
+ */
+ exit (0);
+ break;
+
+ case -1: /* fork fails */
+ if (verbose && in_parent)
+ fprintf (stderr, "%d proxy fork failure.\n", (int)getpid());
+ break;
+
+ default: /* parent exits */
+ vosDebug ("parent pid\n");
+ sleep (2); /* give child a chance to start */
+ }
+ }
+
+ return (0);
+}
+
+
+/**
+ * VOS_SENDCMD -- Send a SAMP_CMD to the specified socket.
+ */
+static int
+vos_sendCmd (int sock, char *cmdline)
+{
+ char res[SZ_LINE];
+ int nread = 0, nwrite = 0, len = (cmdline ? strlen (cmdline) : 0);
+
+
+ vosDebug ("sendCmd: '%s'\n", cmdline);
+ memset (res, 0, SZ_LINE);
+
+ if (vos_sockWriteHdr (sock, len, NULL, SAMP_CMD, SAMP_NOTIFY, to)) {
+ vosDebug ("writing cmdline '%s' fd=%d\n", cmdline, sock);
+ nwrite = vos_sockWrite (sock, cmdline, len);
+
+ /* See if we have a result returned to us. If so, it will be
+ * a character string we should just print out.
+ */
+ if (session && sock != session_sock) {
+ vosDebug ("reading response fd=%d\n", sock);
+ nread = vos_sockRead (sock, &len, sizeof (int));
+ if (len > 0) {
+ char *res = calloc (1, (len+1));
+
+ nread = vos_sockRead (sock, res, len);
+ if ((nread > 0 && strcmp (res, "OK") != 0) || verbose)
+ printf ("%s\n", res);
+ if (res) free ((void *) res);
+ }
+ } else
+ return (1);
+ }
+
+ return (nread);
+}
+
+
+/**
+ * VOS_UPLOADFILES -- Upload any files on the commandline to the remote
+ * host. The remote client is responsible for rewriting the commandline
+ * as appropriate, our job here is to suss out which are the file arguments.
+ */
+int
+vos_uploadFiles (int sock, char *cmdline)
+{
+ char *ip, *op, buf[SZ_BUF], fname[SZ_FNAME];
+ int nfiles = 0;
+
+
+ for (ip=cmdline; *ip; ) {
+ memset (buf, 0, SZ_BUF);
+ memset (fname, 0, SZ_FNAME);
+ for (op=buf; *ip && !isspace(*ip); ) /* get token */
+ *op++ = *ip++;
+
+ /* Upload the file. If we have a file:// URL strip out the
+ * local pathname. Note that in this implementation we're
+ * limited to a single data file per-message.
+ */
+ if (strncmp ("file://", buf, 7) == 0) {
+ strcpy (fname, &buf[7]);
+ if (access (fname, F_OK) < 0) /* file doesn't exist */
+ return (-1);
+ }
+ if (access (buf, F_OK) == 0)
+ strcpy (fname, buf);
+
+ if (fname[0]) { /* upload the file */
+ vosDebug ("uploading file '%s'....\n", fname);
+ if (vos_sendFile (sock, fname, vos_getFName (fname)) != OK)
+ fprintf (stderr, "Error sending file '%s'\n", fname);
+ nfiles++;
+ }
+
+ while (*ip && isspace (*ip)) /* skip whitespace */
+ ip++;
+ }
+
+ return (nfiles);
+}
+
+
+/**
+ * VOS_SENDFILE -- Send a file to a remote host.
+ */
+int
+vos_sendFile (int sock, char *path, char *fname)
+{
+ char block[SZ_BLOCK];
+ int fd, nread = 0, nleft = 0, size = 0, nb = 0;
+ struct stat fs;
+
+
+ if (access (path, R_OK) != 0 || stat (path, &fs) != 0)
+ return (ERR);
+
+ size = fs.st_size;
+ nleft = size;
+
+ if ((fd = open (path, O_RDONLY))) {
+ /* Send the header to pass the filename and size, then
+ * send the data itself.
+ */
+ vos_sockWriteHdr (sock, size, fname, SAMP_DATA, 0, to);
+ while (nleft > 0) {
+ memset (block, 0, SZ_BLOCK);
+ nb = min (SZ_BLOCK, nleft);
+
+ /* Read from the file, write it to the socket.
+ */
+ vos_fileRead (fd, block, nb);
+ vos_sockWrite (sock, block, nb);
+
+ nleft -= nb;
+ nread += nb;
+ }
+ close (fd);
+ }
+
+ return (OK);
+}
+
+
+/**
+ * VOS_RECVFILE -- Receive a file of the specified size from a remote host.
+ */
+int
+vos_recvFile (int sock, int size, char *fname)
+{
+ char block[SZ_BLOCK];
+ int fd, nread = 0, nleft = size, nb = 0;
+
+
+ /* Read the file from the socket, write to the filename.
+ */
+ vosDebug ("receiving file '%s'....%d\n", fname, size);
+ if ((fd = open (fname, O_WRONLY|O_CREAT, 0664))) {
+ while (nleft > 0) {
+ memset (block, 0, SZ_BLOCK);
+ nb = min (SZ_BLOCK, nleft);
+
+ /* Read from the socket, write it to the file.
+ */
+ vos_sockRead (sock, block, nb);
+ vos_fileWrite (fd, block, nb);
+
+ nleft -= nb;
+ nread += nb;
+ }
+ close (fd);
+ }
+
+ return (OK);
+}
+
+
+/**
+ * VOS_HANDLECMDINPUT -- Handle input from an input source.
+ */
+static void
+vos_handleCmdInput ()
+{
+ register int i, read_timeout = 0, rc;
+ char line[SZ_CMD];
+ static char data_file[SZ_FNAME];
+
+
+ memset (line, 0, SZ_CMD);
+ memset (data_file, 0, SZ_FNAME);
+ while (1) { /* loop until timeout */
+
+ /* Initialize the input file descriptor set and cmd buffer.
+ */
+ memset (line, 0, SZ_CMD);
+ memset (cmd, 0, SZ_CMD);
+ for (i=0; i < MAX_ARGS; i++)
+ memset (args[i], 0, SZ_LINE);
+
+ memcpy (&fds, &allset, sizeof(allset));
+ if ((rc = select (8, &fds, NULL, NULL, (timeout ? &tm : NULL))) == 0) {
+ read_timeout++; /* input timeout */
+ if (hub_connected && !samp_hubRunning()) {
+ hub_connected = 0;
+ }
+ if (!hub_connected && samp_hubRunning()) {
+ hub_connected = vos_sampInit();
+#ifdef HUB_TIMEOUT
+ } else {
+ unlink (dotfile); /* clean up the dotfile */
+ vos_sampShutdown (); /* shutdown Hub connection */
+ return;
+#endif
+ }
+ continue;
+
+ } else if (rc < 0) { /* Select error .... */
+ vosDebug ("select error '%s'\n", strerror (errno));
+ continue;
+ }
+
+
+ if (FD_ISSET(svr_sock, &fds)) {
+ int nbytes = 0, nread = 0, type = 0, mode = 0;
+ char fname[SZ_FNAME];
+
+
+ /* Accept a connection on the proxy port from a cmdline client.
+ */
+ vosDebug ("got input on server socket....\n");
+ memset (fname, 0, SZ_FNAME);
+
+ if ((ipc_sock = accept (svr_sock, NULL, NULL)) < 0) {
+ fprintf (stderr, "accept() errno %d: %s",
+ errno, strerror(errno));
+ continue;
+ }
+
+ if (vos_sockReadHdr (ipc_sock, &nbytes, fname, &type, &mode)) {
+ vosDebug ("server input: msgType = %s....\n",
+ vos_typeName (type));
+
+ if (strcasecmp (proxy_host, senderIP) && type == SAMP_DATA) {
+ if (vos_recvFile (ipc_sock, nbytes, fname) != OK) {
+ if (verbose || debug)
+ fprintf (stderr, "Error in recvFile '%s'\n", fname);
+ }
+ strcpy (data_file, fname);
+
+ if (vos_sockReadHdr(ipc_sock, &nbytes, fname,&type,&mode)) {
+ nread = vos_sockRead (ipc_sock, line, nbytes);
+ vos_rewriteCmd (line, data_file);
+ }
+ memset (data_file, 0, SZ_FNAME);
+
+ } else if (type == SAMP_CMD) {
+ nread = vos_sockRead (ipc_sock, line, nbytes);
+ vosDebug ("server cmd = '%s'....nr=%d nb=%d\n",
+ line, nread, nbytes);
+ if (data_file[0]) {
+ vos_rewriteCmd (line, data_file);
+ memset (data_file, 0, SZ_FNAME);
+ }
+ } else if (type == SAMP_RESULT) {
+ ; /* Not yet implemented */
+
+ } else if (type == SAMP_TEST) {
+ close (ipc_sock); /* Test connection, just ignore. */
+ }
+ }
+ input_sock = ipc_sock;
+
+ } else if (FD_ISSET(session_sock, &fds)) {
+ int nbytes = 0, nread = 0, type = 0, mode = 0;
+
+ /* Accept a command from the session manager for forwarding.
+ */
+ if (vos_sockReadHdr (session_sock, &nbytes, fname, &type, &mode)) {
+ vosDebug ("got input on session socket....\n");
+ nread = vos_sockRead (session_sock, line, nbytes);
+ input_sock = session_sock;
+
+ } else {
+ /* Session manager closed the socket, shut it down and
+ * disconnect.
+ */
+ vosDebug ("Closing session socket....\n");
+ FD_CLR (session_sock, &allset);
+ close (session_sock);
+ if (session) free ((void *) session);
+ session = NULL;
+ session_sock = 0;
+ continue;
+ }
+
+ } else
+ vosDebug ("Ignoring input on other descriptor ...\n");
+
+
+ /* Kill any trailing spaces and make sure we have an actual cmdline.
+ */
+ if (isspace(line[strlen(line)-1]))
+ line[strlen(line)-1] = '\0';
+ if (line[0] == '\0')
+ continue;
+
+
+ /* Check whether the command we want to process is directed to the
+ * proxy process itself. If so we process it locally rather than
+ * as a SAMP message for other clients.
+ */
+ vosDebug ("handleCmd line: '%s'\n", line);
+ if (strncasecmp (line, "exec", 4) == 0 ||
+ strncasecmp (line, "echo", 4) == 0) {
+ /* Special-case for exec/echo cmd to create single arg
+ */
+ strncpy (cmd, line, 4);
+ sprintf (args[0], "%s", &line[5]);
+ numargs = 1;
+ vos_procCmd (sampH, to, cmd, args, numargs);
+
+ } else if (strncasecmp (line, "status", 4) == 0) {
+ if (ipc_sock > 0) {
+ short slen, nwrite;
+ char buf[SZ_LINE];
+
+ memset (buf, 0, SZ_LINE);
+ sprintf (buf, "Status: SAMP Hub: %s ",
+ (hub_connected ? "ON " : "OFF"));
+ if (sess_connected) {
+ strcat (buf, "Session Mgr: ON (session='");
+ strcat (buf, session);
+ strcat (buf, "')");
+ } else
+ strcat (buf, "Session Mgr: OFF");
+
+ slen = strlen (buf); /* return result string */
+ if (vos_sockWrite (ipc_sock, &slen, sizeof (short)))
+ nwrite = vos_sockWrite (ipc_sock, buf, slen);
+
+ continue;
+ }
+
+ } else if (strncasecmp (line, "quit", 4) == 0) {
+ /* Quit the proxy process and return.
+ */
+ if (access (vos_dotFile(), F_OK) == 0)
+ unlink (vos_dotFile());
+ vos_sampShutdown (); /* shutdown Hub connection */
+ exit (0);
+
+ } else if (strncasecmp (line, "list", 4) == 0) {
+ /* List the connected clients.
+ */
+ verbose++, numargs=1;
+ vos_procCmd (sampH, to, "listClients", args, numargs);
+
+ } else if (strncasecmp (line, "session", 7) == 0) {
+ /* Special commands for Session management.
+ */
+ numargs = sscanf (line, "%s %s", cmd, args[0]);
+
+ if (strcmp (args[0], "list") == 0) {
+ memset (args[0], 0, SZ_LINE);
+ strcpy (args[0], "listNodes");
+
+ if (session_sock == 0) {
+ fprintf (stderr, "Error: No session established\n");
+ return;
+ } else {
+ verbose++;
+ numargs=1;
+ vos_procCmd (sampH, to, "listNodes", args, numargs);
+ }
+
+ } else if (strncmp (args[0], "leave", 5) == 0) {
+ if (session_sock)
+ vos_closeSession (session_sock);
+
+ } else {
+ /* Open a client connection to the VOSAMP Session Manager.
+ */
+ if (vos_testClientSocket (session_host, session_port) < 0) {
+ fprintf (stderr,
+ "Error: Session manager not available at %s:%d\n",
+ session_host, session_port);
+ return;
+ }
+ vosDebug ("initializing session '%s' on %s:%d\n", args[0],
+ session_host, session_port);
+ session_sock = 0;
+ session = strdup (args[0]);
+ if ((session_sock = vos_openSession (session_host,
+ session_port, args[0])) < 2) {
+ vosDebug ("session open fails...\n");
+ session_sock = 0, session = NULL;
+ } else {
+ vosDebug ("child session sock %d...\n", session_sock);
+ FD_SET (session_sock, &allset);
+ vos_setNonBlock (session_sock);
+ sess_connected = 1;
+ }
+ }
+
+ } else {
+ /* Process the input command as a SAMP message. Only process
+ * the command if we're connected to a Hub
+ */
+ if (hub_connected) {
+ numargs = sscanf (line, "%s %s %s %s %s %s %s %s %s",
+ cmd, args[0], args[1], args[2], args[3],
+ args[4], args[5], args[6], args[7]);
+
+ vos_procCmd (sampH, to, cmd, args, numargs);
+ }
+ }
+ }
+
+#ifdef FOO
+ if (ipc_sock)
+ close (ipc_sock); /* close the socket descriptor */
+#endif
+}
+
+
+/**
+ * VOS_REWRITECMD -- Rewrite the command string with filename substitution.
+ */
+static void
+vos_rewriteCmd (char *line, char *fname)
+{
+ char *ip, *op, buf[SZ_CMD], obuf[SZ_CMD];
+
+ memset (obuf, 0, SZ_CMD);
+ for (ip=line; *ip; ) {
+ memset (buf, 0, SZ_CMD);
+ for (op=buf; *ip && !isspace(*ip); ) /* get token */
+ *op++ = *ip++;
+
+ /* Replace file-URI and absolute paths with the replacement filename.
+ */
+ if (strncmp ("file://", buf, 7) == 0 || buf[0] == '/')
+ strcat (obuf, fname);
+ else
+ strcat (obuf, buf);
+
+ while (*ip && isspace (*ip)) /* skip whitespace */
+ strncat (obuf, ip++, 1);
+ }
+
+ memset (line, 0, SZ_CMD);
+ strcpy (line, obuf);
+}
+
+
+/**
+ * VOS_REWRITEURL -- Rwrite a URL argument so it is compatible with the
+ * session manager. Upload any local files if needed.
+ */
+static char *
+vos_rewriteURL (char *in)
+{
+ static char out[SZ_URL], path[SZ_LINE], *fname;
+ char tmpfile[SZ_LINE];
+
+
+ memset (path, 0, SZ_LINE); /* initialize */
+ memset (tmpfile, 0, SZ_LINE);
+ memset (out, 0, SZ_URL);
+
+ switch (vos_urlType (in)) {
+ case VOS_LOCALURL:
+ sprintf (tmpfile, "/tmp/%s", vos_getFName (in));
+ vos_getURL (in, tmpfile);
+ strcpy (path, tmpfile);
+ break;
+
+ case VOS_LOCALURI:
+ strcpy (path, &in[7]);
+ break;
+
+ case VOS_LOCALFILE:
+ strcpy (path, in);
+ break;
+
+ case VOS_REMOTE:
+ /* Nothing to do, simply return the string.
+ */
+ return (in);
+ }
+
+ /* Get the filename from the path. Format the new URL so that the
+ * session manager can easily rewrite it to use the smgr data space.
+ */
+ fname = vos_getFName (path);
+ sprintf (out, "SESSION_URL/%s", fname);
+
+ /* Send data to the session manager for storage as the 'fname'. The
+ * session manager will rewrite the URL.
+ */
+ if (session_sock && vos_sendFile (session_sock, path, fname) != OK)
+ fprintf (stderr, "Error uploading file '%s'\n", in);
+
+ return (out);
+}
+
+
+/**
+ * USAGE -- Print a task usage summary.
+ */
+static void
+Usage (void)
+{
+ fprintf (stderr,
+ " Usage:\n"
+ "\n"
+ " %% vosamp [-hvd] [-t to] [-p pattern] [-f file] <cmd> [args ...]\n"
+ "\n"
+ " where:\n"
+ " <cmd> command to process\n"
+ " -%%,--test run unit tests\n"
+ " -h,--help print help summary\n"
+ " -d,--debug debug output\n"
+ " -v,--verbose verbose output\n"
+ " -q,--quiet suppress all output\n"
+ "\n"
+ " -i,--interact interactive mode\n"
+ " -m,--many handle multiple messages\n"
+ " -s,--sender <sender> handle only messages from <sender>\n"
+ "\n"
+ " -t,--to <to> send to specified app (or all)\n"
+ " -p,--pattern <pattern> message pattern: sync|async|notify\n"
+ " -f,--file <file> send all commands in the file\n"
+ " -n,--nokeepalive disable keep_alive feature\n"
+ "\n"
+ " -P,--proxy <IP> use specfied proxy IP\n"
+ " -T,--timeout <N> keepalive timeout\n"
+ "\n"
+ " -r,--return return result to API\n"
+ "\n"
+ " Commands:\n"
+ "\n"
+ " snoop print all received messages\n"
+ " send <mtype> [<args> ...] generalized <mtype> message send\n"
+ "\n"
+ " status print Hub availability\n"
+ " list list all registered clients\n"
+ " access <appName> print <appName> availability\n"
+ " handle <mtype> wait for <mtype> message\n"
+ "\n"
+ " exec <cmd> execute a client command\n"
+ " setenv <name> <value> set an environment value\n"
+ " getenv <name> get an environment value\n"
+ " setparam <name> <value> set a parameter value\n"
+ " getparam <name> get a parameter value\n"
+ "\n"
+ " load <url> load the image/table\n"
+ " loadImage <url> load the named image\n"
+ " loadVOTable <url> load the named VOTable\n"
+ " loadFITS <url> load the named FITS bintable\n"
+ " loadSpec <url> load the named spectrum\n"
+ " loadResource <ivorn> load the named VO Resource\n"
+ "\n"
+ " pointAt <ra> <dec> point at given coords\n"
+ " showRow [<url>] [<tblId>] <row> highlight specified row\n"
+ " selectRows [<url>] [<tblId>] <rows> select specified rows\n"
+ " bibcode <bibcode> load the bibcode\n"
+ "\n\n"
+ " Examples:\n\n"
+ " 1) Load a VOTable to Topcat:\n\n"
+ " %% vosamp load /path/example.xml\n"
+ " %% vosamp load http://foo.edu/example.xml\n"
+ " %% vosamp load http://foo.edu/query?RA=0.0&DEC=0.0&SR=0.1\n"
+ "\n"
+ " 2) Send a command string to IRAF:\n"
+ "\n"
+ " %% vosamp -t iraf exec 'display dev$pix 1'\n"
+ "\n"
+ " 3) List all clients in a SAMP desktop session:\n"
+ "\n"
+ " %% vosamp list\n"
+ "\n"
+ " 4) Check whether a Hub is available from a script:\n"
+ "\n"
+ " set isHub = `vosamp access Hub`\n"
+ " if ($isHub == \"no\") then\n"
+ " echo \"No Hub available, quitting .....\"\n"
+ " exit 1\n"
+ " else\n"
+ " ....do something....\n"
+ " endif\n"
+ "\n"
+ );
+}
+
+
+
+/**
+ * Tests -- Task unit tests.
+ */
+static void
+Tests (char *input)
+{
+ Task *task = &self;
+
+ char *img = "http://iraf.noao.edu/votest/ypix.fits";
+ char *vot = "http://iraf.noao.edu/votest/usno-b.xml";
+ char *bin = "http://iraf.noao.edu/votest/usno-b.fits";
+
+
+ if (access (input, F_OK) != 0) {
+ fprintf (stderr, "Error: cannot open input file '%s'\n", input);
+ return;
+ }
+
+ vo_taskTest (task, "--help", NULL);
+
+ vo_taskTest (task, "load", input, NULL);
+ vo_taskTest (task, "load", img, NULL);
+ vo_taskTest (task, "loadImage", img, NULL);
+ vo_taskTest (task, "load", vot, NULL);
+ vo_taskTest (task, "loadVOTable", vot, NULL);
+ vo_taskTest (task, "load", bin, NULL);
+ vo_taskTest (task, "loadFITS", bin, NULL);
+
+ vo_taskTest (task, "access", "hub", NULL);
+ vo_taskTest (task, "list", NULL);
+ vo_taskTest (task, "load", input, NULL);
+
+ vo_taskTestReport (self);
+}
+
+
+/**
+ * VOS_DOTFILE -- Create a pathname to the .vosamp file indicating a
+ * running local proxy server.
+ */
+static char *
+vos_dotFile ()
+{
+ static char dotfile[SZ_FNAME];
+ static int initialized = 0;
+
+ if (! initialized) {
+ char *home = NULL;
+
+ if ((home = getenv ("HOME")) == NULL)
+ home = "./";
+ memset (dotfile, 0, SZ_FNAME);
+ sprintf (dotfile, "%s/.vosamp", home);
+ }
+ initialized++;
+
+ return (dotfile);
+}
+
+
+/**
+ * VOS_SAMPINIT -- Initialize the SAMP/Proxy interface connection.
+ */
+static int
+vos_sampInit (void)
+{
+ FILE *df;
+
+
+ /* If there's no Hub running, don't bother ....
+ */
+ if (!samp_hubRunning())
+ return (0);
+
+ /* Initialize the SAMP interface.
+ */
+ sampH = sampInit ("vosamp", "VOClient SAMP Task");
+/*
+ if (samp_hubActive (sampH) == 0) {
+ vosDebug ("sampInit failed to connect ....\n");
+ vos_sampShutdown ();
+ return (0);
+ }
+*/
+
+ /* Set alternative messaging pattern if requested. Valid values are
+ * 'synch', 'asynch' or 'notify'.
+ */
+ if (pattern) {
+ switch (tolower(pattern[0])) {
+ case 's': samp_setSyncMode (sampH); break; /* default */
+ case 'a': samp_setASyncMode (sampH); break;
+ case 'n': samp_setNotifyMode (sampH); break;
+ default:
+ if (verbose)
+ fprintf (stderr, "Warning: Invalid pattern '%s'\n", pattern);
+ }
+ } else {
+ /* Use Synchronous mode by default so we don't exit before receiving
+ * the reply. Otherwise, we could cause an error in the recipient.
+ */
+ samp_setSyncMode (sampH);
+ }
+
+ /* If we're not sending to a specific client, disable the name mapping
+ * to speed up the connection.
+ if (strncmp (to, "all", 3) == 0)
+ samp_setOpt (sampH, "mapClients", 0);
+ */
+
+ samp_Metadata (sampH, "author.name", "Mike Fitzpatrick, NOAO");
+ samp_Metadata (sampH, "author.email", "fitz@noao.edu");
+ samp_Metadata (sampH, "samp.description.html",
+ "http://iraf.noao.edu/voclient/vosamp.html");
+ samp_Metadata (sampH, "samp.icon.url",
+ "http://iraf.noao.edu/voclient/vao_icon.gif");
+
+ /* If we're in session mode, subscribe to all message types. The
+ * same handler is used to pass on the message to other clients in
+ * the session.
+ */
+ if (session)
+ samp_Subscribe (sampH, "*", vos_sessionHandler);
+
+ /* Register with the Hub and begin messaging.
+ */
+ sampStartup (sampH);
+
+
+ /* Write the dotfile.
+ */
+ if (!interact && (df = fopen (vos_dotFile(), "w+")) != (FILE *) NULL) {
+ fprintf (df, "%s %d %d %ld %s\n", vos_getLocalIP(), proxy_port,
+ (int) getpid(), (long) (time((time_t)0) + timeout),
+ (session ? session : "none"));
+ fclose (df);
+ }
+
+ return (sampH);
+}
+
+
+/**
+ * VOS_SAMPSHUTDOWN -- Shutdown the SAMP/Proxy interface connection.
+ */
+static void
+vos_sampShutdown (void)
+{
+ if (sampShutdown (sampH) < 0) /* clean up */
+ fprintf (stderr, "SAMP shutdown fails\n");
+ sampClose (sampH);
+}
+
+
+/**
+ * VOS_MSGHANDLER -- Incoming message handler.
+ */
+static void
+vos_msgHandler (char *sender, char *mtype, char *msg_id, int params)
+{
+ vosDebug ("in vos_msgHandler.....\n");
+ if (filt_sender && strcasecmp (filt_sender, sender))
+ return;
+
+ /* Either no filters were set, or the message is of the requested type,
+ * print the contents.
+ */
+ if (!quiet)
+ vos_printMessage (mtype, samp_id2app (sampH, sender), params);
+
+ if (!interact && !multiple) { /* Do a clean disconnect .... */
+ if (sampShutdown (sampH) < 0)
+ fprintf (stderr, "SAMP shutdown fails\n");
+ sampClose (sampH);
+ exit (0);
+ }
+}
+
+
+/**
+ * VOS_PRINTMESSAGE -- Print a received message to the stdout.
+ */
+static void
+vos_printMessage (char *mtype, char *sender, Map map)
+{
+ int i, npars = samp_getMapSize (map);
+ char *key = NULL;
+ Map smap;
+
+
+ if (verbose)
+ printf ("sender: '%s'\t", sender);
+ printf ("%s", mtype);
+
+ for (i=0; i < npars; i++) {
+ key = samp_getMapKey (map, i);
+ if (strncmp (key, "meta", 4) == 0 || strncmp (key, "sub", 3) == 0) {
+ smap = samp_getMapFromMap (map, key);
+ printf ("\n");
+ samp_printMap (key, smap);
+ } else
+ printf ("\t%s=%s", key, samp_getMapVal (map, i));
+ }
+
+ printf ("\n");
+}
+
+
+/**
+ * VOS_SESSIONHANDLER -- Generic session message-forwarding handler.
+ */
+
+#define MTYPE(s) (strcasecmp(mtype,s)==0)
+
+static void
+vos_sessionHandler (char *sender, char *mtype, char *msg_id, Map map)
+{
+ char sess_url[SZ_URL], sess_cmd[SZ_CMD], num[SZ_FNAME];
+ char *tid = NULL, *imid = NULL, *url = NULL, *sid = NULL;
+ char *name = NULL, *value = NULL, *cmd = NULL, *bibcode = NULL;
+ char *key = NULL, *val = NULL;
+ int i, row = 0, rows = 0, len, nelem;
+ float ra, dec;
+ Map meta, ids;
+
+
+ if (!mtype)
+ return;
+
+ memset (sess_url, 0, SZ_URL);
+ memset (sess_cmd, 0, SZ_CMD);
+
+ /*
+ vosDebug ("sender: '%s' mtype: '%s' id: '%s'\n", sender, mtype, msg_id);
+ */
+
+ /* Process the mtype.
+ */
+ if (MTYPE ("samp.app.ping")) {
+ ; /* FIXME -- no-op */
+
+ } else if (MTYPE ("samp.app.status")) {
+ ; /* FIXME -- no-op */
+
+ } else if (MTYPE ("table.load.fits")) {
+ tid = strdup (samp_getStringFromMap (map, "table-id"));
+ url = strdup (samp_getStringFromMap (map, "url"));
+ name = strdup (samp_getStringFromMap (map, "name"));
+
+ sprintf (sess_cmd, "loadFITS %s %s", vos_rewriteURL(url), tid);
+
+
+ } else if (MTYPE ("table.load.votable")) {
+ /* Get parameters from the message Map.
+ */
+ tid = strdup (samp_getStringFromMap (map, "table-id"));
+ url = strdup (samp_getStringFromMap (map, "url"));
+ name = strdup (samp_getStringFromMap (map, "name"));
+
+ sprintf (sess_cmd, "loadVOTable %s %s", vos_rewriteURL(url), tid);
+
+
+ } else if (MTYPE ("table.highlight.row")) {
+ tid = strdup (samp_getStringFromMap (map, "table-id"));
+ url = strdup (samp_getStringFromMap (map, "url"));
+ row = samp_getIntFromMap (map, "row");
+
+ sprintf (sess_cmd, "showRow %s %d", vos_rewriteURL(url), row);
+
+
+ } else if (MTYPE ("image.load.fits")) {
+ imid = strdup (samp_getStringFromMap (map, "image-id"));
+ url = strdup (samp_getStringFromMap (map, "url"));
+ name = strdup (samp_getStringFromMap (map, "name"));
+
+ sprintf (sess_cmd, "loadImage %s %s", vos_rewriteURL(url), imid);
+
+
+ } else if (MTYPE ("coord.pointAt.sky")) {
+ ra = samp_getFloatFromMap (map, "ra");
+ dec = samp_getFloatFromMap (map, "dec");
+
+ sprintf (sess_cmd, "pointAt %g %g", ra, dec);
+
+
+ } else if (MTYPE ("client.cmd.exec")) {
+ cmd = strdup (samp_getStringFromMap (map, "cmd"));
+
+ sprintf (sess_cmd, "exec %s", cmd);
+
+
+ } else if (MTYPE ("client.env.get")) { /** NYI **/
+ name = strdup (samp_getStringFromMap (map, "name"));
+
+
+ } else if (MTYPE ("client.env.set")) {
+ name = strdup (samp_getStringFromMap (map, "name"));
+ value = strdup (samp_getStringFromMap (map, "value"));
+
+ sprintf (sess_cmd, "setenv %s %s", name, value);
+
+
+ } else if (MTYPE ("client.param.get")) { /** NYI **/
+ name = strdup (samp_getStringFromMap (map, "name"));
+
+
+ } else if (MTYPE ("client.param.set")) {
+ name = strdup (samp_getStringFromMap (map, "name"));
+ value = strdup (samp_getStringFromMap (map, "value"));
+
+ sprintf (sess_cmd, "setparam %s %s", name, value);
+
+
+ } else if (MTYPE ("bibcode.load")) {
+ bibcode = strdup (samp_getStringFromMap (map, "bibcode"));
+
+ sprintf (sess_cmd, "bibcode %s", bibcode);
+
+
+ } else if (MTYPE ("table.select.rowList")) {
+ tid = strdup (samp_getStringFromMap (map, "table-id"));
+ url = strdup (samp_getStringFromMap (map, "url"));
+ rows = samp_getListFromMap (map, "row-list");
+
+ sprintf (sess_cmd, "selectRows %s %s ", vos_rewriteURL(url), tid);
+ len = samp_listLen (rows);
+ for (i=0; i < len; i++) {
+ sprintf (num, "%d%c", samp_getIntFromList(rows,i),
+ (i < (len - 1) ? ',' : ' '));
+ strcat (sess_cmd, num);
+ }
+
+
+ } else if (MTYPE ("spectrum.load.ssa-generic")) {
+ url = strdup (samp_getStringFromMap (map, "url"));
+ sid = strdup (samp_getStringFromMap (map, "spectrum-id"));
+ name = strdup (samp_getStringFromMap (map, "name"));
+ meta = samp_getMapFromMap (map, "meta");
+
+ sprintf (sess_cmd, "loadSpec %s %s %s",
+ vos_rewriteURL(url), (name ? name : " "), (sid ? sid : " "));
+
+
+ } else if (MTYPE ("voresource.loadlist.*")) { /* NYI */
+ name = strdup (samp_getStringFromMap (map, "name"));
+ ids = samp_getMapFromMap (map, "ids");
+
+ nelem = samp_getMapSize (ids);
+ for (i=0; i < nelem; i++) {
+ key = samp_getMapKey (ids, i);
+ val = samp_getMapVal (ids, i);
+
+ /* Forward the resources individually.
+ */
+ memset (sess_cmd, 0, SZ_CMD);
+ sprintf (sess_cmd, "loadResource %s", vos_rewriteURL(url));
+ vos_forwardCmd (sess_cmd);
+ }
+ goto clean_up;
+
+
+ } else if (MTYPE ("samp.hub.disconnect")) {
+ ; /* ignore hub ejections */
+ } else if (MTYPE ("samp.hub.event.subscriptions")) {
+ ; /* ignore client subscriptions */
+ } else if (MTYPE ("samp.hub.unregister") ||
+ MTYPE ("samp.hub.event.unregister")) {
+ ; /* ignore hub closures */
+
+ } else {
+ if (verbose && debug)
+ fprintf (stderr, "unknown mtype '%s'\n", mtype);
+ }
+
+
+ /* Forward the session command.
+ */
+ vos_forwardCmd (sess_cmd);
+
+ if (verbose && debug)
+ fprintf (stderr, "sessionHandler: cmdline = '%s'\n", sess_cmd);
+
+
+ /* Clean up.
+ */
+clean_up:
+ if (tid) free (tid);
+ if (url) free (url);
+ if (cmd) free (cmd);
+ if (sid) free (sid);
+ if (imid) free (imid);
+ if (name) free (name);
+ if (value) free (value);
+ if (bibcode) free (bibcode);
+}
+
+
+/**
+ * VOS_FORWARDCMD -- Forward a session command.
+ */
+static void
+vos_forwardCmd (char *sess_cmd)
+{
+ int ssock = session_sock, len, nwrite;
+
+ len = strlen (sess_cmd);
+ if (vos_sockWriteHdr (ssock, len, NULL, SAMP_CMD, SAMP_NOTIFY, to))
+ nwrite = vos_sockWrite (ssock, sess_cmd, len);
+}
+
+
+/**
+ * VOS_PROCCMD -- Process the command and its arguments.
+ */
+static void
+vos_procCmd (int sampH, char *to, char *cmd, char *args[], int numargs)
+{
+ int i, reslen = 0, stat = OK, ssock = session_sock;
+ char *result = NULL;
+ char buf[SZ_BUF];
+ char sess_cmd[SZ_BUF];
+
+
+ /* Print command help.
+ */
+ if (!use_ipc) {
+ if (strncmp (cmd, "?", 1) == 0) {
+ Usage ();
+ return;
+ }
+ if (strncmp (args[0], "?", 1) == 0) {
+ vos_cmdHelp (cmd);
+ return;
+ }
+ }
+
+
+ /********************************************
+ *** VOSAMP Custom Commands **
+ ********************************************/
+ memset (buf, 0, SZ_BUF);
+ memset (sess_cmd, 0, SZ_BUF);
+
+ if (MATCH ("status")) {
+ stat = (sampH >= 0);
+
+ } else if (MATCH ("handle")) {
+ int timeout = (vot_atoi (args[1]) == 0 ? 999999 : vot_atoi (args[1]));
+
+ if (verbose)
+ fprintf (stderr, "Waiting for '%s' ....\n", args[0]);
+ if (*args[1])
+ filt_sender = args[1];
+
+ samp_Subscribe (sampH, (filt_mtype = args[0]), vos_msgHandler);
+ samp_DeclareSubscriptions (sampH);
+ sleep (timeout);
+
+ } else if (MATCH ("snoop")) {
+ /* Subscribe to all message types and install the snoop handler.
+ * Sleep forever so the handler can print anything it receives.
+ */
+ multiple = 1;
+ samp_Subscribe (sampH, "*", vos_msgHandler);
+ samp_DeclareSubscriptions (sampH);
+ sleep (9999999);
+
+ } else if (MATCH ("send")) {
+ if (strcasecmp (to, "all")) /* no recipient, use broadcast */
+ samp_setASyncMode (sampH);
+ stat = samp_sendGeneric (sampH, to, args[0], &args[1]);
+
+ } else if (MATCH ("echo")) { /* ECHO */
+ if (!use_ipc) {
+ for (i=0; i < numargs; i++)
+ printf ("%s ", args[i]);
+ printf ("\n");
+ }
+
+ } else if (MATCH ("start")) { /* START */
+ if (!use_ipc)
+ printf ("Starting SAMP interface .....\n");
+ sampStartup (sampH);
+
+ } else if (MATCH ("stop")) { /* STOP */
+ if (!use_ipc)
+ printf ("Stopping SAMP interface .....\n");
+ sampShutdown (sampH);
+
+ } else if (MATCH ("help")) { /* HELP */
+ Usage ();
+
+ } else if (MATCH ("quit")) { /* QUIT */
+ if (sampShutdown (sampH) < 0) {
+ if (!use_ipc)
+ fprintf (stderr, "Shutdown fails\n");
+ }
+ sampClose (sampH);
+ unlink (vos_dotFile());
+ exit (0);
+
+ } else if (MATCH ("trace")) { /* TRACE */
+ xml_trace++;
+ if (xml_trace % 2)
+ setenv ("XMLRPC_TRACE_XML", "1", 1);
+ else
+ unsetenv ("XMLRPC_TRACE_XML");
+
+ } else if (MATCH ("listNodes")) { /* LIST NODES */
+ int type, mode, nbytes, len, nwrite;
+ char buf[SZ_BUF];
+
+ len = strlen ("list");
+ if (vos_sockWriteHdr (ssock, len, "list", SAMP_CMD, SAMP_NOTIFY, to)) {
+ nwrite = vos_sockWrite (ssock, "list", len);
+
+ memset (buf, 0, SZ_BUF);
+ if (vos_sockReadHdr (session_sock, &nbytes, NULL, &type, &mode))
+ reslen = vos_sockRead (session_sock, buf, nbytes);
+ result = strdup (buf);
+ }
+
+ } else if (MATCH ("listClients")) { /* LIST CLIENTS */
+ char *clist = NULL;
+
+ samp_mapClients (sampH);
+ clist = samp_getClients (sampH);
+ if (use_ipc) {
+ reslen = strlen (clist);
+ result = strdup (clist);
+ } else {
+ printf ("\nClients:\n%s\n", clist);
+ }
+
+
+
+ /********************************************
+ *** Hub Administrative Messages ***
+ ********************************************/
+ } else if (MATCH ("ping")) { /* samp.app.ping */
+ stat = samp_Ping (sampH, "Hub");
+
+
+
+ /********************************************
+ *** Client Administrative Messages ***
+ ********************************************/
+ } else if (MATCH ("ping")) { /* samp.app.ping */
+ stat = samp_Ping (sampH, to);
+
+ } else if (MATCH ("access")) { /* samp.app.ping */
+ stat = samp_Ping (sampH, (to=args[0]));
+ if (use_ipc) {
+ result = strdup ((stat < 0 ? "no" : "yes"));
+ reslen = strlen (result);
+ return_stat = (stat < 0 ? ERR : OK);
+ } else {
+ printf ("%s\n", (stat < 0 ? "no" : "yes"));
+ return_stat = (stat < 0 ? ERR : OK);
+ }
+
+
+
+ /********************************************
+ *** Table/Image Load Message Types ***
+ ********************************************/
+ /* image.load.fits */
+ } else if (MATCH ("loadImage")) {
+ if ((stat = vos_invalidArg (numargs, args, 1, 1))) {
+ return_stat = ERR;
+ goto cmd_exit_;
+ }
+ stat = samp_imageLoadFITS (sampH, to,
+ vos_toURL (args[0]), /* URL/file */
+ vos_optArg (args[1]), /* imgId */
+ vos_optArg (args[2])); /* name */
+ sprintf (sess_cmd, "loadImage %s %s",
+ vos_rewriteURL(vos_toURL (args[0])), vos_optArg (args[1]));
+ if (session && input_sock != session_sock)
+ vos_sendCmd (session_sock, sess_cmd);
+
+ } else if (MATCH ("loadFITS")) { /* table.load.fits */
+ if ((stat = vos_invalidArg (numargs, args, 1, 1))) {
+ return_stat = ERR;
+ goto cmd_exit_;
+ }
+ stat = samp_tableLoadFITS (sampH, to,
+ vos_toURL (args[0]), /* URL/file */
+ vos_optArg (args[1]), /* tblId */
+ vos_optArg (args[2])); /* name */
+ sprintf (sess_cmd, "loadFITS %s %s",
+ vos_rewriteURL(vos_toURL (args[0])), vos_optArg (args[1]));
+ if (session && input_sock != session_sock)
+ vos_sendCmd (session_sock, sess_cmd);
+
+
+ } else if (MATCH ("loadVOTable")) { /* table.load.votable */
+ if ((stat = vos_invalidArg (numargs, args, 1, 1))) {
+ return_stat = ERR;
+ goto cmd_exit_;
+ }
+ stat = samp_tableLoadVOTable (sampH, to,
+ vos_toURL (args[0]), /* URL/file */
+ vos_optArg (args[1]), /* tblId */
+ vos_optArg (args[2])); /* name */
+ sprintf (sess_cmd, "loadVOTable %s %s",
+ vos_rewriteURL(vos_toURL (args[0])), vos_optArg (args[1]));
+ if (session && input_sock != session_sock)
+ vos_sendCmd (session_sock, sess_cmd);
+
+ } else if (MATCH ("load")) {
+ char fname[SZ_LINE];
+ extern int vot_fileType();
+
+ memset (fname, 0, SZ_LINE);
+
+ if (strncmp (args[0], "http://", 7) == 0) {
+ strcpy (fname, "/tmp/vostmp"); /* temp download name */
+ if (access (fname, F_OK) == 0)
+ unlink (fname);
+ if (vos_getURL (args[0], fname) <= 0)
+ fprintf (stderr, "Error accessing url '%s'\n", args[0]);
+
+ } else if (strncmp (args[0], "file://", 7) == 0) {
+ strcpy (fname, &args[0][7]);
+ } else
+ strcpy (fname, args[0]);
+
+ if (access (fname, F_OK) == 0) {
+ switch (vot_fileType (fname)) {
+ case VOT_FITS:
+ stat = samp_imageLoadFITS (sampH, to,
+ vos_toURL (fname), /* URL/file */
+ vos_optArg (args[1]), /* imgId */
+ vos_optArg (args[2])); /* name */
+ sprintf (sess_cmd, "loadImage %s %s",
+ vos_rewriteURL(vos_toURL (fname)), vos_optArg (args[1]));
+ if (session && input_sock != session_sock)
+ vos_sendCmd (session_sock, sess_cmd);
+ break;
+ case VOT_VOTABLE:
+ stat = samp_tableLoadVOTable (sampH, to,
+ vos_toURL (fname), /* URL/file */
+ vos_optArg (args[1]), /* tblId */
+ vos_optArg (args[2])); /* name */
+ sprintf (sess_cmd, "loadVOTable %s %s",
+ vos_rewriteURL(vos_toURL (fname)), vos_optArg (args[1]));
+ if (session && input_sock != session_sock)
+ vos_sendCmd (session_sock, sess_cmd);
+ break;
+ case VOT_FITS_SPEC:
+ break;
+ case VOT_VOTABLE_SPEC:
+ break;
+ default:
+ if (!use_ipc)
+ fprintf (stderr,
+ "Error: cannot determine file type of '%s'.\n",
+ args[0]);
+ }
+ } else
+ fprintf (stderr, "Error: cannot access '%s'.\n", fname);
+
+
+
+ /********************************************
+ *** Resource Message Types ***
+ ********************************************/
+ } else if (MATCH ("loadResource")) { /* voresource.loadlist */
+ if ((stat = vos_invalidArg (numargs, args, 1, 1))) {
+ return_stat = ERR;
+ goto cmd_exit_;
+ }
+ /* NYI */
+
+
+
+ /********************************************
+ *** Utility Message Types ***
+ ********************************************/
+ } else if (MATCH ("showRow")) { /* table.highlight.row */
+ /* showRow <url> <row> [<id>] */
+ stat = samp_tableHighlightRow (sampH, to,
+ vos_optArg (args[2]), /* table-id */
+ vos_toURL (args[0]), /* URL/file */
+ vot_atoi(args[1])); /* row */
+
+ } else if (MATCH ("selectRows")) { /* table.select.rowList */
+ int nrows = 0;
+ int *rows = vos_toIntArray (args[2], &nrows);
+
+ stat = samp_tableSelectRowList (sampH, to,
+ vos_optArg (args[0]), /* table-id */
+ vos_toURL (args[1]), /* URL/file */
+ rows, /* rows[] */
+ nrows); /* row */
+
+ } else if (MATCH ("pointAt")) { /* coord.pointAt.sky */
+ stat = samp_coordPointAtSky (sampH, to,
+ vot_atof (args[0]), /* RA */
+ vot_atof (args[1])); /* Dec */
+
+
+ /********************************************
+ *** Spectrum Load Message Types ***
+ ********************************************/
+ } else if (MATCH ("loadSpec")) { /* spectrum.load.ssa-generic */
+ /* FIXME -- meta map not implemented */
+ stat = samp_specLoadSSAGeneric (sampH, to,
+ vos_toURL (args[0]), /* URL */
+ 0, /* Map meta */ /* NYI */
+ vos_optArg (args[2]), /* spectrumId */
+ vos_optArg (args[3])); /* name */
+
+
+ /********************************************
+ *** Bibcode Message Types ***
+ ********************************************/
+ } else if (MATCH ("bibcode")) { /* bibcode.load */
+ stat = samp_bibLoad (sampH, to, args[1]);
+
+
+ /********************************************
+ *** VO/IRAF Message Types ***
+ ********************************************/
+ } else if (MATCH ("exec")) { /* client.cmd.exec */
+ samp_cmdExec (sampH, to, args[0]);
+
+ } else if (MATCH ("getenv")) { /* client.env.get */
+ char *v = samp_envGet (sampH, to,
+ args[0]); /* name */
+ if (use_ipc) {
+ reslen = strlen (v);
+ result = strdup (v);
+ } else
+ printf ("%s\n", v);
+ if (v) free ((void *) v);
+
+ } else if (MATCH ("setenv")) { /* client.env.set */
+ stat = samp_envSet (sampH, to,
+ args[0], /* name */
+ args[1]); /* value */
+
+ } else if (MATCH ("getparam")) { /* client.param.get */
+ char *v = samp_paramGet (sampH, to,
+ args[0]); /* name */
+ if (use_ipc) {
+ reslen = strlen (v);
+ result = strdup (v);
+ } else
+ printf ("%s\n", v);
+ if (v) free ((void *) v);
+
+ } else if (MATCH ("setparam")) { /* client.param.set */
+ stat = samp_paramSet (sampH, to,
+ args[0], /* name */
+ args[1]); /* value */
+
+
+ /********************************************
+ *** Unknown Command ***
+ ********************************************/
+ } else {
+ if (use_ipc) {
+ memset (buf, 0, SZ_BUF);
+ sprintf (buf, "Error: unknown command '%s'\n", cmd);
+ result = strdup (buf);
+ reslen = strlen (buf);
+ } else
+ fprintf (stderr, "Error: unknown command '%s'\n", cmd);
+ }
+
+
+ if (!quiet) {
+ if (!reslen) {
+ result = strdup ((stat < 0 ? "Error" : "OK"));
+ reslen = strlen (result);
+ return_stat = (stat < 0 ? ERR : OK);
+ }
+ }
+ vosDebug ("procCmd: reslen=%d result='%s'\n", reslen, result);
+
+
+ /* Return result to the remote caller.
+ */
+cmd_exit_:
+ if (ipc_sock > 0) {
+ int nwrite;
+ short slen = reslen;
+
+ if (vos_sockWrite (ipc_sock, &slen, sizeof (short)))
+ nwrite = vos_sockWrite (ipc_sock, result, slen);
+ }
+
+ if (result) free (result);
+}
+
+
+/**
+ * VOS_INVALIDARG -- Check arguments for validity.
+ */
+static int
+vos_invalidArg (int argc, char *argv[], int nargs, int exist)
+{
+ int stat = 0;
+
+ /* See if the number of args we have is less than what we require.
+ */
+ if (argc < nargs) {
+ fprintf (stderr, "Error: invalid number of args for command '%s'\n",
+ cmd);
+ return ((stat = -1));
+ }
+
+ /* See whether we require the existance of the first argument. If this
+ * is a local file it must exist, assume URLs are valid.
+ */
+ if (exist) {
+ if (!argv[0] || !argv[0][0])
+ return ((stat = -1));
+ if (strncmp ("http", argv[0], 4) && access (argv[0], R_OK)) {
+ fprintf (stderr, "Error: cannot access file '%s'\n", args[0]);
+ return ((stat = -1));
+ }
+ }
+
+ return (stat);
+}
+
+
+/**
+ * VOS_CMDHELP -- Print a command help summary for interactive mode.
+ */
+static void
+vos_cmdHelp (char *cmd)
+{
+ if (MATCH ("status")) {
+ printf ("status\n");
+ } else if (MATCH ("handle")) {
+ ;
+ } else if (MATCH ("snoop")) {
+ printf ("snoop\n");
+ } else if (MATCH ("send")) {
+ ;
+ } else if (MATCH ("start")) {
+ printf ("start\n");
+ } else if (MATCH ("stop")) {
+ printf ("stop\n");
+ } else if (MATCH ("echo")) {
+ printf ("echo <text_string>\n");
+ } else if (MATCH ("help")) {
+ printf ("help <cmd>\n");
+ } else if (MATCH ("quit")) {
+ printf ("quit\n");
+ } else if (MATCH ("trace")) {
+ printf ("trace\n");
+ } else if (MATCH ("listClients")) {
+ printf ("listClients\n");
+ } else if (MATCH ("ping")) {
+ printf ("ping <appName>\n");
+ } else if (MATCH ("access")) {
+ printf ("access <appName>\n");
+
+ } else if (MATCH ("loadImage") || MATCH ("loadFITS")) {
+ printf ("loadImage <file | URL> [<table-id> [<name>]]\n");
+ } else if (MATCH ("loadVOTable")) {
+ printf ("loadVOTable <file | URL> [<table-id> [<name>]]\n");
+ } else if (MATCH ("loadResource")) {
+ ;
+ } else if (MATCH ("showRow")) {
+ printf ("showRow <table-id> <file | URL> <row>\n");
+ } else if (MATCH ("selectRows")) {
+ printf ("selectRows <table-id> <file | URL> <rowList>\n");
+
+ } else if (MATCH ("pointAt")) {
+ printf ("pointAt <ra> <dec>\t# coords in decimal degrees\n");
+
+ } else if (MATCH ("loadSpec")) {
+ printf ("loadSpec <URL> <meta> [<spectrum-id> <name>]\n");
+ } else if (MATCH ("bibcode")) {
+ printf ("bibcode <bibcode>\n");
+
+ } else if (MATCH ("exec")) {
+ printf ("exec <cmd_str>\n");
+ } else if (MATCH ("getenv")) {
+ printf ("getenv <name>\n");
+ } else if (MATCH ("setenv")) {
+ printf ("setenv <name> <value>\n");
+ } else if (MATCH ("getparam")) {
+ printf ("getparam <name>\n");
+ } else if (MATCH ("setparam")) {
+ printf ("setparam <name> <value>\n");
+ }
+}
+
+
+/**
+ * VOSDEBUG -- Utility to print debug messages.
+ */
+static void
+vosDebug (char *format, ...)
+{
+ va_list argp;
+ char buf[1024];
+ extern char *vo_encodeString ();
+
+
+ if (!debug)
+ return;
+
+ /* Format the message.
+ */
+ memset (buf, 0, 1024);
+ va_start (argp, format);
+ vo_encodeString (buf, format, &argp);
+ va_end (argp);
+
+ if (buf[strlen(buf)-1] != '\n') /* ensure a newline */
+ strcat (buf, "\n");
+
+ fprintf (stderr, "[%d] %s", (int)getpid(), buf);
+}
+
+
+
+/**
+ * VOS_OPENSESSION -- Open a connection to the VOSAMP Session Manager.
+ *
+ * @brief Open a connection to the VOSAMP Session Manager.
+ * @fn int vos_openSession (char *host, int port, char *session_name)
+ *
+ * @param host session manager host
+ * @param port session manager connection port
+ * @param name session name
+ * @return fd to the session socket
+ */
+int
+vos_openSession (char *host, int port, char *session_name)
+{
+ int sock = 0, cb_sock = 0, cb_port = 0, nr, nw, len, ready = SESS_READY;
+ char cmd[SZ_LINE];
+
+
+ /* Open a socket to the connection port.
+ */
+ if ((sock = vos_openClientSocket (host, port, 1)) <= 0)
+ return (1);
+
+ /* Read the callback port number.
+ */
+ if ((nr = vos_sockRead (sock, &cb_port, sizeof (short))) != sizeof (short))
+ return (1);
+
+ /* Close the socket to the connection port.
+ */
+ close (sock);
+
+ /* Open a new connection to the callback port.
+ */
+ if ((cb_sock = vos_openClientSocket (host, cb_port, 1)) <= 0)
+ return (1);
+
+ /* Write the 'ready' code to the callback prot.
+ */
+ nw = vos_sockWrite (cb_sock, &ready, sizeof (short));
+
+
+ /* Send the 'connect' message to connect to the named session. The
+ * server will either create a new session or have us join an existing
+ * session created by another node.
+ */
+ memset (cmd, 0, SZ_LINE);
+ sprintf (cmd, "connect %s", session_name);
+ len = strlen (cmd);
+ if (vos_sockWriteHdr (cb_sock, len, NULL, SAMP_CMD, SAMP_NOTIFY, "smgr"))
+ nw = vos_sockWrite (cb_sock, cmd, len);
+
+ /* Return 0 if we can connect, 1 on err, or the callback descriptor.
+ */
+ return (cb_sock);
+}
+
+
+/**
+ * VOS_CLOSESESSION -- Close the specified session connection.
+ *
+ * @brief Close the specified session connection.
+ * @fn int vos_closeSession (int sock)
+ *
+ * @param sock session socket fd
+ * @return 0 if cmd was sent, 1 otherwise
+ */
+int
+vos_closeSession (int sock)
+{
+ if (vos_sockWriteHdr (sock, 0, NULL, SAMP_QUIT, SAMP_NOTIFY, "smgr"))
+ return (1);
+ return (0);
+}
+
diff --git a/vendor/voclient/voapps/vosesame.c b/vendor/voclient/voapps/vosesame.c
new file mode 100644
index 00000000..47a9c733
--- /dev/null
+++ b/vendor/voclient/voapps/vosesame.c
@@ -0,0 +1,680 @@
+/**
+ * VOSESAME -- Call the Sesame name resolver service on the specified target.
+ *
+ * Usage: vosesame [-adehntsv] [<objfile> | <target> [<target> ...]]
+ *
+ * -a,--all print all information about the object
+ * -d,--decimal print position in decimal degrees (default)
+ * -e,--errors print position errors
+ * -n,--name print object name
+ * -s,--sex print position as sexagesimal coordinates
+ * -t,--type print object type
+ *
+ * INPUT PARAMETERS
+ * -f,--force force new query (i.e. no cache)
+ * -o,--output=<file> specify output file
+ * -p,--pos comma-separated input position
+ *
+ * OUTPUT PARAMETERS
+ * -h,--help print help summary
+ * -q,--quiet quiet (no) output
+ * -v,--verbose verbose output
+ * -A,--ascii ASCII output (i.e. space-delimited)
+ * -C,--comma comma-delimited output
+ * -F,--format format output
+ * -H,--header print header
+ * -T,--tab tab-delimited output
+ * -I,--init_cache initialize the resolver cache directory
+ *
+ * Output is printed as whitespace delimited values in the same order
+ * in which the arguments appear.
+ *
+ * M. Fitzpatrick, NOAO, June 2007
+ *
+ * @file vosesame.c
+ * @author Mike Fitzpatrick
+ * @date 6/23/07
+ * @returns 0 if no error, 1 if an error occurs
+ *
+ * @brief Call the Sesame name resolver service on the specified target.
+ */
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <getopt.h>
+#include "VOClient.h"
+#include "voApps.h"
+
+
+/* Print field flags */
+#define F_ALL 0001 /* Print all fields */
+#define F_DEC 0002 /* Print decimal position */
+#define F_ERR 0004 /* Print position errors */
+#define F_NAM 0010 /* Print object name */
+#define F_TYP 0020 /* Print object type */
+#define F_SEX 0040 /* Print sexagesimal position */
+
+#define MAX_FLAGS 16
+#define SZ_TARGET 64 /* size of target name */
+
+
+static int flags[MAX_FLAGS]; /* argv flags array */
+static int nflags = 0; /* number of flags */
+static int ntargets = 0; /* number of input targets */
+static int all_flags = 0; /* print all fields? */
+
+static int format = TRUE; /* format the output? */
+static int header = FALSE; /* print a header? */
+static int invert = FALSE; /* invert to print non-matches */
+static int debug = FALSE; /* std debug flag */
+static int verbose = FALSE; /* std verbose flag */
+static int quiet = FALSE; /* suppress output flag */
+static int user_pos = TRUE; /* using user position? */
+static int status = OK; /* return status */
+
+static char delim = ' '; /* output table delimiter */
+static char *output = (char *) NULL;
+
+static char *u_ra = (char *) NULL, /* user-defined position */
+ *u_dec = (char *) NULL,
+ *sep = (char *) NULL;
+
+static FILE *out;
+
+
+/* For getopt_long() option parsing.
+*/
+/* Task specific option declarations.
+ */
+int vosesame (int argc, char **argv, size_t *len, void **result);
+
+static Task self = { "vosesame", vosesame, 0, 0, 0 };
+
+static char *opts = "rh%aACdefFHno:p:qsTtvI";
+static struct option long_opts[] = {
+ { "return", 0, 0, 'r' }, /* task option */
+ { "help", 2, 0, 'h' }, /* required */
+ { "test", 2, 0, '%' }, /* required */
+
+ { "all", 2, 0, 'a' }, /* print all info about an object */
+ { "ascii", 2, 0, 'A' }, /* ASCII (space-del) output */
+ { "comma", 2, 0, 'C' }, /* comma-delimited output */
+ { "decimal", 2, 0, 'd' }, /* print pos in dec. deg (def) */
+ { "errors", 2, 0, 'e' }, /* print position errors */
+ { "force", 2, 0, 'f' }, /* force new query (i.e. no cache) */
+ { "format", 2, 0, 'F' }, /* format the output */
+ { "header", 2, 0, 'H' }, /* print output header */
+ { "name", 2, 0, 'n' }, /* print object name */
+ { "output", 1, 0, 'o' }, /* specify output file */
+ { "pos", 1, 0, 'p' }, /* comma-separated input position */
+ { "quiet", 2, 0, 'q' }, /* quiet (i.e. no) output */
+ { "sex", 2, 0, 's' }, /* print sexagesimal coordinates */
+ { "tab", 2, 0, 'T' }, /* tab-delimited output */
+ { "type", 2, 0, 't' }, /* print object type */
+ { "verbose", 2, 0, 'v' }, /* verbose output */
+ { "init_cache",2, 0, 'I' }, /* init resolver cache */
+ { NULL, 0, 0, 0 }
+};
+
+static void Usage (void);
+static void Tests (char *input);
+
+
+extern int isDecimal(), isSexagesimal();
+extern float sexa();
+extern char *toSexa();
+extern double vot_atof (char *v);
+
+static int process_target (char *target);
+static int print_result (char *target, Sesame sr);
+static void print_header (void);
+static void procUserCoord (char *u_ra, char *u_dec);
+
+
+/**
+ * Application entry point.
+ */
+int
+vosesame (int argc, char *argv[], size_t *reslen, void **result)
+{
+ char **pargv, optval[SZ_FNAME];
+ register int ch=0, arg_index=1, narg=0;
+ int pos=0;
+
+
+ /* Process command line arguments and initialize.
+ */
+ nflags = 0;
+ out = stdout;
+ *reslen = 0;
+ *result = NULL;
+ memset (flags, 0, MAX_FLAGS);
+
+ pargv = vo_paramInit (argc, argv, opts, long_opts);
+ while ((ch = vo_paramNext (opts,long_opts,argc,pargv,optval,&pos)) != 0) {
+ if (ch > 0) {
+ switch (ch) {
+ case '%': Tests (optval); return (self.nfail);
+ case 'h': Usage(); return (OK);
+ case 'v': verbose++; quiet=0; break;
+ case 'q': quiet++; verbose=0; break;
+
+ case 'a': all_flags++; break;
+ case 'i': invert++; break;
+ case 'd': flags[nflags++] = F_DEC; break;
+ case 'e': flags[nflags++] = F_ERR; break;
+ case 'n': flags[nflags++] = F_NAM; break;
+ case 's': flags[nflags++] = F_SEX; break;
+ case 't': flags[nflags++] = F_TYP; break;
+
+ case 'p':
+ /* Check for a comma-separate position, break it up
+ ** if necessary.
+ */
+ user_pos++;
+ if ((sep = (char *) strchr (optval, (int)','))) {
+ *sep = '\0';
+ u_dec = strdup (++sep);
+ u_ra = strdup (optval);
+ }
+ if (debug) fprintf (stderr, "ra='%s' dec='%s'\n", u_ra,u_dec);
+ if (u_ra == NULL || u_dec == NULL) {
+ fprintf (stderr, "ERROR: Invalid '-p' syntax\n");
+ return (ERR);
+ }
+
+ /* Process a 'fake record' based on the position given.
+ ** Note this is done using the other options given up to
+ ** this point.
+ */
+ procUserCoord (u_ra, u_dec);
+ break;
+
+ case 'f':
+ if (voc_initVOClient("runid=voc.vosesame,use_cache=no") != OK) {
+ fprintf (stderr, "ERROR: cannot open VOClient\n");
+ return (ERR);
+ }
+ break;
+
+ case 'o':
+ output = strdup (optval);
+ if ((out = fopen (output, "w+")) == (FILE *)NULL) {
+ fprintf (stderr, "Cannot open file '%s'\n", output);
+ return (ERR);
+ }
+ break;
+
+ case 'A': delim = ' '; break;
+ case 'C': delim = ',', format = 0; break;
+ case 'F': format++; break;
+ case 'H': header++; break;
+ case 'T': delim = '\t', format = 0; break;
+
+ case 'I': /* FIXME */
+ system ("/bin/rm -f ~/.voclient/cache/sesame/*");
+ exit (0);;
+ }
+
+ } else if (ch == PARG_ERR) {
+ return (ERR);
+
+ } else {
+ /* Arguments without a leading '-' are assumed to be either
+ ** target names or @-files. We let the processing routine
+ ** figure out how to handle it.
+ */
+ if ((status = process_target (optval)) != OK) {
+ if (!quiet) {
+ fprintf (stderr, "Warning: Cannot resolve target '%s'\n",
+ optval);
+ }
+ }
+ narg++;
+ }
+ arg_index++;
+
+ /* Final error check for argument overflow -- should never happen.
+ if (arg_index > argc)
+ break;
+ */
+ if (narg > MAX_FLAGS) {
+ fprintf (stderr, "ERROR: Too many arguments specified\n");
+ return (1);
+ }
+ }
+
+
+ /* Process the arguments from the standard input.
+ */
+ if (!ntargets) {
+ char *name = calloc (1, SZ_FNAME);
+
+ while (fgets (name, SZ_FNAME, stdin)) {
+ name[strlen(name)-1] = '\0'; /* kill newline */
+ if ((status += process_target (name)) != OK) {
+ if (!quiet) {
+ fprintf (stderr,
+ "Warning: cannot resolve target/access file '%s'\n",
+ name);
+ }
+ } else
+ ntargets++;
+ }
+ free (name);
+ }
+
+ if (!ntargets)
+ fprintf (stderr, "Warning: No target name specified.\n");
+
+ if (u_ra) free ((void *) u_ra);
+ if (u_dec) free ((void *) u_dec);
+ if (output) free ((void *) output);
+
+ if (out != stdout)
+ fclose (out);
+
+ return ( status );
+}
+
+
+/**
+ * USAGE -- Print task help summary.
+ */
+static void
+Usage (void)
+{
+ printf ("\n\
+ Usage: sesame [-adehntsv] [<objfile> | <target> [<target> ...]]\n\
+ \n\
+ -a,--all print all information about the object\n\
+ -d,--decimal print position in decimal degrees (default)\n\
+ -e,--errors print position errors\n\
+ -n,--name print object name\n\
+ -s,--sex print position as sexagesimal coordinates\n\
+ -t,--type print object type\n\
+ \n\
+ INPUT PARAMETERS\n\
+ -f,--force force new query (i.e. no cache)\n\
+ -o,--output=<file> specify output file\n\
+ -p,--pos comma-separated input position\n\
+ \n\
+ OUTPUT PARAMETERS\n\
+ -h,--help print help summary\n\
+ -q,--quiet quiet (no) output\n\
+ -v,--verbose verbose output\n\
+ -A,--ascii ASCII output (i.e. space-delimited)\n\
+ -C,--comma comma-delimited output\n\
+ -F,--format format output\n\
+ -H,--header print header\n\
+ -T,--tab tab-delimited output\n\
+ \n\
+ Output is printed as whitespace delimited values in the same order\n\
+ in which the arguments appear.\n\
+ \n\n");
+
+ printf ("\n\
+ Examples:\n ---------\n\n\
+ \n\
+ 1) Print the coordinates of NGC4456 decimal degrees\n\
+ \n\
+ %% vosesame ngc4456\n\
+ 186.968458 -30.097514\n\
+ \n\
+ 2) Print the sexagesimal coordinates of multiple objects\n\
+ include the type:\n\
+ \n\
+ %% vosesame -st m31 m51 m99\n\
+ 00:42:44.32 +41:16:07.5 LIN\n\
+ 13:29:52.69 +47:11:42.9 Sy2\n\
+ 12:18:49.62 +14:24:59.3 H2G\n\
+ \n\
+ 3) Print the decimal coordinates of those same objects listed\n\
+ in the file 'myobjs.txt', output as CSV, include a header,\n\
+ and print the id, coords, and type:\n\
+ \n\
+ %% vosesame -CHndt myobjs.txt\n\
+ #Name,DRA,DDEC,Type,\n\
+ m31,10.684708,41.268750,LIN\n\
+ m51,202.469575,47.195258,Sy2\n\
+ m99,184.706771,14.416489,H2G\n\
+ : : : :\n\
+ \n\
+ 4) Print the sexagesimal and decimal values for multiple user coords:\n\
+ \n\
+ %% vosesame -sd -p 12:30:0.0,-45:00:0.0 -p 127.5,2.05\n\
+ 12:30:00.0 -45:00:00.0 12.500000 -45.000000\n\
+ 12:30:00.0 02:03:00.0 187.500000 2.050000\n\
+ \n\
+ ");
+
+ printf ("\n\n");
+}
+
+
+/**
+ * Tests -- Task unit tests.
+ */
+static void
+Tests (char *input)
+{
+ Task *task = &self;
+
+ vo_taskTest (task, "--help", NULL);
+
+ vo_taskTestFile ("m31\nm51\nm99\n", "objs.txt");
+
+ vo_taskTest (task, "ngc4456", NULL); // Ex 1
+ vo_taskTest (task, "-s", "ngc4456", NULL); // Ex 2
+ vo_taskTest (task, "-st", "m31", "m51", "m99", NULL); // Ex 3
+ vo_taskTest (task, "-CHndt", "objs.txt", NULL); // Ex 4
+ vo_taskTest (task, "-sd", "-p", "12:30:00.0,-45:00:00.0",
+ "-p", "187.5,2.05", NULL); // Ex 5
+
+ if (access ("objs.txt", F_OK) == 0) unlink ("objs.txt");
+
+ vo_taskTestReport (self);
+}
+
+
+
+
+/************************************************************************
+** PROCUSERCOORD -- Process a user-specified coordinate. Generate a
+** fake resolution record and output the requested values.
+*/
+static void
+procUserCoord (char *ra, char *dec)
+{
+ register int i;
+ char *fmt, sp;
+ char s_ra[SZ_FNAME], s_dec[SZ_FNAME], scoords[SZ_FNAME];
+ double dra = 0.0, ddec = 0.0;
+
+
+ memset (s_ra, 0, SZ_FNAME); /* initialize */
+ memset (s_dec, 0, SZ_FNAME);
+ memset (scoords, 0, SZ_FNAME);
+
+ if (isDecimal (u_ra)) {
+ dra = vot_atof (u_ra);
+ sprintf (s_ra, "%s", toSexa (dra / 15.0));
+ } else if (isSexagesimal (u_ra)) {
+ dra = sexa (u_ra);
+ strcpy (s_ra, u_ra);
+ } else {
+ fprintf (stderr, "Error in RA specification: '%s'\n", u_ra);
+ return;
+ }
+
+ if (isDecimal (u_dec)) {
+ ddec = vot_atof (u_dec);
+ sprintf (s_dec, "%s", toSexa (ddec));
+ } else if (isSexagesimal (u_dec)) {
+ ddec = sexa (u_dec);
+ strcpy (s_dec, u_dec);
+ } else {
+ fprintf (stderr, "Error in Dec specification: '%s'\n", u_dec);
+ return;
+ }
+
+ sprintf (scoords, "%s %s", s_ra, s_dec);
+
+ /* Set the default output if we got no commandline flags so far.
+ */
+ ntargets++;
+ if (nflags == 0)
+ flags[nflags++] = F_DEC;
+
+
+ /* Print the output in the order specified by the flags. The exception
+ ** is the '-a' flag to print all information we have, but we do so in a
+ ** fixed format
+ */
+ if (all_flags) {
+ if (format)
+ fmt = "%12.12s%c%23.23s%c%9.5f%c%9.5f%c0.0%c0.0%c%s\n";
+ else
+ fmt = "%s%c%s%c%f%c%f%c0.0%c0.0%c%s\n";
+
+ fprintf (out, fmt, "UserCoord", delim, scoords, delim,
+ dra, delim, ddec, delim, delim, delim, "Unknown");
+
+ } else {
+ for (i=0; i < nflags; i++) {
+ sp = (i < (nflags - 1) ? delim : (char) 0);
+ switch (flags[i]) {
+ case F_DEC:
+ fprintf (out, "%f%c%f", (float)dra, delim, (float)ddec);
+ break;
+ case F_ERR:
+ fprintf (out, "0.0%c0.0", delim);
+ break;
+ case F_NAM:
+ fprintf (out, "UserCoord");
+ break;
+ case F_TYP:
+ fprintf (out, "Unknown");
+ break;
+ case F_SEX:
+ fprintf (out, "%s", scoords);
+ break;
+ }
+ if (sp)
+ fprintf (out, "%c", sp);
+ }
+ fprintf (out, "\n");
+ }
+}
+
+
+/************************************************************************
+** PROCESS_TARGET -- Process a target name.
+*/
+static int
+process_target (char *target)
+{
+ int status;
+ char name[SZ_FNAME];
+ extern char *vo_urlEncode();
+
+
+ /* Do some error checking before we move on.
+ */
+ if (target == (char *)NULL) {
+ fprintf (stderr, "ERROR: No target name or file specified.\n");
+ return (ERR);
+ }
+
+ /* Set the default output if we got no commandline flags so far.
+ */
+ ntargets++;
+ if (nflags == 0)
+ flags[nflags++] = F_DEC;
+
+ /* Now call the Resolver Service and summarize the results.
+ */
+ if (target[0] == '@' || access (target, R_OK) == 0) {
+ char *fname = (target[0] == '@' ? &target[1] : &target[0]);
+ FILE *fd;
+
+
+ /* Open the @-file and process the contents. We assume there is
+ ** one target per line in the file, a target may contain spaces.
+ */
+ if (access (fname, R_OK) != OK) {
+ fprintf (stderr, "Cannot access target file '%s'\n", fname);
+ return (ERR);
+ } else {
+ if ((fd = fopen (fname, "r")) == (FILE *)NULL) {
+ fprintf (stderr, "Cannot open target file '%s'\n", fname);
+ return (ERR);
+ }
+ }
+
+ while (fgets (name, SZ_FNAME, fd)) {
+ name[strlen(name)-1] = '\0'; /* kill newline */
+ status = print_result (name, voc_nameResolver (vo_urlEncode(name)));
+ }
+ fclose (fd); /* close the file and clean up */
+
+ } else {
+ /* Print the result for a single resolved target.
+ */
+ status = print_result (target, voc_nameResolver (vo_urlEncode(target)));
+ }
+
+ return (status);
+}
+
+
+/************************************************************************
+** PRINT_RESULT -- Print the result table in the requested format.
+*/
+static int
+print_result (char *target, Sesame sr)
+{
+ register int i, found;
+ char *type = NULL, *ip, *pos, sp;
+ double ra, dec, Era, Edec;
+
+
+ if (sr == 0) /* check for no match found */
+ return (ERR);
+
+ /* Fix the target name so spaces become underscores.
+ */
+ for (ip=target; *ip; ip++) {
+ if (isspace (*ip) || *ip == '+')
+ *ip = ' ';
+ }
+
+ /* First time through, check that the formatting makes sense and print
+ ** the header if requested.
+ */
+ if (delim != ' ')
+ format = 0;
+ if (header && !invert)
+ print_header ();
+
+
+ /* Get the information for the object.
+ */
+ pos = voc_resolverPos(sr);
+ if (delim != ' ' && ip) {
+ for (ip=pos; *ip; ip++)
+ *ip = (isspace(*ip) ? delim : *ip);
+ }
+ ra = voc_resolverRA(sr);
+ dec = voc_resolverDEC(sr);
+ Era = voc_resolverRAErr(sr);
+ Edec = voc_resolverDECErr(sr);
+ type = voc_resolverOtype(sr);
+ pos = voc_resolverPos(sr);
+
+ found = 1;
+ if (ra == 0.0 && dec == 0.0 && Era == 0.0 && Edec == 0.0)
+ found = 0;
+
+
+ /* Return if we didn't get any results.
+ */
+ if (!invert && !found)
+ return (ERR);
+
+ /* Print the output in the order specified by the flags. The exception
+ ** is the '-a' flag to print all information we have, but we do so in a
+ ** fixed format
+ */
+ if (all_flags) {
+ char *fmt;
+
+
+ if (format)
+ fmt = "%12.12s%c%23.23s%c%9.5f%c%9.5f%c%6.1f%c%6.1f%c%s\n";
+ else
+ fmt = "%s%c%s%c%f%c%f%c%f%c%f%c%s\n";
+
+ if (!invert || (!found && invert)) {
+ fprintf (out, fmt, target, delim, pos, delim,
+ ra, delim, dec, delim,
+ Era, delim, Edec, delim,
+ type);
+ }
+
+ } else if ((found && !invert) || (!found && invert)) {
+ for (i=0; i < nflags; i++) {
+ sp = (i < (nflags - 1) ? delim : (char) 0);
+ switch (flags[i]) {
+ case F_DEC:
+ fprintf (out, "%f%c%f", ra, delim, dec);
+ break;
+ case F_ERR:
+ fprintf (out, "%f%c%f", Era, delim, Edec);
+ break;
+ case F_NAM:
+ fprintf (out, "%s", target);
+ break;
+ case F_TYP:
+ fprintf (out, "%s", (type ? type : "Unknown"));
+ break;
+ case F_SEX:
+ for (ip=pos; *ip; ip++) {
+ if (isspace (*ip))
+ *ip = delim;
+ }
+ fprintf (out, "%s", pos);
+ break;
+ }
+ if (sp)
+ fprintf (out, "%c", sp);
+ }
+ fprintf (out, "\n");
+ }
+
+
+ return (OK);
+}
+
+
+/************************************************************************
+** PRINT_HEADER -- Put a header on the table.
+*/
+static void
+print_header ()
+{
+ register int i;
+ char *fmt, sp;
+
+
+ if (all_flags) {
+ if (format)
+ fmt = "# %10.10s%c%-11.11s%c%-10.10s%c%-9.9s%c%-9.9s%c%-6.6s%c%-6.6s%c%s\n";
+ else
+ fmt = "# %s%c%s%c%s%c%s%c%s%c%s%c%s%c%s\n";
+
+ fprintf (out, fmt,
+ "Name", delim,
+ (format ? " RA" : "RA"), delim,
+ (format ? " DEC" : "DEC"), delim,
+ (format ? " DRA" : "DRA"), delim,
+ (format ? " DDEC" : "DDEC"), delim,
+ "RAerr", delim, "DECerr", delim,
+ "Type", delim);
+ } else {
+ fprintf (out, "#");
+ for (i=0; i < nflags; i++) {
+ sp = (((nflags-i) > 1) || nflags >= 1 ? delim : (char) 0);
+ switch (flags[i]) {
+ case F_DEC: fprintf (out, "DRA%cDDEC%c", sp, sp); break;
+ case F_ERR: fprintf (out, "RAerr%cDECerr%c", sp, sp); break;
+ case F_NAM: fprintf (out, "Name%c", sp); break;
+ case F_TYP: fprintf (out, "Type%c", sp); break;
+ case F_SEX: fprintf (out, "RA%cDEC%c", sp, sp); break;
+ }
+ }
+ fprintf (out, "\n");
+ }
+ header = 0; /* disable the header */
+}
diff --git a/vendor/voclient/voapps/vosession.c b/vendor/voclient/voapps/vosession.c
new file mode 100644
index 00000000..958f1787
--- /dev/null
+++ b/vendor/voclient/voapps/vosession.c
@@ -0,0 +1,1278 @@
+/**
+ * VOSESSION -- Inter-Desktop Session Manager for the VOSAMP task.
+ *
+ * Usage:
+ *
+ * vosession [<opts>]
+ *
+ * Where
+ * -%,--test run unit tests
+ * -h,--help print help summary
+ * -d,--debug debug output
+ * -v,--verbose verbose output
+ *
+ * Subcommands:
+ *
+ * status print Hub availability
+ * list list all registered clients
+ *
+ *
+ * @file vosession.c
+ * @author Mike Fitzpatrick
+ * @date 6/03/12
+ *
+ * @brief Session Manager for the VOSAMP task.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <ctype.h>
+#include <fcntl.h>
+#include <time.h>
+
+#include <netdb.h>
+#include <sys/errno.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+
+#include "samp.h" /* LIBSAMP interface */
+#include "voApps.h" /* voApps interface */
+
+
+#define SZ_BUF 128
+#define SZ_MTYPE 64
+#define SZ_HOSTIP 16
+
+#define MAX_ARGS 8 /* Max args in a command */
+#define MAX_SESSIONS 64 /* Max sessions to manage */
+#define MAX_PORTS 128 /* Max ports to manage */
+
+#define SESS_SELWIDTH 32 /* select fd width */
+#define SESS_TIMEOUT 3600 /* 1-hr timeout */
+#define SESS_DISCONNECT 309 /* Session Mgr command timeout */
+
+#define MATCH(s) (strcasecmp(cmd,s)==0)
+
+
+/* Connected session client.
+ */
+typedef struct {
+ int sock; /* socket descriptor */
+ int port; /* connection port */
+ char hostIP[SZ_HOSTIP]; /* host IP address */
+ char session[SZ_LINE]; /* session name */
+
+ void *back; /* linked-list back ptr */
+ void *next; /* linked-list next ptr */
+} Node, *NodeP;
+
+
+/* Session structure.
+ */
+typedef struct {
+ int nclients; /* number of clients */
+ Node *clients; /* clients in session */
+ char name[SZ_LINE]; /* session name */
+ char dataCache[SZ_LINE]; /* path to local data cache */
+
+ int ncmds; /* Number of commands sent */
+ int nfiles; /* Number of files uploaded */
+ long nbytes; /* Number of files uploaded */
+ time_t start_time; /* session start time */
+ time_t end_time; /* session end time */
+ time_t last_cmd; /* session last command */
+
+ void *back; /* linked-list back ptr */
+ void *next; /* linked-list next ptr */
+} Session, *SessionP;
+
+
+static int nSessions = 0;
+static Session* sessHead = NULL;
+static Session* sessTail = NULL;
+
+static int nClients = 0;
+static Node* clientHead = NULL;
+static Node* clientTail = NULL;
+
+static int verbose = FALSE; /* verbose output */
+static int debug = FALSE; /* verbose output */
+static int interactive = FALSE; /* interactive mode */
+static int xml_trace = FALSE; /* trace XML_RPC */
+static int timeout = SESS_TIMEOUT; /* select() doesn't timeout */
+static int svr_port = SESS_DEFPORT; /* connection port */
+static int selwidth = SESS_SELWIDTH;/* select() width */
+
+static int keep_alive = TRUE; /* lingering connection */
+static int svr_sock = FALSE; /* server socket descriptor */
+static int cb_sock = 0; /* callback socket descriptor */
+static int cb_port = 0; /* callback port number */
+static int socks[MAX_PORTS]; /* available sockets */
+
+
+static char *to = NULL; /* message recipient */
+static char *session = NULL; /* session name */
+static char cmd[SZ_CMD]; /* command name */
+static char *args[MAX_ARGS]; /* command args buffer */
+static char data_file[SZ_URL]; /* uploaded data file */
+
+
+static fd_set allset, rfds;
+static struct timeval tm;
+
+
+#define NOAO
+#ifdef NOAO
+static char *sessionData = "/iraf/web/vosession";
+static char *sessionUrlBase = "http://iraf.noao.edu/vosession";
+#else
+static char *sessionData = "/tmp/vosession";
+static char *sessionUrlBase = "file:///tmp/vosession";
+#endif
+static char logfile[SZ_LINE];
+static char statfile[SZ_LINE];
+
+
+
+/* Utility socket routines.
+ */
+extern int vos_openServerSocket (int port);
+extern int vos_openClientSocket (char *host, int port, int retry);
+extern int vos_sockRead (int fd, void *vptr, int nbytes);
+extern int vos_sockWrite (int fd, void *vptr, int nbytes);
+extern void vos_setNonBlock (int sock);
+extern int vos_sockWriteHdr (int fd, int len, char *name, int type,
+ int mode, char *to);
+extern int vos_sockReadHdr (int fd, int *len, char *name, int *type,
+ int *mode);
+extern int vos_recvFile (int sock, int size, char *fname);
+extern int vot_atoi (char *v);
+extern char *vo_logtime (void);
+extern char *vos_typeName (int type);
+
+
+
+/* Task specific option declarations.
+ */
+static char *opts = "h%:dikp:tuvS:T:";
+static struct option long_opts[] = {
+ { "help", 2, 0, 'h'}, /* required */
+ { "test", 1, 0, '%'}, /* required */
+ { "debug", 2, 0, 'd'}, /* debug */
+ { "interactive", 2, 0, 'i'}, /* interactive mode */
+ { "keepalive", 2, 0, 'k'}, /* keep connection */
+ { "port", 1, 0, 'p'}, /* server port */
+ { "trace", 2, 0, 't'}, /* trace cmds */
+ { "url", 2, 0, 'u'}, /* upload data base URL */
+ { "verbose", 2, 0, 'v'}, /* verbose */
+ { "session", 1, 0, 'S'}, /* session name */
+ { "timeout", 1, 0, 'T'}, /* connection timeout */
+ { NULL, 0, 0, 0 }
+};
+
+static void Usage (void);
+static void Tests (char *input);
+
+
+static int sess_procCmd (int sock, int msgtype, int nbytes, char *fname);
+static int sess_forwardMessage (int sender, char *msg);
+static int sess_connectClient (int sock);
+static int sess_disconnectClient (int sock);
+static int sess_disconnectAllClients (void);
+static int sess_joinSession (int sock, char *session_name);
+static int sess_leaveSession (int sock, char *session_name);
+
+static Session *sess_newSession (char *name);
+static int sess_freeSession (Session *s);
+
+static Node *sess_newNode (int sock);
+static int sess_freeNode (Node *n);
+
+static Session *sess_byName (char *name);
+static Session *sess_bySock (int sock);
+static Node *sess_clientBySock (int sock);
+
+#ifdef SESSION_EXTRAS
+static Session *sess_byPort (int port);
+static Node *sess_clientByPort (int port);
+static int sess_portToSock (int port);
+#endif
+
+static int sess_newPort (void);
+static int sess_freePort (int port);
+static int sess_sockToPort (int sock);
+
+static char *sess_tok (char *str, int tok);
+static void sess_rewriteCmd (char *line, char *session, char *fname);
+static void sessLog (char *formtat, ...);
+static void sess_writeStats (Session *session);
+static void sess_printSessions (void);
+static void sess_printClients (void);
+
+
+
+
+/****************************************************************************
+ * Program entry point.
+ ***************************************************************************/
+int
+main (int argc, char **argv)
+{
+ char **pargv, optval[SZ_FNAME], ch;
+ int i, rc, pos = 0;
+
+
+
+ /* Initialize.
+ */
+ memset (logfile, 0, SZ_LINE);
+ memset (data_file, 0, SZ_URL);
+ svr_port = SESS_DEFPORT;
+ for (i=0; i < MAX_ARGS; i++)
+ args[i] = calloc (1, SZ_LINE);
+
+
+ /* Parse the argument list.
+ */
+ pargv = vo_paramInit (argc, argv, opts, long_opts);
+ i = 0;
+ while ((ch = vo_paramNext (opts,long_opts,argc,pargv,optval,&pos)) != 0) {
+ i++;
+ if (ch > 0) {
+ switch (ch) {
+ case '%': Tests (optval); return (OK);
+ case 'h': Usage (); return (OK);
+
+ case 'd': debug++; break;
+ case 'v': verbose++; break;
+ case 'k': keep_alive=0; break;
+
+ case 'p': svr_port = vot_atoi(optval); break;
+ case 't': xml_trace=1; break;
+
+ case 'S': session = strdup (optval); break;
+ case 'T': timeout = vot_atoi (optval); break;
+
+ default:
+ fprintf (stderr, "Invalid option '%s'\n", optval);
+ return (1);
+ }
+
+ } else if (ch == PARG_ERR) {
+ return (ERR);
+
+ } else {
+ /* There is no other cmdline arg.
+ */
+ fprintf (stderr, "Invalid option '%s'\n", argv[i]);
+ return (1);
+ }
+ }
+
+
+ /* Sanity checks.
+ */
+ if (to == NULL)
+ to = strdup ("all");
+
+ /* Create the working session directory.
+ */
+ if (access (sessionData, F_OK) < 0) {
+ if (mkdir (sessionData, 0755) < 0) {
+ fprintf (stderr, "Cannot create session directory '%s'\n",
+ sessionData);
+ return (1);
+ }
+ }
+ sprintf (logfile, "%s/Log", sessionData);
+ sprintf (statfile, "%s/Stats", sessionData);
+
+
+ /* Initialize the socket interface and timeouts.
+ */
+ tm.tv_sec = timeout;
+ tm.tv_usec = 0;
+
+ if ((svr_sock = vos_openServerSocket (svr_port)) < 0) {
+ sessLog ("Cannot open server connection port %d\n", svr_port);
+ return (1);
+ } else if (debug) {
+ sessLog ("=======================================\n");
+ sessLog ("VOSession server started on port %4d\n", svr_port);
+ sessLog ("=======================================\n");
+ }
+
+ FD_ZERO (&allset);
+ FD_SET (svr_sock, &allset);
+ vos_setNonBlock (svr_sock);
+ if (interactive) {
+ FD_SET (fileno(stdin), &allset);
+ vos_setNonBlock (fileno(stdin));
+ }
+
+
+ /* Begin processing.
+ */
+ while (1) {
+ /* Initialize the input file descriptor set.
+ */
+ memcpy (&rfds, &allset, sizeof(allset));
+ rc = select (selwidth, &rfds, NULL, NULL, &tm);
+ if (rc == 0) {
+ time_t now = time (NULL);
+ Session *s = (Session *) NULL;
+ Node *n = (Node *) NULL;
+
+ /* Send a disconnect to all subscribed clients that have been
+ * inactive for more than SESS_DISCONNECT seconds (1-hr);
+ */
+ for (s=sessHead; s; s=s->next) {
+ if ((now - s->last_cmd) >= SESS_DISCONNECT) {
+ sessLog ("Session timeout for '%s'\n", s->name);
+ for (n=s->clients; n; n=n->next) {
+ sess_disconnectClient (n->sock);
+ sess_leaveSession (n->sock, s->name);
+ }
+ }
+ }
+ continue;
+ }
+
+ /* Loop over the active descriptors to process input.
+ */
+ for (i=0; i < selwidth+1; i++) {
+ if (FD_ISSET(i, &rfds)) {
+ if (i == svr_sock) {
+ /* Accept a new connection on the port.
+ */
+ if (sess_connectClient (svr_sock) != 0)
+ sessLog ("Cannot connect Client: ", strerror(errno));
+
+ } else {
+ /* Handle input from existing client-node connection.
+ */
+ int nread=0, nbytes=0, type=0, mode=0;
+ char fname[SZ_FNAME];
+
+ memset (fname, 0, SZ_FNAME);
+ if (debug > 1) sessLog ("Input on fd %d ....\n", i);
+
+ /* Read the length of the message and type.
+ */
+ nread = vos_sockReadHdr (i, &nbytes, fname, &type, &mode);
+ if (nread <= 0) {
+ /* Error on the socket or client closed connection.
+ */
+ sess_disconnectClient (i);
+ } else {
+ /* Read the command.
+ */
+ sess_procCmd (i, type, nbytes, fname);
+ }
+ } /* end is server socket */
+ } /* end FD_ISSET */
+ } /* end for */
+ } /* end while */
+
+
+ /* Clean up. Note, we should never actually get here....
+ */
+ if (to) free ((void *) to);
+ if (session) free ((void *) session);
+ sess_disconnectAllClients ();
+
+ /* Close the the connection socket.
+ */
+ if (svr_sock)
+ close (svr_sock);
+
+ return (OK);
+}
+
+
+
+
+/***************************************************************************
+**** Client Handling Procedures ****
+***************************************************************************/
+
+/**
+ * SESS_PROCCMD -- Process a command message.
+ */
+static int
+sess_procCmd (int sock, int msgtype, int nbytes, char *fname)
+{
+
+ int i, len, nsent, type=0, mode=0, nread=0;
+ char line[SZ_LINE], path[SZ_LINE];
+ Session *s = (Session *) sess_bySock (sock);
+
+
+ memset (line, 0, SZ_LINE); /* initialize */
+ memset (path, 0, SZ_LINE);
+
+ /* Read the command header. This will either be a SAMP_DATA
+ * message in which case we get a filename, or SAMP_CMD where
+ * we ignore the fname value and then read the command string.
+ */
+ switch (msgtype) {
+ case SAMP_DATA:
+ sprintf (path, "%s/%s", s->dataCache, fname);
+
+ if (vos_recvFile (sock, nbytes, path) != OK) {
+ if (debug)
+ sessLog ("Error receiving file '%s'\n", fname);
+ }
+ strcpy (data_file, fname);
+
+ vos_sockReadHdr (sock, &nbytes, fname, &type, &mode);
+ nread = vos_sockRead (sock, line, nbytes);
+ if (debug) sessLog ("SAMP_DATA: '%s' '%s'\n", line, fname);
+ sess_rewriteCmd (line, s->name, data_file);
+ memset (data_file, 0, SZ_FNAME);
+
+ s->nfiles++;
+ s->nbytes += nbytes;
+
+ /* Forward to other connected clients.
+ */
+ s->ncmds++;
+ s->last_cmd = time (NULL);
+ nsent = sess_forwardMessage (sock, line);
+ if (debug)
+ sessLog ("Forwarded to %d clients in '%s'\n", nsent, s->name);
+
+ break;
+
+ case SAMP_CMD:
+ case SAMP_RELAY:
+ nread = vos_sockRead (sock, line, nbytes);
+
+ if (debug)
+ sessLog ("%s[%d][%s]: '%s'\n", vos_typeName (msgtype), nread,
+ (s ? s->name : ""), line);
+ if (s && line[0] && data_file[0]) {
+ sess_rewriteCmd (line, s->name, data_file);
+ memset (data_file, 0, SZ_FNAME);
+ }
+
+ if (strncasecmp (line, "quit", 4) == 0) { /* QUIT */
+ sess_disconnectClient (sock);
+
+ } else if (strncasecmp (line, "list", 4) == 0) { /* LIST */
+ Node *n = (Node *) NULL;
+ char buf[(4*SZ_LINE)], line[SZ_LINE];
+
+ memset (buf, 0, (4 * SZ_LINE));
+ sprintf (buf, "Clients in session '%s':\n", s->name);
+ for (i=0,n=clientHead; n; n=n->next,i++) {
+ memset (line, 0, SZ_LINE);
+ sprintf (line, " [%d]: host: %16.16s port: %d\n",
+ i, n->hostIP, n->port);
+ strcat (buf, line);
+ }
+
+ /* Write the result string back to the client.
+ */
+ len = strlen (buf);
+ if (vos_sockWriteHdr (sock, len, NULL, SAMP_RESULT,
+ SAMP_NOTIFY, "all"))
+ nread = vos_sockWrite (sock, buf, strlen (buf));
+
+ } else if (strncasecmp (line, "connect", 4) == 0) { /* JOIN */
+ sess_joinSession (sock, sess_tok (line, 2));
+
+ } else if (strncasecmp (line, "leave", 4) == 0) { /* LEAVE */
+ sess_leaveSession (sock, s->name);
+
+ } else { /* ELSE .... */
+ if (line[0] && msgtype == SAMP_CMD) {
+ nsent = sess_forwardMessage (sock, line);
+ if (debug)
+ sessLog ("Forward to %d clients in '%s'\n", nsent, s->name);
+ }
+ }
+ if (s) {
+ s->ncmds++;
+ s->last_cmd = time (NULL);
+ }
+ break;
+
+ case SAMP_RESULT:
+ if (debug)
+ sessLog ("%s[%s]: '%s'\n", vos_typeName (msgtype),
+ (s ? s->name : ""), " ");
+ break; /* Not yet implemented */
+
+ case SAMP_QUIT:
+ sess_leaveSession (sock, NULL);
+ sess_disconnectClient (sock);
+ break;
+
+ default:
+ sessLog ("cmd: '%s'\n", cmd);
+ }
+
+ return (0);
+}
+
+
+/**
+ * SESS_FORWARDMESSAGE -- Forward the message to all clients in the session
+ * other than the one which originated it.
+ */
+static int
+sess_forwardMessage (int sender, char *msg)
+{
+ Session *s = sess_bySock (sender);
+ Node *n = (Node *) NULL;
+ int len, nw, sock, nsent = 0;
+
+
+ for (n=s->clients; n; n=n->next) {
+ sock = n->sock;
+ if (sock != sender) {
+ if (debug) fprintf (stderr, "forward to '%s'\n", n->hostIP);
+ len = strlen (msg);
+ if (vos_sockWriteHdr (sock, len, NULL, SAMP_RELAY, 0, "all"))
+ nw = vos_sockWrite (sock, msg, len);
+ nsent++;
+ }
+ }
+
+ return (nsent);
+}
+
+
+/**
+ * SESS_CONNECTCLIENT -- Connect a client on the named socket.
+ */
+static int
+sess_connectClient (int sock)
+{
+ int new, nr;
+ short ready, sport;
+ struct sockaddr_in client;
+ size_t size = sizeof (client);
+ char sname[SZ_LINE];
+
+
+ memset (sname, 0, SZ_LINE);
+
+ if ((new = accept (sock, (struct sockaddr *) &client,
+ (socklen_t *) &size)) < 0) {
+ sessLog ("svr_sock accept() errno %d: %s", errno, strerror(errno));
+
+ } else {
+ char *host = inet_ntoa (client.sin_addr);
+ int port = ntohs (client.sin_port);
+ Node *node = (Node *) NULL;
+
+
+ /* Attach the client to the list of connected hosts.
+ */
+ node = sess_newNode (new);
+ node->port = port;
+ node->sock = new;
+ strcpy (node->hostIP, host);
+ if (clientHead) {
+ clientTail->next = node;
+ clientTail = node;
+ } else {
+ clientHead = clientTail = node;
+ }
+ nClients++;
+
+ /* Open new server connection and send the callback
+ * port number over the connection. After that, we
+ * don't need the initial connection so release it.
+ */
+ cb_port = sport = sess_newPort ();
+ cb_sock = vos_openServerSocket (cb_port);
+ if (debug)
+ sessLog ("Connect from host:%s, port:%d, fd:%d, cb_port: %d\n",
+ host, port, new, cb_port);
+ vos_sockWrite (new, &sport, sizeof(short));
+ cb_port = sport;
+ close (new);
+
+ /* Waiting for callback to connect.
+ */
+ if ((new = accept (cb_sock, NULL, NULL)) < 0)
+ sessLog ("cb_sock accept() errno %d: %s", errno, strerror(errno));
+ vos_setNonBlock (new);
+
+ /* Wait for the callback ready message so we know
+ * we are connected to the client.
+ */
+ nr = vos_sockRead (new, &ready, sizeof(short));
+ if (ready == SESS_READY) {
+#ifdef READ_CONNECT
+ int nbytes=0, type=0, mode=0;
+
+ /* Read the session name.
+ */
+ vos_sockReadHdr (new, &nbytes, NULL, &type, &mode);
+ nr = vos_sockRead (new, sname, nbytes);
+
+ if (verbose)
+ sessLog ("Connect host %s:%d\n",
+ inet_ntoa(client.sin_addr), ntohs(client.sin_port), sname);
+ strcpy (node->session, sname);
+#else
+ if (verbose)
+ sessLog ("Connect host %s:%d\n",
+ inet_ntoa (client.sin_addr), ntohs (client.sin_port));
+#endif
+ }
+
+
+ /* Add the client socket fd to the master set of
+ * active descriptors.
+ */
+ FD_SET (new, &allset);
+ }
+
+ return (0);
+}
+
+
+/**
+ * SESS_DISCONNECTCLIENT -- Shutdown client on the named socket.
+ */
+static int
+sess_disconnectClient (int sock)
+{
+ Node *client = sess_clientBySock (sock);
+
+ sessLog ("Disconnecting client %d....\n", sock);
+ FD_CLR (sock, &allset);
+ close (sock);
+
+ sess_freeNode (client);
+ sess_freePort (client->port);
+
+ return (0);
+}
+
+
+/**
+ * SESS_DISCONNECTALLCLIENTS -- Shutdown all connected clients
+ */
+static int
+sess_disconnectAllClients ()
+{
+ Session *s = (Session *) NULL;
+ Node *n = (Node *) NULL;
+
+ /* Loop over all the session and their client lists and disconnect
+ * the client. We do it here rather than following the client list
+ * since we'll also clean up the data cache when the session is closed.
+ */
+ for (s=sessHead; s; s=s->next) {
+ for (n=s->clients; n; n=n->next) {
+ if (debug)
+ sessLog ("Disconnecting host %s on port %d from '%s'\n",
+ n->hostIP, n->port, s->name);
+
+ sess_leaveSession (n->sock, s->name);
+ }
+ }
+ return (0);
+}
+
+
+
+
+/***************************************************************************
+**** Session Procedures ****
+***************************************************************************/
+
+/**
+ * SESS_JOINSESSION -- Join (or create) a session.
+ */
+static int
+sess_joinSession (int sock, char *session_name)
+{
+ Session *s = (Session *) NULL;
+ Node *n = (Node *) NULL;
+ int found = 0;
+
+
+ if (sessHead) {
+ s = sess_byName (session_name);
+ if (s == (Session *) NULL) {
+ /* Name not found, create a new session pointer.
+ */
+ s = sess_newSession (session_name);
+ sessTail->next = s;
+ sessTail = s;
+ nSessions++;
+ }
+
+ } else {
+ /* No active sessions, create one.
+ */
+ s = sessHead = sessTail = sess_newSession (session_name);
+
+ /* Create the working session directory.
+ */
+ sprintf (s->dataCache, "%s/%s", sessionData, session_name);
+ if (access (s->dataCache, F_OK) < 0) {
+ if (debug) sessLog ("Making session cache directory '%s'\n",
+ s->dataCache);
+ if (mkdir (s->dataCache, 0755) < 0) {
+ fprintf (stderr, "Cannot create session cache directory '%s'\n",
+ s->dataCache);
+ return (1);
+ }
+ }
+ nSessions++;
+ }
+
+ /* Now attach the node the session list of clients, both the master
+ * client list and the client list in each session.
+ */
+ for (n=clientHead; n; n=n->next) { /* master client list */
+ if (sock == n->sock)
+ strcpy (n->session, session_name);
+ }
+ found = 0;
+ for (n=s->clients; n && n->next; n=n->next) {
+ if (n->sock == sock) { /* skip to end of client list */
+ /* client is already in session.
+ */
+ found++;
+ }
+ }
+
+ /* Add to client list if it isn't already found.
+ */
+ if (!found) {
+ if (n) {
+ n->next = sess_newNode (sock);
+ strcpy (n->session, session_name);
+ } else {
+ s->clients = sess_newNode (sock);
+ strcpy (s->clients->session, session_name);
+ }
+ s->nclients++;
+ }
+
+ if (debug > 1) { sess_printSessions (); sess_printClients (); }
+ return (0);
+}
+
+
+/**
+ * SESS_LEAVESESSION -- Leave an open session.
+ */
+static int
+sess_leaveSession (int sock, char *session_name)
+{
+ Session *s = (Session *) NULL;
+ int port = sess_sockToPort (sock);
+
+
+ s = (session_name ? sess_byName (session_name) : sess_bySock (sock));
+ if (s) {
+ Node *n = s->clients;
+
+ while (n && n->port != port)
+ n = n->next;
+
+ if (n) {
+ sessLog ("%s leaves session '%s'\n", n->hostIP, s->name);
+ sess_freeNode (n);
+ s->nclients--;
+ }
+
+ if (s->nclients == 0) {
+ /* Remove the working session directory and its contents.
+ */
+ if (access (s->dataCache, F_OK) == 0) {
+ char cmd[SZ_LINE];
+
+ memset (cmd, 0, SZ_LINE);
+ sprintf (cmd, "/bin/rm -rf %s", s->dataCache);
+ if (debug) sessLog ("Removing session cache directory '%s'\n",
+ s->dataCache);
+
+ system (cmd); /* FIXME */
+ }
+ sess_freeSession (s);
+ }
+ }
+
+ if (debug > 1) sess_printSessions ();
+ return (0);
+}
+
+
+/**
+ * SESS_BYNAME - Find a Session pointer by name.
+ */
+static Session *
+sess_byName (char *name)
+{
+ Session *s = (Session *) NULL;
+
+ for (s=sessHead; s; s=s->next)
+ if (strcasecmp (name, s->name) == 0)
+ break;
+
+ return (s);
+}
+
+
+/**
+ * SESS_BYSOCK - Find a Session socket descriptor.
+ */
+static Session *
+sess_bySock (int sock)
+{
+ Session *s = (Session *) NULL;
+ Node *n = (Node *) NULL;
+
+ for (n=clientHead; n; n=n->next) {
+ if (sock == n->sock)
+ return (sess_byName (n->session));
+ }
+ return (s);
+}
+
+
+/**
+ * SESS_CLIENTBYSOCK - Find a Node pointer by socket fd.
+ */
+static Node *
+sess_clientBySock (int sock)
+{
+ Node *n = (Node *) NULL;
+
+ for (n=clientHead; n; n=n->next) {
+ if (n->sock == sock)
+ return (n);
+ }
+
+ return ((Node *) NULL);
+}
+
+
+/**
+ * SESS_SOCKTOPORT - Lookup a port number by the socket fd.
+ */
+static int
+sess_sockToPort (int sock)
+{
+ Node *n = (Node *) NULL;
+
+ for (n=clientHead; n; n=n->next) {
+ if (n->sock == sock)
+ return (n->port);
+ }
+
+ return (-1);
+}
+
+
+#ifdef SESSION_EXTRAS
+/**
+ * SESS_CLIENTBYPORT - Find a Node pointer by port number.
+ */
+static Node *
+sess_clientByPort (int port)
+{
+ Node *n = (Node *) NULL;
+
+ for (n=clientHead; n; n=n->next) {
+ if (n->port == port)
+ return (n);
+ }
+
+ return ((Node *) NULL);
+}
+
+
+/**
+ * SESS_BYPORT - Find a Session port number.
+ */
+static Session *
+sess_byPort (int port)
+{
+ Session *s = (Session *) NULL;
+ Node *n = (Node *) NULL;
+
+ for (n=clientHead; n; n=n->next) {
+ if (port == n->port)
+ return (sess_byName (n->session));
+ }
+ return (s);
+}
+
+
+/**
+ * SESS_PORTTOSOCK - Lookup a socket fd by the client port number.
+ */
+static int
+sess_portToSock (int port)
+{
+ Node *n = clientHead;
+
+ for (n=clientHead; n; n=n->next)
+ if (n->port == port)
+ return (n->sock);
+
+ return (-1);
+}
+#endif
+
+
+/**
+ * SESS_NEWSESSION - Create a new Session structure.
+ */
+static Session *
+sess_newSession (char *name)
+{
+ Session *s = (Session *) calloc (1, sizeof (Session));
+
+ strcpy (s->name, name);
+ s->start_time = time (NULL);
+ return (s);
+}
+
+
+/**
+ * SESS_FREESESSION - Release a Session structure.
+ */
+static int
+sess_freeSession (Session *s)
+{
+ Session *back = (Session *) (s ? s->back : NULL);
+ Session *next = (Session *) (s ? s->next : NULL);
+
+ if (s == sessHead)
+ sessHead = (Session *) next; /* head of the list */
+ else if (s->next == (Session *) NULL)
+ sessHead = (Session *) back; /* tail of the list */
+ else
+ back->next = (void *) s->next; /* middle of the list */
+
+ if (s->nclients == 0) {
+ fprintf (stderr, "Free up session resources for '%s'\n", s->name);
+ }
+ nSessions--;
+
+ s->end_time = time (NULL);
+
+ sess_writeStats (s); /* log the session stats */
+
+ free ((void *) s);
+ if (debug > 1) sess_printSessions ();
+ return (0);
+}
+
+
+/**
+ * SESS_NEWNODE - Create a new Node structure.
+ */
+static Node *
+sess_newNode (int sock)
+{
+ Node *n = (Node *) calloc (1, sizeof (Node));
+ Node *client = sess_clientBySock (sock);
+
+ if (client) {
+ n->sock = client->sock;
+ n->port = client->port;
+ strcpy (n->hostIP, client->hostIP);
+ }
+
+ return (n);
+}
+
+
+/**
+ * SESS_FREENODE - Free a Node structure.
+ */
+static int
+sess_freeNode (Node *node)
+{
+ if (node->back) {
+ Node *back = node->back;
+ back->next = node->next;
+ }
+ if (node->next) {
+ Node *next = node->next;
+ next->back = node->back;
+ }
+
+ free ((void *) node);
+ return (0);
+}
+
+
+/**
+ * SESS_PRINTSESSIONS - Utility to print the session list.
+ */
+static void
+sess_printSessions (void)
+{
+ Session *s = sessHead;
+ Node *n = (Node *) NULL;
+ int i, j;
+
+ if (!s) {
+ fprintf (stderr, "No active sessions\n");
+
+ } else {
+ for (s=sessHead,i=0; s; s=s->next, i++) {
+ fprintf (stderr, "Session[%d]: session '%s' has %d client%c\n",
+ i, s->name, s->nclients, (s->nclients > 1 ? 's':' '));
+ for (n=sessHead->clients,j=0; n; n=n->next, j++) {
+ fprintf (stderr, " Client[%d]: port: %d host: %s\n",
+ j, n->port, n->hostIP);
+ }
+ }
+ }
+}
+
+
+/**
+ * SESS_PRINTCLIENTS - Utility to print the client list.
+ */
+static void
+sess_printClients (void)
+{
+ Node *n = (Node *) NULL;
+ int i;
+
+ for (n=clientHead,i=0; n; n=n->next, i++) {
+ fprintf (stderr, "Client[%d]: port:%d sock:%d host:%s session:%s\n",
+ i, n->port, n->sock, n->hostIP, n->session);
+ }
+}
+
+
+/***************************************************************************
+**** Utility Procedures ****
+***************************************************************************/
+
+/**
+ * SESS_WRITESTATS -- Log the sessions statistics.
+ */
+static void
+sess_writeStats (Session *s)
+{
+ FILE *fd;
+ char buf[SZ_LINE];
+ double nsec;
+
+
+ if (s) {
+ memset (buf, 0, SZ_LINE);
+ nsec = (s->end_time - s->start_time);
+ sprintf (buf,
+ "%s %16.16s ncmds: %d nfiles: %d nbytes: %ld time: %6.1f min\n",
+ vo_logtime(), s->name, s->ncmds, s->nfiles, s->nbytes, (nsec/60.));
+
+ if ((fd = fopen (statfile, "w+"))) {
+ if (debug)
+ sessLog ("%s", buf);
+ fprintf (fd, "%s", buf);
+ fflush (fd); fclose (fd);
+ }
+ } else
+ sessLog ("Error: writeStats gets null session");
+}
+
+
+/**
+ * SESSLOG -- Print a message to the logfile.
+ */
+static void
+sessLog (char *format, ...)
+{
+ FILE *fd;
+ va_list argp;
+ char *buf = calloc (1, 1024);
+ char *tstr = NULL;
+ int len=0;
+ extern char *vo_encodeString ();
+
+
+ /* Format the message.
+ */
+ va_start (argp, format);
+ vo_encodeString (buf, format, &argp);
+ va_end (argp);
+
+ len = strlen (buf); /* ensure a newline */
+ if (buf[len-1] != '\n')
+ strcat (buf, "\n");
+
+
+ /* Log the message.
+ */
+ tstr = vo_logtime ();
+ if (logfile[0] == '-' || strcasecmp (logfile, "stdout") == 0) {
+ printf ("%s %s", tstr, buf);
+
+ } else {
+ if ((fd = fopen (logfile, "w+"))) {
+ if (debug)
+ fprintf (stderr, "%s %s", tstr, buf);
+ fprintf (fd, "%s %s", tstr, buf);
+ fflush (fd); fclose (fd);
+ }
+ }
+
+ free ((void *) buf);
+}
+
+
+/**
+ * SESS_NEWPORT -- Get an open socket/port entry.
+ */
+static int
+sess_newPort ()
+{
+ int i, p;
+
+ for (i=0; i < MAX_PORTS; i++) {
+ p = svr_port + i + 3;
+ if (socks[i] == 0) {
+ socks[i] = p;
+ return (p);
+ }
+ }
+
+ sessLog ("Error: No available client ports.\n");
+ return (-1);
+}
+
+
+/**
+ * SESS_FREEPORT -- Free a socket/port entry.
+ */
+static int
+sess_freePort (int port)
+{
+ int i, p;
+
+ for (i=0; i < MAX_PORTS; i++) {
+ p = svr_port + i + 3;
+ if (p == port) {
+ close (socks[p]);
+ socks[i] = 0;
+ }
+ }
+
+ return (0);
+}
+
+
+/**
+ * SESS_TOK -- Get the specified (1-indexed) w/s delimited token from str.
+ */
+static char *
+sess_tok (char *str, int toknum)
+{
+ register int i;
+ static char tok[SZ_FNAME];
+ char *ip = str, *op = tok;
+
+
+ memset (tok, 0, SZ_FNAME); /* initialize */
+
+ for (i=1; i < toknum; i++) { /* skip ahead to the token */
+ while (!isspace ((int) (*ip)) && *ip) ip++;
+ while ( isspace ((int) (*ip)) && *ip) ip++;
+ }
+
+ do {
+ *op++ = *ip++;
+ } while (!isspace ((int) (*ip)) && *ip); /* copy the token */
+
+ return (tok);
+}
+
+
+/**
+ * SESS_REWRITECMD -- Rewrite the command string with filename substitution.
+ */
+static void
+sess_rewriteCmd (char *line, char *session, char *fname)
+{
+ char *ip, *op, buf[SZ_LINE], obuf[SZ_LINE], name[SZ_FNAME];
+
+
+ memset (obuf, 0, SZ_LINE);
+ for (ip=line; *ip; ) {
+ memset (buf, 0, SZ_LINE);
+ memset (name, 0, SZ_FNAME);
+
+ for (op=buf; *ip && !isspace(*ip); ) /* get token */
+ *op++ = *ip++;
+
+#ifdef USE_FILE_URI
+ /* Replace file-URI and absolute paths with the replacement filename.
+ */
+ if (strncmp ("file://", buf, 7) == 0 || buf[0] == '/')
+ strcat (obuf, fname);
+ else
+ strcat (obuf, buf);
+#else
+ /* Replace 'SESSION_URL' with the session dataCache URL.
+ */
+ if (strncmp ("SESSION_URL", buf, 11) == 0) {
+ strcpy (name, (buf[11] ? &buf[12] : fname));
+ sprintf (buf, "%s/%s/%s", sessionUrlBase, session, name);
+ }
+ strcat (obuf, buf);
+#endif
+
+ while (*ip && isspace (*ip)) /* skip whitespace */
+ strncat (obuf, ip++, 1);
+ }
+
+ memset (line, 0, SZ_LINE);
+ strcpy (line, obuf);
+}
+
+
+
+/**
+ * USAGE -- Print a task usage summary.
+ */
+static void
+Usage (void)
+{
+ fprintf (stderr,
+ " Usage:\n"
+ "\n"
+ " %% vosession [-hvd] [-p <port>]\n"
+ "\n"
+ " where <cmd> command to process\n"
+ " -h print help summary\n"
+ " -v verbose output\n"
+ " -d debug output\n"
+ "\n"
+ " -p <port> server port\n"
+ "\n"
+ );
+}
+
+
+/**
+ * Tests -- Task unit tests.
+ */
+static void
+Tests (char *input)
+{
+ ; /* no-op */
+}
diff --git a/vendor/voclient/voapps/vosloanspec.c b/vendor/voclient/voapps/vosloanspec.c
new file mode 100644
index 00000000..70fcfbe9
--- /dev/null
+++ b/vendor/voclient/voapps/vosloanspec.c
@@ -0,0 +1,765 @@
+/*
+ * VOTSLOANSPEC -- Query and access spectra from SDSS/BOSS
+ *
+ * Usage:
+ * vosloanspec [<opts>] <obj> | {<ra> <dec>} | {<ra> <dec> <radius>}
+ *
+ * where
+ * -%%,--test Run unit tests
+ * -h,--help This message
+ * -d,--debug Debug Flag
+ * -v,--verbose Verbose Flag
+ * -r,--return=<obj> Return object
+ *
+ * -P,--pos=<ra>,<dec> Set query position (dec degrees)
+ * -R,--release=<rel> Data release (dr8/dr9/current) (def=current)
+ * -s,--size=<radius> Set query radius (dec degrees)
+ * -t,--type=<type> Object type (all|galaxy|qso|star)
+ * -z,--redshift=<zrange> Select by redshift range string(s)
+ *
+ * -c,--count Return only count of results
+ * -m,--meta Print result position metadata
+ * -D,--delete Delete spectra after printing metadata
+ * -l,--limit=<N> Limit to top <N> results
+ * -u,--urls Get urls to spectra
+ *
+ * -S,--samp Broadcase urls to SAMP (as spectrum)
+ * -T,--table Broadcase urls as VOTable message
+ * -N,--num=<N> Number of download threads
+ *
+ * -f,--file=<file> Input file
+ * -b,--base=<file> Base filename
+ * -O,--output=<file> Output file
+ * -o,--object=<obj> Object name
+ *
+ * Interface based on API at: http://api.sdss3.org/index.html
+ *
+ *
+ * @file vosloanspec.c
+ * @author Mike Fitzpatrick
+ * @date 9/93/12
+ *
+ * @brief Query and access spectra from SDSS/BOSS
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+#include <ctype.h>
+#include <pthread.h>
+#include <errno.h>
+#include <sys/stat.h>
+
+#include "samp.h"
+#include "VOClient.h"
+#include "voApps.h"
+
+
+#define SZ_RESBUF 8192
+#define SZ_URL 1024
+
+#define MAX_THREADS 64
+#define DEF_THREADS 12
+#define MAX_DOWNLOADS 65537
+
+#define NEXTARG(a) strdup(optval);argnum++;
+
+
+static int verbose = FALSE; /* verbose flag */
+static int debug = FALSE; /* debug flag */
+static int count = FALSE; /* count results */
+static int urls = FALSE; /* get URLs to data? */
+static int asSpec = TRUE; /* SAMP as Spectrum (or Table)? */
+static int nthreads = DEF_THREADS; /* Number of downlaod threads */
+static int ndownloads = 0; /* Number of file downloads */
+static int specnum = 0; /* spectrum number */
+
+static int have_infile = FALSE; /* have input file? */
+static int do_return = FALSE; /* return result? */
+static int do_samp = FALSE; /* broadcast SAMP result? */
+static int do_meta = FALSE; /* get spectrum metadata? */
+static int do_delete = FALSE; /* delete files after metadata? */
+
+static char *pos = NULL; /* position string */
+static char *release = NULL; /* data release */
+static char *limit = NULL; /* limit results */
+static char *size = NULL; /* search radius */
+static char *type = NULL; /* spectrum type */
+static char *redshift = NULL; /* redshift range */
+static char *iname = NULL; /* input position name */
+static char *oname = NULL; /* output name */
+static char *object = NULL; /* object name */
+static char *basename = NULL; /* base filename */
+
+static double ra = -999.9; /* RA query position */
+static double dec = -999.9; /* Dec query position */
+static double rad = 0.25; /* query size (deg) */
+
+static char ra_str[SZ_FNAME];
+static char dec_str[SZ_FNAME];
+static char rad_str[SZ_FNAME];
+
+#ifdef USE_RESBUF
+static char *resbuf; /* result buffer */
+#endif
+
+char url[SZ_URL];
+char *query_base = "http://api.sdss3.org/spectrumQuery?";
+char *spec_base = "http://api.sdss3.org/spectrum?";
+
+
+typedef struct {
+ char url[SZ_URL]; /* access URL */
+ char fname[SZ_URL]; /* local filename */
+ int tnum; /* worker thread number */
+} Acref, *AcrefP;
+
+Acref aclist[MAX_DOWNLOADS]; /* access list */
+
+
+/* Task specific option declarations.
+ */
+int vosloanspec (int argc, char **argv, size_t *len, void **result);
+
+static Task self = { "vosloanspec", vosloanspec, 0, 0, 0 };
+static char *opts = "%hrvdDP:N:R:STs:t:z:cl:uf:o:bm";
+static struct option long_opts[] = {
+ { "test", 2, 0, '%'}, /* required */
+ { "help", 2, 0, 'h'}, /* required */
+ { "verbose", 2, 0, 'v'}, /* verbose flag */
+ { "debug", 2, 0, 'd'}, /* debug flag */
+ { "return", 1, 0, 'r'}, /* task return option */
+
+ { "pos", 1, 0, 'P'}, /* position param */
+ { "release", 1, 0, 'R'}, /* data release */
+ { "table", 2, 0, 'T'}, /* data release */
+ { "size", 1, 0, 's'}, /* search radius */
+ { "type", 1, 0, 't'}, /* spectra type */
+ { "redshift", 1, 0, 'z'}, /* redshift range */
+
+ { "count", 2, 0, 'c'}, /* count results */
+ { "meta", 2, 0, 'm'}, /* count results */
+ { "limit", 1, 0, 'l'}, /* limit results */
+ { "urls", 2, 0, 'u'}, /* get urls */
+ { "samp", 2, 0, 'S'}, /* broadcast SAMP */
+ { "num", 1, 0, 'N'}, /* num downloads */
+ { "delete", 2, 0, 'D'}, /* num downloads */
+
+ { "file", 1, 0, 'f'}, /* input file */
+ { "output", 1, 0, 'O'}, /* output file */
+ { "object", 1, 0, 'o'}, /* object name */
+ { "base", 1, 0, 'b'}, /* base filename */
+ { NULL, 0, 0, 0 }
+};
+
+
+static void Usage (void);
+static void Tests (char *input);
+static int vos_getCountValue (char *fname);
+static int vos_sampInit (void);
+static char *vos_getURLValues (char *fname);
+static void vot_procAclist (void);
+static void vot_procMeta (void);
+static void *vot_getAclist (void *arg);
+
+extern int vos_getURL ();
+extern int vot_atoi (char *v);
+extern double vot_atof (char *v);
+extern char *vot_mktemp ();
+
+extern int vosesame (int argc, char **argv, size_t *len, void **result);
+extern char *vo_urlEncode (char *target);
+
+
+
+/**
+ * Application entry point.
+ */
+int
+vosloanspec (int argc, char **argv, size_t *reslen, void **result)
+{
+ int apos, argnum = 0, status = OK;
+ FILE *fd = (FILE *) NULL;
+ char **pargv, optval[SZ_FNAME], ch, *urlList = NULL;;
+ char *tmp = vot_mktemp ("vosloan");
+
+
+ /* Initialize.
+ */
+ oname = NULL;
+ iname = NULL;
+ *reslen = 0;
+ *result = NULL;
+
+ ra = -999.9;
+ dec = -999.9;
+ memset (ra_str, 0, SZ_FNAME);
+ memset (dec_str, 0, SZ_FNAME);
+ memset (rad_str, 0, SZ_FNAME);
+ memset (url, 0, SZ_URL); /* initialize the query URL */
+ strcpy (url, query_base);
+ strcpy (rad_str, "900"); /* 0.25 deg default */
+
+ asSpec = TRUE;
+ do_samp = FALSE;
+ do_meta = FALSE;
+ do_delete = FALSE;
+
+ pos = NULL; /* position string */
+ release = NULL; /* data release */
+ limit = NULL; /* limit results */
+ size = NULL; /* search radius */
+ type = NULL; /* spectrum type */
+ redshift = NULL; /* redshift range */
+ iname = NULL; /* input position name */
+ oname = NULL; /* output name */
+ object = NULL; /* object name */
+ basename = NULL; /* base filename */
+
+
+ /* Parse the argument list.
+ */
+ pargv = vo_paramInit (argc, argv, opts, long_opts);
+ while ((ch = vo_paramNext (opts,long_opts,argc,pargv,optval,&apos)) != 0) {
+ argnum++;
+ if (ch > 0) {
+ switch (ch) {
+ case '%': Tests (NULL); return (self.nfail);
+ case 'h': Usage (); return (OK);
+
+ case 'v': verbose++; break;
+ case 'd': debug++; break;
+ case 'r': do_return++; break; /* FIX */
+
+ case 'N': nthreads = vot_atoi (optval); argnum++; break;
+ case 'P': pos = NEXTARG (optval); break;
+ case 'R': release = NEXTARG (optval); break;
+ case 's': size = NEXTARG (optval);
+ sprintf (rad_str, "%g", (rad = vot_atof(size) * 3600.));
+ break;
+ case 't': type = NEXTARG (optval); break;
+ case 'z': redshift = NEXTARG (optval); break;
+
+ case 'c': count++; break;
+ case 'm': do_meta++; break;
+ case 'u': urls++; break;
+ case 'S': do_samp++; break;
+ case 'D': do_delete++; break;
+ case 'T': asSpec--; break;
+ case 'l': limit = NEXTARG (optval); break;
+
+ case 'f': iname = NEXTARG (optval); /* NYI */
+ have_infile++;
+ break;
+ case 'O': oname = NEXTARG (optval); break;
+ case 'o': object = NEXTARG (optval);
+ if (argv[argnum]) {
+ Sesame sr;
+ char *opts = "runid=voc.vosloanspec,use_cache=no";
+
+ if (voc_initVOClient (opts) != OK) {
+ fprintf (stderr,"ERROR: can't open VOClient\n");
+ return (ERR);
+ }
+ sr = voc_nameResolver (vo_urlEncode (argv[argnum]));
+ if (sr == 0) {
+ fprintf (stderr,"ERROR: can't resolve '%s'\n",
+ argv[argnum]);
+ return (ERR);
+ } else {
+ sprintf (ra_str, "%f",
+ (ra=voc_resolverRA (sr)));
+ sprintf (dec_str, "%f",
+ (dec=voc_resolverDEC (sr)));
+ }
+ }
+ break;
+ case 'b': basename = NEXTARG (optval); break;
+ default:
+ fprintf (stderr, "Invalid option '%s'\n", optval);
+ return (1);
+ }
+
+ } else if (ch == PARG_ERR) {
+ return (ERR);
+
+ } else {
+
+ switch (argc - argnum) {
+ case -1: /* obj */
+ argnum--;
+ case 0: /* obj */
+ argnum--;
+ case 1: /* obj */
+ /* resolve object pos
+ */
+ if (argv[argnum]) {
+ Sesame sr;
+ char *opts = "runid=voc.vosloanspec,use_cache=no";
+
+ if (voc_initVOClient (opts) != OK) {
+ fprintf (stderr, "ERROR: cannot open VOClient\n");
+ return (ERR);
+ }
+ sr = voc_nameResolver (vo_urlEncode (argv[argnum]));
+ if (sr == 0) {
+ fprintf (stderr,"ERROR: can't resolve '%s'\n",
+ argv[argnum]);
+ return (ERR);
+ }
+ sprintf (ra_str, "%f", (ra = voc_resolverRA (sr)));
+ sprintf (dec_str, "%f", (dec = voc_resolverDEC (sr)));
+ }
+ break;
+ case 2: /* ra dec */
+ ra = vot_atof (argv[argnum]);
+ dec = vot_atof (argv[argnum+1]);
+ strcpy (ra_str, argv[argnum]);
+ strcpy (dec_str, argv[argnum+1]);
+ break;
+ case 3: /* ra dec rad */
+ ra = vot_atof (argv[argnum]);
+ dec = vot_atof (argv[argnum+1]);
+ rad = vot_atof (argv[argnum+2]);
+ strcpy (ra_str, argv[argnum]);
+ strcpy (dec_str, argv[argnum+1]);
+ strcpy (rad_str, argv[argnum+2]);
+ break;
+ }
+ break;
+ }
+ }
+
+ if (debug)
+ fprintf (stderr, "ra = %f dec = %f rad = %f\n", ra, dec, rad);
+
+ /* Sanity checks
+ */
+ if (iname == NULL) iname = strdup ("stdin");
+ if (oname == NULL) oname = strdup ("stdout");
+ if (strcmp (iname, "-") == 0) { free (iname), iname = strdup ("stdin"); }
+ if (strcmp (oname, "-") == 0) { free (oname), oname = strdup ("stdout"); }
+
+ if (rad > 36000) /* enforce max query size of 10 deg */
+ rad = 36000;
+
+
+ /* Append parameters to the base URL based on the cmdline options. We
+ * parse the positions/sizes and deal with files below.
+ */
+ if (limit) strcat (url, "&limit="), strcat (url, limit);
+ if (type) strcat (url, "&class="), strcat (url, type);
+ if (release) strcat (url, "&release="), strcat (url, release);
+ if (redshift) strcat (url, "&redshift="), strcat (url, redshift);
+ if (count) strcat (url, "&count");
+ strcat (url, "&urls"); /* always get URLS */
+
+ if (ra != -999.9)
+ strcat (url, "&ra="), strcat (url, ra_str), strcat (url,"d");;
+ if (dec != -999.9)
+ strcat (url, "&dec="), strcat (url, dec_str);
+ strcat (url, "&radius="); strcat (url, rad_str);
+
+ if (debug)
+ fprintf (stderr, "url[0] = %s\n", url);
+
+
+ /* Access the query URL, saving the result to the named filed. We'll
+ * process the options on the resulting file.
+ */
+ if (vos_getURL (url, tmp) >= 0) {
+ if (count) {
+ printf ("%d\n", vos_getCountValue (tmp));
+
+ } else if (urls) {
+ printf ("%s", (urlList= vos_getURLValues (tmp)));
+
+ } else {
+ char *url = NULL, *base = NULL, tok[SZ_URL], fname[SZ_FNAME];
+ int sampH = vos_sampInit ();
+
+ url = urlList = vos_getURLValues (tmp);
+ memset (tok, 0, SZ_URL);
+ base = (basename ? basename : "sdss");
+
+ if (do_samp) {
+ if (verbose)
+ fprintf (stderr, "Initializing SAMP ....\n");
+ sampH = sampInit ("vosloanspec", "VOClient SDSS Task");
+ }
+
+ for (specnum=0; *url && sscanf (url, "%s", tok); specnum++) {
+ memset (fname, 0, SZ_FNAME);
+ sprintf (fname, "%s%04d.fits", base, specnum);
+
+ if (do_samp) {
+ /* Broadcast URL as a SAMP message, either as a bintable
+ * or an ssa-generic spectrum.
+ */
+ if (sampH) {
+ int stat = -1;
+
+ if (verbose)
+ fprintf (stderr, "Loading '%s' ....\n", tok);
+ if (asSpec) {
+ stat = samp_specLoadSSAGeneric (sampH, "all",
+ tok, /* URL */
+ 0, /* Map meta */ /* NYI */
+ fname, /* spectrumId */
+ fname); /* name */
+ } else {
+ stat = samp_tableLoadFITS (sampH, "all",
+ tok, /* URL/file */
+ fname, /* tblId */
+ fname); /* name */
+ }
+ }
+
+ } else {
+ /* Download URL to a local file.
+ */
+ aclist[specnum].tnum = ((nthreads == 1) ? 0 :
+ (specnum % nthreads));
+ strcpy (aclist[specnum].url, tok);
+ strcpy (aclist[specnum].fname, fname);
+ ndownloads++;
+ }
+
+ url += strlen (tok) + 1;
+ memset (tok, 0, SZ_URL);
+ }
+
+ /* Process the access list (downloads) and metadata request.
+ */
+ if (ndownloads) {
+ vot_procAclist ();
+ if (do_meta)
+ vot_procMeta ();
+ }
+
+ if (do_samp && sampH)
+ sampClose (sampH);
+ }
+ } else
+ status = ERR;
+
+
+ /* Clean up.
+ */
+ if (fd != stdout)
+ fclose (fd);
+ if (urlList)
+ free ((void *) urlList);
+
+ if (pos) free (pos);
+ if (type) free (type);
+ if (size) free (size);
+ if (limit) free (limit);
+ if (iname) free (iname);
+ if (oname) free (oname);
+ if (object) free (object);
+ if (release) free (release);
+ if (redshift) free (redshift);
+ if (basename) free (basename);
+
+ vo_paramFree (argc, pargv);
+
+ return (status);
+}
+
+
+/**
+ * VOT_PROCACLIST -- Process the access list.
+ */
+static void
+vot_procAclist (void)
+{
+ /* Spawn the worker threads.
+ */
+ int rc = 0, tc = 0, status = 0, tnum[MAX_THREADS];
+ pthread_attr_t attr; /* thread attributes */
+ pthread_t thread[MAX_THREADS];
+
+
+ /* Initialize the service processing thread attributes and run 'em.
+ */
+ pthread_attr_init (&attr);
+ pthread_attr_setdetachstate (&attr, PTHREAD_CREATE_JOINABLE);
+
+ for (tc=0; tc < nthreads; tc++) {
+ tnum[tc] = tc;
+ if ((rc = pthread_create (&thread[tc], &attr, vot_getAclist,
+ (void *)&tnum[tc]))) {
+ fprintf (stderr, "ERROR: pthread_create() fails, code=%d\n",
+ rc);
+ return;
+ }
+ }
+
+ /* Free attribute and wait for the threads to complete.
+ */
+ pthread_attr_destroy (&attr);
+ for (tc=0; tc < nthreads; tc++) {
+ if ((rc = pthread_join (thread[tc], (void **)&status)) ) {
+ if (rc != ESRCH) {
+ fprintf (stderr,
+ "ERROR: pthread_join() fails, code=%d status=%d\n",
+ rc, status);
+ return;
+ }
+ }
+ }
+
+ if (verbose)
+ fprintf (stderr, "Downloaded %d files -- complete\n", ndownloads);
+}
+
+
+/**
+ * VOT_GETACLIST -- Download all the files for the specified thread.
+ */
+static void *
+vot_getAclist (void *arg)
+{
+ register int i;
+ int threadNum = 0;
+
+
+ if (arg) {
+ threadNum = *(int *)arg;
+
+ for (i=0; i < ndownloads; i++) {
+ if (aclist[i].tnum == threadNum) {
+ if (verbose)
+ fprintf (stderr, "%s -> %s\n",
+ aclist[i].fname, aclist[i].url);
+ vos_getURL (aclist[i].url, aclist[i].fname);
+ }
+ }
+ }
+ return ((void *) NULL);
+}
+
+
+/**
+ * VOT_PROCMETA -- Process the metadata request.
+ */
+static void
+vot_procMeta (void)
+{
+ int i, fd, nread;
+ char rec[(4 * 2880)];
+
+ for (i=0; i < ndownloads; i++) {
+ if (access (aclist[i].fname, R_OK) == 0) {
+ if ((fd = open (aclist[i].fname, O_RDONLY)) >= 0) {
+ nread = read (fd, rec, (size_t) (4 * 2880));
+ printf ("%s\t", aclist[i].fname);
+ printf ("%11.6f\t", atof (strstr (rec, "PLUG_RA") + 11));
+ printf ("%12.6f\n", atof (strstr (rec, "PLUG_DEC") + 11));
+ close (fd);
+
+ if (do_delete)
+ unlink (aclist[i].fname);
+ }
+ }
+ }
+}
+
+
+/**
+ * VOS_GETCOUNTVALUE -- Get the value from a count request.
+ */
+static int
+vos_getCountValue (char *fname)
+{
+ char buf[SZ_LINE], *line;
+ FILE *fd;
+
+ if (fname && (fd = fopen (fname, "r"))) {
+ memset (buf, 0, SZ_LINE);
+ line = fgets (buf, SZ_LINE, fd);
+ fclose (fd);
+ unlink (fname);
+
+ return (vot_atoi (line));
+ }
+ return (-1);
+}
+
+
+/**
+ * VOS_GETURLVALUES -- Get the values from a URL request.
+ */
+static char *
+vos_getURLValues (char *fname)
+{
+ char *ptr, *out, *ip, *op;
+ FILE *fd;
+ extern int vos_fileRead();
+
+
+ if (fname && (fd = fopen (fname, "r"))) {
+ struct stat info;
+ size_t sz, nr;
+
+ if (stat (fname, &info) < 0) /* read the whole file */
+ return (NULL);
+ sz = info.st_size;
+ ptr = calloc (sz + 1, sizeof(char));
+ out = calloc (sz + 1, sizeof(char));
+ nr = vos_fileRead (fileno(fd), ptr, sz);
+
+ /* Check for a service outage.
+ */
+ if (strstr (ptr, "uWSGI Error")) {
+ if (ptr) free (ptr);
+ if (out) free (out);
+ return ( strdup ("SDSS Service not available\n") );
+ }
+
+ for (ip=ptr, op=out; *ip; ip++) {
+ if (*ip == '[')
+ ;
+ if (*ip == '"') {
+ ip++;
+ while (*ip != '"') /* copy token */
+ *op++ = *ip++;
+ *op++ = '\n';
+ while (*ip != '"') /* skip to next token */
+ ip++;
+ }
+ }
+
+ free ((void *) ptr);
+ fclose (fd);
+ unlink (fname);
+
+ return (out);
+ }
+
+ return (NULL);
+}
+
+
+/**
+ * VOS_SAMPINIT -- Initialize the SAMP interface connection.
+ */
+static int
+vos_sampInit (void)
+{
+ int sampH = 0;
+
+
+ /* If there's no Hub running, don't bother ....
+ */
+ if (!samp_hubRunning())
+ return (0);
+
+ /* Initialize the SAMP interface.
+ */
+ sampH = sampInit ("vosloanspec", "VOClient SDSS Spectrum Task");
+ if (samp_hubActive (sampH) == 0)
+ return (0);
+
+ /* Force 'asynch' messaging.
+ */
+ samp_setSyncMode (sampH);
+
+ /* Load metadata.
+ */
+ samp_Metadata (sampH, "author.name", "Mike Fitzpatrick, NOAO");
+ samp_Metadata (sampH, "author.email", "fitz@noao.edu");
+ samp_Metadata (sampH, "samp.description.html",
+ "http://iraf.noao.edu/voclient/vosamp.html");
+ samp_Metadata (sampH, "samp.icon.url",
+ "http://iraf.noao.edu/voclient/vao_icon.gif");
+
+ /* Register with the Hub and begin messaging.
+ */
+ sampStartup (sampH);
+
+
+ return (sampH);
+}
+
+
+/**
+ * USAGE -- Print task help summary.
+ */
+static void
+Usage (void)
+{
+ fprintf (stderr, "\n Usage:\n\t"
+ "vosloanspec [<opts>] <obj> | {<ra> <dec>} | {<ra> <dec> <radius>}\n\n"
+ " where\n"
+ " -%%,--test Run unit tests\n"
+ " -h,--help This message\n"
+ " -v,--verbose Verbose Flag\n"
+ " -d,--debug Debug Flag\n"
+ " -r,--return=<obj> Return object\n"
+ "\n"
+ " -P,--pos=<ra>,<dec> Set query position (dec degrees)\n"
+ " -R,--release=<rel> Data release (dr8/dr9/def=current)\n"
+ " -s,--size=<radius> Set query radius (dec degrees)\n"
+ " -t,--type=<type> Object type (all|galaxy|qso|star)\n"
+ " -z,--redshift=<zrange> Select by redshift range string(s)\n"
+ "\n"
+ " -c,--count Return only count of results\n"
+ " -m,--meta Print result position metadata\n"
+ " -D,--delete Delete spectra after printing metadata\n"
+ " -l,--limit=<N> Limit to top <N> results\n"
+ " -u,--urls Get urls to spectra\n"
+ "\n"
+ " -S,--samp Broadcase urls to SAMP (as spectrum)\n"
+ " -T,--table Broadcase urls as VOTable message\n"
+ " -N,--num=<N> Number of download threads\n"
+ "\n"
+ " -f,--file=<file> Input file\n"
+ " -b,--base=<file> Base filename\n"
+ " -O,--output=<file> Output file\n"
+ " -o,--object=<obj> Object name\n"
+ "\n\n"
+ " Examples:\n\n"
+ " 1) Download all galaxy spectra w/in 0.1 deg of the Hubble UDF\n\n"
+ " %% vosloanspec -s 0.1 -t galaxy HUDF\n"
+ " %% vosloanspec --size=0.1 --type=galaxy HUDF\n"
+ "\n"
+ " 2) Get only the positions of the SDSS spectra around a point\n\n"
+ " %% vosloanspec -m -d m51\n"
+ " %% vosloanspec --meta --delete m51\n"
+ "\n"
+ " 3) Broadcast 5 spectra around 3c273 to SAMP-enabled apps\n\n"
+ " %% vosloanspec -l 5 --samp 3c273\t# as a spectrum msg\n"
+ " %% vosloanspec -l 5 --samp --table 3c273\t# as a table msg\n"
+ "\n"
+ " 4) Get all QSO spectra with a redshift > 0.3 (Note an upper range\n"
+ " must be specified for the redshift range for a valid query)\n\n"
+ " %% vosloanspec --redshift=0.3-1.0\n"
+ "\n\n"
+ );
+}
+
+
+/**
+ * Tests -- Task unit tests.
+ */
+static void
+Tests (char *input)
+{
+ Task *task = &self;
+
+ vo_taskTest (task, "--help", NULL);
+
+ vo_taskTest (task, "-s", "0.1", "-t", "galaxy", "HUDF", NULL); // Ex 1a
+ vo_taskTest (task, "--size=0.1", "--type=galaxy", "HUDF", NULL); // Ex 1b
+ vo_taskTest (task, "-m", "-D", "m51", NULL); // Ex 2a
+ vo_taskTest (task, "--meta", "--delete", "m51", NULL); // Ex 2b
+ vo_taskTest (task, "-l", "5", "--samp", "3c273", NULL); // Ex 3a
+ vo_taskTest (task, "-l", "5", "--samp", "--table", "3c273", NULL); // Ex 3b
+ vo_taskTest (task, "--redshift=0.3-1.0", NULL); // Ex 4
+
+ vo_taskTestReport (self);
+}
diff --git a/vendor/voclient/voapps/vospectra.c b/vendor/voclient/voapps/vospectra.c
new file mode 100644
index 00000000..ad12f28c
--- /dev/null
+++ b/vendor/voclient/voapps/vospectra.c
@@ -0,0 +1,130 @@
+/**
+ * VOSPECTRA -- Query all VO Spectra services
+ *
+ * Usage:
+ * vospectra [<opts>] [ <object> | <ra> <dec> ] [ <size> ]
+ *
+ * @file vospectra.c
+ * @author Mike Fitzpatrick
+ * @date 2/03/13
+ *
+ * @brief Query all VO Image services.
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+
+#include "votParse.h" /* keep these in order! */
+#include "voApps.h"
+
+
+/* Task specific option declarations. Task options are declared using the
+ * getopt_long(3) syntax.
+ */
+int vodata (int argc, char **argv, size_t *len, void **result);
+int vospectra (int argc, char **argv, size_t *len, void **result);
+
+static Task self = { "vospectra", vospectra, 0, 0, 0 };
+
+extern void vot_setArg (char **argv, int *argc, char *value);
+
+static void Usage (void);
+static void Tests (char *input);
+
+
+/**
+ * Application entry point. All VOApps tasks MUST contain this
+ * method signature.
+ */
+int
+vospectra (int argc, char **argv, size_t *reslen, void **result)
+{
+ char *pargv[argc+2];
+ int i, narg = 0, status = OK;
+
+
+ /* Initialize result object whether we return an object or not.
+ */
+ *reslen = 0;
+ *result = NULL;
+
+ /* Do a quick check of the args so we can provide a task-local
+ * help and test option. Otherwise, we simply pass thru all the
+ * args to VODATA for processing.
+ */
+ if (strncmp (argv[1],"-h",2) == 0 || strncmp (argv[1],"--help",6) == 0) {
+ Usage (); return (OK);
+ }
+ if (strncmp (argv[1],"-%",2) == 0 || strncmp (argv[1],"--test",6) == 0) {
+ Tests (NULL); return (self.nfail);
+ }
+
+ /* Initialize the new argument vector.
+ */
+ vot_setArg (pargv, &narg, argv[0]);
+ vot_setArg (pargv, &narg, "-t");
+ vot_setArg (pargv, &narg, "spectra");
+ for (i=1; i < argc; i++)
+ vot_setArg (pargv, &narg, argv[i]);
+
+
+ /**
+ * The VODATA task does all the real work, we effectively just set the
+ * "-t spectra" option to force the service type as a logical naming
+ * convenience for the user. Note that return parameters are handled
+ * by vodata as well so there is no processing required here.
+ */
+ status = vodata (narg, pargv, reslen, result);
+
+
+ /* Clean up. Rememebr to free whatever pointers were created when
+ * parsing arguments.
+ */
+ for (i=0; i < (argc + 2); i++)
+ free ((void *) pargv[i]);
+
+ return (status);
+}
+
+
+/**
+ * USAGE -- Print task help summary.
+ */
+static void
+Usage (void)
+{
+ fprintf (stderr, "\n Usage:\n\t"
+ "vospectra [<opts>] votable.xml\n\n"
+ " where\n"
+ " -%%,--test run unit tests\n"
+ " -h,--help this message\n"
+ "\n"
+ " <opts> includes all valid VODATA options\n"
+ "\n"
+ " Examples:\n\n"
+ " 1) Query all services for spectra data of 3c273\n\n"
+ " %% vospectra any 3c273\n"
+ "\n"
+ "\n"
+ );
+}
+
+
+/**
+ * Tests -- Task unit tests.
+ */
+static void
+Tests (char *input)
+{
+ Task *task = &self;
+
+
+ vo_taskTest (task, "--help", NULL);
+
+ vo_taskTest (task, "any", "3c273", NULL);
+
+ vo_taskTestReport (self);
+}
diff --git a/vendor/voclient/voapps/votcat.c b/vendor/voclient/voapps/votcat.c
new file mode 100644
index 00000000..d1661f8f
--- /dev/null
+++ b/vendor/voclient/voapps/votcat.c
@@ -0,0 +1,181 @@
+/**
+ * VOTCAT -- Concatenate multiple VOTables.
+ *
+ * Usage:
+ * votcat [-n] <votable> <votable> ....
+ *
+ * @file votcat.c
+ * @author Mike Fitzpatrick
+ * @date 6/03/12
+ *
+ * @brief Concatenate multiple VOTables.
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "votParse.h"
+#include "voApps.h"
+
+
+
+#define MAX_FILES 1024
+
+
+static int nfiles = 0; /* Number of input files */
+static int out = 0; /* Output VOTable handle */
+
+static int vot[MAX_FILES]; /* First VOTable handle */
+static int res[MAX_FILES]; /* <RESOURCE> handle */
+
+static int do_return = 0; /* return object? */
+
+/* Task specific option declarations.
+ */
+int votcat (int argc, char **argv, size_t *len, void **result);
+
+static Task self = { "votcat", votcat, 0, 0, 0 };
+static char *opts = "hivo:r%:";
+static struct option long_opts[] = {
+ { "help", 2, 0, 'h'}, /* required */
+ { "test", 1, 0, '%'}, /* required */
+ { "indent", 2, 0, 'i'}, /* task option */
+ { "output", 1, 0, 'o'}, /* task option */
+ { "verbose", 2, 0, 'v'}, /* task option */
+ { NULL, 0, 0, 0 }
+};
+
+static void Usage (void);
+static void Tests (char *input);
+
+extern int vot_atoi (char *v);
+
+
+/**
+ * Application entry point.
+ */
+int
+votcat (int argc, char **argv, size_t *reslen, void **result)
+{
+ char **pargv, optval[SZ_FNAME];
+ char *oname = (char *) NULL, ch;
+ char *infile[MAX_FILES];
+ int i, verbose = 0, indent = 1, pos = 0;
+
+
+ if (argc < 3) {
+ fprintf (stderr, "Usage: votconcat [-o <out>] <vot1> <vot2> ....\n");
+ return (1);
+ }
+
+ /* Parse the argument list.
+ */
+ pargv = vo_paramInit (argc, argv, opts, long_opts);
+ while ((ch = vo_paramNext (opts,long_opts,argc,pargv,optval,&pos)) != 0) {
+ if (ch > 0) {
+ switch (ch) {
+ case '%': Tests (optval); return (self.nfail);
+ case 'h': Usage (); return (OK);
+ case 'i': indent = vot_atoi (optval); break;
+ case 'o': oname = strdup (optval); break;
+ case 'v': verbose++; break;
+ case 'r': do_return = 1; break;
+ default:
+ fprintf (stderr, "Invalid option '%s'\n", optval);
+ return (1);
+ }
+
+ } else if (ch == PARG_ERR) {
+ return (ERR);
+
+ } else {
+ infile[nfiles++] = strdup (optval);
+ }
+ }
+
+ /* Sanity checks
+ */
+ if (oname == NULL) oname = strdup ("stdout");
+ if (strcmp (oname, "-") == 0) { free (oname), oname = strdup ("stdout"); }
+
+
+ /* Open output table.
+ */
+ out = vot_openVOTABLE (NULL);
+
+ /* Loop over the input tables on the cmdline.
+ */
+ for (i=0; i < nfiles; i++) {
+ vot[i] = vot_openVOTABLE (infile[i]); /* Parse the table */
+
+ /* Concatenate the tables.
+ */
+ if ((res[i] = vot_getRESOURCE (vot[i])))
+ vot_attachNode (out, res[i]);
+ }
+
+ /* Write it out.
+ */
+ vot_writeVOTable (out, oname, indent);
+
+ for (i=0; i < nfiles; i++)
+ vot_closeVOTABLE (vot[i]); /* close the input tables */
+ vot_closeVOTABLE (vot[i]); /* close the output table */
+
+
+ /* Close (and free) the output table and allocated pointers.
+ */
+ if (oname)
+ free (oname);
+ for (i=0; i < nfiles; i++) {
+ if (infile[i])
+ free (infile[i]);
+ }
+
+ vo_paramFree (argc, pargv);
+ return (OK);
+}
+
+
+/**
+ * USAGE -- Print task help summary.
+ */
+static void
+Usage (void)
+{
+ fprintf (stderr, "\n Usage:\n\t"
+ "generic [<opts>] votable.xml\n\n"
+ " where\n"
+ " -%%,--test run unit tests\n"
+ " -h,--help this message\n"
+ " -n,--number number output\n"
+ " -o,--output=<file> output file\n"
+ " -r,--return return result from method\n"
+ "\n"
+ " Examples:\n\n"
+ " 1) First example\n\n"
+ " %% votcat test.xml\n"
+ "\n"
+ " 2) Second example\n\n"
+ " %% votcat -o pos.txt test.xml\n"
+ "\n"
+ );
+}
+
+
+/**
+ * Tests -- Task unit tests.
+ */
+static void
+Tests (char *input)
+{
+ Task *task = &self;
+
+
+ /* First argument must always be the 'self' variable, the last must
+ * always be a NULL to terminate the cmd args.
+ */
+ vo_taskTest (task, "--help", NULL);
+}
diff --git a/vendor/voclient/voapps/votcnv.c b/vendor/voclient/voapps/votcnv.c
new file mode 100644
index 00000000..7ba0421d
--- /dev/null
+++ b/vendor/voclient/voapps/votcnv.c
@@ -0,0 +1,259 @@
+/**
+ * VOTCNV -- Convert a VOTable to a different format.
+ *
+ * Usage:
+ * votcnv [<opts>] <votable>
+ *
+ * Where
+ * -f,--fmt <fmt> Output format (XML, CSV, TSV, HTML, etc)
+ * -h,--help Print help summary
+ * -i,--indent <N> Indention at each level for VOTable output
+ * -o,--output <fname> Name of output file
+ *
+ * -n,--noheader Don't write a header
+ * -r,--return Return result to API
+ *
+ * <votable> Name of input file to compress
+ *
+ * @file votcnv.c
+ * @author Mike Fitzpatrick
+ * @date 6/03/12
+ *
+ * @brief Convert a VOTable to a different format.
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include "votParse.h"
+#include "voApps.h"
+
+
+static char *fmt = NULL; /* format string */
+static int vot = 0; /* VOTable root handle */
+static int indent = 0; /* indention at each level */
+static int hdr = 1; /* print header ?? */
+static int do_return = 0; /* return result from method? */
+
+/* Task specific option declarations.
+ */
+int votcnv (int argc, char **argv, size_t *len, void **result);
+
+static Task self = { "votcnv", votcnv, 0, 0, 0 };
+static char *opts = "%:f:hi:no:r";
+static struct option long_opts[] = {
+ { "test", 1, 0, '%'}, /* --test is std */
+ { "help", 2, 0, 'h'}, /* --help is std */
+ { "fmt", 1, 0, 'f'}, /* output format */
+ { "indent", 1, 0, 'i'}, /* XML indention level */
+ { "noheader", 2, 0, 'n'}, /* suppress header */
+ { "output", 1, 0, 'o'}, /* output name */
+ { "return", 2, 0, 'r'}, /* return result to API */
+ { NULL, 0, 0, 0 }
+};
+
+
+static void Usage (void);
+static void Tests (char *input);
+
+extern int strdic (char *in_str, char *out_str, int maxchars, char *dict);
+extern int vot_isValidFormat (char *fmt);
+extern int vot_atoi (char *v);
+
+
+
+/**
+ * VOApps task entry point.
+ */
+int
+votcnv (int argc, char **argv, size_t *reslen, void **result)
+{
+ int status = OK, pos = 0;
+ char *iname = NULL, *name = NULL, *oname = NULL, format[SZ_FORMAT];
+ char **pargv, ch, optval[SZ_FNAME];
+
+
+ /* Parse the argument list.
+ */
+ pargv = vo_paramInit (argc, argv, opts, long_opts);
+ while ((ch = vo_paramNext (opts,long_opts,argc,pargv,optval,&pos)) != 0) {
+ if (ch > 0) {
+ switch (ch) {
+ case '%': Tests (optval); return (self.nfail);
+ case 'h': Usage(); return (OK);
+ case 'f': if (!vot_isValidFormat ((fmt = strdup (optval)))) {
+ fprintf (stderr, "Error: invalid format '%s'\n",
+ fmt);
+ return (ERR);
+ }
+ break;
+ case 'i': indent = vot_atoi (optval); break;
+ case 'n': hdr--; break;
+ case 'o': oname = strdup (optval); break;
+ case 'r': do_return++; break;
+ default:
+ fprintf (stderr, "Invalid argument '%s'\n", optval);
+ return (ERR);
+ }
+
+ } else if (ch == PARG_ERR) {
+ return (ERR);
+
+ } else {
+ iname = strdup (optval);
+ break;
+ }
+ }
+
+
+ /* Sanity checks.
+ */
+ if (iname == NULL) iname = strdup ("stdin");
+ if (oname == NULL) oname = strdup ("stdout");
+ if (strcmp (iname, "-") == 0) { free (iname), iname = strdup ("stdin"); }
+ if (strcmp (oname, "-") == 0) { free (oname), oname = strdup ("stdout"); }
+
+ fmt = (fmt ? fmt : strdup ("xml"));
+
+ if (do_return) { /* return result */
+ if (name) free (name);
+ oname = calloc (1, SZ_FNAME);
+ sprintf (oname, "/tmp/votcnv.%d", (int) getpid());
+ } else
+ oname = (oname ? oname : strdup ("stdout"));
+
+
+ /* Open and parse the input table.
+ */
+ if ( (vot = vot_openVOTABLE (iname) ) <= 0) {
+ fprintf (stderr, "Error opening VOTable '%s'\n", iname);
+ return (ERR);
+ }
+
+ /* Output the new format.
+ */
+ switch (strdic (fmt, format, SZ_FORMAT, FORMATS)) {
+ case VOT: vot_writeVOTable (vot, oname, indent); break;
+ case ASV: vot_writeASV (vot, oname, hdr); break;
+ case BSV: vot_writeBSV (vot, oname, hdr); break;
+ case CSV: vot_writeCSV (vot, oname, hdr); break;
+ case TSV: vot_writeTSV (vot, oname, hdr); break;
+ case HTML: vot_writeHTML (vot, iname, oname); break;
+ case SHTML: vot_writeSHTML (vot, iname, oname); break;
+ case FITS: vot_writeFITS (vot, oname); break;
+ case XML: vot_writeVOTable (vot, oname, indent); break;
+ case ASCII: vot_writeASV (vot, oname, hdr); break;
+ case RAW: vot_writeVOTable (vot, oname, indent); break;
+ default:
+ fprintf (stderr, "Unknown output format '%s'\n", fmt);
+ status = ERR;
+ }
+ vot_closeVOTABLE (vot); /* close the table */
+
+
+ /* If we requested a return object, get it from the output file.
+ */
+ if (do_return) {
+ vo_setResultFromFile (oname, reslen, result);
+ unlink (oname);
+ }
+
+ /* Clean up.
+ */
+ if (fmt) free (fmt);
+ if (name) free (name);
+ if (iname) free (iname);
+ if (oname) free (oname);
+ vo_paramFree (argc, pargv);
+
+ return (status);
+}
+
+
+/**
+ * USAGE -- Print a task help summary.
+ */
+static void
+Usage (void)
+{
+ fprintf (stderr, "\n Usage:\n\t"
+ "votcnv [-f <fmt>] [-h] [-i <N>] [-o <outname>] [-n] votable.xml\n\n"
+ " where\n"
+ " -f,--fmt <fmt> output format\n"
+ " -h,--help this message\n"
+ " -i,--indent <N> indented xml output?\n"
+ " -n,--noheader disable output header\n"
+ " -o,--output <name> output filename\n"
+ " -r,--return return result from method\n"
+ "\n"
+ " <fmt> is one of\n"
+ " vot A new VOTable\n"
+ " asv ascii separated values\n"
+ " bsv bar separated values\n"
+ " csv comma separated values\n"
+ " tsv tab separated values\n"
+ " html standalone HTML document\n"
+ " shtml single HTML <table>\n"
+ " fits FITS binary table\n"
+ " ascii ASV alias\n"
+ " xml VOTable alias\n"
+ " raw VOTable alias\n"
+ "\n"
+ " Examples:\n\n"
+ " 1) Convert a VOTable to a CSV file:\n\n"
+ " %% votcnv --fmt=csv test.xml\n"
+ "\n"
+ " 2) Rewrite a VOTable with readable indention:\n\n"
+ " %% votcnv -f vot -i 2 test.xml\n"
+ "\n"
+ " 3) Remove indention from a VOTable:\n\n"
+ " %% votcnv -f vot -i 0 test.xml\n"
+ );
+}
+
+
+
+/**
+ * Tests -- Task unit tests.
+ */
+static void
+Tests (char *input)
+{
+ Task *task = &self;
+
+
+ /* First argument must always be the 'self' variable, the last must
+ * always be a NULL to terminate the cmd args.
+ */
+ vo_taskTest (task, "--help", NULL);
+
+ if (access (input, F_OK) != 0) {
+ fprintf (stderr, "Warning: cannot open file '%s'\n", input);
+ return;
+ }
+
+ /* Test each of the conversion formats.
+ */
+ vo_taskTest (task, "--fmt=vot", input, NULL); // Ex 1
+ vo_taskTest (task, "--fmt=asv", input, NULL);
+ vo_taskTest (task, "--fmt=bsv", input, NULL);
+ vo_taskTest (task, "--fmt=csv", input, NULL);
+ vo_taskTest (task, "--fmt=tsv", input, NULL);
+ vo_taskTest (task, "--fmt=html", input, NULL);
+ vo_taskTest (task, "--fmt=shtml", input, NULL);
+ vo_taskTest (task, "--fmt=fits", "-o", "test.fits", input, NULL);
+ vo_taskTest (task, "--fmt=ascii", input, NULL);
+ vo_taskTest (task, "--fmt=xml", input, NULL);
+
+ vo_taskTest (task, "-f", "vot", "-i", "2", input, NULL); // Ex 2
+ vo_taskTest (task, "-f", "vot", "-i", "0", input, NULL); // Ex 3
+ vo_taskTest (task, "-f", "csv", "-n", input, NULL); // Ex 4
+
+
+ if (access ("test.fits", F_OK) == 0) unlink ("test.fits");
+
+ vo_taskTestReport (self);
+}
+
diff --git a/vendor/voclient/voapps/votget.c b/vendor/voclient/voapps/votget.c
new file mode 100644
index 00000000..87bef50c
--- /dev/null
+++ b/vendor/voclient/voapps/votget.c
@@ -0,0 +1,1089 @@
+/**
+ * VOTGET -- Download select/all access references in a VOTable.
+ *
+ * Usage:
+ *
+ * votget [<opts>] <votable.xml>
+ * votget [<opts>] --samp # to listen for SMAP messages
+ *
+ * Where
+ * -b,--base <base> Base output filename
+ * -e,--extn [<extn>] Extension to add to filename (or auto)
+ * -f,--fmt <fmt> Download only specified <type>
+ * -s,--sum Use checksum as file number
+ * -t,--tmp Input file is temporary, delete when done
+ * -u,--ucd <ucd> Use ucd to identify acref column
+ *
+ * -o,--output <fname> Output filename (single download)
+ * -v,--verbose Verbose output
+ * -x,--extract Extract access references
+ *
+ * -A,--acref <colnum> Col number for acref column (0-indexed)
+ * -B,--bkg Background, i.e. run in forked child process
+ * -C,--cache Cache the downloaded file
+ * -D,--download Set download directory
+ * -F,--fmtcol <colnum> Col number for format column (0-indexed)
+ * -N,--num <N> Number of simultaneous downloads
+ * -S,--samp start as SAMP listener
+ * -m,--mtype <mtype> mtype to wait for
+ *
+ * -h,--help Print help summary
+ * -d,--debug Debug output
+ * --test Run unit tests
+ *
+ * <votable> VOTable to process
+ *
+ * @file votget.c
+ * @author Mike Fitzpatrick
+ * @date 6/03/12
+ *
+ * @brief Download select/all access references in a VOTable.
+ */
+
+
+#define _GNU_SOURCE
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <sys/errno.h>
+#include <sys/types.h>
+#include <sys/uio.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+#include <pthread.h>
+
+#include <curl/curl.h>
+#include <curl/types.h>
+#include <curl/easy.h>
+
+#include "samp.h"
+#include "votParse.h"
+#include "voApps.h"
+
+
+#define MIN_THREADS 4 /* min no. simultaneous thread */
+#define MAX_THREADS 64 /* max no. simultaneous threads */
+#define MAX_DOWNLOADS 4096 /* max no. files to download */
+#define MAX_TRYS 3 /* max download attempts */
+
+#define NAXIS_UCD "VOX:Image_Naxis"
+#define NAXES_UCD "VOX:Image_Naxes"
+#define SCALE_UCD "VOX:Image_Scale"
+#define ACREF_UCD "VOX:Image_AccessReference"
+#define FORMAT_UCD "VOX:Image_Format"
+
+
+static int vot = 0; /* VOTable handle */
+static int verbose = 0; /* verbose parameter */
+static int debug = 0; /* debug flag */
+static int extract = 0; /* extract references only */
+static int detach = 0; /* run as detached process */
+static int nfiles = 0; /* number of download files */
+static int ngot = 0; /* number of files downloaded */
+static int seq = 1; /* use sequential file numbers */
+static int isCache = 0; /* is this a cache file? */
+static int isTemp = 0; /* is this a temp file? */
+static int force = 0; /* overwrite existing file */
+static int acol = -1; /* access reference column */
+static int tcol = -1; /* image type column */
+static int filenum = 0; /* running download file number */
+
+static int nthreads = MIN_THREADS; /* number of download threads */
+static int maxTrys = MAX_TRYS; /* download attempts */
+
+static char *base = NULL; /* output base filename */
+static char *extn = NULL; /* output filename extension */
+static char *dir = NULL; /* download directory */
+static char *afname = NULL; /* output acref filename */
+
+static char *acref = NULL; /* acref url */
+static char *acref_ucd = NULL; /* acref UCD */
+static char *fmt = NULL; /* image format */
+static char *fmt_ucd = NULL; /* image format UCD */
+
+static FILE *afd = (FILE *) NULL; /* acref file descriptor */
+
+static pthread_mutex_t counter_mut = PTHREAD_MUTEX_INITIALIZER;
+
+typedef void (*SIGFUNC)(); /* signal handler type */
+
+typedef struct {
+ char url[SZ_URL]; /* access URL */
+ char fname[SZ_URL]; /* local filename */
+ int tnum; /* worker thread number */
+} Acref, *AcrefP;
+
+Acref aclist[MAX_DOWNLOADS]; /* access list */
+
+
+/* Task specific option declarations.
+ */
+int votget (int argc, char **argv, size_t *len, void **result);
+
+static Task self = { "votget", votget, 0, 0, 0 };
+static char *opts = "%:hb:e:f:dstu:o:vxA:BCD:F:N:Sm:";
+static struct option long_opts[] = {
+ { "base", 1, 0, 'b'}, /* task option */
+ { "extn", 1, 0, 'e'}, /* task option */
+ { "fmt", 1, 0, 'f'}, /* task option */
+ { "sum", 2, 0, 's'}, /* task option */
+ { "tmp", 2, 0, 't'}, /* task option */
+ { "ucd", 1, 0, 'u'}, /* task option */
+ { "output", 1, 0, 'o'}, /* task option */
+ { "verbose", 2, 0, 'v'}, /* task option */
+ { "extract", 2, 0, 'x'}, /* task option */
+ { "acref", 1, 0, 'A'}, /* task option */
+ { "bkg", 2, 0, 'B'}, /* task option */
+ { "cache", 2, 0, 'C'}, /* task option */
+ { "download", 1, 0, 'D'}, /* task option */
+ { "fmtcol", 1, 0, 'F'}, /* task option */
+ { "num", 1, 0, 'N'}, /* task option */
+ { "force", 2, 0, 'O'}, /* task option */
+ { "samp", 2, 0, 'S'}, /* task option */
+ { "mtype", 1, 0, 'm'}, /* task option */
+
+ { "help", 2, 0, 'h'}, /* required */
+ { "debug", 2, 0, 'd'}, /* required */
+ { "test", 1, 0, '%'}, /* required */
+ { NULL, 0, 0, 0 }
+};
+
+static int do_return = 0; /* NOT USED */
+static int do_samp = 0; /* samp listener? */
+static char *mtype = NULL; /* samp mtype */
+
+
+static void Usage (void);
+static void Tests (char *input);
+
+
+/* Public methods.
+ */
+extern int vot_isValidFormat (char *fmt);
+extern int vot_atoi (char *val);
+extern int vot_sum32 (char *str);
+extern char *strcasestr ();
+
+
+/* Private methods.
+ */
+static void votableHandler (char *url, char *tblId, char *name);
+
+static int vot_procFile (char *iname);
+static int vot_isVOTable (char *infile);
+static int vot_acrefColumn (handle_t tab);
+static int vot_typeColumn (handle_t tab);
+static int vot_loadText (char *infile);
+static int vot_loadVOTable (char *infile);
+static int vot_getData (char *url, char *ofname);
+
+static void vot_saveAcref (char *acref, int num, int fnum);
+static void *vot_getAclist (void *arg);
+static void vot_printAclist ();
+static void vot_reaper (int sig, int *arg1, int *arg2);
+
+
+
+
+/**
+ * Program entry point.
+ */
+int
+votget (int argc, char **argv, size_t *reslen, void **result)
+{
+ char **pargv, optval[SZ_FNAME];
+ char *iname = NULL, ch;
+ int samp = 0, pos = 0, stat = OK;
+
+
+ /* Initialize.
+ */
+ *reslen = 0;
+ *result = NULL;
+
+
+ /* Parse the argument list.
+ */
+ pargv = vo_paramInit (argc, argv, opts, long_opts);
+ while ((ch = vo_paramNext (opts,long_opts,argc,pargv,optval,&pos)) != 0) {
+ if (ch > 0) {
+
+ switch (ch) {
+ case '%': Tests (optval); return (self.nfail);
+ case 'h': Usage (); return (OK);
+
+ case 'b': base = strdup (optval); break;
+ case 'e': extn = strdup (optval); break;
+ case 'f': if (!vot_isValidFormat ((fmt = strdup (optval)))) {
+ fprintf (stderr, "Error: invalid format '%s'\n",
+ fmt);
+ return (ERR);
+ }
+ break;
+ case 'd': debug++; break;
+ case 's': seq=0; break;
+ case 't': isTemp++; break;
+ case 'u': acref_ucd = strdup (optval); break;
+
+ case 'o': afname = strdup (optval); break;
+ case 'v': verbose++; break;
+ case 'x': extract++; break;
+
+ case 'A': acol = vot_atoi (optval); break;
+ case 'B': detach++; break;
+ case 'C': isCache++; break;
+ case 'D': dir = strdup (optval); break;
+ case 'F': tcol = vot_atoi (optval); break;
+ case 'N': nthreads = vot_atoi (optval); break;
+ case 'O': force++; break;
+ case 'S': do_samp++; break;
+ case 'm': mtype = strdup (optval);; break;
+
+ default:
+ fprintf (stderr, "Invalid option '%c'\n", ch);
+ return (1);
+ }
+
+ } else if (ch == PARG_ERR) {
+ return (ERR);
+
+ } else {
+ iname = strdup (optval);
+ }
+ }
+
+
+ /* Sanity checks
+ */
+ if (iname == NULL) iname = strdup ("stdin");
+ if (strcmp (iname, "-") == 0) { free (iname), iname = strdup ("stdin"); }
+
+
+ /* Setup defaults and initialize.
+ */
+ do_return = 0;
+ memset (&aclist[0], 0, (sizeof (Acref) * MAX_DOWNLOADS));
+
+ if (afname && (afd = fopen (afname, "a+")) == (FILE *) NULL) {
+ if (verbose)
+ fprintf (stderr, "Error: cannot open aclist file '%s'\n", afname);
+ return (ERR);
+ }
+
+ if (!base) base = strdup ("file");
+ if (!mtype) mtype = strdup ("table.load.votable");
+ if (!fmt_ucd) fmt_ucd = strdup (FORMAT_UCD);
+ if (!acref_ucd) acref_ucd = strdup (ACREF_UCD);
+
+
+ if (do_samp) {
+ /* Initialize and startup the SAMP interface. Wait for a message.
+ */
+ if (verbose)
+ fprintf (stderr, "Initializing samp ....\n");
+ samp = sampInit ("votget", "VOClient Task");
+ samp_Subscribe (samp, mtype, votableHandler);
+ if (sampStartup (samp) < 0)
+ return (ERR);
+
+ if (verbose)
+ fprintf (stderr, "Type <cr> to quit ....");
+ while (fgetc(stdin) != EOF)
+ break;
+
+ sampShutdown (samp);
+
+ } else {
+ /* Process the file.
+ */
+ stat = vot_procFile (iname);
+ }
+
+
+ /* Close the table and clean up.
+ */
+ if (base) free (base);
+ if (extn) free (extn);
+ if (dir) free (dir);
+ if (afname) free (afname);
+ if (acref) free (acref);
+ if (acref_ucd) free (acref_ucd);
+ if (fmt) free (fmt);
+ if (fmt_ucd) free (fmt_ucd);
+ if (mtype) free (mtype);
+
+ vo_paramFree (argc, pargv);
+ if (detach)
+ exit (OK);
+ else
+ return (stat);
+}
+
+
+/**
+ * VOTABLEHANDLER -- Callback for the load.table.votable message.
+ */
+static void
+votableHandler (char *url, char *tblId, char *name)
+{
+ char fname[SZ_FNAME];
+
+
+ memset (fname, 0, SZ_FNAME);
+
+ if (verbose)
+ printf ("\n");
+
+
+ if (strncmp (url, "http://", 7) == 0) {
+ strcpy (fname, "/tmp/votgetXXXXXX"); /* temp download name */
+ mktemp (fname);
+ if (vot_getData (url, fname) < 0)
+ fprintf (stderr, "Error accessing url '%s'\n", url);
+
+ vot_procFile (fname);
+ unlink (fname);
+
+ } else if (strncmp (url, "file://", 7) == 0) {
+ strcpy (fname, &url[7]);
+ vot_procFile (fname);
+
+ } else {
+ fprintf (stderr, "Error: unsupported URL type '%s'\n", url);
+ return;
+ }
+
+ /* Clean up for the next file to process.
+ */
+ memset (&aclist[0], 0, (sizeof (Acref) * MAX_DOWNLOADS));
+ nfiles = 0;
+}
+
+
+/**
+ * VOT_PROCFILE -- Process a VOTable file.
+ */
+static int
+vot_procFile (char *iname)
+{
+ int stat = OK;
+
+
+ /* Determine the type of input file.
+ */
+ if (strncmp (iname, "http://", 7) == 0) {
+ if (vot_loadVOTable (iname) < 0) {
+ fprintf (stderr, "Error opening votable '%s'\n", iname);
+ return ( (stat = ERR) );
+ }
+
+ } else {
+ switch ((vot = vot_isVOTable (iname))) {
+ case -1: fprintf (stderr, "Error opening file '%s'\n", iname);
+ return ( (stat = ERR) );
+ case 0: if (vot_loadText (iname) < 0) {
+ fprintf (stderr, "Error opening text file '%s'\n", iname);
+ return ( (stat = ERR) );
+ }
+ break;
+ case 1: if (vot_loadVOTable (iname) < 0) {
+ fprintf (stderr, "Error opening votable '%s'\n", iname);
+ return ( (stat = ERR) );
+ }
+ break;
+ }
+ }
+
+
+ /* If all we're doing is extracting the URLs we can quit now.
+ */
+ if (extract)
+ return (OK);
+
+ if (debug) {
+ fprintf (stderr, "acol = %d tcol = %d\n", acol, tcol);
+ fprintf (stderr, "Downloading %d files ....\n", nfiles);
+ vot_printAclist ();
+ }
+
+
+ /* If we've been asked to detach, fork off to do the downloads in
+ * a child, and return to the caller.
+ */
+ if (detach) {
+ pid_t pid;
+
+ signal (SIGCHLD, (SIGFUNC)vot_reaper);
+ switch ((pid = fork ())) {
+ case -1: return (ERR); /* We are an error */
+ case 0: break; /* We are the child */
+ default: return (OK); /* We are the parent */
+ }
+ }
+
+
+ /* Initialize the download directory.
+ */
+ if (dir) {
+ if (access (dir, F_OK) < 0)
+ mkdir (dir, 0755);
+ if (access (dir, W_OK) < 0) {
+ if (verbose)
+ fprintf (stderr, "Error: Cannot write to directory '%s'\n", dir);
+ return (ERR);
+ }
+ chdir (dir);
+ }
+
+ /* Do the downloads.
+ */
+ if (nfiles < MIN_THREADS)
+ nthreads = nfiles;
+
+ if (nthreads == 1) {
+ vot_getAclist (NULL);
+
+ } else {
+ /* Spawn the worker threads.
+ */
+ int rc = 0, tc = 0, status = 0, tnum[MAX_THREADS];
+ pthread_attr_t attr; /* thread attributes */
+ pthread_t thread[MAX_THREADS];
+
+
+ /* Initialize the service processing thread attributes and run 'em.
+ */
+ pthread_attr_init (&attr);
+ pthread_attr_setdetachstate (&attr, PTHREAD_CREATE_JOINABLE);
+
+ if (verbose)
+ fprintf (stderr, "Starting download ....\r");
+
+ for (tc=0; tc < nthreads; tc++) {
+ tnum[tc] = tc;
+ if ((rc = pthread_create (&thread[tc], &attr, vot_getAclist,
+ (void *)&tnum[tc]))) {
+ fprintf (stderr, "ERROR: pthread_create() fails, code=%d\n",
+ rc);
+ return (-1);
+ }
+ }
+
+ /* Free attribute and wait for the threads to complete.
+ */
+ pthread_attr_destroy (&attr);
+ for (tc=0; tc < nthreads; tc++) {
+ if ((rc = pthread_join (thread[tc], (void **)&status)) ) {
+ if (rc != ESRCH) {
+ fprintf (stderr,
+ "ERROR: pthread_join() fails, code=%d status=%d\n",
+ rc, status);
+ return (-1);
+ }
+ }
+ }
+
+ if (verbose) {
+ fprintf (stderr,
+ "Downloaded %d files -- Download complete (Total: %d)\n",
+ nfiles, (filenum+1));
+ fflush (stderr);
+ }
+ }
+
+
+ /* Remove input file if it is temporary.
+ */
+ if (isTemp)
+ unlink (iname);
+
+ return (stat);
+}
+
+
+
+
+/**
+ * VOT_USAGE -- Print the task usage and exit.
+ */
+static void
+Usage (void)
+{
+ fprintf (stderr, "\n Usage:\n\t"
+ "votget [<opts>] [ <votable.xml> | <urls.txt> ]\n\t"
+ "votget [<opts>] --samp # to listen for SMAP messages\n"
+ "\n"
+ "Where\n"
+ " -b,--base <base> Base output filename\n"
+ " -e,--extn [<extn>] Extension to add to filename (or auto)\n"
+ " -f,--fmt <fmt> Download only specified <type>\n"
+ " -s,--sum Use 32-bit checksum as file numbers\n"
+ " -t,--tmp Input file is temporary, delete when done\n"
+ " -u,--ucd <ucd> Use ucd to identify acref column\n"
+ "\n"
+ " -o,--output <fname> Output filename (single download)\n"
+ " -v,--verbose Verbose output\n"
+ " -x,--extract Extract access references\n"
+ "\n"
+ " -A,--acref <colnum> Col number for acref column (0-indexed)\n"
+ " -B,--bkg Background, i.e. run in forked child\n"
+ " -C,--cache Cache the downloaded file\n"
+ " -D,--download Set download directory\n"
+ " -F,--fmtcol <colnum> Col number for format column (0-indexed)\n"
+ " -N,--num <N> Number of simultaneous downloads\n"
+ " -S,--samp start as SAMP listener\n"
+ "\n"
+ " -h,--help Print help summary\n"
+ " -d,--debug Debug output\n"
+ " --test Run unit tests\n"
+ "\n"
+ " <votable> VOTable to process\n"
+ "\n"
+ " Examples:\n\n"
+
+ " 1) Download all files in the VOTable 'results.xml', 3 files at\n"
+ " a time:\n\n"
+ " %% votget -N 3 results.xml\n"
+ "\n"
+ " 2) Start as a SAMP listener waiting for VOTable events to be \n"
+ " broadcast, saved files will begin with the string 'foo' and \n"
+ " contain a 'fits' filename extension:\n\n"
+ " %% votget -b foo -e fits -S\n"
+ "\n"
+ " To exit the task, hit the <CR>.\n"
+ "\n"
+ " 3) Download all the urls in the file 'urls.txt':\n\n"
+ " %% votget -b foo urls.txt\n"
+ "\n"
+ " 4) Extract all the access references in a VOTable:\n\n"
+ " %% votget -x results.xml\n"
+ "\n"
+ );
+}
+
+
+/**
+ * Tests -- Task unit tests.
+ */
+static void
+Tests (char *input)
+{
+ Task *task = &self;
+ char *urls = "http://iraf.noao.edu/votest/sia.xml\n";
+
+
+ vo_taskTest (task, "--help", NULL);
+
+ if (access (input, F_OK) != 0) {
+ fprintf (stderr, "Warning: cannot open file '%s'\n", input);
+ return;
+ }
+
+ vo_taskTestFile (urls, "urls.txt");
+
+ vo_taskTest (task, "-N", "3", input, NULL); // Ex 1
+ vo_taskTest (task, "-b", "foo", input, NULL); // Ex 3
+ vo_taskTest (task, "-x", input, NULL); // Ex 4
+ vo_taskTest (task, "-x", "-o", "/tmp/acref", input, NULL);
+
+ if (access ("/tmp/acref", F_OK) == 0) unlink ("/tmp/acref");
+ if (access ("urls.txt", F_OK) == 0) unlink ("urls.txt");
+
+ vo_taskTestReport (self);
+}
+
+
+
+/**********************************************************************
+** Private Procedures
+**********************************************************************/
+
+/**
+ * VOT_REAPER -- Catch a SIGCHLD signal and reap all children.
+ */
+static void
+vot_reaper (
+ int sig, /* signal which was trapped */
+ int *arg1, /* not used */
+ int *arg2 /* not used */
+)
+{
+ int status=0, pid=0;
+
+ while ((pid = waitpid ((pid_t) 0, &status, WNOHANG)) > 0)
+ ;
+}
+
+
+/**
+ * VOT_LOADTEXT -- Load the access list from a text file. We assume the
+ * list is simply one url per line.
+ */
+static int
+vot_loadText (char *infile)
+{
+ int i = 0, fd, nread = 0, tnum = 0, sz = 0;
+ char *acref, *buf, *ip;
+ struct stat info;
+
+
+ nfiles = 0;
+ memset (&aclist[0], 0, (sizeof (Acref) * MAX_DOWNLOADS));
+
+ if ((fd = open (infile, O_RDONLY)) < 0)
+ return (-1);
+
+ if (stat (infile, &info) < 0) /* read the whole file */
+ return (-1);
+ sz = info.st_size;
+ buf = calloc (sz + 1, sizeof(char));
+ nread = read (fd, buf, sz);
+ close (fd);
+
+ acref = buf; /* point to 1st url */
+ for (i=0; *acref; i++) {
+ for (ip=acref; *ip && *ip != '\n'; ip++)
+ ;
+ *ip = '\0';
+
+ vot_saveAcref (acref, i, filenum++);
+
+ acref = ip + 1;
+ nfiles++;
+ tnum++;
+ }
+
+ if (afd) /* close the acref file */
+ fclose (afd);
+
+ return (nfiles);
+}
+
+
+/**
+ * VOT_LOADVOTABLE -- Load the access list from a VOTable.
+ */
+static int
+vot_loadVOTable (char *infile)
+{
+ int i, tnum = 0;
+ int res, tab, data, tdata, tr;
+ char *acref;
+
+
+ nfiles = 0;
+ memset (&aclist[0], 0, (sizeof (Acref) * MAX_DOWNLOADS));
+
+ /* Open the table. This also parses it.
+ */
+ if ( (vot = vot_openVOTABLE (infile) ) <= 0) {
+ if (verbose)
+ fprintf (stderr, "Error opening VOTable '%s'\n", infile);
+ return (ERR);
+ }
+
+ /* Loop over all the resources in the file. In most cases there will
+ * only be one <RESOURCE>, if not then the selection applies to all
+ * valid tables.
+ */
+ for (res = vot_getRESOURCE (vot); res; res = vot_getNext (res)) {
+
+ /* Get the <TABLE> element.
+ */
+ if (! (tab = vot_getTABLE (res))) {
+ if (verbose) fprintf (stderr, "Error: No <TABLE> in <RESOURCE>\n");
+ continue;
+ }
+ if ((data = vot_getDATA (tab)))
+ tdata = vot_getTABLEDATA (data);
+ else
+ continue; /* empty data table */
+
+ /* Loop through the FIELDs to find the acref. Let the cmdline param
+ * override the acref column ucd.
+ */
+ acol = (acol < 0 ? vot_acrefColumn (tab) : acol);
+ tcol = (tcol < 0 ? vot_typeColumn (tab) : tcol);
+
+ /* Now scan the data table for acrefs. We got the acref column above
+ * so lookup the table cell directly for each row, either printing
+ * out the acref for a simple extract, or by adding to the access
+ * list to be processed below.
+ */
+ i = 0;
+ for (tr=vot_getTR (tdata); tr; tr=vot_getNext(tr)) {
+ acref = vot_getTableCell (tdata, i, acol);
+ if (tcol >= 0) {
+ char *format = vot_getTableCell (tdata, i, tcol);
+
+ if (format && fmt && strcasestr (format, fmt) == NULL)
+ continue;
+ }
+
+ vot_saveAcref (acref, i, filenum++);
+
+ nfiles++;
+ tnum++;
+ i++;
+ }
+ }
+
+
+ /* Clean up.
+ */
+ if (afd) /* close the acref file */
+ fclose (afd);
+
+ vot_closeVOTABLE (vot);
+
+ return (nfiles);
+}
+
+
+/**
+ * VOT_SAVEACREF -- Save the URL to the access list.
+ */
+static void
+vot_saveAcref (char *acref, int num, int fnum)
+{
+ if (afd)
+ fprintf (afd, "%s\n", acref);
+ else if (extract)
+ fprintf (stderr, "%s\n", acref);
+ else {
+ /* Save to the access list.
+ */
+ aclist[num].tnum = ((nthreads == 1) ? 0 : (num % nthreads));
+ strcpy (aclist[num].url, acref);
+ if (seq)
+ sprintf (aclist[num].fname, "%s%04d", base, (int) fnum);
+ else
+ sprintf (aclist[num].fname, "%s%d", base, vot_sum32 (acref));
+ }
+}
+
+
+/**
+ * VOT_ISVOTABLE -- Determine in the input file is a VOTable or URL @file.
+ * We return zero if the file cannot be parsed as a valid VOTable (i.e.
+ * we assume it is an @file of URLs), or else we return the root handle to
+ * the parsed file.
+ */
+
+#define SZ_READ 2880
+
+static int
+vot_isVOTable (char *infile)
+{
+ FILE *fd = (FILE *) NULL;
+ char buf[SZ_READ], fname[SZ_READ];
+ register int nread;;
+
+
+ memset (fname, 0, SZ_READ);
+ if (strncmp (infile, "file://", 7) == 0)
+ strcpy (fname, &infile[7]);
+ else
+ strcpy (fname, infile);
+
+ /* read the first 1024 bytes and search for a 'votable' string... */
+ if (access (fname, F_OK) < 0) {
+ if (verbose)
+ fprintf (stderr, "Error: Cannot open input file '%s'\n", fname);
+ return (-1);
+
+ } else if ((fd = fopen (fname, "r"))) {
+ memset (buf, 0, SZ_READ);
+ nread = fread (buf, sizeof (char), SZ_READ, fd);
+ fclose (fd);
+
+ return (strcasestr (buf, "votable") ? 1 : 0);
+ }
+ return ( 0 );
+}
+
+
+/**
+ * VOT_ACREFCOLUMN -- Determine the access column for the given table.
+ */
+static int
+vot_acrefColumn (handle_t tab)
+{
+ register int i = 0, acol = -1;
+ handle_t field;
+ char *ucd;
+
+
+ /* Loop through the FIELDs to find the acref.
+ */
+ for (field=vot_getFIELD(tab); field; field=vot_getNext(field),i++) {
+ ucd = vot_getAttr (field, "ucd");
+ if (ucd && strcasecmp (acref_ucd, ucd) == 0) {
+ acol = i;
+ break;
+ }
+ }
+
+ if (acol < 0) { /* make sure we found a column */
+ if (verbose)
+ fprintf (stderr, "Error: no acref column found (%s)\n", acref);
+ return (-1);
+ }
+
+ return (acol);
+}
+
+
+/**
+ * VOT_TYPECOLUMN -- Determine the type column for the given table.
+ */
+static int
+vot_typeColumn (handle_t tab)
+{
+ register int i = 0;
+ handle_t field;
+ char *ucd;
+
+
+ /* Loop through the FIELDs to find the type. Use a generous match.
+ */
+ if (tcol < 0) {
+ for (field=vot_getFIELD(tab); field; field=vot_getNext(field),i++) {
+ ucd = vot_getAttr (field, "ucd");
+ if (ucd && strcasestr (ucd, fmt_ucd)) {
+ tcol = i;
+ break;
+ }
+ }
+ }
+
+ return (tcol);
+}
+
+
+/**
+ * VOT_GETACLIST -- Download all the files for the specified thread.
+ */
+static void *
+vot_getAclist (void *arg)
+{
+ register int i, j, done = 0, ret = 0;
+ int threadNum = 0;
+
+
+ if (arg)
+ threadNum = *(int *)arg;
+
+ for (i=0; i < nfiles; i++) {
+ if (aclist[i].tnum == threadNum) {
+ for (j=0; j < maxTrys; j++) {
+ if ((ret = vot_getData (aclist[i].url, aclist[i].fname)))
+ break;
+ }
+ done += ret;
+ }
+ }
+
+/*
+ pthread_exit (NULL);
+*/
+ return ((void *) NULL);
+}
+
+
+/**
+ * VOT_GETDATA -- Utility routine to do a simple URL download to the file.
+ */
+static int
+vot_getData (char *url, char *ofname)
+{
+ int stat = 0;
+ char lockfile[SZ_FNAME], dot[SZ_FNAME], errBuf[CURL_ERROR_SIZE];
+ char fname[SZ_FNAME], ffname[SZ_FNAME];
+ FILE *fd;
+ CURL *curl_handle;
+
+
+ /* FIXME */
+ if (extn)
+ sprintf (ffname, "%s.%s", ofname, extn);
+ else {
+ sprintf (ffname, "%s.fits", ofname);
+ }
+
+ if (access (ofname, F_OK) == 0 || access (ffname, F_OK) == 0) {
+ /* file already exists */
+ if (force)
+ unlink (ofname);
+ else
+ return (1);
+ }
+
+
+ /* Initialize the lock file.
+ */
+ memset (lockfile, 0, SZ_FNAME);
+ memset (dot, 0, SZ_FNAME);
+
+ sprintf (lockfile, ".%s.LOCK", ofname);
+ sprintf (dot, ".%s", ofname);
+
+ if (access (lockfile, F_OK) == 0 && access (dot, F_OK) < 0) {
+ /* Download currently in progress, perhaps on another thread?
+ */
+ return (0);
+ } else if (access (lockfile, F_OK) == 0 && access (dot, F_OK) == 0) {
+ /* Download complete, stray lockfile.
+ */
+ unlink (lockfile);
+ } else if (access (lockfile, F_OK) < 0) {
+ /* No lock file, create one.
+ */
+ creat (lockfile, O_CREAT);
+ }
+
+
+ /* Append filename extension if specified.
+ */
+ if (extn)
+ sprintf (fname, "%s.%s", ofname, extn);
+ else
+ strcpy (fname, ofname);
+
+
+ /* For the CURL operation to download the file.
+ */
+ curl_global_init (CURL_GLOBAL_ALL); /* init curl session */
+ curl_handle = curl_easy_init ();
+
+ /* Open the output file.
+ */
+ if ((fd = fopen (fname, "wb")) == NULL) {
+ if (verbose)
+ fprintf (stderr, "Error: cannot open output file '%s'\n", fname);
+ curl_easy_cleanup (curl_handle);
+ return 0;
+ }
+
+ /* Set cURL options
+ */
+ curl_easy_setopt (curl_handle, CURLOPT_URL, url);
+ curl_easy_setopt (curl_handle, CURLOPT_NOPROGRESS, 1L);
+ curl_easy_setopt (curl_handle, CURLOPT_WRITEDATA, fd);
+ curl_easy_setopt (curl_handle, CURLOPT_ERRORBUFFER, errBuf);
+ curl_easy_setopt (curl_handle, CURLOPT_FOLLOWLOCATION, 1);
+
+ /* Do the download.
+ */
+ if ((stat = curl_easy_perform (curl_handle)) != 0) {
+ /* Error in download, clean up.
+ */
+ if (verbose)
+ fprintf (stderr, "Error: can't download '%s' : %s\n", url, errBuf);
+ unlink (fname); unlink (lockfile);
+ fclose (fd); /* close the file */
+ curl_easy_cleanup (curl_handle); /* cleanup curl stuff */
+ return (0);
+ }
+
+ fflush (fd);
+ fclose (fd); /* close the file */
+ curl_easy_cleanup (curl_handle); /* cleanup curl stuff */
+
+ /* Save the URL to a "dotfile" is we're downloading to a cache.
+ */
+ if (isCache) {
+ if ((fd = fopen (dot, "w")) == NULL) { /* open cache file */
+ if (verbose)
+ fprintf (stderr, "Error: cannot open cache file '%s'\n", dot);
+ return 0;
+ }
+ fprintf (fd, "%s\n", url);
+ fclose (fd);
+ }
+
+ /* If we didn't specify an extension, try to determin the file type
+ * automatically.
+ */
+ if (!extn) {
+ int i = 0, dfd, maxtrys = 30;
+
+ if ((dfd = open (fname, O_RDONLY)) > 0) {
+ char buf[1024], new[SZ_FNAME];
+ unsigned short *s = (unsigned short *) NULL;
+
+ (void) read (dfd, buf, 1024);
+
+ s = (unsigned short *) buf;
+ memset (new, 0, SZ_FNAME);
+ if ((s[0] == 35615 && s[1] == 2056) || /* GZIP file */
+ (s[0] == 8075 && s[1] == 2048)) {
+ char gz[SZ_FNAME], cmd[SZ_FNAME];
+
+ memset (gz, 0, SZ_FNAME);
+ sprintf (gz, "%s.gz", fname);
+ memset (cmd, 0, SZ_FNAME);
+ sprintf (cmd, "gunzip %s", gz);
+
+ rename (fname, gz); /* FIXME !!! */
+ system (cmd);
+
+ close (dfd);
+ if ((dfd = open (fname, O_RDONLY)) > 0) {
+ (void) lseek (dfd, 0, SEEK_SET);
+ (void) read (dfd, buf, 1024);
+ }
+ }
+
+ memset (new, 0, SZ_FNAME);
+ if (strncmp ("SIMPLE", buf, 6) == 0) { /* FITS */
+ sprintf (new, "%s.fits", fname);
+ rename (fname, new);
+ for (i=0; i < maxtrys; i++) {
+ if (access (new, F_OK) != 0)
+ sleep (1);
+ }
+ }
+
+ close (dfd);
+ }
+ }
+
+ pthread_mutex_lock (&counter_mut);
+ ngot++;
+ if (verbose) {
+ fprintf (stderr, "Downloaded %d of %d files ....\r", ngot, nfiles);
+ fflush (stderr);
+ }
+ pthread_mutex_unlock (&counter_mut);
+
+ /* Remove the lock file to indicate we are done.
+ */
+ unlink (lockfile);
+
+ return (1);
+}
+
+
+
+/******************************************************************************
+** Debug Utilities
+******************************************************************************/
+
+/**
+ * VOT_GETACLIST -- Download all the files for the specified thread.
+ */
+static void
+vot_printAclist ()
+{
+ register int i;
+
+ fprintf (stderr, "\nAccess List: nfiles = %d\n", nfiles);
+ for (i=0; i < nfiles; i++) {
+ fprintf (stderr, "%2d: url='%20.20s...' fname='%s' tnum=%d\n",
+ i, aclist[i].url, aclist[i].fname, aclist[i].tnum);
+ }
+}
diff --git a/vendor/voclient/voapps/votinfo.c b/vendor/voclient/voapps/votinfo.c
new file mode 100644
index 00000000..2a89e703
--- /dev/null
+++ b/vendor/voclient/voapps/votinfo.c
@@ -0,0 +1,455 @@
+/*
+ * VOTINFO -- Print information about the structure of a VOTable.
+ *
+ * Usage:
+ * votinfo [-v] [-w] <votable>
+ *
+ * @file votinfo.c
+ * @author Mike Fitzpatrick
+ * @date 6/03/11
+ *
+ * @brief Print information about the structure of a VOTable.
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+
+#include "voApps.h"
+#include "votParse.h"
+
+#define N_ITEMS "|param|info|rows|cols|resources|"
+
+#define N_PARAMS 0 /* numberOf values */
+#define N_INFO 1
+#define N_ROWS 2
+#define N_COLS 3
+#define N_RESOURCES 4
+
+#define SZ_RESBUF 8192
+
+
+static int vot = 0; /* VOTable handle */
+static int size = 0; /* print size only */
+static int warn = 0; /* warning options */
+static int numberOf = 0; /* element values */
+static int verbose = 0; /* verbose output */
+static int getCols = 0; /* get column names */
+static int getDesc = 0; /* get <DESCRIPTION> */
+static int getInfo = 0; /* get <INFO> */
+static int getParam = 0; /* get <PARAM> */
+static int getQuery = 0; /* get <INFO> QUERY_STATUS val */
+static int do_return = 0; /* return result? */
+
+static char resbuf[SZ_RESBUF]; /* result buffer */
+
+
+/* Task specific option declarations.
+ */
+int votinfo (int argc, char **argv, size_t *len, void **result);
+
+static Task self = { "votinfo", votinfo, 0, 0, 0 };
+
+static char *opts = "%:bc::dhin:pqrsvw";
+static struct option long_opts[] = {
+ { "test", 1, 0, '%'},
+ { "help", 2, 0, 'h'},
+ { "brief", 2, 0, 'b'},
+ { "columns", 2, 0, 'c'},
+ { "description", 2, 0, 'd'},
+ { "info", 2, 0, 'i'},
+ { "numberOf", 1, 0, 'n'},
+ { "param", 2, 0, 'p'},
+ { "query_status", 2, 0, 'q'},
+ { "return", 2, 0, 'r'},
+ { "size", 2, 0, 's'},
+ { "verbose", 2, 0, 'v'},
+ { "warn", 2, 0, 'w'},
+ { NULL, 0, 0, 0 }
+};
+
+
+static void Usage (void);
+static void Tests (char *input);
+
+extern void ppMultiLine (char *result, int poffset, int pwidth, int maxchars);
+extern int strdic (char *in_str, char *out_str, int maxchars, char *dict);
+
+
+
+/**
+ * Application entry point.
+ */
+int
+votinfo (int argc, char **argv, size_t *reslen, void **result)
+{
+ char *iname, *id, *name, *ucd, *desc, *value, *numpar = NULL, *clist=NULL;
+ char **pargv, optval[SZ_FNAME], param[SZ_FNAME];
+ int res, tab, data, tdata, field, handle, status = OK;
+ int i, nlen, ncols, nrows, pos, ch;
+
+
+ /* Initialize.
+ */
+ size = 0;
+ warn = 0;
+ verbose = 0;
+ iname = NULL;
+ memset (param, 0, SZ_FNAME);
+ memset (optval, 0, SZ_FNAME);
+ memset (resbuf, 0, SZ_RESBUF);
+
+ *reslen = 0;
+ *result = NULL;
+
+
+ /* Parse the argument list.
+ */
+ pargv = vo_paramInit (argc, argv, opts, long_opts);
+ while ((ch = vo_paramNext (opts,long_opts,argc,pargv,optval,&pos)) != 0) {
+ if (ch > 0) {
+ switch (ch) {
+ case '%': Tests (optval); return (self.nfail);
+ case 'h': Usage (); return (OK);
+
+ case 'b': verbose=0; break;
+ case 'c':
+ if (optval[0]) {
+ if (optval[0] == 'i') { /* ID */
+ clist = "id";
+ } else if (optval[0] == 'n') { /* NAME */
+ clist = "name";
+ } else if (optval[0] == 'u') { /* UCD */
+ clist = "ucd";
+ }
+ }
+ getCols=1; break;
+ case 'd': getDesc=1; break;
+ case 'i': getInfo=1; break;
+ case 'n': numberOf++, numpar = strdup (optval); break;
+ case 'p': getParam=1; break;
+ case 'q': getQuery=1; break;
+ case 'r': do_return=1; break;
+ case 's': size++; break;
+ case 'v': verbose++; break;
+ case 'w': warn++; break;
+ default:
+ fprintf (stderr, "Invalid option '%s'\n", optval);
+ return (1);
+ }
+
+ } else if (ch == PARG_ERR) {
+ return (ERR);
+
+ } else {
+ iname = strdup (optval);
+ break;
+ }
+ }
+
+
+ /* Sanity checks
+ */
+ if (iname == NULL)
+ iname = strdup ("stdin");
+ vot_setWarnings (warn);
+
+ /* Open the table. This also parses it.
+ */
+ if ( (vot = vot_openVOTABLE (iname) ) <= 0) {
+ fprintf (stderr, "Error opening VOTable '%s'\n", iname);
+ return (1);
+ }
+
+ res = vot_getRESOURCE (vot); /* get handles */
+ tab = vot_getTABLE (res);
+ if ((data = vot_getDATA (tab))) {
+ tdata = vot_getTABLEDATA (data);
+ nrows = vot_getNRows (tdata);
+ ncols = vot_getNCols (tdata);
+ } else
+ tdata = nrows = ncols = 0;
+
+ if (numberOf) {
+ switch (strdic (numpar, param, SZ_FNAME, N_ITEMS)) {
+ case N_PARAMS:
+ if ((handle = vot_getPARAM (res)) > 0) {
+ if (do_return)
+ vo_setResultFromInt (vot_getLength(handle), reslen, result);
+ else
+ printf ("%d\n", vot_getLength(handle));
+ } else
+ printf ("0\n");
+ break;
+ case N_INFO:
+ if ((handle = vot_getINFO (res)) > 0) {
+ if (do_return)
+ vo_setResultFromInt (vot_getLength(handle), reslen, result);
+ else
+ printf ("%d\n", vot_getLength(handle));
+ } else
+ printf ("0\n");
+ break;
+ case N_ROWS:
+ if (do_return)
+ vo_setResultFromInt (nrows, reslen, result);
+ else
+ printf ("%d\n", nrows);
+ break;
+ case N_COLS:
+ if (do_return)
+ vo_setResultFromInt (ncols, reslen, result);
+ else
+ printf ("%d\n", ncols);
+ break;
+ case N_RESOURCES:
+ if (do_return)
+ vo_setResultFromInt (vot_getLength (res), reslen, result);
+ else
+ printf ("%d\n", vot_getLength (res));
+ break;
+ default:
+ fprintf (stderr, "Unknown number request '%s'\n", param);
+ status = ERR;
+ }
+
+
+ } else if (size) {
+ if (do_return) {
+ sprintf (resbuf, "%d %d", nrows, ncols);
+ vo_setResultFromString (resbuf, reslen, result);
+ } else
+ printf ("%d %d\n", nrows, ncols);
+
+
+ } else if (getCols) {
+
+ printf ("%3s %20.20s\t%20.20s\t%20.20s\n", "Col",
+ "ID", "Name", "UCD");
+ printf ("%3s %20.20s\t%20.20s\t%20.20s\n", "===", "==", "====", "===");
+
+ for (i=1, field = vot_getFIELD(tab); field; field=vot_getNext (field)) {
+ id = vot_getAttr (field, "id");
+ name = vot_getAttr (field, "name");
+ ucd = vot_getAttr (field, "ucd");
+
+ printf ("%3d %20.20s\t%20.20s\t%20.20s\n", i,
+ (id ? id : "(none)"), (name ? name : "(none)"),
+ (ucd ? ucd : "(none)"));
+ if (verbose) {
+ if ( (desc = vot_getValue (vot_getDESCRIPTION (field))) )
+ printf ("\t Desc: %-s\n", desc);
+ }
+ i++;
+ }
+
+
+ } else if (getDesc) {
+ char *desc = NULL;
+
+ if ((handle = vot_getDESCRIPTION (vot)))
+ desc = vot_getValue (handle);
+ else if ((handle = vot_getDESCRIPTION (res)))
+ desc = vot_getValue (handle);
+ else
+ desc = "none";
+ if (do_return)
+ vo_setResultFromString ((desc ? desc : "none"), reslen, result);
+ else
+ printf ("%s\n", (desc ? desc : "none"));
+
+
+ } else if (getParam || getInfo) {
+ handle = (getParam ? vot_getPARAM (res) : vot_getINFO (res));
+ if (handle > 0) {
+ char buf[SZ_FNAME];
+
+ nlen = vot_getLength (handle);
+ for (nlen-- ; handle; handle = vot_getNext (handle), nlen--) {
+ name = vot_getAttr (handle, "name");
+ value = vot_getAttr (handle, "value");
+ memset (buf, 0, SZ_FNAME);
+ sprintf (buf, "%s = %s\n", name, value);
+ strcat (resbuf, buf);
+ }
+
+ if (do_return)
+ vo_setResultFromString (resbuf, reslen, result);
+ else
+ printf ("%s", resbuf);
+ }
+
+
+ } else if (getQuery) {
+ int found = 0, resval = 0;
+
+ if ((handle = vot_getINFO (res)) > 0) {
+ nlen = vot_getLength (handle);
+ for (nlen-- ; handle; handle = vot_getNext (handle), nlen--) {
+ name = vot_getAttr (handle, "name");
+ if (name && strncasecmp (name, "QUERY_STATUS", 12) == 0) {
+ value = vot_getAttr (handle, "value");
+ found++;
+ break;
+ }
+ }
+ }
+
+ resval = (found ? (strncasecmp (value, "OK", 2) != 0) : -1);
+ if (do_return)
+ vo_setResultFromInt (resval, reslen, result);
+ else
+ printf ("%d\n", resval);
+
+
+ } else {
+ /* Print a table summary.
+ */
+ printf ("%s\n\n", (iname[0] == '-' ? "stdin" : iname));
+ printf (" Resources: %d\tType: %-12s\t"
+ " Table Size: %d x %d\n",
+ vot_getLength (res), vot_getDATATypeString (data), ncols, nrows);
+
+ if ((handle = vot_getINFO (res)) > 0)
+ printf (" INFO: %d\n", vot_getLength (handle));
+
+ if ((handle = vot_getPARAM (res)) > 0)
+ printf (" PARAM: %d\t",
+ (nlen=vot_getLength (handle)));
+ for (nlen-- ; handle; handle=vot_getNext(handle),nlen--) {
+ if ((name = vot_getAttr (handle, "id")) == NULL)
+ if ((name = vot_getAttr (handle, "name")) == NULL)
+ name = "<noname>";
+ value = vot_getAttr (handle, "value");
+ printf ("%s = %s ", name, value);
+ if (nlen)
+ printf ("\n\t\t\t");
+ }
+ printf ("\n");
+
+#ifdef OLD_VOTABLE
+ if ((handle = vot_getCOOSYS (res)))
+ printf (" COOSYS: %d\n", vot_getLength (handle));
+#endif
+
+ if ((handle = vot_getDESCRIPTION (res))) {
+ desc = vot_getValue (handle);
+ printf (" Description: ");
+ ppMultiLine (desc, 16, 60, 4096);
+ printf ("\n");
+ }
+
+
+ /* Print the column info in verbose mode.
+ */
+ if (verbose) {
+ printf ("\n\t\t\tName\t\t\tUCD\n");
+ i = 0;
+ for (field=vot_getFIELD(tab); field; field=vot_getNext (field)) {
+ name = vot_getAttr (field, "name");
+ ucd = vot_getAttr (field, "ucd");
+
+ printf (" Field %2d: %-20s\t%-30s\n",
+ ++i, (name ? name : ""), (ucd ? ucd : ""));
+ if (verbose > 1) {
+ if ( (desc = vot_getValue (vot_getDESCRIPTION (field))) )
+ printf ("\t Desc: %-s\n", desc);
+ }
+ }
+ }
+ }
+
+ if (iname) free (iname);
+
+ vo_paramFree (argc, pargv);
+ vot_closeVOTABLE (vot); /* close the table */
+
+ return (status);
+}
+
+
+/**
+ * USAGE -- Print task help summary.
+ */
+static void
+Usage (void)
+{
+ fprintf (stderr, "\n Usage:\n\t"
+ "votinfo [<opts>] votable.xml\n\n"
+ " where\n"
+ " -b,--brief brief output\n"
+ " -d,--description print <DESCRIPTION> elements\n"
+ " -h,--help this message\n"
+ " -i,--info print <INFO> elements\n"
+ " -n,--numberOf=<what> get number of specified elements\n"
+ " -p,--param print <PARAM> elements\n"
+ " -q,--query_status print QUERY_STATUS\n"
+ " -r,--return return result from method\n"
+ " -s,--size print table size\n"
+ " -v,--verbose verbose otuput\n"
+ " -w,--warn print parser warnings\n"
+ "\n"
+ " <what> is one of\n"
+ " param <PARAM> elements\n"
+ " info <INFO> elements\n"
+ " rows table rows\n"
+ " cols table cols\n"
+ " resources <RESOURCE> elements\n"
+ "\n"
+ " Examples:\n\n"
+ " 1) Print summary information about a VOTable\n\n"
+ " %% votinfo -v test.xml\n"
+ "\n"
+ " 2) Print the <PARAM> elements in a table, then get a count\n\n"
+ " %% votinfo -p test.xml\n"
+ " %% votinfo --numberOf=param test.xml\n"
+ "\n"
+ " 3) Determine whether a VOTable contains a successful result\n\n"
+ " %% votinfo -q test.xml\n\n"
+ " A zero indicates 'OK', a one is an 'ERR', and -1 means that\n"
+ " an <INFO> with a 'QUERY_STATUS' was not found\n"
+ "\n"
+ );
+}
+
+
+/**
+ * Tests -- Task unit tests.
+ */
+static void
+Tests (char *input)
+{
+ Task *task = &self;
+
+ vo_taskTest (task, "--help", NULL);
+
+ if (access (input, F_OK) != 0) {
+ fprintf (stderr, "Warning: cannot open file '%s'\n", input);
+ return;
+ }
+
+ vo_taskTest (task, "-v", input, NULL); // Ex 1
+ vo_taskTest (task, "-p", input, NULL); // Ex 2
+ vo_taskTest (task, "--numberOf=param", input, NULL); // Ex 3
+ vo_taskTest (task, "--numberOf=info", input, NULL);
+ vo_taskTest (task, "--numberOf=rows", input, NULL);
+ vo_taskTest (task, "--numberOf=cols", input, NULL);
+ vo_taskTest (task, "--numberOf=resource", input, NULL);
+
+ vo_taskTest (task, "-n", "param", input, NULL);
+ vo_taskTest (task, "-n", "info", input, NULL);
+ vo_taskTest (task, "-n", "rows", input, NULL);
+ vo_taskTest (task, "-n", "cols", input, NULL);
+ vo_taskTest (task, "-n", "resource", input, NULL);
+
+ vo_taskTest (task, "-q", input, NULL); // Ex 4
+
+ vo_taskTest (task, "-b", input, NULL);
+ vo_taskTest (task, "-i", input, NULL);
+ vo_taskTest (task, "-d", input, NULL);
+ vo_taskTest (task, "-s", input, NULL);
+
+ vo_taskTestReport (self);
+}
diff --git a/vendor/voclient/voapps/votjoin.c b/vendor/voclient/voapps/votjoin.c
new file mode 100644
index 00000000..49853da4
--- /dev/null
+++ b/vendor/voclient/voapps/votjoin.c
@@ -0,0 +1,203 @@
+/*
+ * VOTJOIN -- Perform an inner-join of two VOTables.
+ *
+ * Usage:
+ * votjoin [<otps>] <votable>
+ *
+ * @file votjoin.c
+ * @author Mike Fitzpatrick
+ * @date 6/03/12
+ *
+ * @brief Perform an inner-join of two VOTables.
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+
+#include "votParse.h" /* keep these in order! */
+#include "voApps.h"
+
+
+
+/* Global task declarations. These should all be defined as 'static' to
+ * avoid namespace collisions.
+ */
+static int vot = 0; /* VOTable handle */
+static int do_return = 0; /* return result? */
+
+
+/* Result Buffer.
+ */
+#ifdef USE_RESBUF
+#define SZ_RESBUF 8192
+
+static char *resbuf;
+#endif
+
+
+/* Task specific option declarations. Task options are declared using the
+ * getopt_long(3) syntax.
+ */
+int votjoin (int argc, char **argv, size_t *len, void **result);
+
+static Task self = { "votjoin", votjoin, 0, 0, 0 };
+static char *opts = "hr";
+static struct option long_opts[] = {
+ { "help", 2, 0, 'h'}, /* --help is std */
+ { "return", 2, 0, 'r'}, /* --return is std */
+ { "test", 2, 0, '%'}, /* --return is std */
+ { NULL, 0, 0, 0 }
+};
+
+
+/* All tasks should declare a static Usage() method to print the help
+ * text in response to a '-h' or '--help' flag. The help text should
+ * include a usage summary, a description of options, and some examples.
+ */
+static void Usage (void);
+static void Tests (char *input);
+
+
+/**
+ * Application entry point.
+ */
+int
+votjoin (int argc, char **argv, size_t *reslen, void **result)
+{
+ char **pargv, optval[SZ_FNAME];
+ char *iname, *oname;
+ int ch = 0, status = OK, number = 0, pos = 0;
+
+
+ /* Initialize result object whether we return an object or not.
+ */
+ *reslen = 0;
+ *result = NULL;
+
+ /* Initialize local task values.
+ */
+ iname = NULL;
+ oname = NULL;
+ vot = -1;
+
+
+ /* Parse the argument list. The use of vo_paramInit() is required to
+ * rewrite the argv[] strings in a way vo_paramNext() can be used to
+ * parse them. The programmatic interface allows "param=value" to
+ * be passed in, but the getopt_long() interface requires these to
+ * be written as "--param=value" so they are not confused with
+ * positional parameters (i.e. any param w/out a leading '-').
+ */
+ pargv = vo_paramInit (argc, argv, opts, long_opts);
+ while ((ch = vo_paramNext(opts,long_opts,argc,pargv,optval,&pos)) != 0) {
+ if (ch > 0) {
+ /* If the 'ch' value is > 0 we are parsing a single letter
+ * flag as defined in the 'opts string.
+ */
+ switch (ch) {
+ case '%': Tests (optval); return (self.nfail);
+ case 'h': Usage (); return (OK);
+ case 'n': number++; break;
+ case 'o': oname = strdup (optval); break;
+ case 'r': do_return=1; break;
+ default:
+ fprintf (stderr, "Invalid option '%s'\n", optval);
+ return (1);
+ }
+
+ } else if (ch == PARG_ERR) {
+ return (ERR);
+
+ } else {
+ /* This code processes the positional arguments. The 'optval'
+ * string contains the value but since this string is
+ * overwritten w/ each arch we need to make a copy (and must
+ * remember to free it later.
+ */
+ iname = strdup (optval);
+ break;
+ }
+ }
+
+
+ /* Sanity checks. Tasks should validate input and accept stdin/stdout
+ * where it makes sense.
+ */
+ if (iname == NULL) iname = strdup ("stdin");
+ if (oname == NULL) oname = strdup ("stdout");
+ if (strcmp (iname, "-") == 0) { free (iname), iname = strdup ("stdin"); }
+ if (strcmp (oname, "-") == 0) { free (oname), oname = strdup ("stdout"); }
+
+
+
+
+ /********
+ ********
+ ********
+ ********
+ ******** Main body of task
+ ********
+ ********
+ ********
+ *******/
+
+
+
+
+ /* Clean up. Rememebr to free whatever pointers were created when
+ * parsing arguments.
+ */
+ if (iname)
+ free (iname);
+ if (oname)
+ free (oname);
+
+ vo_paramFree (argc, pargv);
+
+ return (status); /* status must be OK or ERR (i.e. 0 or 1) */
+}
+
+
+/**
+ * USAGE -- Print task help summary.
+ */
+static void
+Usage (void)
+{
+ fprintf (stderr, "\n Usage:\n\t"
+ "votjoin [<opts>] votable.xml\n\n"
+ " where\n"
+ " -%%,--test run unit tests\n"
+ " -h,--help this message\n"
+ " -n,--number number output\n"
+ " -o,--output=<file> output file\n"
+ " -r,--return return result from method\n"
+ "\n"
+ " Examples:\n\n"
+ " 1) First example\n\n"
+ " %% votjoin test.xml\n"
+ "\n"
+ " 2) Second example\n\n"
+ " %% votjoin -o pos.txt test.xml\n"
+ "\n"
+ );
+}
+
+
+/**
+ * Tests -- Task unit tests.
+ */
+static void
+Tests (char *input)
+{
+ Task *task = &self;
+
+
+ /* First argument must always be the 'self' variable, the last must
+ * always be a NULL to terminate the cmd args.
+ */
+ vo_taskTest (task, "--help", NULL);
+}
diff --git a/vendor/voclient/voapps/votopic.c b/vendor/voclient/voapps/votopic.c
new file mode 100644
index 00000000..990fad18
--- /dev/null
+++ b/vendor/voclient/voapps/votopic.c
@@ -0,0 +1,268 @@
+/**
+ * VOTOPIC -- Query VO services by keyword topic
+ *
+ * Usage:
+ * votopic [<opts>] [ <object> | <ra> <dec> ] [ <size> ]
+ *
+ * @file votopic.c
+ * @author Mike Fitzpatrick
+ * @date 2/03/13
+ *
+ * @brief Query all VO Image services.
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+
+#include "votParse.h" /* keep these in order! */
+#include "voApps.h"
+
+#define MAX_ARGS 1024
+
+
+/* Task specific option declarations. Task options are declared using the
+ * getopt_long(3) syntax.
+ */
+int voregistry (int argc, char **argv, size_t *len, void **result);
+int vodata (int argc, char **argv, size_t *len, void **result);
+int votopic (int argc, char **argv, size_t *len, void **result);
+
+static Task self = { "votopic", votopic, 0, 0, 0 };
+#ifdef USE_OPTS
+static char *opts = "%hrs";
+static struct option long_opts[] = {
+ { "test", 2, 0, '%'}, /* --test is std */
+ { "help", 2, 0, 'h'}, /* --help is std */
+ { "subject", 2, 0, 's'}, /* subject keywords */
+ { "return", 2, 0, 'r'}, /* return result to API */
+ { NULL, 0, 0, 0 }
+};
+#endif
+
+
+static int debug = 0; /* debug flag */
+static int by_subj = 0; /* subject search */
+
+extern void vot_setArg (char **argv, int *argc, char *value);
+extern char *vot_mktemp (char *root);
+extern int isDecimal (char *val);
+extern int isSexagesimal (char *val);
+
+static void Usage (void);
+static void Tests (char *input);
+
+
+/**
+ * Application entry point. All VOApps tasks MUST contain this
+ * method signature.
+ */
+int
+votopic (int argc, char **argv, size_t *reslen, void **result)
+{
+ int i, nres_arg = 0, ndat_arg = 0, status = OK, term = 0;
+ char *res_argv[MAX_ARGS], *dat_argv[MAX_ARGS], *topic = NULL;
+ char *resname;
+
+
+ memset (res_argv, 0, argc+2); /* initialize */
+ memset (dat_argv, 0, argc+2);
+ resname = vot_mktemp ("votopic");
+
+
+ /* Parse the argument list.
+ */
+ if ((isDecimal (argv[argc-1]) || isSexagesimal (argv[argc-1])) &&
+ (isDecimal (argv[argc-2]) || isSexagesimal (argv[argc-2])) &&
+ (isDecimal (argv[argc-3]) || isSexagesimal (argv[argc-3])) )
+ term = argc - 4;
+ if ((isDecimal (argv[argc-1]) || isSexagesimal (argv[argc-1])) &&
+ !(isDecimal (argv[argc-2]) || isSexagesimal (argv[argc-2])) )
+ term = argc - 3;
+ if (!(isDecimal (argv[argc-1]) || isSexagesimal (argv[argc-1])) )
+ term = argc - 2;
+
+ /* Initialize the VOREGISTRY arguments.
+ */
+ vot_setArg (res_argv, &nres_arg, "voregistry");
+
+ /* Initialize the VODATA arguments.
+ */
+ vot_setArg (dat_argv, &ndat_arg, "vodata");
+#ifdef OLD_METHOD
+ if (term <= 0) {
+ fprintf (stderr, "Error: missing <topic> and/or <object> argument\n");
+ return (ERR);
+ }
+
+ for (i=1; i < argc; i++) {
+ if (i == term) {
+ vot_setArg (dat_argv, &ndat_arg, resname);
+ topic = argv[i];
+ } else {
+ if (strcmp(argv[i],"-h")==0 || strcmp(argv[i],"--help")==0) {
+ Usage (); return (OK);
+ } else if (strcmp(argv[i],"-%")==0 || strcmp(argv[i],"--test")==0) {
+ Tests (NULL); return (self.nfail);
+ } else if (strcmp(argv[i],"-d")==0 || strcmp(argv[i],"--dbg")==0) {
+ debug++;
+
+ } else if (strcmp(argv[i],"-s")==0 ||
+ strcmp(argv[i],"--subject")==0) {
+ by_subj++;
+ } else if ((strcmp(argv[i],"-b")==0 ||
+ strcmp(argv[i],"--bpass")==0) ||
+ (strcmp(argv[i],"-t")==0 ||
+ strcmp(argv[i],"--type")==0)) {
+ vot_setArg (res_argv, &nres_arg, argv[ i]); /* -b | -t */
+ vot_setArg (res_argv, &nres_arg, argv[++i]); /* val */
+ } else
+ vot_setArg (dat_argv, &ndat_arg, argv[i]);
+ }
+ }
+
+#else
+ for (i=1; i < argc; i++) {
+ if (strcmp(argv[i],"-h")==0 || strcmp(argv[i],"--help")==0) {
+ Usage (); return (0);
+ } else if (strcmp(argv[i],"-%")==0 || strcmp(argv[i],"--test")==0) {
+ Tests (NULL); return (0);
+ } else if (strcmp(argv[i],"-d")==0 || strcmp(argv[i],"--dbg")==0) {
+ debug++;
+
+ } else if (strcmp(argv[i],"-s")==0 ||
+ strcmp(argv[i],"--subject")==0) {
+ by_subj++;
+ } else if ((strcmp(argv[i],"-b")==0 ||
+ strcmp(argv[i],"--bpass")==0) ||
+ (strcmp(argv[i],"-t")==0 ||
+ strcmp(argv[i],"--type")==0)) {
+ vot_setArg (res_argv, &nres_arg, argv[ i]); /* -b | -t */
+ vot_setArg (res_argv, &nres_arg, argv[++i]); /* val */
+ } else {
+ if (!topic) {
+ vot_setArg (dat_argv, &ndat_arg, resname);
+ topic = argv[i];
+ } else {
+ vot_setArg (dat_argv, &ndat_arg, argv[i]);
+ }
+ }
+ }
+
+ if (topic == NULL) {
+ fprintf (stderr, "Error: missing <topic> argument\n");
+ return (ERR);
+ } else if (ndat_arg < 3) {
+ fprintf (stderr, "Error: missing <object> (or <pos>) argument\n");
+ return (ERR);
+ }
+
+#endif
+
+
+ /* Create the list of VOREGISTRY arguments.
+ */
+ vot_setArg (res_argv, &nres_arg, "-d"); /* dalOnly */
+ vot_setArg (res_argv, &nres_arg, "-o"); /* output name */
+ vot_setArg (res_argv, &nres_arg, resname);
+ if (by_subj)
+ vot_setArg (res_argv, &nres_arg, "-s");
+ vot_setArg (res_argv, &nres_arg, topic);
+
+ if (debug) {
+ for (i=0; i < nres_arg; i++)
+ printf ("'%s' ", res_argv[i]);
+ printf ("\n");
+ for (i=0; i < ndat_arg; i++)
+ printf ("'%s' ", dat_argv[i]);
+ printf ("\n");
+ }
+
+
+ /* Run the Registry query to get the resource list of topics.
+ */
+ status = voregistry (nres_arg, res_argv, reslen, result);
+
+
+ /* Initialize result object whether we return an object or not.
+ */
+ *reslen = 0;
+ *result = NULL;
+
+ /* The VODATA task does all the real work, execute it on the list of
+ * resources we just obtained.
+ */
+ status = vodata (ndat_arg, dat_argv, reslen, result);
+
+
+ /* Clean up. Rememebr to free whatever pointers were created when
+ * parsing arguments.
+ */
+ for (i=0; i < nres_arg; i++)
+ if (res_argv[i]);
+ free ((void *) res_argv[i]);
+ for (i=0; i < ndat_arg; i++)
+ if (dat_argv[i]);
+ free ((void *) dat_argv[i]);
+ unlink (resname);
+
+ return (status);
+}
+
+
+/**
+ * USAGE -- Print task help summary.
+ */
+static void
+Usage (void)
+{
+ fprintf (stderr, "\n Usage:\n\t"
+ "votopic [<opts>] <topic> { <object> | <ra> <dec> } [ <size> ]\n\n"
+ " where\n"
+ " -%%,--test run unit tests\n"
+ " -h,--help this message\n"
+ "\n"
+ "\n"
+ " Examples:\n\n"
+ " 1) Query for catalog data of A2712 from Resources related to\n"
+ " gravitational lensing:\n"
+ "\n"
+ " %% votopic -t catalog lens A2712\n"
+ "\n"
+ " This query is against only 142 services (data found for 128),\n"
+ " a similar query against ALL catalog services would require\n"
+ " more than 8000 services to be queried. This is equivalent to\n"
+ " the commands:\n"
+ "\n"
+ " %% voregistry -t catalog -d -o lens.xml lens\n"
+ " %% vodata lens.xml A2712\n"
+ "\n"
+ " Here the 'lens.xml' output file contains the resources to be\n"
+ " queried, the '-d' flag says to return only DAL services, the\n"
+ " '-t' flag resticts by service type. In the call to VODATA,\n"
+ " the 'lens.xml' file defines the 142 resources to be queried,\n"
+ " the contraint to service type and DAL-only was done in the\n"
+ " registry query that produced the file.\n"
+ "\n"
+ "\n"
+ );
+}
+
+
+/**
+ * Tests -- Task unit tests.
+ */
+static void
+Tests (char *input)
+{
+ Task *task = &self;
+
+
+ vo_taskTest (task, "--help", NULL);
+
+ vo_taskTest (task, "-t", "catalog", "lens", "A2712", NULL);
+
+ vo_taskTestReport (self);
+}
diff --git a/vendor/voclient/voapps/votpos.c b/vendor/voclient/voapps/votpos.c
new file mode 100644
index 00000000..3b6b3fc9
--- /dev/null
+++ b/vendor/voclient/voapps/votpos.c
@@ -0,0 +1,249 @@
+/*
+ * VOTPOS -- Extract the main positional columns from a VOTable.
+ *
+ * Usage:
+ * votpos [<opts>] votable.xml
+ *
+ * where
+ * -%%,--test run unit tests
+ * -h,--help this message
+ * -n,--number number output
+ * -o,--output=<file> output file
+ * -r,--return return result from method
+ *
+ * @file votpos.c
+ * @author Mike Fitzpatrick
+ * @date 6/03/12
+ *
+ * @brief Extract the main positional columns from a VOTable.
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+#include <ctype.h>
+
+#include "votParse.h"
+#include "voApps.h"
+
+
+#define SZ_RESBUF 8192
+
+
+static int vot = 0; /* VOTable handle */
+static int number = 0; /* number values? */
+static int do_return = 0; /* return result? */
+
+#ifdef USE_RESBUF
+static char *resbuf; /* result buffer */
+#endif
+
+
+/* Task specific option declarations.
+ */
+int votpos (int argc, char **argv, size_t *len, void **result);
+
+static Task self = { "votpos", votpos, 0, 0, 0 };
+static char *opts = "hNno:r%:";
+static struct option long_opts[] = {
+ { "Number", 2, 0, 'N'}, /* task option */
+ { "number", 2, 0, 'n'}, /* task option */
+ { "output", 1, 0, 'o'}, /* task option */
+ { "return", 2, 0, 'r'}, /* task option */
+ { "help", 2, 0, 'h'}, /* required */
+ { "test", 1, 0, '%'}, /* required */
+ { NULL, 0, 0, 0 }
+};
+
+
+static void Usage (void);
+static void Tests (char *input);
+
+
+
+/**
+ * Application entry point.
+ */
+int
+votpos (int argc, char **argv, size_t *reslen, void **result)
+{
+ char **pargv, optval[SZ_FNAME], *iname = NULL, *oname = NULL, *ucd = NULL;
+ int res, tab, data, tdata, field, status = OK;
+ int i, ncols, nrows, pos = 0, ch, ra_col, dec_col;
+ int got_ra_col = 0, got_dec_col = 0;
+ FILE *fd = (FILE *) NULL;
+
+
+ /* Initialize.
+ */
+ oname = NULL;
+ iname = NULL;
+ *reslen = 0;
+ *result = NULL;
+
+ /* Parse the argument list.
+ */
+ pargv = vo_paramInit (argc, argv, opts, long_opts);
+ while ((ch = vo_paramNext (opts,long_opts,argc,pargv,optval,&pos)) != 0) {
+ if (ch > 0) {
+ switch (ch) {
+ case '%': Tests (optval); return (self.nfail);
+ case 'h': Usage (); return (OK);
+ case 'N': number=-1; break;
+ case 'n': number=+1; break;
+ case 'o': oname = strdup (optval); break;
+ case 'r': do_return=1; break;
+ default:
+ fprintf (stderr, "Invalid option '%s'\n", optval);
+ return (1);
+ }
+
+ } else if (ch == PARG_ERR) {
+ return (ERR);
+
+ } else {
+ iname = strdup (optval);
+ break;
+ }
+ }
+
+
+ /* Sanity checks
+ */
+ if (iname == NULL) iname = strdup ("stdin");
+ if (oname == NULL) oname = strdup ("stdout");
+ if (strcmp (iname, "-") == 0) { free (iname), iname = strdup ("stdin"); }
+ if (strcmp (oname, "-") == 0) { free (oname), oname = strdup ("stdout"); }
+
+
+ /* Open the table. This also parses it.
+ */
+ if ( (vot = vot_openVOTABLE (iname) ) <= 0) {
+ fprintf (stderr, "Error opening VOTable '%s'\n", iname);
+ return (1);
+ }
+
+ res = vot_getRESOURCE (vot); /* get handles */
+ if (vot_getLength (res) > 1) {
+ fprintf (stderr, "Error: multiple RESOURCE elements not supported\n");
+ goto clean_up_;
+ }
+ tab = vot_getTABLE (res);
+ if ((data = vot_getDATA (tab))) {
+ tdata = vot_getTABLEDATA (data);
+ nrows = vot_getNRows (tdata);
+ ncols = vot_getNCols (tdata);
+ } else
+ goto clean_up_;
+
+
+ /* Find the columns.
+ */
+ for (i=0, field=vot_getFIELD(tab); field; field=vot_getNext (field),i++) {
+ if ((ucd = vot_getAttr (field, "ucd"))) {
+ if ((strcmp (ucd, "POS_EQ_RA_MAIN") == 0) || /* UCD 1 */
+ (strcmp (ucd, "pos.eq.ra;meta.main") == 0)) { /* UCD 1+ */
+ ra_col = i;
+ got_ra_col = 1;
+ }
+ if ((strcmp (ucd, "POS_EQ_DEC_MAIN") == 0) || /* UCD 1 */
+ (strcmp (ucd, "pos.eq.dec;meta.main") == 0)) { /* UCD 1+ */
+ dec_col = i;
+ got_dec_col = 1;
+ }
+ }
+ }
+ if (!got_ra_col || !got_dec_col) {
+ fprintf (stderr, "Error: Cannot find position columns in table.\n");
+ status = ERR;
+ goto clean_up_;
+ }
+
+ /* Print the position cells.
+ */
+ fd = stdout;
+ if (strncasecmp ("stdout", oname, 6)) {
+ if ((fd = fopen (oname, "w+")) == NULL) {
+ fprintf (stderr, "Error: Cannot open output file '%s'\n", oname);
+ return (ERR);
+ }
+ }
+
+ for (i=0; i < nrows; i++) {
+ char *ra, *dec, *s;
+
+ s = vot_getTableCell (tdata, i, ra_col); ra = (s ? s : "INDEF");
+ s = vot_getTableCell (tdata, i, dec_col); dec = (s ? s : "INDEF");
+ if (number > 0)
+ fprintf (fd, "%d ", i);
+ fprintf (fd, "%s %s", ra, dec);
+ if (number < 0)
+ fprintf (fd, " %d", i);
+ fprintf (fd, "\n");
+ }
+
+
+ /* Clean up.
+ */
+clean_up_:
+ if (fd != stdout)
+ fclose (fd);
+ if (iname) free (iname);
+ if (oname) free (oname);
+
+ vo_paramFree (argc, pargv);
+ vot_closeVOTABLE (vot); /* close the table */
+
+ return (status);
+}
+
+
+/**
+ * USAGE -- Print task help summary.
+ */
+static void
+Usage (void)
+{
+ fprintf (stderr, "\n Usage:\n\t"
+ "votpos [<opts>] votable.xml\n\n"
+ " where\n"
+ " -%%,--test run unit tests\n"
+ " -h,--help this message\n"
+ " -n,--number number output\n"
+ " -o,--output=<file> output file\n"
+ " -r,--return return result from method\n"
+ "\n"
+ " Examples:\n\n"
+ " 1) Print the primary (RA,Dec) columns from a table:\n\n"
+ " %% votpos test.xml\t\t\t# un-numbered\n"
+ " %% votpos -n test.xml\t\t# numbered\n"
+ " %% cat test.xml | votpos\t\t# un-numbered\n"
+ "\n"
+ " 2) Print the primary (RA,Dec) columns to a file:\n\n"
+ " %% votpos -o pos.txt test.xml\n"
+ "\n"
+ );
+}
+
+
+/**
+ * Tests -- Task unit tests.
+ */
+static void
+Tests (char *input)
+{
+ Task *task = &self;
+
+ vo_taskTest (task, "--help", NULL);
+
+ vo_taskTest (task, input, NULL);
+ vo_taskTest (task, "-n", input, NULL);
+ vo_taskTest (task, "-o", "-", input, NULL);
+ vo_taskTest (task, "-o", "pos.txt", input, NULL);
+
+ if (access ("pos.txt", F_OK) == 0) unlink ("pos.txt");
+
+ vo_taskTestReport (self);
+}
diff --git a/vendor/voclient/voapps/votsort.c b/vendor/voclient/voapps/votsort.c
new file mode 100644
index 00000000..12945e83
--- /dev/null
+++ b/vendor/voclient/voapps/votsort.c
@@ -0,0 +1,394 @@
+/*
+ * VOTSORT -- Sort a VOTable based on a column value.
+ *
+ * Usage:
+ * votsort [<otps>] <votable.xml>
+ *
+ * Where
+ * -c,--col <N> Sort column num
+ * -d,--desc Sort in descending order
+ * -f,--fmt <format> Output format
+ * -o,--output <name> Output name
+ * -s,--string String sort
+ * -t,--top <N> Print top <N> rows
+ * -i,--indent <N> XML indent level
+ * -n,--noheader Suppress header
+ * -N,--name <name> Find <name> column
+ * -I,--id <id> Find <id> column
+ * -U,--ucd <ucd> Find <ucd> column
+ *
+ * -h,--help This message
+ * -r,--return Return result
+ * -%,--test Run unit tests
+ *
+ * @file votsort.c
+ * @author Mike Fitzpatrick
+ * @date 6/03/12
+ *
+ * @brief Sort a VOTable based on a column.
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+
+#include "votParse.h" /* keep these in order! */
+#include "voApps.h"
+
+
+static int do_return = 0; /* return result? */
+static int sort_order = 1; /* ascending order */
+static int top = 0; /* top results (0 for all) */
+
+
+
+/* A result buffer should be defined to point to the result object if it is
+ * created dynamically, e.g. a list of votable columns. The task is
+ * responsible for initially allocating this pointer and then resizing as
+ * needed.
+ */
+#ifdef USE_RESBUF
+#define SZ_RESBUF 8192
+
+static char *resbuf;
+#endif
+
+
+/* Task specific option declarations. Task options are declared using the
+ * getopt_long(3) syntax.
+ */
+int votsort (int argc, char **argv, size_t *len, void **result);
+
+static Task self = { "votsort", votsort, 0, 0, 0 };
+static char *opts = "%:c:df:hi:LnN:I:U:o:rst:";
+static struct option long_opts[] = {
+ { "col", 1, 0, 'c'}, /* sort column num */
+ { "desc", 2, 0, 'd'}, /* sort in descending order */
+ { "fmt", 1, 0, 'f'}, /* output format */
+ { "output", 1, 0, 'o'}, /* output name */
+ { "string", 2, 0, 's'}, /* string sort */
+ { "top", 1, 0, 't'}, /* string sort */
+ { "indent", 1, 0, 'i'}, /* xml indent level */
+ { "noheader", 2, 0, 'n'}, /* suppress header */
+ { "name", 1, 0, 'N'}, /* find <name> column */
+ { "id", 1, 0, 'I'}, /* find <id> column */
+ { "ucd", 1, 0, 'U'}, /* find <ucd> column */
+
+ { "help", 2, 0, 'h'}, /* --help is std */
+ { "return", 2, 0, 'r'}, /* --return is std */
+ { "test", 1, 0, '%'}, /* --test is std */
+ { NULL, 0, 0, 0 }
+};
+
+
+/* All tasks should declare a static Usage() method to print the help
+ * text in response to a '-h' or '--help' flag. The help text should
+ * include a usage summary, a description of options, and some examples.
+ */
+static void Usage (void);
+static void Tests (char *input);
+
+extern int vot_isNumericField (handle_t field);
+extern int vot_isValidFormat (char *fmt);
+extern int vot_atoi (char *val);
+extern int strdic (char *in_str, char *out_str, int maxchars, char *dict);
+
+
+
+/**
+ * Application entry point. All VOApps tasks MUST contain this
+ * method signature.
+ */
+int
+votsort (int argc, char **argv, size_t *reslen, void **result)
+{
+ /* These declarations are required for the VOApps param interface.
+ */
+ char **pargv, optval[SZ_FNAME], format[SZ_FORMAT];
+ char *iname, *oname, *fmt = NULL;
+ char *byName = NULL, *byID = NULL, *byUCD = NULL;
+ int i = 0, ch = 0, status = OK, pos = 0, col = -1, do_string = 0;
+ int vot, res, tab, data, tdata, field, tr;
+ int indent = 0, scalar = 0, hdr = 1;
+
+
+ /* Initialize result object whether we return an object or not.
+ */
+ *reslen = 0;
+ *result = NULL;
+
+ /* Initialize local task values.
+ */
+ iname = NULL;
+ oname = NULL;
+
+
+ /* Parse the argument list. The use of vo_paramInit() is required to
+ * rewrite the argv[] strings in a way vo_paramNext() can be used to
+ * parse them. The programmatic interface allows "param=value" to
+ * be passed in, but the getopt_long() interface requires these to
+ * be written as "--param=value" so they are not confused with
+ * positional parameters (i.e. any param w/out a leading '-').
+ */
+ pargv = vo_paramInit (argc, argv, opts, long_opts);
+ while ((ch = vo_paramNext(opts,long_opts,argc,pargv,optval,&pos)) != 0) {
+ if (ch > 0) {
+ /* If the 'ch' value is > 0 we are parsing a single letter
+ * flag as defined in the 'opts string.
+ */
+ switch (ch) {
+ case '%': Tests (optval); return (self.nfail);
+ case 'h': Usage (); return (OK);
+ case 'c': col = vot_atoi (optval); break;
+ case 'd': sort_order = -1; break;
+ case 'f': if (!vot_isValidFormat ((fmt = strdup (optval)))) {
+ fprintf (stderr, "Error: invalid format '%s'\n",
+ fmt);
+ return (ERR);
+ }
+ break;
+ case 'o': oname = strdup (optval); break;
+ case 'i': indent = vot_atoi (optval); break;
+ case 'n': hdr=0; break;
+ case 'N': byName = strdup (optval); break;
+ case 'I': byID = strdup (optval); break;
+ case 'U': byUCD = strdup (optval); break;
+ case 'r': do_return = 1; break;
+ case 's': do_string = 1; break;
+ case 't': top = vot_atoi (optval); break;
+ default:
+ fprintf (stderr, "Invalid option '%s'\n", optval);
+ return (1);
+ }
+
+ } else if (ch == PARG_ERR) {
+ return (ERR);
+
+ } else {
+ /* This code processes the positional arguments. The 'optval'
+ * string contains the value but since this string is
+ * overwritten w/ each arch we need to make a copy (and must
+ * remember to free it later).
+ */
+ iname = strdup (optval);
+ break; /* only allow one file */
+ }
+ }
+
+
+ /* Sanity checks. Tasks should validate input and accept stdin/stdout
+ * where it makes sense.
+ */
+ if (iname == NULL) iname = strdup ("stdin");
+ if (oname == NULL) oname = strdup ("stdout");
+ if (strcmp (iname, "-") == 0) { free (iname), iname = strdup ("stdin"); }
+ if (strcmp (oname, "-") == 0) { free (oname), oname = strdup ("stdout"); }
+
+ fmt = (fmt ? fmt : strdup ("xml"));
+
+
+ /* Open the table. This also parses it.
+ */
+ if ( (vot = vot_openVOTABLE (iname) ) <= 0) {
+ fprintf (stderr, "Error opening VOTable '%s'\n", iname);
+ return (1);
+ }
+
+ res = vot_getRESOURCE (vot); /* get handles */
+ if (vot_getLength (res) > 1) {
+ fprintf (stderr, "Error: multiple RESOURCE elements not supported\n");
+ goto clean_up_;
+ }
+ if ((tab = vot_getTABLE (res)) <= 0)
+ goto clean_up_;
+ if ((data = vot_getDATA (tab)))
+ tdata = vot_getTABLEDATA (data);
+ else
+ goto clean_up_;
+
+
+ /* Find the requested sort column. If the column isn't set explicitly
+ * check each field for the name/id/ucd.
+ */
+ if (col < 0) {
+ char *name, *id, *ucd;
+ handle_t field;
+
+ for (field=vot_getFIELD(tab); field; field=vot_getNext(field),i++) {
+ id = vot_getAttr (field, "id");
+ name = vot_getAttr (field, "name");
+ ucd = vot_getAttr (field, "ucd");
+
+ /* See whether this is a column we can sort numerically.
+ */
+ if (! do_string)
+ scalar = vot_isNumericField (field);
+
+ if ((byName && name && strcasecmp (name, byName) == 0) ||
+ (byID && id && strcasecmp (id, byID) == 0) ||
+ (byUCD && ucd && strcasecmp (ucd, byUCD) == 0)) {
+ col = i, do_string = (do_string ? 1 : ! scalar);
+ break;
+ }
+ }
+
+ } else {
+ register int i = 0;
+
+ for (field = vot_getFIELD(tab); field && i < col; i++)
+ field = vot_getNext(field);
+ if (! do_string)
+ scalar = vot_isNumericField (field);
+ do_string = (do_string ? 1 : ! scalar);
+ }
+
+
+ /* Sort the table.
+ */
+ (void) vot_sortTable (tdata, (col < 0 ? 0 : col), do_string, sort_order);
+
+
+ /* Now trim the data rows if we've set a TOP condition.
+ */
+ if (top) {
+ int row = 0, ntr = 0;
+
+ /* Skip over the rows we'll keep
+ */
+ for (tr=vot_getTR (tdata); tr && row < top; tr=vot_getNext(tr))
+ row++;
+
+ /* Free the remaining rows.
+ */
+ for ( ; tr; tr = ntr) {
+ ntr=vot_getNext(tr);
+ vot_deleteNode (tr);
+ }
+ }
+
+
+ /* Output the new format.
+ */
+ memset (format, 0, SZ_FORMAT);
+ switch (strdic (fmt, format, SZ_FORMAT, FORMATS)) {
+ case VOT: vot_writeVOTable (vot, oname, indent); break;
+ case ASV: vot_writeASV (vot, oname, hdr); break;
+ case BSV: vot_writeBSV (vot, oname, hdr); break;
+ case CSV: vot_writeCSV (vot, oname, hdr); break;
+ case TSV: vot_writeTSV (vot, oname, hdr); break;
+ case HTML: vot_writeHTML (vot, iname, oname); break;
+ case SHTML: vot_writeSHTML (vot, iname, oname); break;
+ case FITS: vot_writeFITS (vot, oname); break;
+ case ASCII: vot_writeASV (vot, oname, hdr); break;
+ case XML: vot_writeVOTable (vot, oname, indent); break;
+ case RAW: vot_writeVOTable (vot, oname, indent); break;
+ default:
+ fprintf (stderr, "Unknown output format '%s'\n", fmt);
+ status = ERR;
+ }
+
+
+ /* Clean up. Rememebr to free whatever pointers were created when
+ * parsing arguments.
+ */
+clean_up_:
+ if (iname) free (iname);
+ if (oname) free (oname);
+ if (fmt) free (fmt);
+ if (byID) free (byID);
+ if (byUCD) free (byUCD);
+ if (byName) free (byName);
+
+ vo_paramFree (argc, pargv);
+ vot_closeVOTABLE (vot);
+
+ return (status); /* status must be OK or ERR (i.e. 0 or 1) */
+}
+
+
+/**
+ * USAGE -- Print task help summary.
+ */
+static void
+Usage (void)
+{
+ fprintf (stderr, "\n Usage:\n\t"
+ "votsort [<opts>] votable.xml\n\n"
+ " Where\n"
+ " -c,--col <N> Sort column num\n"
+ " -d,--desc Sort in descending order\n"
+ " -f,--fmt <format> Output format\n"
+ " -o,--output <name> Output name\n"
+ " -s,--string String sort\n"
+ " -t,--top <N> Print top <N> rows\n"
+ " -i,--indent <N> XML indent level\n"
+ " -n,--noheader Suppress header\n"
+ " -N,--name <name> Find <name> column\n"
+ " -I,--id <id> Find <id> column\n"
+ " -U,--ucd <ucd> Find <ucd> column\n"
+ "\n"
+ " -h,--help This message\n"
+ " -r,--return Return result\n"
+ " -%%,--test Run unit tests\n"
+ "\n"
+ " <format> is one of\n"
+ " vot A new VOTable\n"
+ " asv ascii separated values\n"
+ " bsv bar separated values\n"
+ " csv comma separated values\n"
+ " tsv tab separated values\n"
+ " html standalone HTML document\n"
+ " shtml single HTML <table>\n"
+ " fits FITS binary table\n"
+ " ascii ASV alias\n"
+ " xml VOTable alias\n"
+ " raw VOTable alias\n"
+ "\n"
+ "\n"
+ " Examples:\n\n"
+ " 1) Sort a VOTable based on first column\n\n"
+ " %% votsort test.xml\n"
+ " %% votsort http://generic.edu/test.xml\n"
+ " %% cat test.xml | votsort -o sort_test.xml\n"
+ "\n"
+ " A string sort will be done automatically if this is a\n"
+ " string-valued column, otherwise a numeric sort is done.\n"
+ "\n"
+ " 2) Sort a VOTable based on the magnitude column\n\n"
+ " %% votsort --name=id test.xml\n"
+ "\n"
+ " 3) Same as above, select 10 faintest stars\n\n"
+ " %% votsort --name=id --desc --top=10 test.xml\n"
+ "\n"
+ " 4) String sort based on object name, output as CSV\n\n"
+ " %% votsort -s -f csv test.xml\n"
+ " %% votsort --string --fmt=csv test.xml\n"
+ "\n"
+ );
+}
+
+
+/**
+ * Tests -- Task unit tests.
+ */
+static void
+Tests (char *input)
+{
+ Task *task = &self;
+
+ vo_taskTest (task, "--help", NULL);
+
+ vo_taskTest (task, input, NULL); // Ex 1
+ vo_taskTest (task, "http://iraf.noao.edu/votest/sort.xml", NULL); // Ex 2
+ vo_taskTest (task, "--name=id", input, NULL); // Ex 3
+ vo_taskTest (task, "--name=id", "--desc", "--top=10", input, NULL); // Ex 4
+ vo_taskTest (task, "-s", "-f", "csv", input, NULL); // Ex 5
+ vo_taskTest (task, "--string", "--fmt=csv", input, NULL); // Ex 6
+
+ vo_taskTest (task, "--name=id", "-s", "--desc", "--fmt=csv", input, NULL);
+
+ vo_taskTestReport (self);
+}
+
diff --git a/vendor/voclient/voapps/votsplit.c b/vendor/voclient/voapps/votsplit.c
new file mode 100644
index 00000000..9e4695c3
--- /dev/null
+++ b/vendor/voclient/voapps/votsplit.c
@@ -0,0 +1,202 @@
+/*
+ * VOTSPLIT -- Split a Multi-RESOURCE VOTable into single tables.
+ *
+ * Usage:
+ * votsplit [<otps>] <votable>
+ *
+ * @file votsplit.c
+ * @author Mike Fitzpatrick
+ * @date 6/03/12
+ *
+ * @brief Split a Multi-RESOURCE VOTable into single tables.
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+
+#include "votParse.h" /* keep these in order! */
+#include "voApps.h"
+
+
+
+/* Global task declarations. These should all be defined as 'static' to
+ * avoid namespace collisions.
+ */
+static int vot = 0; /* VOTable handle */
+static int do_return = 0; /* return result? */
+
+
+/* Result Buffer.
+ */
+#ifdef USE_RESBUF
+#define SZ_RESBUF 8192
+
+static char *resbuf;
+#endif
+
+
+/* Task specific option declarations. Task options are declared using the
+ * getopt_long(3) syntax.
+ */
+int votsplit (int argc, char **argv, size_t *len, void **result);
+
+static Task self = { "votsplit", votsplit, 0, 0, 0 };
+static char *opts = "hr";
+static struct option long_opts[] = {
+ { "help", 2, 0, 'h'}, /* --help is std */
+ { "return", 2, 0, 'r'}, /* --return is std */
+ { "test", 2, 0, '%'}, /* --return is std */
+ { NULL, 0, 0, 0 }
+};
+
+
+/* All tasks should declare a static Usage() method to print the help
+ * text in response to a '-h' or '--help' flag. The help text should
+ * include a usage summary, a description of options, and some examples.
+ */
+static void Usage (void);
+static void Tests (char *input);
+
+
+/**
+ * Application entry point.
+ */
+int
+votsplit (int argc, char **argv, size_t *reslen, void **result)
+{
+ char **pargv, optval[SZ_FNAME];
+ char *iname, *oname;
+ int ch = 0, status = OK, number = 0, pos = 0;
+
+
+ /* Initialize result object whether we return an object or not.
+ */
+ *reslen = 0;
+ *result = NULL;
+
+ /* Initialize local task values.
+ */
+ iname = NULL;
+ oname = NULL;
+ vot = -1;
+
+
+ /* Parse the argument list. The use of vo_paramInit() is required to
+ * rewrite the argv[] strings in a way vo_paramNext() can be used to
+ * parse them. The programmatic interface allows "param=value" to
+ * be passed in, but the getopt_long() interface requires these to
+ * be written as "--param=value" so they are not confused with
+ * positional parameters (i.e. any param w/out a leading '-').
+ */
+ pargv = vo_paramInit (argc, argv, opts, long_opts);
+ while ((ch = vo_paramNext(opts,long_opts,argc,pargv,optval,&pos)) != 0) {
+ if (ch > 0) {
+ /* If the 'ch' value is > 0 we are parsing a single letter
+ * flag as defined in the 'opts string.
+ */
+ switch (ch) {
+ case '%': Tests (optval); return (self.nfail);
+ case 'h': Usage (); return (OK);
+ case 'n': number++; break;
+ case 'o': oname = strdup (optval); break;
+ case 'r': do_return=1; break;
+ default:
+ fprintf (stderr, "Invalid option '%s'\n", optval);
+ return (1);
+ }
+
+ } else if (ch == PARG_ERR) {
+ return (ERR);
+
+ } else {
+ /* This code processes the positional arguments. The 'optval'
+ * string contains the value but since this string is
+ * overwritten w/ each arch we need to make a copy (and must
+ * remember to free it later.
+ */
+ iname = strdup (optval);
+ break;
+ }
+ }
+
+
+ /* Sanity checks. Tasks should validate input and accept stdin/stdout
+ * where it makes sense.
+ */
+ if (iname == NULL) iname = strdup ("stdin");
+ if (oname == NULL) oname = strdup ("stdout");
+ if (strcmp (iname, "-") == 0) { free (iname), iname = strdup ("stdin"); }
+ if (strcmp (oname, "-") == 0) { free (oname), oname = strdup ("stdout"); }
+
+
+
+
+ /********
+ ********
+ ********
+ ********
+ ******** Main body of task
+ ********
+ ********
+ ********
+ *******/
+
+
+
+
+ /* Clean up. Rememebr to free whatever pointers were created when
+ * parsing arguments.
+ */
+ if (iname)
+ free (iname);
+ if (oname)
+ free (oname);
+
+ vo_paramFree (argc, pargv);
+
+ return (status); /* status must be OK or ERR (i.e. 0 or 1) */
+}
+
+
+/**
+ * USAGE -- Print task help summary.
+ */
+static void
+Usage (void)
+{
+ fprintf (stderr, "\n Usage:\n\t"
+ "votsplit [<opts>] votable.xml\n\n"
+ " where\n"
+ " -%%,--test run unit tests\n"
+ " -h,--help this message\n"
+ " -n,--number number output\n"
+ " -o,--output=<file> output file\n"
+ " -r,--return return result from method\n"
+ "\n"
+ " Examples:\n\n"
+ " 1) First example\n\n"
+ " %% votsplit test.xml\n"
+ "\n"
+ " 2) Second example\n\n"
+ " %% votsplit -o pos.txt test.xml\n"
+ "\n"
+ );
+}
+
+
+/**
+ * Tests -- Task unit tests.
+ */
+static void
+Tests (char *input)
+{
+ Task *task = &self;
+
+ /* First argument must always be the 'self' variable, the last must
+ * always be a NULL to terminate the cmd args.
+ */
+ vo_taskTest (task, "--help", NULL);
+}
diff --git a/vendor/voclient/voapps/votstat.c b/vendor/voclient/voapps/votstat.c
new file mode 100644
index 00000000..0065e314
--- /dev/null
+++ b/vendor/voclient/voapps/votstat.c
@@ -0,0 +1,281 @@
+/*
+ * VOTSTAT -- Compute statistics for numeric columns of a VOTable.
+ *
+ * Usage:
+ * votstat [<otps>] <votable>
+ *
+ * @file votstat.c
+ * @author Mike Fitzpatrick
+ * @date 6/03/12
+ *
+ * @brief Compute statistics for numeric columns of a VOTable.
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <math.h>
+
+#include "votParse.h" /* keep these in order! */
+#include "voApps.h"
+
+
+
+/* Global task declarations.
+ */
+static int vot = 0; /* VOTable handle */
+
+static int do_all = 0; /* all columns? */
+static int do_return = 0; /* return result? */
+
+
+/* A result buffer should be defined to point to the result object if it is
+ * created dynamically, e.g. a list of votable columns. The task is
+ * responsible for initially allocating this pointer and then resizing as
+ * needed.
+ */
+#ifdef USE_RESBUF
+#define SZ_RESBUF 8192
+
+static char *resbuf;
+#endif
+
+
+/* Task specific option declarations. Task options are declared using the
+ * getopt_long(3) syntax.
+ */
+int votstat (int argc, char **argv, size_t *len, void **result);
+
+static Task self = { "votstat", votstat, 0, 0, 0 };
+static char *opts = "%:hao:r";
+static struct option long_opts[] = {
+ { "test", 1, 0, '%'},
+ { "help", 2, 0, 'h'},
+ { "all", 2, 0, 'a'},
+ { "output", 1, 0, 'o'},
+ { "return", 2, 0, 'r'},
+ { NULL, 0, 0, 0 }
+};
+
+
+/* Standard usage method.
+ */
+static void Usage (void);
+static void Tests (char *input);
+
+void vot_colStat (int tdata, int col, int nrows, double *min, double *max,
+ double *mean, double *stddev);
+
+extern int vot_isNumericField (handle_t field);
+extern double vot_atof (char *v);
+
+
+/**
+ * Application entry point.
+ */
+int
+votstat (int argc, char **argv, size_t *reslen, void **result)
+{
+ /* These declarations are required for the VOApps param interface.
+ */
+ char **pargv, optval[SZ_FNAME];
+
+ /* These declarations are specific to the task.
+ */
+ char *iname, *oname, *name, *id, *fstr;
+ int ch = 0, status = OK, numeric = 0;
+ int res, tab, data, tdata, field;
+ int i, ncols, nrows, pos = 0;
+ FILE *fd = (FILE *) NULL;
+
+
+ /* Initialize result object whether we return an object or not.
+ */
+ *reslen = 0;
+ *result = NULL;
+
+ iname = NULL; /* initialize local task values */
+ oname = NULL;
+
+
+ /* Parse the argument list.
+ */
+ pargv = vo_paramInit (argc, argv, opts, long_opts);
+ while ((ch = vo_paramNext(opts,long_opts,argc,pargv,optval,&pos)) != 0) {
+ if (ch > 0) {
+ switch (ch) {
+ case '%': Tests (optval); return (self.nfail);
+ case 'h': Usage (); return (OK);
+ case 'a': do_all++; break;
+ case 'o': oname = strdup (optval); break;
+ case 'r': do_return=1; break;
+ default:
+ fprintf (stderr, "Invalid option '%s'\n", optval);
+ return (1);
+ }
+
+ } else if (ch == PARG_ERR) {
+ return (ERR);
+
+ } else {
+ /* Process the positional arguments.
+ */
+ iname = strdup (optval);
+ break;
+ }
+ }
+
+
+ /* Sanity checks. Tasks should validate input and accept stdin/stdout
+ * where it makes sense.
+ */
+ if (iname == NULL) iname = strdup ("stdin");
+ if (oname == NULL) oname = strdup ("stdout");
+ if (strcmp(iname, "-") == 0) { free (iname), iname = strdup ("stdin"); }
+ if (strcmp(oname, "-") == 0) { free (oname), oname = strdup ("stdout"); }
+
+ if (strcmp ("stdout", oname) == 0)
+ fd = stdout;
+ else {
+ if ((fd = fopen (oname, "w+")) == (FILE *) NULL) {
+ fprintf (stderr, "Cannot open output file '%s'\n", oname);
+ return (ERR);
+ }
+ }
+
+ /* Open the table. This also parses it.
+ */
+ if ( (vot = vot_openVOTABLE (iname) ) <= 0) {
+ fprintf (stderr, "Error opening VOTable '%s'\n", iname);
+ return (1);
+ }
+
+ res = vot_getRESOURCE (vot); /* get handles */
+ if (vot_getLength (res) > 1) {
+ fprintf (stderr, "Error: multiple RESOURCE elements not supported\n");
+ goto clean_up_;
+ }
+ tab = vot_getTABLE (res);
+ if ((data = vot_getDATA (tab)) <= 0)
+ goto clean_up_;
+ tdata = vot_getTABLEDATA (data);
+ nrows = vot_getNRows (tdata);
+ ncols = vot_getNCols (tdata);
+
+
+ fprintf (fd, "# %3s %-20.20s %9.9s %9.9s %9.9s %9.9s\n#\n",
+ "Col", "Name", "Min", "Max", "Mean", "StdDev");
+
+ for (i=0,field=vot_getFIELD(tab); field; field=vot_getNext (field), i++) {
+ name = vot_getAttr (field, "name");
+ id = vot_getAttr (field, "id");
+
+ numeric = vot_isNumericField (field);
+ fstr = (name ? name : (id ? id : "(none)"));
+
+ if (do_all && !numeric) /* non-numeric column */
+ fprintf (fd, " %3d %-20.20s\n", i, fstr);
+
+ else if (do_all || numeric) { /* numeric column */
+ double min, max, mean, stddev;
+
+ vot_colStat (tdata, i, nrows, &min, &max, &mean, &stddev);
+
+ if (mean > 1.0e6 || mean < 1.0e-3)
+ fprintf (fd, " %3d %-20.20s %9.4g %9.4g %9.4g %9.4g\n",
+ i, fstr, min, max, mean, stddev);
+ else
+ fprintf (fd, " %3d %-20.20s %9.2f %9.2f %9.2f %9.2f\n",
+ i, fstr, min, max, mean, stddev);
+ }
+ }
+
+
+ /* Clean up. Rememebr to free whatever pointers were created when
+ * parsing arguments.
+ */
+clean_up_:
+ if (iname) free (iname);
+ if (oname) free (oname);
+
+ vo_paramFree (argc, pargv);
+ vot_closeVOTABLE (vot);
+
+ if (fd != stdout)
+ fclose (fd);
+
+ return (status); /* status must be OK or ERR (i.e. 0 or 1) */
+}
+
+
+/**
+ * VOT_COLSTAT -- Determine the statistics of a table column.
+ */
+void
+vot_colStat (int tdata, int col, int nrows, double *min, double *max,
+ double *mean, double *stddev)
+{
+ register int i = 0;
+ double sum = 0.0, sum2 = 0.0, val = 0.0;
+
+
+ *min = 0.99e306;
+ *max = -0.99e306;
+ *mean = 0.0;
+ *stddev = 0.0;
+
+ for (i=0; i < nrows; i++) {
+ val = vot_atof (vot_getTableCell (tdata, i, col));
+ sum += val;
+ sum2 += (val * val);
+ if (val < (*min)) *min = val;
+ if (val > (*max)) *max = val;
+ }
+
+ *mean = (double) (sum / (double) nrows);
+ *stddev = sqrt ( ( sum2 / (double) nrows) -
+ ( (sum / (double) nrows) * (sum / (double) nrows) ));
+}
+
+
+/**
+ * USAGE -- Print task help summary.
+ */
+static void
+Usage (void)
+{
+ fprintf (stderr, "\n Usage:\n\t"
+ "votstat [<opts>] votable.xml\n\n"
+ " where\n"
+ " -h,--help this message\n"
+ " -%%,--test run unit tests\n"
+ " -r,--return return result from method\n"
+ "\n"
+ " -a,--all print all columns\n"
+ " -o,--output=<file> output file\n"
+ "\n"
+ " Examples:\n\n"
+ " 1) Print statistics for a VOTable\n\n"
+ " %% votstat test.xml\n"
+ "\n"
+ " 2) Print statistics for all column in a VOTable and save \n"
+ " results to a file.\n\n"
+ " %% votstat -a -o stats test.xml\n"
+ "\n"
+ );
+}
+
+
+
+/**
+ * Tests -- Task unit tests.
+ */
+static void
+Tests (char *input)
+{
+ Task *task = &self;
+
+ vo_taskTest (task, "--help", NULL);
+}
diff --git a/vendor/voclient/voapps/zzparam.c b/vendor/voclient/voapps/zzparam.c
new file mode 100644
index 00000000..fd856021
--- /dev/null
+++ b/vendor/voclient/voapps/zzparam.c
@@ -0,0 +1,87 @@
+/**
+ *
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <getopt.h>
+#include <string.h>
+#include <errno.h>
+#include "voApps.h"
+
+
+char optval[128];
+
+/* Task specific option declarations.
+ */
+char *opts = "abn:v:";
+struct option long_opts[] = {
+ { "debug", 0, 0, 'd'},
+ { "nport", 1, 0, 'n'},
+ { "verbose", 2, 0, 'v'},
+ { NULL, 0, 0, 0 }
+};
+
+
+
+/*
+ * -v
+ * -v 0
+ * -v=0
+ * --verbose
+ * --verbose 0
+ * --verbose=0
+ * verbose=0
+*/
+
+int ch=0, all=0, debug=0, verbose=0, nport=0;
+
+int
+main (int argc, char *argv[])
+{
+ int i, pos;
+ char **pargv;
+
+
+ /* Initialize the parameters, i.e. rewrite the options so they can
+ * be processed by getopt_long().
+ */
+ pargv = vo_paramInit (argc, argv, opts, long_opts);
+ while ((ch = vo_paramNext (opts,long_opts,argc,pargv,optval,&pos)) != 0) {
+ if (ch > 0) {
+ switch (ch) {
+ case 'a': printf ("'a' key\n");
+ break;
+ case 'd': printf ("'d' key\n");
+ break;
+ case 'n': printf ("'n' key, arg '%s'\n", optval);
+ nport = atoi (optval);
+ break;
+ case 'v':
+ if (optval[0]) {
+ printf ("'v' key, arg = '%s'\n", optval);
+ verbose = atoi (optval);
+ } else {
+ printf ("'v' key\n"); verbose = 1;
+ }
+ break;
+ default:
+ printf ("\nDEFAULT\n");
+ }
+
+ } else if (ch == PARG_ERR) {
+ return (1);
+
+ } else
+ printf ("pos=%d optind=%d argc=%d val='%s'\n",
+ pos, optind, argc, optval);
+ }
+
+ printf ("\n\n");
+ printf ("final nport = %d\n", nport);
+ printf ("final verbose = %d\n", verbose);
+
+
+ /* Free the allocated arguments.
+ */
+ vo_paramFree (argc, pargv);
+}
diff --git a/vendor/voclient/voapps/zztest.c b/vendor/voclient/voapps/zztest.c
new file mode 100644
index 00000000..ff5add17
--- /dev/null
+++ b/vendor/voclient/voapps/zztest.c
@@ -0,0 +1,427 @@
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+
+#include "votParse.h"
+
+
+
+typedef struct colum {
+ char name[100];
+ char ucd[1000];
+} col_t;
+
+int
+pseudocode1(char *fname)
+{
+ handle_t vot, res, data, tab, field, tr, td, fits, stream, tdata,
+ bin;
+ int nrows, ncols, i, l, m, use_direct = 1;
+ char *str, *extnum, *href, *ucd, *name;
+
+ printf("--------------Test 1-------------------------------------------\n");
+
+ col_t *col;
+
+ vot = vot_openVOTABLE(fname);
+
+ /* Loop over RESOURCES. */
+ res = vot_getRESOURCE(vot);
+
+ printf("Table has toplevel %i RESOURCE elements\n",
+ vot_getLength(res));
+
+ while (res) {
+ tab = vot_getTABLE(res);
+
+ /* Print column info. */
+
+ /* Get the data element. */
+ data = vot_getDATA(tab);
+
+ /* Get data stored as a TABLEDATA XML block. */
+ tdata = vot_getTABLEDATA(data);
+
+ col = (col_t *) calloc(vot_getNCols(tdata), sizeof(col_t));
+
+ for (field = vot_getFIELD(tab), i = 0; field; field = vot_getNext(field), i++) {
+ name = vot_getAttr(field, "name");
+ ucd = vot_getAttr(field, "ucd");
+
+ if (name != NULL)
+ strcpy(col[i].name, name);
+
+ if (ucd != NULL)
+ strcpy(col[i].ucd, ucd);
+
+ printf("%s, ", col[i].name);
+ }
+
+ printf("\n");
+
+ switch (vot_getDATAType(data)) {
+ case TY_TABLEDATA:
+
+ if (use_direct) {
+ /* Get the table data cells by direct index. */
+ tr = vot_getTR(tdata);
+ nrows = vot_getLength(tr);
+ ncols = vot_getLength(vot_getTD(tr));
+
+ for (l = 0; l < nrows; l++) {
+ for (m = 0; m < ncols; m++) {
+ str = vot_getTableCell(tdata, l, m);
+ printf("%s\n", str);
+ }
+
+ printf("--\n");
+ }
+ } else {
+ /* Get the table data cells by looping over rows/cols. */
+ for (tr = vot_getTR(tdata); tr; tr = vot_getNext(tr)) {
+ for (td = vot_getTD(tr); td; td = vot_getNext(td)) {
+ str = vot_getValue(td);
+ printf("%s\n", str);
+ }
+ }
+ }
+
+ break;
+
+ case TY_BINARY:
+ /*
+ * Get data stored as inline binary. If the encoding of the
+ * stream is based64 read the sequence of bytes and decode.
+ */
+
+ bin = vot_getBINARY(data);
+ stream = vot_getSTREAM(bin);
+
+ if (strcasecmp("base64", vot_getAttr(stream, "encoding")) == 0)
+ str = vot_getValue(stream);
+ printf("%s\n", str);
+
+ break;
+
+ case TY_FITS:
+ /*
+ * Read FITS data. Assumes a particular extension of an MEF is
+ * avaliable for download at the given href.
+ */
+ fits = vot_getFITS(data);
+ extnum = vot_getAttr(fits, "extnum");
+
+ stream = vot_getSTREAM(fits);
+ href = vot_getAttr(stream, "href");
+
+ /* Download the FITS file. */
+
+ break;
+
+ default:
+ printf("Error: Invalid table DATA type.\n");
+ }
+
+ res = vot_getNext(res);
+ }
+
+
+ printf("--------------\\Test 1-----------------------------------------\n");
+
+ return (0);
+
+}
+
+int
+pseudocode2(char *fname)
+{
+ handle_t vot, res, p;
+
+ printf("--------------Test 2-------------------------------------------\n");
+ vot = vot_openVOTABLE(fname);
+
+ res = vot_getRESOURCE(vot);
+
+ for (p = vot_getChild(res); p; p = vot_getSibling(p)) {
+ if (vot_typeOf(p) == TY_PARAM)
+ printf("PARAM name=%s value=%s\n",
+ vot_getAttr(p, "name"), vot_getAttr(p, "value"));
+ }
+
+ printf("\n");
+ res = vot_getRESOURCE(vot);
+
+ for (p = vot_getPARAM(res); p; p = vot_getNext(p)) {
+ printf("PARAM name=%s value=%s\n",
+ vot_getAttr(p, "name"), vot_getAttr(p, "value"));
+ }
+
+
+ printf("------------\\Test 2-------------------------------------------\n");
+
+ return (0);
+}
+
+int
+pseudocode3(char *fname)
+{
+ handle_t vot, res, param, info;
+
+ printf("--------------Test 3-------------------------------------------\n");
+ vot = vot_openVOTABLE(fname);
+
+ if ((info = vot_getINFO(vot))) {
+ if (strcasecmp(vot_getAttr(info, "name"), "error") == 0)
+ printf("ERROR: VALUE=%s\n", vot_getAttr(info, "value"));
+ } else {
+ printf("File OK.\n");
+ }
+
+
+ vot = vot_openVOTABLE(fname);
+ res = vot_getRESOURCE(vot);
+ param = vot_getPARAM(res);
+ info = vot_getINFO(res);
+
+ if ((param) && strcasecmp(vot_getAttr(param, "name"), "error") == 0) {
+ /* SCS alternate method where PARAN defines value the error string. */
+ printf("ERROR: VALUE=%s\n", vot_getAttr(param, "value"));
+ } else if ((info) && strcasecmp(vot_getAttr(info, "name"), "QUERY_STATUS") == 0) {
+ /*
+ * All-other DAL methods where PARAM and INFO of the RESOURCE defines
+ * a QUERY_STATUS of the result.
+ */
+ if (strcasecmp(vot_getAttr(info, "value"), "OK") == 0)
+ printf("FILE OK.\n");
+ else
+ printf("ERROR: Value=%s\n", vot_getValue(info));
+ } else
+ printf("FILE OK.\n");
+
+
+ printf("------------\\Test 3-------------------------------------------\n");
+ return (0);
+}
+
+int
+pseudocode4(void)
+{
+ handle_t vot, res, data, tab, f, tr, td, tdata, desc, info;
+ int nrows = 5, ncols = 10, i, j;
+ char colname[50];
+ char **data_m;
+ char **ip;
+ char *tmpstr;
+
+ printf("--------------Test 4-------------------------------------------\n");
+
+ data_m = (char **) calloc((nrows * ncols), sizeof(char *));
+
+ ip = data_m;
+
+ for (i = 0; i < nrows; i++) {
+ for (j = 0; j < ncols; j++) {
+ tmpstr = (char *) calloc(30, sizeof(char));
+ sprintf(tmpstr, "row: %i, col: %i", i, j);
+ *ip++ = tmpstr;
+ }
+ }
+
+
+ vot = vot_openVOTABLE(NULL);
+
+ res = vot_newNode(vot, TY_RESOURCE);
+ vot_setAttr(res, "id", "newtable");
+
+ desc = vot_newNode(vot, TY_DESCRIPTION);
+ vot_setValue(desc, "This is a test description.");
+
+ tab = vot_newNode(res, TY_TABLE);
+
+ for (i = 0; i < 10; i++) {
+ f = vot_newNode(tab, TY_FIELD);
+ sprintf(colname, "col%d", i);
+ vot_setAttr(f, "name", colname);
+ vot_setAttr(f, "id", colname);
+ }
+
+ data = vot_newNode(tab, TY_DATA);
+ tdata = vot_newNode(data, TY_TABLEDATA);
+
+ for (i = 0; i < nrows; i++) {
+ tr = vot_newNode(tdata, TY_TR);
+ for (j = 0; j < ncols; j++) {
+ td = vot_newNode(tr, TY_TD);
+ vot_setValue(td, (char *) data_m[(i * ncols) + j]);
+ }
+ }
+
+ info = vot_newNode(tab, TY_INFO);
+ vot_setAttr(info, "id", "STATUS");
+ vot_setAttr(info, "value", "OK");
+
+ vot_writeVOTable(vot, "stdout", 1);
+
+
+ printf("------------\\Test 4-------------------------------------------\n");
+
+ return (0);
+}
+
+int
+pseudocode5_copy(char *fname1, char *fname2)
+{
+ handle_t vot2, res2, cres2;
+ handle_t vot1, res1, cres1;
+ handle_t vot3;
+
+ printf("--------------Test 5-------------------------------------------\n");
+
+ vot1 = vot_openVOTABLE(fname1);
+ printf("Handles: %i\n", vot_handleCount());
+ vot2 = vot_openVOTABLE(fname2);
+ printf("Handles: %i\n", vot_handleCount());
+
+ res1 = vot_getRESOURCE(vot1);
+ res2 = vot_getRESOURCE(vot2);
+
+ cres1 = vot_copyElement(res1, 0);
+ cres2 = vot_copyElement(res2, 0);
+ printf("Handles: %i\n", vot_handleCount());
+
+ vot3 = vot_openVOTABLE(NULL);
+
+ vot_attachNode(vot3, cres1);
+ vot_attachNode(vot3, cres2);
+
+ vot_writeVOTable(vot3, "stdout", 1);
+
+ printf("Handles: %i\n", vot_handleCount());
+ vot_closeVOTABLE(vot1);
+ vot_closeVOTABLE(vot2);
+ vot_closeVOTABLE(vot3);
+ vot_closeVOTABLE(cres2);
+ vot_closeVOTABLE(cres1);
+ printf("Handles: %i\n", vot_handleCount());
+ vot_deleteNode(cres2);
+ vot_deleteNode(cres1);
+ printf("Handles: %i\n", vot_handleCount());
+ vot_writeVOTable(vot3, "stdout", 1);
+
+ printf("------------\\Test 5-------------------------------------------\n");
+ return (0);
+}
+
+int
+pseudocode5(char *fname1, char *fname2)
+{
+ handle_t vot2, res2;
+ handle_t vot1, res1;
+ handle_t vot3;
+
+ printf("--------------Test 5-------------------------------------------\n");
+
+ vot1 = vot_openVOTABLE(fname1);
+ vot2 = vot_openVOTABLE(fname2);
+
+ res1 = vot_getRESOURCE(vot1);
+ res2 = vot_getRESOURCE(vot2);
+
+ vot3 = vot_openVOTABLE(NULL);
+
+ vot_attachNode(vot3, res1);
+ vot_attachNode(vot3, res2);
+
+ vot_writeVOTable(vot3, "stdout", 1);
+ printf("Handles: %i\n", vot_handleCount());
+ vot_closeVOTABLE(vot1);
+ printf("Handles: %i\n", vot_handleCount());
+ vot_closeVOTABLE(vot2);
+ printf("Handles: %i\n", vot_handleCount());
+ vot_closeVOTABLE(vot3);
+ printf("Handles: %i\n", vot_handleCount());
+ vot_writeVOTable(vot3, "stdout", 1);
+
+ printf("------------\\Test 5-------------------------------------------\n");
+ return (0);
+}
+
+int
+pseudocode6(void)
+{
+
+ printf("--------------Test 6-------------------------------------------\n");
+ printf("------------\\Test 6-------------------------------------------\n");
+ return (0);
+}
+
+void
+copy_test(char *fname)
+{
+ handle_t vot, copy;
+
+ printf("--------------Copy Test-------------------------------------------\n");
+ vot = vot_openVOTABLE(fname);
+
+ /*
+ vot_writeVOTable(vot, "stdout", 1);
+ */
+
+ printf("Handles: %i\n", vot_handleCount());
+
+
+ copy = vot_copyElement(vot, 0);
+
+
+ /*
+ vot_writeVOTable(copy, "stdout", 1);
+ */
+
+ printf("Handles: %i\n", vot_handleCount());
+
+ vot_closeVOTABLE(copy);
+
+ printf("Handles: %i\n", vot_handleCount());
+
+
+
+ vot_closeVOTABLE(vot);
+
+ printf("Handles: %i\n", vot_handleCount());
+
+ printf("------------\\Copy Test-------------------------------------------\n");
+
+}
+
+
+
+int
+main(int argc, char **argv)
+{
+ char *fname = "zztest.xml";
+ char *fname2 = "zzdummy.xml";
+
+
+ printf("Hello World!\n");
+
+
+ /*
+ */
+ pseudocode1(fname);
+ pseudocode2(fname);
+ pseudocode3(fname);
+ pseudocode4();
+
+ pseudocode5(fname, fname2);
+ pseudocode5_copy(fname, fname2);
+
+ pseudocode6();
+
+ copy_test(fname);
+
+
+ return (0);
+}
diff --git a/vendor/voclient/voapps/zzwcs.c b/vendor/voclient/voapps/zzwcs.c
new file mode 100644
index 00000000..e681db51
--- /dev/null
+++ b/vendor/voclient/voapps/zzwcs.c
@@ -0,0 +1,106 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+#include "fitsio.h"
+
+
+int voc_imgQParams (char *name, double *ra, double *dec, double *rad);
+
+
+int main (int argc, char *argv[])
+{
+ double ra, dec, rad;
+ int status = 0;
+
+ status = voc_imgQParams (argv[1], &ra, &dec, &rad);
+ printf ("RA=%f DEC=%f SZ=%f\n", ra, dec, rad);
+}
+
+
+int voc_imgQParams (char *name, double *ra, double *dec, double *rad)
+{
+ fitsfile *fptr;
+
+ double xpos=0.0, ypos=0.0, xpix=0.0, ypix=0.0;
+ double xrval=0.0, yrval=0.0, xrpix=0.0, yrpix=0.0;
+ double xinc=0.0, yinc=0.0, rot=0.0;
+ double ll_x=0.0, ll_y=0.0, ur_x=0.0, ur_y=0.0, c_x=0.0, c_y=0.0;
+ long naxes[3], pcount, gcount;
+ int status=0, extend, simple, naxis, bitpix;
+ char ctype[5];
+
+
+ /* Open the FITS file.
+ */
+ if (ffopen (&fptr, name, READWRITE, &status) > 0) {
+ fprintf (stderr, "Error: open status = %d\n", status);
+ exit (0);
+ }
+
+ /* Get the primary header keywords.
+ */
+ ffghpr (fptr, 99, &simple, &bitpix, &naxis, naxes, &pcount,
+ &gcount, &extend, &status);
+
+fprintf (stderr, "gcount = %d pcount = %d extend = %d \n", gcount, pcount, extend);
+
+ /* Get the header WCS keywords.
+ */
+ ffgics (fptr, &xrval, &yrval, &xrpix,
+ &yrpix, &xinc, &yinc, &rot, ctype, &status);
+ if (status != 506)
+ fprintf (stderr, "Read WCS keywords with ffgics status = %d\n",status);
+
+
+ xpix = 0.5;
+ ypix = 0.5;
+ status = 0;
+ if (ffwldp (xpix, ypix, xrval, yrval, xrpix, yrpix, xinc, yinc, rot, ctype,
+ &ll_x, &ll_y, &status) > 0) {
+ fprintf (stderr, "Calculated sky coordinate with ffwldp status = %d\n",
+ status);
+
+ } else {
+ status = 0;
+ xpix = (double) naxes[0];
+ ypix = (double) naxes[1];
+ ffwldp (xpix, ypix, xrval, yrval, xrpix, yrpix, xinc, yinc, rot, ctype,
+ &ur_x, &ur_y, &status);
+
+ status = 0;
+ xpix = (double) naxes[0] / 2.;
+ ypix = (double) naxes[1] / 2.;
+ ffwldp (xpix, ypix, xrval, yrval, xrpix, yrpix, xinc, yinc, rot, ctype,
+ &c_x, &c_y, &status);
+ }
+
+ *ra = c_x;
+ *dec = c_y;
+ *rad = sqrt ((c_x - ll_x)*(c_x - ll_x) + (c_y - ll_y)*(c_y - ll_y));
+
+#ifdef DBG_WCS
+ printf (" CRVAL1, CRVAL2 = %16.12f, %16.12f\n", xrval, yrval);
+ printf (" CRPIX1, CRPIX2 = %16.12f, %16.12f\n", xrpix, yrpix);
+ printf (" CDELT1, CDELT2 = %16.12f, %16.12f\n", xinc, yinc);
+ printf (" Rotation = %10.3f, CTYPE = %s\n", rot, ctype);
+ printf (" Pixels (%8.4f,%8.4f) --> (%11.6f, %11.6f) Sky\n",
+ xpix, ypix, ll_x, ll_y);
+
+ fprintf (stderr, "RA=%f DEC=%f SZ=%f\n", c_x, c_y,
+ sqrt ((c_x - ll_x)*(c_x - ll_x) + (c_y - ll_y)*(c_y - ll_y)));
+
+ ffxypx (xpos, ypos, xrval, yrval, xrpix, yrpix, xinc, yinc, rot, ctype,
+ &xpix, &ypix, &status);
+ printf ("Calculated pixel coordinate with ffxypx status = %d\n", status);
+ printf (" Sky (%11.6f, %11.6f) --> (%8.4f,%8.4f) Pixels\n",
+ xpos, ypos, xpix, ypix);
+#endif
+
+
+ if (ffclos (fptr, &status) > 0) {
+ fprintf (stderr, "Error: close status = %d\n", status);
+ return (-1);
+ }
+
+ return (0);
+}