aboutsummaryrefslogtreecommitdiff
path: root/vendor/voclient/voapps/lib
diff options
context:
space:
mode:
authorJoseph Hunkeler <jhunkeler@gmail.com>2015-07-08 20:46:52 -0400
committerJoseph Hunkeler <jhunkeler@gmail.com>2015-07-08 20:46:52 -0400
commitfa080de7afc95aa1c19a6e6fc0e0708ced2eadc4 (patch)
treebdda434976bc09c864f2e4fa6f16ba1952b1e555 /vendor/voclient/voapps/lib
downloadiraf-linux-fa080de7afc95aa1c19a6e6fc0e0708ced2eadc4.tar.gz
Initial commit
Diffstat (limited to 'vendor/voclient/voapps/lib')
-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
23 files changed, 11196 insertions, 0 deletions
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);
+}