diff options
Diffstat (limited to 'vendor/voclient/voapps/lib')
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, ">"); + vp += 4, ip++; + } else if (*ip == '<') { + strcpy (vp, "<"); + 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: %s ", pars->name); + fprintf (fd, "Object: %s \n", pars->oname); + fprintf (fd, "RA: %s \n", toSexa(pars->ra / 15.0)); + fprintf (fd, "Dec: %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 '&' encodings in the URL. + */ + for (ip = op = url; *ip; ) { + if (*ip == '&' && strncmp (ip, "&", 4) == 0) { + ip += ((strncmp (ip, "&", 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, ">", 4); + op += 4; + } else if (*ip == '>') { + strncpy (op, ">", 4); + op += 4; + } else if (*ip == '&') { + strncpy (op, "&", 5); + op += 5; + } else if (*ip == '\'') { + strncpy (op, """, 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); +} |