diff options
author | William Joye <wjoye@cfa.harvard.edu> | 2016-10-17 15:27:21 (GMT) |
---|---|---|
committer | William Joye <wjoye@cfa.harvard.edu> | 2016-10-17 15:27:21 (GMT) |
commit | 912e82088edadbdbf95d594f93ddc9dd99a305f8 (patch) | |
tree | 9153dcd3bcf256fb26ebdcbfd8a1a7d9132430f1 /xpa | |
parent | fecf4a80a5080aa65e7c2d717f96e86ad04ca46c (diff) | |
parent | d604b7940b14efb191a38ef22c3a38fa3adba4d0 (diff) | |
download | blt-912e82088edadbdbf95d594f93ddc9dd99a305f8.zip blt-912e82088edadbdbf95d594f93ddc9dd99a305f8.tar.gz blt-912e82088edadbdbf95d594f93ddc9dd99a305f8.tar.bz2 |
Merge commit 'd604b7940b14efb191a38ef22c3a38fa3adba4d0' as 'xpa'
Diffstat (limited to 'xpa')
187 files changed, 69283 insertions, 0 deletions
diff --git a/xpa/.gitignore b/xpa/.gitignore new file mode 100644 index 0000000..aa5260e --- /dev/null +++ b/xpa/.gitignore @@ -0,0 +1,20 @@ +*.[oa] +*~ +*.so +*.bak +foo* +Makefile +a.out.dSYM/ +autom4te.cache/ +oxpa.h +xpa.pc +xpaaccess +xpaget +xpainfo +xpamb +xpans +xpaset +conf.h +config.status +config.cache +config.log diff --git a/xpa/BUGS b/xpa/BUGS new file mode 100644 index 0000000..24b2a08 --- /dev/null +++ b/xpa/BUGS @@ -0,0 +1,39 @@ +using xpans as proxy for xpaset/xpaget (as in chandra-ed): + +Currently, when xpans is used as a proxy connection, an xpaset or +xpaget command will return without waiting for the remote callback to +complete. This is because xpans sets the mode of XPASetFd()/XPAGetFd() +to "dofork=true", to ensure that the XPAClientLoopFork() in client.c +is used. That routine does not wait for the callback to complete. Instead +it forks the callback and then "fakes" the completion. Using the forked +loop and returning immediately prevents xpans from hanging during a long +xpaget/xpaset callback. + +But starting with ds9 7.0, this causes problems: two successive xpaset calls +which both process regions will hang the connection to ds9. For example, +in chandra-ed's zhds9 script, a new region is generated by refinepos, +then the old region is deleted and the new region is sent to ds9 for +display: + + # refinepos creates a new region ... + ${XPASET:-xpaset} -p $XPA regions deleteall + ${XPASET:-xpaset} $XPA regions < $OFILE + +This will hang the xpans connection to ds9, starting with ds9 7.0. Bill reports +that the region parsing got slightly slower with 7.0 because he is creating +a C++ object to pass to the lexer. Somehow that causes a race condition? + +To get around the problem, a delay is needed between the calls: + + ${XPASET:-xpaset} -p $XPA regions deleteall + # this is needed to avoid a race condition, due to the fact that + # xpaset returns immediately when run via xpans proxy + sleep 1 + ${XPASET:-xpaset} $XPA regions < $OFILE + +How can this be handled automatically? Ideally, one would like to +fork() or create a thread at the "right" place in xpans to handle the +xpaset/xpaget call so that it can wait for completion. But its unclear +what that place is: the XPAHandler() is calling the send or receive +callback and expects a status response, and how can fork() deal with that?? + diff --git a/xpa/INSTALL b/xpa/INSTALL new file mode 100644 index 0000000..5c50ba5 --- /dev/null +++ b/xpa/INSTALL @@ -0,0 +1,323 @@ +Quick Summary +============= + +To build and install the XPA package, simply execute: + + ./configure # site-specific configuration + make # build the software + make install # install it + make clean # clean up unneeded temp files + +We strongly recommend that you install in a directory other than the +default of /usr/local, so as not to require root access. To do this, +configure for a different install directory: + + ./configure --prefix=<top_level_install_dir> +e.g., + ./configure --prefix=/soft/saord + +Programs will be installed in /soft/saord/bin, libraries in /soft/saord/lib, +include files in /soft/saord/include, and man pages in /soft/saord/man. +Indeed, we do this at SAO and recommend it as a general rule, in order +to keep SAORD software in one place that does not conflict with other +installations. Note that you will need to add the bin directory to +your path and the man directory to MANPATH. + +The build ("make") takes only a minute or so on modern machines. To +monitor its progress and/or check for errors, redirect output to a file +and use the 'tail' command: + + make >& foo.log &; tail -f foo.log # csh +or + make 1>foo.log 2>&1 &; tail -f foo.log # sh, bash + + +Details of Installation +======================= + + NB: These are generic installation instructions, modified for XPA. + + The `configure' shell script attempts to guess correct values for +various system-dependent variables used during compilation. It uses +those values to create a `Makefile' in each directory of the package. +It may also create one or more `.h' files containing system-dependent +definitions. Finally, it creates a shell script `config.status' that +you can run in the future to recreate the current configuration, a file +`config.cache' that saves the results of its tests to speed up +reconfiguring, and a file `config.log' containing compiler output +(useful mainly for debugging `configure'). + + If you need to do unusual things to compile the package, please try +to figure out how `configure' could check whether to do them, and mail +diffs or instructions to the address given in the `README' so they can +be considered for the next release. If at some point `config.cache' +contains results you don't want to keep, you may remove or edit it. + + The file `configure.in' is used to create `configure' by a program +called `autoconf'. You only need `configure.in' if you want to change +it or regenerate `configure' using a newer version of `autoconf'. + +The simplest way to compile this package is: + + `./configure' to configure the package for your system. If you're + using `csh' on an old version of System V, you might need to type + `sh ./configure' instead to prevent `csh' from trying to execute + `configure' itself. + + Running `configure' takes awhile. While running, it prints some + messages telling which features it is checking for. + + 1. `cd' to the directory containing the package's source code and type + "./configure". This runs a configuration script created by GNU + autoconf, which configures XPA for your system and creates a + Makefile. The configure script allows you to customize the XPA + configuration for your site; for details on how you can do this, + type "./configure -help" or refer to the autoconf documentation (not + included here). The XPA "configure" script supports the following special + switch(es) in addition to the standard ones: + + --enable-shared=yes|link + + Build shared libraries in addition to the + default static library. There are two options: + + If the value is "yes", shared libraries are + built but not used to link xpa programs. + + If the value is "link", shared libraries are + used to link xpa programs. If therefore becomes + your responsibility to put the shared library + where it can be found (or use LD_LIBRARY_PATH). + + --enable-threaded-xpans + Build xpans to support separate threads for + handling name server requests and xpa proxy + callbacks. This is recommended if you are going + to enable proxy handling in xpans (-P), since + XPA long callbacks via proxy can interfere + with the name server functions. (You still have + to start xpans with -P 2 to use 2 threads.) + + --with-tcl=<dir> + Force build Tcl support using parameters found + in <dir>/tclConfig.sh. Configure will look for + the Tcl config script in standard places and + will enable Tcl support if found. It will abort + if tclConfig.sh points to a non-existent tcl.h + file (some versions of Linux have shown this + behavior). Use this switch to override the + standard locations or to force a build even + if tcl.h is not found (e.g. if you are going to + install tcl as part of a larger build). With + Tcl support enabled you can execute: + + make tclxpa + + to generate the XPA package as a shared Tcl + object, loadable using Tcl "package require". + Contact us with problems -- its been a bear to + get this even half-way right. + + --with-threads + If you are going to link XPA into a threaded + program, you need to specify --with-threads. + This add -D_REENTRANT to the compiler flags, + which tells gcc to use thread-safe versions of + global system variables such as errno. No code + changes are made to XPA. Please note that all + XPA calls must be in a single thread: XPA is + not thread-safe in and of itself but does work + in threaded programs. + + --with-gtk=<include_dir> + Build with support for adding xpa to a gtk + loop. The specified include directory must + contain the gtk directory which itself contains + gtk.h, e.g.: + + --with-gtk=/usr/local/include/gtk-1.2 + + which contains gtk/gtk.h + + Standard options are listed below. the most important of which + are --exec-prefix and --prefix (to specify where to install), and + --x-includes=DIR and --x-libraries=DIR (for non-standard X installations). + We recommend --prefix be set to a directory that will hold saord software + (e.g., --prefix=/soft/saord) in order to make management of our software + easier. + + NB: be sure to use only absolute path names (those starting with "/") + in the --prefix and --exec_prefix options. (The configure options we + use at SAO for various machines are given as examples in the script + file called "saoconfig" in this directory.) + + 2. Type `make' to compile the package. + This will create a library archive called libxpa.a. It also will create + the programs xpaget, xpaset, xpainfo, xpaaccess, xpans, and xpamb. It + also will create the libxpa.so shared object if requested using the + --enable-shared switch + + 3. You can build the libxpa.so shared library manually by executing: + + make shlib + + at this point. This will not contain Xt or Tcl routines. If Tcl support + has been enabled (see --with-tcl above), you can build a shared library + called libtclxpa.so that supports the tclxpa package (i.e. Tcl routines + are contained in it) by executing: + + make tclxpa + + This shared library will be loaded automatically with the Tcl command: + + package require tclxpa 2.1 + + assuming, of course, that your shared library can be found by Tcl. + + 4. Type "make install" to install XPA's libraries and binaries in + standard places. You'll need write permission on the installation + directories to do this. The installation directories are + determined by the "configure" script and may be specified with + the --prefix and --exec_prefix options to "configure". See the + Makefile for information on what directories were chosen; you + can override these choices by modifying the "prefix" and + "exec_prefix" variables in the Makefile. + + 5. There are .html help files in the doc directory. You can copy + these files to a more convenient location, if you like. We + did not automate this step because we did not know where to + copy these files by default. (NB: The help.html file is the + top level index file.) + + 6. You can remove the program binaries and object files from the + source code directory by typing `make clean'. To also remove the + files that `configure' created (so you can compile the package for + a different kind of computer), type `make distclean'. There is + also a `make maintainer-clean' target, but that is intended mainly + for the package's developers. If you use it, you may have to get + all sorts of other programs in order to regenerate files that came + with the distribution. + +Compilers and Options +===================== + + Some systems require unusual options for compilation or linking that +the `configure' script does not know about. You can give `configure' +initial values for variables by setting them in the environment: + + ./configure CC=c89 CFLAGS=-O2 LIBS=-lposix + +You also can use this facility to specify a compiler other than the default +gcc (if it exists). + +Installation Names +================== + + By default, `make install' will install the package's files in +`/usr/local/bin', `/usr/local/lib', etc. You can specify an +installation prefix other than `/usr/local' by giving `configure' the +option `--prefix=PATH': + +e.g., + ./configure --prefix=/soft/saord + +Programs will be installed in /soft/saord/bin, libraries in /soft/saord/lib, +and include files in /soft/saord/include. We recommend this as a general rule, +in order to keep SAORD software in one place that does not conflict with other +installations. Note that you will need to add the bin directory to your path. + + You can specify separate installation prefixes for architecture-specific +files and architecture-independent files. If you give `configure' the option +`--exec-prefix=PATH', the package will use PATH as the prefix for installing +programs and libraries. Documentation and other data files will still use the +regular prefix. + + In addition, if you use an unusual directory layout you can give +options like `--bindir=PATH' to specify different values for particular +kinds of files. Run `configure --help' for a list of the directories +you can set and what kinds of files go in them. + + If the package supports it, you can cause programs to be installed +with an extra prefix or suffix on their names by giving `configure' the +option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'. + +Optional Features +================= + + Some packages pay attention to `--enable-FEATURE' options to +`configure', where FEATURE indicates an optional part of the package. +They may also pay attention to `--with-PACKAGE' options, where PACKAGE +is something like `gnu-as' or `x' (for the X Window System). The +`README' should mention any `--enable-' and `--with-' options that the +package recognizes. + + For packages that use the X Window System, `configure' can usually +find the X include and library files automatically, but if it doesn't, +you can use the `configure' options `--x-includes=DIR' and +`--x-libraries=DIR' to specify their locations. + +Specifying the System Type +========================== + + There may be some features `configure' can not figure out +automatically, but needs to determine by the type of host the package +will run on. Usually `configure' can figure that out, but if it prints +a message saying it can not guess the host type, give it the +`--host=TYPE' option. TYPE can either be a short name for the system +type, such as `sun4', or a canonical name with three fields: + CPU-COMPANY-SYSTEM + +See the file `config.sub' for the possible values of each field. If +`config.sub' isn't included in this package, then this package doesn't +need to know the host type. + + If you are building compiler tools for cross-compiling, you can also +use the `--target=TYPE' option to select the type of system they will +produce code for and the `--build=TYPE' option to select the type of +system on which you are compiling the package. + +Sharing Defaults +================ + + If you want to set default values for `configure' scripts to share, +you can create a site shell script called `config.site' that gives +default values for variables like `CC', `cache_file', and `prefix'. +`configure' looks for `PREFIX/share/config.site' if it exists, then +`PREFIX/etc/config.site' if it exists. Or, you can set the +`CONFIG_SITE' environment variable to the location of the site script. +A warning: not all `configure' scripts look for a site script. + +Operation Controls +================== + + `configure' recognizes the following options to control how it +operates. + +`--cache-file=FILE' + Use and save the results of the tests in FILE instead of + `./config.cache'. Set FILE to `/dev/null' to disable caching, for + debugging `configure'. + +`--help' + Print a summary of the options to `configure', and exit. + +`--quiet' +`--silent' +`-q' + Do not print messages saying which checks are being made. To + suppress all normal output, redirect it to `/dev/null' (any error + messages will still be shown). + +`--srcdir=DIR' + Look for the package's source code in directory DIR. Usually + `configure' can determine that directory automatically. + +`--version' + Print the version of Autoconf used to generate the `configure' + script, and exit. + +`configure' also accepts some other, not widely useful, options. + +If you have questions, please contact us at: saord@cfa.harvard.edu. + + Eric Mandel diff --git a/xpa/LICENSE b/xpa/LICENSE new file mode 100644 index 0000000..a9c1e78 --- /dev/null +++ b/xpa/LICENSE @@ -0,0 +1,21 @@ +XPA is distributed under the terms of The MIT License (MIT), reproduced below. + +Copyright (c) 2014-2016 Smithsonian Institution + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/xpa/Makefile.in b/xpa/Makefile.in new file mode 100644 index 0000000..79c5fd9 --- /dev/null +++ b/xpa/Makefile.in @@ -0,0 +1,558 @@ +# +# This file is a Makefile for XPA. If it has the name "Makefile.in" +# then it is a template for a Makefile; to generate the actual Makefile, +# run "./configure", which is a configuration script generated by the +# "autoconf" program (constructs like "@foo@" will get replaced in the +# actual Makefile. +# + +PACKAGE = @PACKAGE_NAME@ +VERSION = @PACKAGE_VERSION@ + +DISTNAME = xpa-${VERSION} +DISTDIR = ../export/${DISTNAME} +FTPDIR = ../ftp + +#---------------------------------------------------------------- +# Things you can change to personalize the Makefile for your own +# site (you can make these changes in either Makefile.in or +# Makefile, but changes to Makefile will get lost if you re-run +# the configuration script). +#---------------------------------------------------------------- + +# Default top-level directories in which to install architecture- +# specific files (exec_prefix) and machine-independent files such +# as scripts (prefix). The values specified here may be overridden +# at configure-time with the --exec-prefix and --prefix options +# to the "configure" script. + +prefix = @prefix@ +exec_prefix = @exec_prefix@ + +# The following definition can be set to non-null for special systems +# like AFS with replication. It allows the pathnames used for installation +# to be different than those used for actually reference files at +# run-time. INSTALL_ROOT is prepended to $prefix and $exec_prefix +# when installing files. +INSTALL_ROOT = + +# Directory in which to install the .a or .so binary for the XPA library: +LIB_INSTALL_DIR = $(INSTALL_ROOT)$(exec_prefix)/lib + +# Directory in which to install the program wish: +BIN_INSTALL_DIR = $(INSTALL_ROOT)$(exec_prefix)/bin + +# Directory in which to install the include file xpa.h: +INCLUDE_INSTALL_DIR = $(INSTALL_ROOT)$(prefix)/include + +# Top-level directory for manual entries: +MAN_INSTALL_DIR = $(INSTALL_ROOT)$(prefix)/man + +# Top-level directory for share entries: +MAN_SHARE_DIR = $(INSTALL_ROOT)$(prefix)/share/xpa + +# Platform-specific X compiler flags (include file specifications) +X_CFLAGS = @X_CFLAGS@ +# Platform-specific link directive for X libraries (-L specification) +X_LIBS = @X_LIBS@ +# Platform-specific libraries that must go before -lXt +X_PRE_LIBS = @X_PRE_LIBS@ +# Platform-specific libraries that must go after -lXt +X_EXTRA_LIBS = @X_EXTRA_LIBS@ + +# Platform-specific include files for Tcl +TCL_CFLAGS = @TCL_CFLAGS@ +# Platform-specific libraries for Tcl +TCL_LIBS = @TCL_LIBS@ + +# Platform-specific include files for Gtk +GTK_CFLAGS = @GTK_CFLAGS@ +# Platform-specific libraries for Gtk +GTK_LIBS = @GTK_LIBS@ + +# combine package cflags +PKG_CFLAGS = $(X_CFLAGS) $(TCL_CFLAGS) $(GTK_CFLAGS) + +# extra Libs required to link (e.g. socket libraries) +LIBS = @EXTRA_LIBS@ + +# pthread lib needed to xpans +TLIB = @TLIB@ + +# To change the compiler switches, for example to change from -O +# to -g, change the following line: +CFLAGS = @CFLAGS@ + +# To add ld switches, change the following line: +LDFLAGS = @LDFLAGS@ + +# Some versions of make, like SGI's, use the following variable to +# determine which shell to use for executing commands: +SHELL = /bin/sh + +# if enabled-shared was specified, this will exand to "shlib" and trigger +# building of the shared library +DOSHARED = @DOSHARED@ + +# There are just too many different versions of "install" around; +# better to use the install-sh script that comes with the distribution, +# which is slower but guaranteed to work. + +INSTALL = @srcdir@/install-sh -c +INSTALL_PROGRAM = ${INSTALL} +INSTALL_DATA = ${INSTALL} -m 644 + +#---------------------------------------------------------------- +# The information below is modified by the configure script when +# Makefile is generated from Makefile.in. You shouldn't normally +# modify any of this stuff by hand. +#---------------------------------------------------------------- + +AC_FLAGS = @DEFS@ +RANLIB = @RANLIB@ +EXE = @EXEEXT@ + +#---------------------------------------------------------------- +# The information below should be usable as is. The configure +# script won't modify it and you shouldn't need to modify it +# either. +#---------------------------------------------------------------- +RM = rm -f + +CC = @CC@ + +CC_SWITCHES = -I. ${CFLAGS} ${AC_FLAGS} + +DEPEND_SWITCHES = -I. ${CFLAGS} ${PKG_CFLAGS} ${AC_FLAGS} + +SRCS = xpa.c xpaio.c command.c acl.c remote.c clipboard.c port.c \ + tcp.c client.c word.c xalloc.c find.c xlaunch.c timedconn.c \ + tclloop.c tcl.c xtloop.c gtkloop.c \ + xpaset.c xpaget.c xpainfo.c xpaaccess.c xpans.c xpamb.c + +BASE_OBJS = xpa.o xpaio.o command.o acl.o remote.o clipboard.o port.o \ + tcp.o client.o word.o xalloc.o find.o xlaunch.o timedconn.o + +TCL_OBJS = tclloop.o tcl.o + +XT_OBJS = xtloop.o + +GTK_OBJS = gtkloop.o + +INCL = xpa.h xpap.h + +# these are all the modules going into the "normal" xpa library +LIBOBJS = ${BASE_OBJS} ${TCL_OBJS} ${XT_OBJS} ${GTK_OBJS} +LIB = libxpa.a + +# used in link line +# LLIB= $(LIB) +LLIB= @LLIB@ + +PROGS = xpaset xpaget xpainfo xpaaccess xpans xpamb + +TESTPROGS = ctest stest rtest + +all: xpa.h lib $(PROGS) + +testall: $(TESTPROGS) + +All: all testall + +install:: install-binaries + +install:: $(DOSHARED)_install + +install:: install-man + +install:: install-share + +install:: install-data + +lib: $(LIB) $(DOSHARED) + +$(LIB): $(LIBOBJS) + $(RM) $(LIB) + ar crv $(LIB) $(LIBOBJS) + $(RANLIB) $(LIB) + +shlib: $(LIB) + @(rm -rf lib$(PACKAGE).tmp; mkdir lib$(PACKAGE).tmp; \ + (cd lib$(PACKAGE).tmp && ar x ../lib$(PACKAGE).a); \ + rm -f lib$(PACKAGE).tmp/xt*.o; \ + rm -f lib$(PACKAGE).tmp/tcl*.o; \ + CC='$(CC)' CXX=$(CXX) \ + ./mklib -o $(PACKAGE) lib$(PACKAGE).tmp/*.o; \ + rm -rf lib$(PACKAGE).tmp) + +mingw-dll: $(LIBOBJS) + $(CC) -I. -DHAVE_CONFIG_H -shared port.c tcp.c acl.c find.c \ + remote.c timedconn.c client.c word.c xpaio.c clipboard.c \ + xlaunch.c xalloc.c command.c xpa.c \ + -Wl,--output-def,libxpa.def,--out-implib,libxpa_dll.a,-no-undefined,--enable-runtime-pseudo-reloc -o libxpa.dll \ + -lwsock32 + +tclxpa: $(LIB) + @(rm -rf libtclxpa.tmp; mkdir libtclxpa.tmp; \ + (cd libtclxpa.tmp && ar x ../lib$(PACKAGE).a); \ + rm -f libtclxpa.tmp/xt*.o; \ + CC='$(CC)' CXX=$(CXX) \ + ./mklib -o tclxpa libtclxpa.tmp/*.o $(TCL_LIBS); \ + test -r libtclxpa.dylib && cp -p libtclxpa.dylib libtclxpa.so && echo "copying libtclxpa.dylib to libtclxpa.so"; \ + rm -rf libtclxpa.tmp) + +diff: + -(for f in `ls *.c`; \ + do \ + echo $$f; \ + diff /soft/saord/xpa-2.1.[0-9]*/$$f .; \ + done); + +index: $(LIB) + @(test -r pkgIndex.tcl && mv pkgIndex.tcl pkgIndex.tcl-old; \ + echo "pkg_mkIndex -direct -verbose . libtclxpa.so; exit"| tclsh) + +xpaset: $(LIB) xpaset.o + $(CC) $(LDFLAGS) xpaset.o -o xpaset $(LLIB) $(LIBS) + +xpaget: $(LIB) xpaget.o + $(CC) $(LDFLAGS) xpaget.o -o xpaget $(LLIB) $(LIBS) + +xpainfo: $(LIB) xpainfo.o + $(CC) $(LDFLAGS) xpainfo.o -o xpainfo $(LLIB) $(LIBS) + +xpaaccess: $(LIB) xpaaccess.o + $(CC) $(LDFLAGS) xpaaccess.o -o xpaaccess $(LLIB) $(LIBS) + +xpans: $(LIB) xpans.o + $(CC) $(LDFLAGS) xpans.o -o xpans $(LLIB) $(LIBS) $(TLIB) + +xpamb: $(LIB) xpamb.o + $(CC) $(LDFLAGS) xpamb.o -o xpamb $(LLIB) $(LIBS) + +ctest: $(LIB) ctest.o + $(CC) $(LDFLAGS) ctest.o -o ctest $(LLIB) $(LIBS) + +stest: $(LIB) stest.o + $(CC) $(LDFLAGS) stest.o -o stest $(LIB) $(LIBS) + +rtest: $(LIB) rtest.o + $(CC) $(LDFLAGS) rtest.o -o rtest $(LIB) $(LIBS) + +stestx: $(LIB) stest.o + $(CC) $(LDFLAGS) stest.o -o stest $(LIB) \ + $(X_LIBS) -lXt $(X_PRE_LIBS) -lXext -lX11 $(LIBS) + +# Smoke test: allows end-users to quickly discern basic usability +smoke: ctest stest + ./stest smoke & + sleep 3 + ./ctest -e -b -l 1000 smoke + ./xpaset -p smoke exit + +# Note: before running ranlib below, must cd to target directory because +# some ranlibs write to current directory, and this might not always be +# possible (e.g. if installing as root). + +# this nop-op gets executed if we are not building shared libraries +_install: + +shlib_install: + @-(for i in `ls *.so* *.dylib *.sl 2>/dev/null` ; \ + do \ + if [ -h $$i ] ; then \ + echo "Installing link $$i" ; \ + tar cf - $$i | (cd $(LIB_INSTALL_DIR); tar xf -) ; \ + else \ + echo "Installing $$i" ; \ + $(INSTALL_DATA) $$i $(LIB_INSTALL_DIR)/$$i ; \ + chmod 555 $(LIB_INSTALL_DIR)/$$i; \ + fi; \ + done;) + +install-binaries: $(LIB) $(PROGS) + @for i in $(LIB_INSTALL_DIR) $(INCLUDE_INSTALL_DIR) $(BIN_INSTALL_DIR) ; \ + do \ + if [ ! -d $$i ] ; then \ + echo "Making directory $$i"; \ + mkdir $$i; \ + chmod 755 $$i; \ + else true; \ + fi; \ + done; + @echo "Installing $(LIB)"; + @$(INSTALL_DATA) $(LIB) $(LIB_INSTALL_DIR)/$(LIB); + @(cd $(LIB_INSTALL_DIR); $(RANLIB) $(LIB)); + @chmod 555 $(LIB_INSTALL_DIR)/$(LIB); + @echo "Installing xpa.h" + @$(INSTALL_DATA) xpa.h $(INCLUDE_INSTALL_DIR)/xpa.h + @echo "Installing prsetup.h" + @$(INSTALL_DATA) prsetup.h $(INCLUDE_INSTALL_DIR)/prsetup.h + @for i in $(PROGS) ; \ + do \ + echo "Installing $$i$(EXE)" ; \ + $(INSTALL_PROGRAM) $$i$(EXE) $(BIN_INSTALL_DIR)/$$i$(EXE) ; \ + done; + +install-man: + @if [ ! -d $(MAN_INSTALL_DIR) ] ; then \ + echo "Making directory $(MAN_INSTALL_DIR)"; \ + mkdir $(MAN_INSTALL_DIR); \ + chmod 755 $(MAN_INSTALL_DIR); \ + else true; \ + fi; + @-(for i in `ls ./man/man?/*.?` ; \ + do \ + B=`basename $$i`; \ + E=`echo $$i | awk -F. '{print $$NF}'`; \ + M="$(MAN_INSTALL_DIR)/man$$E"; \ + if [ ! -d $$M ] ; then \ + echo "Making directory $$M"; \ + mkdir $$M; \ + chmod 755 $$M; \ + else true; \ + fi; \ + echo "Installing $$B" ; \ + $(INSTALL_DATA) $$i $$M/$$B; \ + done;) + +install-share: + @if [ ! -d $(MAN_SHARE_DIR) ] ; then \ + echo "Making directory $(MAN_SHARE_DIR)"; \ + mkdir -p $(MAN_SHARE_DIR); \ + chmod 755 $(MAN_SHARE_DIR); \ + else true; \ + fi; + @-(for i in `ls ./doc/sman/xpa?.*` ; \ + do \ + B=`basename $$i`; \ + echo "Installing $$B" ; \ + $(INSTALL_DATA) $$i $(MAN_SHARE_DIR)/$$B; \ + done;) + +install-data: install-pkgconfig + +install-pkgconfig: + @-(mkdir -p $(LIB_INSTALL_DIR)/pkgconfig; \ + echo "Installing xpa.pc" ; \ + $(INSTALL_DATA) xpa.pc $(LIB_INSTALL_DIR)/pkgconfig;) + +Makefile: Makefile.in + $(SHELL) config.status + +clean: + $(RM) *.a *.so *.so.* *.dylib *.o *.exe core \ + errs *pure* .nfs* \ + foo* *~ *.log \#* TAGS *.E a.out errors \ + $(PROGS) $(TESTPROGS) \ + gmon.out *.pg *.bak \ + config.info config.log \ + doc/*~ doc/*.bak man/*~ + $(RM) -r autom4te.cache a.out.dSYM + +distclean: clean + $(RM) Makefile config.status config.cache config.log conf.h \ + xpa.pc + +maintainer-clean:: clean + $(RM) config.status config.cache config.log + +depend: + makedepend -- $(DEPEND_SWITCHES) -- $(SRCS) + +acl.o: acl.c $(INCL) + $(CC) -c $(CC_SWITCHES) acl.c + +remote.o: remote.c $(INCL) + $(CC) -c $(CC_SWITCHES) remote.c + +clipboard.o: clipboard.c $(INCL) + $(CC) -c $(CC_SWITCHES) clipboard.c + +client.o: client.c $(INCL) + $(CC) -c $(CC_SWITCHES) client.c + +command.o: command.c $(INCL) + $(CC) -c $(CC_SWITCHES) command.c + +find.o: find.c + $(CC) -c $(CC_SWITCHES) find.c + +xlaunch.o: xlaunch.c + $(CC) -c $(CC_SWITCHES) xlaunch.c + +timedconn.o: timedconn.c + $(CC) -c $(CC_SWITCHES) timedconn.c + +port.o: port.c $(INCL) + $(CC) -c $(CC_SWITCHES) port.c + +tcl.o: tcl.c $(INCL) + $(CC) -c $(CC_SWITCHES) $(TCL_CFLAGS) tcl.c + +tclloop.o: tclloop.c $(INCL) + $(CC) -c $(CC_SWITCHES) $(TCL_CFLAGS) tclloop.c + +gtkloop.o: gtkloop.c $(INCL) + $(CC) -c $(CC_SWITCHES) $(GTK_CFLAGS) gtkloop.c + +tcp.o: tcp.c + $(CC) -c $(CC_SWITCHES) tcp.c + +word.o: word.c + $(CC) -c $(CC_SWITCHES) word.c + +xalloc.o: xalloc.c + $(CC) -c $(CC_SWITCHES) xalloc.c + +xpa.o: xpa.c $(INCL) + $(CC) -c $(CC_SWITCHES) xpa.c + +xpaio.o: xpaio.c $(INCL) + $(CC) -c $(CC_SWITCHES) xpaio.c + +xtloop.o: xtloop.c $(INCL) + $(CC) -c $(CC_SWITCHES) $(X_CFLAGS) xtloop.c + +xpaaccess.o: xpaaccess.c $(INCL) + $(CC) -c $(CC_SWITCHES) xpaaccess.c + +xpaget.o: xpaget.c $(INCL) + $(CC) -c $(CC_SWITCHES) xpaget.c + +xpainfo.o: xpainfo.c $(INCL) + $(CC) -c $(CC_SWITCHES) xpainfo.c + +xpans.o: xpans.c $(INCL) + $(CC) -c $(CC_SWITCHES) xpans.c + +xpamb.o: xpamb.c $(INCL) + $(CC) -c $(CC_SWITCHES) xpamb.c + +xpaset.o: xpaset.c $(INCL) + $(CC) -c $(CC_SWITCHES) xpaset.c + +ctest.o: ctest.c + $(CC) -c $(CC_SWITCHES) ctest.c + +stest.o: stest.c + $(CC) -c $(CC_SWITCHES) $(X_CFLAGS) stest.c + +rtest.o: rtest.c + $(CC) -c $(CC_SWITCHES) $(X_CFLAGS) rtest.c + +stestx.o: stest.c + $(CC) -o stest.o -c $(CC_SWITCHES) $(X_CFLAGS) \ + -DBUILD_WITH_XT stest.c + +strstr.o: ./compat/strstr.c + $(CC) -c $(CC_SWITCHES) -o strstr.o ./compat/strstr.c + +xpa.h: configure.ac + @($(RM) -r oxpa.h; \ + MAJOR=`echo "${VERSION}" | awk -F. '{print $$1}'`; \ + MINOR=`echo "${VERSION}" | awk -F. '{print $$2}'`; \ + PATCH=`echo "${VERSION}" | awk -F. '{print $$3}'`; \ + sed "s/^#define XPA_VERSION.*/#define XPA_VERSION \"$(VERSION)\"/;s/^#define XPA_MAJOR_VERSION.*/#define XPA_MAJOR_VERSION $${MAJOR}/;s/^#define XPA_MINOR_VERSION.*/#define XPA_MINOR_VERSION $${MINOR}/;s/^#define XPA_PATCH_LEVEL.*/#define XPA_PATCH_LEVEL $${PATCH}/;" < xpa.h > nxpa.h; \ + mv xpa.h oxpa.h; \ + mv nxpa.h xpa.h) + +configure: configure.ac + autoconf + +dist: configure + ($(RM) -r $(DISTDIR); \ + mkdir $(DISTDIR); \ + cp -p *.[ch] *.tcl $(DISTDIR)/.; \ + cp -p pkgIndex.tcl $(DISTDIR)/.; \ + cp -p Makefile.in $(DISTDIR)/.; \ + chmod 664 $(DISTDIR)/Makefile.in; \ + cp -p conf.h.in $(DISTDIR)/.; \ + chmod 664 $(DISTDIR)/conf.h.in; \ + cp -p configure.ac $(DISTDIR)/.; \ + chmod 644 $(DISTDIR)/configure.ac; \ + cp -p *.m4 $(DISTDIR)/.; \ + chmod 644 $(DISTDIR)/*.m4; \ + cp -p configure $(DISTDIR)/.; \ + chmod 755 $(DISTDIR)/configure; \ + cp -p config.sub config.guess $(DISTDIR)/.; \ + chmod 755 $(DISTDIR)/config.sub $(DISTDIR)/config.guess; \ + cp -p saoconfig $(DISTDIR)/.; \ + chmod 755 $(DISTDIR)/saoconfig; \ + cp -p mklib $(DISTDIR)/.; \ + chmod 755 $(DISTDIR)/mklib; \ + cp -p install-sh $(DISTDIR)/install-sh; \ + chmod 755 $(DISTDIR)/install-sh; \ + cp -p README INSTALL COPYING $(DISTDIR)/.; \ + mkdir $(DISTDIR)/doc; \ + cp -p ./doc/*.html $(DISTDIR)/doc/.; \ + cp -p ./doc/*.ps ./doc/*.pdf $(DISTDIR)/doc/.; \ + cp -p ./doc/Makefile $(DISTDIR)/doc/.; \ + mkdir $(DISTDIR)/doc/sman; \ + cp -p ./doc/sman/* $(DISTDIR)/doc/sman/.; \ + mkdir $(DISTDIR)/man; \ + cp -p -R ./man/* $(DISTDIR)/man/.) + +release: dist + (cd $(DISTDIR); cd ..; \ + tar cf - $(DISTNAME) | \ + gzip -9 -c > $(FTPDIR)/$(DISTNAME).tar.gz) + +tar: + ($(RM) config.cache; \ + cd ..; \ + tar cf - $(DISTNAME) | gzip -9 -c > $(DISTNAME).tar.gz) + +errcheck: + @-egrep 'error|warning' foo + +itar: + (cd doc/sman; \ + tar cf - . | gzip -9 -c > ../../../$(DISTNAME)-iman.tar.gz) + +sman: + @(cd doc && $(MAKE) index) + +docs: + @(cd doc; $(MAKE)) + +pure: xpaset.pure xpaget.pure xpainfo.pure xpaaccess.pure \ + xpans.pure xpamb.pure ctest.pure stest.pure rtest.pure + +xpaset.pure: $(LIB) xpaset.o + purify $(CC) $(LDFLAGS) xpaset.o -o xpaset.pure \ + $(LLIB) $(LIBS) + +xpaget.pure: $(LIB) xpaget.o + purify $(CC) $(LDFLAGS) xpaget.o -o xpaget.pure \ + $(LLIB) $(LIBS) + +xpainfo.pure: $(LIB) xpainfo.o + purify $(CC) $(LDFLAGS) xpainfo.o -o xpainfo.pure \ + $(LLIB) $(LIBS) + +xpaaccess.pure: $(LIB) xpaaccess.o + purify $(CC) $(LDFLAGS) xpaaccess.o -o xpaaccess.pure \ + $(LLIB) $(LIBS) + +xpans.pure: $(LIB) xpans.o + purify $(CC) $(LDFLAGS) xpans.o -o xpans.pure \ + $(LLIB) $(LIBS) $(TLIB) + +xpamb.pure: $(LIB) xpamb.o + purify $(CC) $(LDFLAGS) xpamb.o -o xpamb.pure \ + $(LLIB) $(LIBS) + +ctest.pure: $(LIB) ctest.o + purify $(CC) $(LDFLAGS) ctest.o -o ctest.pure \ + $(LLIB) $(LIBS) + +stest.pure: $(LIB) stest.o + purify $(CC) $(LDFLAGS) stest.o -o stest.pure $(LIB) \ + $(X_LIBS) -lXt $(X_PRE_LIBS) -lXext -lX11 $(LIBS) + +rtest.pure: $(LIB) rtest.o + purify $(CC) $(LDFLAGS) rtest.o -o rtest.pure \ + $(LLIB) $(LIBS) + +# DO NOT DELETE THIS LINE -- make depend depends on it. diff --git a/xpa/README b/xpa/README new file mode 100644 index 0000000..08a4bcb --- /dev/null +++ b/xpa/README @@ -0,0 +1,43 @@ +This is the directory for XPA 2.0. + +The XPA messaging system provides seamless communication between many +kinds of Unix programs, including X programs and Tcl/Tk programs. It +also provides an easy way for users to communicate with XPA-enabled +programs by executing XPA client commands in the shell or by utilizing +such commands in scripts. Because XPA works both at the programming +level and the shell level, it is a powerful tool for unifying any +analysis environment: users and programmers have great flexibility in +choosing the best level or levels at which to access XPA services, and +client access can be extended or modified easily at any time. + +A program becomes an XPA-enabled server by defining named points of +public access through which data and commands can be exchanged with +other client programs (and users). Using standard TCP sockets as a +transport mechanism, XPA supports both single-point and broadcast +messaging to and from these servers. It supports direct communication +between clients and servers, or indirect communication via an +intermediate message bus emulation program. Host-based access control +is implemented, as is as the ability to communicate with XPA servers +across a network. + +XPA implements a layered interface that is designed to be useful both +to software developers and to users. The interface consists of a +library of XPA client and server routines for use in C/C++ programs and +a suite of high-level user programs built on top of these libraries. +Using the XPA library, access points can be added to Tcl/Tk programs, +Xt programs, or to Unix programs that use the XPA event loop or any +event loop based on select(). Client access subroutines can be added +to any Tcl/Tk, Xt, or Unix program. Client access also is supported at +the command line via a suite of high-level programs. + +To build XPA, see the INSTALL instructions (which are based on +standard instructions for building software using GNU configure). + +Documentation for XPA is contained in the doc subdirectory (where the +help.html file is the top-level index). + +If you have questions, please contact us at: saord@cfa.harvard.edu. + + Eric Mandel + +XPA is distributed under the terms of The MIT License. diff --git a/xpa/acl.c b/xpa/acl.c new file mode 100644 index 0000000..24b4489 --- /dev/null +++ b/xpa/acl.c @@ -0,0 +1,568 @@ +/* + * Copyright (c) 1999-2003 Smithsonian Astrophysical Observatory + */ + +/* + * + * acl.c -- xpa access control list management + * + */ + +#include <xpap.h> + +/* + *---------------------------------------------------------------------------- + * + * + * Private Routines + * + * + *---------------------------------------------------------------------------- + */ + +/* this is the head of the global list -- too lazy to do anything more */ +static XACL aclhead=NULL; + +#ifdef ANSI_FUNC +static XACL +XPAAclLookup (char *xclass, char *name, unsigned int ip, int exact) +#else +static XACL XPAAclLookup(xclass, name, ip, exact) + char *xclass; + char *name; + unsigned int ip; + int exact; +#endif +{ + XACL cur; + /* look for exact match */ + for(cur=aclhead; cur!=NULL; cur=cur->next){ + if( !strcmp(xclass, cur->xclass) && + !strcmp(name, cur->name) && + ((cur->ip == 0) || (cur->ip == ip)) ){ + return(cur); + } + } + /* otherwise look for a template match (unless exact was specified) */ + if( !exact ){ + for(cur=aclhead; cur!=NULL; cur=cur->next){ + if( tmatch(xclass, cur->xclass) && + tmatch(name, cur->name) && + ((cur->ip == 0) || (cur->ip == ip)) ){ + return(cur); + } + } + } + return(NULL); +} + +/* + *---------------------------------------------------------------------------- + * + * Routine: XPAAclParse + * + * Purpose: parse acl list into components + * + * Returns: 0 on success, -1 on failure + * + *---------------------------------------------------------------------------- + */ +#ifdef ANSI_FUNC +static int +XPAAclParse (char *lbuf, char *xclass, char *name, unsigned int *ip, + char *acl, int len) +#else +static int XPAAclParse(lbuf, xclass, name, ip, acl, len) + char *lbuf; + char *xclass; + char *name; + unsigned int *ip; + char *acl; + int len; +#endif +{ + char tbuf[SZ_LINE]; + int lp=0; + + /* class:name is required */ + if( word(lbuf, tbuf, &lp) ){ + XPAParseName(tbuf, xclass, name, len); + } + else + return(-1); + + /* host is required but can be "*" for "all hosts" */ + if( word(lbuf, tbuf, &lp) ){ + if( !strcmp(tbuf, "*") ) + *ip = 0; + else + *ip = gethostip(tbuf); + } + else + return(-1); + + /* acl is required */ + if( word(lbuf, tbuf, &lp) ){ + if( !strcmp(tbuf, "+") ) + strcpy(acl, XPA_ACLS); + else if( !strcmp(tbuf, "-") ) + *acl = '\0'; + else + strcpy(acl, tbuf); + return(0); + } + else + return(-1); +} + +/* + *---------------------------------------------------------------------------- + * + * + * Semi-Public Routines (used by command.c) + * + * + *---------------------------------------------------------------------------- + */ + +/* + *---------------------------------------------------------------------------- + * + * Routine: XPAReceiveAcl + * + * Purpose: add or modify the acl for this access point + * + * Returns: 0 for success, -1 for failure + * + *---------------------------------------------------------------------------- + */ +#ifdef ANSI_FUNC +int +XPAReceiveAcl (void *client_data, void *call_data, char *paramlist, + char *buf, size_t len) +#else +int XPAReceiveAcl(client_data, call_data, paramlist, buf, len) + void *client_data; + void *call_data; + char *paramlist; + char *buf; + size_t len; +#endif +{ + XPA xpa = (XPA)call_data; + XPAComm comm; + int i; + int got; + char *s=NULL; + char lbuf[SZ_LINE]; + char tbuf[SZ_LINE]; + + if( paramlist && *paramlist ){ + s = paramlist; + while( isspace((int)*s) ) + s++; + snprintf(tbuf, SZ_LINE, "%s:%s %s\n", xpa->xclass, xpa->name, s); + if( XPAAclEdit(tbuf) < 0 ){ + snprintf(lbuf, SZ_LINE, "invalid acl: %s\n", tbuf); + XPAError(xpa, lbuf); + return(-1); + } + } + else{ + while((XPAGets(xpa, xpa_datafd(xpa), lbuf, SZ_LINE, XPAShortTimeout())>0)&& + *lbuf ){ + snprintf(tbuf, SZ_LINE, "%s:%s %s\n", xpa->xclass, xpa->name, lbuf); + got = XPAAclEdit(tbuf); + if( got < 0 ){ + snprintf(lbuf, SZ_LINE, "invalid acl: %s\n", tbuf); + XPAError(xpa, lbuf); + return(-1); + } + } + } + + /* reset all acl flags for this xpa so acl is recalculated */ + for(comm=xpa->commhead; comm!=NULL; comm=comm->next){ + for(i=0; i<4; i++){ + comm->acl[i] = -1; + } + } + + return(0); +} + +/* + *---------------------------------------------------------------------------- + * + * Routine: XPASendAcl + * + * Purpose: return the acl for this access point + * + * Returns: 0 for success, -1 for failure + * + *---------------------------------------------------------------------------- + */ +#ifdef ANSI_FUNC +int +XPASendAcl (void *client_data, void *call_data, char *paramlist, + char **buf, size_t *len) +#else +int XPASendAcl(client_data, call_data, paramlist, buf, len) + void *client_data; + void *call_data; + char *paramlist; + char **buf; + size_t *len; +#endif +{ + XPA xpa = (XPA)call_data; + XACL cur; + int got = 0; + char tbuf[SZ_LINE]; + + /* zero all flags */ + for(cur=aclhead; cur!=NULL; cur=cur->next){ + cur->flag = 0; + } + /* look for exact matches */ + for(cur=aclhead; cur!=NULL; cur=cur->next){ + if(!strcmp(xpa->xclass, cur->xclass) && !strcmp(xpa->name, cur->name)){ + snprintf(tbuf, SZ_LINE, "%s:%s %s %s\n", + cur->xclass, cur->name, getiphost(cur->ip), cur->acl); + send(xpa_datafd(xpa), tbuf, strlen(tbuf), 0); + cur->flag = 1; + got++; + } + } + /* look for template matches that we have not printed yet */ + for(cur=aclhead; cur!=NULL; cur=cur->next){ + if( cur->flag == 0 ){ + if(tmatch(xpa->xclass, cur->xclass) && tmatch(xpa->name, cur->name)){ + snprintf(tbuf, SZ_LINE, "%s:%s %s %s\n", + cur->xclass, cur->name, getiphost(cur->ip), cur->acl); + send(xpa_datafd(xpa), tbuf, strlen(tbuf), 0); + got++; + } + } + } + /* zero all flags */ + for(cur=aclhead; cur!=NULL; cur=cur->next){ + cur->flag = 0; + } + if( got == 0 ){ + send(xpa_datafd(xpa), "\n", 1, 0); + } + return(0); +} + +/* + *---------------------------------------------------------------------------- + * + * + * Public Routines + * + * + *---------------------------------------------------------------------------- + */ + +/* + *---------------------------------------------------------------------------- + * + * Routine: XPAAclEdit + * + * Purpose: add or modify acl entry in the xpa acl list + * + * Returns: 0 on success, -1 on failure + * + *---------------------------------------------------------------------------- + */ +#ifdef ANSI_FUNC +int +XPAAclEdit (char *lbuf) +#else +int XPAAclEdit(lbuf) + char *lbuf; +#endif +{ + XACL cur; + char xclass[SZ_LINE]; + char name[SZ_LINE]; + char acl[SZ_LINE]; + unsigned int ip; + + if( XPAAclParse(lbuf, xclass, name, &ip, acl, SZ_LINE) < 0 ) + return(-1); + if( ip == 0 ) + return(-1); + cur = XPAAclLookup(xclass, name, ip, 1); + if( cur == NULL ) + return(XPAAclAdd(lbuf)); + else{ + if( *acl == '\0' ){ + XPAAclDel(cur); + } + else{ + if( cur->acl ) + xfree(cur->acl); + cur->acl = xstrdup(acl); + } + return(0); + } +} + + +/* + *---------------------------------------------------------------------------- + * + * Routine: XPAAclAdd + * + * Purpose: add one acl entry to the xpa acl list + * + * Returns: 0 on success, -1 on failure + * + *---------------------------------------------------------------------------- + */ +#ifdef ANSI_FUNC +int +XPAAclAdd (char *lbuf) +#else +int XPAAclAdd(lbuf) + char *lbuf; +#endif +{ + XACL xnew; + XACL cur; + char xclass[SZ_LINE]; + char name[SZ_LINE]; + char acl[SZ_LINE]; + unsigned int ip; + + /* allocate acl struct */ + if( (xnew = (XACL)xcalloc(1, sizeof(XACLRec))) == NULL ) + goto error; + + /* parse info from line buffer */ + if( XPAAclParse(lbuf, xclass, name, &ip, acl, SZ_LINE) < 0 ) + goto error; + + /* fill in the blanks */ + xnew->xclass = xstrdup(xclass); + xnew->name = xstrdup(name); + xnew->ip = ip; + xnew->acl = xstrdup(acl); + + /* add this acl to end of list of acl's */ + if( aclhead == NULL ){ + aclhead = xnew; + } + else{ + for(cur=aclhead; cur->next!=NULL; cur=cur->next) + ; + cur->next = xnew; + } + return(0); + +error: + if( xnew ) + xfree(xnew); + return(-1); +} + +/* + *--------------------------------------------------------------------------- + * + * Routine: XPAAclDel + * + * Purpose: free up memory in the acl record structure + * + * Results: 0 on success, -1 for failure + * + *--------------------------------------------------------------------------- + */ +#ifdef ANSI_FUNC +int +XPAAclDel (XACL acl) +#else +int XPAAclDel(acl) + XACL acl; +#endif +{ + XACL cur; + + if( acl == NULL ) + return(-1); + + /* remove from list of acl's */ + if( aclhead ){ + if( aclhead == acl ){ + aclhead = aclhead->next; + } + else{ + for(cur=aclhead; cur!=NULL; cur=cur->next){ + if( cur->next == acl ){ + cur->next = (cur->next)->next; + break; + } + } + } + } + + /* free up string space */ + if( acl->xclass ) xfree(acl->xclass); + if( acl->name ) xfree(acl->name); + if( acl->acl ) xfree(acl->acl); + + /* free up record struct */ + xfree((char *)acl); + return(0); +} + +/* + *---------------------------------------------------------------------------- + * + * Routine: XPAAclFree + * + * Purpose: + * + * Results: 1 on success, 0 for failure + * + *---------------------------------------------------------------------------- + */ +#ifdef ANSI_FUNC +void +XPAAclFree (void) +#else +void XPAAclFree() +#endif +{ + XACL cur, tacl; + + for(cur=aclhead; cur!=NULL; ){ + tacl = cur->next; + XPAAclDel(cur); + cur = tacl; + } +} + +/* + *---------------------------------------------------------------------------- + * + * Routine: XPAAclNew + * + * Purpose: read or re-read the acl list + * + * Results: number of lines in list (including default) + * + *---------------------------------------------------------------------------- + */ +#ifdef ANSI_FUNC +int +XPAAclNew (char *aname, int flag) +#else +int XPAAclNew(aname, flag) + char *aname; + int flag; +#endif +{ + int got=0; + char lbuf[SZ_LINE]; + char hostname[SZ_LINE]; + char *s; + char *obuf; + char *aclname=NULL; + char *aclpath=NULL; + char *defacl=NULL; + char *defcopy=NULL; + char *keywords[10]; + char *values[10]; + int nkeys; + FILE *fp=NULL; + + /* if there is an old list, free it */ + if( flag == 0 ) + XPAAclFree(); + + /* get acl file name */ + if( aname && *aname ) + aclname = aname; + else if( (aclname=(char *)getenv("XPA_ACLFILE")) == NULL ) + aclname = XPA_ACLFILE; + + /* get the default acl */ + if( (defacl=(char *)getenv("XPA_DEFACL")) == NULL ) + defacl = XPA_DEFACL; + + /* macro-expand it to deal with the host name */ + gethost(hostname, SZ_LINE); + nkeys = 0; + keywords[0] = "host"; values[0] = hostname; nkeys++; + + /* open the acl file */ + if( (aclpath=(char *)Access(aclname, "r")) != NULL ){ + if( (fp=fopen(aclpath, "r")) != NULL ){ + while( fgets(lbuf, SZ_LINE, fp) ){ + if( *lbuf == '#' ){ + continue; + } + if( (obuf=macro(lbuf, keywords, values, nkeys, NULL, NULL)) != NULL ){ + if( XPAAclAdd(obuf) == 0 ) + got++; + xfree(obuf); + } + } + fclose(fp); + } + xfree(aclpath); + } + + /* add default acl (it very likely was overridden in the file) */ + defcopy=(char *)xstrdup(defacl); + for(s=(char *)strtok(defcopy,";"); s!=NULL; s=(char *)strtok(NULL,";")){ + if( (obuf = macro(s, keywords, values, nkeys, NULL, NULL)) != NULL ){ + if( XPAAclAdd(obuf) == 0 ) + got++; + xfree(obuf); + } + } + if( defcopy) xfree(defcopy); + + /* return the news */ + return(got); +} + +/* + *---------------------------------------------------------------------------- + * + * Routine: XPAAclCheck + * + * Purpose: validate an acl for a given class, name, and host + * + * Results: 1 on success, 0 on failure + * + *---------------------------------------------------------------------------- + */ +#ifdef ANSI_FUNC +int +XPAAclCheck (XPA xpa, unsigned int ip, char *acl) +#else +int XPAAclCheck(xpa, ip, acl) + XPA xpa; + unsigned int ip; + char *acl; +#endif +{ + char *s; + XACL cur; + + if( !(cur = XPAAclLookup(xpa->xclass, xpa->name, ip, 0)) ) + return(0); + else if( cur->acl == NULL ) + return(0); + else{ + for(s=acl; *s; s++){ + if( !strchr(cur->acl, *s) ) + return(0); + } + return(1); + } +} diff --git a/xpa/aclocal.m4 b/xpa/aclocal.m4 new file mode 100644 index 0000000..bc7540d --- /dev/null +++ b/xpa/aclocal.m4 @@ -0,0 +1 @@ +builtin(include,tcl.m4) diff --git a/xpa/client.c b/xpa/client.c new file mode 100644 index 0000000..f70ff40 --- /dev/null +++ b/xpa/client.c @@ -0,0 +1,3057 @@ +/* + * Copyright (c) 1999-2003 Smithsonian Astrophysical Observatory + */ + +#include <xpap.h> + +/* + *---------------------------------------------------------------------------- + * + * + * Private Routines and Data + * + * + *---------------------------------------------------------------------------- + */ + +/* this is the head of the global list of client xpas */ +static XPA xpaclienthead=NULL; + +static char errbuf[SZ_LINE]; /* holds current error message */ +static int id=0; /* id of current command */ + +#define DATA_CONNECT 1 +#define DATA_ACCEPT 2 +#define DATA_DATA 4 + +/* use of a double fork() call is used to prevent zombies which happen + if fork is a child of xpans started by an XPA server (i.e., for some + reason, the SIGCHLD signal does not get sent to xpans parent) + See Stevens, Advanced Programming in te Unix Environment, p. 202 */ +#define USE_DOUBLE_FORK 1 +#ifndef USE_DOUBLE_FORK +#ifdef ANSI_FUNC +void sig_chld(int signo) +#else +#endif +{ + int stat; + + while(waitpid(-1, &stat, WNOHANG) > 0){ + ; + } + return; +} +#endif + +/* + *---------------------------------------------------------------------------- + * + * Routine: rdl + * + * Purpose: read characters up a new-line + * + * Returns: number of characters read + * + *---------------------------------------------------------------------------- + */ +#ifdef ANSI_FUNC +static int +rdl (int fd, char *buf, size_t len) +#else +static int rdl(fd, buf, len) + int fd; + char *buf; + int len; +#endif +{ + int i=0; + int got; + + /* start out clean */ + *buf = '\0'; + + /* make sure we have a valid channel */ + if( fd < 0 ) + return(-1); + + /* grab characters up to a new-line or max len */ + while( i < (len-1) ){ + got = read(fd, &(buf[i]), 1); + if( got < 1 ) + break; + else if( buf[i++] == '\n' ) + break; + } + buf[i] = '\0'; + return(i); +} + +/* + *---------------------------------------------------------------------------- + * + * Routine: XPAProxyAccept + * + * Purpose: accept a connection from an XPA proxy server + * + * Return: fd of accepted connection or -1 + * + *---------------------------------------------------------------------------- + */ +#ifdef ANSI_FUNC +static +int XPAProxyAccept(XPA xpa, char *method, char *xclass, char *name, int ifd, + unsigned int *rip, unsigned short *rport, char *rname) +#else +static +int XPAProxyAccept(xpa, method, xclass, name, ifd, rip, rport, rname) + XPA xpa; + char *method; + char *xclass; + char *name; + int ifd; + unsigned int *rip; + unsigned short *rport; + char *rname; +#endif +{ + int sock; + int got; + int oum; + int ofd; + int niter; + int swidth=FD_SETSIZE; + int keep_alive=1; + int reuse_addr=1; + unsigned int ip; + unsigned short port; + char tbuf[SZ_LINE]; + char amethod[SZ_LINE]; + char *tptr; + socklen_t slen; + struct sockaddr_in sock_in; +#if HAVE_SYS_UN_H + struct sockaddr_un sock_un; +#endif + struct timeval tv; + struct timeval *tvp; + fd_set readfds; + + /* initialize results */ + if( rip ) *rip = 0; + if( rport ) *rport = 0; + if( rname ) *rname = '\0'; + + switch(XPAMethod(method)){ + case XPA_INET: + if( !XPAParseIpPort(method, &ip, &port) ){ + goto error; + } + /* open a socket for data connections */ + if( (sock = xsocket(AF_INET, SOCK_STREAM, 0)) < 0 ){ + PERROR(("xpaaccept socket")); + goto error; + } + setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, + (char *)&keep_alive, sizeof(keep_alive)); + setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, + (char *)&reuse_addr, sizeof(reuse_addr)); + memset((char *)&sock_in, 0, sizeof(sock_in)); + sock_in.sin_family = AF_INET; + sock_in.sin_addr.s_addr = htonl(INADDR_ANY); + sock_in.sin_port = htons(port); + /* bind to the ip:port */ + if( xbind(sock, (struct sockaddr *)&sock_in, sizeof(sock_in)) < 0 ){ + PERROR(("xpaaccept bind")); + xclose(sock); + goto error; + } + snprintf(amethod, SZ_LINE, "%x:%d", ip, port); + break; +#if HAVE_SYS_UN_H + case XPA_UNIX: + ip = 0; + port = 0; + /* get filename part, composed of class and name and unique id */ + snprintf(tbuf, SZ_LINE, "%s_%s.%d", xclass, name, (int)time(NULL)); + /* change "/" to "_" for filename */ + for(tptr = tbuf; *tptr != '\0'; tptr++){ + if( *tptr == '/' ) *tptr = '_'; + } + /* create full pathname */ + snprintf(amethod, SZ_LINE, "%s/%s", XPATmpdir(), tbuf); + /* delete old copy */ + unlink (amethod); + /* open a socket and fill in socket information */ + if( (sock = xsocket(AF_UNIX, SOCK_STREAM, 0)) < 0 ){ + goto error; + } + setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, + (char *)&keep_alive, sizeof(keep_alive)); + memset((char *)&sock_un, 0, sizeof(sock_un)); + sock_un.sun_family = AF_UNIX; + strcpy(sock_un.sun_path, amethod); + /* unset umask so that everyone can read and write */ + oum = umask(0); + /* bind to the file */ + got = xbind(sock, (struct sockaddr *)&sock_un, sizeof(sock_un)); + /* reset umask to previous */ + umask(oum); + /* now check for bind error */ + if( got < 0 ){ + xclose(sock); + goto error; + } + break; +#endif + default: + goto error; + } + + /* send port to client so they can connect */ + /* first listen for the connection */ + if( listen(sock, XPA_MAXLISTEN) < 0 ){ + PERROR(("xpaaccept listen")); + xclose(sock); + goto error; + } + + /* and tell the client that we are listening */ + snprintf(tbuf, SZ_LINE, "xpaaccept %s (%s:%s %s)\n", + amethod, xclass, name, method); + FPRINTF((stderr, "%sXPAProxyAccept: sending command to %d:\n%s", + _sp, ifd, tbuf)); + if( XPAPuts(NULL, ifd, tbuf, XPAShortTimeout()) <= 0 ){ + PERROR(("client xpaaccept write")); + xclose(sock); + goto error; + } + + /* we will iterate on xselect */ + if( XPAShortTimeout() > 0 ) + niter = XPAShortTimeout()*100; + else + niter = XPA_SHORT_TIMEOUT*100; +again: + /* this has to be able to time out */ + tv.tv_sec = 0; + tv.tv_usec = 10000; + tvp = &tv; + /* wait for this socket and XPA sockets */ + FD_ZERO(&readfds); + FD_SET(sock, &readfds); + XPAAddSelect(NULL, &readfds); + /* wait for the connection */ + got = xselect(swidth, &readfds, NULL, NULL, tvp); + /* process results of select */ + if( got > 0 ){ + if( !FD_ISSET(sock, &readfds)){ + XPAProcessSelect(&readfds, 0); + goto again; + } + switch(XPAMethod(method)){ + case XPA_INET: + while( 1 ){ + slen = sizeof(struct sockaddr_in); + if((ofd=xaccept(sock, (struct sockaddr *)&sock_in, &slen)) >= 0){ + break; + } + else{ + if( xerrno == EINTR ) + continue; + else{ + PERROR(("xpaaccept acccept")); + xclose(sock); + goto error; + } + } + } + break; +#if HAVE_SYS_UN_H + case XPA_UNIX: + while( 1 ){ + slen = sizeof(struct sockaddr_un); + if((ofd=xaccept(sock, (struct sockaddr *)&sock_un, &slen)) >= 0){ + break; + } + else{ + if( xerrno == EINTR ) + continue; + else{ + PERROR(("xpaaccept acccept")); + xclose(sock); + goto error; + } + } + } + break; +#endif + default: + xclose(sock); + goto error; + } + } + /* timeout? */ + else if( got == 0 ){ + if( --niter > 0 ){ + goto again; + } + else{ + xclose(sock); + FPRINTF((stderr, "%sXPAProxyAccept: select timed out\n", _sp)); + goto error; + } + } + /* error */ + else{ + if( xerrno == EINTR ){ + PERROR(("xpaaccept select")); + goto again; + } + else{ + xclose(sock); + goto error; + } + } + /* done with listening */ + xclose(sock); + + /* fill in return information */ + if( rip ) *rip = ip; + if( rport ) *rport = port; + if( rname ){ + strncpy(rname, amethod, SZ_LINE-1); + rname[SZ_LINE-1] = '\0'; + } + return(ofd); + +error: + return(-1); +} + +/* + *---------------------------------------------------------------------------- + * + * Routine: XPAClientNewInput + * + * Purpose: allocate a new input struct for reading data from stdin + * + * Return: input struct, or NULL on error + * + *---------------------------------------------------------------------------- + */ +#ifdef ANSI_FUNC +static XPAInput +XPAClientNewInput(XPA xpa) +#else +static XPAInput XPAClientNewInput(xpa) + XPA xpa; +#endif +{ + XPAInput xnew, inp; + + /* allocate a new record */ + if( (xnew=(XPAInput)xcalloc(1, sizeof(XPAInputRec))) == NULL ){ + return(NULL); + } + /* allocate the data buffer */ + xnew->buf = (char *)xmalloc(XPA_BIOSIZE); + /* this buffer starts (and currently ends) at the current byte count */ + xnew->start = xpa->inpbytes; + xnew->end = xpa->inpbytes; + xnew->bytes = 0; + + /* add this input to end of list of input's */ + if( xpa->inphead == NULL ){ + xpa->inphead = xnew; + } + else{ + for(inp=xpa->inphead; inp->next!=NULL; inp=inp->next) + ; + inp->next = xnew; + } + + /* return the record struct */ + return(xnew); +} + +/* + *---------------------------------------------------------------------------- + * + * Routine: XPAClientFreeInput + * + * Purpose: free a input buffer once its been sent to all targets + * + * Return: 0 on success, -1 on failure + * + *---------------------------------------------------------------------------- + */ +#ifdef ANSI_FUNC +static void +XPAClientFreeInput (XPA xpa, XPAInput inp) +#else +static void XPAClientFreeInput(xpa, inp) + XPA xpa; + XPAInput inp; +#endif +{ + XPAInput cur; + + if( !xpa || !inp ) + return; + + if( inp == xpa->inphead ){ + xpa->inphead = inp->next; + } + else{ + for(cur=xpa->inphead; cur!=NULL; cur=cur->next){ + if( cur->next == inp ){ + cur->next = inp->next; + break; + } + } + } + + /* free current record */ + if( inp != NULL ){ + if( inp->buf != NULL ) + xfree(inp->buf ); + xfree(inp); + } +} + +/* + *---------------------------------------------------------------------------- + * + * Routine: XPAClientFreeAllInputs + * + * Purpose: free remaining input buffers + * + * Return: 0 on success, -1 on failure + * + *---------------------------------------------------------------------------- + */ +#ifdef ANSI_FUNC +static void +XPAClientFreeAllInputs (XPA xpa) +#else +static void XPAClientFreeAllInputs(xpa) + XPA xpa; +#endif +{ + XPAInput cur, tmp; + + if( !xpa ) + return; + + for(cur=xpa->inphead; cur!=NULL; ){ + tmp = cur->next; + XPAClientFreeInput(xpa, cur); + cur = tmp; + } + xpa->inpbytes = 0; +} + +/* + *---------------------------------------------------------------------------- + * + * Routine: XPAClientProcessInput + * + * Purpose: read input from stdin and store in an input struct + * + * Return: bytes read + * + *---------------------------------------------------------------------------- + */ +#ifdef ANSI_FUNC +static int +XPAClientProcessInput(XPA xpa) +#else +static int XPAClientProcessInput(xpa) + XPA xpa; +#endif +{ + static XPAInput cur=NULL; + int get, got; + + /* set up next buffer, if necessary */ + for(cur=xpa->inphead; cur!=NULL; cur=cur->next){ + if( cur->bytes < XPA_BIOSIZE ) + break; + } + if( cur == NULL ){ + cur = XPAClientNewInput(xpa); + } + + /* read data from stdin */ + get = MIN(XPA_IOSIZE, XPA_BIOSIZE - cur->bytes); + if( isatty(xpa->ifd) ){ + got = rdl(xpa->ifd, &(cur->buf[cur->bytes]), get); + } + else{ + got = read(xpa->ifd, &(cur->buf[cur->bytes]), get); + } + switch(got){ + case -1: + if( XPAVerbosity() ){ + PERROR(("XPA client read")); + } + return(0); + case 0: + xpa->ifd = -1; + FPRINTF((stderr, "%sXPAClientProcessInput: signalling EOF\n", _sp)); + break; + default: + break; + } + cur->bytes += got; + cur->end += got; + xpa->inpbytes += got; +#ifdef FIXEDBYCYGWIN +#if HAVE_CYGWIN + /* on non-NT Windows machines, Cygwin select() does not work once a pipe + gets EOF. It should show the fd ready for reading (and read 0 bytes), + but does not, so we have to hack a manual check */ + /* GetVersion is a Windows call */ + if( GetVersion() >= 0x80000000L ){ + if( got < get ){ + xpa->ifd = -1; + } + } +#endif +#endif + + /* verify to stdout, if necessary */ + if( xpa->client_mode & XPA_CLIENT_VERIFY ){ + fwrite(&(cur->buf[cur->bytes-got]), sizeof(char), got, stdout); + } + + /* return the number of bytes just read */ + return(got); +} + +/* + *---------------------------------------------------------------------------- + * + * Routine: XPAClientFree + * + * Purpose: free a client record and remove from list + * + * Returns: none + * + *---------------------------------------------------------------------------- + */ +#ifdef ANSI_FUNC +static void +XPAClientFree (XPA xpa, XPAClient client) +#else +static void XPAClientFree(xpa, client) + XPA xpa; + XPAClient client; +#endif +{ + XPAClient cur; + + /* remove from list of xpa's */ + if( xpa->clienthead ){ + if( xpa->clienthead == client ){ + xpa->clienthead = client->next; + } + else{ + for(cur=xpa->clienthead; cur!=NULL; cur=cur->next){ + if( cur->next == client ){ + cur->next = client->next; + break; + } + } + } + } + + if( client->cmdfd >= 0 ){ +#if HAVE_CYGWIN + shutdown(client->cmdfd, SHUT_RDWR); +#endif + xclose(client->cmdfd); + } + if( client->datafd >= 0 ){ +#if HAVE_CYGWIN + shutdown(client->datafd, SHUT_RDWR); +#endif + xclose(client->datafd); + } + if( client->dataname ){ + unlink(client->dataname); + xfree(client->dataname); + } + if( client->method ) + xfree(client->method); + if( client->info ) + xfree(client->info); + if( client->xtemplate ) + xfree(client->xtemplate); + if( client->xclass ) + xfree(client->xclass); + if( client->name ) + xfree(client->name); + if( client->id ) + xfree(client->id); + /* xpaget's fd mode has an alloc'ed bufptr and lenptr */ + if( (client->type == 'g') && (client->mode & XPA_CLIENT_FD) ){ + if( client->bufptr && *(client->bufptr) ) + xfree(*(client->bufptr)); + if( client->bufptr ) + xfree(client->bufptr); + if( client->lenptr ) + xfree(client->lenptr); + } + xfree(client); +} + +/* + *---------------------------------------------------------------------------- + * + * Routine: XPAClientDataSent + * + * Purpose: data is sent, so close data channel and change status to + * signal that we are waiting for the server + * + * Returns: none + * + *---------------------------------------------------------------------------- + */ +#ifdef ANSI_FUNC +static void +XPAClientDataSent (XPA xpa, XPAClient client) +#else +static void XPAClientDataSent(xpa, client) + XPA xpa; + XPAClient client; +#endif +{ + FPRINTF((stderr, "%sXPAClientDataSent: for cmd %d data %d\n", _sp, + client->cmdfd, client->datafd)); + /* close the data channel, which should trigger a result from the server */ + if( client->datafd >= 0 ){ +#if HAVE_CYGWIN + shutdown(client->datafd, SHUT_RDWR); +#endif + xclose(client->datafd); + client->datafd = -1; + } + /* we are now waiting for the server to complete the calllback */ + client->status = XPA_CLIENT_WAITING; +} + +/* + *---------------------------------------------------------------------------- + * + * Routine: XPAClientEnd + * + * Purpose: finish up with this client + * + * Returns: error message or null + * + *---------------------------------------------------------------------------- + */ +#ifdef ANSI_FUNC +static char * +XPAClientEnd (XPA xpa, XPAClient client) +#else +static char *XPAClientEnd(xpa, client) + XPA xpa; + XPAClient client; +#endif +{ + char *error=NULL; + char *eptr; + + FPRINTF((stderr, "%sXPAClientEnd: for cmd %d data %d\n", _sp, + client->cmdfd, client->datafd)); + /* always read the status line -- if we are not ack'ing, we'll get an + OK from the server before the calllback and we can exit quickly */ + /* don't do this if client is xpainfo and we're not ack'ing */ + if( !((client->type == 'i') && !(client->mode & XPA_CLIENT_ACK)) ){ +retry: + if( XPAGets(NULL, client->cmdfd, errbuf, SZ_LINE, XPALongTimeout()) >0 ){ + FPRINTF((stderr, "%sXPAClientEnd: read %s\n", _sp, errbuf)); + eptr = errbuf; + /* this should never happen */ + if( *eptr == '?' ){ + snprintf(errbuf, SZ_LINE, + "XPA$WARNING: protocol mismatch - missing id\n%s", eptr); + error = NULL; + } + else{ + /* make sure we are dealing with a proper message */ + if( strncmp(eptr, client->id, strlen(client->id)) ){ + if( XPAVerbosity() > 1 ){ + fprintf(stderr, + "XPA$WARNING: ignoring out of sync server message:\n"); + fprintf(stderr, "%s", errbuf); + } + goto retry; + } + /* go past id */ + eptr += strlen(client->id); + while( isspace((int)*eptr) ) eptr++; + if( !strncmp(eptr, "XPA$OK", 6) ){ + error = NULL; + } + else{ + error = eptr; + } + } + } + else{ + if( XPAVerbosity() > 1 ){ + fprintf(stderr, + "XPA$WARNING: no reply from server callback (assuming OK)\n"); + } + error = NULL; + } + } + else + error = NULL; + + /* store the error return */ + if( client->errptr ) + *(client->errptr) = xstrdup(error); + + /* remove this client if we are not meant to persist */ + if( !xpa->persist ){ + XPAClientFree(xpa, client); + } + /* otherwise mark as inactive */ + else{ + client->status = XPA_CLIENT_IDLE; + client->bytes = 0; + } + + /* return error status */ + return(error); +} + +/* + *---------------------------------------------------------------------------- + * + * Routine: XPAClientNew + * + * Purpose: allocate a new xpa client + * + * Returns: xpa client struct + * + *---------------------------------------------------------------------------- + */ +#ifdef ANSI_FUNC +static XPAClient +XPAClientNew (XPA xpa, char *mode, char *xtemplate, int type, + char *xclass, char *name, char *method, char *info) +#else +static XPAClient XPAClientNew(xpa, mode, xtemplate, type, + xclass, name, method, info) + XPA xpa; + char *mode; + char *xtemplate; + int type; + char *xclass; + char *name; + char *method; + char *info; +#endif +{ + XPAClient xnew, client; + struct sockaddr_in sock_in; +#if HAVE_SYS_UN_H + struct sockaddr_un sock_un; +#endif + char xmode[SZ_LINE]; + char tbuf[SZ_LINE]; + char amethod[SZ_LINE]; + char *s=NULL; + unsigned short port; + unsigned int ip=0; + int fd; + int pfd; + int tries=0; + int nsproxy=0; + int keep_alive=1; + + FPRINTF((stderr, "%sXPAClientNew: entering with %s %s %s %s\n", _sp, + xclass, name, method, info)); + + /* no errors as yet */ + *errbuf = '\0'; + + /* look for reuse of xpans fd (used in conjunction with the xpans proxy) */ + *xmode = '\0'; + if( mode ){ + strncpy(xmode, mode, SZ_LINE-1); + xmode[SZ_LINE-1] = '\0'; + } + if( keyword(xmode, "nsproxy", tbuf, SZ_LINE) ){ + nsproxy = 1; + pfd = strtol(tbuf, &s, 0); + fd = XPAProxyAccept(xpa, XPANSMethod(NULL,2), + xclass, name, pfd, &ip, &port, amethod); + /* make sure we got a valid int fd */ + if( fd < 0 ){ + snprintf(errbuf, SZ_LINE, + "XPA$ERROR: no response from server on proxyaccept (%s:%s%s)\n", + xclass, name, XPATimestamp()); + FPRINTF((stderr, "%sXPAClientNew: %s", _sp, errbuf)); + PERROR(("XPAClientNew")); + return(NULL); + } + } + /* normal usage: connect to server */ + else{ + switch(XPAMethod(method)){ + case XPA_INET: +again1: + if( !XPAParseIpPort(method, &ip, &port) ) + return(NULL); + /* use $localhost over $host (we do not trust host to be correct) */ + if( (ip == gethostip("$host")) && (tries == 0) ) + ip = gethostip("$localhost"); + /* connect to the server before we go further */ + if( (fd = xsocket(AF_INET, SOCK_STREAM, 0)) < 0 ){ + return(NULL); + } + setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, + (char *)&keep_alive, sizeof(keep_alive)); + memset((char *)&sock_in, 0, sizeof(sock_in)); + sock_in.sin_family = AF_INET; + sock_in.sin_addr.s_addr = htonl(ip); + sock_in.sin_port = htons(port); + /* make the connection with the server */ + if( connect(fd, (struct sockaddr *)&sock_in, sizeof(sock_in)) <0 ){ + xclose(fd); + /* if localhost doesn't work, make one try with the host ip */ + /* we also try again just in case there was an odd error such + as "permission denied", which we have seen once or twice */ + if( tries < 2 ){ + tries++; + goto again1; + } + /* give up */ + else{ + snprintf(errbuf, SZ_LINE, + "XPA$ERROR: no response from server on connect (%s:%s%s)\n", + xclass, name, XPATimestamp()); + PERROR(("XPAClientNew")); + return(NULL); + } + } + /* make sure we close on exec */ + xfcntl(fd, F_SETFD, FD_CLOEXEC); + FPRINTF((stderr, "%sXPAClientNew: inet connect returns fd %d\n", + _sp, fd)); + break; +#if HAVE_SYS_UN_H + case XPA_UNIX: +again2: + /* open a socket and fill in socket information */ + if( (fd = xsocket(AF_UNIX, SOCK_STREAM, 0)) < 0 ){ + return(NULL); + } + setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, + (char *)&keep_alive, sizeof(keep_alive)); + memset((char *)&sock_un, 0, sizeof(sock_un)); + sock_un.sun_family = AF_UNIX; + strcpy(sock_un.sun_path, method); + /* make the connection with the server */ + if( connect(fd, (struct sockaddr *)&sock_un, sizeof(sock_un)) <0 ){ + xclose(fd); + /* Unix sockets get ECONNREFUSED when the listen queue is full, + so we try a few times to give the server a chance to recover */ + if( (xerrno == ECONNREFUSED) && (tries < XPA_RETRIES) ){ + tries++; + XPASleep(10); + goto again2; + } + /* give up */ + else{ + snprintf(errbuf, SZ_LINE, + "XPA$ERROR: no response from server on connect (%s:%s%s)\n", + xclass, name, XPATimestamp()); + PERROR(("XPAClientNew")); + return(NULL); + } + } + /* make sure we close on exec */ + xfcntl(fd, F_SETFD, FD_CLOEXEC); + FPRINTF((stderr, "%sXPAClientNew: unix connect returns fd %d\n", + _sp, fd)); + break; +#endif + default: + return(NULL); + } + strncpy(amethod, method, SZ_LINE-1); + amethod[SZ_LINE-1] = '\0'; + } + + /* allocate new send record */ + if( (xnew=(XPAClient)xcalloc(1, sizeof(XPAClientRec))) == NULL ){ + xclose(fd); + return(NULL); + } + + /* fill in the blanks */ + xnew->xtemplate = xstrdup(xtemplate); + xnew->type = type; + xnew->cmdfd = fd; + xnew->datafd = -1; + xnew->xclass = xstrdup(xclass); + xnew->name = xstrdup(name); + xnew->method = xstrdup(amethod); + xnew->info = xstrdup(info); + xnew->ip = ip; + xnew->nsproxy = nsproxy; + xnew->status = XPA_CLIENT_ACTIVE; + + /* now that we have a valid client, add to list */ + if( xpa->clienthead == NULL ){ + xpa->clienthead = xnew; + } + else{ + for(client=xpa->clienthead; client->next!=NULL; client=client->next) + ; + client->next = xnew; + } + FPRINTF((stderr, "%sXPAClientNew: new fd %d\n", _sp, xnew->cmdfd)); + /* return the good news */ + return(xnew); +} + +/* + *---------------------------------------------------------------------------- + * + * Routine: XPAClientAddSelect + * + * Purpose: add one or more xpa client sockets to the select flags + * + * Return: number of clients that were added to the select flags + * + *---------------------------------------------------------------------------- + */ +#ifdef ANSI_FUNC +int +XPAClientAddSelect (XPA xpa, fd_set *readfdsptr, fd_set *writefdsptr) +#else +int XPAClientAddSelect(xpa, readfdsptr, writefdsptr) + XPA xpa; + fd_set *readfdsptr; + fd_set *writefdsptr; +#endif +{ + XPAClient client; + int got=0; + int loop=0; + + /* better have some place to set the flags */ + if( readfdsptr == NULL ) + return(0); + + /* if no xpa is specified, do them all */ + if( xpa == NULL ){ + if( xpaclienthead == NULL ) return(0); + xpa = xpaclienthead; + loop = 1; + } + +loop: + /* set select flags for all clients */ + for(client=xpa->clienthead; client!=NULL; client=client->next){ + /* if this client is processing */ + if( (client->status == XPA_CLIENT_PROCESSING) && (client->datafd >= 0) ){ + if( client->type == 'g' ){ + FPRINTF((stderr, "%sXPAClientAddSelect(get): adding fd %d\n", _sp, + client->datafd)); + FD_SET(client->datafd, readfdsptr); + got++; + } + else if( client->type == 's' ){ + FPRINTF((stderr, "%sXPAClientAddSelect(set): adding fd %d\n", _sp, + client->datafd)); + FD_SET(client->datafd, writefdsptr); + got++; + } + } + /* if this client is waiting */ + else if( (client->status == XPA_CLIENT_WAITING) && (client->cmdfd >= 0) ){ + FPRINTF((stderr, "%sXPAClientAddSelect(waiting): adding fd %d\n", _sp, + client->cmdfd)); + FD_SET(client->cmdfd, readfdsptr); + got++; + } + } + /* loop if necessary */ + if( loop && (xpa=xpa->next) ) goto loop; + /* return the news */ + return(got); +} + +/* + *---------------------------------------------------------------------------- + * + * Routine: XPAClientGet + * + * Purpose: process an xpaget request for a given client + * + * Return: 0 on success, -1 on failure + * + *---------------------------------------------------------------------------- + */ +#ifdef ANSI_FUNC +static int +XPAClientGet (XPA xpa, XPAClient client) +#else +static int XPAClientGet(xpa, client) + XPA xpa; + XPAClient client; +#endif +{ + int status; + char tbuf[SZ_LINE]; + + /* allocate the first buffer, if necessary */ + if( *(client->bufptr) == NULL ){ + client->bufsize = XPA_IOSIZE; + *(client->bufptr) = (char *)xmalloc(client->bufsize); + *(client->lenptr) = 0; + } + if( (*(client->lenptr) + XPA_IOSIZE) > client->bufsize ){ + client->bufsize += (XPA_IOSIZE*10); + *(client->bufptr) = (char *)xrealloc(*(client->bufptr), client->bufsize); + } + + /* now retrieve the data from the server */ + status = recv(client->datafd, *(client->bufptr) + *(client->lenptr), + XPA_IOSIZE, 0); + /* status < 0 means error */ + switch(status){ + /* error */ + case -1: + /* socket would block */ + if((xerrno == EINPROGRESS) || (xerrno == EWOULDBLOCK)){ + return(0); + } + /* clean up after error */ + if( *(client->bufptr) ){ + xfree(*(client->bufptr)); + *(client->bufptr) = NULL; + client->bufsize = 0; + } + *(client->lenptr) = 0; + XPAClientDataSent(xpa, client); +#ifdef OLD + (void)XPAClientEnd(xpa, client); + /* we need to flag some sort of error, if nothing came across */ + if( *(client->errptr) == NULL ){ + *(client->errptr) = xstrdup( + "XPA$ERROR: incomplete transmission from server\n"); + } +#endif + break; + /* eof */ + case 0: + /* if we have multiple clients, we now need to write this one */ + if( client->mode & XPA_CLIENT_FD ){ + if( xpa->nclient > 1 ){ + snprintf(tbuf, SZ_LINE, "XPA$BEGIN %s:%s %s\n", + client->xclass, client->name, client->method); + write(client->fd, tbuf, strlen(tbuf)); + } + write(client->fd, *(client->bufptr), *(client->lenptr)); + if( xpa->nclient > 1 ){ + snprintf(tbuf, SZ_LINE, "XPA$END %s:%s %s\n", + client->xclass, client->name, client->method); + write(client->fd, tbuf, strlen(tbuf)); + } + /* we can free buf, since its not being passed back */ + if( *(client->bufptr) ){ + xfree(*(client->bufptr)); + *(client->bufptr) = NULL; + client->bufsize = 0; + } + } + else{ + /* set final buffer size and put a convenience null at the end */ + if( *(client->bufptr) ){ + client->bufsize = *(client->lenptr)+1; + *(client->bufptr) = (char *)xrealloc(*(client->bufptr),client->bufsize); + *(*(client->bufptr)+*(client->lenptr)) = '\0'; + } + } + /* for all clients, we need to clean up */ + XPAClientDataSent(xpa, client); +#ifdef OLD + (void)XPAClientEnd(xpa, client); +#endif + break; + /* status > 0: bytes read */ + default: + *(client->lenptr) += status; + /* for single client fd mode, we write immediately -- this deals with + the important case of one client with a large amount of data */ + if( (client->mode & XPA_CLIENT_FD) && (xpa->nclient == 1) ){ + write(client->fd, *(client->bufptr), *(client->lenptr)); + /* reset buf for next read */ + if( *(client->bufptr) ) xfree(*(client->bufptr)); + *(client->bufptr) = NULL; + *(client->lenptr) = 0; + } + break; + } + return(status); +} + +/* + *---------------------------------------------------------------------------- + * + * Routine: XPAClientSet + * + * Purpose: process an xpaset request for a given client + * + * Return: 0 on success, -1 on failure + * + *---------------------------------------------------------------------------- + */ +#ifdef ANSI_FUNC +static int +XPAClientSet (XPA xpa, XPAClient client) +#else +static int XPAClientSet(xpa, client) + XPA xpa; + XPAClient client; +#endif +{ + int status; + int left; + int got; + int len; + XPAInput inp; + + if( client->mode & XPA_CLIENT_BUF ){ + while( 1 ){ + len = MIN(XPA_IOSIZE, client->len - client->bytes); + /* see if we have written it all */ + if( len == 0 ){ + status = 1; + goto done; + } + /* write the next chunk */ + FPRINTF((stderr, + "%sXPAClientSet: fd %d sending %lu bytes (%lu - %lu)\n", _sp, + client->datafd, (unsigned long)len, + (unsigned long)client->len, (unsigned long)client->bytes)); + got=send(client->datafd, &(client->buf[client->bytes]), len, 0); + if( got >= 0 ){ + client->bytes += got; + if( XPALevelGet() >0 ) + return(got); + } + else{ + PERROR(("XPAClientSet")); + /* check for error */ + if( (xerrno != EWOULDBLOCK) && (xerrno != EAGAIN) ){ + status = -1; + goto done; + } + /* write would block, so we return and wait the server */ + else{ + return(0); + } + } + } + } + /* reading from stdin and writing to servers */ + else{ + /* find the input buf that contains the data we need */ + for(inp=xpa->inphead; inp!=NULL; inp=inp->next){ + if( (client->bytes >= inp->start) && (client->bytes < inp->end) ){ + break; + } + } + /* if we can't find a buffer ... */ + if( !inp ){ + /* ... and we have all the input, we are done */ + if( xpa->ifd < 0 ){ + FPRINTF((stderr, "%sXPAClientSet: all data read\n", _sp)); + status = 1; + goto done; + } + /* ... but there is more input to come, return */ + else{ + return(0); + } + } + /* optimization: don't write a buffer until its full (or until eof) */ + if( (xpa->ifd >=0) && (inp->bytes < XPA_BIOSIZE) ){ + return(0); + } + + /* write bytes until we would block or until end of this buffer, etc */ + while( 1 ){ + len = MIN(XPA_IOSIZE, inp->end - client->bytes); + FPRINTF((stderr, "%sXPAClientSet: has %lu=min(%d,(%lu-%lu)) [%d]\n", + _sp, (unsigned long)len, XPA_IOSIZE, + (unsigned long)inp->end, (unsigned long)client->bytes, + client->status)); + /* if we are done with this buffer, just return */ + if( (client->status == XPA_CLIENT_PROCESSING) && (len <=0) ){ + /* see if everyone else is done with this buffer as well, + in which case we can free it */ + left = 0; + for(client=xpa->clienthead; client!=NULL; client=client->next){ + if( (client->type != 's') || !(client->mode & XPA_CLIENT_FD) ) + continue; + /* in order to be totally written out, the following must be true: + * 1. send->bytes must be past the end of this buffer + * and + * 2. this buffer must be filled or else we hit eof + */ + FPRINTF((stderr, + "%sXPAClientSet: %lu>=%lu && ((%lu>=%d) or %d<0)) .. ", + _sp, client->bytes, (unsigned long)inp->end, + (unsigned long)inp->bytes, XPA_BIOSIZE, + xpa->ifd)); + if( (client->bytes >= inp->end) && + ((inp->bytes >= XPA_BIOSIZE) || (xpa->ifd < 0)) ){ + /* buffer complete written */ + FPRINTF((stderr, "%sEOF (%lu)\n", + _sp, (unsigned long)xpa->inpbytes)); + ; + } + else{ + FPRINTF((stderr, "%s\n", _sp)); + /* buffer not complete written */ + left++; + break; + } + } + /* if nothing is left, we can free this input struct */ + if( !left ){ + XPAClientFreeInput(xpa, inp); + } + return(0); + } + /* write to the server */ + FPRINTF((stderr, + "%sXPAClientSet: fd %d sending %lu bytes (%lu):\n", _sp, + client->datafd, + (unsigned long)len, (unsigned long)client->bytes)); + got = send(client->datafd, &(inp->buf[client->bytes-inp->start]),len,0); + /* check for success */ + if( got >= 0 ){ + /* update the number of bytes we wrote */ + client->bytes += got; + FPRINTF((stderr, "%sXPAClientSet: sent %lu bytes (total is %lu)\n", + _sp, (unsigned long)got, (unsigned long)client->bytes)); + /* go back for more */ + if( XPALevelGet() >0 ) + return(got); + else + continue; + } + /* check for error */ + else{ + PERROR(("XPAClientSet")); + /* anything but a "would block" error is bad */ + if( (xerrno != EWOULDBLOCK) && (xerrno != EAGAIN) ){ + status = -1; + goto done; + } + /* write would block, so we return and wait the server */ + else{ + FPRINTF((stderr, "%sXPAClientSet: waiting for more data\n", _sp)); + return(0); + } + } + } + } + +done: + XPAClientDataSent(xpa, client); +#ifdef OLD + (void)XPAClientEnd(xpa, client); +#endif + return(status); +} + +/* + *---------------------------------------------------------------------------- + * + * Routine: XPAClientProcessSelect + * + * Purpose: process xpas that have pending reads or writes + * + * Return: number of xpas processed + * + *---------------------------------------------------------------------------- + */ +#ifdef ANSI_FUNC +int +XPAClientProcessSelect (XPA xpa, + fd_set *readfdsptr, fd_set *writefdsptr, int maxreq) +#else +int XPAClientProcessSelect(xpa, readfdsptr, writefdsptr, maxreq) + XPA xpa; + fd_set *readfdsptr; + fd_set *writefdsptr; + int maxreq; +#endif +{ + int got=0; + int loop=0; + XPAClient client; + + /* <= 0 means do all of them */ + if( maxreq < 0 ){ + maxreq = 0; + } + + /* if no xpa is specified, do them all */ + if( xpa == NULL ){ + if( xpaclienthead == NULL ) return(0); + xpa = xpaclienthead; + loop = 1; + } + +loop: + /* first process any new input before we write output */ + if( xfd_isset_stdin(xpa->ifd, readfdsptr) ){ + xfd_clr_stdin(xpa->ifd, readfdsptr); + XPAClientProcessInput(xpa); + } + /* look at all clients */ +again: + for(client=xpa->clienthead; client!=NULL; client=client->next){ + /* if we are processing */ + if( (client->status == XPA_CLIENT_PROCESSING) && (client->datafd>=0) ){ + /* then handle new requests */ + if((client->type == 'g') && FD_ISSET(client->datafd, readfdsptr)){ + FD_CLR(client->datafd, readfdsptr); + XPAClientGet(xpa, client); + got++; + if( maxreq && (got >= maxreq) ) return(got); + goto again; + } + else if((client->type == 's') && FD_ISSET(client->datafd, writefdsptr)){ + FD_CLR(client->datafd, writefdsptr); + /* if the return is > 0, we completed the send */ + if( XPAClientSet(xpa, client) > 0 ) + got++; + if( maxreq && (got >= maxreq) ) return(got); + goto again; + } + } + /* if this client is waiting */ + else if( (client->status == XPA_CLIENT_WAITING) && (client->cmdfd >= 0) ){ + if( FD_ISSET(client->cmdfd, readfdsptr)){ + FD_CLR(client->cmdfd, readfdsptr); + XPAClientEnd(xpa, client); + got++; + if( maxreq && (got >= maxreq) ) return(got); + goto again; + } + } + } + /* loop if necessary */ + if( loop && (xpa=xpa->next) ) goto loop; + /* return the news */ + return(got); +} + +/* + *---------------------------------------------------------------------------- + * + * Routine: XPAClientLoop + * + * Purpose: non-X programs event loop for handling XPA client events + * + * Returns: none + * + *---------------------------------------------------------------------------- + */ +#ifdef ANSI_FUNC +static int +XPAClientLoop (XPA xpa, int mode) +#else +static int XPAClientLoop(xpa, mode) + XPA xpa; + int mode; +#endif +{ + int got=0; + int sgot; + int doxpa=1; + int ltimeout; + char *s=NULL; + fd_set readfds; + fd_set writefds; + static int width=0; + struct timeval tv; + struct timeval *tvp; + + /* set width once */ + if( width == 0 ){ + width = FD_SETSIZE; + } + /* allow environment to turn off xpa server processing in client loop */ + if( (s=getenv("XPA_CLIENT_DOXPA")) && isfalse(s) ){ + doxpa = 0; + } + ltimeout = XPALongTimeout(); + FD_ZERO(&readfds); + FD_ZERO(&writefds); + while( XPAClientAddSelect(xpa, &readfds, &writefds) ){ + /* add other XPA's and process them as we process the client */ + if( (mode & XPA_CLIENT_SEL_XPA) && doxpa ){ + FPRINTF((stderr, "%sXPAClientLoop: will handle server reqs ...\n", _sp)); + XPAAddSelect(NULL, &readfds); + } + /* hopefully, a server will respond in a finite amount of time */ + if( ltimeout > 0 ){ + tv.tv_sec = ltimeout; + tv.tv_usec = 0; + tvp = &tv; + } + /* wait forever, if necessary */ + else{ + tvp = NULL; + } + /* add stdin to select, if there is one */ + if( xpa->ifd >= 0 ){ + xfd_set_stdin(xpa->ifd, &readfds); +#if HAVE_MINGW32 + /* BUT: for windows, we can't add stdin to select and therefore we + must set a short timeout and look manually */ + tv.tv_sec = 0; + tv.tv_usec = 10000; + /* this is the number of window iterations we will perform */ + if( ltimeout > 0 ) + ltimeout *= 100; + tvp = &tv; +#endif + } + /* wait for a server to respond */ + FPRINTF((stderr, "%sXPAClientLoop: waiting on select() ...\n", _sp)); + sgot = xselect(width, &readfds, &writefds, NULL, tvp); + FPRINTF((stderr, "%sXPAClientLoop: select returns: %d\n", _sp, sgot)); + /* error -- what should we do? */ + if( sgot < 0 ){ + if( xerrno == EINTR ){ + FD_ZERO(&readfds); + FD_ZERO(&writefds); + continue; + } + if( XPAVerbosity() ){ + perror("XPAClientLoop() select"); + } + exit(1); + } + /* timed out -- no one responded */ + else if( sgot == 0 ){ +#if HAVE_MINGW32 + if( xpa->ifd >= 0 ){ + if( ltimeout > 0 ){ + if( --ltimeout <= 0 ) + break; + } + } + else{ + break; + } +#else + break; +#endif + } + else{ + got += XPAClientProcessSelect(xpa, &readfds, &writefds, 0); + if( (mode & XPA_CLIENT_SEL_XPA) && doxpa ){ + got += XPAProcessSelect(&readfds, 0); + } + } + FD_ZERO(&readfds); + FD_ZERO(&writefds); + } + return(got); +} + +#if HAVE_MINGW32==0 +/* + *---------------------------------------------------------------------------- + * + * Routine: XPAClientLoopFork + * + * Purpose: non-X programs forked event loop for handling XPA client events + * + * Returns: number of clients "processed" + * + *---------------------------------------------------------------------------- + */ +#ifdef ANSI_FUNC +static int +XPAClientLoopFork (XPA xpa, int mode) +#else +static int XPAClientLoopFork(xpa, mode) + XPA xpa; + int mode; +#endif +{ + XPAClient client, tclient; + pid_t pid; + int got; + int fd[2]; + char active=1; +#ifndef USE_DOUBLE_FORK + struct sigaction act; + /* set up the signal handler to reap children (to avoid zombies) */ + act.sa_handler = sig_chld; + sigemptyset(&act.sa_mask); + act.sa_flags = 0; +#ifdef SA_RESTART + act.sa_flags |= SA_RESTART; +#endif +#ifdef SA_NOCLDWAIT + act.sa_flags |= SA_NOCLDWAIT; +#endif + sigaction(SIGCHLD, &act, NULL); +#endif + + if( pipe(fd) < 0 ){ + got = 0; + } + else if( (pid = fork()) < 0 ){ + close(fd[0]); + close(fd[1]); + got=0; + } + else if( pid == 0 ){ /* child */ + /* child write to parent that he is active */ + close(fd[0]); + write(fd[1], &active, 1); + close(fd[1]); +#ifdef USE_DOUBLE_FORK + /* second fork prevents zombies: + when child/parent exits, second child is inherited + by init and thus is not a child of original parent */ + if( (pid = fork()) >= 0 ){ + /* child/parent exits */ + if( pid > 0 ) + exit(0); + /* new child goes on under init ... */ + } +#endif + /* enter the main loop and process */ + XPAIOCallsXPA(0); + XPAClientLoop(xpa, mode); + exit(0); + } else { /* parent */ + /* parent waits for child to wake up */ + close(fd[1]); + read(fd[0], &active, 1); + close(fd[0]); +#ifdef USE_DOUBLE_FORK + /* for double fork, also wait for intermediate process to exit */ + waitpid(pid, NULL, 0); +#endif + /* fake end of clients */ + for(got=0, client=xpa->clienthead; client!=NULL; ){ + got++; + tclient = client->next; + if( (client->status == XPA_CLIENT_PROCESSING) && (client->datafd >=0) ){ +#if HAVE_CYGWIN + /* In Cygwin, we call shutdown (as well as close) to avoid Windows + problems. The parent can't do this since the child is using the + sockets, so we just close the sockets explicitly here */ + xclose(client->datafd); + client->datafd = -1; + if( !xpa->persist ){ + xclose(client->cmdfd); + client->cmdfd = -1; + } +#endif + client->errptr = NULL; + /* remove this client if we are not meant to persist */ + if( !xpa->persist ){ + XPAClientFree(xpa, client); + } + /* otherwise mark as inactive */ + else{ + client->status = XPA_CLIENT_IDLE; + client->bytes = 0; + } + } + client = tclient; + } + } + return(got); +} +#endif + +/* + *---------------------------------------------------------------------------- + * + * Routine: XPAClientConnect + * + * Purpose: go to name service and get new names, merge with old, + * and connect to servers + * + * Returns: number of connections + * + *---------------------------------------------------------------------------- + */ +#ifdef ANSI_FUNC +static int +XPAClientConnect (XPA xpa, char *mode, char *xtemplate, int type) +#else +static int XPAClientConnect(xpa, mode, xtemplate, type) + XPA xpa; + char *mode; + char *xtemplate; + int type; +#endif +{ + int i; + int n; + int got; + int lp=0; + int total=0; + char **xclasses; + char **names; + char **methods; + char **infos; + char xtype[2]; + char xmode[SZ_LINE]; + char tbuf[SZ_LINE]; + char lbuf[SZ_LINE]; + XPAClient client; + + /* do some initialization */ + XPAInitEnv(); + + /* make sure we have a target */ + if( !xtemplate || !*xtemplate ) + return(0); + + /* make a string out of the type for the lookup */ + xtype[0] = type; + xtype[1] = '\0'; + + /* reset the number of clients we are processing */ + xpa->nclient = 0; + + /* look for specific proxy info */ + *xmode = '\0'; + if( mode ){ + strncpy(xmode, mode, SZ_LINE-1); + xmode[SZ_LINE-1] = '\0'; + } + if( keyword(xmode, "ns", lbuf, SZ_LINE) ){ + FPRINTF((stderr, "%sXPAClientConnect: using ns info: %s\n", _sp, lbuf)); + newdtable("(),"); + xclasses = (char **)xmalloc(sizeof(char *)); + names = (char **)xmalloc(sizeof(char *)); + methods = (char **)xmalloc(sizeof(char *)); + infos = (char **)xmalloc(sizeof(char *)); + if( word(lbuf, tbuf, &lp) ) + xclasses[0] = xstrdup(tbuf); + if( word(lbuf, tbuf, &lp) ) + names[0] = xstrdup(tbuf); + if( word(lbuf, tbuf, &lp) ) + methods[0] = xstrdup(tbuf); + infos[0] = xstrdup(XPA_DEF_CLIENT_INFO); + n = 1; + freedtable(); + } + /* else ask xpans for access points matching the template */ + else{ + n = XPANSLookup(xpa, + xtemplate, xtype, &xclasses, &names, &methods, &infos); + } + /* mark existing clients who do not match this template */ + for(got=0, client=xpa->clienthead; client !=NULL; client=client->next){ + for(i=0; i<n; i++){ + if( (client->type == type) && + (!strcmp(client->xclass, xclasses[i])) && + (!strcmp(client->name, names[i])) && + (!strcmp(client->method, methods[i])) && + (!strcmp(client->info, infos[i])) ){ + got++; + } + } + /* don't unmark if its a different type -- someone else might be active */ + if( !got && (client->type == type) ){ + client->status = XPA_CLIENT_IDLE; + } + } + /* add new clients for this type */ + for(i=0; i<n; i++){ + for(got=0, client=xpa->clienthead; client !=NULL; client=client->next){ + if( (client->type == type) && + (!strcmp(client->xclass, xclasses[i])) && + (!strcmp(client->name, names[i])) && + (!strcmp(client->method, methods[i])) && + (!strcmp(client->info, infos[i])) ){ + /* might have to change the template */ + if( strcmp(client->xtemplate, xtemplate) ){ + xfree(client->xtemplate); + client->xtemplate = xstrdup(xtemplate); + } + client->status = XPA_CLIENT_ACTIVE; + got++; + total++; + FPRINTF((stderr, "%sXPAClientConnect: existing match: %s %s %s\n", + _sp, xclasses[i], names[i], methods[i])); + break; + } + } + if( !got ){ + FPRINTF((stderr, "%sXPAClientConnect: calls XPAClientNew for %s:%s %s\n", + _sp, xclasses[i], names[i], methods[i])); + if( XPAClientNew(xpa, mode, xtemplate, type, + xclasses[i], names[i], methods[i], infos[i]) ) + total++; + } + /* done with these strings */ + xfree(xclasses[i]); + xfree(names[i]); + xfree(methods[i]); + xfree(infos[i]); + } + /* free up arrays alloc'ed by names server */ + if( n > 0 ){ + xfree(xclasses); + xfree(names); + xfree(methods); + xfree(infos); + } + return(total); +} + +/* + *---------------------------------------------------------------------------- + * + * Routine: XPAClientStart + * + * Purpose: send init string to server and perform other authentication + * tasks + * + * Returns: 0 if success, -1 otherwise + * + *---------------------------------------------------------------------------- + */ +#ifdef ANSI_FUNC +static int +XPAClientStart (XPA xpa, XPAClient client, char *paramlist, char *mode) +#else +static int XPAClientStart(xpa, client, paramlist, mode) + XPA xpa; + XPAClient client; + char *paramlist; + char *mode; +#endif +{ + int fd=0; + int lp=0; + int flags; + int tries=0; + int dmode=0; + int keep_alive=1; + unsigned int ip=0; + unsigned short port; + char tbuf[SZ_LINE]; + char tbuf2[SZ_LINE]; + char lbuf[SZ_LINE]; + char *cmd=NULL; + char *method=NULL; + struct sockaddr_in sock_in; +#if HAVE_SYS_UN_H + struct sockaddr_un sock_un; +#endif + + switch(client->type){ + case 'a': + cmd = "xpaaccess"; + break; + case 'g': + cmd = "xpaget"; + break; + case 'i': + cmd = "xpainfo"; + break; + case 's': + cmd = "xpaset"; + break; + } + + /* get mode flags */ + XPAMode(mode, &(client->mode), "ack", XPA_CLIENT_ACK, 1); + if( client->type == 's' ) + XPAMode(mode, &(xpa->client_mode), "verify", XPA_CLIENT_VERIFY, 0); + /* package up and send the initialization message */ + strcpy(lbuf, cmd); + /* set and save the id value */ + snprintf(tbuf, SZ_LINE, "%c%d", client->type, id++); + if( client->id ) xfree(client->id); + client->id = xstrdup(tbuf); + /* if we are using the xpans proxy, we will want to call + accept() (server calls connect()) for the data channel */ + if( client->nsproxy ) + strcat(lbuf, " -a"); + /* set the value of the client big-endian-ness */ + snprintf(tbuf, SZ_LINE, " -e %s", XPAEndian() ? "big" : "little"); + strcat(lbuf, tbuf); + snprintf(tbuf, SZ_LINE, " -i %s", client->id); + strcat(lbuf, tbuf); + if( !(client->mode & XPA_CLIENT_ACK) ) + strcat(lbuf, " -n"); + if( strcmp(client->info, XPA_DEF_CLIENT_INFO) ){ + snprintf(tbuf, SZ_LINE, " -p %s", client->info); + strcat(lbuf, tbuf); + } + snprintf(tbuf, SZ_LINE, " %s:%s", client->xclass, client->name); + strcat(lbuf, tbuf); + if( paramlist && *paramlist ){ + strcat(lbuf, " "); + strncat(lbuf, paramlist, MAX(0,(int)(SZ_LINE-(int)strlen(lbuf)-2))); + } + strcat(lbuf, "\n"); + FPRINTF((stderr, "%sXPAClientStart: fd %d sends:\n%s", + _sp, client->cmdfd, lbuf)); + if( XPAPuts(NULL, client->cmdfd, lbuf, XPAShortTimeout()) <= 0 ){ + goto error; + } + + /* if xpainfo and no ack'ing, we are basically done */ + if( (client->type == 'i') && !(client->mode & XPA_CLIENT_ACK) ){ + goto done; + } + + /* authentication */ +retry: + lp = 0; + if( XPAGets(NULL, client->cmdfd, lbuf, SZ_LINE, XPAShortTimeout()) >0 ){ + FPRINTF((stderr, "%sXPAClientStart: fd %d received cmd:\n%s", _sp, + client->cmdfd, lbuf)); + /* this should never happen */ + if( !word(lbuf, tbuf, &lp) || (*tbuf == '?') ){ + snprintf(errbuf, SZ_LINE, + "XPA$WARNING: Protocol mismatch: id\n%s", lbuf); + goto error; + } + /* make sure we are dealing with a proper message */ + if( strcmp(tbuf, client->id) ){ + FPRINTF((stderr, "%sXPA$WARNING: ignoring out of sync message:\n", _sp)); + FPRINTF((stderr, "%s", lbuf)); + if( XPAVerbosity() > 1 ){ + fprintf(stderr, "XPA$WARNING: ignoring out of sync server message:\n"); + fprintf(stderr, "%s", lbuf); + } + goto retry; + } + + /* this should never happen */ + if( !word(lbuf, tbuf, &lp) ){ + snprintf(errbuf, SZ_LINE, "XPA$WARNING: missing BUF request\n%s", lbuf); + goto error; + } + if( !strcmp(tbuf, "XPA$NODATA") || !strcmp(tbuf, "XPA$NOBUF") ){ + xpa->nclient += 1; + goto started; + } + /* support 2.2 (DATA) and 2.0,2.1 (BUF) */ + else if( !strcmp(tbuf, "XPA$DATA") || !strcmp(tbuf, "XPA$BUF") ){ + if( !strcmp(tbuf, "XPA$DATA") ){ + dmode |= DATA_DATA; + if( !word(lbuf, tbuf, &lp) ){ + snprintf(errbuf, SZ_LINE, + "XPA$WARNING: missing DATA request type\n%s", lbuf); + goto error; + } + if( !strcmp(tbuf, "connect") ){ + method = client->method; + dmode |= DATA_CONNECT; + } + else if( !strcmp(tbuf, "accept") ){ + method = client->method; + dmode |= DATA_ACCEPT; + } + else{ + snprintf(errbuf, SZ_LINE, + "XPA$WARNING: invalid data connection request: %s (%s:%s)\n", + tbuf, client->xclass, client->name); + goto error; + } + } + else if( !strcmp(tbuf, "XPA$BUF") ){ + if( !word(lbuf, tbuf, &lp) ){ + snprintf(errbuf, SZ_LINE, + "XPA$ERROR: missing data buffer method (%s:%s%s)\n", + client->xclass, client->name, XPATimestamp()); + goto error; + } + method = tbuf; + dmode |= DATA_CONNECT; + } + /* handle connect-type requests */ + if( dmode & DATA_CONNECT ){ + switch(XPAMethod(method)){ + case XPA_INET: + XPAParseIpPort(method, &ip, &port); + /* connect to the server before we go further */ + if( (fd = xsocket(AF_INET, SOCK_STREAM, 0)) < 0 ){ + snprintf(errbuf, SZ_LINE, + "XPA$ERROR: bad socket for data chan (%s:%s%s)\n", + client->xclass, client->name, XPATimestamp()); + if( XPAVerbosity() ){ + perror("XPA client socket"); + } + goto error; + } + setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, + (char *)&keep_alive, sizeof(keep_alive)); + memset((char *)&sock_in, 0, sizeof(sock_in)); + sock_in.sin_family = AF_INET; + /* connect using the same ip we used for the command channel + (i.e., could be localhost) */ + sock_in.sin_addr.s_addr = htonl(client->ip); + sock_in.sin_port = htons(port); + FPRINTF((stderr, + "%sXPAClientStart: attempting dchan connect: %s\n", + _sp, method)); + if( connect(fd, (struct sockaddr *)&sock_in, sizeof(sock_in)) < 0 ){ + PERROR(("dchan connect")); + snprintf(errbuf, SZ_LINE, + "XPA$ERROR: can't connect to data chan (%s:%s%s)\n", + client->xclass, client->name, XPATimestamp()); + if( XPAVerbosity() ){ + perror("XPA client connect"); + } + xclose(fd); + goto error; + } + break; +#if HAVE_SYS_UN_H + case XPA_UNIX: +again: + /* open a socket and fill in socket information */ + if( (fd = xsocket(AF_UNIX, SOCK_STREAM, 0)) < 0 ){ + snprintf(errbuf, SZ_LINE, + "XPA$ERROR: bad socket for data chan (%s:%s%s)\n", + client->xclass, client->name, XPATimestamp()); + if( XPAVerbosity() ){ + perror("XPA client socket"); + } + goto error; + } + setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, + (char *)&keep_alive, sizeof(keep_alive)); + memset((char *)&sock_un, 0, sizeof(sock_un)); + sock_un.sun_family = AF_UNIX; + strcpy(sock_un.sun_path, method); + FPRINTF((stderr, + "%sXPAClientStart: attempting dchan connect: %s\n", + _sp, method)); + if( connect(fd, (struct sockaddr *)&sock_un, sizeof(sock_un)) < 0 ){ + PERROR(("dchan connect")); + xclose(fd); + if( (xerrno == ECONNREFUSED) && (tries < XPA_RETRIES) ){ + tries++; + xclose(fd); + XPASleep(10); + goto again; + } + /* give up */ + else{ + snprintf(errbuf, SZ_LINE, + "XPA$ERROR: can't connect to data chan (%s:%s%s)\n", + client->xclass, client->name, XPATimestamp()); + if( XPAVerbosity() ){ + perror("XPA client connect"); + } + goto error; + } + } + break; +#endif + default: + snprintf(errbuf, SZ_LINE, + "XPA$ERROR: unknown connection method (%s:%s%s)\n", + client->xclass, client->name, XPATimestamp()); + goto error; + } + } + /* handle "doaccept" requests */ + else if( dmode & DATA_ACCEPT ){ + fd = XPAProxyAccept(xpa, XPANSMethod(NULL,2), + client->xclass, client->name, client->cmdfd, + NULL, NULL, tbuf2); + if( fd < 0 ){ + snprintf(errbuf, SZ_LINE, + "XPA$ERROR: can't connect to proxy server (%s:%s%s)\n", + client->xclass, client->name, XPATimestamp()); + goto error; + } + else if( *tbuf2 ){ + client->dataname = xstrdup(tbuf2); + } + } + + /* common code for either type of data connect request */ + client->datafd = fd; + /* make sure we close on exec */ + xfcntl(client->datafd, F_SETFD, FD_CLOEXEC); + /* for senders, set to no block mode */ + if( client->type == 's' ){ + /* save state and set in non-blocking mode */ + xfcntl_nonblock(client->datafd, flags); + } + xpa->nclient += 1; + goto started; + } + /* handle error message */ + else if( !strcmp(tbuf, "XPA$ERROR") ){ + snprintf(errbuf, SZ_LINE, "%s", &lbuf[lp]); + goto error; + } + /* everything else is an error */ + else{ + snprintf(errbuf, SZ_LINE, "%s", &lbuf[lp]); + goto error; + } + } + else{ + snprintf(errbuf, SZ_LINE, + "XPA$ERROR: no response from server during handshake (%s:%s%s)\n", + client->xclass, client->name, XPATimestamp()); + goto error; + } + +error: + FPRINTF((stderr, "Error in XPAClientStart: %s", errbuf)); + XPAClientFree(xpa, client); + return(-1); + +started: + /* it is necessary to add this this extra hack/ack between the + authentication ack and the error return (both from the server) + to avoid getting Nagle buffered. if we already did an accept, + however, we already sent a message and need not repeat it */ + if( !(dmode & DATA_ACCEPT) ){ + FPRINTF((stderr, "%sXPAClientStart: %d sending nagle\n", + _sp, client->cmdfd)); + XPAPuts(NULL, client->cmdfd, "xpanagle\n", XPAShortTimeout()); + } + + /* write a "data request" to the server on the data channel, supplying + the arguments to allow the server to find the associated command */ + if( dmode & DATA_DATA ){ + if( !word(lbuf, tbuf, &lp) ) + strcpy(tbuf, "?"); + if( !word(lbuf, tbuf2, &lp) ) + strcpy(tbuf2, "?"); + snprintf(lbuf, SZ_LINE, "xpadata -f %s %s\n", tbuf, tbuf2); + FPRINTF((stderr, + "%sXPAClientStart: sending data channel %d request: %s", _sp, + client->datafd, lbuf)); + if( XPAPuts(NULL, client->datafd, lbuf, XPAShortTimeout()) <0 ){ + snprintf(errbuf, SZ_LINE, + "XPA$ERROR: unable to issue data request: %s (%s:%s%s)\n", + lbuf, client->xclass, client->name, XPATimestamp()); + FPRINTF((stderr, "%sXPAClientStart: error returned is %s", _sp, errbuf)); + goto error; + } + } + +done: + /* mark as active and started */ + client->status = XPA_CLIENT_PROCESSING; + return(0); +} + +/* + *---------------------------------------------------------------------------- + * + * + * Public Routines + * + * + *---------------------------------------------------------------------------- + */ + +/* + *--------------------------------------------------------------------------- + * + * Routine: XPAClientValid + * + * Purpose: see if the xpa client struct is valid + * + * Results: 1 on success, 0 for failure + * + *--------------------------------------------------------------------------- + */ +#ifdef ANSI_FUNC +int +XPAClientValid (XPA xpa) +#else +int XPAClientValid(xpa) + XPA xpa; +#endif +{ + return(_XPAValid(xpaclienthead, xpa, "c")); +} + +/* + *---------------------------------------------------------------------------- + * + * Routine: XPAOpen + * + * Purpose: open a persistent XPA client connection + * + * Returns: XPA struct on success + * + *---------------------------------------------------------------------------- + */ +#ifdef ANSI_FUNC +XPA +XPAOpen (char *mode) +#else +XPA XPAOpen(mode) + char *mode; +#endif +{ + XPA xpa; + + /* allocate xpa struct */ + if( (xpa = (XPA)xcalloc(1, sizeof(XPARec))) == NULL ) + return(NULL); + /* add version */ + xpa->version = xstrdup(XPA_VERSION); + /* mark this as a client struct */ + xpa->type = xstrdup("c"); + /* mark as persistent so we don't destroy at the end of the transfer */ + xpa->persist = 1; + + /* add this xpa to end of list of client xpas */ + XPAListAdd(&xpaclienthead, xpa); + + return(xpa); +} + +/* + *---------------------------------------------------------------------------- + * + * Routine: XPAClose + * + * Purpose: close a persistent XPA client connection + * + * Returns: none + * + *---------------------------------------------------------------------------- + */ +#ifdef ANSI_FUNC +void +XPAClose (XPA xpa) +#else +void XPAClose(xpa) + XPA xpa; +#endif +{ + XPAClient client, tclient; + NS ns, tns; + + /* ignore struct if its not a client struct */ + if( !XPAClientValid(xpa) ) + return; + + /* remove from list of client xpas */ + XPAListDel(&xpaclienthead, xpa); + + /* free each remaining client */ + for(client=xpa->clienthead; client!=NULL; ){ + tclient = client->next; + XPAClientFree(xpa, client); + client = tclient; + } + + /* close down the name server and all of the remotes for this xpa */ + for(ns=xpa->nshead; ns!=NULL; ){ + tns = ns->next; + XPANSClose(xpa, ns); + ns = tns; + } + + /* free string space */ + if( xpa->version ) + xfree(xpa->version); + if( xpa->type ) + xfree(xpa->type); + if( xpa ) + xfree(xpa); +} + +/* + *---------------------------------------------------------------------------- + * + * Routine: XPAGet + * + * Purpose: get XPA values + * + * Returns: 0 for success, -1 for failure + * len bytes of data returned in buf + * + *---------------------------------------------------------------------------- + */ +#ifdef ANSI_FUNC +int +XPAGet (XPA xpa, char *xtemplate, char *paramlist, char *mode, + char **bufs, size_t *lens, char **names, char **messages, int n) +#else +int XPAGet(xpa, xtemplate, paramlist, mode, bufs, lens, names, messages, n) + XPA xpa; + char *xtemplate; + char *paramlist; + char *mode; + char **bufs; + size_t *lens; + char **names; + char **messages; + int n; +#endif +{ + int i; + int oldmode=0; + int xmode=0; + int type='g'; + int idef=1; + int got=0; + char tbuf[SZ_LINE]; + XPAClient client, tclient; + + FPRINTF((stderr, "%sXPAGet: starting\n", _sp)); + /* if not persistent, we need a temp xpa struct; + (also ignore passed struct if its not a client struct) */ + if( (xpa == NULL) || strcmp(xpa->type, "c") ){ + if( (xpa = XPAOpen(NULL)) == NULL ) + return(-1); + /* mark this as not persistent */ + xpa->persist = 0; + } + /* save xpa mode -- this call might override */ + else{ + /* make sure we have a valid client handle */ + if( !XPAClientValid(xpa) ){ + if( XPAVerbosity() ){ + fprintf(stderr, "XPA$ERROR: invalid xpa client handle\n"); + } + return(-1); + } + oldmode = xpa->client_mode; + } + + /* these arrays are required */ + if( (bufs == NULL) || (lens == NULL) ){ + got = -1; + goto done; + } + + /* flag that we don't read from stdin */ + xpa->ifd = -1; + + /* zero out the return buffers */ + memset((char *)bufs, 0, ABS(n)*sizeof(char *)); + memset((char *)lens, 0, ABS(n)*sizeof(size_t)); + if( names != NULL ) + memset((char *)names, 0, ABS(n)*sizeof(char *)); + if( messages != NULL ) + memset((char *)messages, 0, ABS(n)*sizeof(char *)); + + /* connect to clients and grab data */ + if( XPAClientConnect(xpa, mode, xtemplate, type) >0 ){ + /* retrieve data from n active clients */ + for(client=xpa->clienthead; client!=NULL; ){ + tclient = client->next; + if( (client->type == type) && (client->status != XPA_CLIENT_IDLE) && + (got<ABS(n)) ){ + if( names != NULL ){ + snprintf(tbuf, SZ_LINE, "%s:%s %s", + client->xclass, client->name, client->method); + names[got] = xstrdup(tbuf); + } + if( XPAClientStart(xpa, client, paramlist, mode) >=0 ){ + /* we fill buffers */ + client->mode |= XPA_CLIENT_BUF; + client->bufptr = &(bufs[got]); + client->lenptr = &(lens[got]); + if( names != NULL ) + client->nameptr = &(names[got]); + if( messages != NULL ) + client->errptr = &(messages[got]); + } + else{ + if( messages != NULL ) + messages[got] = xstrdup(errbuf); + } + got++; + } + client = tclient; + } + /* if we have active clients */ + if( got ){ +#if HAVE_MINGW32==0 + /* check for loop modes */ + XPAMode(mode, &xmode, "dofork", XPA_CLIENT_SEL_FORK, 0); + /* dofork implies don't do xpa */ + if( xmode & XPA_CLIENT_SEL_FORK ) + idef = 0; + XPAMode(mode, &xmode, "doxpa", XPA_CLIENT_SEL_XPA, idef); + if( xmode & XPA_CLIENT_SEL_FORK ){ + XPAClientLoopFork(xpa, xmode); + } + else{ + /* enter the main loop and process */ + XPAClientLoop(xpa, xmode); + } +#else + XPAMode(mode, &xmode, "doxpa", XPA_CLIENT_SEL_XPA, idef); + XPAClientLoop(xpa, xmode); +#endif + } + } + +done: + /* look for clients who timed out */ + for(i=0, client=xpa->clienthead; client!=NULL; client=client->next){ + if( (client->type == type) && (client->status != XPA_CLIENT_IDLE) && + (i<ABS(n)) ){ + i++; + if( (client->status == XPA_CLIENT_PROCESSING) && ( messages != NULL) ){ + snprintf(errbuf, SZ_LINE, + "XPA$ERROR: no response from server callback (%s:%s%s)\n", + client->xclass, client->name, XPATimestamp()); + messages[i] = xstrdup(errbuf); + } + } + } + /* remove this xpa if we are not meant to persist */ + if( xpa && !xpa->persist ) + XPAClose(xpa); + /* restore xpa mode -- this call might override */ + else + xpa->client_mode = oldmode; + + /* return number of clients processes (including errors) */ + return(got); +} + +/* + *---------------------------------------------------------------------------- + * + * Routine: XPAGetFd + * + * Purpose: get XPA values + * + * Returns: 0 for success, -1 for failure + * len bytes of data returned in buf + * + *---------------------------------------------------------------------------- + */ +#ifdef ANSI_FUNC +int +XPAGetFd (XPA xpa, char *xtemplate, char *paramlist, char *mode, + int *fds, char **names, char **messages, int n) +#else +int XPAGetFd(xpa, xtemplate, paramlist, mode, fds, names, messages, n) + XPA xpa; + char *xtemplate; + char *paramlist; + int *fds; + char *mode; + char **names; + char **messages; + int n; +#endif +{ + int i; + int oldmode=0; + int xmode=0; + int got=0; + int type='g'; + int idef=1; + char tbuf[SZ_LINE]; + XPAClient client, tclient; + + FPRINTF((stderr, "%sXPAGetFd: starting\n", _sp)); + /* if not persistent, we need a temp xpa struct; + (also ignore passed struct if its not a client struct) */ + if( (xpa == NULL) || strcmp(xpa->type, "c") ){ + if( (xpa = XPAOpen(NULL)) == NULL ) + return(-1); + /* mark this as not persistent */ + xpa->persist = 0; + } + /* save xpa mode -- this call might override */ + else{ + /* make sure we have a valid client handle */ + if( !XPAClientValid(xpa) ){ + if( XPAVerbosity() ){ + fprintf(stderr, "XPA$ERROR: invalid xpa client handle\n"); + } + return(-1); + } + oldmode = xpa->client_mode; + } + + /* flag that we don't read from stdin */ + xpa->ifd = -1; + + /* zero out the return buffers */ + if( names != NULL ) + memset((char *)names, 0, ABS(n)*sizeof(char *)); + if( messages != NULL ) + memset((char *)messages, 0, ABS(n)*sizeof(char *)); + + /* connect to clients and grab data */ + if( XPAClientConnect(xpa, mode, xtemplate, type) > 0 ){ + /* retrieve data from n active clients */ + for(client=xpa->clienthead; client!=NULL; ){ + tclient = client->next; + if( (client->type == type) && (client->status != XPA_CLIENT_IDLE) && + (got<ABS(n)) ){ + if( names != NULL ){ + snprintf(tbuf, SZ_LINE, "%s:%s %s", + client->xclass, client->name, client->method); + names[got] = xstrdup(tbuf); + } + if( XPAClientStart(xpa, client, paramlist, mode) >= 0 ){ + /* we write to an fd */ + client->mode |= XPA_CLIENT_FD; + /* negative value => one channel for all clients */ + if( n < 0 ) + client->fd = fds[0]; + else + client->fd = fds[got]; + client->bufptr = (char **)xcalloc(1, sizeof(char *)); + client->lenptr = (size_t *)xcalloc(1, sizeof(size_t)); + if( names != NULL ) + client->nameptr = &(names[got]); + if( messages != NULL ) + client->errptr = &(messages[got]); + } + else{ + if( messages != NULL ) + messages[got] = xstrdup(errbuf); + } + got++; + } + client = tclient; + } + /* if we have active clients */ + if( got ){ +#if HAVE_MINGW32==0 + /* check for loop modes */ + XPAMode(mode, &xmode, "dofork", XPA_CLIENT_SEL_FORK, 0); + /* dofork implies don't do xpa */ + if( xmode & XPA_CLIENT_SEL_FORK ) + idef = 0; + XPAMode(mode, &xmode, "doxpa", XPA_CLIENT_SEL_XPA, idef); + if( xmode & XPA_CLIENT_SEL_FORK ){ + XPAClientLoopFork(xpa, xmode); + } + else{ + /* enter the main loop and process */ + XPAClientLoop(xpa, xmode); + } +#else + XPAMode(mode, &xmode, "doxpa", XPA_CLIENT_SEL_XPA, idef); + XPAClientLoop(xpa, xmode); +#endif + } + } + /* look for clients who timed out */ + for(i=0, client=xpa->clienthead; client!=NULL; client=client->next){ + if( (client->type == type) && (client->status != XPA_CLIENT_IDLE) && + (i<ABS(n)) ){ + i++; + if( (client->status == XPA_CLIENT_PROCESSING) && ( messages != NULL) ){ + snprintf(errbuf, SZ_LINE, + "XPA$ERROR: no response from server callback (%s:%s%s)\n", + client->xclass, client->name, XPATimestamp()); + messages[i] = xstrdup(errbuf); + } + } + } + /* remove this xpa if we are not meant to persist */ + if( xpa && !xpa->persist ) + XPAClose(xpa); + /* restore xpa mode -- this call might override */ + else + xpa->client_mode = oldmode; + + /* return number of clients processes (including errors) */ + return(got); +} + +/* + *---------------------------------------------------------------------------- + * + * Routine: XPASet + * + * Purpose: set XPA values + * + * Returns: 0 for success, -1 for failure + * + *---------------------------------------------------------------------------- + */ +#ifdef ANSI_FUNC +int +XPASet (XPA xpa, char *xtemplate, char *paramlist, char *mode, + char *buf, size_t len, char **names, char **messages, int n) +#else +int XPASet(xpa, xtemplate, paramlist, mode, buf, len, names, messages, n) + XPA xpa; + char *xtemplate; + char *paramlist; + char *mode; + char *buf; + size_t len; + char **names; + char **messages; + int n; +#endif +{ + int i; + int oldmode=0; + int xmode=0; + int got=0; + int type='s'; + int idef=1; + char tbuf[SZ_LINE]; + XPAClient client, tclient; + + FPRINTF((stderr, "%sXPASet: starting\n", _sp)); + /* if not persistent, we need a temp xpa struct; + (also ignore passed struct if its not a client struct) */ + if( (xpa == NULL) || strcmp(xpa->type, "c") ){ + if( (xpa = XPAOpen(NULL)) == NULL ) + return(-1); + /* mark this as not persistent */ + xpa->persist = 0; + } + /* save xpa mode -- this call might override */ + else{ + /* make sure we have a valid client handle */ + if( !XPAClientValid(xpa) ){ + if( XPAVerbosity() ){ + fprintf(stderr, "XPA$ERROR: invalid xpa client handle\n"); + } + return(-1); + } + oldmode = xpa->client_mode; + } + + /* flag that we don't read from stdin */ + xpa->ifd = -1; + + /* zero out the return buffers */ + if( names != NULL ) + memset((char *)names, 0, ABS(n)*sizeof(char *)); + if( messages != NULL ) + memset((char *)messages, 0, ABS(n)*sizeof(char *)); + + /* connect to clients and grab data */ + if( XPAClientConnect(xpa, mode, xtemplate, type) >0 ){ + /* retrieve data from n active clients */ + for(client=xpa->clienthead; client!=NULL; ){ + tclient = client->next; + if( (client->type == type) && (client->status != XPA_CLIENT_IDLE) && + (got<ABS(n)) ){ + if( names != NULL ){ + snprintf(tbuf, SZ_LINE, "%s:%s %s", + client->xclass, client->name, client->method); + names[got] = xstrdup(tbuf); + } + if( XPAClientStart(xpa, client, paramlist, mode) >= 0 ){ + /* we fill buffers */ + client->mode |= XPA_CLIENT_BUF; + client->buf = buf; + client->len = len; + if( names != NULL ) + client->nameptr = &(names[got]); + if( messages != NULL ) + client->errptr = &(messages[got]); + } + else{ + if( messages != NULL ) + messages[got] = xstrdup(errbuf); + } + got++; + } + client = tclient; + } + /* if we have active clients */ + if( got ){ +#if HAVE_MINGW32==0 + /* check for loop modes */ + XPAMode(mode, &xmode, "dofork", XPA_CLIENT_SEL_FORK, 0); + /* dofork implies don't do xpa */ + if( xmode & XPA_CLIENT_SEL_FORK ) + idef = 0; + XPAMode(mode, &xmode, "doxpa", XPA_CLIENT_SEL_XPA, idef); + if( xmode & XPA_CLIENT_SEL_FORK ){ + XPAClientLoopFork(xpa, xmode); + } + else{ + /* enter the main loop and process */ + XPAClientLoop(xpa, xmode); + } +#else + XPAMode(mode, &xmode, "doxpa", XPA_CLIENT_SEL_XPA, idef); + XPAClientLoop(xpa, xmode); +#endif + } + } + /* look for clients who timed out */ + for(i=0, client=xpa->clienthead; client!=NULL; client=client->next){ + if( (client->type == type) && (client->status != XPA_CLIENT_IDLE) && + (i<ABS(n)) ){ + i++; + if( (client->status == XPA_CLIENT_PROCESSING) && ( messages != NULL) ){ + snprintf(errbuf, SZ_LINE, + "XPA$ERROR: no response from server callback (%s:%s%s)\n", + client->xclass, client->name, XPATimestamp()); + messages[i] = xstrdup(errbuf); + } + } + } + /* remove this xpa if we are not meant to persist */ + if( xpa && !xpa->persist ) + XPAClose(xpa); + /* restore xpa mode -- this call might override */ + else + xpa->client_mode = oldmode; + + /* return number of clients processes (including errors) */ + return(got); +} + +/* + *---------------------------------------------------------------------------- + * + * Routine: XPASetFd + * + * Purpose: set XPA values + * + * Returns: 0 for success, -1 for failure + * + *---------------------------------------------------------------------------- + */ +#ifdef ANSI_FUNC +int +XPASetFd (XPA xpa, char *xtemplate, char *paramlist, char *mode, + int fd, char **names, char **messages, int n) +#else +int XPASetFd(xpa, xtemplate, paramlist, mode, fd, names, messages, n) + XPA xpa; + char *xtemplate; + char *paramlist; + char *mode; + int fd; + char **names; + char **messages; + int n; +#endif +{ + int i; + int oldmode=0; + int xmode=0; + int got=0; + int got2=0; + int type='s'; + int idef=1; + int flags; + char *s; + char tbuf[SZ_LINE]; + XPAClient client, tclient; + + FPRINTF((stderr, "%sXPASetFd: starting\n", _sp)); + /* if not persistent, we need a temp xpa struct; + (also ignore passed struct if its not a client struct) */ + if( (xpa == NULL) || strcmp(xpa->type, "c") ){ + if( (xpa = XPAOpen(NULL)) == NULL ) + return(-1); + /* mark this as not persistent */ + xpa->persist = 0; + } + /* save xpa mode -- this call might override */ + else{ + /* make sure we have a valid client handle */ + if( !XPAClientValid(xpa) ){ + if( XPAVerbosity() ){ + fprintf(stderr, "XPA$ERROR: invalid xpa client handle\n"); + } + return(-1); + } + oldmode = xpa->client_mode; + } + + /* Set non-blocking mode for the input fd, if its not a tty */ + xpa->ifd = fd; + if( isatty(xpa->ifd) == 0 ){ + /* save state and set in non-blocking mode */ + xfcntl_nonblock(xpa->ifd, flags); + } + /* zero out the return buffers */ + if( names != NULL ) + memset((char *)names, 0, ABS(n)*sizeof(char *)); + if( messages != NULL ) + memset((char *)messages, 0, ABS(n)*sizeof(char *)); + + /* connect to clients and grab data */ + if( XPAClientConnect(xpa, mode, xtemplate, type) >0 ){ + /* open clients all at once */ + for(client=xpa->clienthead; client!=NULL; ){ + tclient = client->next; + if( (client->type == type) && (client->status != XPA_CLIENT_IDLE) && + (got<ABS(n)) ){ + if( names != NULL ){ + snprintf(tbuf, SZ_LINE, "%s:%s %s", + client->xclass, client->name, client->method); + names[got] = xstrdup(tbuf); + } + if( XPAClientStart(xpa, client, paramlist, mode) >= 0 ){ + /* we fill buffers */ + client->mode |= XPA_CLIENT_FD; + if( names != NULL ) + client->nameptr = &(names[got]); + if( messages != NULL ) + client->errptr = &(messages[got]); + } + else{ + if( messages != NULL ) + messages[got] = xstrdup(errbuf); + } + got++; + } + client = tclient; + } + /* if we have active clients */ + if( got ){ + /* if fd is null, user did not want to send data, just the paramlist */ + if( fd < 0 ){ + for(client=xpa->clienthead; client!=NULL; ){ + tclient = client->next; + if( (client->type == type) && (client->status != XPA_CLIENT_IDLE) && + (got<ABS(n)) ){ + XPAClientDataSent(xpa, client); + s = XPAClientEnd(xpa, client); + if( (messages != NULL) && (messages[got2] == NULL) ) + messages[got2] = xstrdup(s); + got2++; + } + client = tclient; + } + } + else{ +#if HAVE_MINGW32==0 + /* check for loop modes */ + XPAMode(mode, &xmode, "dofork", XPA_CLIENT_SEL_FORK, 0); + /* dofork implies don't do xpa */ + if( xmode & XPA_CLIENT_SEL_FORK ) + idef = 0; + XPAMode(mode, &xmode, "doxpa", XPA_CLIENT_SEL_XPA, idef); + if( xmode & XPA_CLIENT_SEL_FORK ){ + XPAClientLoopFork(xpa, xmode); + } + else{ + /* enter the main loop and process */ + XPAClientLoop(xpa, xmode); + } +#else + XPAMode(mode, &xmode, "doxpa", XPA_CLIENT_SEL_XPA, idef); + XPAClientLoop(xpa, xmode); +#endif + } + } + } + /* look for clients who timed out */ + for(i=0, client=xpa->clienthead; client!=NULL; client=client->next){ + if( (client->type == type) && (client->status != XPA_CLIENT_IDLE) && + (i<ABS(n)) ){ + i++; + if( (client->status == XPA_CLIENT_PROCESSING) && ( messages != NULL) ){ + snprintf(errbuf, SZ_LINE, + "XPA$ERROR: no response from server callback (%s:%s%s)\n", + client->xclass, client->name, XPATimestamp()); + messages[i] = xstrdup(errbuf); + } + } + } + /* reset flags, if necessary */ + if( xpa->ifd >=0 && (isatty(xpa->ifd) ==0) ){ + xfcntl(xpa->ifd, F_SETFL, flags); + } + /* free all input structs */ + XPAClientFreeAllInputs(xpa); + /* remove this xpa if we are not meant to persist */ + if( xpa && !xpa->persist ) + XPAClose(xpa); + /* restore xpa mode -- this call might override */ + else + xpa->client_mode = oldmode; + + /* return number of clients processes (including errors) */ + return(got); +} + +/* + *---------------------------------------------------------------------------- + * + * Routine: XPAInfo + * + * Purpose: send XPA info + * + * Returns: 0 for success, -1 for failure + * + *---------------------------------------------------------------------------- + */ +#ifdef ANSI_FUNC +int +XPAInfo (XPA xpa, char *xtemplate, char *paramlist, char *mode, + char **names, char **messages, int n) +#else +int XPAInfo(xpa, xtemplate, paramlist, mode, names, messages, n) + XPA xpa; + char *xtemplate; + char *paramlist; + char *mode; + char **names; + char **messages; + int n; +#endif +{ + int i; + int oldmode=0; + int got=0; + char type='i'; + char *s; + char tbuf[SZ_LINE]; + XPAClient client, tclient; + + /* if not persistent, we need a temp xpa struct; + (also ignore passed struct if its not a client struct) */ + if( (xpa == NULL) || strcmp(xpa->type, "c") ){ + if( (xpa = XPAOpen(NULL)) == NULL ) + return(-1); + /* mark this as not persistent */ + xpa->persist = 0; + } + /* save xpa mode -- this call might override */ + else{ + /* make sure we have a valid client handle */ + if( !XPAClientValid(xpa) ){ + if( XPAVerbosity() ){ + fprintf(stderr, "XPA$ERROR: invalid xpa client handle\n"); + } + return(-1); + } + oldmode = xpa->client_mode; + } + + /* flag that we don't read from stdin */ + xpa->ifd = -1; + + /* zero out the return buffers */ + if( names != NULL ) + memset((char *)names, 0, ABS(n)*sizeof(char *)); + if( messages != NULL ) + memset((char *)messages, 0, ABS(n)*sizeof(char *)); + + /* connect to clients and grab data */ + if( XPAClientConnect(xpa, mode, xtemplate, type) >0 ){ + /* retrieve data from n active clients */ + for(client=xpa->clienthead; client!=NULL; ){ + tclient = client->next; + if( (client->type == type) && (client->status != XPA_CLIENT_IDLE) && + (got<ABS(n)) ){ + if( names != NULL ){ + snprintf(tbuf, SZ_LINE, "%s:%s %s", + client->xclass, client->name, client->method); + names[got] = xstrdup(tbuf); + } + if( XPAClientStart(xpa, client, paramlist, mode) >= 0 ){ + XPAClientDataSent(xpa, client); + s = XPAClientEnd(xpa, client); + if( (messages != NULL) && (messages[got] == NULL) ) + messages[got] = xstrdup(s); + } + else{ + if( (messages != NULL) && (messages[got] == NULL) ) + messages[got] = xstrdup(errbuf); + } + got++; + } + client = tclient; + } + } + /* look for clients who timed out */ + for(i=0, client=xpa->clienthead; client!=NULL; client=client->next){ + if( (client->type == type) && (client->status != XPA_CLIENT_IDLE) && + (i<ABS(n)) ){ + i++; + if( (client->status == XPA_CLIENT_PROCESSING) && ( messages != NULL) ){ + snprintf(errbuf, SZ_LINE, + "XPA$ERROR: no response from server callback (%s:%s%s)\n", + client->xclass, client->name, XPATimestamp()); + messages[i] = xstrdup(errbuf); + } + } + } + /* remove this xpa if we are not meant to persist */ + if( xpa && !xpa->persist ) + XPAClose(xpa); + /* restore xpa mode -- this call might override */ + else + xpa->client_mode = oldmode; + + /* return number of clients processes (including errors) */ + return(got); +} + +/* + *---------------------------------------------------------------------------- + * + * Routine: XPAAccess + * + * Purpose: determine if XPA access point is available + * + * Returns: 0 for success, -1 for failure + * + *---------------------------------------------------------------------------- + */ +#ifdef ANSI_FUNC +int +XPAAccess (XPA xpa, char *xtemplate, char *paramlist, char *mode, + char **names, char **messages, int n) +#else +int XPAAccess(xpa, xtemplate, paramlist, mode, names, messages, n) + XPA xpa; + char *xtemplate; + char *paramlist; + char *mode; + char **names; + char **messages; + int n; +#endif +{ + int i; + int oldmode=0; + int xmode=0; + int got=0; + int type='a'; + char *s; + char *ind1, *ind2; + char tbuf[SZ_LINE]; + XPAClient client, tclient; + + /* if not persistent, we need a temp xpa struct; + (also ignore passed struct if its not a client struct) */ + if( (xpa == NULL) || strcmp(xpa->type, "c") ){ + if( (xpa = XPAOpen(NULL)) == NULL ) + return(-1); + /* mark this as not persistent */ + xpa->persist = 0; + } + /* save xpa mode -- this call might override */ + else{ + /* make sure we have a valid client handle */ + if( !XPAClientValid(xpa) ){ + if( XPAVerbosity() ){ + fprintf(stderr, "XPA$ERROR: invalid xpa client handle\n"); + } + return(-1); + } + oldmode = xpa->client_mode; + } + + /* flag that we don't read from stdin */ + xpa->ifd = -1; + + /* zero out the return buffers */ + if( names != NULL ) + memset((char *)names, 0, ABS(n)*sizeof(char *)); + if( messages != NULL ) + memset((char *)messages, 0, ABS(n)*sizeof(char *)); + + /* connect to clients and grab data */ + if( XPAClientConnect(xpa, mode, xtemplate, type) >0 ){ + /* retrieve data from n active clients */ + for(client=xpa->clienthead; client!=NULL; ){ + tclient = client->next; + if( (client->type == type) && (client->status != XPA_CLIENT_IDLE) && + (got<ABS(n)) ){ + if( names != NULL ){ + snprintf(tbuf, SZ_LINE, "%s:%s %s", + client->xclass, client->name, client->method); + names[got] = xstrdup(tbuf); + } + if( XPAClientStart(xpa, client, paramlist, mode) >=0 ){ + XPAClientDataSent(xpa, client); + s = XPAClientEnd(xpa, client); + if( (messages != NULL) && (messages[got] == NULL) ) + messages[got] = xstrdup(s); + } + else{ + if( (messages != NULL) && (messages[got] == NULL) ) + messages[got] = xstrdup(errbuf); + } + /* might have to fix the name if was an explicit mach:port */ + if( names && names[got] && *errbuf && + !strncmp(names[got], "?:?", 3) && + (ind1=strrchr(errbuf, '(')) && (ind2=strrchr(errbuf, ')')) ){ + ind1++; + strncpy(tbuf, ind1, ind2-ind1); + tbuf[ind2-ind1] = '\0'; + xfree(names[got]); + names[got] = xstrdup(tbuf); + } + got++; + } + client = tclient; + } + /* if we have active clients */ + if( got ){ + /* check for loop modes */ + XPAMode(mode, &xmode, "doxpa", XPA_CLIENT_SEL_XPA, 1); + /* enter the main loop and process */ + XPAClientLoop(xpa, xmode); + } + } + /* look for clients who timed out */ + for(i=0, client=xpa->clienthead; client!=NULL; client=client->next){ + if( (client->type == type) && (client->status != XPA_CLIENT_IDLE) && + (i<ABS(n)) ){ + i++; + if( (client->status == XPA_CLIENT_PROCESSING) && ( messages != NULL) ){ + snprintf(errbuf, SZ_LINE, + "XPA$ERROR: no response from server callback (%s:%s%s)\n", + client->xclass, client->name, XPATimestamp()); + messages[i] = xstrdup(errbuf); + } + } + } + /* remove this xpa if we are not meant to persist */ + if( xpa && !xpa->persist ) + XPAClose(xpa); + /* restore xpa mode -- this call might override */ + else + xpa->client_mode = oldmode; + + /* return number of clients processes (including errors) */ + return(got); +} + diff --git a/xpa/clipboard.c b/xpa/clipboard.c new file mode 100644 index 0000000..68df675 --- /dev/null +++ b/xpa/clipboard.c @@ -0,0 +1,324 @@ +/* + * Copyright (c) 1999-2003 Smithsonian Astrophysical Observatory + */ + +/* + * + * remote.c -- xpa access control list management + * + */ + +#include <xpap.h> + +/* + *---------------------------------------------------------------------------- + * + * + * Private Routines + * + * + *---------------------------------------------------------------------------- + */ + +#ifdef ANSI_FUNC +static XPAClip +ClipBoardNew(XPA xpa, char *name) +#else +static XPAClip ClipBoardNew(xpa, name) + XPA xpa; + char *name; +#endif +{ + XPAClip cur, xnew; + if( (xnew = (XPAClip)xcalloc(1, sizeof(XPAClipRec))) == NULL ) + return(NULL); + + /* fill in record structure */ + xnew->name = xstrdup(name); + xnew->ip = xpa->comm->cmdip; + + /* add to the end of list */ + if( xpa->cliphead == NULL ){ + xpa->cliphead = xnew; + } + else{ + for(cur=xpa->cliphead; cur->next!=NULL; cur=cur->next){ + ; + } + cur->next = xnew; + } + return xnew; +} + +#ifdef ANSI_FUNC +static XPAClip +ClipBoardLookup(XPA xpa, char *name) +#else +static XPAClip ClipBoardLookup(xpa, name) + XPA xpa; + char *name; +#endif +{ + XPAClip cur; + + /* look for reserved keywords that have callbacks */ + for(cur=xpa->cliphead; cur!=NULL; cur=cur->next){ + if( !strcmp(name, cur->name) && (xpa->comm->cmdip == cur->ip) ){ + return(cur); + } + } + return NULL; +} + +#ifdef ANSI_FUNC +static int +ClipBoardAdd(XPA xpa, char *name, char *paramlist, char *buf) +#else +static int +ClipBoardAdd(xpa, name, paramlist, buf) + XPA xpa; + char *name; + char *paramlist; + char *buf; +#endif +{ + XPAClip cur; + if( !(cur = ClipBoardLookup(xpa, name)) ) + cur = ClipBoardNew(xpa, name); + if( !cur ) + return -1; + if( cur->value ) + xfree(cur->value); + cur->value = xstrdup(buf); + return 0; +} + +#ifdef ANSI_FUNC +static int +ClipBoardAppend(XPA xpa, char *name, char *paramlist, char *buf) +#else +static int +ClipBoardAppend(xpa, name, paramlist, buf) + XPA xpa; + char *name; + char *paramlist; + char *buf; +#endif +{ + XPAClip cur; + if( !(cur = ClipBoardLookup(xpa, name)) ) + cur = ClipBoardNew(xpa, name); + if( !cur ) + return -1; + if( cur->value ){ + if( (cur->value = (char *)xrealloc(cur->value, + strlen(cur->value)+strlen(buf)+1)) ) + strcat(cur->value, buf); + else + return -1; + } + else{ + cur->value = xstrdup(buf); + } + return 0; +} + +#ifdef ANSI_FUNC +static int +ClipBoardDelete(XPA xpa, char *name, char *paramlist) +#else +static int +ClipBoardDelete(xpa, name, paramlist) + XPA xpa; + char *name; + char *paramlist; +#endif +{ + XPAClip cur; + if( (cur = ClipBoardLookup(xpa, name)) ){ + ClipBoardFree(xpa, cur); + return 0; + } + else + return -1; +} + +/* + *---------------------------------------------------------------------------- + * + * + * Semi-Public Routines (used by xpa.c and command.c) + * + * + *---------------------------------------------------------------------------- + */ + +#ifdef ANSI_FUNC +int +ClipBoardFree(XPA xpa, XPAClip clip) +#else +int ClipBoardFree(xpa, clip) + XPA xpa; + XPAClip clip; +#endif +{ + XPAClip cur; + + if( !clip ) + return 0; + /* remove from list */ + if( xpa->cliphead ){ + if( xpa->cliphead == clip ){ + xpa->cliphead = clip->next; + } + else{ + for(cur=xpa->cliphead; cur!=NULL; cur=cur->next){ + if( cur->next == clip ){ + cur->next = clip->next; + break; + } + } + } + } + if( clip->name ) xfree(clip->name); + if( clip->value ) xfree(clip->value); + xfree(clip); + return 1; +} + +/* + *---------------------------------------------------------------------------- + * + * Routine: XPAReceiveClipboard + * + * Purpose: add a new clipboard entry + * + * Returns: xpa callback error codes + * + *---------------------------------------------------------------------------- + */ +#ifdef ANSI_FUNC +int +XPAReceiveClipboard (void *client_data, void *call_data, char *paramlist, + char *buf, size_t len) +#else +int XPAReceiveClipboard(client_data, call_data, paramlist, buf, len) + void *client_data; + void *call_data; + char *paramlist; + char *buf; + size_t len; +#endif +{ + XPA xpa = (XPA)call_data; + char cmd[SZ_LINE]; + char name[SZ_LINE]; + char tbuf[SZ_LINE]; + int lp=0; + int status = -1; + + *cmd = '\0'; + *name = '\0'; + if( paramlist && *paramlist ){ + if( !word(paramlist, cmd, &lp) || !word(paramlist, name, &lp) ) + goto done; + /* lookup the command */ + if( !strcmp(cmd, "add") ){ + status = ClipBoardAdd(xpa, name, ¶mlist[lp], buf); + } + else if( !strncmp(cmd, "app", 3) ){ + status = ClipBoardAppend(xpa, name, ¶mlist[lp], buf); + } + else if( !strncmp(cmd, "del", 3) ){ + status = ClipBoardDelete(xpa, name, ¶mlist[lp]); + } +#ifdef LATER + else if( !strncmp(cmd, "loa", 3) ){ + status = ClipBoardLoad(xpa, name, ¶mlist[lp], buf); + } + else if( !strncmp(cmd, "sav", 3) ){ + status = ClipBoardSave(xpa, name, ¶mlist[lp]); + } +#endif + } + +done: + if( status < 0 ){ + if( !*cmd || !*name ){ + XPAError(xpa, "XPA clipboard requires: add|append|delete name\n"); + } + else{ + snprintf(tbuf, SZ_LINE, + "XPA clipboard invalid cmd or name: %s %s\n", cmd, name); + XPAError(xpa, tbuf); + } + } + return(status); +} + +/* + *---------------------------------------------------------------------------- + * + * Routine: XPASendClipboard + * + * Purpose: return clipboard information + * + * Returns: 0 for success, -1 for failure + * + *---------------------------------------------------------------------------- + */ +#ifdef ANSI_FUNC +int +XPASendClipboard (void *client_data, void *call_data, char *paramlist, + char **buf, size_t *len) +#else +int XPASendClipboard(client_data, call_data, paramlist, buf, len) + void *client_data; + void *call_data; + char *paramlist; + char **buf; + size_t *len; +#endif +{ + XPA xpa = (XPA)call_data; + char name[SZ_LINE]; + char tbuf[SZ_LINE]; + int lp=0; + int status = -1; + XPAClip cur; + + *name = '\0'; + if( paramlist && *paramlist ){ + if( !word(paramlist, name, &lp) ) + goto done; + if( !(cur = ClipBoardLookup(xpa, name)) ) + goto done; + if( cur->value ){ + send(xpa_datafd(xpa), cur->value, strlen(cur->value), 0); + status = 0; + } + } + +done: + if( status < 0 ){ + if( !*name ){ + XPAError(xpa, "XPA clipboard requires: name\n"); + } + else{ + snprintf(tbuf, SZ_LINE, "XPA clipboard invalid name: %s\n", name); + XPAError(xpa, tbuf); + } + } + return(status); +} + +/* + *---------------------------------------------------------------------------- + * + * + * Public Routines + * + * + *---------------------------------------------------------------------------- + */ + diff --git a/xpa/command.c b/xpa/command.c new file mode 100644 index 0000000..2ea182d --- /dev/null +++ b/xpa/command.c @@ -0,0 +1,1217 @@ +/* + * Copyright (c) 1999-2003 Smithsonian Astrophysical Observatory + */ + +#include <xpap.h> + +/* + *---------------------------------------------------------------------------- + * + * + * Private Routines and Data + * + * + *---------------------------------------------------------------------------- + */ + +/* this is the static xpa struct that holds the reserved commands */ +static XPA rxpa=NULL; + +/* + *---------------------------------------------------------------------------- + * + * Routine: XPACmdParseNames + * + * Purpose: massage a name string, changing multiple sequential spaces + * into a single space + * + * Returns: new name, with spaces massaged (also number of spacess) + * + *---------------------------------------------------------------------------- + */ +#ifdef ANSI_FUNC +static char * +XPACmdParseNames(char *lbuf, int *ntokens) +#else +static char *XPACmdParseNames(lbuf, ntokens) + char *lbuf; + int *ntokens; +#endif +{ + char tbuf[SZ_LINE]; + int lp=0; + char *buf; + + /* can't be larger than the original string */ + buf = (char *)xmalloc(strlen(lbuf)+1); + *buf = '\0'; + *ntokens = 0; + + /* pick off each word, separating by a single space */ + while( word(lbuf, tbuf, &lp)){ + if( *buf != '\0' ) + strcat(buf, " "); + strcat(buf, tbuf); + *ntokens += 1; + } + + /* make the string the right size */ + buf = (char *)xrealloc(buf, strlen(buf)+1); + return(buf); +} + +/* + *---------------------------------------------------------------------------- + * + * Routine: XPAReceiveNSConnect + * + * Purpose: reset and re-establish connection to name server + * + * Returns: xpa callback error codes + * + *---------------------------------------------------------------------------- + */ +#ifdef ANSI_FUNC +static int +XPAReceiveNSConnect (void *client_data, void *call_data, char *paramlist, + char *buf, size_t len) +#else +static int XPAReceiveNSConnect(client_data, call_data, paramlist, buf, len) + void *client_data; + void *call_data; + char *paramlist; + char *buf; + size_t len; +#endif +{ + XPA xpa = (XPA)call_data; + XPA txpa; + char tbuf[SZ_LINE]; + int doall=0; + int lp=0; + + if( paramlist && *paramlist ){ + if( word(paramlist, tbuf, &lp) && !strcmp(tbuf, "-all") ){ + doall = 1; + } + } + if( doall ){ + for(txpa=XPAListHead(); txpa!=NULL; txpa=txpa->next){ + XPANSAdd(txpa, NULL, NULL); + } + } + else{ + XPANSAdd(xpa, NULL, NULL); + } + return(0); +} + +/* + *---------------------------------------------------------------------------- + * + * Routine: XPAReceiveNSDisconnect + * + * Purpose: break connection to name server + * + * Returns: xpa callback error codes + * + *---------------------------------------------------------------------------- + */ +#ifdef ANSI_FUNC +static int +XPAReceiveNSDisconnect (void *client_data, void *call_data, char *paramlist, + char *buf, size_t len) +#else +static int XPAReceiveNSDisconnect(client_data, call_data, paramlist, buf, len) + void *client_data; + void *call_data; + char *paramlist; + char *buf; + size_t len; +#endif +{ + XPA xpa = (XPA)call_data; + XPA txpa; + NS ns, tns; + char tbuf[SZ_LINE]; + int doall=0; + int lp=0; + + if( paramlist && *paramlist ){ + if( word(paramlist, tbuf, &lp) && !strcmp(tbuf, "-all") ){ + doall = 1; + } + } + if( doall ){ + for(txpa=XPAListHead(); txpa!=NULL; txpa=txpa->next){ + for(ns=txpa->nshead; ns!= NULL; ){ + tns = ns->next; + XPANSClose(txpa, ns); + ns = tns; + } + } + } + else{ + for(ns=xpa->nshead; ns!= NULL; ){ + tns = ns->next; + XPANSClose(xpa, ns); + ns = tns; + } + } + return(0); +} + +/* + *---------------------------------------------------------------------------- + * + * Routine: XPAReceiveEnv + * + * Purpose: set an environment variable + * + * Returns: xpa callback error codes + * + *---------------------------------------------------------------------------- + */ +#ifdef ANSI_FUNC +static int +XPAReceiveEnv (void *client_data, void *call_data, char *paramlist, + char *buf, size_t len) +#else +static int XPAReceiveEnv(client_data, call_data, paramlist, buf, len) + void *client_data; + void *call_data; + char *paramlist; + char *buf; + size_t len; +#endif +{ + XPA xpa = (XPA)call_data; + char name[SZ_LINE]; + char value[SZ_LINE]; + char *tbuf; + int lp=0; + + if( word(paramlist, name, &lp) ){ + if( word(paramlist, value, &lp) ){ + tbuf = (char *)xmalloc(strlen(name)+1+strlen(value)+1); + snprintf(tbuf, SZ_LINE, "%s=%s", name, value); + putenv(tbuf); + return(0); + } + else{ + if( strchr(name, '=') != NULL ){ + tbuf = xstrdup(name); + putenv(tbuf); + return(0); + } + else{ + XPAError(xpa, "XPA setenv requires name and value pair\n"); + return(-1); + } + } + } + else{ + XPAError(xpa, "XPA setenv requires name and value pair\n"); + return(-1); + } +} + +/* + *---------------------------------------------------------------------------- + * + * Routine: XPASendEnv + * + * Purpose: return an environment variable to client + * + * Returns: xpa callback error codes + * + *---------------------------------------------------------------------------- + */ +#ifdef ANSI_FUNC +static int +XPASendEnv (void *client_data, void *call_data, char *paramlist, + char **buf, size_t *len) +#else +static int XPASendEnv(client_data, call_data, paramlist, buf, len) + void *client_data; + void *call_data; + char *paramlist; + char **buf; + size_t *len; +#endif +{ + int tlen; + char *tbuf; + char *ebuf; + + if( (ebuf = (char *)getenv(paramlist)) != NULL ){ + tlen = strlen(ebuf)+2; + tbuf = (char *)xmalloc(tlen); + snprintf(tbuf, tlen, "%s\n", ebuf); + *buf = tbuf; + *len = strlen(tbuf); + } + else{ + *buf = xstrdup("\n"); + *len = 1; + } + return(0); +} + +/* + *---------------------------------------------------------------------------- + * + * Routine: XPAReceiveReserved + * + * Purpose: execute reserved command + * + * Returns: xpa callback error codes + * + *---------------------------------------------------------------------------- + */ +#ifdef ANSI_FUNC +static int +XPAReceiveReserved (void *client_data, void *call_data, char *paramlist, + char *buf, size_t len) +#else +static int XPAReceiveReserved(client_data, call_data, paramlist, buf, len) + void *client_data; + void *call_data; + char *paramlist; + char *buf; + size_t len; +#endif +{ + char *cmd = (char *)client_data; + XPA xpa = (XPA)call_data; + + if( !strcmp(cmd, "end") ){ + xpa->comm->status |= XPA_STATUS_ENDBUF; + return(0); + } + else if( !strcmp(cmd, "exec") ){ + xpa->comm->status |= XPA_STATUS_READBUF; + return(0); + } + else{ + return(-1); + } +} + +/* + *---------------------------------------------------------------------------- + * + * Routine: XPASendHelp + * + * Purpose: send help strings + * + * Returns: xpa callback error codes + * + *---------------------------------------------------------------------------- + */ +#ifdef ANSI_FUNC +static int +XPASendHelp (void *client_data, void *call_data, char *paramlist, + char **buf, size_t *len) +#else +static int XPASendHelp(client_data, call_data, paramlist, buf, len) + void *client_data; + void *call_data; + char *paramlist; + char **buf; + size_t *len; +#endif +{ + XPA xpa = (XPA)call_data; + XPACmd cmd; + int lp=0; + int slen; + char tbuf[SZ_LINE]; + char lbuf[SZ_LINE]; + char *sbuf; + + if( !paramlist || !*paramlist ){ + if( xpa->version != NULL ){ + snprintf(lbuf, SZ_LINE, "XPA version: %s\n", xpa->version); + send(xpa_datafd(xpa), lbuf, strlen(lbuf), 0); + } + } + if( xpa->commands == NULL ){ + if( xpa->help != NULL ){ + slen = strlen(xpa->help)+SZ_LINE; + sbuf = (char *)xmalloc(slen); + snprintf(sbuf, slen, "%s\n", xpa->help); + send(xpa_datafd(xpa), sbuf, strlen(sbuf), 0); + xfree(sbuf); + } + else{ + strcpy(lbuf, "\n"); + send(xpa_datafd(xpa), lbuf, strlen(lbuf), 0); + } + } + else{ + if( paramlist && *paramlist ){ + while( word(paramlist, tbuf, &lp) ){ + for(cmd=xpa->commands; cmd!=NULL; cmd=cmd->next){ + if( !strcmp(tbuf, cmd->name) ){ + if( cmd->help != NULL ){ + slen = strlen(cmd->name)+strlen(cmd->help)+SZ_LINE; + sbuf = (char *)xmalloc(slen); + snprintf(sbuf, slen, "%s:\t%s\n", cmd->name, cmd->help); + send(xpa_datafd(xpa), sbuf, strlen(sbuf), 0); + xfree(sbuf); + } + else{ + snprintf(lbuf, SZ_LINE, "%s:\t(no help available)\n", cmd->name); + send(xpa_datafd(xpa), lbuf, strlen(lbuf), 0); + } + } + } + } + } + else{ + for(cmd=xpa->commands; cmd!=NULL; cmd=cmd->next){ + if( cmd->help != NULL ){ + slen = strlen(cmd->name)+strlen(cmd->help)+SZ_LINE; + sbuf = (char *)xmalloc(slen); + snprintf(sbuf, slen, "%s:\t%s\n", cmd->name, cmd->help); + send(xpa_datafd(xpa), sbuf, strlen(sbuf), 0); + xfree(sbuf); + } + else{ + snprintf(lbuf, SZ_LINE, "%s:\t(no help available)\n", cmd->name); + send(xpa_datafd(xpa), lbuf, strlen(lbuf), 0); + } + } + } + } + return(0); +} + +/* + *---------------------------------------------------------------------------- + * + * Routine: XPASendVersion + * + * Purpose: send XPA version string + * + * Returns: xpa callback error codes + * + *---------------------------------------------------------------------------- + */ +#ifdef ANSI_FUNC +static int +XPASendVersion (void *client_data, void *call_data, char *paramlist, + char **buf, size_t *len) +#else +static int XPASendVersion(client_data, call_data, paramlist, buf, len) + void *client_data; + void *call_data; + char *paramlist; + char **buf; + size_t *len; +#endif +{ + XPA xpa = (XPA)call_data; + char lbuf[SZ_LINE]; + + if( xpa->version != NULL ) + snprintf(lbuf, SZ_LINE, "%s\n", xpa->version); + else + strcpy(lbuf, "\n"); + send(xpa_datafd(xpa), lbuf, strlen(lbuf), 0); + return(0); +} + +/* + *---------------------------------------------------------------------------- + * + * + * Semi-Public Routines and Data + * + * These routines are used by XPAHandler and XPANew + * + * + *---------------------------------------------------------------------------- + */ + +/* + *---------------------------------------------------------------------------- + * + * Routine: XPAInitReserved + * + * Purpose: add the reserved commands to the reserved xpa struct + * + * Results: none + * + *---------------------------------------------------------------------------- + */ +#ifdef ANSI_FUNC +void +XPAInitReserved (void) +#else +void XPAInitReserved() +#endif +{ + if( !rxpa ){ + if( (rxpa = (XPA)xcalloc(1, sizeof(struct xparec))) == NULL ) + return; + /* XPACmdAdd requires that the callbacks be defined explicitly in rxpa */ + rxpa->send_callback = XPASendCommands; + rxpa->receive_callback = XPAReceiveCommands; + /* add reserved commands */ + XPACmdAdd(rxpa, "-acl", + "\tget (set) the access control list\n\t\t options: host type acl", + XPASendAcl, NULL, NULL, XPAReceiveAcl, NULL, "fillbuf=false"); + XPACmdAdd(rxpa, "-env", + "\tget (set) an environment variable\n\t\t options: name (value)", + XPASendEnv, NULL, NULL, XPAReceiveEnv, NULL, NULL); + XPACmdAdd(rxpa, "-exec", + "\texecute commands from buffer\n\t\t options: none", + NULL, NULL, NULL, XPAReceiveReserved, (void *)"exec", NULL); + XPACmdAdd(rxpa, "-help", + "\treturn help string for specified XPA\n\t\t options: cmd name (commands only)", + XPASendHelp, NULL, NULL, NULL, NULL, NULL); + XPACmdAdd(rxpa, "-ltimeout", + "\tget (set) long timeout\n\t\t options: seconds|reset", + XPASendLTimeout, NULL, NULL, XPAReceiveLTimeout, NULL, NULL); + XPACmdAdd(rxpa, "-nsconnect", + "\tre-establish name server connection to this XPA\n\t\t options: -all", + NULL, NULL, NULL, XPAReceiveNSConnect, NULL, NULL); + XPACmdAdd(rxpa, "-nsdisconnect", + "\tbreak name server connection to this XPA\n\t\t options: -all", + NULL, NULL, NULL, XPAReceiveNSDisconnect, NULL, NULL); + XPACmdAdd(rxpa, "-remote", + "\tconnect to remote name service with specified acl \n\t\t options: host:port +|-|acl -proxy", + XPASendRemote, NULL, NULL, XPAReceiveRemote, NULL, "fillbuf=false"); + XPACmdAdd(rxpa, "-clipboard", + "\tset/get clipboard information \n\t\t options: [cmd] name", + XPASendClipboard, NULL, NULL, XPAReceiveClipboard, NULL, NULL); + XPACmdAdd(rxpa, "-stimeout", + "\tget (set) short timeout\n\t\t options: seconds|reset", + XPASendSTimeout, NULL, NULL, XPAReceiveSTimeout, NULL, NULL); + XPACmdAdd(rxpa, "-version", + "\treturn XPA version string\n\t\t options: none", + XPASendVersion, NULL, NULL, NULL, NULL, NULL); + } +} + +#ifdef ANSI_FUNC +void +XPAFreeReserved (void) +#else +void XPAFreeReserved() +#endif +{ + XPACmd cmd, tcmd; + if( !rxpa ) return; + /* free reserved commands */ + for(cmd=rxpa->commands; cmd!=NULL; ){ + tcmd = cmd->next; + XPACmdDel(rxpa, cmd); + cmd = tcmd; + } + xfree(rxpa); + rxpa = NULL; +} + +/* + *---------------------------------------------------------------------------- + * + * Routine: XPACmdLookupReserved + * + * Purpose: lookup a reserved command name + * + * Results: cmd struct or null + * + *---------------------------------------------------------------------------- + */ +#ifdef ANSI_FUNC +XPACmd +XPACmdLookupReserved (XPA xpa, char *lbuf, int *lp) +#else +XPACmd XPACmdLookupReserved(xpa, lbuf, lp) + XPA xpa; + char *lbuf; + int *lp; +#endif +{ + XPACmd cmd; + int lp2=0; + char *lptr; + char name[SZ_LINE]; + + /* make sure we have something to work with */ + if( (rxpa==NULL) || (lbuf==NULL) || (lbuf[*lp]=='\0') ) + return(NULL); + + /* this is where we start parsing */ + lptr = &(lbuf[*lp]); + + /* to simplify life, we assume reserved words are 1 token */ + if( !word(lptr, name, &lp2) ) + return(NULL); + + /* look for reserved keywords that have callbacks */ + for(cmd=rxpa->commands; cmd!=NULL; cmd=cmd->next){ + if( !strcmp(name, cmd->name) ){ + *lp += lp2; + return(cmd); + } + } + + /* nothing, nowhere */ + return(NULL); +} + +/* + *---------------------------------------------------------------------------- + * + * Routine: XPACmdLookup + * + * Purpose: lookup a user-defined command name + * + * Results: cmd struct or null + * + *---------------------------------------------------------------------------- + */ +#ifdef ANSI_FUNC +XPACmd +XPACmdLookup (XPA xpa, char *lbuf, int *lp) +#else +XPACmd XPACmdLookup(xpa, lbuf, lp) + XPA xpa; + char *lbuf; + int *lp; +#endif +{ + XPACmd cmd; + int i; + int lp2; + int len, tlen; + char *lptr; + char tbuf[SZ_LINE]; + char name[SZ_LINE]; + + /* make sure we have something to work with */ + if( (xpa==NULL) || (lbuf==NULL) || (lbuf[*lp]=='\0') ) + return(NULL); + + /* this is where we start parsing */ + lptr = &(lbuf[*lp]); + + /* look up commands for this name */ + for(cmd=xpa->commands; cmd!=NULL; cmd=cmd->next){ + /* make up a name with the required number of tokens for this command */ + *name = '\0'; + lp2 = 0; + tlen = 0; + for(i=0; i<cmd->ntokens; i++){ + if( word(lptr, tbuf, &lp2)){ + len = strlen(tbuf)+1; + if( (tlen+len) <= (SZ_LINE-1) ){ + if( *name != '\0' ) + strcat(name, " "); + strcat(name, tbuf); + tlen += len; + } + /* not enough room */ + else{ + *name = '\0'; + break; + } + } + } + /* we now have the name, see if its what we want */ + if( *name && !strcmp(cmd->name, name) ){ + *lp += lp2; + return(cmd); + } + } + + /* did not find the command in this xpa -- now look through reserved */ + return(XPACmdLookupReserved(xpa, lbuf, lp)); +} + +/* + *---------------------------------------------------------------------------- + * + * Routine: XPAReceiveCommands + * + * Purpose: process a list of commands from xpaset + * + * Results: number of commands processed + * + *---------------------------------------------------------------------------- + */ +#ifdef ANSI_FUNC +int +XPAReceiveCommands (void *client_data, void *call_data, char *paramlist, + char *buf, size_t len) +#else +int XPAReceiveCommands(client_data, call_data, paramlist, buf, len) + void *client_data; + void *call_data; + char *paramlist; + char *buf; + size_t len; +#endif +{ + XPA xpa = (XPA)call_data; + XPACmd cmd; + int lp; + int savelp; + int plen; + int bgot; + int got=0; + int gotbuf=0; + int freebuf=1; + char lbuf[SZ_LINE]; + char tbuf[SZ_LINE]; + char tbuf1[SZ_LINE]; + + /* use ";" as a command separator (as well as \n) */ + newdtable(";"); + + /* if we already have buf, there will be no need to get it */ + if( buf ) + gotbuf++; + + /* if we have no paramlist, we read from the socket */ + if( (xpa_datafd(xpa) >=0) && (!paramlist || (*paramlist == '\0')) ){ + xpa->comm->status |= XPA_STATUS_READBUF; + XPAGets(xpa, xpa_datafd(xpa), lbuf, SZ_LINE, XPALongTimeout()); + FPRINTF((stderr, "%sXPAReceiveCommands: read %s\n", _sp, lbuf)); + } + else{ + xpa->comm->status &= ~XPA_STATUS_READBUF; + nowhite(paramlist, lbuf); + } + + /* we must have something to start with */ + if( *lbuf == '\0' ){ + XPAError(xpa, xpaMessbuf[XPA_RTN_NOCMD2]); + got = -1; + goto done; + } + + /* This look either executes the one set of commands in paramlist, + or reads one line at a time from the socket and executes commands. + In the latter case, each callback can read the socket as well */ + while( 1 ){ + FPRINTF((stderr, "%sXPAReceiveCommands: top of loop: %s\n", _sp, lbuf)); + lp = 0; + while( lbuf[lp] != '\0' ){ + if( (cmd = XPACmdLookup(xpa, lbuf, &lp)) == NULL ){ + XPAError(xpa, xpaMessbuf[XPA_RTN_UNCMD]); + got = -1; + goto done; + } + /* reserved commands can only be called from the same host as the server, + or from local (unix) sockets */ + if( (cmd->xpa == rxpa) && + strcmp(cmd->name, "-help") && strcmp(cmd->name, "-version") ){ + if( XPAMtype() == XPA_INET ){ + if( (!xpa->comm || !LOCALIP(xpa->comm->cmdip)) ){ + FPRINTF((stderr, "%sXPAReceiveCommands: rejecting reserved: %s\n", + _sp, cmd->name)); + XPAError(xpa, xpaMessbuf[XPA_RTN_NOAUTH]); + got = -1; + goto done; + } + } + } + FPRINTF((stderr, "%sXPAReceiveCommands: cmd->name: %s\n", + _sp, cmd->name)); + *tbuf = '\0'; + if( (lastdelim() != ';') && (lastdelim() != '\n') ){ + /* skip white space between command and params */ + while( isspace((int)lbuf[lp]) ) + lp++; + /* here is where the params start */ + savelp = lp; + /* look for command delimiter -- the end of the params */ + while( word(lbuf, tbuf1, &lp) ){ + if( (lastdelim() == ';') || (lastdelim() == '\n') ){ + break; + } + /* make sure a command-ending delim is not next */ + while( isspace((int)lbuf[lp]) ) + lp++; + if( (lbuf[lp] == ';') || (lbuf[lp] == '\n') ){ + break; + } + } + /* get length of parameter list */ + plen = lp - savelp; + /* but skip final delim */ + if( (plen>0) && ((lastdelim() == ';')||(lastdelim() == '\n')) ) + plen--; + /* copy the params up to the command delimiter */ + if( plen > 0 ){ + strncpy(tbuf, &(lbuf[savelp]), plen); + tbuf[plen] = '\0'; + } + } + /* execute the associated XPA callback */ + if( cmd->receive_callback != NULL ){ + /* get buf now, if its needed */ + if( !gotbuf && (xpa_datafd(xpa) >= 0) && + (cmd->receive_mode & XPA_MODE_FILLBUF) ){ + /* read buf -- this buf will stay around for all commands */ + FPRINTF((stderr, "%sXPAReceiveCommands: at XPAGetBuf\n", _sp)); + bgot = XPAGetBuf(xpa, xpa_datafd(xpa), &buf, &len, -1); + /* close the data channel */ + XPACloseData(xpa, xpa->comm); + if( bgot >= 0 ){ + /* got the buffer */ + gotbuf++; + } + /* error getting buf */ + else{ + XPAError(xpa, xpaMessbuf[XPA_RTN_NODATA]); + got = -1; + goto done; + } + } + got = (cmd->receive_callback)(cmd->receive_data, call_data, + tbuf, buf, len); + /* if we don't want to free the buffer, mark it for saving */ + if( (buf != NULL) && !(cmd->receive_mode & XPA_MODE_FREEBUF) ){ + freebuf=0; + } + if( got != 0 ){ + goto done; + } + } + else{ + XPAError(xpa, xpaMessbuf[XPA_RTN_NOREC]); + got = -1; + goto done; + } + } + /* conditions for exiting the command loop: */ + /* if we processed the END command, we are done */ + if( xpa->comm->status & XPA_STATUS_ENDBUF ) + break; + /* if we are not reading the data buffer, we are done */ + if( !(xpa->comm->status & XPA_STATUS_READBUF) ) + break; + /* if we got EOF or error reading the data buffer, we are done */ + if( XPAGets(xpa, xpa_datafd(xpa), lbuf, SZ_LINE, XPALongTimeout()) <=0 ) + break; + } + +done: + /* if no one wants buf, free it now */ + if( freebuf ) + xfree(buf); + /* restore last delimiter table */ + freedtable(); + /* return error code */ + return(got); +} + +/* + *---------------------------------------------------------------------------- + * + * Routine: XPASendCommands + * + * Purpose: process a list of commands from xpaget + * + * Results: number of commands processed (currently 0 or 1) + * + *---------------------------------------------------------------------------- + */ +#ifdef ANSI_FUNC +int +XPASendCommands (void *client_data, void *call_data, char *paramlist, + char **buf, size_t *len) +#else +int XPASendCommands(client_data, call_data, paramlist, buf, len) + void *client_data; + void *call_data; + char *paramlist; + char **buf; + size_t *len; +#endif +{ + XPA xpa = (XPA)call_data; + XPACmd cmd; + char tbuf[SZ_LINE]; + int lp=0; + int got=0; + + /* return help as default */ + if( *paramlist == '\0' ){ + paramlist = "-help"; + } + + /* lookup the command and execute */ + if( (cmd = XPACmdLookup(xpa, paramlist, &lp)) != NULL ){ + /* reserved commands can only be called from the same host as the server, + or from local (unix) sockets */ + if( (cmd->xpa == rxpa) && + strcmp(cmd->name, "-help") && strcmp(cmd->name, "-version") ){ + if( XPAMtype() == XPA_INET ){ + if( (!xpa->comm || !LOCALIP(xpa->comm->cmdip)) ){ + FPRINTF((stderr, "%sXPAReceiveCommands: rejecting reserved: %s\n", + _sp, cmd->name)); + XPAError(xpa, xpaMessbuf[XPA_RTN_NOAUTH]); + got = -1; + goto done; + } + } + } + /* execute the associated XPA send callback, + using the remaining command string as an argument */ + strcpy(tbuf, ¶mlist[lp]); + nocr(tbuf); + if( !strcmp(tbuf, "-help") ){ + if( cmd->help != NULL ) + snprintf(tbuf, SZ_LINE, "%s\n", cmd->help); + else + snprintf(tbuf, SZ_LINE, "\n"); + send(xpa_datafd(xpa), tbuf, strlen(tbuf), 0); + got = 0; + } + else if( cmd->send_callback != NULL ){ + got = (cmd->send_callback)(cmd->send_data, call_data, + ¶mlist[lp], buf, len); + } + else{ + XPAError(xpa, xpaMessbuf[XPA_RTN_NOSEND]); + got = -1; + goto done; + } + } + else{ + XPAError(xpa, xpaMessbuf[XPA_RTN_UNCMD]); + got = -1; + goto done; + } + +done: + /* return error code */ + return(got); +} + +/* + *---------------------------------------------------------------------------- + * + * + * Public Routines and Data + * + * + *---------------------------------------------------------------------------- + */ + +/* + *---------------------------------------------------------------------------- + * + * Routine: XPACmdNew + * + * Purpose: define a named command access point + * + * Results: XPA struct or NULL + * + *---------------------------------------------------------------------------- + */ +#ifdef ANSI_FUNC +XPA +XPACmdNew (char *xclass, char *name) +#else +XPA XPACmdNew(xclass, name) + char *xclass; + char *name; +#endif +{ + XPA xpa; + char tbuf[SZ_LINE]; + + /* we need a name */ + if( (name == NULL) || (*name == '\0') ) + return(NULL); + + /* we need some valid class */ + if( (xclass == NULL) || (*xclass == '\0') ) + xclass = "*"; + + /* help string */ + snprintf(tbuf, SZ_LINE, "XPA commands for %s:%s\n\t\t options: see -help", + xclass, name); + + /* create a new XPA with command callbacks */ + xpa = XPANew(xclass, name, tbuf, + XPASendCommands, NULL, NULL, + XPAReceiveCommands, NULL, "fillbuf=false"); + + /* return the good news */ + return(xpa); +} + +/* + *---------------------------------------------------------------------------- + * + * Routine: XPACmdAdd + * + * Purpose: add a command to a named command access point + * + * Results: 0 on success, -1 for failure + * + *---------------------------------------------------------------------------- + */ +#ifdef ANSI_FUNC +XPACmd +XPACmdAdd (XPA xpa, char *name, char *help, + SendCb send_callback, void *send_data, char *send_mode, + ReceiveCb rec_callback, void *rec_data, char *rec_mode) +#else +XPACmd XPACmdAdd(xpa, name, help, + send_callback, send_data, send_mode, + rec_callback, rec_data, rec_mode) + XPA xpa; + char *name; + char *help; + SendCb send_callback; + void *send_data; + char *send_mode; + ReceiveCb rec_callback; + void *rec_data; + char *rec_mode; +#endif +{ + XPACmd xnew; + XPACmd cur; + XPACmd prev; + + /* make sure we have a valid command record */ + if( !xpa || + (xpa->send_callback != XPASendCommands) || + (xpa->receive_callback != XPAReceiveCommands) ){ + return(NULL); + } + + /* we need either a send or a receive or both */ + if( (send_callback == NULL) && (rec_callback == NULL ) ){ + return(NULL); + } + + /* limit the size of the cmd name designation */ + if( strlen(name) > XPA_NAMELEN ){ + return(NULL); + } + + /* allocate space for a new record */ + xnew = (XPACmd)xcalloc(1, sizeof(struct xpacmdrec)); + + /* backlink to xpa */ + xnew->xpa = xpa; + + /* fill in the blanks */ + xnew->name = XPACmdParseNames(name, &(xnew->ntokens)); + xnew->help = xstrdup(help); + + /* receive callback */ + xnew->send_callback = send_callback; + xnew->send_data = send_data; + xnew->send_mode = XPA_DEF_MODE_SEND; + XPAMode(send_mode, &(xnew->send_mode), "freebuf", XPA_MODE_FREEBUF,1); + /* acl is a global mode */ + XPAMode(send_mode, &(xpa->send_mode), "acl", XPA_MODE_ACL, 1); + + /* receive callback */ + xnew->receive_callback = rec_callback; + xnew->receive_data = rec_data; + /* process the mode string */ + xnew->receive_mode = XPA_DEF_MODE_REC; + XPAMode(rec_mode, &(xnew->receive_mode), "usebuf", XPA_MODE_BUF,1); + XPAMode(rec_mode, &(xnew->receive_mode), "fillbuf", XPA_MODE_FILLBUF,1); + XPAMode(rec_mode, &(xnew->receive_mode), "freebuf", XPA_MODE_FREEBUF,1); + /* acl is a global mode */ + XPAMode(rec_mode, &(xpa->receive_mode), "acl", XPA_MODE_ACL, 1); + + /* enter into list, in alphabetical order */ + if( xpa->commands == NULL ){ + xpa->commands = xnew; + return(xnew); + } + else{ + for(prev=NULL, cur=xpa->commands; cur!=NULL; prev=cur, cur=cur->next){ + /* if new name is an existing name, add it before */ + if( strcmp(xnew->name, cur->name) ==0 ) + goto addname; + /* if existing name is a subset of new name, add it before */ + else if( !strncmp(xnew->name, cur->name, strlen(cur->name)) ) + goto addname; + /* if new name is a subset of existing name, add it after */ + else if( !strncmp(xnew->name, cur->name, strlen(xnew->name)) ) + continue; + /* if new name is lexically greater than existing name, add it after */ + else if( strcmp(xnew->name, cur->name) >0 ) + continue; +addname: + /* add the new name here and return */ + if( prev == NULL ){ + xpa->commands = xnew; + xnew->next = cur; + return(xnew); + } + else{ + prev->next = xnew; + xnew->next = cur; + return(xnew); + } + } + /* if we are still here, we did not find a place to insert, i.e., + we are at the end of the list */ + prev->next = xnew; + return(xnew); + } +} + +/* + *---------------------------------------------------------------------------- + * + * Routine: XPACmdDel + * + * Purpose: free a named command access point + * + * Results: none + * + *---------------------------------------------------------------------------- + */ +#ifdef ANSI_FUNC +int +XPACmdDel (XPA xpa, XPACmd cmd) +#else +int XPACmdDel(xpa, cmd) + XPA xpa; + XPACmd cmd; +#endif +{ + XPACmd cur; + int got=0; + + /* gotta have something to free */ + if( cmd == NULL ) + return(-1); + + /* remove from list of xpa's commands */ + if( xpa && xpa->commands ){ + if( xpa->commands == cmd ){ + xpa->commands = cmd->next; + got++; + } + else{ + for(cur=xpa->commands; cur!=NULL; cur=cur->next){ + if( cur->next == cmd ){ + cur->next = cmd->next; + got++; + break; + } + } + } + } + + /* free up space */ + if( got ){ + if( cmd->name ) + xfree(cmd->name); + if( cmd->help ) + xfree(cmd->help); + xfree(cmd); + return(0); + } + else{ + return(-1); + } +} + +/* + *---------------------------------------------------------------------------- + * + * Routine: XPACmdInternalReceive + * + * Purpose: internal execute of the receive callback for this command + * + * Results: number of commands processed + * + *---------------------------------------------------------------------------- + */ +#ifdef ANSI_FUNC +int +XPACmdInternalReceive (void *client_data, void *call_data, + char *paramlist, char *buf, size_t len) +#else +int XPACmdInternalReceive(client_data, call_data, paramlist, buf, len) + void *client_data; + void *call_data; + char *paramlist; + char *buf; + size_t len; +#endif +{ + XPA xpa = (XPA)call_data; + + /* make sure we have something */ + if( xpa == NULL ) + return(-1); + /* make the call */ + return(XPAReceiveCommands(client_data, xpa, paramlist, buf, len)); +} + +/* + *---------------------------------------------------------------------------- + * + * Routine: XPACmdInternalSend + * + * Purpose: internal execute of the send callback for this command + * + * Results: number of commands processed (currently 0 or 1) + * + *---------------------------------------------------------------------------- + */ +#ifdef ANSI_FUNC +int +XPACmdInternalSend (void *client_data, void *call_data, + char *paramlist, char **buf, size_t *len) +#else +int XPACmdInternalSend(client_data, call_data, paramlist, buf, len) + void *client_data; + void *call_data; + char *paramlist; + char **buf; + size_t *len; +#endif +{ + XPA xpa = (XPA)call_data; + + /* make sure we have something */ + if( xpa == NULL ) + return(-1); + + /* make the call */ + return(XPASendCommands(client_data, xpa, paramlist, buf, len)); +} + +/* + *---------------------------------------------------------------------------- + * + * Routine: XPAGetReserved + * + * Purpose: return xpa handle for reserved xpa commands + * + * Return: xpa handle + * + *---------------------------------------------------------------------------- + */ +#ifdef ANSI_FUNC +XPA +XPAGetReserved (void) +#else +XPA XPAGetReserved() +#endif +{ + return(rxpa); +} diff --git a/xpa/conf.h.in b/xpa/conf.h.in new file mode 100644 index 0000000..206d8d6 --- /dev/null +++ b/xpa/conf.h.in @@ -0,0 +1,96 @@ +/* + * Copyright (c) 1999-2003 Smithsonian Astrophysical Observatory + */ + +/* Define as 1 if you have string.h */ +#undef HAVE_STRING_H + +/* Define as 1 if you have strings.h */ +#undef HAVE_STRINGS_H + +/* Define as 1 if you have stdlib.h */ +#undef HAVE_STDLIB_H + +/* Define as 1 if you have malloc.h */ +#undef HAVE_MALLOC_H + +/* Define as 1 if you have unistd.h */ +#undef HAVE_UNISTD_H + +/* Define as 1 if you have getopt.h */ +#undef HAVE_GETOPT_H + +/* Define as 1 if you have pwd.h */ +#undef HAVE_PWD_H + +/* Define as 1 if you have values.h */ +#undef HAVE_VALUES_H + +/* Define as 1 if you have dlfcn.h */ +#undef HAVE_DLFCN_H + +/* Define as 1 if you have sys/un.h */ +#undef HAVE_SYS_UN_H + +/* Define as 1 if you have sys/shm.h */ +#undef HAVE_SYS_SHM_H + +/* Define as 1 if you have sys/mman.h */ +#undef HAVE_SYS_MMAN_H + +/* Define as 1 if you have sys/select.h */ +#undef HAVE_SYS_SELECT_H + +/* Define as 1 if you have sys/ipc.h */ +#undef HAVE_SYS_IPC_H + +/* Define as 1 if you have setjmp.h */ +#undef HAVE_SETJMP_H + +/* Define as 1 if you have socklen_t */ +#undef HAVE_SOCKLEN_T + +/* Define as 1 if you have strchr */ +#undef HAVE_STRCHR + +/* Define as 1 if you have memcpy */ +#undef HAVE_MEMCPY + +/* Define as 1 if you have snprintf */ +#undef HAVE_SNPRINTF + +/* Define as 1 if you have setenv */ +#undef HAVE_SETENV + +/* Define as 1 if you have posix_spawn */ +#undef HAVE_POSIX_SPAWN + +/* Define as 1 if you have crt_externs.h */ +#undef HAVE_CRT_EXTERNS_H + +/* Define as 1 if you have NSGetEvniron */ +#undef HAVE__NSGETENVIRON + +/* Define as 1 if you have atexit */ +#undef HAVE_ATEXIT + +/* Define as 1 if you have pthread library */ +#undef HAVE_LIBPTHREAD + +/* Define as 1 if you need reentrant errno, etc. */ +#undef _REENTRANT + +/* Define as 1 if you have Tcl */ +#undef HAVE_TCL + +/* Define as 1 if you have Xt */ +#undef HAVE_XT + +/* Define as 1 if you have Gtk */ +#undef HAVE_GTK + +/* Define as 1 if you are running Cygwin. */ +#undef HAVE_CYGWIN + +/* Define as 1 if you are running MinGW. */ +#undef HAVE_MINGW32 diff --git a/xpa/config.guess b/xpa/config.guess new file mode 100755 index 0000000..22906b3 --- /dev/null +++ b/xpa/config.guess @@ -0,0 +1,1495 @@ +#! /bin/sh +# Attempt to guess a canonical system name. +# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, +# 2000, 2001, 2002, 2003, 2004, 2005, 2006 Free Software Foundation, +# Inc. + +timestamp='2006-03-13' + +# This file is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA +# 02110-1301, USA. +# +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. + + +# Originally written by Per Bothner <per@bothner.com>. +# Please send patches to <config-patches@gnu.org>. Submit a context +# diff and a properly formatted ChangeLog entry. +# +# This script attempts to guess a canonical system name similar to +# config.sub. If it succeeds, it prints the system name on stdout, and +# exits with 0. Otherwise, it exits with 1. +# +# The plan is that this can be called by configure scripts if you +# don't specify an explicit build system type. + +me=`echo "$0" | sed -e 's,.*/,,'` + +usage="\ +Usage: $0 [OPTION] + +Output the configuration name of the system \`$me' is run on. + +Operation modes: + -h, --help print this help, then exit + -t, --time-stamp print date of last modification, then exit + -v, --version print version number, then exit + +Report bugs and patches to <config-patches@gnu.org>." + +version="\ +GNU config.guess ($timestamp) + +Originally written by Per Bothner. +Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005 +Free Software Foundation, Inc. + +This is free software; see the source for copying conditions. There is NO +warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." + +help=" +Try \`$me --help' for more information." + +# Parse command line +while test $# -gt 0 ; do + case $1 in + --time-stamp | --time* | -t ) + echo "$timestamp" ; exit ;; + --version | -v ) + echo "$version" ; exit ;; + --help | --h* | -h ) + echo "$usage"; exit ;; + -- ) # Stop option processing + shift; break ;; + - ) # Use stdin as input. + break ;; + -* ) + echo "$me: invalid option $1$help" >&2 + exit 1 ;; + * ) + break ;; + esac +done + +if test $# != 0; then + echo "$me: too many arguments$help" >&2 + exit 1 +fi + +trap 'exit 1' 1 2 15 + +# CC_FOR_BUILD -- compiler used by this script. Note that the use of a +# compiler to aid in system detection is discouraged as it requires +# temporary files to be created and, as you can see below, it is a +# headache to deal with in a portable fashion. + +# Historically, `CC_FOR_BUILD' used to be named `HOST_CC'. We still +# use `HOST_CC' if defined, but it is deprecated. + +# Portable tmp directory creation inspired by the Autoconf team. + +set_cc_for_build=' +trap "exitcode=\$?; (rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null) && exit \$exitcode" 0 ; +trap "rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null; exit 1" 1 2 13 15 ; +: ${TMPDIR=/tmp} ; + { tmp=`(umask 077 && mktemp -d "$TMPDIR/cgXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" ; } || + { test -n "$RANDOM" && tmp=$TMPDIR/cg$$-$RANDOM && (umask 077 && mkdir $tmp) ; } || + { tmp=$TMPDIR/cg-$$ && (umask 077 && mkdir $tmp) && echo "Warning: creating insecure temp directory" >&2 ; } || + { echo "$me: cannot create a temporary directory in $TMPDIR" >&2 ; exit 1 ; } ; +dummy=$tmp/dummy ; +tmpfiles="$dummy.c $dummy.o $dummy.rel $dummy" ; +case $CC_FOR_BUILD,$HOST_CC,$CC in + ,,) echo "int x;" > $dummy.c ; + for c in cc gcc c89 c99 ; do + if ($c -c -o $dummy.o $dummy.c) >/dev/null 2>&1 ; then + CC_FOR_BUILD="$c"; break ; + fi ; + done ; + if test x"$CC_FOR_BUILD" = x ; then + CC_FOR_BUILD=no_compiler_found ; + fi + ;; + ,,*) CC_FOR_BUILD=$CC ;; + ,*,*) CC_FOR_BUILD=$HOST_CC ;; +esac ; set_cc_for_build= ;' + +# This is needed to find uname on a Pyramid OSx when run in the BSD universe. +# (ghazi@noc.rutgers.edu 1994-08-24) +if (test -f /.attbin/uname) >/dev/null 2>&1 ; then + PATH=$PATH:/.attbin ; export PATH +fi + +UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown +UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown +UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown +UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown + +# Note: order is significant - the case branches are not exclusive. + +case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in + *:NetBSD:*:*) + # NetBSD (nbsd) targets should (where applicable) match one or + # more of the tupples: *-*-netbsdelf*, *-*-netbsdaout*, + # *-*-netbsdecoff* and *-*-netbsd*. For targets that recently + # switched to ELF, *-*-netbsd* would select the old + # object file format. This provides both forward + # compatibility and a consistent mechanism for selecting the + # object file format. + # + # Note: NetBSD doesn't particularly care about the vendor + # portion of the name. We always set it to "unknown". + sysctl="sysctl -n hw.machine_arch" + UNAME_MACHINE_ARCH=`(/sbin/$sysctl 2>/dev/null || \ + /usr/sbin/$sysctl 2>/dev/null || echo unknown)` + case "${UNAME_MACHINE_ARCH}" in + armeb) machine=armeb-unknown ;; + arm*) machine=arm-unknown ;; + sh3el) machine=shl-unknown ;; + sh3eb) machine=sh-unknown ;; + *) machine=${UNAME_MACHINE_ARCH}-unknown ;; + esac + # The Operating System including object format, if it has switched + # to ELF recently, or will in the future. + case "${UNAME_MACHINE_ARCH}" in + arm*|i386|m68k|ns32k|sh3*|sparc|vax) + eval $set_cc_for_build + if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \ + | grep __ELF__ >/dev/null + then + # Once all utilities can be ECOFF (netbsdecoff) or a.out (netbsdaout). + # Return netbsd for either. FIX? + os=netbsd + else + os=netbsdelf + fi + ;; + *) + os=netbsd + ;; + esac + # The OS release + # Debian GNU/NetBSD machines have a different userland, and + # thus, need a distinct triplet. However, they do not need + # kernel version information, so it can be replaced with a + # suitable tag, in the style of linux-gnu. + case "${UNAME_VERSION}" in + Debian*) + release='-gnu' + ;; + *) + release=`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'` + ;; + esac + # Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM: + # contains redundant information, the shorter form: + # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used. + echo "${machine}-${os}${release}" + exit ;; + *:OpenBSD:*:*) + UNAME_MACHINE_ARCH=`arch | sed 's/OpenBSD.//'` + echo ${UNAME_MACHINE_ARCH}-unknown-openbsd${UNAME_RELEASE} + exit ;; + *:ekkoBSD:*:*) + echo ${UNAME_MACHINE}-unknown-ekkobsd${UNAME_RELEASE} + exit ;; + *:SolidBSD:*:*) + echo ${UNAME_MACHINE}-unknown-solidbsd${UNAME_RELEASE} + exit ;; + macppc:MirBSD:*:*) + echo powerppc-unknown-mirbsd${UNAME_RELEASE} + exit ;; + *:MirBSD:*:*) + echo ${UNAME_MACHINE}-unknown-mirbsd${UNAME_RELEASE} + exit ;; + alpha:OSF1:*:*) + case $UNAME_RELEASE in + *4.0) + UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'` + ;; + *5.*) + UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $4}'` + ;; + esac + # According to Compaq, /usr/sbin/psrinfo has been available on + # OSF/1 and Tru64 systems produced since 1995. I hope that + # covers most systems running today. This code pipes the CPU + # types through head -n 1, so we only detect the type of CPU 0. + ALPHA_CPU_TYPE=`/usr/sbin/psrinfo -v | sed -n -e 's/^ The alpha \(.*\) processor.*$/\1/p' | head -n 1` + case "$ALPHA_CPU_TYPE" in + "EV4 (21064)") + UNAME_MACHINE="alpha" ;; + "EV4.5 (21064)") + UNAME_MACHINE="alpha" ;; + "LCA4 (21066/21068)") + UNAME_MACHINE="alpha" ;; + "EV5 (21164)") + UNAME_MACHINE="alphaev5" ;; + "EV5.6 (21164A)") + UNAME_MACHINE="alphaev56" ;; + "EV5.6 (21164PC)") + UNAME_MACHINE="alphapca56" ;; + "EV5.7 (21164PC)") + UNAME_MACHINE="alphapca57" ;; + "EV6 (21264)") + UNAME_MACHINE="alphaev6" ;; + "EV6.7 (21264A)") + UNAME_MACHINE="alphaev67" ;; + "EV6.8CB (21264C)") + UNAME_MACHINE="alphaev68" ;; + "EV6.8AL (21264B)") + UNAME_MACHINE="alphaev68" ;; + "EV6.8CX (21264D)") + UNAME_MACHINE="alphaev68" ;; + "EV6.9A (21264/EV69A)") + UNAME_MACHINE="alphaev69" ;; + "EV7 (21364)") + UNAME_MACHINE="alphaev7" ;; + "EV7.9 (21364A)") + UNAME_MACHINE="alphaev79" ;; + esac + # A Pn.n version is a patched version. + # A Vn.n version is a released version. + # A Tn.n version is a released field test version. + # A Xn.n version is an unreleased experimental baselevel. + # 1.2 uses "1.2" for uname -r. + echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[PVTX]//' | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` + exit ;; + Alpha\ *:Windows_NT*:*) + # How do we know it's Interix rather than the generic POSIX subsystem? + # Should we change UNAME_MACHINE based on the output of uname instead + # of the specific Alpha model? + echo alpha-pc-interix + exit ;; + 21064:Windows_NT:50:3) + echo alpha-dec-winnt3.5 + exit ;; + Amiga*:UNIX_System_V:4.0:*) + echo m68k-unknown-sysv4 + exit ;; + *:[Aa]miga[Oo][Ss]:*:*) + echo ${UNAME_MACHINE}-unknown-amigaos + exit ;; + *:[Mm]orph[Oo][Ss]:*:*) + echo ${UNAME_MACHINE}-unknown-morphos + exit ;; + *:OS/390:*:*) + echo i370-ibm-openedition + exit ;; + *:z/VM:*:*) + echo s390-ibm-zvmoe + exit ;; + *:OS400:*:*) + echo powerpc-ibm-os400 + exit ;; + arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*) + echo arm-acorn-riscix${UNAME_RELEASE} + exit ;; + arm:riscos:*:*|arm:RISCOS:*:*) + echo arm-unknown-riscos + exit ;; + SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*) + echo hppa1.1-hitachi-hiuxmpp + exit ;; + Pyramid*:OSx*:*:* | MIS*:OSx*:*:* | MIS*:SMP_DC-OSx*:*:*) + # akee@wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE. + if test "`(/bin/universe) 2>/dev/null`" = att ; then + echo pyramid-pyramid-sysv3 + else + echo pyramid-pyramid-bsd + fi + exit ;; + NILE*:*:*:dcosx) + echo pyramid-pyramid-svr4 + exit ;; + DRS?6000:unix:4.0:6*) + echo sparc-icl-nx6 + exit ;; + DRS?6000:UNIX_SV:4.2*:7* | DRS?6000:isis:4.2*:7*) + case `/usr/bin/uname -p` in + sparc) echo sparc-icl-nx7; exit ;; + esac ;; + sun4H:SunOS:5.*:*) + echo sparc-hal-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*) + echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + i86pc:SunOS:5.*:*) + echo i386-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + sun4*:SunOS:6*:*) + # According to config.sub, this is the proper way to canonicalize + # SunOS6. Hard to guess exactly what SunOS6 will be like, but + # it's likely to be more like Solaris than SunOS4. + echo sparc-sun-solaris3`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + sun4*:SunOS:*:*) + case "`/usr/bin/arch -k`" in + Series*|S4*) + UNAME_RELEASE=`uname -v` + ;; + esac + # Japanese Language versions have a version number like `4.1.3-JL'. + echo sparc-sun-sunos`echo ${UNAME_RELEASE}|sed -e 's/-/_/'` + exit ;; + sun3*:SunOS:*:*) + echo m68k-sun-sunos${UNAME_RELEASE} + exit ;; + sun*:*:4.2BSD:*) + UNAME_RELEASE=`(sed 1q /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null` + test "x${UNAME_RELEASE}" = "x" && UNAME_RELEASE=3 + case "`/bin/arch`" in + sun3) + echo m68k-sun-sunos${UNAME_RELEASE} + ;; + sun4) + echo sparc-sun-sunos${UNAME_RELEASE} + ;; + esac + exit ;; + aushp:SunOS:*:*) + echo sparc-auspex-sunos${UNAME_RELEASE} + exit ;; + # The situation for MiNT is a little confusing. The machine name + # can be virtually everything (everything which is not + # "atarist" or "atariste" at least should have a processor + # > m68000). The system name ranges from "MiNT" over "FreeMiNT" + # to the lowercase version "mint" (or "freemint"). Finally + # the system name "TOS" denotes a system which is actually not + # MiNT. But MiNT is downward compatible to TOS, so this should + # be no problem. + atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*) + echo m68k-atari-mint${UNAME_RELEASE} + exit ;; + atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*) + echo m68k-atari-mint${UNAME_RELEASE} + exit ;; + *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*) + echo m68k-atari-mint${UNAME_RELEASE} + exit ;; + milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*) + echo m68k-milan-mint${UNAME_RELEASE} + exit ;; + hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*) + echo m68k-hades-mint${UNAME_RELEASE} + exit ;; + *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*) + echo m68k-unknown-mint${UNAME_RELEASE} + exit ;; + m68k:machten:*:*) + echo m68k-apple-machten${UNAME_RELEASE} + exit ;; + powerpc:machten:*:*) + echo powerpc-apple-machten${UNAME_RELEASE} + exit ;; + RISC*:Mach:*:*) + echo mips-dec-mach_bsd4.3 + exit ;; + RISC*:ULTRIX:*:*) + echo mips-dec-ultrix${UNAME_RELEASE} + exit ;; + VAX*:ULTRIX*:*:*) + echo vax-dec-ultrix${UNAME_RELEASE} + exit ;; + 2020:CLIX:*:* | 2430:CLIX:*:*) + echo clipper-intergraph-clix${UNAME_RELEASE} + exit ;; + mips:*:*:UMIPS | mips:*:*:RISCos) + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c +#ifdef __cplusplus +#include <stdio.h> /* for printf() prototype */ + int main (int argc, char *argv[]) { +#else + int main (argc, argv) int argc; char *argv[]; { +#endif + #if defined (host_mips) && defined (MIPSEB) + #if defined (SYSTYPE_SYSV) + printf ("mips-mips-riscos%ssysv\n", argv[1]); exit (0); + #endif + #if defined (SYSTYPE_SVR4) + printf ("mips-mips-riscos%ssvr4\n", argv[1]); exit (0); + #endif + #if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD) + printf ("mips-mips-riscos%sbsd\n", argv[1]); exit (0); + #endif + #endif + exit (-1); + } +EOF + $CC_FOR_BUILD -o $dummy $dummy.c && + dummyarg=`echo "${UNAME_RELEASE}" | sed -n 's/\([0-9]*\).*/\1/p'` && + SYSTEM_NAME=`$dummy $dummyarg` && + { echo "$SYSTEM_NAME"; exit; } + echo mips-mips-riscos${UNAME_RELEASE} + exit ;; + Motorola:PowerMAX_OS:*:*) + echo powerpc-motorola-powermax + exit ;; + Motorola:*:4.3:PL8-*) + echo powerpc-harris-powermax + exit ;; + Night_Hawk:*:*:PowerMAX_OS | Synergy:PowerMAX_OS:*:*) + echo powerpc-harris-powermax + exit ;; + Night_Hawk:Power_UNIX:*:*) + echo powerpc-harris-powerunix + exit ;; + m88k:CX/UX:7*:*) + echo m88k-harris-cxux7 + exit ;; + m88k:*:4*:R4*) + echo m88k-motorola-sysv4 + exit ;; + m88k:*:3*:R3*) + echo m88k-motorola-sysv3 + exit ;; + AViiON:dgux:*:*) + # DG/UX returns AViiON for all architectures + UNAME_PROCESSOR=`/usr/bin/uname -p` + if [ $UNAME_PROCESSOR = mc88100 ] || [ $UNAME_PROCESSOR = mc88110 ] + then + if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx ] || \ + [ ${TARGET_BINARY_INTERFACE}x = x ] + then + echo m88k-dg-dgux${UNAME_RELEASE} + else + echo m88k-dg-dguxbcs${UNAME_RELEASE} + fi + else + echo i586-dg-dgux${UNAME_RELEASE} + fi + exit ;; + M88*:DolphinOS:*:*) # DolphinOS (SVR3) + echo m88k-dolphin-sysv3 + exit ;; + M88*:*:R3*:*) + # Delta 88k system running SVR3 + echo m88k-motorola-sysv3 + exit ;; + XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3) + echo m88k-tektronix-sysv3 + exit ;; + Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD) + echo m68k-tektronix-bsd + exit ;; + *:IRIX*:*:*) + echo mips-sgi-irix`echo ${UNAME_RELEASE}|sed -e 's/-/_/g'` + exit ;; + ????????:AIX?:[12].1:2) # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX. + echo romp-ibm-aix # uname -m gives an 8 hex-code CPU id + exit ;; # Note that: echo "'`uname -s`'" gives 'AIX ' + i*86:AIX:*:*) + echo i386-ibm-aix + exit ;; + ia64:AIX:*:*) + if [ -x /usr/bin/oslevel ] ; then + IBM_REV=`/usr/bin/oslevel` + else + IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE} + fi + echo ${UNAME_MACHINE}-ibm-aix${IBM_REV} + exit ;; + *:AIX:2:3) + if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + #include <sys/systemcfg.h> + + main() + { + if (!__power_pc()) + exit(1); + puts("powerpc-ibm-aix3.2.5"); + exit(0); + } +EOF + if $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` + then + echo "$SYSTEM_NAME" + else + echo rs6000-ibm-aix3.2.5 + fi + elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then + echo rs6000-ibm-aix3.2.4 + else + echo rs6000-ibm-aix3.2 + fi + exit ;; + *:AIX:*:[45]) + IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | sed 1q | awk '{ print $1 }'` + if /usr/sbin/lsattr -El ${IBM_CPU_ID} | grep ' POWER' >/dev/null 2>&1; then + IBM_ARCH=rs6000 + else + IBM_ARCH=powerpc + fi + if [ -x /usr/bin/oslevel ] ; then + IBM_REV=`/usr/bin/oslevel` + else + IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE} + fi + echo ${IBM_ARCH}-ibm-aix${IBM_REV} + exit ;; + *:AIX:*:*) + echo rs6000-ibm-aix + exit ;; + ibmrt:4.4BSD:*|romp-ibm:BSD:*) + echo romp-ibm-bsd4.4 + exit ;; + ibmrt:*BSD:*|romp-ibm:BSD:*) # covers RT/PC BSD and + echo romp-ibm-bsd${UNAME_RELEASE} # 4.3 with uname added to + exit ;; # report: romp-ibm BSD 4.3 + *:BOSX:*:*) + echo rs6000-bull-bosx + exit ;; + DPX/2?00:B.O.S.:*:*) + echo m68k-bull-sysv3 + exit ;; + 9000/[34]??:4.3bsd:1.*:*) + echo m68k-hp-bsd + exit ;; + hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*) + echo m68k-hp-bsd4.4 + exit ;; + 9000/[34678]??:HP-UX:*:*) + HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` + case "${UNAME_MACHINE}" in + 9000/31? ) HP_ARCH=m68000 ;; + 9000/[34]?? ) HP_ARCH=m68k ;; + 9000/[678][0-9][0-9]) + if [ -x /usr/bin/getconf ]; then + sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null` + sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null` + case "${sc_cpu_version}" in + 523) HP_ARCH="hppa1.0" ;; # CPU_PA_RISC1_0 + 528) HP_ARCH="hppa1.1" ;; # CPU_PA_RISC1_1 + 532) # CPU_PA_RISC2_0 + case "${sc_kernel_bits}" in + 32) HP_ARCH="hppa2.0n" ;; + 64) HP_ARCH="hppa2.0w" ;; + '') HP_ARCH="hppa2.0" ;; # HP-UX 10.20 + esac ;; + esac + fi + if [ "${HP_ARCH}" = "" ]; then + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + + #define _HPUX_SOURCE + #include <stdlib.h> + #include <unistd.h> + + int main () + { + #if defined(_SC_KERNEL_BITS) + long bits = sysconf(_SC_KERNEL_BITS); + #endif + long cpu = sysconf (_SC_CPU_VERSION); + + switch (cpu) + { + case CPU_PA_RISC1_0: puts ("hppa1.0"); break; + case CPU_PA_RISC1_1: puts ("hppa1.1"); break; + case CPU_PA_RISC2_0: + #if defined(_SC_KERNEL_BITS) + switch (bits) + { + case 64: puts ("hppa2.0w"); break; + case 32: puts ("hppa2.0n"); break; + default: puts ("hppa2.0"); break; + } break; + #else /* !defined(_SC_KERNEL_BITS) */ + puts ("hppa2.0"); break; + #endif + default: puts ("hppa1.0"); break; + } + exit (0); + } +EOF + (CCOPTS= $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null) && HP_ARCH=`$dummy` + test -z "$HP_ARCH" && HP_ARCH=hppa + fi ;; + esac + if [ ${HP_ARCH} = "hppa2.0w" ] + then + eval $set_cc_for_build + + # hppa2.0w-hp-hpux* has a 64-bit kernel and a compiler generating + # 32-bit code. hppa64-hp-hpux* has the same kernel and a compiler + # generating 64-bit code. GNU and HP use different nomenclature: + # + # $ CC_FOR_BUILD=cc ./config.guess + # => hppa2.0w-hp-hpux11.23 + # $ CC_FOR_BUILD="cc +DA2.0w" ./config.guess + # => hppa64-hp-hpux11.23 + + if echo __LP64__ | (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | + grep __LP64__ >/dev/null + then + HP_ARCH="hppa2.0w" + else + HP_ARCH="hppa64" + fi + fi + echo ${HP_ARCH}-hp-hpux${HPUX_REV} + exit ;; + ia64:HP-UX:*:*) + HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` + echo ia64-hp-hpux${HPUX_REV} + exit ;; + 3050*:HI-UX:*:*) + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + #include <unistd.h> + int + main () + { + long cpu = sysconf (_SC_CPU_VERSION); + /* The order matters, because CPU_IS_HP_MC68K erroneously returns + true for CPU_PA_RISC1_0. CPU_IS_PA_RISC returns correct + results, however. */ + if (CPU_IS_PA_RISC (cpu)) + { + switch (cpu) + { + case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break; + case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break; + case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break; + default: puts ("hppa-hitachi-hiuxwe2"); break; + } + } + else if (CPU_IS_HP_MC68K (cpu)) + puts ("m68k-hitachi-hiuxwe2"); + else puts ("unknown-hitachi-hiuxwe2"); + exit (0); + } +EOF + $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` && + { echo "$SYSTEM_NAME"; exit; } + echo unknown-hitachi-hiuxwe2 + exit ;; + 9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:* ) + echo hppa1.1-hp-bsd + exit ;; + 9000/8??:4.3bsd:*:*) + echo hppa1.0-hp-bsd + exit ;; + *9??*:MPE/iX:*:* | *3000*:MPE/iX:*:*) + echo hppa1.0-hp-mpeix + exit ;; + hp7??:OSF1:*:* | hp8?[79]:OSF1:*:* ) + echo hppa1.1-hp-osf + exit ;; + hp8??:OSF1:*:*) + echo hppa1.0-hp-osf + exit ;; + i*86:OSF1:*:*) + if [ -x /usr/sbin/sysversion ] ; then + echo ${UNAME_MACHINE}-unknown-osf1mk + else + echo ${UNAME_MACHINE}-unknown-osf1 + fi + exit ;; + parisc*:Lites*:*:*) + echo hppa1.1-hp-lites + exit ;; + C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*) + echo c1-convex-bsd + exit ;; + C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*) + if getsysinfo -f scalar_acc + then echo c32-convex-bsd + else echo c2-convex-bsd + fi + exit ;; + C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*) + echo c34-convex-bsd + exit ;; + C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*) + echo c38-convex-bsd + exit ;; + C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*) + echo c4-convex-bsd + exit ;; + CRAY*Y-MP:*:*:*) + echo ymp-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit ;; + CRAY*[A-Z]90:*:*:*) + echo ${UNAME_MACHINE}-cray-unicos${UNAME_RELEASE} \ + | sed -e 's/CRAY.*\([A-Z]90\)/\1/' \ + -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/ \ + -e 's/\.[^.]*$/.X/' + exit ;; + CRAY*TS:*:*:*) + echo t90-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit ;; + CRAY*T3E:*:*:*) + echo alphaev5-cray-unicosmk${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit ;; + CRAY*SV1:*:*:*) + echo sv1-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit ;; + *:UNICOS/mp:*:*) + echo craynv-cray-unicosmp${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit ;; + F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*) + FUJITSU_PROC=`uname -m | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` + FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` + FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'` + echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" + exit ;; + 5000:UNIX_System_V:4.*:*) + FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` + FUJITSU_REL=`echo ${UNAME_RELEASE} | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/ /_/'` + echo "sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" + exit ;; + i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*) + echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE} + exit ;; + sparc*:BSD/OS:*:*) + echo sparc-unknown-bsdi${UNAME_RELEASE} + exit ;; + *:BSD/OS:*:*) + echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE} + exit ;; + *:FreeBSD:*:*) + case ${UNAME_MACHINE} in + pc98) + echo i386-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;; + *) + echo ${UNAME_MACHINE}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;; + esac + exit ;; + i*:CYGWIN*:*) + echo ${UNAME_MACHINE}-pc-cygwin + exit ;; + i*:MINGW*:*) + echo ${UNAME_MACHINE}-pc-mingw32 + exit ;; + i*:windows32*:*) + # uname -m includes "-pc" on this system. + echo ${UNAME_MACHINE}-mingw32 + exit ;; + i*:PW*:*) + echo ${UNAME_MACHINE}-pc-pw32 + exit ;; + x86:Interix*:[345]*) + echo i586-pc-interix${UNAME_RELEASE} + exit ;; + EM64T:Interix*:[345]*) + echo x86_64-unknown-interix${UNAME_RELEASE} + exit ;; + [345]86:Windows_95:* | [345]86:Windows_98:* | [345]86:Windows_NT:*) + echo i${UNAME_MACHINE}-pc-mks + exit ;; + i*:Windows_NT*:* | Pentium*:Windows_NT*:*) + # How do we know it's Interix rather than the generic POSIX subsystem? + # It also conflicts with pre-2.0 versions of AT&T UWIN. Should we + # UNAME_MACHINE based on the output of uname instead of i386? + echo i586-pc-interix + exit ;; + i*:UWIN*:*) + echo ${UNAME_MACHINE}-pc-uwin + exit ;; + amd64:CYGWIN*:*:* | x86_64:CYGWIN*:*:*) + echo x86_64-unknown-cygwin + exit ;; + p*:CYGWIN*:*) + echo powerpcle-unknown-cygwin + exit ;; + prep*:SunOS:5.*:*) + echo powerpcle-unknown-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + *:GNU:*:*) + # the GNU system + echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-gnu`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'` + exit ;; + *:GNU/*:*:*) + # other systems with GNU libc and userland + echo ${UNAME_MACHINE}-unknown-`echo ${UNAME_SYSTEM} | sed 's,^[^/]*/,,' | tr '[A-Z]' '[a-z]'``echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`-gnu + exit ;; + i*86:Minix:*:*) + echo ${UNAME_MACHINE}-pc-minix + exit ;; + arm*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + cris:Linux:*:*) + echo cris-axis-linux-gnu + exit ;; + crisv32:Linux:*:*) + echo crisv32-axis-linux-gnu + exit ;; + frv:Linux:*:*) + echo frv-unknown-linux-gnu + exit ;; + ia64:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + m32r*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + m68*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + mips:Linux:*:*) + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + #undef CPU + #undef mips + #undef mipsel + #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL) + CPU=mipsel + #else + #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB) + CPU=mips + #else + CPU= + #endif + #endif +EOF + eval "`$CC_FOR_BUILD -E $dummy.c 2>/dev/null | sed -n ' + /^CPU/{ + s: ::g + p + }'`" + test x"${CPU}" != x && { echo "${CPU}-unknown-linux-gnu"; exit; } + ;; + mips64:Linux:*:*) + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + #undef CPU + #undef mips64 + #undef mips64el + #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL) + CPU=mips64el + #else + #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB) + CPU=mips64 + #else + CPU= + #endif + #endif +EOF + eval "`$CC_FOR_BUILD -E $dummy.c 2>/dev/null | sed -n ' + /^CPU/{ + s: ::g + p + }'`" + test x"${CPU}" != x && { echo "${CPU}-unknown-linux-gnu"; exit; } + ;; + or32:Linux:*:*) + echo or32-unknown-linux-gnu + exit ;; + ppc:Linux:*:*) + echo powerpc-unknown-linux-gnu + exit ;; + ppc64:Linux:*:*) + echo powerpc64-unknown-linux-gnu + exit ;; + alpha:Linux:*:*) + case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in + EV5) UNAME_MACHINE=alphaev5 ;; + EV56) UNAME_MACHINE=alphaev56 ;; + PCA56) UNAME_MACHINE=alphapca56 ;; + PCA57) UNAME_MACHINE=alphapca56 ;; + EV6) UNAME_MACHINE=alphaev6 ;; + EV67) UNAME_MACHINE=alphaev67 ;; + EV68*) UNAME_MACHINE=alphaev68 ;; + esac + objdump --private-headers /bin/sh | grep ld.so.1 >/dev/null + if test "$?" = 0 ; then LIBC="libc1" ; else LIBC="" ; fi + echo ${UNAME_MACHINE}-unknown-linux-gnu${LIBC} + exit ;; + parisc:Linux:*:* | hppa:Linux:*:*) + # Look for CPU level + case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in + PA7*) echo hppa1.1-unknown-linux-gnu ;; + PA8*) echo hppa2.0-unknown-linux-gnu ;; + *) echo hppa-unknown-linux-gnu ;; + esac + exit ;; + parisc64:Linux:*:* | hppa64:Linux:*:*) + echo hppa64-unknown-linux-gnu + exit ;; + s390:Linux:*:* | s390x:Linux:*:*) + echo ${UNAME_MACHINE}-ibm-linux + exit ;; + sh64*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + sh*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + sparc:Linux:*:* | sparc64:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + vax:Linux:*:*) + echo ${UNAME_MACHINE}-dec-linux-gnu + exit ;; + x86_64:Linux:*:*) + echo x86_64-unknown-linux-gnu + exit ;; + i*86:Linux:*:*) + # The BFD linker knows what the default object file format is, so + # first see if it will tell us. cd to the root directory to prevent + # problems with other programs or directories called `ld' in the path. + # Set LC_ALL=C to ensure ld outputs messages in English. + ld_supported_targets=`cd /; LC_ALL=C ld --help 2>&1 \ + | sed -ne '/supported targets:/!d + s/[ ][ ]*/ /g + s/.*supported targets: *// + s/ .*// + p'` + case "$ld_supported_targets" in + elf32-i386) + TENTATIVE="${UNAME_MACHINE}-pc-linux-gnu" + ;; + a.out-i386-linux) + echo "${UNAME_MACHINE}-pc-linux-gnuaout" + exit ;; + coff-i386) + echo "${UNAME_MACHINE}-pc-linux-gnucoff" + exit ;; + "") + # Either a pre-BFD a.out linker (linux-gnuoldld) or + # one that does not give us useful --help. + echo "${UNAME_MACHINE}-pc-linux-gnuoldld" + exit ;; + esac + # Determine whether the default compiler is a.out or elf + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + #include <features.h> + #ifdef __ELF__ + # ifdef __GLIBC__ + # if __GLIBC__ >= 2 + LIBC=gnu + # else + LIBC=gnulibc1 + # endif + # else + LIBC=gnulibc1 + # endif + #else + #if defined(__INTEL_COMPILER) || defined(__PGI) || defined(__sun) + LIBC=gnu + #else + LIBC=gnuaout + #endif + #endif + #ifdef __dietlibc__ + LIBC=dietlibc + #endif +EOF + eval "`$CC_FOR_BUILD -E $dummy.c 2>/dev/null | sed -n ' + /^LIBC/{ + s: ::g + p + }'`" + test x"${LIBC}" != x && { + echo "${UNAME_MACHINE}-pc-linux-${LIBC}" + exit + } + test x"${TENTATIVE}" != x && { echo "${TENTATIVE}"; exit; } + ;; + i*86:DYNIX/ptx:4*:*) + # ptx 4.0 does uname -s correctly, with DYNIX/ptx in there. + # earlier versions are messed up and put the nodename in both + # sysname and nodename. + echo i386-sequent-sysv4 + exit ;; + i*86:UNIX_SV:4.2MP:2.*) + # Unixware is an offshoot of SVR4, but it has its own version + # number series starting with 2... + # I am not positive that other SVR4 systems won't match this, + # I just have to hope. -- rms. + # Use sysv4.2uw... so that sysv4* matches it. + echo ${UNAME_MACHINE}-pc-sysv4.2uw${UNAME_VERSION} + exit ;; + i*86:OS/2:*:*) + # If we were able to find `uname', then EMX Unix compatibility + # is probably installed. + echo ${UNAME_MACHINE}-pc-os2-emx + exit ;; + i*86:XTS-300:*:STOP) + echo ${UNAME_MACHINE}-unknown-stop + exit ;; + i*86:atheos:*:*) + echo ${UNAME_MACHINE}-unknown-atheos + exit ;; + i*86:syllable:*:*) + echo ${UNAME_MACHINE}-pc-syllable + exit ;; + i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.0*:*) + echo i386-unknown-lynxos${UNAME_RELEASE} + exit ;; + i*86:*DOS:*:*) + echo ${UNAME_MACHINE}-pc-msdosdjgpp + exit ;; + i*86:*:4.*:* | i*86:SYSTEM_V:4.*:*) + UNAME_REL=`echo ${UNAME_RELEASE} | sed 's/\/MP$//'` + if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then + echo ${UNAME_MACHINE}-univel-sysv${UNAME_REL} + else + echo ${UNAME_MACHINE}-pc-sysv${UNAME_REL} + fi + exit ;; + i*86:*:5:[678]*) + # UnixWare 7.x, OpenUNIX and OpenServer 6. + case `/bin/uname -X | grep "^Machine"` in + *486*) UNAME_MACHINE=i486 ;; + *Pentium) UNAME_MACHINE=i586 ;; + *Pent*|*Celeron) UNAME_MACHINE=i686 ;; + esac + echo ${UNAME_MACHINE}-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}${UNAME_VERSION} + exit ;; + i*86:*:3.2:*) + if test -f /usr/options/cb.name; then + UNAME_REL=`sed -n 's/.*Version //p' </usr/options/cb.name` + echo ${UNAME_MACHINE}-pc-isc$UNAME_REL + elif /bin/uname -X 2>/dev/null >/dev/null ; then + UNAME_REL=`(/bin/uname -X|grep Release|sed -e 's/.*= //')` + (/bin/uname -X|grep i80486 >/dev/null) && UNAME_MACHINE=i486 + (/bin/uname -X|grep '^Machine.*Pentium' >/dev/null) \ + && UNAME_MACHINE=i586 + (/bin/uname -X|grep '^Machine.*Pent *II' >/dev/null) \ + && UNAME_MACHINE=i686 + (/bin/uname -X|grep '^Machine.*Pentium Pro' >/dev/null) \ + && UNAME_MACHINE=i686 + echo ${UNAME_MACHINE}-pc-sco$UNAME_REL + else + echo ${UNAME_MACHINE}-pc-sysv32 + fi + exit ;; + pc:*:*:*) + # Left here for compatibility: + # uname -m prints for DJGPP always 'pc', but it prints nothing about + # the processor, so we play safe by assuming i386. + echo i386-pc-msdosdjgpp + exit ;; + Intel:Mach:3*:*) + echo i386-pc-mach3 + exit ;; + paragon:*:*:*) + echo i860-intel-osf1 + exit ;; + i860:*:4.*:*) # i860-SVR4 + if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then + echo i860-stardent-sysv${UNAME_RELEASE} # Stardent Vistra i860-SVR4 + else # Add other i860-SVR4 vendors below as they are discovered. + echo i860-unknown-sysv${UNAME_RELEASE} # Unknown i860-SVR4 + fi + exit ;; + mini*:CTIX:SYS*5:*) + # "miniframe" + echo m68010-convergent-sysv + exit ;; + mc68k:UNIX:SYSTEM5:3.51m) + echo m68k-convergent-sysv + exit ;; + M680?0:D-NIX:5.3:*) + echo m68k-diab-dnix + exit ;; + M68*:*:R3V[5678]*:*) + test -r /sysV68 && { echo 'm68k-motorola-sysv'; exit; } ;; + 3[345]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 3[34]??/*:*:4.0:3.0 | 4400:*:4.0:3.0 | 4850:*:4.0:3.0 | SKA40:*:4.0:3.0 | SDS2:*:4.0:3.0 | SHG2:*:4.0:3.0 | S7501*:*:4.0:3.0) + OS_REL='' + test -r /etc/.relid \ + && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` + /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ + && { echo i486-ncr-sysv4.3${OS_REL}; exit; } + /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ + && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;; + 3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*) + /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ + && { echo i486-ncr-sysv4; exit; } ;; + m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*) + echo m68k-unknown-lynxos${UNAME_RELEASE} + exit ;; + mc68030:UNIX_System_V:4.*:*) + echo m68k-atari-sysv4 + exit ;; + TSUNAMI:LynxOS:2.*:*) + echo sparc-unknown-lynxos${UNAME_RELEASE} + exit ;; + rs6000:LynxOS:2.*:*) + echo rs6000-unknown-lynxos${UNAME_RELEASE} + exit ;; + PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.0*:*) + echo powerpc-unknown-lynxos${UNAME_RELEASE} + exit ;; + SM[BE]S:UNIX_SV:*:*) + echo mips-dde-sysv${UNAME_RELEASE} + exit ;; + RM*:ReliantUNIX-*:*:*) + echo mips-sni-sysv4 + exit ;; + RM*:SINIX-*:*:*) + echo mips-sni-sysv4 + exit ;; + *:SINIX-*:*:*) + if uname -p 2>/dev/null >/dev/null ; then + UNAME_MACHINE=`(uname -p) 2>/dev/null` + echo ${UNAME_MACHINE}-sni-sysv4 + else + echo ns32k-sni-sysv + fi + exit ;; + PENTIUM:*:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort + # says <Richard.M.Bartel@ccMail.Census.GOV> + echo i586-unisys-sysv4 + exit ;; + *:UNIX_System_V:4*:FTX*) + # From Gerald Hewes <hewes@openmarket.com>. + # How about differentiating between stratus architectures? -djm + echo hppa1.1-stratus-sysv4 + exit ;; + *:*:*:FTX*) + # From seanf@swdc.stratus.com. + echo i860-stratus-sysv4 + exit ;; + i*86:VOS:*:*) + # From Paul.Green@stratus.com. + echo ${UNAME_MACHINE}-stratus-vos + exit ;; + *:VOS:*:*) + # From Paul.Green@stratus.com. + echo hppa1.1-stratus-vos + exit ;; + mc68*:A/UX:*:*) + echo m68k-apple-aux${UNAME_RELEASE} + exit ;; + news*:NEWS-OS:6*:*) + echo mips-sony-newsos6 + exit ;; + R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*) + if [ -d /usr/nec ]; then + echo mips-nec-sysv${UNAME_RELEASE} + else + echo mips-unknown-sysv${UNAME_RELEASE} + fi + exit ;; + BeBox:BeOS:*:*) # BeOS running on hardware made by Be, PPC only. + echo powerpc-be-beos + exit ;; + BeMac:BeOS:*:*) # BeOS running on Mac or Mac clone, PPC only. + echo powerpc-apple-beos + exit ;; + BePC:BeOS:*:*) # BeOS running on Intel PC compatible. + echo i586-pc-beos + exit ;; + SX-4:SUPER-UX:*:*) + echo sx4-nec-superux${UNAME_RELEASE} + exit ;; + SX-5:SUPER-UX:*:*) + echo sx5-nec-superux${UNAME_RELEASE} + exit ;; + SX-6:SUPER-UX:*:*) + echo sx6-nec-superux${UNAME_RELEASE} + exit ;; + Power*:Rhapsody:*:*) + echo powerpc-apple-rhapsody${UNAME_RELEASE} + exit ;; + *:Rhapsody:*:*) + echo ${UNAME_MACHINE}-apple-rhapsody${UNAME_RELEASE} + exit ;; + *:Darwin:*:*) + UNAME_PROCESSOR=`uname -p` || UNAME_PROCESSOR=unknown + case $UNAME_PROCESSOR in + unknown) UNAME_PROCESSOR=powerpc ;; + esac + echo ${UNAME_PROCESSOR}-apple-darwin${UNAME_RELEASE} + exit ;; + *:procnto*:*:* | *:QNX:[0123456789]*:*) + UNAME_PROCESSOR=`uname -p` + if test "$UNAME_PROCESSOR" = "x86"; then + UNAME_PROCESSOR=i386 + UNAME_MACHINE=pc + fi + echo ${UNAME_PROCESSOR}-${UNAME_MACHINE}-nto-qnx${UNAME_RELEASE} + exit ;; + *:QNX:*:4*) + echo i386-pc-qnx + exit ;; + NSE-?:NONSTOP_KERNEL:*:*) + echo nse-tandem-nsk${UNAME_RELEASE} + exit ;; + NSR-?:NONSTOP_KERNEL:*:*) + echo nsr-tandem-nsk${UNAME_RELEASE} + exit ;; + *:NonStop-UX:*:*) + echo mips-compaq-nonstopux + exit ;; + BS2000:POSIX*:*:*) + echo bs2000-siemens-sysv + exit ;; + DS/*:UNIX_System_V:*:*) + echo ${UNAME_MACHINE}-${UNAME_SYSTEM}-${UNAME_RELEASE} + exit ;; + *:Plan9:*:*) + # "uname -m" is not consistent, so use $cputype instead. 386 + # is converted to i386 for consistency with other x86 + # operating systems. + if test "$cputype" = "386"; then + UNAME_MACHINE=i386 + else + UNAME_MACHINE="$cputype" + fi + echo ${UNAME_MACHINE}-unknown-plan9 + exit ;; + *:TOPS-10:*:*) + echo pdp10-unknown-tops10 + exit ;; + *:TENEX:*:*) + echo pdp10-unknown-tenex + exit ;; + KS10:TOPS-20:*:* | KL10:TOPS-20:*:* | TYPE4:TOPS-20:*:*) + echo pdp10-dec-tops20 + exit ;; + XKL-1:TOPS-20:*:* | TYPE5:TOPS-20:*:*) + echo pdp10-xkl-tops20 + exit ;; + *:TOPS-20:*:*) + echo pdp10-unknown-tops20 + exit ;; + *:ITS:*:*) + echo pdp10-unknown-its + exit ;; + SEI:*:*:SEIUX) + echo mips-sei-seiux${UNAME_RELEASE} + exit ;; + *:DragonFly:*:*) + echo ${UNAME_MACHINE}-unknown-dragonfly`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` + exit ;; + *:*VMS:*:*) + UNAME_MACHINE=`(uname -p) 2>/dev/null` + case "${UNAME_MACHINE}" in + A*) echo alpha-dec-vms ; exit ;; + I*) echo ia64-dec-vms ; exit ;; + V*) echo vax-dec-vms ; exit ;; + esac ;; + *:XENIX:*:SysV) + echo i386-pc-xenix + exit ;; + i*86:skyos:*:*) + echo ${UNAME_MACHINE}-pc-skyos`echo ${UNAME_RELEASE}` | sed -e 's/ .*$//' + exit ;; + i*86:rdos:*:*) + echo ${UNAME_MACHINE}-pc-rdos + exit ;; +esac + +#echo '(No uname command or uname output not recognized.)' 1>&2 +#echo "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" 1>&2 + +eval $set_cc_for_build +cat >$dummy.c <<EOF +#ifdef _SEQUENT_ +# include <sys/types.h> +# include <sys/utsname.h> +#endif +main () +{ +#if defined (sony) +#if defined (MIPSEB) + /* BFD wants "bsd" instead of "newsos". Perhaps BFD should be changed, + I don't know.... */ + printf ("mips-sony-bsd\n"); exit (0); +#else +#include <sys/param.h> + printf ("m68k-sony-newsos%s\n", +#ifdef NEWSOS4 + "4" +#else + "" +#endif + ); exit (0); +#endif +#endif + +#if defined (__arm) && defined (__acorn) && defined (__unix) + printf ("arm-acorn-riscix\n"); exit (0); +#endif + +#if defined (hp300) && !defined (hpux) + printf ("m68k-hp-bsd\n"); exit (0); +#endif + +#if defined (NeXT) +#if !defined (__ARCHITECTURE__) +#define __ARCHITECTURE__ "m68k" +#endif + int version; + version=`(hostinfo | sed -n 's/.*NeXT Mach \([0-9]*\).*/\1/p') 2>/dev/null`; + if (version < 4) + printf ("%s-next-nextstep%d\n", __ARCHITECTURE__, version); + else + printf ("%s-next-openstep%d\n", __ARCHITECTURE__, version); + exit (0); +#endif + +#if defined (MULTIMAX) || defined (n16) +#if defined (UMAXV) + printf ("ns32k-encore-sysv\n"); exit (0); +#else +#if defined (CMU) + printf ("ns32k-encore-mach\n"); exit (0); +#else + printf ("ns32k-encore-bsd\n"); exit (0); +#endif +#endif +#endif + +#if defined (__386BSD__) + printf ("i386-pc-bsd\n"); exit (0); +#endif + +#if defined (sequent) +#if defined (i386) + printf ("i386-sequent-dynix\n"); exit (0); +#endif +#if defined (ns32000) + printf ("ns32k-sequent-dynix\n"); exit (0); +#endif +#endif + +#if defined (_SEQUENT_) + struct utsname un; + + uname(&un); + + if (strncmp(un.version, "V2", 2) == 0) { + printf ("i386-sequent-ptx2\n"); exit (0); + } + if (strncmp(un.version, "V1", 2) == 0) { /* XXX is V1 correct? */ + printf ("i386-sequent-ptx1\n"); exit (0); + } + printf ("i386-sequent-ptx\n"); exit (0); + +#endif + +#if defined (vax) +# if !defined (ultrix) +# include <sys/param.h> +# if defined (BSD) +# if BSD == 43 + printf ("vax-dec-bsd4.3\n"); exit (0); +# else +# if BSD == 199006 + printf ("vax-dec-bsd4.3reno\n"); exit (0); +# else + printf ("vax-dec-bsd\n"); exit (0); +# endif +# endif +# else + printf ("vax-dec-bsd\n"); exit (0); +# endif +# else + printf ("vax-dec-ultrix\n"); exit (0); +# endif +#endif + +#if defined (alliant) && defined (i860) + printf ("i860-alliant-bsd\n"); exit (0); +#endif + + exit (1); +} +EOF + +$CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null && SYSTEM_NAME=`$dummy` && + { echo "$SYSTEM_NAME"; exit; } + +# Apollos put the system type in the environment. + +test -d /usr/apollo && { echo ${ISP}-apollo-${SYSTYPE}; exit; } + +# Convex versions that predate uname can use getsysinfo(1) + +if [ -x /usr/convex/getsysinfo ] +then + case `getsysinfo -f cpu_type` in + c1*) + echo c1-convex-bsd + exit ;; + c2*) + if getsysinfo -f scalar_acc + then echo c32-convex-bsd + else echo c2-convex-bsd + fi + exit ;; + c34*) + echo c34-convex-bsd + exit ;; + c38*) + echo c38-convex-bsd + exit ;; + c4*) + echo c4-convex-bsd + exit ;; + esac +fi + +cat >&2 <<EOF +$0: unable to guess system type + +This script, last modified $timestamp, has failed to recognize +the operating system you are using. It is advised that you +download the most up to date version of the config scripts from + + http://savannah.gnu.org/cgi-bin/viewcvs/*checkout*/config/config/config.guess +and + http://savannah.gnu.org/cgi-bin/viewcvs/*checkout*/config/config/config.sub + +If the version you run ($0) is already up to date, please +send the following data and any information you think might be +pertinent to <config-patches@gnu.org> in order to provide the needed +information to handle your system. + +config.guess timestamp = $timestamp + +uname -m = `(uname -m) 2>/dev/null || echo unknown` +uname -r = `(uname -r) 2>/dev/null || echo unknown` +uname -s = `(uname -s) 2>/dev/null || echo unknown` +uname -v = `(uname -v) 2>/dev/null || echo unknown` + +/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null` +/bin/uname -X = `(/bin/uname -X) 2>/dev/null` + +hostinfo = `(hostinfo) 2>/dev/null` +/bin/universe = `(/bin/universe) 2>/dev/null` +/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null` +/bin/arch = `(/bin/arch) 2>/dev/null` +/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null` +/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null` + +UNAME_MACHINE = ${UNAME_MACHINE} +UNAME_RELEASE = ${UNAME_RELEASE} +UNAME_SYSTEM = ${UNAME_SYSTEM} +UNAME_VERSION = ${UNAME_VERSION} +EOF + +exit 1 + +# Local variables: +# eval: (add-hook 'write-file-hooks 'time-stamp) +# time-stamp-start: "timestamp='" +# time-stamp-format: "%:y-%02m-%02d" +# time-stamp-end: "'" +# End: diff --git a/xpa/config.sub b/xpa/config.sub new file mode 100755 index 0000000..5705e54 --- /dev/null +++ b/xpa/config.sub @@ -0,0 +1,1609 @@ +#! /bin/sh +# Configuration validation subroutine script. +# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, +# 2000, 2001, 2002, 2003, 2004, 2005, 2006 Free Software Foundation, +# Inc. + +timestamp='2006-03-07' + +# This file is (in principle) common to ALL GNU software. +# The presence of a machine in this file suggests that SOME GNU software +# can handle that machine. It does not imply ALL GNU software can. +# +# This file is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA +# 02110-1301, USA. +# +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. + + +# Please send patches to <config-patches@gnu.org>. Submit a context +# diff and a properly formatted ChangeLog entry. +# +# Configuration subroutine to validate and canonicalize a configuration type. +# Supply the specified configuration type as an argument. +# If it is invalid, we print an error message on stderr and exit with code 1. +# Otherwise, we print the canonical config type on stdout and succeed. + +# This file is supposed to be the same for all GNU packages +# and recognize all the CPU types, system types and aliases +# that are meaningful with *any* GNU software. +# Each package is responsible for reporting which valid configurations +# it does not support. The user should be able to distinguish +# a failure to support a valid configuration from a meaningless +# configuration. + +# The goal of this file is to map all the various variations of a given +# machine specification into a single specification in the form: +# CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM +# or in some cases, the newer four-part form: +# CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM +# It is wrong to echo any other type of specification. + +me=`echo "$0" | sed -e 's,.*/,,'` + +usage="\ +Usage: $0 [OPTION] CPU-MFR-OPSYS + $0 [OPTION] ALIAS + +Canonicalize a configuration name. + +Operation modes: + -h, --help print this help, then exit + -t, --time-stamp print date of last modification, then exit + -v, --version print version number, then exit + +Report bugs and patches to <config-patches@gnu.org>." + +version="\ +GNU config.sub ($timestamp) + +Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005 +Free Software Foundation, Inc. + +This is free software; see the source for copying conditions. There is NO +warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." + +help=" +Try \`$me --help' for more information." + +# Parse command line +while test $# -gt 0 ; do + case $1 in + --time-stamp | --time* | -t ) + echo "$timestamp" ; exit ;; + --version | -v ) + echo "$version" ; exit ;; + --help | --h* | -h ) + echo "$usage"; exit ;; + -- ) # Stop option processing + shift; break ;; + - ) # Use stdin as input. + break ;; + -* ) + echo "$me: invalid option $1$help" + exit 1 ;; + + *local*) + # First pass through any local machine types. + echo $1 + exit ;; + + * ) + break ;; + esac +done + +case $# in + 0) echo "$me: missing argument$help" >&2 + exit 1;; + 1) ;; + *) echo "$me: too many arguments$help" >&2 + exit 1;; +esac + +# Separate what the user gave into CPU-COMPANY and OS or KERNEL-OS (if any). +# Here we must recognize all the valid KERNEL-OS combinations. +maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'` +case $maybe_os in + nto-qnx* | linux-gnu* | linux-dietlibc | linux-newlib* | linux-uclibc* | \ + uclinux-uclibc* | uclinux-gnu* | kfreebsd*-gnu* | knetbsd*-gnu* | netbsd*-gnu* | \ + storm-chaos* | os2-emx* | rtmk-nova*) + os=-$maybe_os + basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'` + ;; + *) + basic_machine=`echo $1 | sed 's/-[^-]*$//'` + if [ $basic_machine != $1 ] + then os=`echo $1 | sed 's/.*-/-/'` + else os=; fi + ;; +esac + +### Let's recognize common machines as not being operating systems so +### that things like config.sub decstation-3100 work. We also +### recognize some manufacturers as not being operating systems, so we +### can provide default operating systems below. +case $os in + -sun*os*) + # Prevent following clause from handling this invalid input. + ;; + -dec* | -mips* | -sequent* | -encore* | -pc532* | -sgi* | -sony* | \ + -att* | -7300* | -3300* | -delta* | -motorola* | -sun[234]* | \ + -unicom* | -ibm* | -next | -hp | -isi* | -apollo | -altos* | \ + -convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\ + -c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \ + -harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \ + -apple | -axis | -knuth | -cray) + os= + basic_machine=$1 + ;; + -sim | -cisco | -oki | -wec | -winbond) + os= + basic_machine=$1 + ;; + -scout) + ;; + -wrs) + os=-vxworks + basic_machine=$1 + ;; + -chorusos*) + os=-chorusos + basic_machine=$1 + ;; + -chorusrdb) + os=-chorusrdb + basic_machine=$1 + ;; + -hiux*) + os=-hiuxwe2 + ;; + -sco6) + os=-sco5v6 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco5) + os=-sco3.2v5 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco4) + os=-sco3.2v4 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco3.2.[4-9]*) + os=`echo $os | sed -e 's/sco3.2./sco3.2v/'` + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco3.2v[4-9]*) + # Don't forget version if it is 3.2v4 or newer. + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco5v6*) + # Don't forget version if it is 3.2v4 or newer. + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco*) + os=-sco3.2v2 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -udk*) + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -isc) + os=-isc2.2 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -clix*) + basic_machine=clipper-intergraph + ;; + -isc*) + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -lynx*) + os=-lynxos + ;; + -ptx*) + basic_machine=`echo $1 | sed -e 's/86-.*/86-sequent/'` + ;; + -windowsnt*) + os=`echo $os | sed -e 's/windowsnt/winnt/'` + ;; + -psos*) + os=-psos + ;; + -mint | -mint[0-9]*) + basic_machine=m68k-atari + os=-mint + ;; +esac + +# Decode aliases for certain CPU-COMPANY combinations. +case $basic_machine in + # Recognize the basic CPU types without company name. + # Some are omitted here because they have special meanings below. + 1750a | 580 \ + | a29k \ + | alpha | alphaev[4-8] | alphaev56 | alphaev6[78] | alphapca5[67] \ + | alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] | alpha64pca5[67] \ + | am33_2.0 \ + | arc | arm | arm[bl]e | arme[lb] | armv[2345] | armv[345][lb] | avr \ + | bfin \ + | c4x | clipper \ + | d10v | d30v | dlx | dsp16xx \ + | fr30 | frv \ + | h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \ + | i370 | i860 | i960 | ia64 \ + | ip2k | iq2000 \ + | m32r | m32rle | m68000 | m68k | m88k | maxq | mb | microblaze | mcore \ + | mips | mipsbe | mipseb | mipsel | mipsle \ + | mips16 \ + | mips64 | mips64el \ + | mips64vr | mips64vrel \ + | mips64orion | mips64orionel \ + | mips64vr4100 | mips64vr4100el \ + | mips64vr4300 | mips64vr4300el \ + | mips64vr5000 | mips64vr5000el \ + | mips64vr5900 | mips64vr5900el \ + | mipsisa32 | mipsisa32el \ + | mipsisa32r2 | mipsisa32r2el \ + | mipsisa64 | mipsisa64el \ + | mipsisa64r2 | mipsisa64r2el \ + | mipsisa64sb1 | mipsisa64sb1el \ + | mipsisa64sr71k | mipsisa64sr71kel \ + | mipstx39 | mipstx39el \ + | mn10200 | mn10300 \ + | mt \ + | msp430 \ + | nios | nios2 \ + | ns16k | ns32k \ + | or32 \ + | pdp10 | pdp11 | pj | pjl \ + | powerpc | powerpc64 | powerpc64le | powerpcle | ppcbe \ + | pyramid \ + | sh | sh[1234] | sh[24]a | sh[23]e | sh[34]eb | sheb | shbe | shle | sh[1234]le | sh3ele \ + | sh64 | sh64le \ + | sparc | sparc64 | sparc64b | sparc64v | sparc86x | sparclet | sparclite \ + | sparcv8 | sparcv9 | sparcv9b | sparcv9v \ + | strongarm \ + | tahoe | thumb | tic4x | tic80 | tron \ + | v850 | v850e \ + | we32k \ + | x86 | xscale | xscalee[bl] | xstormy16 | xtensa \ + | z8k) + basic_machine=$basic_machine-unknown + ;; + m32c) + basic_machine=$basic_machine-unknown + ;; + m6811 | m68hc11 | m6812 | m68hc12) + # Motorola 68HC11/12. + basic_machine=$basic_machine-unknown + os=-none + ;; + m88110 | m680[12346]0 | m683?2 | m68360 | m5200 | v70 | w65 | z8k) + ;; + ms1) + basic_machine=mt-unknown + ;; + + # We use `pc' rather than `unknown' + # because (1) that's what they normally are, and + # (2) the word "unknown" tends to confuse beginning users. + i*86 | x86_64) + basic_machine=$basic_machine-pc + ;; + # Object if more than one company name word. + *-*-*) + echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 + exit 1 + ;; + # Recognize the basic CPU types with company name. + 580-* \ + | a29k-* \ + | alpha-* | alphaev[4-8]-* | alphaev56-* | alphaev6[78]-* \ + | alpha64-* | alpha64ev[4-8]-* | alpha64ev56-* | alpha64ev6[78]-* \ + | alphapca5[67]-* | alpha64pca5[67]-* | arc-* \ + | arm-* | armbe-* | armle-* | armeb-* | armv*-* \ + | avr-* \ + | bfin-* | bs2000-* \ + | c[123]* | c30-* | [cjt]90-* | c4x-* | c54x-* | c55x-* | c6x-* \ + | clipper-* | craynv-* | cydra-* \ + | d10v-* | d30v-* | dlx-* \ + | elxsi-* \ + | f30[01]-* | f700-* | fr30-* | frv-* | fx80-* \ + | h8300-* | h8500-* \ + | hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \ + | i*86-* | i860-* | i960-* | ia64-* \ + | ip2k-* | iq2000-* \ + | m32r-* | m32rle-* \ + | m68000-* | m680[012346]0-* | m68360-* | m683?2-* | m68k-* \ + | m88110-* | m88k-* | maxq-* | mcore-* \ + | mips-* | mipsbe-* | mipseb-* | mipsel-* | mipsle-* \ + | mips16-* \ + | mips64-* | mips64el-* \ + | mips64vr-* | mips64vrel-* \ + | mips64orion-* | mips64orionel-* \ + | mips64vr4100-* | mips64vr4100el-* \ + | mips64vr4300-* | mips64vr4300el-* \ + | mips64vr5000-* | mips64vr5000el-* \ + | mips64vr5900-* | mips64vr5900el-* \ + | mipsisa32-* | mipsisa32el-* \ + | mipsisa32r2-* | mipsisa32r2el-* \ + | mipsisa64-* | mipsisa64el-* \ + | mipsisa64r2-* | mipsisa64r2el-* \ + | mipsisa64sb1-* | mipsisa64sb1el-* \ + | mipsisa64sr71k-* | mipsisa64sr71kel-* \ + | mipstx39-* | mipstx39el-* \ + | mmix-* \ + | mt-* \ + | msp430-* \ + | nios-* | nios2-* \ + | none-* | np1-* | ns16k-* | ns32k-* \ + | orion-* \ + | pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \ + | powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* | ppcbe-* \ + | pyramid-* \ + | romp-* | rs6000-* \ + | sh-* | sh[1234]-* | sh[24]a-* | sh[23]e-* | sh[34]eb-* | sheb-* | shbe-* \ + | shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \ + | sparc-* | sparc64-* | sparc64b-* | sparc64v-* | sparc86x-* | sparclet-* \ + | sparclite-* \ + | sparcv8-* | sparcv9-* | sparcv9b-* | sparcv9v-* | strongarm-* | sv1-* | sx?-* \ + | tahoe-* | thumb-* \ + | tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* \ + | tron-* \ + | v850-* | v850e-* | vax-* \ + | we32k-* \ + | x86-* | x86_64-* | xps100-* | xscale-* | xscalee[bl]-* \ + | xstormy16-* | xtensa-* \ + | ymp-* \ + | z8k-*) + ;; + m32c-*) + ;; + # Recognize the various machine names and aliases which stand + # for a CPU type and a company and sometimes even an OS. + 386bsd) + basic_machine=i386-unknown + os=-bsd + ;; + 3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc) + basic_machine=m68000-att + ;; + 3b*) + basic_machine=we32k-att + ;; + a29khif) + basic_machine=a29k-amd + os=-udi + ;; + abacus) + basic_machine=abacus-unknown + ;; + adobe68k) + basic_machine=m68010-adobe + os=-scout + ;; + alliant | fx80) + basic_machine=fx80-alliant + ;; + altos | altos3068) + basic_machine=m68k-altos + ;; + am29k) + basic_machine=a29k-none + os=-bsd + ;; + amd64) + basic_machine=x86_64-pc + ;; + amd64-*) + basic_machine=x86_64-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + amdahl) + basic_machine=580-amdahl + os=-sysv + ;; + amiga | amiga-*) + basic_machine=m68k-unknown + ;; + amigaos | amigados) + basic_machine=m68k-unknown + os=-amigaos + ;; + amigaunix | amix) + basic_machine=m68k-unknown + os=-sysv4 + ;; + apollo68) + basic_machine=m68k-apollo + os=-sysv + ;; + apollo68bsd) + basic_machine=m68k-apollo + os=-bsd + ;; + aux) + basic_machine=m68k-apple + os=-aux + ;; + balance) + basic_machine=ns32k-sequent + os=-dynix + ;; + c90) + basic_machine=c90-cray + os=-unicos + ;; + convex-c1) + basic_machine=c1-convex + os=-bsd + ;; + convex-c2) + basic_machine=c2-convex + os=-bsd + ;; + convex-c32) + basic_machine=c32-convex + os=-bsd + ;; + convex-c34) + basic_machine=c34-convex + os=-bsd + ;; + convex-c38) + basic_machine=c38-convex + os=-bsd + ;; + cray | j90) + basic_machine=j90-cray + os=-unicos + ;; + craynv) + basic_machine=craynv-cray + os=-unicosmp + ;; + cr16c) + basic_machine=cr16c-unknown + os=-elf + ;; + crds | unos) + basic_machine=m68k-crds + ;; + crisv32 | crisv32-* | etraxfs*) + basic_machine=crisv32-axis + ;; + cris | cris-* | etrax*) + basic_machine=cris-axis + ;; + crx) + basic_machine=crx-unknown + os=-elf + ;; + da30 | da30-*) + basic_machine=m68k-da30 + ;; + decstation | decstation-3100 | pmax | pmax-* | pmin | dec3100 | decstatn) + basic_machine=mips-dec + ;; + decsystem10* | dec10*) + basic_machine=pdp10-dec + os=-tops10 + ;; + decsystem20* | dec20*) + basic_machine=pdp10-dec + os=-tops20 + ;; + delta | 3300 | motorola-3300 | motorola-delta \ + | 3300-motorola | delta-motorola) + basic_machine=m68k-motorola + ;; + delta88) + basic_machine=m88k-motorola + os=-sysv3 + ;; + djgpp) + basic_machine=i586-pc + os=-msdosdjgpp + ;; + dpx20 | dpx20-*) + basic_machine=rs6000-bull + os=-bosx + ;; + dpx2* | dpx2*-bull) + basic_machine=m68k-bull + os=-sysv3 + ;; + ebmon29k) + basic_machine=a29k-amd + os=-ebmon + ;; + elxsi) + basic_machine=elxsi-elxsi + os=-bsd + ;; + encore | umax | mmax) + basic_machine=ns32k-encore + ;; + es1800 | OSE68k | ose68k | ose | OSE) + basic_machine=m68k-ericsson + os=-ose + ;; + fx2800) + basic_machine=i860-alliant + ;; + genix) + basic_machine=ns32k-ns + ;; + gmicro) + basic_machine=tron-gmicro + os=-sysv + ;; + go32) + basic_machine=i386-pc + os=-go32 + ;; + h3050r* | hiux*) + basic_machine=hppa1.1-hitachi + os=-hiuxwe2 + ;; + h8300hms) + basic_machine=h8300-hitachi + os=-hms + ;; + h8300xray) + basic_machine=h8300-hitachi + os=-xray + ;; + h8500hms) + basic_machine=h8500-hitachi + os=-hms + ;; + harris) + basic_machine=m88k-harris + os=-sysv3 + ;; + hp300-*) + basic_machine=m68k-hp + ;; + hp300bsd) + basic_machine=m68k-hp + os=-bsd + ;; + hp300hpux) + basic_machine=m68k-hp + os=-hpux + ;; + hp3k9[0-9][0-9] | hp9[0-9][0-9]) + basic_machine=hppa1.0-hp + ;; + hp9k2[0-9][0-9] | hp9k31[0-9]) + basic_machine=m68000-hp + ;; + hp9k3[2-9][0-9]) + basic_machine=m68k-hp + ;; + hp9k6[0-9][0-9] | hp6[0-9][0-9]) + basic_machine=hppa1.0-hp + ;; + hp9k7[0-79][0-9] | hp7[0-79][0-9]) + basic_machine=hppa1.1-hp + ;; + hp9k78[0-9] | hp78[0-9]) + # FIXME: really hppa2.0-hp + basic_machine=hppa1.1-hp + ;; + hp9k8[67]1 | hp8[67]1 | hp9k80[24] | hp80[24] | hp9k8[78]9 | hp8[78]9 | hp9k893 | hp893) + # FIXME: really hppa2.0-hp + basic_machine=hppa1.1-hp + ;; + hp9k8[0-9][13679] | hp8[0-9][13679]) + basic_machine=hppa1.1-hp + ;; + hp9k8[0-9][0-9] | hp8[0-9][0-9]) + basic_machine=hppa1.0-hp + ;; + hppa-next) + os=-nextstep3 + ;; + hppaosf) + basic_machine=hppa1.1-hp + os=-osf + ;; + hppro) + basic_machine=hppa1.1-hp + os=-proelf + ;; + i370-ibm* | ibm*) + basic_machine=i370-ibm + ;; +# I'm not sure what "Sysv32" means. Should this be sysv3.2? + i*86v32) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-sysv32 + ;; + i*86v4*) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-sysv4 + ;; + i*86v) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-sysv + ;; + i*86sol2) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-solaris2 + ;; + i386mach) + basic_machine=i386-mach + os=-mach + ;; + i386-vsta | vsta) + basic_machine=i386-unknown + os=-vsta + ;; + iris | iris4d) + basic_machine=mips-sgi + case $os in + -irix*) + ;; + *) + os=-irix4 + ;; + esac + ;; + isi68 | isi) + basic_machine=m68k-isi + os=-sysv + ;; + m88k-omron*) + basic_machine=m88k-omron + ;; + magnum | m3230) + basic_machine=mips-mips + os=-sysv + ;; + merlin) + basic_machine=ns32k-utek + os=-sysv + ;; + mingw32) + basic_machine=i386-pc + os=-mingw32 + ;; + miniframe) + basic_machine=m68000-convergent + ;; + *mint | -mint[0-9]* | *MiNT | *MiNT[0-9]*) + basic_machine=m68k-atari + os=-mint + ;; + mips3*-*) + basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'` + ;; + mips3*) + basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`-unknown + ;; + monitor) + basic_machine=m68k-rom68k + os=-coff + ;; + morphos) + basic_machine=powerpc-unknown + os=-morphos + ;; + msdos) + basic_machine=i386-pc + os=-msdos + ;; + ms1-*) + basic_machine=`echo $basic_machine | sed -e 's/ms1-/mt-/'` + ;; + mvs) + basic_machine=i370-ibm + os=-mvs + ;; + ncr3000) + basic_machine=i486-ncr + os=-sysv4 + ;; + netbsd386) + basic_machine=i386-unknown + os=-netbsd + ;; + netwinder) + basic_machine=armv4l-rebel + os=-linux + ;; + news | news700 | news800 | news900) + basic_machine=m68k-sony + os=-newsos + ;; + news1000) + basic_machine=m68030-sony + os=-newsos + ;; + news-3600 | risc-news) + basic_machine=mips-sony + os=-newsos + ;; + necv70) + basic_machine=v70-nec + os=-sysv + ;; + next | m*-next ) + basic_machine=m68k-next + case $os in + -nextstep* ) + ;; + -ns2*) + os=-nextstep2 + ;; + *) + os=-nextstep3 + ;; + esac + ;; + nh3000) + basic_machine=m68k-harris + os=-cxux + ;; + nh[45]000) + basic_machine=m88k-harris + os=-cxux + ;; + nindy960) + basic_machine=i960-intel + os=-nindy + ;; + mon960) + basic_machine=i960-intel + os=-mon960 + ;; + nonstopux) + basic_machine=mips-compaq + os=-nonstopux + ;; + np1) + basic_machine=np1-gould + ;; + nsr-tandem) + basic_machine=nsr-tandem + ;; + op50n-* | op60c-*) + basic_machine=hppa1.1-oki + os=-proelf + ;; + openrisc | openrisc-*) + basic_machine=or32-unknown + ;; + os400) + basic_machine=powerpc-ibm + os=-os400 + ;; + OSE68000 | ose68000) + basic_machine=m68000-ericsson + os=-ose + ;; + os68k) + basic_machine=m68k-none + os=-os68k + ;; + pa-hitachi) + basic_machine=hppa1.1-hitachi + os=-hiuxwe2 + ;; + paragon) + basic_machine=i860-intel + os=-osf + ;; + pbd) + basic_machine=sparc-tti + ;; + pbb) + basic_machine=m68k-tti + ;; + pc532 | pc532-*) + basic_machine=ns32k-pc532 + ;; + pc98) + basic_machine=i386-pc + ;; + pc98-*) + basic_machine=i386-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pentium | p5 | k5 | k6 | nexgen | viac3) + basic_machine=i586-pc + ;; + pentiumpro | p6 | 6x86 | athlon | athlon_*) + basic_machine=i686-pc + ;; + pentiumii | pentium2 | pentiumiii | pentium3) + basic_machine=i686-pc + ;; + pentium4) + basic_machine=i786-pc + ;; + pentium-* | p5-* | k5-* | k6-* | nexgen-* | viac3-*) + basic_machine=i586-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pentiumpro-* | p6-* | 6x86-* | athlon-*) + basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pentiumii-* | pentium2-* | pentiumiii-* | pentium3-*) + basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pentium4-*) + basic_machine=i786-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pn) + basic_machine=pn-gould + ;; + power) basic_machine=power-ibm + ;; + ppc) basic_machine=powerpc-unknown + ;; + ppc-*) basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + ppcle | powerpclittle | ppc-le | powerpc-little) + basic_machine=powerpcle-unknown + ;; + ppcle-* | powerpclittle-*) + basic_machine=powerpcle-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + ppc64) basic_machine=powerpc64-unknown + ;; + ppc64-*) basic_machine=powerpc64-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + ppc64le | powerpc64little | ppc64-le | powerpc64-little) + basic_machine=powerpc64le-unknown + ;; + ppc64le-* | powerpc64little-*) + basic_machine=powerpc64le-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + ps2) + basic_machine=i386-ibm + ;; + pw32) + basic_machine=i586-unknown + os=-pw32 + ;; + rdos) + basic_machine=i386-pc + os=-rdos + ;; + rom68k) + basic_machine=m68k-rom68k + os=-coff + ;; + rm[46]00) + basic_machine=mips-siemens + ;; + rtpc | rtpc-*) + basic_machine=romp-ibm + ;; + s390 | s390-*) + basic_machine=s390-ibm + ;; + s390x | s390x-*) + basic_machine=s390x-ibm + ;; + sa29200) + basic_machine=a29k-amd + os=-udi + ;; + sb1) + basic_machine=mipsisa64sb1-unknown + ;; + sb1el) + basic_machine=mipsisa64sb1el-unknown + ;; + sei) + basic_machine=mips-sei + os=-seiux + ;; + sequent) + basic_machine=i386-sequent + ;; + sh) + basic_machine=sh-hitachi + os=-hms + ;; + sh64) + basic_machine=sh64-unknown + ;; + sparclite-wrs | simso-wrs) + basic_machine=sparclite-wrs + os=-vxworks + ;; + sps7) + basic_machine=m68k-bull + os=-sysv2 + ;; + spur) + basic_machine=spur-unknown + ;; + st2000) + basic_machine=m68k-tandem + ;; + stratus) + basic_machine=i860-stratus + os=-sysv4 + ;; + sun2) + basic_machine=m68000-sun + ;; + sun2os3) + basic_machine=m68000-sun + os=-sunos3 + ;; + sun2os4) + basic_machine=m68000-sun + os=-sunos4 + ;; + sun3os3) + basic_machine=m68k-sun + os=-sunos3 + ;; + sun3os4) + basic_machine=m68k-sun + os=-sunos4 + ;; + sun4os3) + basic_machine=sparc-sun + os=-sunos3 + ;; + sun4os4) + basic_machine=sparc-sun + os=-sunos4 + ;; + sun4sol2) + basic_machine=sparc-sun + os=-solaris2 + ;; + sun3 | sun3-*) + basic_machine=m68k-sun + ;; + sun4) + basic_machine=sparc-sun + ;; + sun386 | sun386i | roadrunner) + basic_machine=i386-sun + ;; + sv1) + basic_machine=sv1-cray + os=-unicos + ;; + symmetry) + basic_machine=i386-sequent + os=-dynix + ;; + t3e) + basic_machine=alphaev5-cray + os=-unicos + ;; + t90) + basic_machine=t90-cray + os=-unicos + ;; + tic54x | c54x*) + basic_machine=tic54x-unknown + os=-coff + ;; + tic55x | c55x*) + basic_machine=tic55x-unknown + os=-coff + ;; + tic6x | c6x*) + basic_machine=tic6x-unknown + os=-coff + ;; + tx39) + basic_machine=mipstx39-unknown + ;; + tx39el) + basic_machine=mipstx39el-unknown + ;; + toad1) + basic_machine=pdp10-xkl + os=-tops20 + ;; + tower | tower-32) + basic_machine=m68k-ncr + ;; + tpf) + basic_machine=s390x-ibm + os=-tpf + ;; + udi29k) + basic_machine=a29k-amd + os=-udi + ;; + ultra3) + basic_machine=a29k-nyu + os=-sym1 + ;; + v810 | necv810) + basic_machine=v810-nec + os=-none + ;; + vaxv) + basic_machine=vax-dec + os=-sysv + ;; + vms) + basic_machine=vax-dec + os=-vms + ;; + vpp*|vx|vx-*) + basic_machine=f301-fujitsu + ;; + vxworks960) + basic_machine=i960-wrs + os=-vxworks + ;; + vxworks68) + basic_machine=m68k-wrs + os=-vxworks + ;; + vxworks29k) + basic_machine=a29k-wrs + os=-vxworks + ;; + w65*) + basic_machine=w65-wdc + os=-none + ;; + w89k-*) + basic_machine=hppa1.1-winbond + os=-proelf + ;; + xbox) + basic_machine=i686-pc + os=-mingw32 + ;; + xps | xps100) + basic_machine=xps100-honeywell + ;; + ymp) + basic_machine=ymp-cray + os=-unicos + ;; + z8k-*-coff) + basic_machine=z8k-unknown + os=-sim + ;; + none) + basic_machine=none-none + os=-none + ;; + +# Here we handle the default manufacturer of certain CPU types. It is in +# some cases the only manufacturer, in others, it is the most popular. + w89k) + basic_machine=hppa1.1-winbond + ;; + op50n) + basic_machine=hppa1.1-oki + ;; + op60c) + basic_machine=hppa1.1-oki + ;; + romp) + basic_machine=romp-ibm + ;; + mmix) + basic_machine=mmix-knuth + ;; + rs6000) + basic_machine=rs6000-ibm + ;; + vax) + basic_machine=vax-dec + ;; + pdp10) + # there are many clones, so DEC is not a safe bet + basic_machine=pdp10-unknown + ;; + pdp11) + basic_machine=pdp11-dec + ;; + we32k) + basic_machine=we32k-att + ;; + sh[1234] | sh[24]a | sh[34]eb | sh[1234]le | sh[23]ele) + basic_machine=sh-unknown + ;; + sparc | sparcv8 | sparcv9 | sparcv9b | sparcv9v) + basic_machine=sparc-sun + ;; + cydra) + basic_machine=cydra-cydrome + ;; + orion) + basic_machine=orion-highlevel + ;; + orion105) + basic_machine=clipper-highlevel + ;; + mac | mpw | mac-mpw) + basic_machine=m68k-apple + ;; + pmac | pmac-mpw) + basic_machine=powerpc-apple + ;; + *-unknown) + # Make sure to match an already-canonicalized machine name. + ;; + *) + echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 + exit 1 + ;; +esac + +# Here we canonicalize certain aliases for manufacturers. +case $basic_machine in + *-digital*) + basic_machine=`echo $basic_machine | sed 's/digital.*/dec/'` + ;; + *-commodore*) + basic_machine=`echo $basic_machine | sed 's/commodore.*/cbm/'` + ;; + *) + ;; +esac + +# Decode manufacturer-specific aliases for certain operating systems. + +if [ x"$os" != x"" ] +then +case $os in + # First match some system type aliases + # that might get confused with valid system types. + # -solaris* is a basic system type, with this one exception. + -solaris1 | -solaris1.*) + os=`echo $os | sed -e 's|solaris1|sunos4|'` + ;; + -solaris) + os=-solaris2 + ;; + -svr4*) + os=-sysv4 + ;; + -unixware*) + os=-sysv4.2uw + ;; + -gnu/linux*) + os=`echo $os | sed -e 's|gnu/linux|linux-gnu|'` + ;; + # First accept the basic system types. + # The portable systems comes first. + # Each alternative MUST END IN A *, to match a version number. + # -sysv* is not here because it comes later, after sysvr4. + -gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \ + | -*vms* | -sco* | -esix* | -isc* | -aix* | -sunos | -sunos[34]*\ + | -hpux* | -unos* | -osf* | -luna* | -dgux* | -solaris* | -sym* \ + | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \ + | -aos* \ + | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \ + | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \ + | -hiux* | -386bsd* | -knetbsd* | -mirbsd* | -netbsd* \ + | -openbsd* | -solidbsd* \ + | -ekkobsd* | -kfreebsd* | -freebsd* | -riscix* | -lynxos* \ + | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \ + | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \ + | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \ + | -chorusos* | -chorusrdb* \ + | -cygwin* | -pe* | -psos* | -moss* | -proelf* | -rtems* \ + | -mingw32* | -linux-gnu* | -linux-newlib* | -linux-uclibc* \ + | -uxpv* | -beos* | -mpeix* | -udk* \ + | -interix* | -uwin* | -mks* | -rhapsody* | -darwin* | -opened* \ + | -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \ + | -storm-chaos* | -tops10* | -tenex* | -tops20* | -its* \ + | -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \ + | -morphos* | -superux* | -rtmk* | -rtmk-nova* | -windiss* \ + | -powermax* | -dnix* | -nx6 | -nx7 | -sei* | -dragonfly* \ + | -skyos* | -haiku* | -rdos*) + # Remember, each alternative MUST END IN *, to match a version number. + ;; + -qnx*) + case $basic_machine in + x86-* | i*86-*) + ;; + *) + os=-nto$os + ;; + esac + ;; + -nto-qnx*) + ;; + -nto*) + os=`echo $os | sed -e 's|nto|nto-qnx|'` + ;; + -sim | -es1800* | -hms* | -xray | -os68k* | -none* | -v88r* \ + | -windows* | -osx | -abug | -netware* | -os9* | -beos* | -haiku* \ + | -macos* | -mpw* | -magic* | -mmixware* | -mon960* | -lnews*) + ;; + -mac*) + os=`echo $os | sed -e 's|mac|macos|'` + ;; + -linux-dietlibc) + os=-linux-dietlibc + ;; + -linux*) + os=`echo $os | sed -e 's|linux|linux-gnu|'` + ;; + -sunos5*) + os=`echo $os | sed -e 's|sunos5|solaris2|'` + ;; + -sunos6*) + os=`echo $os | sed -e 's|sunos6|solaris3|'` + ;; + -opened*) + os=-openedition + ;; + -os400*) + os=-os400 + ;; + -wince*) + os=-wince + ;; + -osfrose*) + os=-osfrose + ;; + -osf*) + os=-osf + ;; + -utek*) + os=-bsd + ;; + -dynix*) + os=-bsd + ;; + -acis*) + os=-aos + ;; + -atheos*) + os=-atheos + ;; + -syllable*) + os=-syllable + ;; + -386bsd) + os=-bsd + ;; + -ctix* | -uts*) + os=-sysv + ;; + -nova*) + os=-rtmk-nova + ;; + -ns2 ) + os=-nextstep2 + ;; + -nsk*) + os=-nsk + ;; + # Preserve the version number of sinix5. + -sinix5.*) + os=`echo $os | sed -e 's|sinix|sysv|'` + ;; + -sinix*) + os=-sysv4 + ;; + -tpf*) + os=-tpf + ;; + -triton*) + os=-sysv3 + ;; + -oss*) + os=-sysv3 + ;; + -svr4) + os=-sysv4 + ;; + -svr3) + os=-sysv3 + ;; + -sysvr4) + os=-sysv4 + ;; + # This must come after -sysvr4. + -sysv*) + ;; + -ose*) + os=-ose + ;; + -es1800*) + os=-ose + ;; + -xenix) + os=-xenix + ;; + -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) + os=-mint + ;; + -aros*) + os=-aros + ;; + -kaos*) + os=-kaos + ;; + -zvmoe) + os=-zvmoe + ;; + -none) + ;; + *) + # Get rid of the `-' at the beginning of $os. + os=`echo $os | sed 's/[^-]*-//'` + echo Invalid configuration \`$1\': system \`$os\' not recognized 1>&2 + exit 1 + ;; +esac +else + +# Here we handle the default operating systems that come with various machines. +# The value should be what the vendor currently ships out the door with their +# machine or put another way, the most popular os provided with the machine. + +# Note that if you're going to try to match "-MANUFACTURER" here (say, +# "-sun"), then you have to tell the case statement up towards the top +# that MANUFACTURER isn't an operating system. Otherwise, code above +# will signal an error saying that MANUFACTURER isn't an operating +# system, and we'll never get to this point. + +case $basic_machine in + *-acorn) + os=-riscix1.2 + ;; + arm*-rebel) + os=-linux + ;; + arm*-semi) + os=-aout + ;; + c4x-* | tic4x-*) + os=-coff + ;; + # This must come before the *-dec entry. + pdp10-*) + os=-tops20 + ;; + pdp11-*) + os=-none + ;; + *-dec | vax-*) + os=-ultrix4.2 + ;; + m68*-apollo) + os=-domain + ;; + i386-sun) + os=-sunos4.0.2 + ;; + m68000-sun) + os=-sunos3 + # This also exists in the configure program, but was not the + # default. + # os=-sunos4 + ;; + m68*-cisco) + os=-aout + ;; + mips*-cisco) + os=-elf + ;; + mips*-*) + os=-elf + ;; + or32-*) + os=-coff + ;; + *-tti) # must be before sparc entry or we get the wrong os. + os=-sysv3 + ;; + sparc-* | *-sun) + os=-sunos4.1.1 + ;; + *-be) + os=-beos + ;; + *-haiku) + os=-haiku + ;; + *-ibm) + os=-aix + ;; + *-knuth) + os=-mmixware + ;; + *-wec) + os=-proelf + ;; + *-winbond) + os=-proelf + ;; + *-oki) + os=-proelf + ;; + *-hp) + os=-hpux + ;; + *-hitachi) + os=-hiux + ;; + i860-* | *-att | *-ncr | *-altos | *-motorola | *-convergent) + os=-sysv + ;; + *-cbm) + os=-amigaos + ;; + *-dg) + os=-dgux + ;; + *-dolphin) + os=-sysv3 + ;; + m68k-ccur) + os=-rtu + ;; + m88k-omron*) + os=-luna + ;; + *-next ) + os=-nextstep + ;; + *-sequent) + os=-ptx + ;; + *-crds) + os=-unos + ;; + *-ns) + os=-genix + ;; + i370-*) + os=-mvs + ;; + *-next) + os=-nextstep3 + ;; + *-gould) + os=-sysv + ;; + *-highlevel) + os=-bsd + ;; + *-encore) + os=-bsd + ;; + *-sgi) + os=-irix + ;; + *-siemens) + os=-sysv4 + ;; + *-masscomp) + os=-rtu + ;; + f30[01]-fujitsu | f700-fujitsu) + os=-uxpv + ;; + *-rom68k) + os=-coff + ;; + *-*bug) + os=-coff + ;; + *-apple) + os=-macos + ;; + *-atari*) + os=-mint + ;; + *) + os=-none + ;; +esac +fi + +# Here we handle the case where we know the os, and the CPU type, but not the +# manufacturer. We pick the logical manufacturer. +vendor=unknown +case $basic_machine in + *-unknown) + case $os in + -riscix*) + vendor=acorn + ;; + -sunos*) + vendor=sun + ;; + -aix*) + vendor=ibm + ;; + -beos*) + vendor=be + ;; + -hpux*) + vendor=hp + ;; + -mpeix*) + vendor=hp + ;; + -hiux*) + vendor=hitachi + ;; + -unos*) + vendor=crds + ;; + -dgux*) + vendor=dg + ;; + -luna*) + vendor=omron + ;; + -genix*) + vendor=ns + ;; + -mvs* | -opened*) + vendor=ibm + ;; + -os400*) + vendor=ibm + ;; + -ptx*) + vendor=sequent + ;; + -tpf*) + vendor=ibm + ;; + -vxsim* | -vxworks* | -windiss*) + vendor=wrs + ;; + -aux*) + vendor=apple + ;; + -hms*) + vendor=hitachi + ;; + -mpw* | -macos*) + vendor=apple + ;; + -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) + vendor=atari + ;; + -vos*) + vendor=stratus + ;; + esac + basic_machine=`echo $basic_machine | sed "s/unknown/$vendor/"` + ;; +esac + +echo $basic_machine$os +exit + +# Local variables: +# eval: (add-hook 'write-file-hooks 'time-stamp) +# time-stamp-start: "timestamp='" +# time-stamp-format: "%:y-%02m-%02d" +# time-stamp-end: "'" +# End: diff --git a/xpa/configure b/xpa/configure new file mode 100755 index 0000000..f6c832d --- /dev/null +++ b/xpa/configure @@ -0,0 +1,9061 @@ +#! /bin/sh +# Guess values for system-dependent variables and create Makefiles. +# Generated by GNU Autoconf 2.59 for xpa 2.1.18. +# +# Report bugs to <eric@cfa.harvard.edu>. +# +# Copyright (C) 2003 Free Software Foundation, Inc. +# This configure script is free software; the Free Software Foundation +# gives unlimited permission to copy, distribute and modify it. +## --------------------- ## +## M4sh Initialization. ## +## --------------------- ## + +# Be Bourne compatible +if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then + emulate sh + NULLCMD=: + # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which + # is contrary to our usage. Disable this feature. + alias -g '${1+"$@"}'='"$@"' +elif test -n "${BASH_VERSION+set}" && (set -o posix) >/dev/null 2>&1; then + set -o posix +fi +DUALCASE=1; export DUALCASE # for MKS sh + +# Support unset when possible. +if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then + as_unset=unset +else + as_unset=false +fi + + +# Work around bugs in pre-3.0 UWIN ksh. +$as_unset ENV MAIL MAILPATH +PS1='$ ' +PS2='> ' +PS4='+ ' + +# NLS nuisances. +for as_var in \ + LANG LANGUAGE LC_ADDRESS LC_ALL LC_COLLATE LC_CTYPE LC_IDENTIFICATION \ + LC_MEASUREMENT LC_MESSAGES LC_MONETARY LC_NAME LC_NUMERIC LC_PAPER \ + LC_TELEPHONE LC_TIME +do + if (set +x; test -z "`(eval $as_var=C; export $as_var) 2>&1`"); then + eval $as_var=C; export $as_var + else + $as_unset $as_var + fi +done + +# Required to use basename. +if expr a : '\(a\)' >/dev/null 2>&1; then + as_expr=expr +else + as_expr=false +fi + +if (basename /) >/dev/null 2>&1 && test "X`basename / 2>&1`" = "X/"; then + as_basename=basename +else + as_basename=false +fi + + +# Name of the executable. +as_me=`$as_basename "$0" || +$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ + X"$0" : 'X\(//\)$' \| \ + X"$0" : 'X\(/\)$' \| \ + . : '\(.\)' 2>/dev/null || +echo X/"$0" | + sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/; q; } + /^X\/\(\/\/\)$/{ s//\1/; q; } + /^X\/\(\/\).*/{ s//\1/; q; } + s/.*/./; q'` + + +# PATH needs CR, and LINENO needs CR and PATH. +# Avoid depending upon Character Ranges. +as_cr_letters='abcdefghijklmnopqrstuvwxyz' +as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' +as_cr_Letters=$as_cr_letters$as_cr_LETTERS +as_cr_digits='0123456789' +as_cr_alnum=$as_cr_Letters$as_cr_digits + +# The user is always right. +if test "${PATH_SEPARATOR+set}" != set; then + echo "#! /bin/sh" >conf$$.sh + echo "exit 0" >>conf$$.sh + chmod +x conf$$.sh + if (PATH="/nonexistent;."; conf$$.sh) >/dev/null 2>&1; then + PATH_SEPARATOR=';' + else + PATH_SEPARATOR=: + fi + rm -f conf$$.sh +fi + + + as_lineno_1=$LINENO + as_lineno_2=$LINENO + as_lineno_3=`(expr $as_lineno_1 + 1) 2>/dev/null` + test "x$as_lineno_1" != "x$as_lineno_2" && + test "x$as_lineno_3" = "x$as_lineno_2" || { + # Find who we are. Look in the path if we contain no path at all + # relative or not. + case $0 in + *[\\/]* ) as_myself=$0 ;; + *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break +done + + ;; + esac + # We did not find ourselves, most probably we were run as `sh COMMAND' + # in which case we are not to be found in the path. + if test "x$as_myself" = x; then + as_myself=$0 + fi + if test ! -f "$as_myself"; then + { echo "$as_me: error: cannot find myself; rerun with an absolute path" >&2 + { (exit 1); exit 1; }; } + fi + case $CONFIG_SHELL in + '') + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for as_base in sh bash ksh sh5; do + case $as_dir in + /*) + if ("$as_dir/$as_base" -c ' + as_lineno_1=$LINENO + as_lineno_2=$LINENO + as_lineno_3=`(expr $as_lineno_1 + 1) 2>/dev/null` + test "x$as_lineno_1" != "x$as_lineno_2" && + test "x$as_lineno_3" = "x$as_lineno_2" ') 2>/dev/null; then + $as_unset BASH_ENV || test "${BASH_ENV+set}" != set || { BASH_ENV=; export BASH_ENV; } + $as_unset ENV || test "${ENV+set}" != set || { ENV=; export ENV; } + CONFIG_SHELL=$as_dir/$as_base + export CONFIG_SHELL + exec "$CONFIG_SHELL" "$0" ${1+"$@"} + fi;; + esac + done +done +;; + esac + + # Create $as_me.lineno as a copy of $as_myself, but with $LINENO + # uniformly replaced by the line number. The first 'sed' inserts a + # line-number line before each line; the second 'sed' does the real + # work. The second script uses 'N' to pair each line-number line + # with the numbered line, and appends trailing '-' during + # substitution so that $LINENO is not a special case at line end. + # (Raja R Harinath suggested sed '=', and Paul Eggert wrote the + # second 'sed' script. Blame Lee E. McMahon for sed's syntax. :-) + sed '=' <$as_myself | + sed ' + N + s,$,-, + : loop + s,^\(['$as_cr_digits']*\)\(.*\)[$]LINENO\([^'$as_cr_alnum'_]\),\1\2\1\3, + t loop + s,-$,, + s,^['$as_cr_digits']*\n,, + ' >$as_me.lineno && + chmod +x $as_me.lineno || + { echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2 + { (exit 1); exit 1; }; } + + # Don't try to exec as it changes $[0], causing all sort of problems + # (the dirname of $[0] is not the place where we might find the + # original and so on. Autoconf is especially sensible to this). + . ./$as_me.lineno + # Exit status is that of the last command. + exit +} + + +case `echo "testing\c"; echo 1,2,3`,`echo -n testing; echo 1,2,3` in + *c*,-n*) ECHO_N= ECHO_C=' +' ECHO_T=' ' ;; + *c*,* ) ECHO_N=-n ECHO_C= ECHO_T= ;; + *) ECHO_N= ECHO_C='\c' ECHO_T= ;; +esac + +if expr a : '\(a\)' >/dev/null 2>&1; then + as_expr=expr +else + as_expr=false +fi + +rm -f conf$$ conf$$.exe conf$$.file +echo >conf$$.file +if ln -s conf$$.file conf$$ 2>/dev/null; then + # We could just check for DJGPP; but this test a) works b) is more generic + # and c) will remain valid once DJGPP supports symlinks (DJGPP 2.04). + if test -f conf$$.exe; then + # Don't use ln at all; we don't have any links + as_ln_s='cp -p' + else + as_ln_s='ln -s' + fi +elif ln conf$$.file conf$$ 2>/dev/null; then + as_ln_s=ln +else + as_ln_s='cp -p' +fi +rm -f conf$$ conf$$.exe conf$$.file + +if mkdir -p . 2>/dev/null; then + as_mkdir_p=: +else + test -d ./-p && rmdir ./-p + as_mkdir_p=false +fi + +as_executable_p="test -f" + +# Sed expression to map a string onto a valid CPP name. +as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" + +# Sed expression to map a string onto a valid variable name. +as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" + + +# IFS +# We need space, tab and new line, in precisely that order. +as_nl=' +' +IFS=" $as_nl" + +# CDPATH. +$as_unset CDPATH + + +# Name of the host. +# hostname on some systems (SVR3.2, Linux) returns a bogus exit status, +# so uname gets run too. +ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q` + +exec 6>&1 + +# +# Initializations. +# +ac_default_prefix=/usr/local +ac_config_libobj_dir=. +cross_compiling=no +subdirs= +MFLAGS= +MAKEFLAGS= +SHELL=${CONFIG_SHELL-/bin/sh} + +# Maximum number of lines to put in a shell here document. +# This variable seems obsolete. It should probably be removed, and +# only ac_max_sed_lines should be used. +: ${ac_max_here_lines=38} + +# Identity of this package. +PACKAGE_NAME='xpa' +PACKAGE_TARNAME='xpa' +PACKAGE_VERSION='2.1.18' +PACKAGE_STRING='xpa 2.1.18' +PACKAGE_BUGREPORT='eric@cfa.harvard.edu' + +ac_unique_file="./xpa.h" +# Factoring default headers for most tests. +ac_includes_default="\ +#include <stdio.h> +#if HAVE_SYS_TYPES_H +# include <sys/types.h> +#endif +#if HAVE_SYS_STAT_H +# include <sys/stat.h> +#endif +#if STDC_HEADERS +# include <stdlib.h> +# include <stddef.h> +#else +# if HAVE_STDLIB_H +# include <stdlib.h> +# endif +#endif +#if HAVE_STRING_H +# if !STDC_HEADERS && HAVE_MEMORY_H +# include <memory.h> +# endif +# include <string.h> +#endif +#if HAVE_STRINGS_H +# include <strings.h> +#endif +#if HAVE_INTTYPES_H +# include <inttypes.h> +#else +# if HAVE_STDINT_H +# include <stdint.h> +# endif +#endif +#if HAVE_UNISTD_H +# include <unistd.h> +#endif" + +ac_subst_vars='SHELL PATH_SEPARATOR PACKAGE_NAME PACKAGE_TARNAME PACKAGE_VERSION PACKAGE_STRING PACKAGE_BUGREPORT exec_prefix prefix program_transform_name bindir sbindir libexecdir datadir sysconfdir sharedstatedir localstatedir libdir includedir oldincludedir infodir mandir build_alias host_alias target_alias DEFS ECHO_C ECHO_N ECHO_T LIBS build build_cpu build_vendor build_os host host_cpu host_vendor host_os CC CFLAGS LDFLAGS CPPFLAGS ac_ct_CC EXEEXT OBJEXT CPP EGREP SZ_LONG RANLIB ac_ct_RANLIB TLIB DOSHARED LLIB X_CFLAGS X_PRE_LIBS X_LIBS X_EXTRA_LIBS TCL_VERSION TCL_BIN_DIR TCL_SRC_DIR TCL_LIB_FILE TCL_LIB_FLAG TCL_LIB_SPEC TCL_STUB_LIB_FILE TCL_STUB_LIB_FLAG TCL_STUB_LIB_SPEC TCL_CFLAGS TCL_LIBS GTK_CFLAGS GTK_LIBS EXTRA_LIBS LIBOBJS LTLIBOBJS' +ac_subst_files='' + +# Initialize some variables set by options. +ac_init_help= +ac_init_version=false +# The variables have the same names as the options, with +# dashes changed to underlines. +cache_file=/dev/null +exec_prefix=NONE +no_create= +no_recursion= +prefix=NONE +program_prefix=NONE +program_suffix=NONE +program_transform_name=s,x,x, +silent= +site= +srcdir= +verbose= +x_includes=NONE +x_libraries=NONE + +# Installation directory options. +# These are left unexpanded so users can "make install exec_prefix=/foo" +# and all the variables that are supposed to be based on exec_prefix +# by default will actually change. +# Use braces instead of parens because sh, perl, etc. also accept them. +bindir='${exec_prefix}/bin' +sbindir='${exec_prefix}/sbin' +libexecdir='${exec_prefix}/libexec' +datadir='${prefix}/share' +sysconfdir='${prefix}/etc' +sharedstatedir='${prefix}/com' +localstatedir='${prefix}/var' +libdir='${exec_prefix}/lib' +includedir='${prefix}/include' +oldincludedir='/usr/include' +infodir='${prefix}/info' +mandir='${prefix}/man' + +ac_prev= +for ac_option +do + # If the previous option needs an argument, assign it. + if test -n "$ac_prev"; then + eval "$ac_prev=\$ac_option" + ac_prev= + continue + fi + + ac_optarg=`expr "x$ac_option" : 'x[^=]*=\(.*\)'` + + # Accept the important Cygnus configure options, so we can diagnose typos. + + case $ac_option in + + -bindir | --bindir | --bindi | --bind | --bin | --bi) + ac_prev=bindir ;; + -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*) + bindir=$ac_optarg ;; + + -build | --build | --buil | --bui | --bu) + ac_prev=build_alias ;; + -build=* | --build=* | --buil=* | --bui=* | --bu=*) + build_alias=$ac_optarg ;; + + -cache-file | --cache-file | --cache-fil | --cache-fi \ + | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c) + ac_prev=cache_file ;; + -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \ + | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*) + cache_file=$ac_optarg ;; + + --config-cache | -C) + cache_file=config.cache ;; + + -datadir | --datadir | --datadi | --datad | --data | --dat | --da) + ac_prev=datadir ;; + -datadir=* | --datadir=* | --datadi=* | --datad=* | --data=* | --dat=* \ + | --da=*) + datadir=$ac_optarg ;; + + -disable-* | --disable-*) + ac_feature=`expr "x$ac_option" : 'x-*disable-\(.*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_feature" : ".*[^-_$as_cr_alnum]" >/dev/null && + { echo "$as_me: error: invalid feature name: $ac_feature" >&2 + { (exit 1); exit 1; }; } + ac_feature=`echo $ac_feature | sed 's/-/_/g'` + eval "enable_$ac_feature=no" ;; + + -enable-* | --enable-*) + ac_feature=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_feature" : ".*[^-_$as_cr_alnum]" >/dev/null && + { echo "$as_me: error: invalid feature name: $ac_feature" >&2 + { (exit 1); exit 1; }; } + ac_feature=`echo $ac_feature | sed 's/-/_/g'` + case $ac_option in + *=*) ac_optarg=`echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"`;; + *) ac_optarg=yes ;; + esac + eval "enable_$ac_feature='$ac_optarg'" ;; + + -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \ + | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \ + | --exec | --exe | --ex) + ac_prev=exec_prefix ;; + -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \ + | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \ + | --exec=* | --exe=* | --ex=*) + exec_prefix=$ac_optarg ;; + + -gas | --gas | --ga | --g) + # Obsolete; use --with-gas. + with_gas=yes ;; + + -help | --help | --hel | --he | -h) + ac_init_help=long ;; + -help=r* | --help=r* | --hel=r* | --he=r* | -hr*) + ac_init_help=recursive ;; + -help=s* | --help=s* | --hel=s* | --he=s* | -hs*) + ac_init_help=short ;; + + -host | --host | --hos | --ho) + ac_prev=host_alias ;; + -host=* | --host=* | --hos=* | --ho=*) + host_alias=$ac_optarg ;; + + -includedir | --includedir | --includedi | --included | --include \ + | --includ | --inclu | --incl | --inc) + ac_prev=includedir ;; + -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \ + | --includ=* | --inclu=* | --incl=* | --inc=*) + includedir=$ac_optarg ;; + + -infodir | --infodir | --infodi | --infod | --info | --inf) + ac_prev=infodir ;; + -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*) + infodir=$ac_optarg ;; + + -libdir | --libdir | --libdi | --libd) + ac_prev=libdir ;; + -libdir=* | --libdir=* | --libdi=* | --libd=*) + libdir=$ac_optarg ;; + + -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \ + | --libexe | --libex | --libe) + ac_prev=libexecdir ;; + -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \ + | --libexe=* | --libex=* | --libe=*) + libexecdir=$ac_optarg ;; + + -localstatedir | --localstatedir | --localstatedi | --localstated \ + | --localstate | --localstat | --localsta | --localst \ + | --locals | --local | --loca | --loc | --lo) + ac_prev=localstatedir ;; + -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \ + | --localstate=* | --localstat=* | --localsta=* | --localst=* \ + | --locals=* | --local=* | --loca=* | --loc=* | --lo=*) + localstatedir=$ac_optarg ;; + + -mandir | --mandir | --mandi | --mand | --man | --ma | --m) + ac_prev=mandir ;; + -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*) + mandir=$ac_optarg ;; + + -nfp | --nfp | --nf) + # Obsolete; use --without-fp. + with_fp=no ;; + + -no-create | --no-create | --no-creat | --no-crea | --no-cre \ + | --no-cr | --no-c | -n) + no_create=yes ;; + + -no-recursion | --no-recursion | --no-recursio | --no-recursi \ + | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) + no_recursion=yes ;; + + -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \ + | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \ + | --oldin | --oldi | --old | --ol | --o) + ac_prev=oldincludedir ;; + -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \ + | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \ + | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*) + oldincludedir=$ac_optarg ;; + + -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) + ac_prev=prefix ;; + -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*) + prefix=$ac_optarg ;; + + -program-prefix | --program-prefix | --program-prefi | --program-pref \ + | --program-pre | --program-pr | --program-p) + ac_prev=program_prefix ;; + -program-prefix=* | --program-prefix=* | --program-prefi=* \ + | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*) + program_prefix=$ac_optarg ;; + + -program-suffix | --program-suffix | --program-suffi | --program-suff \ + | --program-suf | --program-su | --program-s) + ac_prev=program_suffix ;; + -program-suffix=* | --program-suffix=* | --program-suffi=* \ + | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*) + program_suffix=$ac_optarg ;; + + -program-transform-name | --program-transform-name \ + | --program-transform-nam | --program-transform-na \ + | --program-transform-n | --program-transform- \ + | --program-transform | --program-transfor \ + | --program-transfo | --program-transf \ + | --program-trans | --program-tran \ + | --progr-tra | --program-tr | --program-t) + ac_prev=program_transform_name ;; + -program-transform-name=* | --program-transform-name=* \ + | --program-transform-nam=* | --program-transform-na=* \ + | --program-transform-n=* | --program-transform-=* \ + | --program-transform=* | --program-transfor=* \ + | --program-transfo=* | --program-transf=* \ + | --program-trans=* | --program-tran=* \ + | --progr-tra=* | --program-tr=* | --program-t=*) + program_transform_name=$ac_optarg ;; + + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil) + silent=yes ;; + + -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) + ac_prev=sbindir ;; + -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ + | --sbi=* | --sb=*) + sbindir=$ac_optarg ;; + + -sharedstatedir | --sharedstatedir | --sharedstatedi \ + | --sharedstated | --sharedstate | --sharedstat | --sharedsta \ + | --sharedst | --shareds | --shared | --share | --shar \ + | --sha | --sh) + ac_prev=sharedstatedir ;; + -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \ + | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \ + | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \ + | --sha=* | --sh=*) + sharedstatedir=$ac_optarg ;; + + -site | --site | --sit) + ac_prev=site ;; + -site=* | --site=* | --sit=*) + site=$ac_optarg ;; + + -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) + ac_prev=srcdir ;; + -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) + srcdir=$ac_optarg ;; + + -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \ + | --syscon | --sysco | --sysc | --sys | --sy) + ac_prev=sysconfdir ;; + -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \ + | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*) + sysconfdir=$ac_optarg ;; + + -target | --target | --targe | --targ | --tar | --ta | --t) + ac_prev=target_alias ;; + -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*) + target_alias=$ac_optarg ;; + + -v | -verbose | --verbose | --verbos | --verbo | --verb) + verbose=yes ;; + + -version | --version | --versio | --versi | --vers | -V) + ac_init_version=: ;; + + -with-* | --with-*) + ac_package=`expr "x$ac_option" : 'x-*with-\([^=]*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_package" : ".*[^-_$as_cr_alnum]" >/dev/null && + { echo "$as_me: error: invalid package name: $ac_package" >&2 + { (exit 1); exit 1; }; } + ac_package=`echo $ac_package| sed 's/-/_/g'` + case $ac_option in + *=*) ac_optarg=`echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"`;; + *) ac_optarg=yes ;; + esac + eval "with_$ac_package='$ac_optarg'" ;; + + -without-* | --without-*) + ac_package=`expr "x$ac_option" : 'x-*without-\(.*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_package" : ".*[^-_$as_cr_alnum]" >/dev/null && + { echo "$as_me: error: invalid package name: $ac_package" >&2 + { (exit 1); exit 1; }; } + ac_package=`echo $ac_package | sed 's/-/_/g'` + eval "with_$ac_package=no" ;; + + --x) + # Obsolete; use --with-x. + with_x=yes ;; + + -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \ + | --x-incl | --x-inc | --x-in | --x-i) + ac_prev=x_includes ;; + -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \ + | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*) + x_includes=$ac_optarg ;; + + -x-libraries | --x-libraries | --x-librarie | --x-librari \ + | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l) + ac_prev=x_libraries ;; + -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \ + | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*) + x_libraries=$ac_optarg ;; + + -*) { echo "$as_me: error: unrecognized option: $ac_option +Try \`$0 --help' for more information." >&2 + { (exit 1); exit 1; }; } + ;; + + *=*) + ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='` + # Reject names that are not valid shell variable names. + expr "x$ac_envvar" : ".*[^_$as_cr_alnum]" >/dev/null && + { echo "$as_me: error: invalid variable name: $ac_envvar" >&2 + { (exit 1); exit 1; }; } + ac_optarg=`echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` + eval "$ac_envvar='$ac_optarg'" + export $ac_envvar ;; + + *) + # FIXME: should be removed in autoconf 3.0. + echo "$as_me: WARNING: you should use --build, --host, --target" >&2 + expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null && + echo "$as_me: WARNING: invalid host type: $ac_option" >&2 + : ${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option} + ;; + + esac +done + +if test -n "$ac_prev"; then + ac_option=--`echo $ac_prev | sed 's/_/-/g'` + { echo "$as_me: error: missing argument to $ac_option" >&2 + { (exit 1); exit 1; }; } +fi + +# Be sure to have absolute paths. +for ac_var in exec_prefix prefix +do + eval ac_val=$`echo $ac_var` + case $ac_val in + [\\/$]* | ?:[\\/]* | NONE | '' ) ;; + *) { echo "$as_me: error: expected an absolute directory name for --$ac_var: $ac_val" >&2 + { (exit 1); exit 1; }; };; + esac +done + +# Be sure to have absolute paths. +for ac_var in bindir sbindir libexecdir datadir sysconfdir sharedstatedir \ + localstatedir libdir includedir oldincludedir infodir mandir +do + eval ac_val=$`echo $ac_var` + case $ac_val in + [\\/$]* | ?:[\\/]* ) ;; + *) { echo "$as_me: error: expected an absolute directory name for --$ac_var: $ac_val" >&2 + { (exit 1); exit 1; }; };; + esac +done + +# There might be people who depend on the old broken behavior: `$host' +# used to hold the argument of --host etc. +# FIXME: To remove some day. +build=$build_alias +host=$host_alias +target=$target_alias + +# FIXME: To remove some day. +if test "x$host_alias" != x; then + if test "x$build_alias" = x; then + cross_compiling=maybe + echo "$as_me: WARNING: If you wanted to set the --build type, don't use --host. + If a cross compiler is detected then cross compile mode will be used." >&2 + elif test "x$build_alias" != "x$host_alias"; then + cross_compiling=yes + fi +fi + +ac_tool_prefix= +test -n "$host_alias" && ac_tool_prefix=$host_alias- + +test "$silent" = yes && exec 6>/dev/null + + +# Find the source files, if location was not specified. +if test -z "$srcdir"; then + ac_srcdir_defaulted=yes + # Try the directory containing this script, then its parent. + ac_confdir=`(dirname "$0") 2>/dev/null || +$as_expr X"$0" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$0" : 'X\(//\)[^/]' \| \ + X"$0" : 'X\(//\)$' \| \ + X"$0" : 'X\(/\)' \| \ + . : '\(.\)' 2>/dev/null || +echo X"$0" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; } + /^X\(\/\/\)[^/].*/{ s//\1/; q; } + /^X\(\/\/\)$/{ s//\1/; q; } + /^X\(\/\).*/{ s//\1/; q; } + s/.*/./; q'` + srcdir=$ac_confdir + if test ! -r $srcdir/$ac_unique_file; then + srcdir=.. + fi +else + ac_srcdir_defaulted=no +fi +if test ! -r $srcdir/$ac_unique_file; then + if test "$ac_srcdir_defaulted" = yes; then + { echo "$as_me: error: cannot find sources ($ac_unique_file) in $ac_confdir or .." >&2 + { (exit 1); exit 1; }; } + else + { echo "$as_me: error: cannot find sources ($ac_unique_file) in $srcdir" >&2 + { (exit 1); exit 1; }; } + fi +fi +(cd $srcdir && test -r ./$ac_unique_file) 2>/dev/null || + { echo "$as_me: error: sources are in $srcdir, but \`cd $srcdir' does not work" >&2 + { (exit 1); exit 1; }; } +srcdir=`echo "$srcdir" | sed 's%\([^\\/]\)[\\/]*$%\1%'` +ac_env_build_alias_set=${build_alias+set} +ac_env_build_alias_value=$build_alias +ac_cv_env_build_alias_set=${build_alias+set} +ac_cv_env_build_alias_value=$build_alias +ac_env_host_alias_set=${host_alias+set} +ac_env_host_alias_value=$host_alias +ac_cv_env_host_alias_set=${host_alias+set} +ac_cv_env_host_alias_value=$host_alias +ac_env_target_alias_set=${target_alias+set} +ac_env_target_alias_value=$target_alias +ac_cv_env_target_alias_set=${target_alias+set} +ac_cv_env_target_alias_value=$target_alias +ac_env_CC_set=${CC+set} +ac_env_CC_value=$CC +ac_cv_env_CC_set=${CC+set} +ac_cv_env_CC_value=$CC +ac_env_CFLAGS_set=${CFLAGS+set} +ac_env_CFLAGS_value=$CFLAGS +ac_cv_env_CFLAGS_set=${CFLAGS+set} +ac_cv_env_CFLAGS_value=$CFLAGS +ac_env_LDFLAGS_set=${LDFLAGS+set} +ac_env_LDFLAGS_value=$LDFLAGS +ac_cv_env_LDFLAGS_set=${LDFLAGS+set} +ac_cv_env_LDFLAGS_value=$LDFLAGS +ac_env_CPPFLAGS_set=${CPPFLAGS+set} +ac_env_CPPFLAGS_value=$CPPFLAGS +ac_cv_env_CPPFLAGS_set=${CPPFLAGS+set} +ac_cv_env_CPPFLAGS_value=$CPPFLAGS +ac_env_CPP_set=${CPP+set} +ac_env_CPP_value=$CPP +ac_cv_env_CPP_set=${CPP+set} +ac_cv_env_CPP_value=$CPP + +# +# Report the --help message. +# +if test "$ac_init_help" = "long"; then + # Omit some internal or obsolete options to make the list less imposing. + # This message is too long to be a string in the A/UX 3.1 sh. + cat <<_ACEOF +\`configure' configures xpa 2.1.18 to adapt to many kinds of systems. + +Usage: $0 [OPTION]... [VAR=VALUE]... + +To assign environment variables (e.g., CC, CFLAGS...), specify them as +VAR=VALUE. See below for descriptions of some of the useful variables. + +Defaults for the options are specified in brackets. + +Configuration: + -h, --help display this help and exit + --help=short display options specific to this package + --help=recursive display the short help of all the included packages + -V, --version display version information and exit + -q, --quiet, --silent do not print \`checking...' messages + --cache-file=FILE cache test results in FILE [disabled] + -C, --config-cache alias for \`--cache-file=config.cache' + -n, --no-create do not create output files + --srcdir=DIR find the sources in DIR [configure dir or \`..'] + +_ACEOF + + cat <<_ACEOF +Installation directories: + --prefix=PREFIX install architecture-independent files in PREFIX + [$ac_default_prefix] + --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX + [PREFIX] + +By default, \`make install' will install all the files in +\`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify +an installation prefix other than \`$ac_default_prefix' using \`--prefix', +for instance \`--prefix=\$HOME'. + +For better control, use the options below. + +Fine tuning of the installation directories: + --bindir=DIR user executables [EPREFIX/bin] + --sbindir=DIR system admin executables [EPREFIX/sbin] + --libexecdir=DIR program executables [EPREFIX/libexec] + --datadir=DIR read-only architecture-independent data [PREFIX/share] + --sysconfdir=DIR read-only single-machine data [PREFIX/etc] + --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com] + --localstatedir=DIR modifiable single-machine data [PREFIX/var] + --libdir=DIR object code libraries [EPREFIX/lib] + --includedir=DIR C header files [PREFIX/include] + --oldincludedir=DIR C header files for non-gcc [/usr/include] + --infodir=DIR info documentation [PREFIX/info] + --mandir=DIR man documentation [PREFIX/man] +_ACEOF + + cat <<\_ACEOF + +X features: + --x-includes=DIR X include files are in DIR + --x-libraries=DIR X library files are in DIR + +System types: + --build=BUILD configure for building on BUILD [guessed] + --host=HOST cross-compile to build programs to run on HOST [BUILD] +_ACEOF +fi + +if test -n "$ac_init_help"; then + case $ac_init_help in + short | recursive ) echo "Configuration of xpa 2.1.18:";; + esac + cat <<\_ACEOF + +Optional Features: + --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no) + --enable-FEATURE[=ARG] include FEATURE [ARG=yes] + --enable-threaded-xpans build threaded xpans + --enable-shared build shared libraries + --enable-posix_spawn use posix_spawn() if available + +Optional Packages: + --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] + --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no) + --with-x use the X Window System + --with-tcl directory containing tcl configuration (tclConfig.sh) + --with-threads build for use in threaded programs + --with-gtk=<path> include directory for gtk e.g. /usr/include/gtk-1.2 + +Some influential environment variables: + CC C compiler command + CFLAGS C compiler flags + LDFLAGS linker flags, e.g. -L<lib dir> if you have libraries in a + nonstandard directory <lib dir> + CPPFLAGS C/C++ preprocessor flags, e.g. -I<include dir> if you have + headers in a nonstandard directory <include dir> + CPP C preprocessor + +Use these variables to override the choices made by `configure' or to help +it to find libraries and programs with nonstandard names/locations. + +Report bugs to <eric@cfa.harvard.edu>. +_ACEOF +fi + +if test "$ac_init_help" = "recursive"; then + # If there are subdirs, report their specific --help. + ac_popdir=`pwd` + for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue + test -d $ac_dir || continue + ac_builddir=. + +if test "$ac_dir" != .; then + ac_dir_suffix=/`echo "$ac_dir" | sed 's,^\.[\\/],,'` + # A "../" for each directory in $ac_dir_suffix. + ac_top_builddir=`echo "$ac_dir_suffix" | sed 's,/[^\\/]*,../,g'` +else + ac_dir_suffix= ac_top_builddir= +fi + +case $srcdir in + .) # No --srcdir option. We are building in place. + ac_srcdir=. + if test -z "$ac_top_builddir"; then + ac_top_srcdir=. + else + ac_top_srcdir=`echo $ac_top_builddir | sed 's,/$,,'` + fi ;; + [\\/]* | ?:[\\/]* ) # Absolute path. + ac_srcdir=$srcdir$ac_dir_suffix; + ac_top_srcdir=$srcdir ;; + *) # Relative path. + ac_srcdir=$ac_top_builddir$srcdir$ac_dir_suffix + ac_top_srcdir=$ac_top_builddir$srcdir ;; +esac + +# Do not use `cd foo && pwd` to compute absolute paths, because +# the directories may not exist. +case `pwd` in +.) ac_abs_builddir="$ac_dir";; +*) + case "$ac_dir" in + .) ac_abs_builddir=`pwd`;; + [\\/]* | ?:[\\/]* ) ac_abs_builddir="$ac_dir";; + *) ac_abs_builddir=`pwd`/"$ac_dir";; + esac;; +esac +case $ac_abs_builddir in +.) ac_abs_top_builddir=${ac_top_builddir}.;; +*) + case ${ac_top_builddir}. in + .) ac_abs_top_builddir=$ac_abs_builddir;; + [\\/]* | ?:[\\/]* ) ac_abs_top_builddir=${ac_top_builddir}.;; + *) ac_abs_top_builddir=$ac_abs_builddir/${ac_top_builddir}.;; + esac;; +esac +case $ac_abs_builddir in +.) ac_abs_srcdir=$ac_srcdir;; +*) + case $ac_srcdir in + .) ac_abs_srcdir=$ac_abs_builddir;; + [\\/]* | ?:[\\/]* ) ac_abs_srcdir=$ac_srcdir;; + *) ac_abs_srcdir=$ac_abs_builddir/$ac_srcdir;; + esac;; +esac +case $ac_abs_builddir in +.) ac_abs_top_srcdir=$ac_top_srcdir;; +*) + case $ac_top_srcdir in + .) ac_abs_top_srcdir=$ac_abs_builddir;; + [\\/]* | ?:[\\/]* ) ac_abs_top_srcdir=$ac_top_srcdir;; + *) ac_abs_top_srcdir=$ac_abs_builddir/$ac_top_srcdir;; + esac;; +esac + + cd $ac_dir + # Check for guested configure; otherwise get Cygnus style configure. + if test -f $ac_srcdir/configure.gnu; then + echo + $SHELL $ac_srcdir/configure.gnu --help=recursive + elif test -f $ac_srcdir/configure; then + echo + $SHELL $ac_srcdir/configure --help=recursive + elif test -f $ac_srcdir/configure.ac || + test -f $ac_srcdir/configure.in; then + echo + $ac_configure --help + else + echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2 + fi + cd $ac_popdir + done +fi + +test -n "$ac_init_help" && exit 0 +if $ac_init_version; then + cat <<\_ACEOF +xpa configure 2.1.18 +generated by GNU Autoconf 2.59 + +Copyright (C) 2003 Free Software Foundation, Inc. +This configure script is free software; the Free Software Foundation +gives unlimited permission to copy, distribute and modify it. +_ACEOF + exit 0 +fi +exec 5>config.log +cat >&5 <<_ACEOF +This file contains any messages produced by compilers while +running configure, to aid debugging if configure makes a mistake. + +It was created by xpa $as_me 2.1.18, which was +generated by GNU Autoconf 2.59. Invocation command line was + + $ $0 $@ + +_ACEOF +{ +cat <<_ASUNAME +## --------- ## +## Platform. ## +## --------- ## + +hostname = `(hostname || uname -n) 2>/dev/null | sed 1q` +uname -m = `(uname -m) 2>/dev/null || echo unknown` +uname -r = `(uname -r) 2>/dev/null || echo unknown` +uname -s = `(uname -s) 2>/dev/null || echo unknown` +uname -v = `(uname -v) 2>/dev/null || echo unknown` + +/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown` +/bin/uname -X = `(/bin/uname -X) 2>/dev/null || echo unknown` + +/bin/arch = `(/bin/arch) 2>/dev/null || echo unknown` +/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null || echo unknown` +/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown` +hostinfo = `(hostinfo) 2>/dev/null || echo unknown` +/bin/machine = `(/bin/machine) 2>/dev/null || echo unknown` +/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null || echo unknown` +/bin/universe = `(/bin/universe) 2>/dev/null || echo unknown` + +_ASUNAME + +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + echo "PATH: $as_dir" +done + +} >&5 + +cat >&5 <<_ACEOF + + +## ----------- ## +## Core tests. ## +## ----------- ## + +_ACEOF + + +# Keep a trace of the command line. +# Strip out --no-create and --no-recursion so they do not pile up. +# Strip out --silent because we don't want to record it for future runs. +# Also quote any args containing shell meta-characters. +# Make two passes to allow for proper duplicate-argument suppression. +ac_configure_args= +ac_configure_args0= +ac_configure_args1= +ac_sep= +ac_must_keep_next=false +for ac_pass in 1 2 +do + for ac_arg + do + case $ac_arg in + -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;; + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil) + continue ;; + *" "*|*" "*|*[\[\]\~\#\$\^\&\*\(\)\{\}\\\|\;\<\>\?\"\']*) + ac_arg=`echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; + esac + case $ac_pass in + 1) ac_configure_args0="$ac_configure_args0 '$ac_arg'" ;; + 2) + ac_configure_args1="$ac_configure_args1 '$ac_arg'" + if test $ac_must_keep_next = true; then + ac_must_keep_next=false # Got value, back to normal. + else + case $ac_arg in + *=* | --config-cache | -C | -disable-* | --disable-* \ + | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \ + | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \ + | -with-* | --with-* | -without-* | --without-* | --x) + case "$ac_configure_args0 " in + "$ac_configure_args1"*" '$ac_arg' "* ) continue ;; + esac + ;; + -* ) ac_must_keep_next=true ;; + esac + fi + ac_configure_args="$ac_configure_args$ac_sep'$ac_arg'" + # Get rid of the leading space. + ac_sep=" " + ;; + esac + done +done +$as_unset ac_configure_args0 || test "${ac_configure_args0+set}" != set || { ac_configure_args0=; export ac_configure_args0; } +$as_unset ac_configure_args1 || test "${ac_configure_args1+set}" != set || { ac_configure_args1=; export ac_configure_args1; } + +# When interrupted or exit'd, cleanup temporary files, and complete +# config.log. We remove comments because anyway the quotes in there +# would cause problems or look ugly. +# WARNING: Be sure not to use single quotes in there, as some shells, +# such as our DU 5.0 friend, will then `close' the trap. +trap 'exit_status=$? + # Save into config.log some information that might help in debugging. + { + echo + + cat <<\_ASBOX +## ---------------- ## +## Cache variables. ## +## ---------------- ## +_ASBOX + echo + # The following way of writing the cache mishandles newlines in values, +{ + (set) 2>&1 | + case `(ac_space='"'"' '"'"'; set | grep ac_space) 2>&1` in + *ac_space=\ *) + sed -n \ + "s/'"'"'/'"'"'\\\\'"'"''"'"'/g; + s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='"'"'\\2'"'"'/p" + ;; + *) + sed -n \ + "s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1=\\2/p" + ;; + esac; +} + echo + + cat <<\_ASBOX +## ----------------- ## +## Output variables. ## +## ----------------- ## +_ASBOX + echo + for ac_var in $ac_subst_vars + do + eval ac_val=$`echo $ac_var` + echo "$ac_var='"'"'$ac_val'"'"'" + done | sort + echo + + if test -n "$ac_subst_files"; then + cat <<\_ASBOX +## ------------- ## +## Output files. ## +## ------------- ## +_ASBOX + echo + for ac_var in $ac_subst_files + do + eval ac_val=$`echo $ac_var` + echo "$ac_var='"'"'$ac_val'"'"'" + done | sort + echo + fi + + if test -s confdefs.h; then + cat <<\_ASBOX +## ----------- ## +## confdefs.h. ## +## ----------- ## +_ASBOX + echo + sed "/^$/d" confdefs.h | sort + echo + fi + test "$ac_signal" != 0 && + echo "$as_me: caught signal $ac_signal" + echo "$as_me: exit $exit_status" + } >&5 + rm -f core *.core && + rm -rf conftest* confdefs* conf$$* $ac_clean_files && + exit $exit_status + ' 0 +for ac_signal in 1 2 13 15; do + trap 'ac_signal='$ac_signal'; { (exit 1); exit 1; }' $ac_signal +done +ac_signal=0 + +# confdefs.h avoids OS command line length limits that DEFS can exceed. +rm -rf conftest* confdefs.h +# AIX cpp loses on an empty file, so make sure it contains at least a newline. +echo >confdefs.h + +# Predefined preprocessor variables. + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_NAME "$PACKAGE_NAME" +_ACEOF + + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_TARNAME "$PACKAGE_TARNAME" +_ACEOF + + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_VERSION "$PACKAGE_VERSION" +_ACEOF + + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_STRING "$PACKAGE_STRING" +_ACEOF + + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT" +_ACEOF + + +# Let the site file select an alternate cache file if it wants to. +# Prefer explicitly selected file to automatically selected ones. +if test -z "$CONFIG_SITE"; then + if test "x$prefix" != xNONE; then + CONFIG_SITE="$prefix/share/config.site $prefix/etc/config.site" + else + CONFIG_SITE="$ac_default_prefix/share/config.site $ac_default_prefix/etc/config.site" + fi +fi +for ac_site_file in $CONFIG_SITE; do + if test -r "$ac_site_file"; then + { echo "$as_me:$LINENO: loading site script $ac_site_file" >&5 +echo "$as_me: loading site script $ac_site_file" >&6;} + sed 's/^/| /' "$ac_site_file" >&5 + . "$ac_site_file" + fi +done + +if test -r "$cache_file"; then + # Some versions of bash will fail to source /dev/null (special + # files actually), so we avoid doing that. + if test -f "$cache_file"; then + { echo "$as_me:$LINENO: loading cache $cache_file" >&5 +echo "$as_me: loading cache $cache_file" >&6;} + case $cache_file in + [\\/]* | ?:[\\/]* ) . $cache_file;; + *) . ./$cache_file;; + esac + fi +else + { echo "$as_me:$LINENO: creating cache $cache_file" >&5 +echo "$as_me: creating cache $cache_file" >&6;} + >$cache_file +fi + +# Check that the precious variables saved in the cache have kept the same +# value. +ac_cache_corrupted=false +for ac_var in `(set) 2>&1 | + sed -n 's/^ac_env_\([a-zA-Z_0-9]*\)_set=.*/\1/p'`; do + eval ac_old_set=\$ac_cv_env_${ac_var}_set + eval ac_new_set=\$ac_env_${ac_var}_set + eval ac_old_val="\$ac_cv_env_${ac_var}_value" + eval ac_new_val="\$ac_env_${ac_var}_value" + case $ac_old_set,$ac_new_set in + set,) + { echo "$as_me:$LINENO: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5 +echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;} + ac_cache_corrupted=: ;; + ,set) + { echo "$as_me:$LINENO: error: \`$ac_var' was not set in the previous run" >&5 +echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;} + ac_cache_corrupted=: ;; + ,);; + *) + if test "x$ac_old_val" != "x$ac_new_val"; then + { echo "$as_me:$LINENO: error: \`$ac_var' has changed since the previous run:" >&5 +echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;} + { echo "$as_me:$LINENO: former value: $ac_old_val" >&5 +echo "$as_me: former value: $ac_old_val" >&2;} + { echo "$as_me:$LINENO: current value: $ac_new_val" >&5 +echo "$as_me: current value: $ac_new_val" >&2;} + ac_cache_corrupted=: + fi;; + esac + # Pass precious variables to config.status. + if test "$ac_new_set" = set; then + case $ac_new_val in + *" "*|*" "*|*[\[\]\~\#\$\^\&\*\(\)\{\}\\\|\;\<\>\?\"\']*) + ac_arg=$ac_var=`echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;; + *) ac_arg=$ac_var=$ac_new_val ;; + esac + case " $ac_configure_args " in + *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy. + *) ac_configure_args="$ac_configure_args '$ac_arg'" ;; + esac + fi +done +if $ac_cache_corrupted; then + { echo "$as_me:$LINENO: error: changes in the environment can compromise the build" >&5 +echo "$as_me: error: changes in the environment can compromise the build" >&2;} + { { echo "$as_me:$LINENO: error: run \`make distclean' and/or \`rm $cache_file' and start over" >&5 +echo "$as_me: error: run \`make distclean' and/or \`rm $cache_file' and start over" >&2;} + { (exit 1); exit 1; }; } +fi + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ac_config_headers="$ac_config_headers conf.h" + + +ac_aux_dir= +for ac_dir in $srcdir $srcdir/.. $srcdir/../..; do + if test -f $ac_dir/install-sh; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/install-sh -c" + break + elif test -f $ac_dir/install.sh; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/install.sh -c" + break + elif test -f $ac_dir/shtool; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/shtool install -c" + break + fi +done +if test -z "$ac_aux_dir"; then + { { echo "$as_me:$LINENO: error: cannot find install-sh or install.sh in $srcdir $srcdir/.. $srcdir/../.." >&5 +echo "$as_me: error: cannot find install-sh or install.sh in $srcdir $srcdir/.. $srcdir/../.." >&2;} + { (exit 1); exit 1; }; } +fi +ac_config_guess="$SHELL $ac_aux_dir/config.guess" +ac_config_sub="$SHELL $ac_aux_dir/config.sub" +ac_configure="$SHELL $ac_aux_dir/configure" # This should be Cygnus configure. + +# Make sure we can run config.sub. +$ac_config_sub sun4 >/dev/null 2>&1 || + { { echo "$as_me:$LINENO: error: cannot run $ac_config_sub" >&5 +echo "$as_me: error: cannot run $ac_config_sub" >&2;} + { (exit 1); exit 1; }; } + +echo "$as_me:$LINENO: checking build system type" >&5 +echo $ECHO_N "checking build system type... $ECHO_C" >&6 +if test "${ac_cv_build+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_cv_build_alias=$build_alias +test -z "$ac_cv_build_alias" && + ac_cv_build_alias=`$ac_config_guess` +test -z "$ac_cv_build_alias" && + { { echo "$as_me:$LINENO: error: cannot guess build type; you must specify one" >&5 +echo "$as_me: error: cannot guess build type; you must specify one" >&2;} + { (exit 1); exit 1; }; } +ac_cv_build=`$ac_config_sub $ac_cv_build_alias` || + { { echo "$as_me:$LINENO: error: $ac_config_sub $ac_cv_build_alias failed" >&5 +echo "$as_me: error: $ac_config_sub $ac_cv_build_alias failed" >&2;} + { (exit 1); exit 1; }; } + +fi +echo "$as_me:$LINENO: result: $ac_cv_build" >&5 +echo "${ECHO_T}$ac_cv_build" >&6 +build=$ac_cv_build +build_cpu=`echo $ac_cv_build | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\1/'` +build_vendor=`echo $ac_cv_build | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\2/'` +build_os=`echo $ac_cv_build | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\3/'` + + +echo "$as_me:$LINENO: checking host system type" >&5 +echo $ECHO_N "checking host system type... $ECHO_C" >&6 +if test "${ac_cv_host+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_cv_host_alias=$host_alias +test -z "$ac_cv_host_alias" && + ac_cv_host_alias=$ac_cv_build_alias +ac_cv_host=`$ac_config_sub $ac_cv_host_alias` || + { { echo "$as_me:$LINENO: error: $ac_config_sub $ac_cv_host_alias failed" >&5 +echo "$as_me: error: $ac_config_sub $ac_cv_host_alias failed" >&2;} + { (exit 1); exit 1; }; } + +fi +echo "$as_me:$LINENO: result: $ac_cv_host" >&5 +echo "${ECHO_T}$ac_cv_host" >&6 +host=$ac_cv_host +host_cpu=`echo $ac_cv_host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\1/'` +host_vendor=`echo $ac_cv_host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\2/'` +host_os=`echo $ac_cv_host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\3/'` + + + +# save LDFLAGS +XLDFLAGS="$LDFLAGS" + +# +# checks that we use in most projects +# +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu +if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args. +set dummy ${ac_tool_prefix}gcc; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_CC+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_CC="${ac_tool_prefix}gcc" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + echo "$as_me:$LINENO: result: $CC" >&5 +echo "${ECHO_T}$CC" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + +fi +if test -z "$ac_cv_prog_CC"; then + ac_ct_CC=$CC + # Extract the first word of "gcc", so it can be a program name with args. +set dummy gcc; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_ac_ct_CC+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$ac_ct_CC"; then + ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_CC="gcc" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + +fi +fi +ac_ct_CC=$ac_cv_prog_ac_ct_CC +if test -n "$ac_ct_CC"; then + echo "$as_me:$LINENO: result: $ac_ct_CC" >&5 +echo "${ECHO_T}$ac_ct_CC" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + + CC=$ac_ct_CC +else + CC="$ac_cv_prog_CC" +fi + +if test -z "$CC"; then + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args. +set dummy ${ac_tool_prefix}cc; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_CC+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_CC="${ac_tool_prefix}cc" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + echo "$as_me:$LINENO: result: $CC" >&5 +echo "${ECHO_T}$CC" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + +fi +if test -z "$ac_cv_prog_CC"; then + ac_ct_CC=$CC + # Extract the first word of "cc", so it can be a program name with args. +set dummy cc; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_ac_ct_CC+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$ac_ct_CC"; then + ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_CC="cc" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + +fi +fi +ac_ct_CC=$ac_cv_prog_ac_ct_CC +if test -n "$ac_ct_CC"; then + echo "$as_me:$LINENO: result: $ac_ct_CC" >&5 +echo "${ECHO_T}$ac_ct_CC" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + + CC=$ac_ct_CC +else + CC="$ac_cv_prog_CC" +fi + +fi +if test -z "$CC"; then + # Extract the first word of "cc", so it can be a program name with args. +set dummy cc; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_CC+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else + ac_prog_rejected=no +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then + ac_prog_rejected=yes + continue + fi + ac_cv_prog_CC="cc" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + +if test $ac_prog_rejected = yes; then + # We found a bogon in the path, so make sure we never use it. + set dummy $ac_cv_prog_CC + shift + if test $# != 0; then + # We chose a different compiler from the bogus one. + # However, it has the same basename, so the bogon will be chosen + # first if we set CC to just the basename; use the full file name. + shift + ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@" + fi +fi +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + echo "$as_me:$LINENO: result: $CC" >&5 +echo "${ECHO_T}$CC" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + +fi +if test -z "$CC"; then + if test -n "$ac_tool_prefix"; then + for ac_prog in cl + do + # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. +set dummy $ac_tool_prefix$ac_prog; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_CC+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_CC="$ac_tool_prefix$ac_prog" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + echo "$as_me:$LINENO: result: $CC" >&5 +echo "${ECHO_T}$CC" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + + test -n "$CC" && break + done +fi +if test -z "$CC"; then + ac_ct_CC=$CC + for ac_prog in cl +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_ac_ct_CC+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$ac_ct_CC"; then + ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_CC="$ac_prog" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + +fi +fi +ac_ct_CC=$ac_cv_prog_ac_ct_CC +if test -n "$ac_ct_CC"; then + echo "$as_me:$LINENO: result: $ac_ct_CC" >&5 +echo "${ECHO_T}$ac_ct_CC" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + + test -n "$ac_ct_CC" && break +done + + CC=$ac_ct_CC +fi + +fi + + +test -z "$CC" && { { echo "$as_me:$LINENO: error: no acceptable C compiler found in \$PATH +See \`config.log' for more details." >&5 +echo "$as_me: error: no acceptable C compiler found in \$PATH +See \`config.log' for more details." >&2;} + { (exit 1); exit 1; }; } + +# Provide some information about the compiler. +echo "$as_me:$LINENO:" \ + "checking for C compiler version" >&5 +ac_compiler=`set X $ac_compile; echo $2` +{ (eval echo "$as_me:$LINENO: \"$ac_compiler --version </dev/null >&5\"") >&5 + (eval $ac_compiler --version </dev/null >&5) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } +{ (eval echo "$as_me:$LINENO: \"$ac_compiler -v </dev/null >&5\"") >&5 + (eval $ac_compiler -v </dev/null >&5) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } +{ (eval echo "$as_me:$LINENO: \"$ac_compiler -V </dev/null >&5\"") >&5 + (eval $ac_compiler -V </dev/null >&5) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } + +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +ac_clean_files_save=$ac_clean_files +ac_clean_files="$ac_clean_files a.out a.exe b.out" +# Try to create an executable without -o first, disregard a.out. +# It will help us diagnose broken compilers, and finding out an intuition +# of exeext. +echo "$as_me:$LINENO: checking for C compiler default output file name" >&5 +echo $ECHO_N "checking for C compiler default output file name... $ECHO_C" >&6 +ac_link_default=`echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'` +if { (eval echo "$as_me:$LINENO: \"$ac_link_default\"") >&5 + (eval $ac_link_default) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; then + # Find the output, starting from the most likely. This scheme is +# not robust to junk in `.', hence go to wildcards (a.*) only as a last +# resort. + +# Be careful to initialize this variable, since it used to be cached. +# Otherwise an old cache value of `no' led to `EXEEXT = no' in a Makefile. +ac_cv_exeext= +# b.out is created by i960 compilers. +for ac_file in a_out.exe a.exe conftest.exe a.out conftest a.* conftest.* b.out +do + test -f "$ac_file" || continue + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.o | *.obj ) + ;; + conftest.$ac_ext ) + # This is the source file. + ;; + [ab].out ) + # We found the default executable, but exeext='' is most + # certainly right. + break;; + *.* ) + ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` + # FIXME: I believe we export ac_cv_exeext for Libtool, + # but it would be cool to find out if it's true. Does anybody + # maintain Libtool? --akim. + export ac_cv_exeext + break;; + * ) + break;; + esac +done +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +{ { echo "$as_me:$LINENO: error: C compiler cannot create executables +See \`config.log' for more details." >&5 +echo "$as_me: error: C compiler cannot create executables +See \`config.log' for more details." >&2;} + { (exit 77); exit 77; }; } +fi + +ac_exeext=$ac_cv_exeext +echo "$as_me:$LINENO: result: $ac_file" >&5 +echo "${ECHO_T}$ac_file" >&6 + +# Check the compiler produces executables we can run. If not, either +# the compiler is broken, or we cross compile. +echo "$as_me:$LINENO: checking whether the C compiler works" >&5 +echo $ECHO_N "checking whether the C compiler works... $ECHO_C" >&6 +# FIXME: These cross compiler hacks should be removed for Autoconf 3.0 +# If not cross compiling, check that we can run a simple program. +if test "$cross_compiling" != yes; then + if { ac_try='./$ac_file' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + cross_compiling=no + else + if test "$cross_compiling" = maybe; then + cross_compiling=yes + else + { { echo "$as_me:$LINENO: error: cannot run C compiled programs. +If you meant to cross compile, use \`--host'. +See \`config.log' for more details." >&5 +echo "$as_me: error: cannot run C compiled programs. +If you meant to cross compile, use \`--host'. +See \`config.log' for more details." >&2;} + { (exit 1); exit 1; }; } + fi + fi +fi +echo "$as_me:$LINENO: result: yes" >&5 +echo "${ECHO_T}yes" >&6 + +rm -f a.out a.exe conftest$ac_cv_exeext b.out +ac_clean_files=$ac_clean_files_save +# Check the compiler produces executables we can run. If not, either +# the compiler is broken, or we cross compile. +echo "$as_me:$LINENO: checking whether we are cross compiling" >&5 +echo $ECHO_N "checking whether we are cross compiling... $ECHO_C" >&6 +echo "$as_me:$LINENO: result: $cross_compiling" >&5 +echo "${ECHO_T}$cross_compiling" >&6 + +echo "$as_me:$LINENO: checking for suffix of executables" >&5 +echo $ECHO_N "checking for suffix of executables... $ECHO_C" >&6 +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; then + # If both `conftest.exe' and `conftest' are `present' (well, observable) +# catch `conftest.exe'. For instance with Cygwin, `ls conftest' will +# work properly (i.e., refer to `conftest.exe'), while it won't with +# `rm'. +for ac_file in conftest.exe conftest conftest.*; do + test -f "$ac_file" || continue + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.o | *.obj ) ;; + *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` + export ac_cv_exeext + break;; + * ) break;; + esac +done +else + { { echo "$as_me:$LINENO: error: cannot compute suffix of executables: cannot compile and link +See \`config.log' for more details." >&5 +echo "$as_me: error: cannot compute suffix of executables: cannot compile and link +See \`config.log' for more details." >&2;} + { (exit 1); exit 1; }; } +fi + +rm -f conftest$ac_cv_exeext +echo "$as_me:$LINENO: result: $ac_cv_exeext" >&5 +echo "${ECHO_T}$ac_cv_exeext" >&6 + +rm -f conftest.$ac_ext +EXEEXT=$ac_cv_exeext +ac_exeext=$EXEEXT +echo "$as_me:$LINENO: checking for suffix of object files" >&5 +echo $ECHO_N "checking for suffix of object files... $ECHO_C" >&6 +if test "${ac_cv_objext+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.o conftest.obj +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; then + for ac_file in `(ls conftest.o conftest.obj; ls conftest.*) 2>/dev/null`; do + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg ) ;; + *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'` + break;; + esac +done +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +{ { echo "$as_me:$LINENO: error: cannot compute suffix of object files: cannot compile +See \`config.log' for more details." >&5 +echo "$as_me: error: cannot compute suffix of object files: cannot compile +See \`config.log' for more details." >&2;} + { (exit 1); exit 1; }; } +fi + +rm -f conftest.$ac_cv_objext conftest.$ac_ext +fi +echo "$as_me:$LINENO: result: $ac_cv_objext" >&5 +echo "${ECHO_T}$ac_cv_objext" >&6 +OBJEXT=$ac_cv_objext +ac_objext=$OBJEXT +echo "$as_me:$LINENO: checking whether we are using the GNU C compiler" >&5 +echo $ECHO_N "checking whether we are using the GNU C compiler... $ECHO_C" >&6 +if test "${ac_cv_c_compiler_gnu+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ +#ifndef __GNUC__ + choke me +#endif + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_compiler_gnu=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_compiler_gnu=no +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +ac_cv_c_compiler_gnu=$ac_compiler_gnu + +fi +echo "$as_me:$LINENO: result: $ac_cv_c_compiler_gnu" >&5 +echo "${ECHO_T}$ac_cv_c_compiler_gnu" >&6 +GCC=`test $ac_compiler_gnu = yes && echo yes` +ac_test_CFLAGS=${CFLAGS+set} +ac_save_CFLAGS=$CFLAGS +CFLAGS="-g" +echo "$as_me:$LINENO: checking whether $CC accepts -g" >&5 +echo $ECHO_N "checking whether $CC accepts -g... $ECHO_C" >&6 +if test "${ac_cv_prog_cc_g+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_prog_cc_g=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_cv_prog_cc_g=no +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +fi +echo "$as_me:$LINENO: result: $ac_cv_prog_cc_g" >&5 +echo "${ECHO_T}$ac_cv_prog_cc_g" >&6 +if test "$ac_test_CFLAGS" = set; then + CFLAGS=$ac_save_CFLAGS +elif test $ac_cv_prog_cc_g = yes; then + if test "$GCC" = yes; then + CFLAGS="-g -O2" + else + CFLAGS="-g" + fi +else + if test "$GCC" = yes; then + CFLAGS="-O2" + else + CFLAGS= + fi +fi +echo "$as_me:$LINENO: checking for $CC option to accept ANSI C" >&5 +echo $ECHO_N "checking for $CC option to accept ANSI C... $ECHO_C" >&6 +if test "${ac_cv_prog_cc_stdc+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_cv_prog_cc_stdc=no +ac_save_CC=$CC +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include <stdarg.h> +#include <stdio.h> +#include <sys/types.h> +#include <sys/stat.h> +/* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */ +struct buf { int x; }; +FILE * (*rcsopen) (struct buf *, struct stat *, int); +static char *e (p, i) + char **p; + int i; +{ + return p[i]; +} +static char *f (char * (*g) (char **, int), char **p, ...) +{ + char *s; + va_list v; + va_start (v,p); + s = g (p, va_arg (v,int)); + va_end (v); + return s; +} + +/* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has + function prototypes and stuff, but not '\xHH' hex character constants. + These don't provoke an error unfortunately, instead are silently treated + as 'x'. The following induces an error, until -std1 is added to get + proper ANSI mode. Curiously '\x00'!='x' always comes out true, for an + array size at least. It's necessary to write '\x00'==0 to get something + that's true only with -std1. */ +int osf4_cc_array ['\x00' == 0 ? 1 : -1]; + +int test (int i, double x); +struct s1 {int (*f) (int a);}; +struct s2 {int (*f) (double a);}; +int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int); +int argc; +char **argv; +int +main () +{ +return f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1]; + ; + return 0; +} +_ACEOF +# Don't try gcc -ansi; that turns off useful extensions and +# breaks some systems' header files. +# AIX -qlanglvl=ansi +# Ultrix and OSF/1 -std1 +# HP-UX 10.20 and later -Ae +# HP-UX older versions -Aa -D_HPUX_SOURCE +# SVR4 -Xc -D__EXTENSIONS__ +for ac_arg in "" -qlanglvl=ansi -std1 -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__" +do + CC="$ac_save_CC $ac_arg" + rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_prog_cc_stdc=$ac_arg +break +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +fi +rm -f conftest.err conftest.$ac_objext +done +rm -f conftest.$ac_ext conftest.$ac_objext +CC=$ac_save_CC + +fi + +case "x$ac_cv_prog_cc_stdc" in + x|xno) + echo "$as_me:$LINENO: result: none needed" >&5 +echo "${ECHO_T}none needed" >&6 ;; + *) + echo "$as_me:$LINENO: result: $ac_cv_prog_cc_stdc" >&5 +echo "${ECHO_T}$ac_cv_prog_cc_stdc" >&6 + CC="$CC $ac_cv_prog_cc_stdc" ;; +esac + +# Some people use a C++ compiler to compile C. Since we use `exit', +# in C++ we need to declare it. In case someone uses the same compiler +# for both compiling C and C++ we need to have the C++ compiler decide +# the declaration of exit, since it's the most demanding environment. +cat >conftest.$ac_ext <<_ACEOF +#ifndef __cplusplus + choke me +#endif +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + for ac_declaration in \ + '' \ + 'extern "C" void std::exit (int) throw (); using std::exit;' \ + 'extern "C" void std::exit (int); using std::exit;' \ + 'extern "C" void exit (int) throw ();' \ + 'extern "C" void exit (int);' \ + 'void exit (int);' +do + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_declaration +#include <stdlib.h> +int +main () +{ +exit (42); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + : +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +continue +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_declaration +int +main () +{ +exit (42); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + break +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +done +rm -f conftest* +if test -n "$ac_declaration"; then + echo '#ifdef __cplusplus' >>confdefs.h + echo $ac_declaration >>confdefs.h + echo '#endif' >>confdefs.h +fi + +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + + +if test x"${EXEEXT}" = "xno"; then + EXEEXT="" +fi + + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu +echo "$as_me:$LINENO: checking how to run the C preprocessor" >&5 +echo $ECHO_N "checking how to run the C preprocessor... $ECHO_C" >&6 +# On Suns, sometimes $CPP names a directory. +if test -n "$CPP" && test -d "$CPP"; then + CPP= +fi +if test -z "$CPP"; then + if test "${ac_cv_prog_CPP+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + # Double quotes because CPP needs to be expanded + for CPP in "$CC -E" "$CC -E -traditional-cpp" "/lib/cpp" + do + ac_preproc_ok=false +for ac_c_preproc_warn_flag in '' yes +do + # Use a header file that comes with gcc, so configuring glibc + # with a fresh cross-compiler works. + # Prefer <limits.h> to <assert.h> if __STDC__ is defined, since + # <limits.h> exists even on freestanding compilers. + # On the NeXT, cc -E runs the code through the compiler's parser, + # not just through cpp. "Syntax error" is here to catch this case. + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#ifdef __STDC__ +# include <limits.h> +#else +# include <assert.h> +#endif + Syntax error +_ACEOF +if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 + (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null; then + if test -s conftest.err; then + ac_cpp_err=$ac_c_preproc_warn_flag + ac_cpp_err=$ac_cpp_err$ac_c_werror_flag + else + ac_cpp_err= + fi +else + ac_cpp_err=yes +fi +if test -z "$ac_cpp_err"; then + : +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + # Broken: fails on valid input. +continue +fi +rm -f conftest.err conftest.$ac_ext + + # OK, works on sane cases. Now check whether non-existent headers + # can be detected and how. + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include <ac_nonexistent.h> +_ACEOF +if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 + (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null; then + if test -s conftest.err; then + ac_cpp_err=$ac_c_preproc_warn_flag + ac_cpp_err=$ac_cpp_err$ac_c_werror_flag + else + ac_cpp_err= + fi +else + ac_cpp_err=yes +fi +if test -z "$ac_cpp_err"; then + # Broken: success on invalid input. +continue +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + # Passes both tests. +ac_preproc_ok=: +break +fi +rm -f conftest.err conftest.$ac_ext + +done +# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. +rm -f conftest.err conftest.$ac_ext +if $ac_preproc_ok; then + break +fi + + done + ac_cv_prog_CPP=$CPP + +fi + CPP=$ac_cv_prog_CPP +else + ac_cv_prog_CPP=$CPP +fi +echo "$as_me:$LINENO: result: $CPP" >&5 +echo "${ECHO_T}$CPP" >&6 +ac_preproc_ok=false +for ac_c_preproc_warn_flag in '' yes +do + # Use a header file that comes with gcc, so configuring glibc + # with a fresh cross-compiler works. + # Prefer <limits.h> to <assert.h> if __STDC__ is defined, since + # <limits.h> exists even on freestanding compilers. + # On the NeXT, cc -E runs the code through the compiler's parser, + # not just through cpp. "Syntax error" is here to catch this case. + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#ifdef __STDC__ +# include <limits.h> +#else +# include <assert.h> +#endif + Syntax error +_ACEOF +if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 + (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null; then + if test -s conftest.err; then + ac_cpp_err=$ac_c_preproc_warn_flag + ac_cpp_err=$ac_cpp_err$ac_c_werror_flag + else + ac_cpp_err= + fi +else + ac_cpp_err=yes +fi +if test -z "$ac_cpp_err"; then + : +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + # Broken: fails on valid input. +continue +fi +rm -f conftest.err conftest.$ac_ext + + # OK, works on sane cases. Now check whether non-existent headers + # can be detected and how. + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include <ac_nonexistent.h> +_ACEOF +if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 + (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null; then + if test -s conftest.err; then + ac_cpp_err=$ac_c_preproc_warn_flag + ac_cpp_err=$ac_cpp_err$ac_c_werror_flag + else + ac_cpp_err= + fi +else + ac_cpp_err=yes +fi +if test -z "$ac_cpp_err"; then + # Broken: success on invalid input. +continue +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + # Passes both tests. +ac_preproc_ok=: +break +fi +rm -f conftest.err conftest.$ac_ext + +done +# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. +rm -f conftest.err conftest.$ac_ext +if $ac_preproc_ok; then + : +else + { { echo "$as_me:$LINENO: error: C preprocessor \"$CPP\" fails sanity check +See \`config.log' for more details." >&5 +echo "$as_me: error: C preprocessor \"$CPP\" fails sanity check +See \`config.log' for more details." >&2;} + { (exit 1); exit 1; }; } +fi + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +echo "$as_me:$LINENO: checking for egrep" >&5 +echo $ECHO_N "checking for egrep... $ECHO_C" >&6 +if test "${ac_cv_prog_egrep+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if echo a | (grep -E '(a|b)') >/dev/null 2>&1 + then ac_cv_prog_egrep='grep -E' + else ac_cv_prog_egrep='egrep' + fi +fi +echo "$as_me:$LINENO: result: $ac_cv_prog_egrep" >&5 +echo "${ECHO_T}$ac_cv_prog_egrep" >&6 + EGREP=$ac_cv_prog_egrep + + +echo "$as_me:$LINENO: checking for ANSI C header files" >&5 +echo $ECHO_N "checking for ANSI C header files... $ECHO_C" >&6 +if test "${ac_cv_header_stdc+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include <stdlib.h> +#include <stdarg.h> +#include <string.h> +#include <float.h> + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_header_stdc=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_cv_header_stdc=no +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext + +if test $ac_cv_header_stdc = yes; then + # SunOS 4.x string.h does not declare mem*, contrary to ANSI. + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include <string.h> + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "memchr" >/dev/null 2>&1; then + : +else + ac_cv_header_stdc=no +fi +rm -f conftest* + +fi + +if test $ac_cv_header_stdc = yes; then + # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI. + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include <stdlib.h> + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "free" >/dev/null 2>&1; then + : +else + ac_cv_header_stdc=no +fi +rm -f conftest* + +fi + +if test $ac_cv_header_stdc = yes; then + # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi. + if test "$cross_compiling" = yes; then + : +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include <ctype.h> +#if ((' ' & 0x0FF) == 0x020) +# define ISLOWER(c) ('a' <= (c) && (c) <= 'z') +# define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c)) +#else +# define ISLOWER(c) \ + (('a' <= (c) && (c) <= 'i') \ + || ('j' <= (c) && (c) <= 'r') \ + || ('s' <= (c) && (c) <= 'z')) +# define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c)) +#endif + +#define XOR(e, f) (((e) && !(f)) || (!(e) && (f))) +int +main () +{ + int i; + for (i = 0; i < 256; i++) + if (XOR (islower (i), ISLOWER (i)) + || toupper (i) != TOUPPER (i)) + exit(2); + exit (0); +} +_ACEOF +rm -f conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { ac_try='./conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + : +else + echo "$as_me: program exited with status $ac_status" >&5 +echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +( exit $ac_status ) +ac_cv_header_stdc=no +fi +rm -f core *.core gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext +fi +fi +fi +echo "$as_me:$LINENO: result: $ac_cv_header_stdc" >&5 +echo "${ECHO_T}$ac_cv_header_stdc" >&6 +if test $ac_cv_header_stdc = yes; then + +cat >>confdefs.h <<\_ACEOF +#define STDC_HEADERS 1 +_ACEOF + +fi + +# On IRIX 5.3, sys/types and inttypes.h are conflicting. + + + + + + + + + +for ac_header in sys/types.h sys/stat.h stdlib.h string.h memory.h strings.h \ + inttypes.h stdint.h unistd.h +do +as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh` +echo "$as_me:$LINENO: checking for $ac_header" >&5 +echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6 +if eval "test \"\${$as_ac_Header+set}\" = set"; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default + +#include <$ac_header> +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + eval "$as_ac_Header=yes" +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +eval "$as_ac_Header=no" +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +fi +echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5 +echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6 +if test `eval echo '${'$as_ac_Header'}'` = yes; then + cat >>confdefs.h <<_ACEOF +#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1 +_ACEOF + +fi + +done + + +echo "$as_me:$LINENO: checking for long" >&5 +echo $ECHO_N "checking for long... $ECHO_C" >&6 +if test "${ac_cv_type_long+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +int +main () +{ +if ((long *) 0) + return 0; +if (sizeof (long)) + return 0; + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_type_long=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_cv_type_long=no +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +fi +echo "$as_me:$LINENO: result: $ac_cv_type_long" >&5 +echo "${ECHO_T}$ac_cv_type_long" >&6 + +echo "$as_me:$LINENO: checking size of long" >&5 +echo $ECHO_N "checking size of long... $ECHO_C" >&6 +if test "${ac_cv_sizeof_long+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test "$ac_cv_type_long" = yes; then + # The cast to unsigned long works around a bug in the HP C Compiler + # version HP92453-01 B.11.11.23709.GP, which incorrectly rejects + # declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'. + # This bug is HP SR number 8606223364. + if test "$cross_compiling" = yes; then + # Depending upon the size, compute the lo and hi bounds. +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +int +main () +{ +static int test_array [1 - 2 * !(((long) (sizeof (long))) >= 0)]; +test_array [0] = 0 + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_lo=0 ac_mid=0 + while :; do + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +int +main () +{ +static int test_array [1 - 2 * !(((long) (sizeof (long))) <= $ac_mid)]; +test_array [0] = 0 + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_hi=$ac_mid; break +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_lo=`expr $ac_mid + 1` + if test $ac_lo -le $ac_mid; then + ac_lo= ac_hi= + break + fi + ac_mid=`expr 2 '*' $ac_mid + 1` +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext + done +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +int +main () +{ +static int test_array [1 - 2 * !(((long) (sizeof (long))) < 0)]; +test_array [0] = 0 + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_hi=-1 ac_mid=-1 + while :; do + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +int +main () +{ +static int test_array [1 - 2 * !(((long) (sizeof (long))) >= $ac_mid)]; +test_array [0] = 0 + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_lo=$ac_mid; break +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_hi=`expr '(' $ac_mid ')' - 1` + if test $ac_mid -le $ac_hi; then + ac_lo= ac_hi= + break + fi + ac_mid=`expr 2 '*' $ac_mid` +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext + done +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_lo= ac_hi= +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +# Binary search between lo and hi bounds. +while test "x$ac_lo" != "x$ac_hi"; do + ac_mid=`expr '(' $ac_hi - $ac_lo ')' / 2 + $ac_lo` + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +int +main () +{ +static int test_array [1 - 2 * !(((long) (sizeof (long))) <= $ac_mid)]; +test_array [0] = 0 + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_hi=$ac_mid +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_lo=`expr '(' $ac_mid ')' + 1` +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +done +case $ac_lo in +?*) ac_cv_sizeof_long=$ac_lo;; +'') { { echo "$as_me:$LINENO: error: cannot compute sizeof (long), 77 +See \`config.log' for more details." >&5 +echo "$as_me: error: cannot compute sizeof (long), 77 +See \`config.log' for more details." >&2;} + { (exit 1); exit 1; }; } ;; +esac +else + if test "$cross_compiling" = yes; then + { { echo "$as_me:$LINENO: error: cannot run test program while cross compiling +See \`config.log' for more details." >&5 +echo "$as_me: error: cannot run test program while cross compiling +See \`config.log' for more details." >&2;} + { (exit 1); exit 1; }; } +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +long longval () { return (long) (sizeof (long)); } +unsigned long ulongval () { return (long) (sizeof (long)); } +#include <stdio.h> +#include <stdlib.h> +int +main () +{ + + FILE *f = fopen ("conftest.val", "w"); + if (! f) + exit (1); + if (((long) (sizeof (long))) < 0) + { + long i = longval (); + if (i != ((long) (sizeof (long)))) + exit (1); + fprintf (f, "%ld\n", i); + } + else + { + unsigned long i = ulongval (); + if (i != ((long) (sizeof (long)))) + exit (1); + fprintf (f, "%lu\n", i); + } + exit (ferror (f) || fclose (f) != 0); + + ; + return 0; +} +_ACEOF +rm -f conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { ac_try='./conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_sizeof_long=`cat conftest.val` +else + echo "$as_me: program exited with status $ac_status" >&5 +echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +( exit $ac_status ) +{ { echo "$as_me:$LINENO: error: cannot compute sizeof (long), 77 +See \`config.log' for more details." >&5 +echo "$as_me: error: cannot compute sizeof (long), 77 +See \`config.log' for more details." >&2;} + { (exit 1); exit 1; }; } +fi +rm -f core *.core gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext +fi +fi +rm -f conftest.val +else + ac_cv_sizeof_long=0 +fi +fi +echo "$as_me:$LINENO: result: $ac_cv_sizeof_long" >&5 +echo "${ECHO_T}$ac_cv_sizeof_long" >&6 +cat >>confdefs.h <<_ACEOF +#define SIZEOF_LONG $ac_cv_sizeof_long +_ACEOF + + +SZ_LONG=$ac_cv_sizeof_long + + +if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}ranlib", so it can be a program name with args. +set dummy ${ac_tool_prefix}ranlib; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_RANLIB+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$RANLIB"; then + ac_cv_prog_RANLIB="$RANLIB" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_RANLIB="${ac_tool_prefix}ranlib" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + +fi +fi +RANLIB=$ac_cv_prog_RANLIB +if test -n "$RANLIB"; then + echo "$as_me:$LINENO: result: $RANLIB" >&5 +echo "${ECHO_T}$RANLIB" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + +fi +if test -z "$ac_cv_prog_RANLIB"; then + ac_ct_RANLIB=$RANLIB + # Extract the first word of "ranlib", so it can be a program name with args. +set dummy ranlib; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_ac_ct_RANLIB+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$ac_ct_RANLIB"; then + ac_cv_prog_ac_ct_RANLIB="$ac_ct_RANLIB" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_RANLIB="ranlib" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + + test -z "$ac_cv_prog_ac_ct_RANLIB" && ac_cv_prog_ac_ct_RANLIB=":" +fi +fi +ac_ct_RANLIB=$ac_cv_prog_ac_ct_RANLIB +if test -n "$ac_ct_RANLIB"; then + echo "$as_me:$LINENO: result: $ac_ct_RANLIB" >&5 +echo "${ECHO_T}$ac_ct_RANLIB" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + + RANLIB=$ac_ct_RANLIB +else + RANLIB="$ac_cv_prog_RANLIB" +fi + + +echo "$as_me:$LINENO: checking for ANSI C header files" >&5 +echo $ECHO_N "checking for ANSI C header files... $ECHO_C" >&6 +if test "${ac_cv_header_stdc+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include <stdlib.h> +#include <stdarg.h> +#include <string.h> +#include <float.h> + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_header_stdc=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_cv_header_stdc=no +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext + +if test $ac_cv_header_stdc = yes; then + # SunOS 4.x string.h does not declare mem*, contrary to ANSI. + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include <string.h> + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "memchr" >/dev/null 2>&1; then + : +else + ac_cv_header_stdc=no +fi +rm -f conftest* + +fi + +if test $ac_cv_header_stdc = yes; then + # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI. + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include <stdlib.h> + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "free" >/dev/null 2>&1; then + : +else + ac_cv_header_stdc=no +fi +rm -f conftest* + +fi + +if test $ac_cv_header_stdc = yes; then + # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi. + if test "$cross_compiling" = yes; then + : +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include <ctype.h> +#if ((' ' & 0x0FF) == 0x020) +# define ISLOWER(c) ('a' <= (c) && (c) <= 'z') +# define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c)) +#else +# define ISLOWER(c) \ + (('a' <= (c) && (c) <= 'i') \ + || ('j' <= (c) && (c) <= 'r') \ + || ('s' <= (c) && (c) <= 'z')) +# define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c)) +#endif + +#define XOR(e, f) (((e) && !(f)) || (!(e) && (f))) +int +main () +{ + int i; + for (i = 0; i < 256; i++) + if (XOR (islower (i), ISLOWER (i)) + || toupper (i) != TOUPPER (i)) + exit(2); + exit (0); +} +_ACEOF +rm -f conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { ac_try='./conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + : +else + echo "$as_me: program exited with status $ac_status" >&5 +echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +( exit $ac_status ) +ac_cv_header_stdc=no +fi +rm -f core *.core gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext +fi +fi +fi +echo "$as_me:$LINENO: result: $ac_cv_header_stdc" >&5 +echo "${ECHO_T}$ac_cv_header_stdc" >&6 +if test $ac_cv_header_stdc = yes; then + +cat >>confdefs.h <<\_ACEOF +#define STDC_HEADERS 1 +_ACEOF + +fi + + +for ac_header in malloc.h +do +as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh` +if eval "test \"\${$as_ac_Header+set}\" = set"; then + echo "$as_me:$LINENO: checking for $ac_header" >&5 +echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6 +if eval "test \"\${$as_ac_Header+set}\" = set"; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +fi +echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5 +echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6 +else + # Is the header compilable? +echo "$as_me:$LINENO: checking $ac_header usability" >&5 +echo $ECHO_N "checking $ac_header usability... $ECHO_C" >&6 +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +#include <$ac_header> +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_header_compiler=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_header_compiler=no +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +echo "$as_me:$LINENO: result: $ac_header_compiler" >&5 +echo "${ECHO_T}$ac_header_compiler" >&6 + +# Is the header present? +echo "$as_me:$LINENO: checking $ac_header presence" >&5 +echo $ECHO_N "checking $ac_header presence... $ECHO_C" >&6 +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include <$ac_header> +_ACEOF +if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 + (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null; then + if test -s conftest.err; then + ac_cpp_err=$ac_c_preproc_warn_flag + ac_cpp_err=$ac_cpp_err$ac_c_werror_flag + else + ac_cpp_err= + fi +else + ac_cpp_err=yes +fi +if test -z "$ac_cpp_err"; then + ac_header_preproc=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_header_preproc=no +fi +rm -f conftest.err conftest.$ac_ext +echo "$as_me:$LINENO: result: $ac_header_preproc" >&5 +echo "${ECHO_T}$ac_header_preproc" >&6 + +# So? What about this header? +case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in + yes:no: ) + { echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5 +echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5 +echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;} + ac_header_preproc=yes + ;; + no:yes:* ) + { echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5 +echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: check for missing prerequisite headers?" >&5 +echo "$as_me: WARNING: $ac_header: check for missing prerequisite headers?" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5 +echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&5 +echo "$as_me: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5 +echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5 +echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;} + ( + cat <<\_ASBOX +## ----------------------------------- ## +## Report this to eric@cfa.harvard.edu ## +## ----------------------------------- ## +_ASBOX + ) | + sed "s/^/$as_me: WARNING: /" >&2 + ;; +esac +echo "$as_me:$LINENO: checking for $ac_header" >&5 +echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6 +if eval "test \"\${$as_ac_Header+set}\" = set"; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + eval "$as_ac_Header=\$ac_header_preproc" +fi +echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5 +echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6 + +fi +if test `eval echo '${'$as_ac_Header'}'` = yes; then + cat >>confdefs.h <<_ACEOF +#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1 +_ACEOF + +fi + +done + + +for ac_header in getopt.h +do +as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh` +if eval "test \"\${$as_ac_Header+set}\" = set"; then + echo "$as_me:$LINENO: checking for $ac_header" >&5 +echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6 +if eval "test \"\${$as_ac_Header+set}\" = set"; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +fi +echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5 +echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6 +else + # Is the header compilable? +echo "$as_me:$LINENO: checking $ac_header usability" >&5 +echo $ECHO_N "checking $ac_header usability... $ECHO_C" >&6 +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +#include <$ac_header> +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_header_compiler=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_header_compiler=no +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +echo "$as_me:$LINENO: result: $ac_header_compiler" >&5 +echo "${ECHO_T}$ac_header_compiler" >&6 + +# Is the header present? +echo "$as_me:$LINENO: checking $ac_header presence" >&5 +echo $ECHO_N "checking $ac_header presence... $ECHO_C" >&6 +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include <$ac_header> +_ACEOF +if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 + (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null; then + if test -s conftest.err; then + ac_cpp_err=$ac_c_preproc_warn_flag + ac_cpp_err=$ac_cpp_err$ac_c_werror_flag + else + ac_cpp_err= + fi +else + ac_cpp_err=yes +fi +if test -z "$ac_cpp_err"; then + ac_header_preproc=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_header_preproc=no +fi +rm -f conftest.err conftest.$ac_ext +echo "$as_me:$LINENO: result: $ac_header_preproc" >&5 +echo "${ECHO_T}$ac_header_preproc" >&6 + +# So? What about this header? +case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in + yes:no: ) + { echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5 +echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5 +echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;} + ac_header_preproc=yes + ;; + no:yes:* ) + { echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5 +echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: check for missing prerequisite headers?" >&5 +echo "$as_me: WARNING: $ac_header: check for missing prerequisite headers?" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5 +echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&5 +echo "$as_me: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5 +echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5 +echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;} + ( + cat <<\_ASBOX +## ----------------------------------- ## +## Report this to eric@cfa.harvard.edu ## +## ----------------------------------- ## +_ASBOX + ) | + sed "s/^/$as_me: WARNING: /" >&2 + ;; +esac +echo "$as_me:$LINENO: checking for $ac_header" >&5 +echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6 +if eval "test \"\${$as_ac_Header+set}\" = set"; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + eval "$as_ac_Header=\$ac_header_preproc" +fi +echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5 +echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6 + +fi +if test `eval echo '${'$as_ac_Header'}'` = yes; then + cat >>confdefs.h <<_ACEOF +#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1 +_ACEOF + +fi + +done + + +for ac_header in pwd.h +do +as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh` +if eval "test \"\${$as_ac_Header+set}\" = set"; then + echo "$as_me:$LINENO: checking for $ac_header" >&5 +echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6 +if eval "test \"\${$as_ac_Header+set}\" = set"; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +fi +echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5 +echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6 +else + # Is the header compilable? +echo "$as_me:$LINENO: checking $ac_header usability" >&5 +echo $ECHO_N "checking $ac_header usability... $ECHO_C" >&6 +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +#include <$ac_header> +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_header_compiler=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_header_compiler=no +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +echo "$as_me:$LINENO: result: $ac_header_compiler" >&5 +echo "${ECHO_T}$ac_header_compiler" >&6 + +# Is the header present? +echo "$as_me:$LINENO: checking $ac_header presence" >&5 +echo $ECHO_N "checking $ac_header presence... $ECHO_C" >&6 +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include <$ac_header> +_ACEOF +if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 + (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null; then + if test -s conftest.err; then + ac_cpp_err=$ac_c_preproc_warn_flag + ac_cpp_err=$ac_cpp_err$ac_c_werror_flag + else + ac_cpp_err= + fi +else + ac_cpp_err=yes +fi +if test -z "$ac_cpp_err"; then + ac_header_preproc=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_header_preproc=no +fi +rm -f conftest.err conftest.$ac_ext +echo "$as_me:$LINENO: result: $ac_header_preproc" >&5 +echo "${ECHO_T}$ac_header_preproc" >&6 + +# So? What about this header? +case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in + yes:no: ) + { echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5 +echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5 +echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;} + ac_header_preproc=yes + ;; + no:yes:* ) + { echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5 +echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: check for missing prerequisite headers?" >&5 +echo "$as_me: WARNING: $ac_header: check for missing prerequisite headers?" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5 +echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&5 +echo "$as_me: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5 +echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5 +echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;} + ( + cat <<\_ASBOX +## ----------------------------------- ## +## Report this to eric@cfa.harvard.edu ## +## ----------------------------------- ## +_ASBOX + ) | + sed "s/^/$as_me: WARNING: /" >&2 + ;; +esac +echo "$as_me:$LINENO: checking for $ac_header" >&5 +echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6 +if eval "test \"\${$as_ac_Header+set}\" = set"; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + eval "$as_ac_Header=\$ac_header_preproc" +fi +echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5 +echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6 + +fi +if test `eval echo '${'$as_ac_Header'}'` = yes; then + cat >>confdefs.h <<_ACEOF +#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1 +_ACEOF + +fi + +done + + +for ac_header in values.h +do +as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh` +if eval "test \"\${$as_ac_Header+set}\" = set"; then + echo "$as_me:$LINENO: checking for $ac_header" >&5 +echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6 +if eval "test \"\${$as_ac_Header+set}\" = set"; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +fi +echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5 +echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6 +else + # Is the header compilable? +echo "$as_me:$LINENO: checking $ac_header usability" >&5 +echo $ECHO_N "checking $ac_header usability... $ECHO_C" >&6 +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +#include <$ac_header> +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_header_compiler=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_header_compiler=no +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +echo "$as_me:$LINENO: result: $ac_header_compiler" >&5 +echo "${ECHO_T}$ac_header_compiler" >&6 + +# Is the header present? +echo "$as_me:$LINENO: checking $ac_header presence" >&5 +echo $ECHO_N "checking $ac_header presence... $ECHO_C" >&6 +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include <$ac_header> +_ACEOF +if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 + (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null; then + if test -s conftest.err; then + ac_cpp_err=$ac_c_preproc_warn_flag + ac_cpp_err=$ac_cpp_err$ac_c_werror_flag + else + ac_cpp_err= + fi +else + ac_cpp_err=yes +fi +if test -z "$ac_cpp_err"; then + ac_header_preproc=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_header_preproc=no +fi +rm -f conftest.err conftest.$ac_ext +echo "$as_me:$LINENO: result: $ac_header_preproc" >&5 +echo "${ECHO_T}$ac_header_preproc" >&6 + +# So? What about this header? +case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in + yes:no: ) + { echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5 +echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5 +echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;} + ac_header_preproc=yes + ;; + no:yes:* ) + { echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5 +echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: check for missing prerequisite headers?" >&5 +echo "$as_me: WARNING: $ac_header: check for missing prerequisite headers?" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5 +echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&5 +echo "$as_me: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5 +echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5 +echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;} + ( + cat <<\_ASBOX +## ----------------------------------- ## +## Report this to eric@cfa.harvard.edu ## +## ----------------------------------- ## +_ASBOX + ) | + sed "s/^/$as_me: WARNING: /" >&2 + ;; +esac +echo "$as_me:$LINENO: checking for $ac_header" >&5 +echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6 +if eval "test \"\${$as_ac_Header+set}\" = set"; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + eval "$as_ac_Header=\$ac_header_preproc" +fi +echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5 +echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6 + +fi +if test `eval echo '${'$as_ac_Header'}'` = yes; then + cat >>confdefs.h <<_ACEOF +#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1 +_ACEOF + +fi + +done + + +for ac_header in dlfcn.h +do +as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh` +if eval "test \"\${$as_ac_Header+set}\" = set"; then + echo "$as_me:$LINENO: checking for $ac_header" >&5 +echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6 +if eval "test \"\${$as_ac_Header+set}\" = set"; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +fi +echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5 +echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6 +else + # Is the header compilable? +echo "$as_me:$LINENO: checking $ac_header usability" >&5 +echo $ECHO_N "checking $ac_header usability... $ECHO_C" >&6 +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +#include <$ac_header> +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_header_compiler=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_header_compiler=no +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +echo "$as_me:$LINENO: result: $ac_header_compiler" >&5 +echo "${ECHO_T}$ac_header_compiler" >&6 + +# Is the header present? +echo "$as_me:$LINENO: checking $ac_header presence" >&5 +echo $ECHO_N "checking $ac_header presence... $ECHO_C" >&6 +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include <$ac_header> +_ACEOF +if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 + (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null; then + if test -s conftest.err; then + ac_cpp_err=$ac_c_preproc_warn_flag + ac_cpp_err=$ac_cpp_err$ac_c_werror_flag + else + ac_cpp_err= + fi +else + ac_cpp_err=yes +fi +if test -z "$ac_cpp_err"; then + ac_header_preproc=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_header_preproc=no +fi +rm -f conftest.err conftest.$ac_ext +echo "$as_me:$LINENO: result: $ac_header_preproc" >&5 +echo "${ECHO_T}$ac_header_preproc" >&6 + +# So? What about this header? +case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in + yes:no: ) + { echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5 +echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5 +echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;} + ac_header_preproc=yes + ;; + no:yes:* ) + { echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5 +echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: check for missing prerequisite headers?" >&5 +echo "$as_me: WARNING: $ac_header: check for missing prerequisite headers?" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5 +echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&5 +echo "$as_me: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5 +echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5 +echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;} + ( + cat <<\_ASBOX +## ----------------------------------- ## +## Report this to eric@cfa.harvard.edu ## +## ----------------------------------- ## +_ASBOX + ) | + sed "s/^/$as_me: WARNING: /" >&2 + ;; +esac +echo "$as_me:$LINENO: checking for $ac_header" >&5 +echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6 +if eval "test \"\${$as_ac_Header+set}\" = set"; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + eval "$as_ac_Header=\$ac_header_preproc" +fi +echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5 +echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6 + +fi +if test `eval echo '${'$as_ac_Header'}'` = yes; then + cat >>confdefs.h <<_ACEOF +#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1 +_ACEOF + +fi + +done + + +for ac_header in setjmp.h +do +as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh` +if eval "test \"\${$as_ac_Header+set}\" = set"; then + echo "$as_me:$LINENO: checking for $ac_header" >&5 +echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6 +if eval "test \"\${$as_ac_Header+set}\" = set"; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +fi +echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5 +echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6 +else + # Is the header compilable? +echo "$as_me:$LINENO: checking $ac_header usability" >&5 +echo $ECHO_N "checking $ac_header usability... $ECHO_C" >&6 +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +#include <$ac_header> +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_header_compiler=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_header_compiler=no +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +echo "$as_me:$LINENO: result: $ac_header_compiler" >&5 +echo "${ECHO_T}$ac_header_compiler" >&6 + +# Is the header present? +echo "$as_me:$LINENO: checking $ac_header presence" >&5 +echo $ECHO_N "checking $ac_header presence... $ECHO_C" >&6 +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include <$ac_header> +_ACEOF +if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 + (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null; then + if test -s conftest.err; then + ac_cpp_err=$ac_c_preproc_warn_flag + ac_cpp_err=$ac_cpp_err$ac_c_werror_flag + else + ac_cpp_err= + fi +else + ac_cpp_err=yes +fi +if test -z "$ac_cpp_err"; then + ac_header_preproc=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_header_preproc=no +fi +rm -f conftest.err conftest.$ac_ext +echo "$as_me:$LINENO: result: $ac_header_preproc" >&5 +echo "${ECHO_T}$ac_header_preproc" >&6 + +# So? What about this header? +case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in + yes:no: ) + { echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5 +echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5 +echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;} + ac_header_preproc=yes + ;; + no:yes:* ) + { echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5 +echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: check for missing prerequisite headers?" >&5 +echo "$as_me: WARNING: $ac_header: check for missing prerequisite headers?" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5 +echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&5 +echo "$as_me: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5 +echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5 +echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;} + ( + cat <<\_ASBOX +## ----------------------------------- ## +## Report this to eric@cfa.harvard.edu ## +## ----------------------------------- ## +_ASBOX + ) | + sed "s/^/$as_me: WARNING: /" >&2 + ;; +esac +echo "$as_me:$LINENO: checking for $ac_header" >&5 +echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6 +if eval "test \"\${$as_ac_Header+set}\" = set"; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + eval "$as_ac_Header=\$ac_header_preproc" +fi +echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5 +echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6 + +fi +if test `eval echo '${'$as_ac_Header'}'` = yes; then + cat >>confdefs.h <<_ACEOF +#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1 +_ACEOF + +fi + +done + + +for ac_header in sys/un.h +do +as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh` +if eval "test \"\${$as_ac_Header+set}\" = set"; then + echo "$as_me:$LINENO: checking for $ac_header" >&5 +echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6 +if eval "test \"\${$as_ac_Header+set}\" = set"; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +fi +echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5 +echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6 +else + # Is the header compilable? +echo "$as_me:$LINENO: checking $ac_header usability" >&5 +echo $ECHO_N "checking $ac_header usability... $ECHO_C" >&6 +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +#include <$ac_header> +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_header_compiler=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_header_compiler=no +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +echo "$as_me:$LINENO: result: $ac_header_compiler" >&5 +echo "${ECHO_T}$ac_header_compiler" >&6 + +# Is the header present? +echo "$as_me:$LINENO: checking $ac_header presence" >&5 +echo $ECHO_N "checking $ac_header presence... $ECHO_C" >&6 +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include <$ac_header> +_ACEOF +if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 + (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null; then + if test -s conftest.err; then + ac_cpp_err=$ac_c_preproc_warn_flag + ac_cpp_err=$ac_cpp_err$ac_c_werror_flag + else + ac_cpp_err= + fi +else + ac_cpp_err=yes +fi +if test -z "$ac_cpp_err"; then + ac_header_preproc=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_header_preproc=no +fi +rm -f conftest.err conftest.$ac_ext +echo "$as_me:$LINENO: result: $ac_header_preproc" >&5 +echo "${ECHO_T}$ac_header_preproc" >&6 + +# So? What about this header? +case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in + yes:no: ) + { echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5 +echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5 +echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;} + ac_header_preproc=yes + ;; + no:yes:* ) + { echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5 +echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: check for missing prerequisite headers?" >&5 +echo "$as_me: WARNING: $ac_header: check for missing prerequisite headers?" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5 +echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&5 +echo "$as_me: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5 +echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5 +echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;} + ( + cat <<\_ASBOX +## ----------------------------------- ## +## Report this to eric@cfa.harvard.edu ## +## ----------------------------------- ## +_ASBOX + ) | + sed "s/^/$as_me: WARNING: /" >&2 + ;; +esac +echo "$as_me:$LINENO: checking for $ac_header" >&5 +echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6 +if eval "test \"\${$as_ac_Header+set}\" = set"; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + eval "$as_ac_Header=\$ac_header_preproc" +fi +echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5 +echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6 + +fi +if test `eval echo '${'$as_ac_Header'}'` = yes; then + cat >>confdefs.h <<_ACEOF +#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1 +_ACEOF + +fi + +done + + +for ac_header in sys/shm.h +do +as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh` +if eval "test \"\${$as_ac_Header+set}\" = set"; then + echo "$as_me:$LINENO: checking for $ac_header" >&5 +echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6 +if eval "test \"\${$as_ac_Header+set}\" = set"; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +fi +echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5 +echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6 +else + # Is the header compilable? +echo "$as_me:$LINENO: checking $ac_header usability" >&5 +echo $ECHO_N "checking $ac_header usability... $ECHO_C" >&6 +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +#include <$ac_header> +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_header_compiler=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_header_compiler=no +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +echo "$as_me:$LINENO: result: $ac_header_compiler" >&5 +echo "${ECHO_T}$ac_header_compiler" >&6 + +# Is the header present? +echo "$as_me:$LINENO: checking $ac_header presence" >&5 +echo $ECHO_N "checking $ac_header presence... $ECHO_C" >&6 +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include <$ac_header> +_ACEOF +if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 + (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null; then + if test -s conftest.err; then + ac_cpp_err=$ac_c_preproc_warn_flag + ac_cpp_err=$ac_cpp_err$ac_c_werror_flag + else + ac_cpp_err= + fi +else + ac_cpp_err=yes +fi +if test -z "$ac_cpp_err"; then + ac_header_preproc=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_header_preproc=no +fi +rm -f conftest.err conftest.$ac_ext +echo "$as_me:$LINENO: result: $ac_header_preproc" >&5 +echo "${ECHO_T}$ac_header_preproc" >&6 + +# So? What about this header? +case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in + yes:no: ) + { echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5 +echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5 +echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;} + ac_header_preproc=yes + ;; + no:yes:* ) + { echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5 +echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: check for missing prerequisite headers?" >&5 +echo "$as_me: WARNING: $ac_header: check for missing prerequisite headers?" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5 +echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&5 +echo "$as_me: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5 +echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5 +echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;} + ( + cat <<\_ASBOX +## ----------------------------------- ## +## Report this to eric@cfa.harvard.edu ## +## ----------------------------------- ## +_ASBOX + ) | + sed "s/^/$as_me: WARNING: /" >&2 + ;; +esac +echo "$as_me:$LINENO: checking for $ac_header" >&5 +echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6 +if eval "test \"\${$as_ac_Header+set}\" = set"; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + eval "$as_ac_Header=\$ac_header_preproc" +fi +echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5 +echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6 + +fi +if test `eval echo '${'$as_ac_Header'}'` = yes; then + cat >>confdefs.h <<_ACEOF +#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1 +_ACEOF + +fi + +done + + +for ac_header in sys/mman.h +do +as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh` +if eval "test \"\${$as_ac_Header+set}\" = set"; then + echo "$as_me:$LINENO: checking for $ac_header" >&5 +echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6 +if eval "test \"\${$as_ac_Header+set}\" = set"; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +fi +echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5 +echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6 +else + # Is the header compilable? +echo "$as_me:$LINENO: checking $ac_header usability" >&5 +echo $ECHO_N "checking $ac_header usability... $ECHO_C" >&6 +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +#include <$ac_header> +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_header_compiler=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_header_compiler=no +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +echo "$as_me:$LINENO: result: $ac_header_compiler" >&5 +echo "${ECHO_T}$ac_header_compiler" >&6 + +# Is the header present? +echo "$as_me:$LINENO: checking $ac_header presence" >&5 +echo $ECHO_N "checking $ac_header presence... $ECHO_C" >&6 +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include <$ac_header> +_ACEOF +if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 + (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null; then + if test -s conftest.err; then + ac_cpp_err=$ac_c_preproc_warn_flag + ac_cpp_err=$ac_cpp_err$ac_c_werror_flag + else + ac_cpp_err= + fi +else + ac_cpp_err=yes +fi +if test -z "$ac_cpp_err"; then + ac_header_preproc=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_header_preproc=no +fi +rm -f conftest.err conftest.$ac_ext +echo "$as_me:$LINENO: result: $ac_header_preproc" >&5 +echo "${ECHO_T}$ac_header_preproc" >&6 + +# So? What about this header? +case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in + yes:no: ) + { echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5 +echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5 +echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;} + ac_header_preproc=yes + ;; + no:yes:* ) + { echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5 +echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: check for missing prerequisite headers?" >&5 +echo "$as_me: WARNING: $ac_header: check for missing prerequisite headers?" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5 +echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&5 +echo "$as_me: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5 +echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5 +echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;} + ( + cat <<\_ASBOX +## ----------------------------------- ## +## Report this to eric@cfa.harvard.edu ## +## ----------------------------------- ## +_ASBOX + ) | + sed "s/^/$as_me: WARNING: /" >&2 + ;; +esac +echo "$as_me:$LINENO: checking for $ac_header" >&5 +echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6 +if eval "test \"\${$as_ac_Header+set}\" = set"; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + eval "$as_ac_Header=\$ac_header_preproc" +fi +echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5 +echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6 + +fi +if test `eval echo '${'$as_ac_Header'}'` = yes; then + cat >>confdefs.h <<_ACEOF +#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1 +_ACEOF + +fi + +done + + +for ac_header in sys/ipc.h +do +as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh` +if eval "test \"\${$as_ac_Header+set}\" = set"; then + echo "$as_me:$LINENO: checking for $ac_header" >&5 +echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6 +if eval "test \"\${$as_ac_Header+set}\" = set"; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +fi +echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5 +echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6 +else + # Is the header compilable? +echo "$as_me:$LINENO: checking $ac_header usability" >&5 +echo $ECHO_N "checking $ac_header usability... $ECHO_C" >&6 +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +#include <$ac_header> +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_header_compiler=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_header_compiler=no +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +echo "$as_me:$LINENO: result: $ac_header_compiler" >&5 +echo "${ECHO_T}$ac_header_compiler" >&6 + +# Is the header present? +echo "$as_me:$LINENO: checking $ac_header presence" >&5 +echo $ECHO_N "checking $ac_header presence... $ECHO_C" >&6 +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include <$ac_header> +_ACEOF +if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 + (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null; then + if test -s conftest.err; then + ac_cpp_err=$ac_c_preproc_warn_flag + ac_cpp_err=$ac_cpp_err$ac_c_werror_flag + else + ac_cpp_err= + fi +else + ac_cpp_err=yes +fi +if test -z "$ac_cpp_err"; then + ac_header_preproc=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_header_preproc=no +fi +rm -f conftest.err conftest.$ac_ext +echo "$as_me:$LINENO: result: $ac_header_preproc" >&5 +echo "${ECHO_T}$ac_header_preproc" >&6 + +# So? What about this header? +case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in + yes:no: ) + { echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5 +echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5 +echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;} + ac_header_preproc=yes + ;; + no:yes:* ) + { echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5 +echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: check for missing prerequisite headers?" >&5 +echo "$as_me: WARNING: $ac_header: check for missing prerequisite headers?" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5 +echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&5 +echo "$as_me: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5 +echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5 +echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;} + ( + cat <<\_ASBOX +## ----------------------------------- ## +## Report this to eric@cfa.harvard.edu ## +## ----------------------------------- ## +_ASBOX + ) | + sed "s/^/$as_me: WARNING: /" >&2 + ;; +esac +echo "$as_me:$LINENO: checking for $ac_header" >&5 +echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6 +if eval "test \"\${$as_ac_Header+set}\" = set"; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + eval "$as_ac_Header=\$ac_header_preproc" +fi +echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5 +echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6 + +fi +if test `eval echo '${'$as_ac_Header'}'` = yes; then + cat >>confdefs.h <<_ACEOF +#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1 +_ACEOF + +fi + +done + + +for ac_header in sys/select.h +do +as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh` +if eval "test \"\${$as_ac_Header+set}\" = set"; then + echo "$as_me:$LINENO: checking for $ac_header" >&5 +echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6 +if eval "test \"\${$as_ac_Header+set}\" = set"; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +fi +echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5 +echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6 +else + # Is the header compilable? +echo "$as_me:$LINENO: checking $ac_header usability" >&5 +echo $ECHO_N "checking $ac_header usability... $ECHO_C" >&6 +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +#include <$ac_header> +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_header_compiler=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_header_compiler=no +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +echo "$as_me:$LINENO: result: $ac_header_compiler" >&5 +echo "${ECHO_T}$ac_header_compiler" >&6 + +# Is the header present? +echo "$as_me:$LINENO: checking $ac_header presence" >&5 +echo $ECHO_N "checking $ac_header presence... $ECHO_C" >&6 +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include <$ac_header> +_ACEOF +if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 + (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null; then + if test -s conftest.err; then + ac_cpp_err=$ac_c_preproc_warn_flag + ac_cpp_err=$ac_cpp_err$ac_c_werror_flag + else + ac_cpp_err= + fi +else + ac_cpp_err=yes +fi +if test -z "$ac_cpp_err"; then + ac_header_preproc=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_header_preproc=no +fi +rm -f conftest.err conftest.$ac_ext +echo "$as_me:$LINENO: result: $ac_header_preproc" >&5 +echo "${ECHO_T}$ac_header_preproc" >&6 + +# So? What about this header? +case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in + yes:no: ) + { echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5 +echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5 +echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;} + ac_header_preproc=yes + ;; + no:yes:* ) + { echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5 +echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: check for missing prerequisite headers?" >&5 +echo "$as_me: WARNING: $ac_header: check for missing prerequisite headers?" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5 +echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&5 +echo "$as_me: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5 +echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5 +echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;} + ( + cat <<\_ASBOX +## ----------------------------------- ## +## Report this to eric@cfa.harvard.edu ## +## ----------------------------------- ## +_ASBOX + ) | + sed "s/^/$as_me: WARNING: /" >&2 + ;; +esac +echo "$as_me:$LINENO: checking for $ac_header" >&5 +echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6 +if eval "test \"\${$as_ac_Header+set}\" = set"; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + eval "$as_ac_Header=\$ac_header_preproc" +fi +echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5 +echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6 + +fi +if test `eval echo '${'$as_ac_Header'}'` = yes; then + cat >>confdefs.h <<_ACEOF +#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1 +_ACEOF + +fi + +done + + +echo "$as_me:$LINENO: checking for socklen_t" >&5 +echo $ECHO_N "checking for socklen_t... $ECHO_C" >&6 +if test "${ac_cv_type_socklen_t+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include <sys/socket.h> + +int +main () +{ +if ((socklen_t *) 0) + return 0; +if (sizeof (socklen_t)) + return 0; + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_type_socklen_t=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_cv_type_socklen_t=no +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +fi +echo "$as_me:$LINENO: result: $ac_cv_type_socklen_t" >&5 +echo "${ECHO_T}$ac_cv_type_socklen_t" >&6 +if test $ac_cv_type_socklen_t = yes; then + +cat >>confdefs.h <<_ACEOF +#define HAVE_SOCKLEN_T 1 +_ACEOF + + +fi + + +echo "$as_me:$LINENO: checking for an ANSI C-conforming const" >&5 +echo $ECHO_N "checking for an ANSI C-conforming const... $ECHO_C" >&6 +if test "${ac_cv_c_const+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ +/* FIXME: Include the comments suggested by Paul. */ +#ifndef __cplusplus + /* Ultrix mips cc rejects this. */ + typedef int charset[2]; + const charset x; + /* SunOS 4.1.1 cc rejects this. */ + char const *const *ccp; + char **p; + /* NEC SVR4.0.2 mips cc rejects this. */ + struct point {int x, y;}; + static struct point const zero = {0,0}; + /* AIX XL C 1.02.0.0 rejects this. + It does not let you subtract one const X* pointer from another in + an arm of an if-expression whose if-part is not a constant + expression */ + const char *g = "string"; + ccp = &g + (g ? g-g : 0); + /* HPUX 7.0 cc rejects these. */ + ++ccp; + p = (char**) ccp; + ccp = (char const *const *) p; + { /* SCO 3.2v4 cc rejects this. */ + char *t; + char const *s = 0 ? (char *) 0 : (char const *) 0; + + *t++ = 0; + } + { /* Someone thinks the Sun supposedly-ANSI compiler will reject this. */ + int x[] = {25, 17}; + const int *foo = &x[0]; + ++foo; + } + { /* Sun SC1.0 ANSI compiler rejects this -- but not the above. */ + typedef const int *iptr; + iptr p = 0; + ++p; + } + { /* AIX XL C 1.02.0.0 rejects this saying + "k.c", line 2.27: 1506-025 (S) Operand must be a modifiable lvalue. */ + struct s { int j; const int *ap[3]; }; + struct s *b; b->j = 5; + } + { /* ULTRIX-32 V3.1 (Rev 9) vcc rejects this */ + const int foo = 10; + } +#endif + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_c_const=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_cv_c_const=no +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +fi +echo "$as_me:$LINENO: result: $ac_cv_c_const" >&5 +echo "${ECHO_T}$ac_cv_c_const" >&6 +if test $ac_cv_c_const = no; then + +cat >>confdefs.h <<\_ACEOF +#define const +_ACEOF + +fi + + + + + + + +for ac_func in strchr memcpy snprintf atexit setenv +do +as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh` +echo "$as_me:$LINENO: checking for $ac_func" >&5 +echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6 +if eval "test \"\${$as_ac_var+set}\" = set"; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +/* Define $ac_func to an innocuous variant, in case <limits.h> declares $ac_func. + For example, HP-UX 11i <limits.h> declares gettimeofday. */ +#define $ac_func innocuous_$ac_func + +/* System header to define __stub macros and hopefully few prototypes, + which can conflict with char $ac_func (); below. + Prefer <limits.h> to <assert.h> if __STDC__ is defined, since + <limits.h> exists even on freestanding compilers. */ + +#ifdef __STDC__ +# include <limits.h> +#else +# include <assert.h> +#endif + +#undef $ac_func + +/* Override any gcc2 internal prototype to avoid an error. */ +#ifdef __cplusplus +extern "C" +{ +#endif +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char $ac_func (); +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined (__stub_$ac_func) || defined (__stub___$ac_func) +choke me +#else +char (*f) () = $ac_func; +#endif +#ifdef __cplusplus +} +#endif + +int +main () +{ +return f != $ac_func; + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + eval "$as_ac_var=yes" +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +eval "$as_ac_var=no" +fi +rm -f conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +fi +echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_var'}'`" >&5 +echo "${ECHO_T}`eval echo '${'$as_ac_var'}'`" >&6 +if test `eval echo '${'$as_ac_var'}'` = yes; then + cat >>confdefs.h <<_ACEOF +#define `echo "HAVE_$ac_func" | $as_tr_cpp` 1 +_ACEOF + +fi +done + + +echo "$as_me:$LINENO: checking for connect" >&5 +echo $ECHO_N "checking for connect... $ECHO_C" >&6 +if test "${ac_cv_func_connect+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +/* Define connect to an innocuous variant, in case <limits.h> declares connect. + For example, HP-UX 11i <limits.h> declares gettimeofday. */ +#define connect innocuous_connect + +/* System header to define __stub macros and hopefully few prototypes, + which can conflict with char connect (); below. + Prefer <limits.h> to <assert.h> if __STDC__ is defined, since + <limits.h> exists even on freestanding compilers. */ + +#ifdef __STDC__ +# include <limits.h> +#else +# include <assert.h> +#endif + +#undef connect + +/* Override any gcc2 internal prototype to avoid an error. */ +#ifdef __cplusplus +extern "C" +{ +#endif +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char connect (); +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined (__stub_connect) || defined (__stub___connect) +choke me +#else +char (*f) () = connect; +#endif +#ifdef __cplusplus +} +#endif + +int +main () +{ +return f != connect; + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_func_connect=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_cv_func_connect=no +fi +rm -f conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +fi +echo "$as_me:$LINENO: result: $ac_cv_func_connect" >&5 +echo "${ECHO_T}$ac_cv_func_connect" >&6 + +if test $ac_cv_func_connect = no; then + echo "$as_me:$LINENO: checking for connect in -lsocket" >&5 +echo $ECHO_N "checking for connect in -lsocket... $ECHO_C" >&6 +if test "${ac_cv_lib_socket_connect+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lsocket $LIBS" +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +/* Override any gcc2 internal prototype to avoid an error. */ +#ifdef __cplusplus +extern "C" +#endif +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char connect (); +int +main () +{ +connect (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_lib_socket_connect=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_cv_lib_socket_connect=no +fi +rm -f conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +echo "$as_me:$LINENO: result: $ac_cv_lib_socket_connect" >&5 +echo "${ECHO_T}$ac_cv_lib_socket_connect" >&6 +if test $ac_cv_lib_socket_connect = yes; then + EXTRA_LIBS="$EXTRA_LIBS -lsocket" +fi + +fi +echo "$as_me:$LINENO: checking for gethostbyname" >&5 +echo $ECHO_N "checking for gethostbyname... $ECHO_C" >&6 +if test "${ac_cv_func_gethostbyname+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +/* Define gethostbyname to an innocuous variant, in case <limits.h> declares gethostbyname. + For example, HP-UX 11i <limits.h> declares gettimeofday. */ +#define gethostbyname innocuous_gethostbyname + +/* System header to define __stub macros and hopefully few prototypes, + which can conflict with char gethostbyname (); below. + Prefer <limits.h> to <assert.h> if __STDC__ is defined, since + <limits.h> exists even on freestanding compilers. */ + +#ifdef __STDC__ +# include <limits.h> +#else +# include <assert.h> +#endif + +#undef gethostbyname + +/* Override any gcc2 internal prototype to avoid an error. */ +#ifdef __cplusplus +extern "C" +{ +#endif +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char gethostbyname (); +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined (__stub_gethostbyname) || defined (__stub___gethostbyname) +choke me +#else +char (*f) () = gethostbyname; +#endif +#ifdef __cplusplus +} +#endif + +int +main () +{ +return f != gethostbyname; + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_func_gethostbyname=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_cv_func_gethostbyname=no +fi +rm -f conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +fi +echo "$as_me:$LINENO: result: $ac_cv_func_gethostbyname" >&5 +echo "${ECHO_T}$ac_cv_func_gethostbyname" >&6 + +if test $ac_cv_func_gethostbyname = no; then + echo "$as_me:$LINENO: checking for gethostbyname in -lnsl" >&5 +echo $ECHO_N "checking for gethostbyname in -lnsl... $ECHO_C" >&6 +if test "${ac_cv_lib_nsl_gethostbyname+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lnsl $LIBS" +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +/* Override any gcc2 internal prototype to avoid an error. */ +#ifdef __cplusplus +extern "C" +#endif +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char gethostbyname (); +int +main () +{ +gethostbyname (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_lib_nsl_gethostbyname=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_cv_lib_nsl_gethostbyname=no +fi +rm -f conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +echo "$as_me:$LINENO: result: $ac_cv_lib_nsl_gethostbyname" >&5 +echo "${ECHO_T}$ac_cv_lib_nsl_gethostbyname" >&6 +if test $ac_cv_lib_nsl_gethostbyname = yes; then + EXTRA_LIBS="$EXTRA_LIBS -lnsl" +fi + +fi +# AC_CHECK_LIB(db, snprintf, EXTRA_LIBS="$EXTRA_LIBS -ldb") + +# +# checks specific to this project +# + +echo "$as_me:$LINENO: checking for threaded xpans" >&5 +echo $ECHO_N "checking for threaded xpans... $ECHO_C" >&6 +# Check whether --enable-threaded-xpans or --disable-threaded-xpans was given. +if test "${enable_threaded_xpans+set}" = set; then + enableval="$enable_threaded_xpans" + fun_ok=$enableval +else + fun_ok=no +fi; +if test "$fun_ok" = "yes"; then + echo "$as_me:$LINENO: result: $fun_ok" >&5 +echo "${ECHO_T}$fun_ok" >&6 + echo "$as_me:$LINENO: checking for pthread_create in -lpthread" >&5 +echo $ECHO_N "checking for pthread_create in -lpthread... $ECHO_C" >&6 +if test "${ac_cv_lib_pthread_pthread_create+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lpthread $LIBS" +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +/* Override any gcc2 internal prototype to avoid an error. */ +#ifdef __cplusplus +extern "C" +#endif +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char pthread_create (); +int +main () +{ +pthread_create (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_lib_pthread_pthread_create=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_cv_lib_pthread_pthread_create=no +fi +rm -f conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +echo "$as_me:$LINENO: result: $ac_cv_lib_pthread_pthread_create" >&5 +echo "${ECHO_T}$ac_cv_lib_pthread_pthread_create" >&6 +if test $ac_cv_lib_pthread_pthread_create = yes; then + have_pthread=yes +fi + + if test x"${have_pthread}" = x"yes"; then + cat >>confdefs.h <<\_ACEOF +#define HAVE_LIBPTHREAD 1 +_ACEOF + + cat >>confdefs.h <<\_ACEOF +#define _REENTRANT 1 +_ACEOF + + TLIB="-lpthread" + else + { { echo "$as_me:$LINENO: error: no threads found ... can't use enable-threaded-xpans" >&5 +echo "$as_me: error: no threads found ... can't use enable-threaded-xpans" >&2;} + { (exit 1); exit 1; }; } + fi +else + echo "$as_me:$LINENO: result: $fun_ok" >&5 +echo "${ECHO_T}$fun_ok" >&6 +fi + + +echo "$as_me:$LINENO: checking for shared library build" >&5 +echo $ECHO_N "checking for shared library build... $ECHO_C" >&6 +# Check whether --enable-shared or --disable-shared was given. +if test "${enable_shared+set}" = set; then + enableval="$enable_shared" + fun_ok=$enableval +else + fun_ok=no +fi; +if test "$fun_ok" != "no"; then + fpic="yes" + DOSHARED=shlib + + if test "$fun_ok" = "link"; then + LLIB="-L. -l$PACKAGE_NAME" + else + LLIB='$(LIB)' + fi +else + DOSHARED="" + LLIB='$(LIB)' +fi + +echo "$as_me:$LINENO: result: $fun_ok" >&5 +echo "${ECHO_T}$fun_ok" >&6 + +echo "$as_me:$LINENO: checking for request to use posix_spawn" >&5 +echo $ECHO_N "checking for request to use posix_spawn... $ECHO_C" >&6 +# Check whether --enable-posix_spawn or --disable-posix_spawn was given. +if test "${enable_posix_spawn+set}" = set; then + enableval="$enable_posix_spawn" + fun_ok=$enableval +else + fun_ok=no +fi; +echo "$as_me:$LINENO: result: $fun_ok" >&5 +echo "${ECHO_T}$fun_ok" >&6 +if test "$fun_ok" = "yes"; then + + +for ac_func in posix_spawn _NSGetEnviron +do +as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh` +echo "$as_me:$LINENO: checking for $ac_func" >&5 +echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6 +if eval "test \"\${$as_ac_var+set}\" = set"; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +/* Define $ac_func to an innocuous variant, in case <limits.h> declares $ac_func. + For example, HP-UX 11i <limits.h> declares gettimeofday. */ +#define $ac_func innocuous_$ac_func + +/* System header to define __stub macros and hopefully few prototypes, + which can conflict with char $ac_func (); below. + Prefer <limits.h> to <assert.h> if __STDC__ is defined, since + <limits.h> exists even on freestanding compilers. */ + +#ifdef __STDC__ +# include <limits.h> +#else +# include <assert.h> +#endif + +#undef $ac_func + +/* Override any gcc2 internal prototype to avoid an error. */ +#ifdef __cplusplus +extern "C" +{ +#endif +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char $ac_func (); +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined (__stub_$ac_func) || defined (__stub___$ac_func) +choke me +#else +char (*f) () = $ac_func; +#endif +#ifdef __cplusplus +} +#endif + +int +main () +{ +return f != $ac_func; + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + eval "$as_ac_var=yes" +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +eval "$as_ac_var=no" +fi +rm -f conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +fi +echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_var'}'`" >&5 +echo "${ECHO_T}`eval echo '${'$as_ac_var'}'`" >&6 +if test `eval echo '${'$as_ac_var'}'` = yes; then + cat >>confdefs.h <<_ACEOF +#define `echo "HAVE_$ac_func" | $as_tr_cpp` 1 +_ACEOF + +fi +done + + +for ac_header in crt_externs.h +do +as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh` +if eval "test \"\${$as_ac_Header+set}\" = set"; then + echo "$as_me:$LINENO: checking for $ac_header" >&5 +echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6 +if eval "test \"\${$as_ac_Header+set}\" = set"; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +fi +echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5 +echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6 +else + # Is the header compilable? +echo "$as_me:$LINENO: checking $ac_header usability" >&5 +echo $ECHO_N "checking $ac_header usability... $ECHO_C" >&6 +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +#include <$ac_header> +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_header_compiler=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_header_compiler=no +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +echo "$as_me:$LINENO: result: $ac_header_compiler" >&5 +echo "${ECHO_T}$ac_header_compiler" >&6 + +# Is the header present? +echo "$as_me:$LINENO: checking $ac_header presence" >&5 +echo $ECHO_N "checking $ac_header presence... $ECHO_C" >&6 +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include <$ac_header> +_ACEOF +if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 + (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null; then + if test -s conftest.err; then + ac_cpp_err=$ac_c_preproc_warn_flag + ac_cpp_err=$ac_cpp_err$ac_c_werror_flag + else + ac_cpp_err= + fi +else + ac_cpp_err=yes +fi +if test -z "$ac_cpp_err"; then + ac_header_preproc=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_header_preproc=no +fi +rm -f conftest.err conftest.$ac_ext +echo "$as_me:$LINENO: result: $ac_header_preproc" >&5 +echo "${ECHO_T}$ac_header_preproc" >&6 + +# So? What about this header? +case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in + yes:no: ) + { echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5 +echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5 +echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;} + ac_header_preproc=yes + ;; + no:yes:* ) + { echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5 +echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: check for missing prerequisite headers?" >&5 +echo "$as_me: WARNING: $ac_header: check for missing prerequisite headers?" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5 +echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&5 +echo "$as_me: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5 +echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5 +echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;} + ( + cat <<\_ASBOX +## ----------------------------------- ## +## Report this to eric@cfa.harvard.edu ## +## ----------------------------------- ## +_ASBOX + ) | + sed "s/^/$as_me: WARNING: /" >&2 + ;; +esac +echo "$as_me:$LINENO: checking for $ac_header" >&5 +echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6 +if eval "test \"\${$as_ac_Header+set}\" = set"; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + eval "$as_ac_Header=\$ac_header_preproc" +fi +echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5 +echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6 + +fi +if test `eval echo '${'$as_ac_Header'}'` = yes; then + cat >>confdefs.h <<_ACEOF +#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1 +_ACEOF + +fi + +done + +fi + +echo "$as_me:$LINENO: checking for X" >&5 +echo $ECHO_N "checking for X... $ECHO_C" >&6 + + +# Check whether --with-x or --without-x was given. +if test "${with_x+set}" = set; then + withval="$with_x" + +fi; +# $have_x is `yes', `no', `disabled', or empty when we do not yet know. +if test "x$with_x" = xno; then + # The user explicitly disabled X. + have_x=disabled +else + if test "x$x_includes" != xNONE && test "x$x_libraries" != xNONE; then + # Both variables are already set. + have_x=yes + else + if test "${ac_cv_have_x+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + # One or both of the vars are not set, and there is no cached value. +ac_x_includes=no ac_x_libraries=no +rm -fr conftest.dir +if mkdir conftest.dir; then + cd conftest.dir + # Make sure to not put "make" in the Imakefile rules, since we grep it out. + cat >Imakefile <<'_ACEOF' +acfindx: + @echo 'ac_im_incroot="${INCROOT}"; ac_im_usrlibdir="${USRLIBDIR}"; ac_im_libdir="${LIBDIR}"' +_ACEOF + if (xmkmf) >/dev/null 2>/dev/null && test -f Makefile; then + # GNU make sometimes prints "make[1]: Entering...", which would confuse us. + eval `${MAKE-make} acfindx 2>/dev/null | grep -v make` + # Open Windows xmkmf reportedly sets LIBDIR instead of USRLIBDIR. + for ac_extension in a so sl; do + if test ! -f $ac_im_usrlibdir/libX11.$ac_extension && + test -f $ac_im_libdir/libX11.$ac_extension; then + ac_im_usrlibdir=$ac_im_libdir; break + fi + done + # Screen out bogus values from the imake configuration. They are + # bogus both because they are the default anyway, and because + # using them would break gcc on systems where it needs fixed includes. + case $ac_im_incroot in + /usr/include) ;; + *) test -f "$ac_im_incroot/X11/Xos.h" && ac_x_includes=$ac_im_incroot;; + esac + case $ac_im_usrlibdir in + /usr/lib | /lib) ;; + *) test -d "$ac_im_usrlibdir" && ac_x_libraries=$ac_im_usrlibdir ;; + esac + fi + cd .. + rm -fr conftest.dir +fi + +# Standard set of common directories for X headers. +# Check X11 before X11Rn because it is often a symlink to the current release. +ac_x_header_dirs=' +/usr/X11/include +/usr/X11R6/include +/usr/X11R5/include +/usr/X11R4/include + +/usr/include/X11 +/usr/include/X11R6 +/usr/include/X11R5 +/usr/include/X11R4 + +/usr/local/X11/include +/usr/local/X11R6/include +/usr/local/X11R5/include +/usr/local/X11R4/include + +/usr/local/include/X11 +/usr/local/include/X11R6 +/usr/local/include/X11R5 +/usr/local/include/X11R4 + +/usr/X386/include +/usr/x386/include +/usr/XFree86/include/X11 + +/usr/include +/usr/local/include +/usr/unsupported/include +/usr/athena/include +/usr/local/x11r5/include +/usr/lpp/Xamples/include + +/usr/openwin/include +/usr/openwin/share/include' + +if test "$ac_x_includes" = no; then + # Guess where to find include files, by looking for Intrinsic.h. + # First, try using that file with no special directory specified. + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include <X11/Intrinsic.h> +_ACEOF +if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 + (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null; then + if test -s conftest.err; then + ac_cpp_err=$ac_c_preproc_warn_flag + ac_cpp_err=$ac_cpp_err$ac_c_werror_flag + else + ac_cpp_err= + fi +else + ac_cpp_err=yes +fi +if test -z "$ac_cpp_err"; then + # We can compile using X headers with no special include directory. +ac_x_includes= +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + for ac_dir in $ac_x_header_dirs; do + if test -r "$ac_dir/X11/Intrinsic.h"; then + ac_x_includes=$ac_dir + break + fi +done +fi +rm -f conftest.err conftest.$ac_ext +fi # $ac_x_includes = no + +if test "$ac_x_libraries" = no; then + # Check for the libraries. + # See if we find them without any special options. + # Don't add to $LIBS permanently. + ac_save_LIBS=$LIBS + LIBS="-lXt $LIBS" + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include <X11/Intrinsic.h> +int +main () +{ +XtMalloc (0) + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + LIBS=$ac_save_LIBS +# We can link X programs with no special library path. +ac_x_libraries= +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +LIBS=$ac_save_LIBS +for ac_dir in `echo "$ac_x_includes $ac_x_header_dirs" | sed s/include/lib/g` +do + # Don't even attempt the hair of trying to link an X program! + for ac_extension in a so sl; do + if test -r $ac_dir/libXt.$ac_extension; then + ac_x_libraries=$ac_dir + break 2 + fi + done +done +fi +rm -f conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +fi # $ac_x_libraries = no + +if test "$ac_x_includes" = no || test "$ac_x_libraries" = no; then + # Didn't find X anywhere. Cache the known absence of X. + ac_cv_have_x="have_x=no" +else + # Record where we found X for the cache. + ac_cv_have_x="have_x=yes \ + ac_x_includes=$ac_x_includes ac_x_libraries=$ac_x_libraries" +fi +fi + + fi + eval "$ac_cv_have_x" +fi # $with_x != no + +if test "$have_x" != yes; then + echo "$as_me:$LINENO: result: $have_x" >&5 +echo "${ECHO_T}$have_x" >&6 + no_x=yes +else + # If each of the values was on the command line, it overrides each guess. + test "x$x_includes" = xNONE && x_includes=$ac_x_includes + test "x$x_libraries" = xNONE && x_libraries=$ac_x_libraries + # Update the cache value to reflect the command line values. + ac_cv_have_x="have_x=yes \ + ac_x_includes=$x_includes ac_x_libraries=$x_libraries" + echo "$as_me:$LINENO: result: libraries $x_libraries, headers $x_includes" >&5 +echo "${ECHO_T}libraries $x_libraries, headers $x_includes" >&6 +fi + +if test "$no_x" = yes; then + # Not all programs may use this symbol, but it does not hurt to define it. + +cat >>confdefs.h <<\_ACEOF +#define X_DISPLAY_MISSING 1 +_ACEOF + + X_CFLAGS= X_PRE_LIBS= X_LIBS= X_EXTRA_LIBS= +else + if test -n "$x_includes"; then + X_CFLAGS="$X_CFLAGS -I$x_includes" + fi + + # It would also be nice to do this for all -L options, not just this one. + if test -n "$x_libraries"; then + X_LIBS="$X_LIBS -L$x_libraries" + # For Solaris; some versions of Sun CC require a space after -R and + # others require no space. Words are not sufficient . . . . + case `(uname -sr) 2>/dev/null` in + "SunOS 5"*) + echo "$as_me:$LINENO: checking whether -R must be followed by a space" >&5 +echo $ECHO_N "checking whether -R must be followed by a space... $ECHO_C" >&6 + ac_xsave_LIBS=$LIBS; LIBS="$LIBS -R$x_libraries" + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_R_nospace=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_R_nospace=no +fi +rm -f conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + if test $ac_R_nospace = yes; then + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 + X_LIBS="$X_LIBS -R$x_libraries" + else + LIBS="$ac_xsave_LIBS -R $x_libraries" + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_R_space=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_R_space=no +fi +rm -f conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + if test $ac_R_space = yes; then + echo "$as_me:$LINENO: result: yes" >&5 +echo "${ECHO_T}yes" >&6 + X_LIBS="$X_LIBS -R $x_libraries" + else + echo "$as_me:$LINENO: result: neither works" >&5 +echo "${ECHO_T}neither works" >&6 + fi + fi + LIBS=$ac_xsave_LIBS + esac + fi + + # Check for system-dependent libraries X programs must link with. + # Do this before checking for the system-independent R6 libraries + # (-lICE), since we may need -lsocket or whatever for X linking. + + if test "$ISC" = yes; then + X_EXTRA_LIBS="$X_EXTRA_LIBS -lnsl_s -linet" + else + # Martyn Johnson says this is needed for Ultrix, if the X + # libraries were built with DECnet support. And Karl Berry says + # the Alpha needs dnet_stub (dnet does not exist). + ac_xsave_LIBS="$LIBS"; LIBS="$LIBS $X_LIBS -lX11" + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +/* Override any gcc2 internal prototype to avoid an error. */ +#ifdef __cplusplus +extern "C" +#endif +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char XOpenDisplay (); +int +main () +{ +XOpenDisplay (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + : +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +echo "$as_me:$LINENO: checking for dnet_ntoa in -ldnet" >&5 +echo $ECHO_N "checking for dnet_ntoa in -ldnet... $ECHO_C" >&6 +if test "${ac_cv_lib_dnet_dnet_ntoa+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-ldnet $LIBS" +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +/* Override any gcc2 internal prototype to avoid an error. */ +#ifdef __cplusplus +extern "C" +#endif +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char dnet_ntoa (); +int +main () +{ +dnet_ntoa (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_lib_dnet_dnet_ntoa=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_cv_lib_dnet_dnet_ntoa=no +fi +rm -f conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +echo "$as_me:$LINENO: result: $ac_cv_lib_dnet_dnet_ntoa" >&5 +echo "${ECHO_T}$ac_cv_lib_dnet_dnet_ntoa" >&6 +if test $ac_cv_lib_dnet_dnet_ntoa = yes; then + X_EXTRA_LIBS="$X_EXTRA_LIBS -ldnet" +fi + + if test $ac_cv_lib_dnet_dnet_ntoa = no; then + echo "$as_me:$LINENO: checking for dnet_ntoa in -ldnet_stub" >&5 +echo $ECHO_N "checking for dnet_ntoa in -ldnet_stub... $ECHO_C" >&6 +if test "${ac_cv_lib_dnet_stub_dnet_ntoa+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-ldnet_stub $LIBS" +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +/* Override any gcc2 internal prototype to avoid an error. */ +#ifdef __cplusplus +extern "C" +#endif +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char dnet_ntoa (); +int +main () +{ +dnet_ntoa (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_lib_dnet_stub_dnet_ntoa=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_cv_lib_dnet_stub_dnet_ntoa=no +fi +rm -f conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +echo "$as_me:$LINENO: result: $ac_cv_lib_dnet_stub_dnet_ntoa" >&5 +echo "${ECHO_T}$ac_cv_lib_dnet_stub_dnet_ntoa" >&6 +if test $ac_cv_lib_dnet_stub_dnet_ntoa = yes; then + X_EXTRA_LIBS="$X_EXTRA_LIBS -ldnet_stub" +fi + + fi +fi +rm -f conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + LIBS="$ac_xsave_LIBS" + + # msh@cis.ufl.edu says -lnsl (and -lsocket) are needed for his 386/AT, + # to get the SysV transport functions. + # Chad R. Larson says the Pyramis MIS-ES running DC/OSx (SVR4) + # needs -lnsl. + # The nsl library prevents programs from opening the X display + # on Irix 5.2, according to T.E. Dickey. + # The functions gethostbyname, getservbyname, and inet_addr are + # in -lbsd on LynxOS 3.0.1/i386, according to Lars Hecking. + echo "$as_me:$LINENO: checking for gethostbyname" >&5 +echo $ECHO_N "checking for gethostbyname... $ECHO_C" >&6 +if test "${ac_cv_func_gethostbyname+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +/* Define gethostbyname to an innocuous variant, in case <limits.h> declares gethostbyname. + For example, HP-UX 11i <limits.h> declares gettimeofday. */ +#define gethostbyname innocuous_gethostbyname + +/* System header to define __stub macros and hopefully few prototypes, + which can conflict with char gethostbyname (); below. + Prefer <limits.h> to <assert.h> if __STDC__ is defined, since + <limits.h> exists even on freestanding compilers. */ + +#ifdef __STDC__ +# include <limits.h> +#else +# include <assert.h> +#endif + +#undef gethostbyname + +/* Override any gcc2 internal prototype to avoid an error. */ +#ifdef __cplusplus +extern "C" +{ +#endif +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char gethostbyname (); +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined (__stub_gethostbyname) || defined (__stub___gethostbyname) +choke me +#else +char (*f) () = gethostbyname; +#endif +#ifdef __cplusplus +} +#endif + +int +main () +{ +return f != gethostbyname; + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_func_gethostbyname=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_cv_func_gethostbyname=no +fi +rm -f conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +fi +echo "$as_me:$LINENO: result: $ac_cv_func_gethostbyname" >&5 +echo "${ECHO_T}$ac_cv_func_gethostbyname" >&6 + + if test $ac_cv_func_gethostbyname = no; then + echo "$as_me:$LINENO: checking for gethostbyname in -lnsl" >&5 +echo $ECHO_N "checking for gethostbyname in -lnsl... $ECHO_C" >&6 +if test "${ac_cv_lib_nsl_gethostbyname+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lnsl $LIBS" +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +/* Override any gcc2 internal prototype to avoid an error. */ +#ifdef __cplusplus +extern "C" +#endif +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char gethostbyname (); +int +main () +{ +gethostbyname (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_lib_nsl_gethostbyname=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_cv_lib_nsl_gethostbyname=no +fi +rm -f conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +echo "$as_me:$LINENO: result: $ac_cv_lib_nsl_gethostbyname" >&5 +echo "${ECHO_T}$ac_cv_lib_nsl_gethostbyname" >&6 +if test $ac_cv_lib_nsl_gethostbyname = yes; then + X_EXTRA_LIBS="$X_EXTRA_LIBS -lnsl" +fi + + if test $ac_cv_lib_nsl_gethostbyname = no; then + echo "$as_me:$LINENO: checking for gethostbyname in -lbsd" >&5 +echo $ECHO_N "checking for gethostbyname in -lbsd... $ECHO_C" >&6 +if test "${ac_cv_lib_bsd_gethostbyname+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lbsd $LIBS" +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +/* Override any gcc2 internal prototype to avoid an error. */ +#ifdef __cplusplus +extern "C" +#endif +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char gethostbyname (); +int +main () +{ +gethostbyname (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_lib_bsd_gethostbyname=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_cv_lib_bsd_gethostbyname=no +fi +rm -f conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +echo "$as_me:$LINENO: result: $ac_cv_lib_bsd_gethostbyname" >&5 +echo "${ECHO_T}$ac_cv_lib_bsd_gethostbyname" >&6 +if test $ac_cv_lib_bsd_gethostbyname = yes; then + X_EXTRA_LIBS="$X_EXTRA_LIBS -lbsd" +fi + + fi + fi + + # lieder@skyler.mavd.honeywell.com says without -lsocket, + # socket/setsockopt and other routines are undefined under SCO ODT + # 2.0. But -lsocket is broken on IRIX 5.2 (and is not necessary + # on later versions), says Simon Leinen: it contains gethostby* + # variants that don't use the name server (or something). -lsocket + # must be given before -lnsl if both are needed. We assume that + # if connect needs -lnsl, so does gethostbyname. + echo "$as_me:$LINENO: checking for connect" >&5 +echo $ECHO_N "checking for connect... $ECHO_C" >&6 +if test "${ac_cv_func_connect+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +/* Define connect to an innocuous variant, in case <limits.h> declares connect. + For example, HP-UX 11i <limits.h> declares gettimeofday. */ +#define connect innocuous_connect + +/* System header to define __stub macros and hopefully few prototypes, + which can conflict with char connect (); below. + Prefer <limits.h> to <assert.h> if __STDC__ is defined, since + <limits.h> exists even on freestanding compilers. */ + +#ifdef __STDC__ +# include <limits.h> +#else +# include <assert.h> +#endif + +#undef connect + +/* Override any gcc2 internal prototype to avoid an error. */ +#ifdef __cplusplus +extern "C" +{ +#endif +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char connect (); +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined (__stub_connect) || defined (__stub___connect) +choke me +#else +char (*f) () = connect; +#endif +#ifdef __cplusplus +} +#endif + +int +main () +{ +return f != connect; + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_func_connect=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_cv_func_connect=no +fi +rm -f conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +fi +echo "$as_me:$LINENO: result: $ac_cv_func_connect" >&5 +echo "${ECHO_T}$ac_cv_func_connect" >&6 + + if test $ac_cv_func_connect = no; then + echo "$as_me:$LINENO: checking for connect in -lsocket" >&5 +echo $ECHO_N "checking for connect in -lsocket... $ECHO_C" >&6 +if test "${ac_cv_lib_socket_connect+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lsocket $X_EXTRA_LIBS $LIBS" +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +/* Override any gcc2 internal prototype to avoid an error. */ +#ifdef __cplusplus +extern "C" +#endif +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char connect (); +int +main () +{ +connect (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_lib_socket_connect=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_cv_lib_socket_connect=no +fi +rm -f conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +echo "$as_me:$LINENO: result: $ac_cv_lib_socket_connect" >&5 +echo "${ECHO_T}$ac_cv_lib_socket_connect" >&6 +if test $ac_cv_lib_socket_connect = yes; then + X_EXTRA_LIBS="-lsocket $X_EXTRA_LIBS" +fi + + fi + + # Guillermo Gomez says -lposix is necessary on A/UX. + echo "$as_me:$LINENO: checking for remove" >&5 +echo $ECHO_N "checking for remove... $ECHO_C" >&6 +if test "${ac_cv_func_remove+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +/* Define remove to an innocuous variant, in case <limits.h> declares remove. + For example, HP-UX 11i <limits.h> declares gettimeofday. */ +#define remove innocuous_remove + +/* System header to define __stub macros and hopefully few prototypes, + which can conflict with char remove (); below. + Prefer <limits.h> to <assert.h> if __STDC__ is defined, since + <limits.h> exists even on freestanding compilers. */ + +#ifdef __STDC__ +# include <limits.h> +#else +# include <assert.h> +#endif + +#undef remove + +/* Override any gcc2 internal prototype to avoid an error. */ +#ifdef __cplusplus +extern "C" +{ +#endif +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char remove (); +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined (__stub_remove) || defined (__stub___remove) +choke me +#else +char (*f) () = remove; +#endif +#ifdef __cplusplus +} +#endif + +int +main () +{ +return f != remove; + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_func_remove=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_cv_func_remove=no +fi +rm -f conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +fi +echo "$as_me:$LINENO: result: $ac_cv_func_remove" >&5 +echo "${ECHO_T}$ac_cv_func_remove" >&6 + + if test $ac_cv_func_remove = no; then + echo "$as_me:$LINENO: checking for remove in -lposix" >&5 +echo $ECHO_N "checking for remove in -lposix... $ECHO_C" >&6 +if test "${ac_cv_lib_posix_remove+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lposix $LIBS" +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +/* Override any gcc2 internal prototype to avoid an error. */ +#ifdef __cplusplus +extern "C" +#endif +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char remove (); +int +main () +{ +remove (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_lib_posix_remove=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_cv_lib_posix_remove=no +fi +rm -f conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +echo "$as_me:$LINENO: result: $ac_cv_lib_posix_remove" >&5 +echo "${ECHO_T}$ac_cv_lib_posix_remove" >&6 +if test $ac_cv_lib_posix_remove = yes; then + X_EXTRA_LIBS="$X_EXTRA_LIBS -lposix" +fi + + fi + + # BSDI BSD/OS 2.1 needs -lipc for XOpenDisplay. + echo "$as_me:$LINENO: checking for shmat" >&5 +echo $ECHO_N "checking for shmat... $ECHO_C" >&6 +if test "${ac_cv_func_shmat+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +/* Define shmat to an innocuous variant, in case <limits.h> declares shmat. + For example, HP-UX 11i <limits.h> declares gettimeofday. */ +#define shmat innocuous_shmat + +/* System header to define __stub macros and hopefully few prototypes, + which can conflict with char shmat (); below. + Prefer <limits.h> to <assert.h> if __STDC__ is defined, since + <limits.h> exists even on freestanding compilers. */ + +#ifdef __STDC__ +# include <limits.h> +#else +# include <assert.h> +#endif + +#undef shmat + +/* Override any gcc2 internal prototype to avoid an error. */ +#ifdef __cplusplus +extern "C" +{ +#endif +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char shmat (); +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined (__stub_shmat) || defined (__stub___shmat) +choke me +#else +char (*f) () = shmat; +#endif +#ifdef __cplusplus +} +#endif + +int +main () +{ +return f != shmat; + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_func_shmat=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_cv_func_shmat=no +fi +rm -f conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +fi +echo "$as_me:$LINENO: result: $ac_cv_func_shmat" >&5 +echo "${ECHO_T}$ac_cv_func_shmat" >&6 + + if test $ac_cv_func_shmat = no; then + echo "$as_me:$LINENO: checking for shmat in -lipc" >&5 +echo $ECHO_N "checking for shmat in -lipc... $ECHO_C" >&6 +if test "${ac_cv_lib_ipc_shmat+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lipc $LIBS" +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +/* Override any gcc2 internal prototype to avoid an error. */ +#ifdef __cplusplus +extern "C" +#endif +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char shmat (); +int +main () +{ +shmat (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_lib_ipc_shmat=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_cv_lib_ipc_shmat=no +fi +rm -f conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +echo "$as_me:$LINENO: result: $ac_cv_lib_ipc_shmat" >&5 +echo "${ECHO_T}$ac_cv_lib_ipc_shmat" >&6 +if test $ac_cv_lib_ipc_shmat = yes; then + X_EXTRA_LIBS="$X_EXTRA_LIBS -lipc" +fi + + fi + fi + + # Check for libraries that X11R6 Xt/Xaw programs need. + ac_save_LDFLAGS=$LDFLAGS + test -n "$x_libraries" && LDFLAGS="$LDFLAGS -L$x_libraries" + # SM needs ICE to (dynamically) link under SunOS 4.x (so we have to + # check for ICE first), but we must link in the order -lSM -lICE or + # we get undefined symbols. So assume we have SM if we have ICE. + # These have to be linked with before -lX11, unlike the other + # libraries we check for below, so use a different variable. + # John Interrante, Karl Berry + echo "$as_me:$LINENO: checking for IceConnectionNumber in -lICE" >&5 +echo $ECHO_N "checking for IceConnectionNumber in -lICE... $ECHO_C" >&6 +if test "${ac_cv_lib_ICE_IceConnectionNumber+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lICE $X_EXTRA_LIBS $LIBS" +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +/* Override any gcc2 internal prototype to avoid an error. */ +#ifdef __cplusplus +extern "C" +#endif +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char IceConnectionNumber (); +int +main () +{ +IceConnectionNumber (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_lib_ICE_IceConnectionNumber=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_cv_lib_ICE_IceConnectionNumber=no +fi +rm -f conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +echo "$as_me:$LINENO: result: $ac_cv_lib_ICE_IceConnectionNumber" >&5 +echo "${ECHO_T}$ac_cv_lib_ICE_IceConnectionNumber" >&6 +if test $ac_cv_lib_ICE_IceConnectionNumber = yes; then + X_PRE_LIBS="$X_PRE_LIBS -lSM -lICE" +fi + + LDFLAGS=$ac_save_LDFLAGS + +fi + +if test x"${have_x}" = "xyes"; then + cat >>confdefs.h <<\_ACEOF +#define HAVE_XT 1 +_ACEOF + +fi + + + # + # Ok, lets find the tcl configuration + # First, look for one uninstalled. + # the alternative search directory is invoked by --with-tcl + # + + if test x"${no_tcl}" = x ; then + # we reset no_tcl in case something fails here + no_tcl=true + +# Check whether --with-tcl or --without-tcl was given. +if test "${with_tcl+set}" = set; then + withval="$with_tcl" + with_tclconfig=${withval} +fi; + echo "$as_me:$LINENO: checking for Tcl configuration" >&5 +echo $ECHO_N "checking for Tcl configuration... $ECHO_C" >&6 + if test x"${withval}" != xno ; then + if test "${ac_cv_c_tclconfig+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + + + # First check to see if --with-tcl was specified. + if test x"${with_tclconfig}" != x ; then + if test -f "${with_tclconfig}/tclConfig.sh" ; then + ac_cv_c_tclconfig=`(cd ${with_tclconfig}; pwd)` + else + echo "$as_me:$LINENO: result: ${with_tclconfig} directory doesn't contain tclConfig.sh" >&5 +echo "${ECHO_T}${with_tclconfig} directory doesn't contain tclConfig.sh" >&6 + fi + fi + + # then check for a private Tcl installation + if test x"${ac_cv_c_tclconfig}" = x ; then + for i in \ + ../tcl \ + `ls -dr ../tcl[8-9].[0-9]* 2>/dev/null` \ + ../../tcl \ + `ls -dr ../../tcl[8-9].[0-9]* 2>/dev/null` \ + ../../../tcl \ + `ls -dr ../../../tcl[8-9].[0-9]* 2>/dev/null` ; do + if test -f "$i/unix/tclConfig.sh" ; then + ac_cv_c_tclconfig=`(cd $i/unix; pwd)` + break + fi + done + fi + + # check in a few common install locations + if test x"${ac_cv_c_tclconfig}" = x ; then + for i in `ls -d ${libdir} 2>/dev/null` \ + `ls -d /usr/local/lib 2>/dev/null` \ + `ls -d /usr/contrib/lib 2>/dev/null` \ + `ls -d /usr/lib 2>/dev/null` \ + ; do + if test -f "$i/tclConfig.sh" ; then + ac_cv_c_tclconfig=`(cd $i; pwd)` + break + fi + done + fi + + # check in a few other private locations + if test x"${ac_cv_c_tclconfig}" = x ; then + for i in \ + ${srcdir}/../tcl \ + `ls -dr ${srcdir}/../tcl[8-9].[0-9]* 2>/dev/null` ; do + if test -f "$i/unix/tclConfig.sh" ; then + ac_cv_c_tclconfig=`(cd $i/unix; pwd)` + break + fi + done + fi + +fi + + else + echo "$as_me:$LINENO: result: skipping Tcl configuration" >&5 +echo "${ECHO_T}skipping Tcl configuration" >&6 + ac_cv_c_tclconfig="none" + fi + + if test x"${ac_cv_c_tclconfig}" = x ; then + TCL_BIN_DIR="# no Tcl configs found" + echo "$as_me:$LINENO: result: can't find Tcl configuration definitions" >&5 +echo "${ECHO_T}can't find Tcl configuration definitions" >&6 +# no Tcl is OK egm 03/25/03 +# AC_MSG_WARN(Can't find Tcl configuration definitions) +# exit 0 + elif test x"${ac_cv_c_tclconfig}" = xnone ; then + TCL_BIN_DIR="" + else + no_tcl= + TCL_BIN_DIR=${ac_cv_c_tclconfig} + echo "$as_me:$LINENO: result: found $TCL_BIN_DIR/tclConfig.sh" >&5 +echo "${ECHO_T}found $TCL_BIN_DIR/tclConfig.sh" >&6 + fi + fi + +if test x"${no_tcl}" = x ; then + + echo "$as_me:$LINENO: checking for existence of $TCL_BIN_DIR/tclConfig.sh" >&5 +echo $ECHO_N "checking for existence of $TCL_BIN_DIR/tclConfig.sh... $ECHO_C" >&6 + + if test -f "$TCL_BIN_DIR/tclConfig.sh" ; then + echo "$as_me:$LINENO: result: loading" >&5 +echo "${ECHO_T}loading" >&6 + . $TCL_BIN_DIR/tclConfig.sh + else + echo "$as_me:$LINENO: result: file not found" >&5 +echo "${ECHO_T}file not found" >&6 + fi + + # + # If the TCL_BIN_DIR is the build directory (not the install directory), + # then set the common variable name to the value of the build variables. + # For example, the variable TCL_LIB_SPEC will be set to the value + # of TCL_BUILD_LIB_SPEC. An extension should make use of TCL_LIB_SPEC + # instead of TCL_BUILD_LIB_SPEC since it will work with both an + # installed and uninstalled version of Tcl. + # + + if test -f $TCL_BIN_DIR/Makefile ; then + TCL_LIB_SPEC=${TCL_BUILD_LIB_SPEC} + TCL_STUB_LIB_SPEC=${TCL_BUILD_STUB_LIB_SPEC} + TCL_STUB_LIB_PATH=${TCL_BUILD_STUB_LIB_PATH} + fi + + # + # eval is required to do the TCL_DBGX substitution + # + + eval "TCL_LIB_FILE=\"${TCL_LIB_FILE}\"" + eval "TCL_LIB_FLAG=\"${TCL_LIB_FLAG}\"" + eval "TCL_LIB_SPEC=\"${TCL_LIB_SPEC}\"" + + eval "TCL_STUB_LIB_FILE=\"${TCL_STUB_LIB_FILE}\"" + eval "TCL_STUB_LIB_FLAG=\"${TCL_STUB_LIB_FLAG}\"" + eval "TCL_STUB_LIB_SPEC=\"${TCL_STUB_LIB_SPEC}\"" + + + + + + + + + + + + + + if test -r $TCL_PREFIX/include/tcl.h; then + TCL_CFLAGS="$TCL_INCLUDE_SPEC" + if test x"$DOSHARED" != x -a x"$TCL_SUPPORTS_STUBS" = x1; then + TCL_LIBS="$TCL_STUB_LIB_SPEC" + TCL_CFLAGS="$TCL_CFLAGS -DUSE_TCL_STUBS=1" + echo "$as_me:$LINENO: result: Tcl support will utilize stubs library: $TCL_LIBS" >&5 +echo "${ECHO_T}Tcl support will utilize stubs library: $TCL_LIBS" >&6 + else + TCL_LIBS="$TCL_LIB_SPEC" + echo "$as_me:$LINENO: result: Tcl support will utilize library: $TCL_LIBS" >&5 +echo "${ECHO_T}Tcl support will utilize library: $TCL_LIBS" >&6 + fi + cat >>confdefs.h <<\_ACEOF +#define HAVE_TCL 1 +_ACEOF + + else + if test x"${with_tclconfig}" != x ; then + TCL_CFLAGS="$TCL_INCLUDE_SPEC" + TCL_LIBS="$TCL_LIB_SPEC" + cat >>confdefs.h <<\_ACEOF +#define HAVE_TCL 1 +_ACEOF + + echo "$as_me:$LINENO: result: warning: tcl.h not found with --with-tcl ... tcl build might fail" >&5 +echo "${ECHO_T}warning: tcl.h not found with --with-tcl ... tcl build might fail" >&6 + else + echo "$as_me:$LINENO: result: $TCL_PREFIX/include/tcl.h not found ... use --with-tcl to build tcl explicitly" >&5 +echo "${ECHO_T}$TCL_PREFIX/include/tcl.h not found ... use --with-tcl to build tcl explicitly" >&6 + fi + fi +fi + + + +echo "$as_me:$LINENO: checking for incorporation of thread support" >&5 +echo $ECHO_N "checking for incorporation of thread support... $ECHO_C" >&6 + +# Check whether --with-threads or --without-threads was given. +if test "${with_threads+set}" = set; then + withval="$with_threads" + thr=1 +else + thr=0 +fi; +if test x"$thr" = x1 ; then + echo "$as_me:$LINENO: result: yes" >&5 +echo "${ECHO_T}yes" >&6 + CFLAGS="$CFLAGS -D_REENTRANT" +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + +echo "$as_me:$LINENO: checking for gtk" >&5 +echo $ECHO_N "checking for gtk... $ECHO_C" >&6 + +# Check whether --with-gtk or --without-gtk was given. +if test "${with_gtk+set}" = set; then + withval="$with_gtk" + havelib=1 +else + havelib=0 +fi; +if test x"$havelib" = x1 ; then + echo "$as_me:$LINENO: result: yes ($withval)" >&5 +echo "${ECHO_T}yes ($withval)" >&6 + GTK_CFLAGS="`pkg-config gtk+-2.0 --cflags` -DHAVE_GTK=1" + GTK_LIBS="`pkg-config gtk+-2.0 --libs`" + cat >>confdefs.h <<\_ACEOF +#define HAVE_GTK 1 +_ACEOF + +else + GTK_CFLAGS="" + GTK_LIBS="" + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + + + +# restore LDFLAGS +LDFLAGS="$LDFLAGS $XLDFLAGS" + +echo "$as_me:$LINENO: checking $host_os configuration" >&5 +echo $ECHO_N "checking $host_os configuration... $ECHO_C" >&6 +case $host_os in + *cygwin*|*Cygwin* ) + cat >>confdefs.h <<\_ACEOF +#define HAVE_CYGWIN 1 +_ACEOF + + echo "$as_me:$LINENO: result: flagging Cygwin" >&5 +echo "${ECHO_T}flagging Cygwin" >&6 + ;; + *mingw32*|*Mingw32*) + CFLAGS="$CFLAGS -mconsole" + EXTRA_LIBS="$EXTRA_LIBS -lwsock32" + cat >>confdefs.h <<\_ACEOF +#define HAVE_MINGW32 1 +_ACEOF + + echo "$as_me:$LINENO: result: flagging MinGW" >&5 +echo "${ECHO_T}flagging MinGW" >&6 + ;; + *darwin*|*Darwin*) + LDFLAGS="$LDFLAGS $CFLAGS" + G=`$CC -v 2>&1 | grep version | awk '{print $3}' | awk -F. '{print $1$2}'` + if test x"$G" != x -a "$G" -lt 42; then + CFLAGS="$CFLAGS -no-cpp-precomp" + fi + if test x"$TCL_PREFIX" = x"/usr/local"; then + TCL_CFLAGS="" + echo "$as_me:$LINENO: result: removing -I/usr/local/include" >&5 +echo "${ECHO_T}removing -I/usr/local/include" >&6 + fi + ;; + *osf*|*Osf*) + echo "$as_me:$LINENO: checking for snprintf in -ldb" >&5 +echo $ECHO_N "checking for snprintf in -ldb... $ECHO_C" >&6 +if test "${ac_cv_lib_db_snprintf+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-ldb $LIBS" +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +/* Override any gcc2 internal prototype to avoid an error. */ +#ifdef __cplusplus +extern "C" +#endif +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char snprintf (); +int +main () +{ +snprintf (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_lib_db_snprintf=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_cv_lib_db_snprintf=no +fi +rm -f conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +echo "$as_me:$LINENO: result: $ac_cv_lib_db_snprintf" >&5 +echo "${ECHO_T}$ac_cv_lib_db_snprintf" >&6 +if test $ac_cv_lib_db_snprintf = yes; then + EXTRA_LIBS="$EXTRA_LIBS -ldb" +fi + + ;; + * ) + if test x"$fpic" = x"yes" ; then + if test "$CC" = "gcc" -o `$CC -v 2>&1 | grep -c gcc` != "0" ; then + CFLAGS="$CFLAGS -fPIC" + echo "$as_me:$LINENO: result: adding -fPIC to gcc" >&5 +echo "${ECHO_T}adding -fPIC to gcc" >&6 + else + echo "$as_me:$LINENO: result: none" >&5 +echo "${ECHO_T}none" >&6 + fi + else + echo "$as_me:$LINENO: result: none" >&5 +echo "${ECHO_T}none" >&6 + fi + ;; +esac + + + + ac_config_files="$ac_config_files Makefile" + + +# generate pkg-config meta-data file + ac_config_files="$ac_config_files xpa.pc" + + +cat >confcache <<\_ACEOF +# This file is a shell script that caches the results of configure +# tests run on this system so they can be shared between configure +# scripts and configure runs, see configure's option --config-cache. +# It is not useful on other systems. If it contains results you don't +# want to keep, you may remove or edit it. +# +# config.status only pays attention to the cache file if you give it +# the --recheck option to rerun configure. +# +# `ac_cv_env_foo' variables (set or unset) will be overridden when +# loading this file, other *unset* `ac_cv_foo' will be assigned the +# following values. + +_ACEOF + +# The following way of writing the cache mishandles newlines in values, +# but we know of no workaround that is simple, portable, and efficient. +# So, don't put newlines in cache variables' values. +# Ultrix sh set writes to stderr and can't be redirected directly, +# and sets the high bit in the cache file unless we assign to the vars. +{ + (set) 2>&1 | + case `(ac_space=' '; set | grep ac_space) 2>&1` in + *ac_space=\ *) + # `set' does not quote correctly, so add quotes (double-quote + # substitution turns \\\\ into \\, and sed turns \\ into \). + sed -n \ + "s/'/'\\\\''/g; + s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p" + ;; + *) + # `set' quotes correctly as required by POSIX, so do not add quotes. + sed -n \ + "s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1=\\2/p" + ;; + esac; +} | + sed ' + t clear + : clear + s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/ + t end + /^ac_cv_env/!s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/ + : end' >>confcache +if diff $cache_file confcache >/dev/null 2>&1; then :; else + if test -w $cache_file; then + test "x$cache_file" != "x/dev/null" && echo "updating cache $cache_file" + cat confcache >$cache_file + else + echo "not updating unwritable cache $cache_file" + fi +fi +rm -f confcache + +test "x$prefix" = xNONE && prefix=$ac_default_prefix +# Let make expand exec_prefix. +test "x$exec_prefix" = xNONE && exec_prefix='${prefix}' + +# VPATH may cause trouble with some makes, so we remove $(srcdir), +# ${srcdir} and @srcdir@ from VPATH if srcdir is ".", strip leading and +# trailing colons and then remove the whole line if VPATH becomes empty +# (actually we leave an empty line to preserve line numbers). +if test "x$srcdir" = x.; then + ac_vpsub='/^[ ]*VPATH[ ]*=/{ +s/:*\$(srcdir):*/:/; +s/:*\${srcdir}:*/:/; +s/:*@srcdir@:*/:/; +s/^\([^=]*=[ ]*\):*/\1/; +s/:*$//; +s/^[^=]*=[ ]*$//; +}' +fi + +DEFS=-DHAVE_CONFIG_H + +ac_libobjs= +ac_ltlibobjs= +for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue + # 1. Remove the extension, and $U if already installed. + ac_i=`echo "$ac_i" | + sed 's/\$U\././;s/\.o$//;s/\.obj$//'` + # 2. Add them. + ac_libobjs="$ac_libobjs $ac_i\$U.$ac_objext" + ac_ltlibobjs="$ac_ltlibobjs $ac_i"'$U.lo' +done +LIBOBJS=$ac_libobjs + +LTLIBOBJS=$ac_ltlibobjs + + + +: ${CONFIG_STATUS=./config.status} +ac_clean_files_save=$ac_clean_files +ac_clean_files="$ac_clean_files $CONFIG_STATUS" +{ echo "$as_me:$LINENO: creating $CONFIG_STATUS" >&5 +echo "$as_me: creating $CONFIG_STATUS" >&6;} +cat >$CONFIG_STATUS <<_ACEOF +#! $SHELL +# Generated by $as_me. +# Run this file to recreate the current configuration. +# Compiler output produced by configure, useful for debugging +# configure, is in config.log if it exists. + +debug=false +ac_cs_recheck=false +ac_cs_silent=false +SHELL=\${CONFIG_SHELL-$SHELL} +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF +## --------------------- ## +## M4sh Initialization. ## +## --------------------- ## + +# Be Bourne compatible +if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then + emulate sh + NULLCMD=: + # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which + # is contrary to our usage. Disable this feature. + alias -g '${1+"$@"}'='"$@"' +elif test -n "${BASH_VERSION+set}" && (set -o posix) >/dev/null 2>&1; then + set -o posix +fi +DUALCASE=1; export DUALCASE # for MKS sh + +# Support unset when possible. +if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then + as_unset=unset +else + as_unset=false +fi + + +# Work around bugs in pre-3.0 UWIN ksh. +$as_unset ENV MAIL MAILPATH +PS1='$ ' +PS2='> ' +PS4='+ ' + +# NLS nuisances. +for as_var in \ + LANG LANGUAGE LC_ADDRESS LC_ALL LC_COLLATE LC_CTYPE LC_IDENTIFICATION \ + LC_MEASUREMENT LC_MESSAGES LC_MONETARY LC_NAME LC_NUMERIC LC_PAPER \ + LC_TELEPHONE LC_TIME +do + if (set +x; test -z "`(eval $as_var=C; export $as_var) 2>&1`"); then + eval $as_var=C; export $as_var + else + $as_unset $as_var + fi +done + +# Required to use basename. +if expr a : '\(a\)' >/dev/null 2>&1; then + as_expr=expr +else + as_expr=false +fi + +if (basename /) >/dev/null 2>&1 && test "X`basename / 2>&1`" = "X/"; then + as_basename=basename +else + as_basename=false +fi + + +# Name of the executable. +as_me=`$as_basename "$0" || +$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ + X"$0" : 'X\(//\)$' \| \ + X"$0" : 'X\(/\)$' \| \ + . : '\(.\)' 2>/dev/null || +echo X/"$0" | + sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/; q; } + /^X\/\(\/\/\)$/{ s//\1/; q; } + /^X\/\(\/\).*/{ s//\1/; q; } + s/.*/./; q'` + + +# PATH needs CR, and LINENO needs CR and PATH. +# Avoid depending upon Character Ranges. +as_cr_letters='abcdefghijklmnopqrstuvwxyz' +as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' +as_cr_Letters=$as_cr_letters$as_cr_LETTERS +as_cr_digits='0123456789' +as_cr_alnum=$as_cr_Letters$as_cr_digits + +# The user is always right. +if test "${PATH_SEPARATOR+set}" != set; then + echo "#! /bin/sh" >conf$$.sh + echo "exit 0" >>conf$$.sh + chmod +x conf$$.sh + if (PATH="/nonexistent;."; conf$$.sh) >/dev/null 2>&1; then + PATH_SEPARATOR=';' + else + PATH_SEPARATOR=: + fi + rm -f conf$$.sh +fi + + + as_lineno_1=$LINENO + as_lineno_2=$LINENO + as_lineno_3=`(expr $as_lineno_1 + 1) 2>/dev/null` + test "x$as_lineno_1" != "x$as_lineno_2" && + test "x$as_lineno_3" = "x$as_lineno_2" || { + # Find who we are. Look in the path if we contain no path at all + # relative or not. + case $0 in + *[\\/]* ) as_myself=$0 ;; + *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break +done + + ;; + esac + # We did not find ourselves, most probably we were run as `sh COMMAND' + # in which case we are not to be found in the path. + if test "x$as_myself" = x; then + as_myself=$0 + fi + if test ! -f "$as_myself"; then + { { echo "$as_me:$LINENO: error: cannot find myself; rerun with an absolute path" >&5 +echo "$as_me: error: cannot find myself; rerun with an absolute path" >&2;} + { (exit 1); exit 1; }; } + fi + case $CONFIG_SHELL in + '') + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for as_base in sh bash ksh sh5; do + case $as_dir in + /*) + if ("$as_dir/$as_base" -c ' + as_lineno_1=$LINENO + as_lineno_2=$LINENO + as_lineno_3=`(expr $as_lineno_1 + 1) 2>/dev/null` + test "x$as_lineno_1" != "x$as_lineno_2" && + test "x$as_lineno_3" = "x$as_lineno_2" ') 2>/dev/null; then + $as_unset BASH_ENV || test "${BASH_ENV+set}" != set || { BASH_ENV=; export BASH_ENV; } + $as_unset ENV || test "${ENV+set}" != set || { ENV=; export ENV; } + CONFIG_SHELL=$as_dir/$as_base + export CONFIG_SHELL + exec "$CONFIG_SHELL" "$0" ${1+"$@"} + fi;; + esac + done +done +;; + esac + + # Create $as_me.lineno as a copy of $as_myself, but with $LINENO + # uniformly replaced by the line number. The first 'sed' inserts a + # line-number line before each line; the second 'sed' does the real + # work. The second script uses 'N' to pair each line-number line + # with the numbered line, and appends trailing '-' during + # substitution so that $LINENO is not a special case at line end. + # (Raja R Harinath suggested sed '=', and Paul Eggert wrote the + # second 'sed' script. Blame Lee E. McMahon for sed's syntax. :-) + sed '=' <$as_myself | + sed ' + N + s,$,-, + : loop + s,^\(['$as_cr_digits']*\)\(.*\)[$]LINENO\([^'$as_cr_alnum'_]\),\1\2\1\3, + t loop + s,-$,, + s,^['$as_cr_digits']*\n,, + ' >$as_me.lineno && + chmod +x $as_me.lineno || + { { echo "$as_me:$LINENO: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&5 +echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2;} + { (exit 1); exit 1; }; } + + # Don't try to exec as it changes $[0], causing all sort of problems + # (the dirname of $[0] is not the place where we might find the + # original and so on. Autoconf is especially sensible to this). + . ./$as_me.lineno + # Exit status is that of the last command. + exit +} + + +case `echo "testing\c"; echo 1,2,3`,`echo -n testing; echo 1,2,3` in + *c*,-n*) ECHO_N= ECHO_C=' +' ECHO_T=' ' ;; + *c*,* ) ECHO_N=-n ECHO_C= ECHO_T= ;; + *) ECHO_N= ECHO_C='\c' ECHO_T= ;; +esac + +if expr a : '\(a\)' >/dev/null 2>&1; then + as_expr=expr +else + as_expr=false +fi + +rm -f conf$$ conf$$.exe conf$$.file +echo >conf$$.file +if ln -s conf$$.file conf$$ 2>/dev/null; then + # We could just check for DJGPP; but this test a) works b) is more generic + # and c) will remain valid once DJGPP supports symlinks (DJGPP 2.04). + if test -f conf$$.exe; then + # Don't use ln at all; we don't have any links + as_ln_s='cp -p' + else + as_ln_s='ln -s' + fi +elif ln conf$$.file conf$$ 2>/dev/null; then + as_ln_s=ln +else + as_ln_s='cp -p' +fi +rm -f conf$$ conf$$.exe conf$$.file + +if mkdir -p . 2>/dev/null; then + as_mkdir_p=: +else + test -d ./-p && rmdir ./-p + as_mkdir_p=false +fi + +as_executable_p="test -f" + +# Sed expression to map a string onto a valid CPP name. +as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" + +# Sed expression to map a string onto a valid variable name. +as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" + + +# IFS +# We need space, tab and new line, in precisely that order. +as_nl=' +' +IFS=" $as_nl" + +# CDPATH. +$as_unset CDPATH + +exec 6>&1 + +# Open the log real soon, to keep \$[0] and so on meaningful, and to +# report actual input values of CONFIG_FILES etc. instead of their +# values after options handling. Logging --version etc. is OK. +exec 5>>config.log +{ + echo + sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX +## Running $as_me. ## +_ASBOX +} >&5 +cat >&5 <<_CSEOF + +This file was extended by xpa $as_me 2.1.18, which was +generated by GNU Autoconf 2.59. Invocation command line was + + CONFIG_FILES = $CONFIG_FILES + CONFIG_HEADERS = $CONFIG_HEADERS + CONFIG_LINKS = $CONFIG_LINKS + CONFIG_COMMANDS = $CONFIG_COMMANDS + $ $0 $@ + +_CSEOF +echo "on `(hostname || uname -n) 2>/dev/null | sed 1q`" >&5 +echo >&5 +_ACEOF + +# Files that config.status was made for. +if test -n "$ac_config_files"; then + echo "config_files=\"$ac_config_files\"" >>$CONFIG_STATUS +fi + +if test -n "$ac_config_headers"; then + echo "config_headers=\"$ac_config_headers\"" >>$CONFIG_STATUS +fi + +if test -n "$ac_config_links"; then + echo "config_links=\"$ac_config_links\"" >>$CONFIG_STATUS +fi + +if test -n "$ac_config_commands"; then + echo "config_commands=\"$ac_config_commands\"" >>$CONFIG_STATUS +fi + +cat >>$CONFIG_STATUS <<\_ACEOF + +ac_cs_usage="\ +\`$as_me' instantiates files from templates according to the +current configuration. + +Usage: $0 [OPTIONS] [FILE]... + + -h, --help print this help, then exit + -V, --version print version number, then exit + -q, --quiet do not print progress messages + -d, --debug don't remove temporary files + --recheck update $as_me by reconfiguring in the same conditions + --file=FILE[:TEMPLATE] + instantiate the configuration file FILE + --header=FILE[:TEMPLATE] + instantiate the configuration header FILE + +Configuration files: +$config_files + +Configuration headers: +$config_headers + +Report bugs to <bug-autoconf@gnu.org>." +_ACEOF + +cat >>$CONFIG_STATUS <<_ACEOF +ac_cs_version="\\ +xpa config.status 2.1.18 +configured by $0, generated by GNU Autoconf 2.59, + with options \\"`echo "$ac_configure_args" | sed 's/[\\""\`\$]/\\\\&/g'`\\" + +Copyright (C) 2003 Free Software Foundation, Inc. +This config.status script is free software; the Free Software Foundation +gives unlimited permission to copy, distribute and modify it." +srcdir=$srcdir +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF +# If no file are specified by the user, then we need to provide default +# value. By we need to know if files were specified by the user. +ac_need_defaults=: +while test $# != 0 +do + case $1 in + --*=*) + ac_option=`expr "x$1" : 'x\([^=]*\)='` + ac_optarg=`expr "x$1" : 'x[^=]*=\(.*\)'` + ac_shift=: + ;; + -*) + ac_option=$1 + ac_optarg=$2 + ac_shift=shift + ;; + *) # This is not an option, so the user has probably given explicit + # arguments. + ac_option=$1 + ac_need_defaults=false;; + esac + + case $ac_option in + # Handling of the options. +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF + -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) + ac_cs_recheck=: ;; + --version | --vers* | -V ) + echo "$ac_cs_version"; exit 0 ;; + --he | --h) + # Conflict between --help and --header + { { echo "$as_me:$LINENO: error: ambiguous option: $1 +Try \`$0 --help' for more information." >&5 +echo "$as_me: error: ambiguous option: $1 +Try \`$0 --help' for more information." >&2;} + { (exit 1); exit 1; }; };; + --help | --hel | -h ) + echo "$ac_cs_usage"; exit 0 ;; + --debug | --d* | -d ) + debug=: ;; + --file | --fil | --fi | --f ) + $ac_shift + CONFIG_FILES="$CONFIG_FILES $ac_optarg" + ac_need_defaults=false;; + --header | --heade | --head | --hea ) + $ac_shift + CONFIG_HEADERS="$CONFIG_HEADERS $ac_optarg" + ac_need_defaults=false;; + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil | --si | --s) + ac_cs_silent=: ;; + + # This is an error. + -*) { { echo "$as_me:$LINENO: error: unrecognized option: $1 +Try \`$0 --help' for more information." >&5 +echo "$as_me: error: unrecognized option: $1 +Try \`$0 --help' for more information." >&2;} + { (exit 1); exit 1; }; } ;; + + *) ac_config_targets="$ac_config_targets $1" ;; + + esac + shift +done + +ac_configure_extra_args= + +if $ac_cs_silent; then + exec 6>/dev/null + ac_configure_extra_args="$ac_configure_extra_args --silent" +fi + +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF +if \$ac_cs_recheck; then + echo "running $SHELL $0 " $ac_configure_args \$ac_configure_extra_args " --no-create --no-recursion" >&6 + exec $SHELL $0 $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion +fi + +_ACEOF + + + + + +cat >>$CONFIG_STATUS <<\_ACEOF +for ac_config_target in $ac_config_targets +do + case "$ac_config_target" in + # Handling of arguments. + "Makefile" ) CONFIG_FILES="$CONFIG_FILES Makefile" ;; + "xpa.pc" ) CONFIG_FILES="$CONFIG_FILES xpa.pc" ;; + "conf.h" ) CONFIG_HEADERS="$CONFIG_HEADERS conf.h" ;; + *) { { echo "$as_me:$LINENO: error: invalid argument: $ac_config_target" >&5 +echo "$as_me: error: invalid argument: $ac_config_target" >&2;} + { (exit 1); exit 1; }; };; + esac +done + +# If the user did not use the arguments to specify the items to instantiate, +# then the envvar interface is used. Set only those that are not. +# We use the long form for the default assignment because of an extremely +# bizarre bug on SunOS 4.1.3. +if $ac_need_defaults; then + test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files + test "${CONFIG_HEADERS+set}" = set || CONFIG_HEADERS=$config_headers +fi + +# Have a temporary directory for convenience. Make it in the build tree +# simply because there is no reason to put it here, and in addition, +# creating and moving files from /tmp can sometimes cause problems. +# Create a temporary directory, and hook for its removal unless debugging. +$debug || +{ + trap 'exit_status=$?; rm -rf $tmp && exit $exit_status' 0 + trap '{ (exit 1); exit 1; }' 1 2 13 15 +} + +# Create a (secure) tmp directory for tmp files. + +{ + tmp=`(umask 077 && mktemp -d -q "./confstatXXXXXX") 2>/dev/null` && + test -n "$tmp" && test -d "$tmp" +} || +{ + tmp=./confstat$$-$RANDOM + (umask 077 && mkdir $tmp) +} || +{ + echo "$me: cannot create a temporary directory in ." >&2 + { (exit 1); exit 1; } +} + +_ACEOF + +cat >>$CONFIG_STATUS <<_ACEOF + +# +# CONFIG_FILES section. +# + +# No need to generate the scripts if there are no CONFIG_FILES. +# This happens for instance when ./config.status config.h +if test -n "\$CONFIG_FILES"; then + # Protect against being on the right side of a sed subst in config.status. + sed 's/,@/@@/; s/@,/@@/; s/,;t t\$/@;t t/; /@;t t\$/s/[\\\\&,]/\\\\&/g; + s/@@/,@/; s/@@/@,/; s/@;t t\$/,;t t/' >\$tmp/subs.sed <<\\CEOF +s,@SHELL@,$SHELL,;t t +s,@PATH_SEPARATOR@,$PATH_SEPARATOR,;t t +s,@PACKAGE_NAME@,$PACKAGE_NAME,;t t +s,@PACKAGE_TARNAME@,$PACKAGE_TARNAME,;t t +s,@PACKAGE_VERSION@,$PACKAGE_VERSION,;t t +s,@PACKAGE_STRING@,$PACKAGE_STRING,;t t +s,@PACKAGE_BUGREPORT@,$PACKAGE_BUGREPORT,;t t +s,@exec_prefix@,$exec_prefix,;t t +s,@prefix@,$prefix,;t t +s,@program_transform_name@,$program_transform_name,;t t +s,@bindir@,$bindir,;t t +s,@sbindir@,$sbindir,;t t +s,@libexecdir@,$libexecdir,;t t +s,@datadir@,$datadir,;t t +s,@sysconfdir@,$sysconfdir,;t t +s,@sharedstatedir@,$sharedstatedir,;t t +s,@localstatedir@,$localstatedir,;t t +s,@libdir@,$libdir,;t t +s,@includedir@,$includedir,;t t +s,@oldincludedir@,$oldincludedir,;t t +s,@infodir@,$infodir,;t t +s,@mandir@,$mandir,;t t +s,@build_alias@,$build_alias,;t t +s,@host_alias@,$host_alias,;t t +s,@target_alias@,$target_alias,;t t +s,@DEFS@,$DEFS,;t t +s,@ECHO_C@,$ECHO_C,;t t +s,@ECHO_N@,$ECHO_N,;t t +s,@ECHO_T@,$ECHO_T,;t t +s,@LIBS@,$LIBS,;t t +s,@build@,$build,;t t +s,@build_cpu@,$build_cpu,;t t +s,@build_vendor@,$build_vendor,;t t +s,@build_os@,$build_os,;t t +s,@host@,$host,;t t +s,@host_cpu@,$host_cpu,;t t +s,@host_vendor@,$host_vendor,;t t +s,@host_os@,$host_os,;t t +s,@CC@,$CC,;t t +s,@CFLAGS@,$CFLAGS,;t t +s,@LDFLAGS@,$LDFLAGS,;t t +s,@CPPFLAGS@,$CPPFLAGS,;t t +s,@ac_ct_CC@,$ac_ct_CC,;t t +s,@EXEEXT@,$EXEEXT,;t t +s,@OBJEXT@,$OBJEXT,;t t +s,@CPP@,$CPP,;t t +s,@EGREP@,$EGREP,;t t +s,@SZ_LONG@,$SZ_LONG,;t t +s,@RANLIB@,$RANLIB,;t t +s,@ac_ct_RANLIB@,$ac_ct_RANLIB,;t t +s,@TLIB@,$TLIB,;t t +s,@DOSHARED@,$DOSHARED,;t t +s,@LLIB@,$LLIB,;t t +s,@X_CFLAGS@,$X_CFLAGS,;t t +s,@X_PRE_LIBS@,$X_PRE_LIBS,;t t +s,@X_LIBS@,$X_LIBS,;t t +s,@X_EXTRA_LIBS@,$X_EXTRA_LIBS,;t t +s,@TCL_VERSION@,$TCL_VERSION,;t t +s,@TCL_BIN_DIR@,$TCL_BIN_DIR,;t t +s,@TCL_SRC_DIR@,$TCL_SRC_DIR,;t t +s,@TCL_LIB_FILE@,$TCL_LIB_FILE,;t t +s,@TCL_LIB_FLAG@,$TCL_LIB_FLAG,;t t +s,@TCL_LIB_SPEC@,$TCL_LIB_SPEC,;t t +s,@TCL_STUB_LIB_FILE@,$TCL_STUB_LIB_FILE,;t t +s,@TCL_STUB_LIB_FLAG@,$TCL_STUB_LIB_FLAG,;t t +s,@TCL_STUB_LIB_SPEC@,$TCL_STUB_LIB_SPEC,;t t +s,@TCL_CFLAGS@,$TCL_CFLAGS,;t t +s,@TCL_LIBS@,$TCL_LIBS,;t t +s,@GTK_CFLAGS@,$GTK_CFLAGS,;t t +s,@GTK_LIBS@,$GTK_LIBS,;t t +s,@EXTRA_LIBS@,$EXTRA_LIBS,;t t +s,@LIBOBJS@,$LIBOBJS,;t t +s,@LTLIBOBJS@,$LTLIBOBJS,;t t +CEOF + +_ACEOF + + cat >>$CONFIG_STATUS <<\_ACEOF + # Split the substitutions into bite-sized pieces for seds with + # small command number limits, like on Digital OSF/1 and HP-UX. + ac_max_sed_lines=48 + ac_sed_frag=1 # Number of current file. + ac_beg=1 # First line for current file. + ac_end=$ac_max_sed_lines # Line after last line for current file. + ac_more_lines=: + ac_sed_cmds= + while $ac_more_lines; do + if test $ac_beg -gt 1; then + sed "1,${ac_beg}d; ${ac_end}q" $tmp/subs.sed >$tmp/subs.frag + else + sed "${ac_end}q" $tmp/subs.sed >$tmp/subs.frag + fi + if test ! -s $tmp/subs.frag; then + ac_more_lines=false + else + # The purpose of the label and of the branching condition is to + # speed up the sed processing (if there are no `@' at all, there + # is no need to browse any of the substitutions). + # These are the two extra sed commands mentioned above. + (echo ':t + /@[a-zA-Z_][a-zA-Z_0-9]*@/!b' && cat $tmp/subs.frag) >$tmp/subs-$ac_sed_frag.sed + if test -z "$ac_sed_cmds"; then + ac_sed_cmds="sed -f $tmp/subs-$ac_sed_frag.sed" + else + ac_sed_cmds="$ac_sed_cmds | sed -f $tmp/subs-$ac_sed_frag.sed" + fi + ac_sed_frag=`expr $ac_sed_frag + 1` + ac_beg=$ac_end + ac_end=`expr $ac_end + $ac_max_sed_lines` + fi + done + if test -z "$ac_sed_cmds"; then + ac_sed_cmds=cat + fi +fi # test -n "$CONFIG_FILES" + +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF +for ac_file in : $CONFIG_FILES; do test "x$ac_file" = x: && continue + # Support "outfile[:infile[:infile...]]", defaulting infile="outfile.in". + case $ac_file in + - | *:- | *:-:* ) # input from stdin + cat >$tmp/stdin + ac_file_in=`echo "$ac_file" | sed 's,[^:]*:,,'` + ac_file=`echo "$ac_file" | sed 's,:.*,,'` ;; + *:* ) ac_file_in=`echo "$ac_file" | sed 's,[^:]*:,,'` + ac_file=`echo "$ac_file" | sed 's,:.*,,'` ;; + * ) ac_file_in=$ac_file.in ;; + esac + + # Compute @srcdir@, @top_srcdir@, and @INSTALL@ for subdirectories. + ac_dir=`(dirname "$ac_file") 2>/dev/null || +$as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$ac_file" : 'X\(//\)[^/]' \| \ + X"$ac_file" : 'X\(//\)$' \| \ + X"$ac_file" : 'X\(/\)' \| \ + . : '\(.\)' 2>/dev/null || +echo X"$ac_file" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; } + /^X\(\/\/\)[^/].*/{ s//\1/; q; } + /^X\(\/\/\)$/{ s//\1/; q; } + /^X\(\/\).*/{ s//\1/; q; } + s/.*/./; q'` + { if $as_mkdir_p; then + mkdir -p "$ac_dir" + else + as_dir="$ac_dir" + as_dirs= + while test ! -d "$as_dir"; do + as_dirs="$as_dir $as_dirs" + as_dir=`(dirname "$as_dir") 2>/dev/null || +$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$as_dir" : 'X\(//\)[^/]' \| \ + X"$as_dir" : 'X\(//\)$' \| \ + X"$as_dir" : 'X\(/\)' \| \ + . : '\(.\)' 2>/dev/null || +echo X"$as_dir" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; } + /^X\(\/\/\)[^/].*/{ s//\1/; q; } + /^X\(\/\/\)$/{ s//\1/; q; } + /^X\(\/\).*/{ s//\1/; q; } + s/.*/./; q'` + done + test ! -n "$as_dirs" || mkdir $as_dirs + fi || { { echo "$as_me:$LINENO: error: cannot create directory \"$ac_dir\"" >&5 +echo "$as_me: error: cannot create directory \"$ac_dir\"" >&2;} + { (exit 1); exit 1; }; }; } + + ac_builddir=. + +if test "$ac_dir" != .; then + ac_dir_suffix=/`echo "$ac_dir" | sed 's,^\.[\\/],,'` + # A "../" for each directory in $ac_dir_suffix. + ac_top_builddir=`echo "$ac_dir_suffix" | sed 's,/[^\\/]*,../,g'` +else + ac_dir_suffix= ac_top_builddir= +fi + +case $srcdir in + .) # No --srcdir option. We are building in place. + ac_srcdir=. + if test -z "$ac_top_builddir"; then + ac_top_srcdir=. + else + ac_top_srcdir=`echo $ac_top_builddir | sed 's,/$,,'` + fi ;; + [\\/]* | ?:[\\/]* ) # Absolute path. + ac_srcdir=$srcdir$ac_dir_suffix; + ac_top_srcdir=$srcdir ;; + *) # Relative path. + ac_srcdir=$ac_top_builddir$srcdir$ac_dir_suffix + ac_top_srcdir=$ac_top_builddir$srcdir ;; +esac + +# Do not use `cd foo && pwd` to compute absolute paths, because +# the directories may not exist. +case `pwd` in +.) ac_abs_builddir="$ac_dir";; +*) + case "$ac_dir" in + .) ac_abs_builddir=`pwd`;; + [\\/]* | ?:[\\/]* ) ac_abs_builddir="$ac_dir";; + *) ac_abs_builddir=`pwd`/"$ac_dir";; + esac;; +esac +case $ac_abs_builddir in +.) ac_abs_top_builddir=${ac_top_builddir}.;; +*) + case ${ac_top_builddir}. in + .) ac_abs_top_builddir=$ac_abs_builddir;; + [\\/]* | ?:[\\/]* ) ac_abs_top_builddir=${ac_top_builddir}.;; + *) ac_abs_top_builddir=$ac_abs_builddir/${ac_top_builddir}.;; + esac;; +esac +case $ac_abs_builddir in +.) ac_abs_srcdir=$ac_srcdir;; +*) + case $ac_srcdir in + .) ac_abs_srcdir=$ac_abs_builddir;; + [\\/]* | ?:[\\/]* ) ac_abs_srcdir=$ac_srcdir;; + *) ac_abs_srcdir=$ac_abs_builddir/$ac_srcdir;; + esac;; +esac +case $ac_abs_builddir in +.) ac_abs_top_srcdir=$ac_top_srcdir;; +*) + case $ac_top_srcdir in + .) ac_abs_top_srcdir=$ac_abs_builddir;; + [\\/]* | ?:[\\/]* ) ac_abs_top_srcdir=$ac_top_srcdir;; + *) ac_abs_top_srcdir=$ac_abs_builddir/$ac_top_srcdir;; + esac;; +esac + + + + if test x"$ac_file" != x-; then + { echo "$as_me:$LINENO: creating $ac_file" >&5 +echo "$as_me: creating $ac_file" >&6;} + rm -f "$ac_file" + fi + # Let's still pretend it is `configure' which instantiates (i.e., don't + # use $as_me), people would be surprised to read: + # /* config.h. Generated by config.status. */ + if test x"$ac_file" = x-; then + configure_input= + else + configure_input="$ac_file. " + fi + configure_input=$configure_input"Generated from `echo $ac_file_in | + sed 's,.*/,,'` by configure." + + # First look for the input files in the build tree, otherwise in the + # src tree. + ac_file_inputs=`IFS=: + for f in $ac_file_in; do + case $f in + -) echo $tmp/stdin ;; + [\\/$]*) + # Absolute (can't be DOS-style, as IFS=:) + test -f "$f" || { { echo "$as_me:$LINENO: error: cannot find input file: $f" >&5 +echo "$as_me: error: cannot find input file: $f" >&2;} + { (exit 1); exit 1; }; } + echo "$f";; + *) # Relative + if test -f "$f"; then + # Build tree + echo "$f" + elif test -f "$srcdir/$f"; then + # Source tree + echo "$srcdir/$f" + else + # /dev/null tree + { { echo "$as_me:$LINENO: error: cannot find input file: $f" >&5 +echo "$as_me: error: cannot find input file: $f" >&2;} + { (exit 1); exit 1; }; } + fi;; + esac + done` || { (exit 1); exit 1; } +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF + sed "$ac_vpsub +$extrasub +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF +:t +/@[a-zA-Z_][a-zA-Z_0-9]*@/!b +s,@configure_input@,$configure_input,;t t +s,@srcdir@,$ac_srcdir,;t t +s,@abs_srcdir@,$ac_abs_srcdir,;t t +s,@top_srcdir@,$ac_top_srcdir,;t t +s,@abs_top_srcdir@,$ac_abs_top_srcdir,;t t +s,@builddir@,$ac_builddir,;t t +s,@abs_builddir@,$ac_abs_builddir,;t t +s,@top_builddir@,$ac_top_builddir,;t t +s,@abs_top_builddir@,$ac_abs_top_builddir,;t t +" $ac_file_inputs | (eval "$ac_sed_cmds") >$tmp/out + rm -f $tmp/stdin + if test x"$ac_file" != x-; then + mv $tmp/out $ac_file + else + cat $tmp/out + rm -f $tmp/out + fi + +done +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF + +# +# CONFIG_HEADER section. +# + +# These sed commands are passed to sed as "A NAME B NAME C VALUE D", where +# NAME is the cpp macro being defined and VALUE is the value it is being given. +# +# ac_d sets the value in "#define NAME VALUE" lines. +ac_dA='s,^\([ ]*\)#\([ ]*define[ ][ ]*\)' +ac_dB='[ ].*$,\1#\2' +ac_dC=' ' +ac_dD=',;t' +# ac_u turns "#undef NAME" without trailing blanks into "#define NAME VALUE". +ac_uA='s,^\([ ]*\)#\([ ]*\)undef\([ ][ ]*\)' +ac_uB='$,\1#\2define\3' +ac_uC=' ' +ac_uD=',;t' + +for ac_file in : $CONFIG_HEADERS; do test "x$ac_file" = x: && continue + # Support "outfile[:infile[:infile...]]", defaulting infile="outfile.in". + case $ac_file in + - | *:- | *:-:* ) # input from stdin + cat >$tmp/stdin + ac_file_in=`echo "$ac_file" | sed 's,[^:]*:,,'` + ac_file=`echo "$ac_file" | sed 's,:.*,,'` ;; + *:* ) ac_file_in=`echo "$ac_file" | sed 's,[^:]*:,,'` + ac_file=`echo "$ac_file" | sed 's,:.*,,'` ;; + * ) ac_file_in=$ac_file.in ;; + esac + + test x"$ac_file" != x- && { echo "$as_me:$LINENO: creating $ac_file" >&5 +echo "$as_me: creating $ac_file" >&6;} + + # First look for the input files in the build tree, otherwise in the + # src tree. + ac_file_inputs=`IFS=: + for f in $ac_file_in; do + case $f in + -) echo $tmp/stdin ;; + [\\/$]*) + # Absolute (can't be DOS-style, as IFS=:) + test -f "$f" || { { echo "$as_me:$LINENO: error: cannot find input file: $f" >&5 +echo "$as_me: error: cannot find input file: $f" >&2;} + { (exit 1); exit 1; }; } + # Do quote $f, to prevent DOS paths from being IFS'd. + echo "$f";; + *) # Relative + if test -f "$f"; then + # Build tree + echo "$f" + elif test -f "$srcdir/$f"; then + # Source tree + echo "$srcdir/$f" + else + # /dev/null tree + { { echo "$as_me:$LINENO: error: cannot find input file: $f" >&5 +echo "$as_me: error: cannot find input file: $f" >&2;} + { (exit 1); exit 1; }; } + fi;; + esac + done` || { (exit 1); exit 1; } + # Remove the trailing spaces. + sed 's/[ ]*$//' $ac_file_inputs >$tmp/in + +_ACEOF + +# Transform confdefs.h into two sed scripts, `conftest.defines' and +# `conftest.undefs', that substitutes the proper values into +# config.h.in to produce config.h. The first handles `#define' +# templates, and the second `#undef' templates. +# And first: Protect against being on the right side of a sed subst in +# config.status. Protect against being in an unquoted here document +# in config.status. +rm -f conftest.defines conftest.undefs +# Using a here document instead of a string reduces the quoting nightmare. +# Putting comments in sed scripts is not portable. +# +# `end' is used to avoid that the second main sed command (meant for +# 0-ary CPP macros) applies to n-ary macro definitions. +# See the Autoconf documentation for `clear'. +cat >confdef2sed.sed <<\_ACEOF +s/[\\&,]/\\&/g +s,[\\$`],\\&,g +t clear +: clear +s,^[ ]*#[ ]*define[ ][ ]*\([^ (][^ (]*\)\(([^)]*)\)[ ]*\(.*\)$,${ac_dA}\1${ac_dB}\1\2${ac_dC}\3${ac_dD},gp +t end +s,^[ ]*#[ ]*define[ ][ ]*\([^ ][^ ]*\)[ ]*\(.*\)$,${ac_dA}\1${ac_dB}\1${ac_dC}\2${ac_dD},gp +: end +_ACEOF +# If some macros were called several times there might be several times +# the same #defines, which is useless. Nevertheless, we may not want to +# sort them, since we want the *last* AC-DEFINE to be honored. +uniq confdefs.h | sed -n -f confdef2sed.sed >conftest.defines +sed 's/ac_d/ac_u/g' conftest.defines >conftest.undefs +rm -f confdef2sed.sed + +# This sed command replaces #undef with comments. This is necessary, for +# example, in the case of _POSIX_SOURCE, which is predefined and required +# on some systems where configure will not decide to define it. +cat >>conftest.undefs <<\_ACEOF +s,^[ ]*#[ ]*undef[ ][ ]*[a-zA-Z_][a-zA-Z_0-9]*,/* & */, +_ACEOF + +# Break up conftest.defines because some shells have a limit on the size +# of here documents, and old seds have small limits too (100 cmds). +echo ' # Handle all the #define templates only if necessary.' >>$CONFIG_STATUS +echo ' if grep "^[ ]*#[ ]*define" $tmp/in >/dev/null; then' >>$CONFIG_STATUS +echo ' # If there are no defines, we may have an empty if/fi' >>$CONFIG_STATUS +echo ' :' >>$CONFIG_STATUS +rm -f conftest.tail +while grep . conftest.defines >/dev/null +do + # Write a limited-size here document to $tmp/defines.sed. + echo ' cat >$tmp/defines.sed <<CEOF' >>$CONFIG_STATUS + # Speed up: don't consider the non `#define' lines. + echo '/^[ ]*#[ ]*define/!b' >>$CONFIG_STATUS + # Work around the forget-to-reset-the-flag bug. + echo 't clr' >>$CONFIG_STATUS + echo ': clr' >>$CONFIG_STATUS + sed ${ac_max_here_lines}q conftest.defines >>$CONFIG_STATUS + echo 'CEOF + sed -f $tmp/defines.sed $tmp/in >$tmp/out + rm -f $tmp/in + mv $tmp/out $tmp/in +' >>$CONFIG_STATUS + sed 1,${ac_max_here_lines}d conftest.defines >conftest.tail + rm -f conftest.defines + mv conftest.tail conftest.defines +done +rm -f conftest.defines +echo ' fi # grep' >>$CONFIG_STATUS +echo >>$CONFIG_STATUS + +# Break up conftest.undefs because some shells have a limit on the size +# of here documents, and old seds have small limits too (100 cmds). +echo ' # Handle all the #undef templates' >>$CONFIG_STATUS +rm -f conftest.tail +while grep . conftest.undefs >/dev/null +do + # Write a limited-size here document to $tmp/undefs.sed. + echo ' cat >$tmp/undefs.sed <<CEOF' >>$CONFIG_STATUS + # Speed up: don't consider the non `#undef' + echo '/^[ ]*#[ ]*undef/!b' >>$CONFIG_STATUS + # Work around the forget-to-reset-the-flag bug. + echo 't clr' >>$CONFIG_STATUS + echo ': clr' >>$CONFIG_STATUS + sed ${ac_max_here_lines}q conftest.undefs >>$CONFIG_STATUS + echo 'CEOF + sed -f $tmp/undefs.sed $tmp/in >$tmp/out + rm -f $tmp/in + mv $tmp/out $tmp/in +' >>$CONFIG_STATUS + sed 1,${ac_max_here_lines}d conftest.undefs >conftest.tail + rm -f conftest.undefs + mv conftest.tail conftest.undefs +done +rm -f conftest.undefs + +cat >>$CONFIG_STATUS <<\_ACEOF + # Let's still pretend it is `configure' which instantiates (i.e., don't + # use $as_me), people would be surprised to read: + # /* config.h. Generated by config.status. */ + if test x"$ac_file" = x-; then + echo "/* Generated by configure. */" >$tmp/config.h + else + echo "/* $ac_file. Generated by configure. */" >$tmp/config.h + fi + cat $tmp/in >>$tmp/config.h + rm -f $tmp/in + if test x"$ac_file" != x-; then + if diff $ac_file $tmp/config.h >/dev/null 2>&1; then + { echo "$as_me:$LINENO: $ac_file is unchanged" >&5 +echo "$as_me: $ac_file is unchanged" >&6;} + else + ac_dir=`(dirname "$ac_file") 2>/dev/null || +$as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$ac_file" : 'X\(//\)[^/]' \| \ + X"$ac_file" : 'X\(//\)$' \| \ + X"$ac_file" : 'X\(/\)' \| \ + . : '\(.\)' 2>/dev/null || +echo X"$ac_file" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; } + /^X\(\/\/\)[^/].*/{ s//\1/; q; } + /^X\(\/\/\)$/{ s//\1/; q; } + /^X\(\/\).*/{ s//\1/; q; } + s/.*/./; q'` + { if $as_mkdir_p; then + mkdir -p "$ac_dir" + else + as_dir="$ac_dir" + as_dirs= + while test ! -d "$as_dir"; do + as_dirs="$as_dir $as_dirs" + as_dir=`(dirname "$as_dir") 2>/dev/null || +$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$as_dir" : 'X\(//\)[^/]' \| \ + X"$as_dir" : 'X\(//\)$' \| \ + X"$as_dir" : 'X\(/\)' \| \ + . : '\(.\)' 2>/dev/null || +echo X"$as_dir" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; } + /^X\(\/\/\)[^/].*/{ s//\1/; q; } + /^X\(\/\/\)$/{ s//\1/; q; } + /^X\(\/\).*/{ s//\1/; q; } + s/.*/./; q'` + done + test ! -n "$as_dirs" || mkdir $as_dirs + fi || { { echo "$as_me:$LINENO: error: cannot create directory \"$ac_dir\"" >&5 +echo "$as_me: error: cannot create directory \"$ac_dir\"" >&2;} + { (exit 1); exit 1; }; }; } + + rm -f $ac_file + mv $tmp/config.h $ac_file + fi + else + cat $tmp/config.h + rm -f $tmp/config.h + fi +done +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF + +{ (exit 0); exit 0; } +_ACEOF +chmod +x $CONFIG_STATUS +ac_clean_files=$ac_clean_files_save + + +# configure is writing to config.log, and then calls config.status. +# config.status does its own redirection, appending to config.log. +# Unfortunately, on DOS this fails, as config.log is still kept open +# by configure, so config.status won't be able to write to it; its +# output is simply discarded. So we exec the FD to /dev/null, +# effectively closing config.log, so it can be properly (re)opened and +# appended to by config.status. When coming back to configure, we +# need to make the FD available again. +if test "$no_create" != yes; then + ac_cs_success=: + ac_config_status_args= + test "$silent" = yes && + ac_config_status_args="$ac_config_status_args --quiet" + exec 5>/dev/null + $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false + exec 5>>config.log + # Use ||, not &&, to avoid exiting from the if with $? = 1, which + # would make configure fail if this is the last instruction. + $ac_cs_success || { (exit 1); exit 1; } +fi + diff --git a/xpa/configure.ac b/xpa/configure.ac new file mode 100644 index 0000000..fb5aeb2 --- /dev/null +++ b/xpa/configure.ac @@ -0,0 +1,217 @@ +# This file is an input file used by the GNU "autoconf" program to +# generate the file "configure", which is run during XPA installation +# to configure the system for the local environment. +AC_INIT(xpa, 2.1.18, eric@cfa.harvard.edu, xpa) + +AC_CONFIG_HEADERS([conf.h]) +AC_CONFIG_SRCDIR(./xpa.h) +AC_CANONICAL_HOST + +# save LDFLAGS +XLDFLAGS="$LDFLAGS" + +# +# checks that we use in most projects +# +AC_PROG_CC + +AC_EXEEXT +if test x"${EXEEXT}" = "xno"; then + EXEEXT="" +fi + +AC_CHECK_SIZEOF(long) +SZ_LONG=$ac_cv_sizeof_long +AC_SUBST(SZ_LONG) + +AC_PROG_RANLIB + +AC_HEADER_STDC +AC_CHECK_HEADERS(malloc.h) +AC_CHECK_HEADERS(getopt.h) +AC_CHECK_HEADERS(pwd.h) +AC_CHECK_HEADERS(values.h) +AC_CHECK_HEADERS(dlfcn.h) +AC_CHECK_HEADERS(setjmp.h) +AC_CHECK_HEADERS(sys/un.h) +AC_CHECK_HEADERS(sys/shm.h) +AC_CHECK_HEADERS(sys/mman.h) +AC_CHECK_HEADERS(sys/ipc.h) +AC_CHECK_HEADERS(sys/select.h) + +AC_CHECK_TYPES([socklen_t], [], [], [#include <sys/socket.h>]) + +AC_C_CONST + +AC_CHECK_FUNCS(strchr memcpy snprintf atexit setenv) + +AC_CHECK_FUNC(connect) +if test $ac_cv_func_connect = no; then + AC_CHECK_LIB(socket, connect, EXTRA_LIBS="$EXTRA_LIBS -lsocket") +fi +AC_CHECK_FUNC(gethostbyname) +if test $ac_cv_func_gethostbyname = no; then + AC_CHECK_LIB(nsl, gethostbyname, EXTRA_LIBS="$EXTRA_LIBS -lnsl") +fi +# AC_CHECK_LIB(db, snprintf, EXTRA_LIBS="$EXTRA_LIBS -ldb") + +# +# checks specific to this project +# + +AC_MSG_CHECKING(for threaded xpans) +AC_ARG_ENABLE(threaded-xpans, [ --enable-threaded-xpans build threaded xpans], + [fun_ok=$enableval], [fun_ok=no]) +if test "$fun_ok" = "yes"; then + AC_MSG_RESULT($fun_ok) + AC_CHECK_LIB(pthread, pthread_create, have_pthread=yes) + if test x"${have_pthread}" = x"yes"; then + AC_DEFINE(HAVE_LIBPTHREAD) + AC_DEFINE(_REENTRANT) + TLIB="-lpthread" + else + AC_MSG_ERROR([no threads found ... can't use enable-threaded-xpans], 1) + fi +else + AC_MSG_RESULT($fun_ok) +fi +AC_SUBST(TLIB) + +AC_MSG_CHECKING(for shared library build) +AC_ARG_ENABLE(shared, [ --enable-shared build shared libraries], + [fun_ok=$enableval], [fun_ok=no]) +if test "$fun_ok" != "no"; then + fpic="yes" + DOSHARED=shlib + AC_SUBST(DOSHARED) + if test "$fun_ok" = "link"; then + LLIB="-L. -l$PACKAGE_NAME" + else + LLIB='$(LIB)' + fi +else + DOSHARED="" + LLIB='$(LIB)' +fi +AC_SUBST(LLIB) +AC_MSG_RESULT($fun_ok) + +AC_MSG_CHECKING(for request to use posix_spawn) +AC_ARG_ENABLE(posix_spawn, [ --enable-posix_spawn use posix_spawn() if available], + [fun_ok=$enableval], [fun_ok=no]) +AC_MSG_RESULT($fun_ok) +if test "$fun_ok" = "yes"; then + AC_CHECK_FUNCS(posix_spawn _NSGetEnviron) + AC_CHECK_HEADERS(crt_externs.h) +fi + +AC_PATH_XTRA +if test x"${have_x}" = "xyes"; then + AC_DEFINE(HAVE_XT) +fi + +SC_PATH_TCLCONFIG +if test x"${no_tcl}" = x ; then + SC_LOAD_TCLCONFIG + if test -r $TCL_PREFIX/include/tcl.h; then + TCL_CFLAGS="$TCL_INCLUDE_SPEC" + if test x"$DOSHARED" != x -a x"$TCL_SUPPORTS_STUBS" = x1; then + TCL_LIBS="$TCL_STUB_LIB_SPEC" + TCL_CFLAGS="$TCL_CFLAGS -DUSE_TCL_STUBS=1" + AC_MSG_RESULT([Tcl support will utilize stubs library: $TCL_LIBS]) + else + TCL_LIBS="$TCL_LIB_SPEC" + AC_MSG_RESULT([Tcl support will utilize library: $TCL_LIBS]) + fi + AC_DEFINE(HAVE_TCL) + else + if test x"${with_tclconfig}" != x ; then + TCL_CFLAGS="$TCL_INCLUDE_SPEC" + TCL_LIBS="$TCL_LIB_SPEC" + AC_DEFINE(HAVE_TCL) + AC_MSG_RESULT([warning: tcl.h not found with --with-tcl ... tcl build might fail]) + else + AC_MSG_RESULT([$TCL_PREFIX/include/tcl.h not found ... use --with-tcl to build tcl explicitly]) + fi + fi +fi +AC_SUBST(TCL_CFLAGS) +AC_SUBST(TCL_LIBS) + +AC_MSG_CHECKING(for incorporation of thread support) +AC_ARG_WITH(threads, + [ --with-threads build for use in threaded programs], thr=1, thr=0) +if test x"$thr" = x1 ; then + AC_MSG_RESULT(yes) + CFLAGS="$CFLAGS -D_REENTRANT" +else + AC_MSG_RESULT(no) +fi + +AC_MSG_CHECKING(for gtk) +AC_ARG_WITH(gtk, + [ --with-gtk=<path> include directory for gtk e.g. /usr/include/gtk-1.2], havelib=1, havelib=0) +if test x"$havelib" = x1 ; then + AC_MSG_RESULT(yes ($withval)) + GTK_CFLAGS="`pkg-config gtk+-2.0 --cflags` -DHAVE_GTK=1" + GTK_LIBS="`pkg-config gtk+-2.0 --libs`" + AC_DEFINE(HAVE_GTK) +else + GTK_CFLAGS="" + GTK_LIBS="" + AC_MSG_RESULT(no) +fi +AC_SUBST(GTK_CFLAGS) +AC_SUBST(GTK_LIBS) + +# restore LDFLAGS +LDFLAGS="$LDFLAGS $XLDFLAGS" + +AC_MSG_CHECKING([$host_os configuration]) +case $host_os in + *cygwin*|*Cygwin* ) + AC_DEFINE(HAVE_CYGWIN) + AC_MSG_RESULT([flagging Cygwin]) + ;; + *mingw32*|*Mingw32*) + CFLAGS="$CFLAGS -mconsole" + EXTRA_LIBS="$EXTRA_LIBS -lwsock32" + AC_DEFINE(HAVE_MINGW32) + AC_MSG_RESULT([flagging MinGW]) + ;; + *darwin*|*Darwin*) + LDFLAGS="$LDFLAGS $CFLAGS" + G=`$CC -v 2>&1 | grep version | awk '{print $3}' | awk -F. '{print $1$2}'` + if test x"$G" != x -a "$G" -lt 42; then + CFLAGS="$CFLAGS -no-cpp-precomp" + fi + if test x"$TCL_PREFIX" = x"/usr/local"; then + TCL_CFLAGS="" + AC_MSG_RESULT([removing -I/usr/local/include]) + fi + ;; + *osf*|*Osf*) + AC_CHECK_LIB(db, snprintf, EXTRA_LIBS="$EXTRA_LIBS -ldb") + ;; + * ) + if test x"$fpic" = x"yes" ; then + if test "$CC" = "gcc" -o `$CC -v 2>&1 | grep -c gcc` != "0" ; then + CFLAGS="$CFLAGS -fPIC" + AC_MSG_RESULT([adding -fPIC to gcc]) + else + AC_MSG_RESULT(none) + fi + else + AC_MSG_RESULT(none) + fi + ;; +esac + +AC_SUBST(EXTRA_LIBS) + +AC_CONFIG_FILES(Makefile) + +# generate pkg-config meta-data file +AC_CONFIG_FILES(xpa.pc) + +AC_OUTPUT diff --git a/xpa/copyright b/xpa/copyright new file mode 100644 index 0000000..e115788 --- /dev/null +++ b/xpa/copyright @@ -0,0 +1,30 @@ +Unless otherwise indicated, all source is: + +Copyright (C) 1999-2013 +Smithsonian Astrophysical Observatory, Cambridge, MA, USA + +XPA is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +Correspondence concerning XPA should be addressed as follows: + +Eric Mandel +Smithsonian Astrophysical Observatory +MS 3 +60 Garden St. +Cambridge, MA 02138 USA + +eric@cfa.harvard.edu + +http://hea-www.harvard.edu/saord/xpa/ diff --git a/xpa/ctest.c b/xpa/ctest.c new file mode 100644 index 0000000..b4827d1 --- /dev/null +++ b/xpa/ctest.c @@ -0,0 +1,684 @@ +/* + * Copyright (c) 1999-2003 Smithsonian Astrophysical Observatory + */ + +/* + * + * ctest -- client test for xpa + * + */ +#include <xpap.h> + +extern char *optarg; +extern int optind; + +int quiet=0; +int dowait=0; +int n=0; +int don=0; +int save_bytes=-1; +int exitonerror=0; +char *save_buf=NULL; +char *mode=""; +char name[SZ_LINE]; + +#define MAX_FPS 4 + +#ifdef ANSI_FUNC +int +send_cb (void *client_data, void *call_data, char *paramlist, + char **buf, size_t *len) +#else +int send_cb(client_data, call_data, paramlist, buf, len) + void *client_data; + void *call_data; + char *paramlist; + char **buf; + size_t *len; +#endif +{ + char *s = (char *)client_data; + XPA xpa = (XPA)call_data; + char tbuf[SZ_LINE]; + int sendbuf=0; + + /* introduce ourselves */ + if( !quiet ){ + fprintf(stdout, "SEND_CB #%d: %s:%s (%s)\n", + n++, xpa_class(xpa), xpa_name(xpa), s); + } + + /* process special paramlist tokens */ + if( paramlist && *paramlist ){ + if( !quiet ) + fprintf(stdout, "\tparamlist: %s\n", paramlist); + if( !strncmp(paramlist, "buf", 3) ){ + sendbuf=1; + } + else if( !strncmp(paramlist, "error", 5) ){ + if( !quiet ) + fprintf(stdout, "\treturning error: %s\n", ¶mlist[6]); + *len = 0; + *buf = NULL; + XPAError(xpa, ¶mlist[6]); + return(-1); + } + else if( !strcmp(paramlist, "exit") ){ + if( !quiet ) + fprintf(stdout, "Exiting\n"); + exit(0); + } + else if( !strcmp(paramlist, "wait") ){ + fprintf(stdout, "Press <CR> to continue ..."); + fgets(tbuf, SZ_LINE, stdin); + } + } + else if( dowait ){ + fprintf(stdout, "Press <CR> to continue ..."); + fgets(tbuf, SZ_LINE, stdin); + } + + /* return information about this xpa */ + if( !sendbuf ){ + snprintf(tbuf, SZ_LINE, + "nclass: %s\nname: %s\nmethod: %s\nsendian: %s\ncendian: %s\n", + xpa_class(xpa), xpa_name(xpa), xpa_method(xpa), + xpa_sendian(xpa), xpa_cendian(xpa)); + + if( (xpa->send_mode & XPA_MODE_FILLBUF) ){ + send(xpa_datafd(xpa), tbuf, strlen(tbuf), 0); + *len = 0; + *buf = NULL; + if( !quiet) + fprintf(stdout, "\tcallback writes %d bytes to client\n", + (int)strlen(tbuf)); + } + /* return the buffer and let xpa transmit it */ + else{ + *len = strlen(tbuf); + *buf = (char *)xmalloc(*len); + memcpy(*buf, tbuf, *len); + if( !quiet) + fprintf(stdout, "\tcallback returns %d bytes to xpa handler\n", + (int)strlen(tbuf)); + } + } + /* return the last buffer we were sent */ + else{ + if( (xpa->send_mode & XPA_MODE_FILLBUF) ){ + send(xpa_datafd(xpa), save_buf, save_bytes, 0); + *len = 0; + *buf = NULL; + if( !quiet) + fprintf(stdout, "\tcallback writes %d bytes to client\n", save_bytes); + } + /* return the buffer and let xpa transmit it */ + else{ + *len = save_bytes; + *buf = (char *)xmalloc(*len); + memcpy(*buf, save_buf, *len); + if( !quiet) + fprintf(stdout, "\tcallback returns %d bytes to xpa handler\n", + save_bytes); + } + } + fflush(stdout); + fflush(stderr); + return(0); +} + +#ifdef ANSI_FUNC +int +receive_cb (void *client_data, void *call_data, char *paramlist, + char *buf, size_t len) +#else +int receive_cb(client_data, call_data, paramlist, buf, len) + void *client_data; + void *call_data; + char *paramlist; + char *buf; + size_t len; +#endif +{ + XPA xpa = (XPA)call_data; + char *s = (char *)client_data; + char tbuf[SZ_LINE]; + char *errs[1]; + int i; + int ip; + int got; + int xwait; + + if( !quiet ){ + fprintf(stdout, "RECEIVE_CB #%d: %s:%s (%s)\n", + n++, xpa_class(xpa), xpa_name(xpa), s); + } + if( !quiet ){ + fprintf(stdout, "\tbuf: %lu bytes\n", (unsigned long)len); + } + + /* process param list */ + if( paramlist && *paramlist ){ + if( !quiet ) + fprintf(stdout, "\tparamlist: %s\n", paramlist); + if( !strcmp(paramlist, "free") ){ + if( !quiet ) + fprintf(stdout, "Freeing xpa struct\n"); + XPAFree(xpa); + return(0); + } + else if( !strncmp(paramlist, "error", 5) ){ + if( !quiet ) + fprintf(stdout, "Processing error: %s\n", ¶mlist[6]); + XPAError(xpa, ¶mlist[6]); + return(-1); + } + else if( !strcmp(paramlist, "exit") ){ + if( !quiet ) + fprintf(stdout, "Exiting\n"); + exit(0); + } + else if( !strcmp(paramlist, "wait") ){ + fprintf(stdout, "Press <CR> to continue ..."); + fgets(tbuf, SZ_LINE, stdin); + } + else if( !strncmp(paramlist, "xpaset", 6) ){ + ip = 0; + word(paramlist, tbuf, &ip); + if( word(paramlist, tbuf, &ip) ){ + if( !quiet ) + fprintf(stdout, "calling XPASet(%s, \"%s\")\n", + tbuf, &(paramlist[ip])); + got = XPASet(NULL, tbuf, &(paramlist[ip]), mode, + paramlist, strlen(paramlist), NULL, errs, 1); + if( got == 0 ){ + if( !quiet ) + fprintf(stdout, "no XPA access points matched template %s\n", + tbuf); + } + else if( errs[0] != NULL ){ + if( !quiet ) + fprintf(stdout, "Error on xpaset to %s: %s\n", tbuf, errs[0]); + xfree(errs[0]); + if( exitonerror ) + exit(1); + } + else{ + if( !quiet ) + fprintf(stdout, "XPASet to %s successful\n", tbuf); + } + } + return(0); + } + } + else if( dowait ){ + fprintf(stdout, "Press <CR> to continue ..."); + fgets(tbuf, SZ_LINE, stdin); + } + + /* reset save buffer */ + if( save_buf != NULL ){ + xfree(save_buf); + save_buf = NULL; + } + save_bytes = 0; + + xwait = dowait; + if( !(xpa->receive_mode & XPA_MODE_FILLBUF) ){ + while( (got=recv(xpa_datafd(xpa), tbuf, SZ_LINE, 0)) >0 ){ + if( xwait >0 ){ + fprintf(stdout, "got %d bytes ... press <CR> to continue ...", got); + fgets(tbuf, SZ_LINE, stdin); + xwait--; + } + i = save_bytes; + save_bytes += got; + if( save_buf == NULL ) + save_buf = (char *)xmalloc(save_bytes); + else + save_buf = (char *)xrealloc(save_buf, save_bytes); + memcpy(&save_buf[i], tbuf, got); + } + if( !quiet ) + fprintf(stdout, "callback read %d bytes\n", save_bytes); + } + else{ + save_bytes = len; + save_buf = (char *)xmalloc(len); + memcpy(save_buf, buf, len); + } + fflush(stdout); + fflush(stderr); + return(0); +} + +#ifdef ANSI_FUNC +int +info_cb (void *client_data, void *call_data, char *paramlist) +#else +int info_cb(client_data, call_data, paramlist) + void *client_data; + void *call_data; + char *paramlist; +#endif +{ + XPA xpa = (XPA)call_data; + char *s = (char *)client_data; + char xtemplate[SZ_LINE]; + char *names[MAX_FPS]; + char *bufs[MAX_FPS]; + char *errs[MAX_FPS]; + size_t lens[MAX_FPS]; + int i; + int ip; + int got; + + if( !quiet ){ + fprintf(stdout, "INFO_CB #%d: %s:%s (%s)\n", + n++, xpa_class(xpa), xpa_name(xpa), s); + } + + if( paramlist && *paramlist ){ + if( !quiet ) + fprintf(stdout, "\tparamlist: %s\n", paramlist); + ip = 0; + word(paramlist, xtemplate, &ip); + if( !strcmp(xtemplate, "xpaget") ){ + word(paramlist, xtemplate, &ip); + got = XPAGet(xpa, xtemplate, &(paramlist[ip]), NULL, + bufs, lens, names, errs, MAX_FPS); + if( !quiet ) + fprintf(stdout, "XPAGet (%s) returned %d buffer(s)\n", xtemplate, got); + for(i=0; i<got; i++){ + if( !quiet ) + fprintf(stdout, "\t%d: %s\n", i, names[i]); + if( errs[i] == NULL ){ + if( lens[i] > 0 ){ + fprintf(stdout, "contents (%lu bytes):\n", (unsigned long)lens[i]); + write(fileno(stdout), bufs[i], lens[i]); + } + if( !quiet ) + fprintf(stdout, "\n"); + } + else{ + write(fileno(stdout), errs[i], strlen(errs[i])); + if( exitonerror ) + exit(1); + } + if( bufs[i] ) + xfree(bufs[i]); + if( names[i] ) + xfree(names[i]); + if( errs[i] ) + xfree(errs[i]); + } + } + } + fflush(stdout); + fflush(stderr); + return(0); +} + +#ifdef ANSI_FUNC +int +main (int argc, char **argv) +#else +int +main(argc, argv) + int argc; + char **argv; +#endif +{ + char *plist=NULL; + char *paramlist=NULL; + char *xtemplate="*:*"; + char *smode=NULL; + char tbuf[SZ_LINE]; + char name[SZ_LINE]; + char cmd[SZ_LINE]; + char fxpa[SZ_LINE]; + char *names[MAX_FPS]; + char *bufs[MAX_FPS]; + char *dbufs[MAX_FPS]; + char *errs[MAX_FPS]; + char *buf=NULL; + int c; + size_t lens[MAX_FPS]; + size_t dlens[MAX_FPS]; + int i; + int got; + int maxbufs; + int j=0; + int loop=1; + int delay=0; + int get=1; + int set=0; + int info=0; + int access=0; + int pipe=0; + int tiny=0; + int doxpa = 0; + int xpaopen=0; + int wait=0; + XPA xpa=NULL; + XPA xpa1=NULL; + int fds[1]; + +#if HAVE_MINGW32==0 + setvbuf(stdout, NULL, _IONBF, 0); + setvbuf(stderr, NULL, _IONBF, 0); +#endif + + *cmd = '\0'; + /* process switch arguments */ + while ((c = getopt(argc, argv, "abd:ef:gil:m:nopqstwx:")) != -1){ + switch(c){ + case 'a': + get = 0; + set = 0; + info = 0; + access = 1; + break; + case 'b': + get = 1; + set = 1; + info = 0; + access = 0; + break; + case 'd': + delay = atoi(optarg); + break; + case 'e': + exitonerror++; + break; + case 'f': + snprintf(cmd, SZ_LINE, "stest %s &\n", optarg); + snprintf(fxpa, SZ_LINE, "%s1", optarg); + break; + case 'g': + get = 1; + set = 0; + info = 0; + access = 0; + break; + case 'i': + get = 0; + set = 0; + info = 1; + access = 0; + break; + case 'l': + loop = atoi(optarg); + break; + case 'm': + smode = xstrdup(optarg); + break; + case 'n': + don = 1; + break; + case 'o': + xpaopen = 1; + break; + case 'p': + pipe = 1; + fds[0] = fileno(stdout); + break; + case 'q': + quiet = 1; + break; + case 's': + get = 0; + set = 1; + info = 0; + access = 0; + break; + case 't': + tiny = 1; + break; + case 'w': + wait = 1; + break; + case 'x': + doxpa = 1; + strcpy(name, optarg); + break; + } + } + if( optind < argc ){ + xtemplate = argv[optind]; + optind++; + } + + /* make up the paramlist */ + plist = XPAArgvParamlist(argc, argv, optind); + if( !don ) + paramlist = plist; + else + paramlist = (char *)xcalloc(strlen(plist)+SZ_LINE, sizeof(char)); + + /* for setting, make up a number of dbufs that we will send */ + if( set ){ + /* must be less than MAX_FPS */ + maxbufs = 2; + + dbufs[0] = (char *)xmalloc(SZ_LINE); + strcpy(dbufs[0], "this is a short string"); + dlens[0] = strlen(dbufs[0]); + + if( tiny ) + dlens[1] = 256+1; + else + dlens[1] = 256*1000+1; + dbufs[1] = (char *)xmalloc(dlens[1]); + for(j=0, buf=dbufs[1]; j<dlens[1]; j++){ + buf[j] = j%256; + } + } + + /* background process initialization */ + if( *cmd != '\0' ){ + fprintf(stdout, "starting bkgd process: %s", cmd); + system(cmd); + for(i=0, n=0; i<5; i++){ + if( (got=XPAAccess(NULL, fxpa, "g", NULL, names, errs, MAX_FPS)) ){ + for(j=0; j<got; j++){ + if( names[j] ) xfree(names[j]); + if( !errs[j] ) + n++; + else + xfree(errs[j]); + } + if( n ){ + fprintf(stdout, "process is started\n"); + break; + } + } + else{ + XPASleep(1000); + } + } + } + + /* start up an xpa server, if necessary */ + if( doxpa ) { + snprintf(tbuf, SZ_LINE, "%s from ctest", name); + if( (xpa1 = XPANew("CLIENT", name, name, + send_cb, tbuf, mode, receive_cb, tbuf, mode)) == NULL ){ + fprintf(stderr, "ERROR: could not init client xpa: %s\n", name); + } + else{ + fprintf(stdout, "%s using method: %s\n", + xpa_name(xpa1), xpa_method(xpa1)); + } + } + + /* XPAOpen */ + if( xpaopen ){ + if( (xpa = XPAOpen(NULL)) == NULL ){ + fprintf(stderr, "ERROR: could not open any xpa access points: %s\n", + xtemplate); + exit(1); + } + } + + /* iterate */ + for(j=0; j<loop; j++){ + if( loop > 1 ){ + if( !quiet ){ + fprintf(stdout, "CLIENT #%d: %s\n", j, xtemplate); + if( paramlist && *paramlist ) + fprintf(stdout, "\tparamlist: %s\n", paramlist); + } + } + /* make up paramlist, if necessary */ + if( don ) + snprintf(paramlist, SZ_LINE, "%s %d", plist, j); + /* XPAGet, XPAGetFd */ + if( get ){ + if( pipe ){ + got = XPAGetFd(xpa, xtemplate, paramlist, smode, + fds, names, errs, -MAX_FPS); + } + else{ + got = XPAGet(xpa, xtemplate, paramlist, smode, + bufs, lens, names, errs, MAX_FPS); + for(i=0; i<got; i++){ + if( !quiet ){ + if( strcmp(paramlist, "buf") ) + fprintf(stdout, "\treceived from %s\n", names[i]); + if( errs[i] == NULL ){ + if( lens[i] > 0 ){ + write(fileno(stdout), bufs[i], lens[i]); + } + if( strcmp(paramlist, "buf") ) + fprintf(stdout, "\n"); + } + else{ + write(fileno(stdout), errs[i], strlen(errs[i])); + if( exitonerror ) + exit(1); + } + } + if( bufs[i] ) + xfree(bufs[i]); + if( names[i] ) + xfree(names[i]); + if( errs[i] ) + xfree(errs[i]); + } + } + } + + /* XPASet, XPASetFd */ + if( set ){ + if( pipe ){ + if( !quiet ) + fprintf(stdout, "\tsending data from stdin\n"); + got =XPASetFd(xpa, xtemplate, paramlist, smode, + fileno(stdin), names, errs, MAX_FPS); + } + else{ + got = XPASet(xpa, xtemplate, paramlist, smode, + dbufs[j%maxbufs], dlens[j%maxbufs], + names, errs, MAX_FPS); + } + for(i=0; i<got; i++){ + if( !quiet ) + fprintf(stdout, "\tsent %lu bytes to %s\n", + (unsigned long)dlens[j%maxbufs], names[i]); + if( errs[i] != NULL ){ + fprintf(stdout, "Error from server %s\n", names[i]); + write(fileno(stdout), errs[i], strlen(errs[i])); + if( exitonerror ) + exit(1); + } + if( names[i] ) + xfree(names[i]); + if( errs[i] ) + xfree(errs[i]); + } + } + + /* XPAInfo */ + if( info ){ + got = XPAInfo(xpa, xtemplate, paramlist, smode, names, errs, MAX_FPS); + for(i=0; i<got; i++){ + if( !quiet ){ + fprintf(stdout, "\tinfo from %s\n", names[i]); + if( errs[i] != NULL ){ + write(fileno(stdout), errs[i], strlen(errs[i])); + if( exitonerror ) + exit(1); + } + } + if( names[i] ) + xfree(names[i]); + if( errs[i] ) + xfree(errs[i]); + } + } + + /* XPAAccess */ + if( access ){ + got = XPAAccess(xpa, xtemplate, paramlist, smode, names, errs, MAX_FPS); + for(i=0; i<got; i++){ + if( !quiet ){ + fprintf(stdout, "\taccess from %s\n", names[i]); + if( errs[i] != NULL ){ + write(fileno(stdout), errs[i], strlen(errs[i])); + if( exitonerror ) + exit(1); + } + } + if( names[i] ) + xfree(names[i]); + if( errs[i] ) + xfree(errs[i]); + } + } + + /* if we processed no access points, let`s hear about it */ + if( got == 0 ){ + fprintf(stderr, "XPA$ERROR: no xpa access points processed\n"); + } + else{ + if( !quiet ){ + if( strcmp(paramlist, "buf") ) + fprintf(stdout, "CLIENT #%d complete\n", j); + } + else{ + fprintf(stdout, "."); + fflush(stdout); + } + } + + /* wait for next iteration */ + if( wait ){ + fprintf(stdout, "Press <CR> to continue ..."); + fgets(tbuf, SZ_LINE, stdin); + } + + /* delay */ + if( delay ) + XPASleep(delay); + } + + /* XPAOpen/XPAClose */ + if( xpaopen ){ + XPAClose(xpa); + } + + /* free up space */ + if( set ){ + for(j=0; j<maxbufs; j++){ + if( dbufs[j] ) + xfree(dbufs[j]); + } + } + if( plist ) xfree(plist); + if( don ) xfree(paramlist); + if( smode ) xfree(smode); + /* make valgrind happy */ + XPACleanup(); + exit(0); +} diff --git a/xpa/dns.c b/xpa/dns.c new file mode 100644 index 0000000..32e33b1 --- /dev/null +++ b/xpa/dns.c @@ -0,0 +1,48 @@ +/* + * Copyright (c) 1999-2003 Smithsonian Astrophysical Observatory + */ + +#include <unistd.h> +#include <strings.h> +#include <stdio.h> +#include <netdb.h> /* gethostbyname() */ + +#define SZ_LINE 1024 + +int main(int argc, char **argv) +{ + int i; + char host[SZ_LINE]; + struct hostent *hostent; + + if( argc > 1 ) + strcpy(host, argv[1]); + else{ + fprintf(stderr, "calling gethostname() ...\n"); + if( gethostname(host, SZ_LINE) == -1 ){ + perror("gethostname"); + exit(1); + } + else{ + fprintf(stderr, "host name is %s\n", host); + } + } + fprintf(stderr, "calling gethostbyname(host) ...\n"); + if( !(hostent = gethostbyname(host)) ){ + perror("gethostbyname"); + exit(1); + } + else{ + fprintf(stderr, "gethostbyname() succeeded\n"); + } + fprintf(stderr, "printing ip address(es) for this host ...\n"); + if( hostent ){ + for(i=0; hostent->h_addr_list[i]; i++){ + fprintf(stderr, "%x\n", *(int *)hostent->h_addr_list[i]); + } + } + else{ + fprintf(stderr, "ERROR: can't look up: %s\n", host); + } + return(0); +} diff --git a/xpa/doc/Makefile b/xpa/doc/Makefile new file mode 100644 index 0000000..eda8931 --- /dev/null +++ b/xpa/doc/Makefile @@ -0,0 +1,51 @@ +# +# Makefile for misc programs, not good enough for their own directory +# + +RM = rm +RMFLAGS = -f +MV = mv +MVFLAGS = -f +CP = cp +CPFLAGS = -p + +MANDIR = ../man + +all: dirs files hardcopy + +dirs: + @(if [ ! -d ${MANDIR} ]; then \ + mkdir ${MANDIR}; \ + mkdir ${MANDIR}/man1 ${MANDIR}/man3 ${MANDIR}/mann; \ + fi) + +files: + @(for i in *.html; do \ + echo processing $$i; \ + ./html2man ../man < $$i; \ + done) + +hardcopy: + html2ps -C fb -d -g -n -u -W b -x 1 -o xpa.ps help.html + ps2pdf xpa.ps xpa.pdf + + +# NB: sman.conf must be copied to $HOME or else its not found ... +# we also have to figure out where swish-e is located and hardwire it +index: szlong + @(cd ..; MANPATH=`pwd`/man; export MANPATH; cd doc; \ + SW=`which swish-e`; \ + SZ_LONG=`./szlong`; \ + sed -e 's#@SW@#'$$SW'#g' < sman_conf.tmpl > $${HOME}/sman.conf; \ + sman-update --clearcache; \ + sman-update --verbose --index=./sman/xpa$${SZ_LONG}.index; \ + rm -f $${HOME}/sman.conf szlong) + +szlong: szlong.c + $(CC) $(CFLAGS) -o szlong szlong.c + +clean: + -$(RM) $(RMFLAGS) *.BAK *.bak *.o core errs ,* *~ *.a \ + foo* goo* tags TAGS html2ps.dbg + + diff --git a/xpa/doc/acl.html b/xpa/doc/acl.html new file mode 100644 index 0000000..b1f458d --- /dev/null +++ b/xpa/doc/acl.html @@ -0,0 +1,137 @@ +<!-- =defdoc xpaacl xpaacl n --> +<HTML> +<HEAD> +<TITLE>XPA Access Control</TITLE> +</HEAD> +<BODY> + +<!-- =section xpaacl NAME --> +<H2><A NAME="xpaacl">XPAAcl: Access Control for XPA Messaging</A></H2> + +<!-- =section xpaacl SYNOPSIS --> +<H2>Summary</H2> +<P> +XPA supports host-based access control for each XPA access point. You +can enable/disable access control using the XPA_ACL environment +variable. You can specify access to specific XPA access points for +specific machines using the XPA_DEFACL and XPA_ACLFILE environment +variables. By default, an XPA access point is accessible only to +processes running on the same machine (same as X Windows). + +<!-- =section xpaacl DESCRIPTION --> +<H2>Description</H2> +<P> +When INET sockets are in use (the default, as specified by the +<EM>XPA_METHOD</EM> environment variable), XPA supports a host-based +access control mechanism for individual access points. This mean that +access can be specified for get, set, or info operations for each +access point on a machine by machine basis. For LOCAL sockets, access +is restricted (by definition) to the host machine. + +<P> +XPA access control is enabled by default, but can be turned off by +setting the <EM>XPA_ACL</EM> environment variable to <EM>false</EM>. +In this case, any process can access any XPA server. + +<P> +Assuming that access control is turned on, the ACL for an individual +XPA access point is set up when that access point is registered +(although it can be changed later on; see below). This can be done in +one of two ways: + +Firstly, the <EM>XPA_ACLFILE</EM> environment variable can defined to +point to a file of access controls for individual access points. The format +of this file is: +<pre> + class:name ip acl +</pre> +The first argument is a template that specifies the class:name of the +access point covered by this ACL. See +<A HREF="./template.html">XPA Access Points and Templates</A> +for more information about xpa templates. + +<P> +The second argument is the IP address (in human-readable format) of +the machine which is being given access. This argument can be +<EM>*</EM> to match all IP addresses. It also can be <EM>$host</EM> +to match the IP address of the current host. + +<P> +The third argument is a string combination of <EM>s</EM>, <EM>g</EM>, +or <EM>i</EM> to allow <EM>xpaset</EM>, <EM>xpaget</EM>, or +<EM>xpainfo</EM> access respectively. The ACL argument can be +<EM>+</EM> to give <EM>sgi</EM> access or it can be <EM>-</EM> to turn +off all access. + +<P> +For example, +<PRE> + *:xpa1 somehost sg + *:xpa1 myhost + + * * g +</PRE> +will allow processes on the machine somehost to make xpaget and xpaset calls, +allow processes on myhost to make any call, and allow all other hosts to +make xpaget (but not xpaset) calls. + +Secondly, if the <EM>XPA_ACLFILE</EM> does not exist, then a single +default value for all access points can be specified using the +<EM>XPA_DEFACL</EM> environment variable. The default value for this +variable is: +<PRE> + #define XPA_DEFACL "*:* $host +" +</PRE> +meaning that all access points are fully accessible to all processes +on the current host. Thus, in the absence of any ACL environment variables, +processes on the current host have full access to all access points +created on that host. This parallels the X11 xhost mechanism. + +<P> +Access to an individual XPA access point can be changed using the -acl +parameter for that access point. For example: +<PRE> + xpaset -p xpa1 -acl "somehost -" +</PRE> +will turn off all access control for somehost to the xpa1 access point, while: +<PRE> + xpaset -p XPA:xpa1 -acl "beberly gs" +</PRE> +will give beberly xpaget and xpaset access to the access point whose +class is XPA and whose name is xpa1. +<P> +Similarly, the current ACL for a given access point can be retrieved using: +<PRE> + xpaget xpa1 -acl +</PRE> +Of course, you must have xpaget access to this XPA access point to +retrieve its ACL. + +<P> +Note that the XPA access points registered in the <EM>xpans</EM> +program also behave according to the ACL rules. That is, you cannot +use xpaget to view the access points registered with xpans unless +you have the proper ACL. + +<P> +Note also when a client request is made to an XPA server, the access +control is checked when the initial connection is established. This +access in effect at this time remains in effect so long as the client +connection is maintained, regardless of whether the access fro that +XPA is changed later on. + +<P> +We recognize that host-based access control is only relatively secure +and will consider more stringent security (e.g., private key) in the +future if the community requires such support. + +<!-- =section xpaacl SEE ALSO --> +<!-- =text See xpa(n) for a list of XPA help pages --> +<!-- =stop --> + +<P> +<A HREF="./help.html">Go to XPA Help Index</A> + +<H5>Last updated: September 10, 2003</H5> + +</BODY> +</HTML> diff --git a/xpa/doc/changelog.html b/xpa/doc/changelog.html new file mode 100644 index 0000000..c7b146a --- /dev/null +++ b/xpa/doc/changelog.html @@ -0,0 +1,806 @@ +<HTML> +<HEAD> +<TITLE>XPA ChangeLog</TITLE> +</HEAD> +<BODY> +<H2>XPA ChangeLog</H2> + +<P> +This ChangeLog covers the XPA 2 implementation. It will be updated +as we continue to develop and improve XPA. The up-to-date version can be +found <A HREF="http://hea-www.harvard.edu/RD/xpa/changelog.html">here</A>. + +<H2> Public Release 2.1.16 (TBD)</H2> +<ul> +<li> Ensure that mingw utilizes Windows error codes instead of *nix codes +</ul> + +<H2> Public Release 2.1.15 (July 23, 2013)</H2> +<ul> +<p> +<li> Added support for large data transfers +<P> +<li> XPAGet and XPASet now pass size_t instead of int for lengths +<p> +<li> Send and receive callbacks now pass size_t instead of int for lengths +<p> +<li> Port to mingw (Windows) +</ul> + + +<H2> Public Release 2.1.14 (June 7, 2012)</H2> +<ul> +<P> +<li> Fixed several memory leaks in the Tcl wrappers (tcl.c). +<P> +<li> Use Tcl stubs library for linking shared Tcl, if available. +</ul> + +<H2> Public Release 2.1.13 (April 14, 2011)</H2> +<ul> +<P> +<li> An atexit handler is no longer installed automatically (it crashes +Tcl 8.5.8 applications). Call XPAAtExit(void) to install the handler. +<p> +<li> Removed permission checking from Find() on cygwin systems. This was broken +by Windows 7. +<p> +<li> Removed addition of -no-cpp-precomp flag from gcc 4.2 and beyond (Mac). +</ul> + +<H2> Public Release 2.1.12 (January 26, 2010)</H2> +<ul> +<p> +<li> Added XPA_HOST environment variable to allow users to specify +the hostname (and hence, ip) component of the INET method id. This is +useful, for example, if you want to register an access point using a +VPN-generated IP instead of the canonical IP. +<p> +<li> Fix typo in Tcl binding to xpainfo causing a crash after 2 invocations. +</ul> + +<H2> Public Release 2.1.11 (December 7, 2009)</H2> +<ul> +<p> +<li> Generalized XPANSKeepAlive() to send messages to xpans, proxy xpans, or +both. The default is to send just to proxies (e.g. chandra-ed). +<p> +<li> Changed XPANSKeepAlive() to send an in-band new-line char to +xpans, changed xpans to handle an in-band new-line as a keep-alive +message. Necessitated by Cisco routers that clear the URG flag in +a TCP packet, breaking OOB data transfer for the whole Internet, as +well as the OOB-based keep-alive implemented in xpans. +<p> +<li> In xpans, print warning when the keep-alive option switch is used. +<p> +<li> Port to mingw (thanks to B.Schoenhammer) +<p> +<li> Change OOB character sent by xpans keepalive to a space, trying to working around cisco routers that force OOB data into the inbound stream. +<p> +<li> fix gcc fprintf warning in xpans.c +</ul> + +<H2> Public Release 2.1.10 (September 1, 2009)</H2> +<ul> +<p> +<li> Update mklib and configure.ac to support 64-bit builds on Macs. +<p> +<li> Fixed bug in XPAAccess() in which the returned names could have an extra +(bogus) character when the target is an explicit ip:port or local socket file. +<p> +<li> Add setjmp/longjmp support to xalloc. +<p> +<li> Add XPASaveJmp(void *env) as a high-level interface to xalloc_savejmp(); +</ul> + +<H2> Internal Release 2.1.9</H2> +<ul> +<p> +<li> Fixed a bug that prevented an access point starting with a number +from being recognized peoperly. NB: a pure number still signifies a +port on the current machine. Also num:num signifies ip:port, where ip +can be a pure hex value or the canonical form vvv.xxx.yyy.zzz. +<p> +<li> Modified internal Launch() routine to use posix_spawn(), if necessary. +This is required for OS X 10.5 (leopard), which frowns upon use of fork() +and exec(). Also modified zprocess routines to use Launch(). +<p> +<li> Added XPASetFree(xpa, void (*myfree)(void *)) routine to allow callbacks +to specify a free routine other than malloc free (e.g. Perl garbage collection). +<p> +<li> XPACmdAdd() now checks to ensure that it was passed an XPA struct created +by XPACmdNew(). +<p> +<li> Change launch.h to xlaunch.h to avoid conflict with OS X. +</ul> + +<H2> Public Release 2.1.8 (1 November 2007)</H2> +<ul> +<p> +<li> A public release to complete current XPA development work. +</ul> + +<H2> Patch Release 2.1.7b[1,2] (Feb 22, 2006; March 8, 2007)</H2> +<ul> + +<p> +<li> Added a convenience null to the end of the buffers returned by XPAGet. + +<p> +<li> Added code to avoid calling atexit routine if a fork'ed child +calls exit() instead of _exit(). + +<p> +<li> Added XPA_CLIENT_DOXPA environment variable to turn off client +processing of xpa server requests. + +<p> +<li> Added --version to xpaset, xpaget, xpainfo, xpaaccess, xpans to +display XPA version and exit. + +<p> +<li> Added support for integrating XPA into a Gtk loop. + +<p> +<li> xpaaccess now returns its answer in the error code as well as to stdout +(without the -n switch, it returns 1 for a match, with the -n switch, +the number of matches is returned). + +<p> +<li> Fixed bug which prevented xpans from being started up automatically +by an xpa server if its pathname contained a space character. + +<p> +<li> Fixed bug in MINGW port of xpans in which an XPA server that +terminated via an interrupt was not being properly removed from the +list of registered access points. + +<p> +<li> Added XPA_LOGNAME to override LOGNAME when registering username + +<p> +<li> Upgraded swish-e indexing code to 2.4.5. + +</ul> + +<H2> Patch Release 2.1.6 (4 May 2005)</H2> +<ul> + +<p> +<li> Added -P switch to xpans to enable experimental proxy support +(default is disabled). An argument of 1 processes proxy requests in +the same thread as xpans requests, while an argument of 2 processes +proxy requests in a separate thread. (The latter is recommended to +avoid xpans timeouts, since xpa callback processing can take a long +time.) + +<p> +<li> Added ability to build shared libraries (done automatically with +configure --enable-shared) with compilers other than gcc. + +<p> +<li> Made yet another attempt to build shared libraries under OS X. + +<p> +<li> Fixed a server bug in Tcl support under Windows (introduced early +in 2.1.6) which caused an occasional SEGV. + +<p> +<li> Fixed race condition in cases where 2 or more servers makes client calls +to one another. + +<p> +<li> Fixed bug in the XPA handler routine in which an access point was +turned off if an error occurred in that routine (as opposed to the +user-defined callback routine). + +<p> +<li> Fixed race condition when "ack=false" flag (or -n) is used with XPASet() +(or xpaset). + +<p> +<li> Added defensive code to XPA handler to ensure that the passed XPA record +is valid. + +<p> +<li> Tcl/XPA servers such as ds9 were not turning off select() on the +xpa channels inside an xpa callback, as required. This is now fixed. + +<p> +<li> Added timestamps to most server and client error messages if the +XPA_TIMESTAMP_ERRORS variable is set. This is useful when XPA errors are +being logged in an error log (e.g. Web/CGI use). + +<p> +<li> Generated PostScript and PDF versions of the help pages. + +<p> +<li> Moved OPTIONS section before (often-lengthy) DESCRIPTION section in +man pages. + +<p> +<li> All memory allocation now performs error checking on the result. + +<p> +<li> Removed some compiler warnings that surfaced when using gcc -O2. + +<p> +<li> Updated configure.ac to better support Tcl in Panther with Apple +Frameworks. + +</ul> + +<H2> Patch Release 2.1.5 (12 January 2004)</H2> +<ul> + +<p> +<li> Fixed bug in XPAPoll(). Erroneously, no requests were being +processed when maxreq==0. Now, all pending events are processed, as +per the documentation. + +<p> +<li> Added ack=false to XPAInfo() (and corresponding -n to xpainfo) +so that client does not wait for a response from the server. This is +essential in cases where XPA servers wish to send info messages to +one another without causing a race condition. + +<p> +<li> Generated man pages from the html pages. These are installed +automatically at build time. + +<p> +<li> The xpans program with Unix sockets now uses a lock file to signal +that it is running, in order to avoid a potential (but rare) race +condition at startup. + +<p> +<li> Code that calls Unix-type bind() now manipulate umask() to ensure that +all users have write permissions to the socket file (OS X apparently uses +these permissions while previous platforms ignore them). + +<p> +<li> Configure now checks for socklen_t type (OS X does not define it). + +<p> +<li> Added an atexit function to run XPAFree. The aim here is to delete Unix +socket files on exiting. + +<p> +<li> Under Windows, the Tcl event-handling code now blocks for 1/1000 of a +second instead of not blocking at all (which inadvertently used 100% of cpu). + +<p> +<li> Upgraded Tcl/Tk support to 8.4. + +<p> +<li> Made another round of checks was made through all instances of +strcat, strcpy, etc. to look for potential buffer overflows. Changed +all instances of sprintf() to snprintf(). + +<p> +<li> Class and name designators are now limited to 1024 characters, for +no particular reason. + +<p> +<li> The obsolete $SAORD_BIN variable was being added to the path when +searching for xpans. This is no longer the case. + +<p> +<li> Fixed non-ANSI compiler errors in both xpa.c and xpans.c. + +<p> +<li> Fixed minor problems to support compilation with g++. + +<p> +<li> Ported to Intel icc and gcc 3.3 compilers. + +<p> +<li> Upgraded autoconf to 2.57. Included in this upgrade is a change that +makes gcc the default compiler (use "configure CC=cc" to change this). +Also, by default, the Tcl shared object is no longer automatically built +if the Tcl libraries are used. Use the --enable-tclshlib switch in +configure to enable this feature. + +<p> +<li> Changed license from public domain to GNU GPL. + +</ul> + +<H2> Patch Release 2.1.4 (24 March 2003)</H2> +<ul> + +<p> +<li> Made inet method unique, even when hosts are behind a firewall using +the same ports (on different local machines). + +<p> +<li> The initial connection from an xpa server to a local xpans now is +controlled by a timeout (default 5 sec, controlled by XPA_CONNECT_TIMEOUT +variable). This should prevent a hang on connect() if the network +is not set up correctly. + +<p> +<li> Fixed rare race condition when an XPA server callback performed its own +XPAGet or XPASet call to another XPA server. + +<p> +<li> Use POSIX O_NONBLOCK for non-blocking I/O in fcntl call if it +exists, instead of O_NDELAY. + +</ul> + +<H2> Patch Release 2.1.3 (26 September 2002)</H2> +<ul> + +<p> +<li> Added -k [sec] switch to xpans to support sending one-byte keepalive +messages from xpans to registered xpa servers. + +<p> +<li> Added XPANSKeepAlive routine (and Tcl equivalent) to allow +xpa servers to send a one-byte keepalive message to xpans. + +</ul> + +<H2> Patch Release 2.1.2 (18 July 2002)</H2> +<ul> + +<p> +<li> The "-help" reserved command now also displays the XPA version, if +no explicit sub-commands are specified. + +<p> +<li> Change internal state of xpans proxy to save ip:port value of a +server behind a NAT firewall. This is required to give some hope of +distinguishing multiple instances of ds9 running behind NAT. + +</ul> + +<H2> Patch Release 2.1.1 (20 June 2002)</H2> +<ul> + +<p> +<li> Added a version check between xpans and an access point, +performed when it gets registered by an XPA server. If the server +has a version greater than the xpans version, a warning is issued by +both programs. + +<p> +<li> Added a boolean XPA_NSREGISTER environment variable to allow an +XPA server to skip xpans registration. The default is to register with +the name server. If set to "false", the access point still is set up +but it is not registered with an xpans. It can be registered later on +(using -remote or -proxy, for example). + +<p> +<li> Fixed bug in which xpans was still listening on any interface when +XPA_METHOD was localhost (instead of just listening on localhost). + +</ul> + +<H2> Public Release 2.1.0 (22 April 2002)</H2> + +<P> +New features include: + +<ul> +<p> +<li> Support for proxy access to XPA servers (e.g. ds9) situated +behind a firewall (useful for NVO-type applications). + +<p> +<li> Improved support for allowing remote machines access rights to the +XPA access points (useful for NVO-type applications). + +<p> +<li> Ability for XPAAccess() routine and xpaaccess program to contact XPA + directly. + +<p> +<li> Support for a clipboard access point that allows clients to store ASCII +state information in an XPA-enabled server. + +<p> +<li> Improved support for Windows platform, as well as new support for Mac OSX. +</ul> + +<H2> Pre-Release 2.1.0e (2 April 2002)</H2> +<UL> + +<P> +<LI> Removed the environment variable generated by each XPA access +point (of the form XPA_name=method). The putenv() call was causing ds9 +to crash under both Linux and LinuxPPC during a socket operation. We +suspect a bug in putenv but cannot prove it and this feature is not +essential, so ... + +</UL> + +<H2> Pre-Release 2.1.0e (1 April 2002)</H2> +<UL> + +<P> +<LI> Fixed an uninitialized variable in xpamb which prevented it from +working at all on some systems. + +<P> +<LI> Changed xpamb switch from "-add" to "-data" (to store named data). + +<P> +<LI> Changed how xpamb works with xpaget so that xpamb can return data +from XPA access points as well as from stored data. (Previous versions +only returned stored data.) Now, you can retrieve stored data +explicitly using the -info and/or -data switches. For example: +<PRE> + xpaget xpamb -info foo +</PRE> +will return info about the previously stored data named foo. If +neither switch is present, then the name is assumed to be an XPA access +point. +</UL> + +<H2> Pre-Release 2.1.0e (25 March 2002)</H2> +<UL> + +<P> +<LI> Changed symbol for default port from "*" to "$port" to avoid +a syntactical conflict between class:* and machine:* when processing an +XPA access point class:name specification. Thus, the default inet +method now is '$host:$port' instead of '$host:*'. + +</UL> + +<H2> Pre-Release 2.1.0e (19 March 2002)</H2> +<UL> + +<P> +<LI> Removed timeout check when reading data (in clients using xpaget +and servers filling the data buffer). We have more and more cases +where we need to wait a long time to retrieve data (e.g., slow +networks or receiving data being compressed on the fly). + +<P> +<LI> Moved call to sigaction(SIGCHLD,...) out of XPAOpen(), so that it +is only executed when needed by XPAGet()/XPASet() routines called from +within xpans/proxy. But then changed logic to use a double fork() instead +of sigaction() to prevent zombies (Stevens Adv. Programming p 202). + +<P> +<LI> Each XPA access point now generates an environment variable of the +form XPA_name=method so that children can communicate with the parent access +point more easily. + +<P> +<LI> Added version option to Tcl xparec: +<PRE> + if [catch { xparec "" version } version] { + puts "pre-2.1.0e" + } else { + puts [split $version .] + } +</PRE> +to help differentiate between XPA versions within Tcl code. + +</UL> + +<H2> Pre-Release 2.1.0e (14 February 2002)</H2> +<UL> +<P> +<LI> Fixed client handling of out-of-sync messages. +</UL> + +<H2> Pre-Release 2.1.0e (11 February 2002)</H2> +<UL> + +<P> +<LI> Fixed client.c/xopen() so that it does not open an extra socket. + +<P> +<LI> Fixed xpainfo/xopen() to prevent client from hanging waiting for ack. + +<P> +<LI> Modified stest to generate xpaaccess points xpa, xpa1, c_xpa, and +i_xpa (or more generally, <name>, <name>1, c_<name>, i<name>) to allow +more flexible testing of templates. Also added -a for testing XPAAccess(). + +</UL> + +<H2> Beta Release 2.1.0b10 (31 January 2002)</H2> +<UL> + +<P> +<LI> Added support for Mac OSX/Darwin to configure file. + +</UL> + +<H2> Beta Release 2.1.0b9 (26 January 2002)</H2> +<UL> + +<P> +<LI> Fixed bug in client library that caused XPAAccess() call to hang. + +</UL> + +<H2> Beta Release 2.1.0b8 (4 January 2002)</H2> +<UL> + +<P> +<LI> Made modifications to Makefile.in to make releases easier. + +<P> +<LI> Added instructions to Makefile.in so that xpa.h will always have +correct #defines for XPA_VERSION, XPA_MAJOR_VERSION, XPA_MINOR_VERSION, +and XPA_PATCH_LEVEL. + +</UL> + +<H2> Beta Release 2.1.0b7 (21 December 2001)</H2> +<UL> + +<P> +<LI> Added -proxy switch to -remote sub-command to allow remote access +through a firewall, using xpans as a proxy server. The support for proxy +processing required a change to the client/server protocol. This means +that new xpa servers will not work with old xpa clients (although new +xpa clients will work with old xpa servers). For details about proxy +firewall support, see http://hea-www.harvard.edu/RD/xpa/inet.html. + +<P> +<LI> Fixed Tcl support for XPA under Windows/Cygwin by re-writing +the code used to add XPA to the Tcl event loop. This fix makes ds9 +support for XPA much more stable under Windows. + +<P> +<LI> Added the shutdown() call to XPA under Cygwin/Windows before +closing send() sockets. It appears that a Cygwin recv() socket call +does not always sense when the other end closes the socket using +close(). This measure must be considered a hack, since the actual +problem was never resolved. + +<P> +<LI> Added code to protect accept() and select() calls from interrupts. + +<P> +<LI> Extended syntax of the environment variable XPA_NSINET to: +<PRE> + setenv XPA_NSINET host:port[,port[,port]] +</PRE> +to allow specification of the XPA access point port for xpans, +as well as the proxy data port. + +<P> +<LI> Modified xpans log file so that it contains the xpaset commands +required to reconnect with xpa servers. + +<P> +<LI> xpans now deletes its Unix socket files. + +</UL> + +<H2> Beta Release 2.1.0b6 (29 October 2001)</H2> +<UL> + +<P> +<LI> Implemented a reserve public access point named -clipboard so +that clients can store ASCII state information on any number of named +clipboards. Clipboards of the same name created by clients on +different machines are kept separate. The syntax for creating a +clipboard is: +<PRE> + [data] | xpaset [server] -clipboard add|append [clipboard_name] + xpaset -p [server] -clipboard delete [clipboard_name] + xpaget [server] -clipboard [clipboard_name] +</PRE> +Use "add" to create a new clipboard or replace the contents of an existing +one. Use "append" to append to an existing clipboard. + +</UL> + +<H2> Beta Release 2.1.0b5 (22 October 2001)</H2> +<UL> + +<P> +<LI> Use FD_SETSIZE instead of getdtablesize() to determine how many files +to check during select(); + +<P> +<LI> Under Cygwin, the launch() routine now uses the Cygwin spawnvp() +instead of fork()/exec() where possible (i.e., if no stdfiles are +being redirected). This is recommended by Cygwin's (skimpy) on-line +documentation and seems to fix the problems ds9 had when starting xpans +automatically. + +<P> +<LI> Added error check to select() call in xpans. + +</UL> + +<H2> Beta Release 2.1.0b4 (24 September 2001)</H2> +<UL> + +<P> +<LI> The launch() now can return an error code if the execv() system +call fails (something system() does not do). + +<P> +<LI> INET socket calls between xpa clients and servers now will use +localhost if they are on the same machine. This protects against +Linux systems where the hostname is hardwired (wrongly) in a DHCP +environment. + +</UL> + +<H2> Beta Release 2.1.0b3 (6 September 2001)</H2> +<UL> + +<P> +<LI> Modified xpans so that, in the case of a firewall, it tries to +correct the specified ip:port by matching against the ip found in +the socket packet at accept() time. + +<P> +<LI> Replaced system() call used to start xpans automatically with +a special launch() call, which performs execvp() directly without going +through sh. (launch() works under DOS and has fewer security problems.) + +<P> +<LI> Fixed bug in xpans in which its xpa port was always being set to 14286. + +</UL> + +<H2> Beta Release 2.1.0b2 (17 August 2001)</H2> +<UL> + +<P> +<LI>Added support for -remote command, which registers the access +point in the XPA name server of the specified remote server, and gives +the remote server access rights to the access point. This is used, for +example, to give data servers xpa access to ds9 so that data can be +sent to ds9 as a result of a CGI-based Web query. + +<P> +<LI>Reserved commands (except "-help" and "-version") now can only be +executed on the machine on which the xpa service is running (not +through -remote servers). + +<P> +<LI>Fixed bug in xpans in which a bad telnet command could hang the program. + +<P> +<LI>Added -s [security file] to xpans to allow logging of all external +connections. + +</UL> + +<H2> Beta Release 2.1.0b1 (6 August 2001)</H2> +<UL> +<P> +<LI> The xpaaccess client program and XPAAccess() client subroutine +were modified so that an access-type query can directly contact the +xpa servers matching the requested xpa template, instead of just +querying the name server for registered access points. This avoid the +race condition in which an access point is registered but is not yet +available, perhaps because the server has not yet entered its event +loop. Note that the calling sequence of the XPAAccess() routine was +changed to return all matching access points and their availability +status (instead of just returning the number of registered access +points). Because of this, we are calling this a minor release instead +of a patch. + +<P> +<LI> Added support for XPA_PORT and XPA_PORTFILE environment variables +to allow specification of the port to be used by the command channel +(and data channel, if an optional second port is specified) for a given +access point. + +<P> +<LI> Added -m switch to xpaget, xpaset, xpainfo, xpaaccess to allow +override of the XPA_METHOD environment variable. + +<P> +<LI> Changed the default name of the ACL file from xpa.acl to acls.xpa. + +<P> +<LI> Fixed bug in which it was not possible to send a "set ACL" +command to an XPA server which did not have a receive callback (i.e., +did not allow xpaset). The xpans program is one such server. It now is +possible to set the ACL on xpans. + +<P> +<LI> We have discovered that Tcl support for datachan and cmdchan is +broken under Windows due to an unexplained incompatibility between +Cygwin sockets and Win32 sockets. We therefore have removed datachan +and cmdchan from the Windows/Tcl support until further notice. + +<P> +<LI> Extended the behavior of the XPA_DEFACL environment variable so that +it can support more than one acl, using a list of semi-colon delimited +controls such as: setenv XPA_DEFACL '*:* $host +; *:foo1 otherhost +'. + +<P> +<LI> Fixed bug in which the class:name specifier "*:*" was erroneously +trying to access the xpans name server, instead of accessing all +access points. + +<P> +<LI> Support TMPDIR and TMP environment variables as well as XPA_TMPDIR. + +</UL> + +<H2> Patch Release 2.0.5 (10 November 2000)</H2> +<UL> +<P> +<LI> Added support for Tcl on Windows where there is no select()-based +event loop (i.e., where there is no Tcl_CreateFileHandler call in Tcl) +<P> +<LI> Minor fixes in Makefile for installing on Windows +<P> +<LI> Minor compiler fixes from gcc -Wall. +</UL> + +<H2> Patch Release 2.0.4 (20 September 2000) </H2> +<UL> +<P> +<LI> Removed extraneous include of varargs.h from find.c. +<P> +<LI> Ported to SGI C compiler, which caught lots of unused variables, etc. +<P> +<LI> Ported to Cygwin/Windows, which required that we change socket read() +and write() calls to recv() and send() respectively. Also had to ensure that +we only did socket I/O on sockets (no fileio). +</UL> + +<H2> Patch Release 2.0.3 (15 June 2000) </H2> +<UL> +<P> +<LI> Fixed the client XPASet() and XPASetFd() calls to handle the specified +max number of connections (they were ignoring this argument, leading to +memory overwrites). +<P> +<LI> Fixed Makefile.in so that CFLAGS and LDFLAGS are not hard-wired values. +<P> +<LI> Fixed word.h to load malloc.h and stdlib.h only if they exist. +<P> +<LI> Documentation fixes to programs.html (in xpaaccess) and client.html +(XPANSLookup). +<P> +<LI> Added explicit typecast to strlen() argument to MAX #define in +XPAClientStart (strlen() is unsigned in Linux, which can break MAX). +<P> +<LI> Removed bogus Imakefile from directory. +<P> +<LI> Changed directory name to include patch level (i.e., xpa-2.0.3). +</UL> + +<H2> Patch Release 2.0.2 (9 September 1999)</H2> +<UL> +<P> +<LI> Fixed server mode (-s) in the xpaset program by properly cleaning up +the input buffers (sending commands and data in server mode was broken). +</UL> + +<H2> Patch Release 2.0.1 (6 August 1999)</H2> +<UL> +<P> +<LI> Fixed the Tcl binding code (tcl.c) for 64-bit machines (Dec Alpha) +(erroneously used %x instead of %p when converting pointers to ASCII). +<P> +<LI> Got rid of a few compiler warnings on 64-bit machines (a few are +unavoidable since we must cast int to void * and back when passing around +client data). +</UL> + +<H2> Public Release 2.0 (27 May 1999)</H2> +<UL> +<P> +<LI> "a new day with no mistakes ... yet" +</UL> + +<HR> +<P> +<A HREF="./help.html">Index to the XPA Help Pages</A> + +<HR> +<H5>Last updated: 22 April 2002</H5> +</BODY> +</HTML> diff --git a/xpa/doc/changes.html b/xpa/doc/changes.html new file mode 100644 index 0000000..8488985 --- /dev/null +++ b/xpa/doc/changes.html @@ -0,0 +1,69 @@ +<!-- =defdoc xpachanges xpachanges 1 --> +<HTML> +<HEAD> +<TITLE>Changes For Users from XPA 1.0 and 2.0</TITLE> +</HEAD> +<BODY> + +<!-- =section xpachanges NAME --> +<H2><A NAME="xpachanges">XPA Changes: Changes For Users from XPA 1.0 and 2.0</A></H2> + +<!-- =section xpachanges SYNOPSIS --> +<H2>Summary</H2> +<P> +This document describes changes that will affect users who migrate +from XPA 1.0 to XPA 2.0. + +<!-- =section xpachanges DESCRIPTION --> +<H2>Description</H2> +<P> +There have been a few changes that affect users who upgrade XPA +from version 1.0 to version 2.0. These changes are detailed below. +<UL> +<P> +<LI>XPA commands no longer have a resolver routine (this is open to +negotiations, but we decided the idea was dumb). For the SAOtng +program, this means that you must explicitly specify the access +point, i.e.,: +<PRE> + cat foo.fits | xpaset SAOtng fits +</PRE> + +<P> +instead of: +<PRE> + cat foo.fits | xpaset SAOtng +</PRE> +<P> +<LI>By default, xpaset, xpaget, etc. now wait for the server callback to +complete; i.e., the old -W is implied (and the switch is ignored). +This allows support for better error handling. If you want xpaset, etc. +to return before the callback is complete, use -n switch: +<PRE> + echo "file foo.fits" | xpaset -n SAOtng +</PRE> +<P> +<LI>The old -w switch in xpaset and xpaget is no longer necessary (and is +ignored), since you can have more than one process communicating with +an xpa access point at one time. + +<P> +<LI>The new -p switch on xpaset means you need not read from stdout: +<PRE> + xpaset -p SAOtng colormap I8 +</PRE> +<P> +will send the paramlist to the SAOtng callback without reading from stdin. + +</UL> + +<!-- =section xpachanges SEE ALSO --> +<!-- =text See xpa(n) for a list of XPA help pages --> +<!-- =stop --> + +<P> +<A HREF="./help.html">Go to XPA Help Index</A> + +<H5>Last updated: September 10, 2003</H5> +</BODY> +</HTML> diff --git a/xpa/doc/client.html b/xpa/doc/client.html new file mode 100644 index 0000000..5648d85 --- /dev/null +++ b/xpa/doc/client.html @@ -0,0 +1,898 @@ +<!-- =defdoc xpaclient xpaclient 3 --> +<HTML> +<HEAD> +<TITLE>XPA Client API</TITLE> +</HEAD> +<BODY> + +<!-- =section xpaclient NAME --> +<H2><A NAME="xpaclient">XPAClient: The XPA Client-side Programming Interface</A></H2> + +<!-- =section xpaclient SYNOPSIS --> +<H2>Summary</H2> +A description of the XPA client-side programming interface. + +<!-- =section xpaclient DESCRIPTION --> +<H2><A NAME="intro">Introduction to XPA Client Programming</H2></A> +<P> +Sending/receiving data to/from an XPA access point is easy: you +generally only need to call the XPAGet() or XPASet() subroutines. +<PRE> + #include <xpa.h> + + int <A HREF="./client.html#xpaget">XPAGet</A>(XPA xpa, + char *template, char *paramlist, char *mode, + char **bufs, size_t *lens, char **names, char **messages, int n); + + int <A HREF="./client.html#xpaset">XPASet</A>(XPA xpa, + char *template, char *paramlist, char *mode, + char *buf, size_t len, char **names, char **messages, int n); + + int <A HREF="./client.html#xpainfo">XPAInfo</A>(XPA xpa, + char *template, char *paramlist, char *mode, + char **names, char **messages, int n); + + int <A HREF="./client.html#xpaaccess">XPAAccess</A>(XPA xpa, + char *template, char *paramlist, char *mode, + char **names, char **messages, int n); + + int <A HREF="./client.html#xpagetfd">XPAGetFd</A>(XPA xpa, + char *template, char *paramlist, char *mode, + int *fds, char **names, char **messages, int n); + + int <A HREF="./client.html#xpasetfd">XPASetFd</A>(XPA xpa, + char *template, char *paramlist, char *mode, + int fd, char **names, char **messages, int n); + + XPA <A HREF="./client.html#xpaopen">XPAOpen</A>(char *mode); + + void <A HREF="./client.html#xpaclose">XPAClose</A>(XPA xpa); + + int <A HREF="./client.html#xpanslookup">XPANSLookup</A>(XPA xpa, + char *template, char *type, + char ***classes, char ***names, char ***methods, char ***infos); +</PRE> + +<H2>Introduction</H2> + +To use the XPA application programming interface, a software developer +generally will include the xpa.h definitions file: +<PRE> + #include <xpa.h> +</PRE> +in the software module that defines or accesses an XPA access point and +then will link against the libxpa.a library: +<PRE> + gcc -o foo foo.c libxpa.a +</PRE> +XPA has been compiled using both C and C++ compilers. +<P> +Client communication with XPA public access points generally is +accomplished using XPAGet() or XPASet() within a program (or xpaget +and xpaset at the command line). Both routines require specification +of the name of the access point. If a <A HREF="./template.html">template</A> +is used to specify the access point name (e.g., "ds9*"), then +communication will take place with all servers matching that template. + +<!-- =defdoc xpaget xpaget 3 --> + +<!-- =section xpaget NAME --> +<H2><A NAME="xpaget">XPAGet: retrieve data from one or more XPA servers</A></H2> + +<!-- =section xpaget SYNOPSIS --> +<B> +<PRE> + #include <xpa.h> + + int XPAGet(XPA xpa, + char *template, char *paramlist, char *mode, + char **bufs, size_t *lens, char **names, char **messages, + int n); +</PRE> +</B> + +<!-- =section xpaget DESCRIPTION --> +<P> +Retrieve data from one or more XPA servers whose class:name identifier +matches the specified template. + +<P> +A +<A HREF="./template.html">template</A> +of the form "class1:name1" is sent to the +XPA name server, which returns a list of at most n matching XPA +servers. A connection is established with each of these servers and +the paramlist string is passed to the server as the data transfer +request is initiated. If an XPA struct is passed to the call, then the +persistent connections are updated as described above. Otherwise, +temporary connections are made to the servers (which will be closed +when the call completes). + +<P> +The XPAGet() routine then retrieves data from at most n XPA servers, +places these data into n allocated buffers and places the buffer +pointers in the bufs array. The length of each buffer is stored in the +lens array. A string containing the class:name and ip:port is stored +in the name array. If a given server returned an error or the server +callback sends a message back to the client, then the message will be +stored in the associated element of the messages array. NB: if +specified, the name and messages arrays must be of size n or greater. + +<p> +The returned message string will be of the form: +<PRE> + XPA$ERROR error-message (class:name ip:port) +</PRE> +or +<PRE> + XPA$MESSAGE message (class:name ip:port) +</PRE> +<P> +Note that when there is an error stored in an messages entry, the +corresponding bufs and lens entry may or may not be NULL and 0 +(respectively), depending on the particularities of the server. + +<P> +The return value will contain the actual number of servers that were +processed. This value thus will hold the number of valid entries in +the bufs, lens, names, and messages arrays, and can be used to loop +through these arrays. In names and/or messages is NULL, no information is +passed back in that array. + +<P> +The bufs, names, and messages arrays should be freed upon completion (if +they are not NULL); + +<P> +The mode string is of the form: "key1=value1,key2=value2,..." +The following keywords are recognized: +<PRE> + key value default explanation + ------ -------- -------- ----------- + ack true/false true if false, don't wait for ack from server (after callback completes) + doxpa true/false true client processes xpa requests +</PRE> +<P> +The ack keyword is not very useful, since the server completes the callback +in order to return the data anyway. It is here for completion (and perhaps +for future usefulness). + +<p> +Normally, an XPA client will process incoming XPA server requests +while awaiting the completion of the client request. Setting this +variable to "false" will prevent XPA server requests from being +processed by the client. + +<P> +<B>Example:</B> +<PRE> + #include <xpa.h> + + #define NXPA 10 + int i, got; + size_t lens[NXPA]; + char *bufs[NXPA]; + char *names[NXPA]; + char *messages[NXPA]; + got = XPAGet(NULL, "ds9", "file", NULL, bufs, lens, names, messages, + NXPA); + for(i=0; i<got; i++){ + if( messages[i] == NULL ){ + /* process buf contents */ + ProcessImage(bufs[i], ...); + free(bufs[i]); + } + else{ + /* error processing */ + fprintf(stderr, "ERROR: %s (%s)\n", messages[i], names[i]); + } + if( names[i] ) + free(names[i]); + if( messages[i] ) + free(messages[i]); + } +</PRE> + +<!-- =defdoc xpaset xpaset 3 --> + +<!-- =section xpaset NAME --> +<H2><A NAME="xpaset">XPASet: send data to one or more XPA servers</A></H2> + +<!-- =section xpaset SYNOPSIS --> +<B> +<PRE> + #include <xpa.h> + + int XPASet(XPA xpa, + char *template, char *paramlist, char *mode, + char *buf, size_t len, char **names, char **messages, + int n); +</PRE> +</B> + +<!-- =section xpaset DESCRIPTION --> +<P> +Send data to one or more XPA servers whose class:name identifier +matches the specified template. + +<P> +A +<A HREF="./template.html">template</A> +of the form "class1:name1" is sent to the +XPA name server, which returns a list of at most n matching XPA +servers. A connection is established with each of these servers and +the paramlist string is passed to the server as the data transfer +request is initiated. If an XPA struct is passed to the call, the +persistent connections are updated as described above. Otherwise, +temporary connections are made to the servers (which will be closed +when the call completes). + +<P> +The XPASet() routine transfers data from buf to the XPA servers. +The length of buf (in bytes) should be placed in the len variable. + +<P> +A string containing the class:name and ip:port of each of these server +is returned in the name array. If a given server returned an error or +the server callback sends a message back to the client, then the +message will be stored in the associated element of the messages +array. NB: if specified, the name and messages arrays must be of size +n or greater. + +<p> +The returned message string will be of the form: + +<PRE> + XPA$ERROR [error] (class:name ip:port) +</PRE> +or +<PRE> + XPA$MESSAGE [message] (class:name ip:port) +</PRE> +<P> +The return value will contain the actual number of servers that were +processed. This value thus will hold the number of valid entries in +the names and messages arrays, and can be used to loop through these +arrays. In names and/or messages is NULL, no information is passed back +in that particular array. + +<P> +The mode string is of the form: "key1=value1,key2=value2,..." +The following keywords are recognized: +<PRE> + key value default explanation + ------ -------- -------- ----------- + ack true/false true if false, don't wait for ack from server (after callback completes) + verify true/false false send buf from XPASet[Fd] to stdout + doxpa true/false true client processes xpa requests +</PRE> +<P> +The ack keyword is useful in cases where one does not want to wait for +the server to complete, e.g. if a lot of processing needs to be done +by the server on the passed data or when the success of the server +operation is not relevant to the client. + +<p> +Normally, an XPA client will process incoming XPA server requests +while awaiting the completion of the client request. Setting this +variable to "false" will prevent XPA server requests from being +processed by the client. + +<P> +<B>Example:</B> +<PRE> + #include <xpa.h> + + #define NXPA 10 + int i, got; + size_t len; + char *buf; + char *names[NXPA]; + char *messages[NXPA]; + ... + [fill buf with data and set len to the length, in bytes, of the data] + ... + /* send data to all access points */ + got = XPASet(NULL, "ds9", "fits", NULL, buf, len, names, messages, NXPA); + /* error processing */ + for(i=0; i<got; i++){ + if( messages[i] ){ + fprintf(stderr, "ERROR: %s (%s)\n", messages[i], names[i]); + } + if( names[i] ) free(names[i]); + if( messages[i] ) free(messages[i]); + } +</PRE> + +<!-- =defdoc xpainfo xpainfo 3 --> + +<!-- =section xpainfo NAME --> +<H2><A NAME="xpainfo">XPAInfo: send short message to one or more XPA servers</A></H2> + +<!-- =section xpainfo SYNOPSIS --> +<B> +<PRE> + #include <xpa.h> + + int XPAInfo(XPA xpa, + char *template, char *paramlist, char *mode, + char **names, char **messages, int n); +</PRE> +</B> + +<!-- =section xpainfo DESCRIPTION --> +<P> +Send a short paramlist message to one or more XPA servers whose +class:name identifier matches the specified +<A HREF="./template.html">template</A>. + +<P> +A +<A HREF="./template.html">template</A> +of the form "class1:name1" is sent to the +XPA name server, which returns a list of at most n matching XPA +servers. A connection is established with each of these servers and +the paramlist string is passed to the server as the data transfer +request is initiated. If an XPA struct is passed to the call, then the +persistent connections are updated as described above. Otherwise, +temporary connections are made to the servers (which will be closed +when the call completes). + +<P> +The XPAInfo() routine does not send data from a buf to the XPA +servers. Only the paramlist is sent. The semantics of the paramlist +is not formalized, but at a minimum is should tell the server how to +get more information. For example, it might contain the class:name +of the XPA access point from which the server (acting as a client) +can obtain more info using XPAGet. + +<P> +A string containing the class:name and ip:port of each server is +returned in the name array. If a given server returned an error or +the server callback sends a message back to the client, then the +message will be stored in the associated element of the messages +array. The returned message string will be of the form: +<PRE> + XPA$ERROR error-message (class:name ip:port) +</PRE> +or +<PRE> + XPA$MESSAGE message (class:name ip:port) +</PRE> +<P> +The return value will contain the actual number of servers that were +processed. This value thus will hold the number of valid entries in +the names and messages arrays, and can be used to loop through these +arrays. In names and/or messages is NULL, no information is passed back +in that array. + +<P> +The following keywords are recognized: +<PRE> + key value default explanation + ------ -------- -------- ----------- + ack true/false true if false, don't wait for ack from server +</PRE> +<P> +When ack is false, XPAInfo() will not wait for an error return from the XPA +server. This means, in effect, that XPAInfo will send its paramlist string +to the XPA server and then exit: no information will be sent from the server +to the client. This UDP-like behavior is essential to avoid race +conditions in cases where XPA servers are sending info messages to +other servers. If two servers try to send each other an info message +at the same time and then wait for an ack, a race condition will result and +one or both will time out. + +<P> +<B>Example:</B> +<PRE> + (void)XPAInfo(NULL, "IMAGE", "ds9 image", NULL, NULL, NULL, 0); +</PRE> + +<!-- =defdoc xpagetfd xpagetfd 3 --> + +<!-- =section xpagetfd NAME --> +<H2><A NAME="xpagetfd">XPAGetFd: retrieve data from one or more XPA servers and write to files</A></H2> + +<!-- =section xpagetfd SYNOPSIS --> +<B> +<PRE> + #include <xpa.h> + + int XPAGetFd(XPA xpa, + char *template, char *paramlist, char *mode, + int *fds, char **names, char **messages, int n); +</PRE> +</B> + +<!-- =section xpagetfd DESCRIPTION --> +<P> +Retrieve data from one or more XPA servers whose class:name identifier +matches the specified +<A HREF="./template.html">template</A> +and write it to files associated with +one or more standard I/O fds (i.e, handles returned by open()). + +<P> +A +<A HREF="./template.html">template</A> +of the form "class1:name1" is sent to the +XPA name server, which returns a list of at most ABS(n) matching XPA +servers. A connection is established with each of these servers and +the paramlist string is passed to the server as the data transfer +request is initiated. If an XPA struct is passed to the call, then the +persistent connections are updated as described above. Otherwise, +temporary connections are made to the servers (which will be closed +when the call completes). + +<P> +The XPAGetFd() routine then retrieves data from the XPA servers, +and write these data to the fds associated with one or more fds +(i.e., results from open). Is n is positive, then there will be n fds +and the data from each server will be sent to a separate fd. If n is +negative, then there is only 1 fd and all data is sent to this single +fd. (The latter is how xpaget is implemented.) + +<P> +A string containing the class:name and ip:port is stored in the name +array. If a given server returned an error or the server callback +sends a message back to the client, then the message will be stored in +the associated element of the messages array. NB: if specified, the +name and messages arrays must be of size n or greater. + +<P> +The returned message string will be of the form: +<PRE> + XPA$ERROR error-message (class:name ip:port) +</PRE> +or +<PRE> + XPA$MESSAGE message (class:name ip:port) +</PRE> +<P> +Note that when there is an error stored in an messages entry, the +corresponding bufs and lens entry may or may not be NULL and 0 +(respectively), depending on the particularities of the server. + +<P> +The return value will contain the actual number of servers that were +processed. This value thus will hold the number of valid entries in +the bufs, lens, names, and messages arrays, and can be used to loop +through these arrays. In names and/or messages is NULL, no information is +passed back in that array. + +<P> +The mode string is of the form: "key1=value1,key2=value2,..." +The following keywords are recognized: +<PRE> + key value default explanation + ------ -------- -------- ----------- + ack true/false true if false, don't wait for ack from server (after callback completes) +</PRE> +<P> +The ack keyword is not very useful, since the server completes the callback +in order to return the data anyway. It is here for completion (and perhaps +for future usefulness). + +<P> +<B>Example:</B> +<PRE> + #include <xpa.h> + #define NXPA 10 + int i, got; + int fds[NXPA]; + char *names[NXPA]; + char *messages[NXPA]; + for(i=0; i<NXPA; i++) + fds[i] = open(...); + got = XPAGetFd(NULL, "ds9", "file", NULL, fds, names, messages, NXPA); + for(i=0; i<got; i++){ + if( messages[i] != NULL ){ + /* error processing */ + fprintf(stderr, "ERROR: %s (%s)\n", messages[i], names[i]); + } + if( names[i] ) + free(names[i]); + if( messages[i] ) + free(messages[i]); + } +</PRE> + +<!-- =defdoc xpasetfd xpasetfd 3 --> + +<!-- =section xpasetfd NAME --> +<H2><A NAME="xpasetfd">XPASetFd: send data from stdin to one or more XPA servers</A></H2> + +<!-- =section xpasetfd SYNOPSIS --> +</B> +<PRE> + #include <xpa.h> + + int XPASetFd(XPA xpa, + char *template, char *paramlist, char *mode, + int fd, char **names, char **messages, int n) +</PRE> +</B> + +<!-- =section xpasetfd DESCRIPTION --> +<P> +Read data from a standard I/O fd and send it to one or more XPA +servers whose class:name identifier matches the specified +<A HREF="./template.html">template. + +<P> +A +<A HREF="./template.html">template</A> +of the form "class1:name1" is sent to the +XPA name server, which returns a list of at most n matching XPA +servers. A connection is established with each of these servers and +the paramlist string is passed to the server as the data transfer +request is initiated. If an XPA struct is passed to the call, then the +persistent connections are updated as described above. Otherwise, +temporary connections are made to the servers (which will be closed +when the call completes). + +<P> +The XPASetFd() routine then reads bytes from the specified fd +until EOF and sends these bytes to the XPA servers. +The final parameter n specifies the maximum number of servers to contact. +A string containing the class:name and ip:port of each server is returned in +the name array. If a given server returned an error, then the error +message will be stored in the associated element of the messages array. +NB: if specified, the name and messages arrays must be of size n or greater. + +<P> +The return value will contain the actual number of servers that were +processed. This value thus will hold the number of valid entries in +the names and messages arrays, and can be used to loop through these +arrays. In names and/or messages is NULL, no information is passed back +in that array. + +<P> +The mode string is of the form: "key1=value1,key2=value2,..." +The following keywords are recognized: +<PRE> + key value default explanation + ------ -------- -------- ----------- + ack true/false true if false, don't wait for ack from server (after callback completes) + verify true/false false send buf from XPASet[Fd] to stdout +</PRE> +<P> +The ack keyword is useful in cases where one does not want to wait for +the server to complete, e.g. is a lot of processing needs to be done +on the passed data or when the success of the server operation is not +relevant to the client. + +<P> +<B>Example:</B> +<PRE> + #include <xpa.h> + + #define NXPA 10 + int i, got; + int fd; + char *names[NXPA]; + char *messages[NXPA]; + fd = open(...); + got = XPASetFd(NULL, "ds9", "fits", NULL, fd, names, messages, NXPA); + for(i=0; i<got; i++){ + if( messages[i] != NULL ){ + /* error processing */ + fprintf(stderr, "ERROR: %s (%s)\n", messages[i], names[i]); + } + if( names[i] ) + free(names[i]); + if( messages[i] ) + free(messages[i]); + } +</PRE> + +<!-- =defdoc xpaopen xpaopen 3 --> + +<!-- =section xpaopen NAME --> +<H2><A NAME="xpaopen">XPAOpen: allocate a persistent client handle</A></H2> + +<!-- =section xpaopen SYNOPSIS --> +<B> +<PRE> + #include <xpa.h> + + XPA XPAOpen(char *mode); +</PRE> +</B> + +<!-- =section xpaopen DESCRIPTION --> +<P> +XPAOpen() allocates a persistent XPA struct that can be used with +calls to XPAGet(), XPASet(), XPAInfo(), XPAGetFd(), and +XPASetFd(). Persistence means that a connection to an XPA server is +not closed when one of the above calls is completed but will be +re-used on successive calls. Using XPAOpen() therefore saves the time +it takes to connect to a server, which could be significant with slow +connections or if there will be a large number of exchanges with a +given access point. The mode argument currently is ignored ("reserved +for future use"). + +<P> +An XPA struct is returned if XPAOpen() was successful; otherwise NULL +is returned. This returned struct can be passed as the first argument +to XPAGet(), etc. Those calls will update the list of active XPA +connections. Already connected servers (from a previous call) are +left connected and new servers also will be connected. Old servers +(from a previous call) that are no longer needed are disconnected. +The connected servers will remain connected when the next call to +XPAGet() is made and connections are once again updated. + +<P> +<B>Example:</B> +<PRE> + #include <xpa.h> + + XPA xpa; + xpa = XPAOpen(NULL); +</PRE> + +<!-- =defdoc xpaclose xpaclose 3 --> + +<!-- =section xpaclose NAME --> +<H2><A NAME="xpaclose">XPAClose: close a persistent XPA client handle</A></H2> + +<!-- =section xpaclose SYNOPSIS --> +<B> +<PRE> + #include <xpa.h> + + void XPAClose(XPA xpa); +</PRE> +</B> + +<!-- =section xpaclose DESCRIPTION --> +<P> +XPAClose closes the persistent connections associated with this XPA struct +and frees all allocated space. It also closes the open sockets connections +to all XPA servers that were opened using this handle. + +<P> +<B>Example:</B> +<PRE> + #include <xpa.h> + + XPA xpa; + XPAClose(xpa); +</PRE> + +<!-- =defdoc xpanslookup xpanslookup 3 --> + +<!-- =section xpanslookup NAME --> +<H2><A NAME="xpanslookup">XPANSLookup: lookup registered XPA access points</A></H2> + +<!-- =section xpanslookup SYNOPSIS --> +<B> +<PRE> + #include <xpa.h> + + int XPANSLookup(XPA xpa, + char *template, char type, + char ***classes, char ***names, + char ***methods, char ***infos) +</PRE> +</B> + +<!-- =section xpanslookup DESCRIPTION --> +<P> +XPA routines act on a class:name identifier in such a way +that all access points that match the identifier are processed. It is +sometimes desirable to choose specific access points from the +candidates that match the +<A HREF="./template.html">template</A>. In order to do this, the +XPANSLookup routine can be called to return a list of matches, so that +specific class:name instances can then be fed to XPAGet(), XPASet(), etc. + +<P> The first argument is an optional XPA struct. If non-NULL, the +existing name server connection associated with the specified xpa is +used to query the xpans name server for matching templates. Otherwise, +a new (temporary) connection is established with the name server. + +<P> +The second argument to XPANSLookup is the class:name +<A HREF="./template.html">template</A> +to match. + +<P> +The third argument for XPANSLookup() is the type of access and can be +any combination of: +<PRE> + type explanation + ------ ----------- + g xpaget calls can be made on this access point + s xpaset calls can be made on this access point + i xpainfo calls can be made on this access point +</PRE> +<P> +The call typically specifies only one of these at a time. + +<P> +The final arguments are pointers to arrays that will be filled +in and returned by the name server. The name server will allocate and +return arrays filled with the classes, names, and methods of all XPA +access points that match the <A HREF="./template.html">template</A> +and have the specified type. Also returned are info strings, which +generally are used internally by the client routines. These can be +ignored (but the strings must be freed). The function returns the +number of matches. The returned value can be used to loop through the +matches: + +<B>Example:</B> +<PRE> + #include <xpa.h> + + char **classes; + char **names; + char **methods; + char **infos; + int i, n; + n = XPANSLookup(NULL, "foo*", "g", &classes, &names, &methods, &infos); + for(i=0; i<n; i++){ + [more specific checks on possibilities ...] + [perhaps a call to XPAGet for those that pass, etc. ...] + /* don't forget to free alloc'ed strings when done */ + free(classes[i]); + free(names[i]); + free(methods[i]); + free(infos[i]); + } + /* free up arrays alloc'ed by names server */ + if( n > 0 ){ + free(classes); + free(names); + free(methods); + free(infos); + } +</PRE> +<P> +The specified +<A HREF="./template.html">template</A> +also can be a host:port specification, for example: +<PRE> + myhost:12345 +</PRE> +<P> +In this case, no connection is made to the name server. Instead, the +call will return one entry such that the ip array contains the ip for +the specified host and the port array contains the port. The class +and name entries are set to the character "?", since the class and +name of the access point are not known. + +<!-- =defdoc xpaaccess xpaaccess 3 --> + +<!-- =section xpaaccess NAME --> +<H2><A NAME="xpaaccess">XPAAccess: return XPA access points matching +template (XPA 2.1 and above)</A></H2> + +<!-- =section xpaaccess SYNOPSIS --> +<B> +<PRE> + #include <xpa.h> + + int XPAAccess(XPA xpa, + char *template, char *paramlist, char *mode, + char **names, char **messages, int n); +</PRE> +</B> + +<!-- =section xpaaccess DESCRIPTION --> +<P> +The XPAAccess routine returns the public access points that match the +specified second argument <A HREF="./template.html">template</A> and +have the specified access type. + +<P> +A +<A HREF="./template.html">template</A> +of the form "class1:name1" is sent to the +XPA name server, which returns a list of at most n matching XPA +servers. A connection is established with each of these servers and +the paramlist string is passed to the server as the data transfer +request is initiated. If an XPA struct is passed to the call, then the +persistent connections are updated as described above. Otherwise, +temporary connections are made to the servers (which will be closed +when the call completes). + +<P> +The XPAAccess() routine retrieves names from at most n XPA servers +that match the specified template and that were checked for access +using the specified mode. The return string contains both the +class:name and ip:port. If a given server returned an error or the +server callback sends a message back to the client, then the message +will be stored in the associated element of the messages array. +NB: if specified, the name and messages arrays must be of size n or greater. + +<P> +The returned message string will be of the form: +<PRE> + XPA$ERROR error-message (class:name ip:port) +</PRE> +<P> +Note that names of matching registered access points are always +returned but may not be valid; it is not sufficient to assume that the +returned number of access points is the number of valid access points. +Rather, it is essential to check the messages array for error +messages. Any string in the messages array is an error message and +indicated that the associated access point is not available. + +<P> +For example, assume that a server registers a number of access points +but delays entering its event loop. If a call to XPAAccess() is made +before the event loop is entered, the call will timeout (after waiting +for the long timeout period) and return an error of the form: +<PRE> + XPA$ERROR: timeout waiting for server authentication (XPA:xpa1) +</PRE> +The error means that the XPA access point has been registered but is +not yet available (because events are not being processed). When the +server finally enters its event loop, subsequent calls to XPAAccess() +will return successfully. + +<P> +NB: This routine only works with XPA servers built with XPA 2.1.x and later. +Servers with older versions of XPA will return the error message: + + XPA$ERROR invalid xpa command in initialization string + +If you get this error message, then the old server actually is ready +for access, since it got to the point of fielding the query! The +xpaaccess program, for example, ignores this message in order to work +properly with older servers. + +<P> +The third argument for XPAAccess() is the type of access and can be +any combination of: +<PRE> + type explanation + ------ ----------- + g xpaget calls can be made on this access point + s xpaset calls can be made on this access point + i xpainfo calls can be made on this access point +</PRE> +<P> +The mode string argument is of the form: "key1=value1,key2=value2,..." +The following keywords are recognized: +<PRE> + key value default explanation + ------ -------- -------- ----------- + ack true/false true if false, don't wait for ack from server (after callback completes) +</PRE> +<P> +The ack keyword is not very useful, since the server completes the callback +in order to return the data anyway. It is here for completion (and perhaps +for future usefulness). + +<!-- =section xpaclient SEE ALSO --> +<!-- =text See xpa(n) for a list of XPA help pages --> +<!-- =section xpaget SEE ALSO --> +<!-- =text See xpa(n) for a list of XPA help pages --> +<!-- =section xpaset SEE ALSO --> +<!-- =text See xpa(n) for a list of XPA help pages --> +<!-- =section xpainfo SEE ALSO --> +<!-- =text See xpa(n) for a list of XPA help pages --> +<!-- =section xpagetfd SEE ALSO --> +<!-- =text See xpa(n) for a list of XPA help pages --> +<!-- =section xpasetfd SEE ALSO --> +<!-- =text See xpa(n) for a list of XPA help pages --> +<!-- =section xpaopen SEE ALSO --> +<!-- =text See xpa(n) for a list of XPA help pages --> +<!-- =section xpaclose SEE ALSO --> +<!-- =text See xpa(n) for a list of XPA help pages --> +<!-- =section xpanslookup SEE ALSO --> +<!-- =text See xpa(n) for a list of XPA help pages --> +<!-- =section xpaaccess SEE ALSO --> +<!-- =text See xpa(n) for a list of XPA help pages --> +<!-- =stop --> + +<P> +<A HREF="./help.html">Go to XPA Help Index</A> + +<H5>Last updated: March 10, 2007</H5> + +</BODY> +</HTML> diff --git a/xpa/doc/convert.html b/xpa/doc/convert.html new file mode 100644 index 0000000..a8d0dd2 --- /dev/null +++ b/xpa/doc/convert.html @@ -0,0 +1,146 @@ +<!-- =defdoc xpaconvert xpaconvert n --> +<HTML> +<HEAD> +<TITLE>Converting the XPA API to 2.0</TITLE> +</HEAD> +<BODY> + +<!-- =section xpaconvert NAME --> +<H2><A NAME="xpaconvert">XPAConvert: Converting the XPA API to 2.0</A></H2> + +<!-- =section xpaconvert SYNOPSIS --> +<H2>Summary</H2> +<P> +This document describes tips for converting from xpa 1.0 (Xt-based +xpa) to xpa 2.0 (socket-based xpa). + +<!-- =section xpaconvert DESCRIPTION --> +<H2>Description</H2> +<P> +The following are tips for converting from xpa 1.0 (Xt-based xpa) to +xpa 2.0 (socket-based xpa). The changes are straight-forward and +almost can be done automatically (we used editor macros for most of +the conversion). +<UL> +<P> +<LI>The existence of the cpp XPA_VERSION directive to distinguish between 1.0 +(where it is not defined) and 2.0 (where it is defined). + +<P> +<LI>Remove the first widget argument from all send and receive server +callbacks. Also change first 2 arguments from XtPointer to void +*. For example: +<PRE> +#ifdef XPA_VERSION +static void XPAReceiveFile(client_data, call_data, paramlist, buf, len) + void *client_data; + void *call_data; + char *paramlist; + char *buf; + int len; +#else +static void XPAReceiveFile(w, client_data, call_data, paramlist, buf, len) + Widget w; + XtPointer client_data; + XtPointer call_data; + char *paramlist; + char *buf; + int len; +#endif +</PRE> +<P> +<LI>Server callbacks should be declared as returning int instead +of void. They now should return 0 for no errors, -1 for error. + +<P> +<LI> The mode flags have changed when defining XPA server callbacks. +The old <EM>S</EM> flag (save buffer) is replaced by <EM>freebuf=false</EM>. +The old <EM>E</EM> flag (empty buffer is OK) is no longer used (it +was an artifact of the X implementation). + +<P> +<LI>Change NewXPACommand() to XPAcmdNew(), with the new calling sequence: +<PRE> + xpa = NewXPACommand(toplevel, NULL, prefix, NULL); +</PRE> +is changed to: +<PRE> + xpa = XPACmdNew(xclass, name); +</PRE> +<P> +<LI>Change the AddXPACommand() subroutine name to XPACmdAdd (with the same +calling sequence): +<PRE> + AddXPACommand(xpa, "file", + "\tdisplay a new file\n\t\t requires: filename", + NULL, NULL, NULL, XPAReceiveFile, text, NULL); +</PRE> +is changed to: +<PRE> + XPACmdAdd(xpa, "file", + "\tdisplay a new file\n\t\t requires: filename", + NULL, NULL, NULL, XPAReceiveFile, text, NULL); +</PRE> +<P> +<LI>The XPAXtAppInput() routine should be called just before XtAppMainLoop() +to add xpa fds to the Xt event loop: +<PRE> + /* add the xpas to the Xt loop */ + XPAXtAddInput(app, NULL); + + /* process events */ + XtAppMainLoop(app); +</PRE> +<P> +<LI>Change NewXPA() to XPANew() and call XPAXtAddInput() if the XtAppMainLoop +routine already has been entered: +<PRE> + xpa = NewXPA(saotng->xim->toplevel, prefix, xparoot, + "FITS data or image filename\n\t\t options: file type", + XPASendData, new, NULL, + XPAReceiveData, new, "SE"); +</PRE> +is changed to: +<PRE> + sprintf(tbuf, "%s.%s", prefix, xparoot); + xpa = XPANew("SAOTNG", tbuf, + "FITS data or image filename\n\t\t options: file type", + XPASendData, new, NULL, + XPAReceiveData, new, "SE"); + XPAXtAddInput(XtWidgetToApplicationContext(saotng->xim->toplevel), xpa); +</PRE> +<P> +<LI>Change XPAInternalReceiveCommand() to XPACmdInternalReceive() +remove first argument in the calling sequence): +<PRE> + XPAInternalReceiveCommand(im->saotng->xim->toplevel, + im->saotng, im->saotng->commands, + "zoom reset", NULL, 0); +</PRE> +is changed to: +<PRE> + XPACmdInternalReceive(im->saotng, im->saotng->commands, + "zoom reset", NULL, 0); +</PRE> +<P> +<LI>Change DestroyXPA to XPAFree: +<PRE> + DestroyXPA(im->dataxpa); +</PRE> +is changed to: +<PRE> + XPAFree(im->dataxpa); +</PRE> +</UL> + +<!-- =section xpaconvert SEE ALSO --> +<!-- =text See xpa(n) for a list of XPA help pages --> +<!-- =stop --> + +<P> +<A HREF="./help.html">Go to XPA Help Index</A> + +<H5>Last updated: September 10, 2003</H5> + +</BODY> +</HTML> diff --git a/xpa/doc/env.html b/xpa/doc/env.html new file mode 100644 index 0000000..4a71e80 --- /dev/null +++ b/xpa/doc/env.html @@ -0,0 +1,371 @@ +<!-- =defdoc xpaenv xpaenv n --> +<HTML> +<HEAD> +<TITLE>The XPA Environment</TITLE> +</HEAD> +<BODY> + +<!-- =section xpaenv NAME --> +<H2><A NAME="xpaenvl">XPAEnv: Environment Variables for XPA Messaging</A></H2> + +<!-- =section xpaenv SYNOPSIS --> +<H2>Summary</H2> +Describes the environment variables which can be used to tailor the overall +XPA environment. + +<!-- =section xpaenv DESCRIPTION --> +<H2>Description</H2> +<P> +The following environment variables are supported by XPA: +<DL> +<P> +<DT><B>XPA_ACL</B> +<DD> If <EM>XPA_ACL</EM> is <EM>true</EM>, then +host-based <A HREF="./acl.html">XPA Access Control</A> +is turned on and only specified machines can access specified access +points. If <EM>false</EM>, then access control is turned off and any +machine can access point. The default is turn turn access control on. + +<P> +<DT><B>XPA_ACLFILE</B> +<DD> If +<A HREF="./acl.html">XPA Access Control</A> +is turned on, this variable specifies the name of the file containing +access control information for all access points started by this user. +The default file name is: <EM>$HOME/acls.xpa</EM>. + +<P> +<DT><B>XPA_CONNECT_TIMEOUT</B> +<DD> When an XPA server first starts up, it immediately tries to +connect to the XPA name server program (xpans) on the host specified by +the <em>XPA_NSINET</em> variable. (If this connection fails on the +local host, and if xpans can be found in the path, then the name +server is started automatically.) Unfortunately, a mis-configured +network can cause this connect attempt to hang for many seconds while +the connect() system call times out. Therefore, an alarm is started +to interrupt the connect() call and prevent a long hang. The initial +value of the alarm timeout is 10 seconds, but can be changed by setting +this environment variable. If you want to disable the alarm and allow +the initial connect() to time out, set the value of this variable to +0. Normally, users would not change this variable at all. + +<P> +<DT><B>XPA_CLIENT_DOXPA</B> +<DD> Normally, an XPA client (xpaget, xpaset, etc.) will process incoming +XPA server requests while awaiting the completion of the client request. +Setting this variable to "false" will prevent XPA server requests from +being processed by the client. + +<P> +<DT><B>XPA_DEFACL</B> +<DD> If +<A HREF="./acl.html">XPA Access Control</A> +is turned on, this variable specifies the default access control +condition for all access points, if the <EM>XPA_ACLFILE</EM> file does +not exist. The default acl is: <EM>$host:* $host +</EM>, meaning that +all processes on the host machine have full access to all access points. + +<P> +<DT><B>XPA_HOST</B> +<DD> +For the INET socket method, XPA utilizes the canonical hostname (as +returned by the gethostname() routine) to construct the IP part of the +method id. Under some circumstances, this might not be a correct choice +of name and IP. For example, if an XPA server is started on a machine +running VPN, you might want to use the VPN name and IP instead of the +canonical host name, so that other machines in the VPN network can +access the server. In this case, you can set the XPA_HOST to be +the VPN name (if resolvable) or, more easily, the VPN IP. + +<P> +<DT><B>XPA_IOCALLSXPA</B> +<DD> +Setting this variable causes all XPA socket IO calls to process +outstanding XPA requests whenever the primary socket is not ready for +IO. This means that a server making a client call will (recursively) +process incoming server requests while waiting for client completion. +This inter-IO XPA processing avoids a rare +<A HREF="./server.html#race">XPA Race Condition</A>: two or more +XPA servers sending messages to one another using an XPA client +routine such as XPASet() can deadlock while each waits for the other +server to respond. This can happen, for example, if the servers call +XPAPoll() with a time limit, and send messages in between the polling call. + +<P> +By default, this option is turned off, because we judge that the added +code complication and overhead involved will not be justified by the +amount of its use. Moreover, processing XPA requests within socket IO +can lead to non-intuitive results, since incoming server requests will +not necessarily be processed to completion in the order in which they +are received. + +<P> +<DT><B>XPA_LOGNAME</B> +<DD> +XPA preferentially uses the de facto standard environment variable +LOGNAME to determine the username when registering an access point in +the name server. If this environment variable has been used for +something other than the actual user name (such as a log file name), +unexpected results can ensue. In such cases, use the XPA_LOGNAME +variable to set the user name. (If neither exists, then getpwuid(geteuid()) +is used as a last resort). + +<P> +<DT><B>XPA_LONG_TIMEOUT</B> +<DD> XPA is designed to allow data to be sent from one process to +another over a long period of time (i.e., a program that generates +image data sends that data to an image display, but slowly) but it +also seeks to prevent hangs. This is done by supporting 2 timeout +periods: a <EM>short</EM> timeout for protocol communication +and a <EM>long</EM> for data communication. +<P> +The <EM>XPA_LONG_TIMEOUT</EM> variable controls the <EM>long</EM> +timeout and is used to prevent hangs in cases where communication +between the client and server that is <EM>not</EM> controlled by the +XPA interface itself. Transfer of data between client and server, or a +client's wait for a status message after completion of the server +callback, are two examples of this sort of communication. By default, +the <EM>long</EM> timeout is set to 180 seconds. +Setting the value to -1 will disable <EM>long</EM> timeouts and allow +an infinite amount of time. + +<P> +<DT><B>XPA_MAXHOSTS</B> +<DD> The maximum number of access points that the programs +<EM>xpaset</EM>, <EM>xpaget</EM>, and <EM>xpainfo</EM> will +communicate with at one time. The default is 64, meaning, for +example, that the <EM>xpaset</EM> program will not send a message +to more than 100 access points at one time and <EM>xpaget</EM> will +not retrieve from more than 100 access points at one time. + +<P> +<DT><B>XPA_METHOD</B> +<DD> +Determines the socket connection method used by this session of XPA. +The choices are: <EM>inet</EM> (to use INET or Internet-based +sockets), <EM>localhost</EM> (to use the machines localhost inet +socket), or <EM>local (unix)</EM> (to use UNIX sockets). The default +is <EM>INET</EM>. Using the <EM>inet</EM> method will allow access +from other machines (subject to access controls) but using +<EM>localhost</EM> or <EM>local</EM> will not. Localhost is most useful +for private access and when the machine in question is not connected +to the Internet. The unix method also can be used for private access +and non-Internet connections (Unix platforms only). +<P> +Once defined, the first registration of an XPA access point will +ensure that an instance of the +<A HREF="./xpans.html">XPA Name Server (xpans)</A> +is running that handles that connection method. All new access points +will use the new connection method but existing access points will use +the original method. + +<P> +<DT><B>XPA_NSINET</B> +<DD> For the <EM>inet</EM> method of socket connection, this variable +specifies the host and port on which the +<A HREF="./xpans.html">XPA Name Server (xpans)</A> +is listens for new access points. The default is <EM>$host:$port</EM>, +meaning that the default XPA port (14285) on the current machine +(as returned by gethostname()) is used. If several machines were all +accessing the same XPA access points, you would use this variable to +specify that they all use the same name server to find out about these +access points. For example, a value of <EM>myhost:$port</EM> would +mean that the xpans name server is running on myhost and uses the +default port 12345. All machines would then get the XPA access points +registered with that name server, subject to access controls. +<P> +The port used by xpans to register its XPA access point normally is +taken to be one greater than the port on which it receives new access +points from XPA servers. You can specify a specific access point port +using the syntax machine:port1,port2, i.e., the access point port is +specified after the comma. For example, $host:12345,23456 will listen +for new access ports on 12345 and will accept XPA commands on 23456. + +<P> +<DT><B>XPA_NSREGISTER</B> +<DD> +This boolean variable specifies whether a server registers its XPA +access point with the specified xpans name server. The default is +<em>true</em>. If set to <em>false</em>, the access point still is +set up but it is not registered with xpans and therefore cannot be +accessed by name. (It can be accessed by method, if the latter is +known.) Note that an access point can be registered later on (using +-remote or -proxy, for example). This variable mainly is useful in +cases where the Internet configuration is broken (so that registration +causes a DNS hang) but you still wish to and can use the server with a +remote xpans (e.g., ds9's Virtual Observatory capability). + +<P> +<DT><B>XPA_NSUNIX</B> +<DD> For the <EM>local</EM> method of socket connection, this variable +specifies the name of the Unix file that will be used to access the +<A HREF="./xpans.html">XPA Name Server (xpans)</A>. The default is +<EM>xpans_unix</EM>. This variable is not usually needed. Note that +is the <EM>local</EM> socket method is used, then remote machines will +not be able to access the xpans name server or the registered XPA access +points. + +<P> +<DT><B>XPA_NSUSERS</B> +<DD> +This variable specifies whether other users' access points will be +returned by the +<A HREF="./xpans.html">XPA Name Server (xpans)</A> for use by +<EM>xpaget</EM>, <EM>xpaset</EM>, etc. +Generally speaking, it is sufficient to run one xpans name server per +machine and register the access points for all users with that xpans. +This means, for example, that if you request information from +ds9 by running: +<PRE> + xpaget ds9 colormap +</PRE> +you might get information from your own ds9 as well as +from another user running ds9 on the same machine. The +<EM>XPA_NSUSERS</EM> variable controls whether you want such access +to the access points of other users. +By default, only your own access points are returned, so +that, in the example above, you would only get the colormap information +from the ds9 you registered. If, however, you had set the value of the +<EM>XPA_NSUSERS</EM> variable to <EM>eric,fred</EM>, then you would be +able to communicate with both eric and fred's access points. Note that +this variable can be overridden using the <EM>-u</EM> switch on the +<EM>xpaget</EM>, <EM>xpaset</EM>, and <EM>xpainfo</EM> programs. + +<P> +<DT><B>XPA_PORT</B> +<DD> +A semi-colon delimited list of user specified ports to use for specific +XPA access points. The format is each specification is: +<PRE> +class:template port1[ port2] +</PRE> +where <B>port1</B> is the main (command) port for the access point and +<B>port2</B> is the (secondary) data port. If port2 is not specified, +it defaults to a value of 0 (meaning the system assigns the port). + +<P> +Specification of specific ports is useful, for example, when a machine +outside a firewall needs to communicate with a machine inside a +firewall. In such a case, the firewall should be configured to allow +socket connections to both the command and data port from the outside +machine, and the inside XPA program should be started up with the +outside machine in its ACL list. Then, when the inside program is +started with specified ports, outside XPA programs can use +"machine:port" to contact the inside access points, instead of the +access point names. That is, the machine outside the firewall does not +need access to the XPA name server: +<PRE> +export XPA_PORT="DS9:ds9 12345 12346" # on machine "inside" +cat foo.fits | xpaset inside:12345 fits # on machine "outside" +</PRE> +Note that 2 ports are required for full XPA communication and +therefore 2 ports should be specified to go through a firewall. The +second port assignment is not important if you simply are assigning +the command port in order to communicate commands with a known +port (e.g., to bypass the xpans name server). If only one (command) +port is specified, the system will negotiate a random data port and +everything will work properly. + +<P> +This support is somewhat experimental. If you run into problems, please +let us know. + +<P> +<DT><B>XPA_PORTFILE</B> +<DD> +A list of user-specified port to use for specific xpa access points. +The format of the file is: +<PRE> +class:template port1 [port2] +</PRE> +where <B>port1</B> is the main port for the access point and +<B>port2</B> is the data port. If port2 is not specified, it defaults +to a value of 0 (meaning the system assigns the port). See +<B>XPA_PORT</B> above for an explanation of user-specified ports. + +<P> +<DT><B>XPA_SHORT_TIMEOUT</B> +<DD> XPA is designed to allow data to be sent from one process to +another over a long period of time (i.e., a program that generates +image data sends that data to an image display, but slowly) but it +also seeks to prevent hangs. This is done by supporting 2 timeout +periods: a <EM>short</EM> timeout for protocol communication +and a <EM>long</EM> for data communication. +<P> +The <EM>XPA_SHORT_TIMEOUT</EM> variable +controls the <EM>short</EM> timeout and is used to prevent hangs +in cases where the XPA protocol requires internal communication between +the client and server that is controlled by the XPA interface +itself. Authentication is an example of this sort of communication, +as is the establishment of a data channel between the two processes. +The default value for the <EM>short</EM> is 30 seconds (which is +a pretty long time, actually). Setting the value to -1 will disable +<EM>short</EM> timeouts and allow an infinite amount of time. + +<P> +<DT><B>XPA_SIGUSR1</B> +<DD> If the value of this variable is <EM>true</EM>, then XPA will +catch SIGUSR1 signals when performing an I/O operation in order to +curtail that operation. This facility allows users to send a SIGUSR1 +signal to an XPA server if a client is hanging up the server by +sending or receiving data too slowly (timeouts also can be used -- see +above). When enabled in this way, the SIGUSR1 signal is ignored at all other +times, so that its safe to send the signal at any time. If the +variable is set to <EM>false</EM>, then SIGUSR1 is not used at +all. Turning off SIGUSR1 would be desired in cases there the program +uses SIGUSR1 for some other reason and does not want XPA interfering. +The default is to use the signal. + +<P> +<DT><B>XPA_TIMESTAMP_ERRORS</B> +<DD> If <EM>XPA_TIMESTAMP_ERRORS</EM> is <EM>true</EM>, then error +messages will include a date/time string. This can be useful when +XPA errors are being saved in an error log (e.g. Web/CGI use). The +default is false. +</DL> + +<P> +<DT><B>XPA_TMPDIR</B> +<DD> This variable specifies the directory into which XPA logs, Unix +socket files (when <EM>XPA_METHOD</EM> is <EM>local</EM>), etc. are +stored. The default is <EM>/tmp/.xpa</EM>. + +<P> +<DT><B>XPA_VERBOSITY</B> +<DD> Specify the verbosity level of error messages. If the value is +set to <EM>0</EM>, <EM>false</EM>, or <EM>off</EM>, then no error +messages are printed to stderr. If the value is <EM>1</EM>, then +important XPA error messages will be output. If the value is +set to <EM>2</EM>, XPA warnings about out-of-sync messages will also +be output. These latter almost always can be ignored. + +<P> +<DT><B>XPA_VERSIONCHECK</B> +<DD> Specify whether a new access point should check its major and minor XPA +version number against the version used by the xpans name server at +registration time. The default is <EM>true</EM>. When checking is +performed, a warning is issued if the server major version is found to +be greater than the xpans version. Note that the check is performed +both by the XPA server and by the xpans process and warnings will be +issued by each. Also, instead of the values of <EM>true</EM> or +<em>false</em>, you can give this variable an integer value n. In this +case, each version checking process (i.e., the XPA-enabled server or +xpans) will print out a maximum of n warning messages (after which +version warnings are silently swallowed). +<P> +In general, it is a bad idea to run an XPA-enabled server program +using a version of XPA newer than the basic xpaset, xpaget, xpaaccess, +xpans programs. This sort of mismatch usually will not work due to +protocol changes. + +<!-- =section xpaenv SEE ALSO --> +<!-- =text See xpa(n) for a list of XPA help pages --> +<!-- =stop --> + +<P> +<A HREF="./help.html">Go to XPA Help Index</A> + +<H5>Last updated: December 23, 2009</H5> + +</BODY> +</HTML> diff --git a/xpa/doc/examples.html b/xpa/doc/examples.html new file mode 100644 index 0000000..0bd68d4 --- /dev/null +++ b/xpa/doc/examples.html @@ -0,0 +1,64 @@ +<!-- =defdoc xpacode xpacode n --> +<HTML> +<HEAD> +<TITLE>Where to Find Example/Test Code</TITLE> +</HEAD> +<BODY> + +<!-- =section xpacode NAME --> +<H2><A NAME="xpacode">XPACode: Where to Find Example/Test Code</A></H2> + +<!-- =section xpacode SYNOPSIS --> +<H2>Summary</H2> +<P> +The XPA source code directory contains two test programs, +<EM>stest.c</EM>, and <EM>ctest.c</EM> that can serve as +examples for writing XPA servers and clients, respectively. +They also can be used to test various features of XPA. + +<!-- =section xpacode DESCRIPTION --> +<H2>Description</H2> +<P> +To build the XPA test programs, execute: +<PRE> + make All +</PRE> +in the XPA source directory to generate the <EM>stest</EM> and +<EM>ctest</EM> programs. (NB: this should work on all platforms, +although we have had problems with unresolved externals on one +Sun/Solaris machine, for reasons still unknown.) +<P> +The stest program can be executed with no arguments to start +an XPA server that contains the access points: xpa, xpa1, +c_xpa (containing sub-commands cmd1 and cmd2), and i_xpa. +You then can use xpaset and xpaget to interact with these access points: +<PRE> + cat xpa.c | xpaset xpa # send to xpa + cat xpa.c | xpaset "xpa*" # send to xpa and xpa1 + xpaget xpa # receive from xpa + xpaget xpa* # receive from xpa and xpa1 +</PRE> +etc. You also can use ctest to do the same thing, or to iterate: +<PRE> + ctest -s -l 100 xpa # send to xpa 100 times + ctest -s -l 100 "xpa*" # send to xpa and xpa1 100 times + ctest -g -l 100 xpa # receive from xpa 100 times + ctest -g -l 100 "xpa*" # receive from xpa and xpa1 100 times +</PRE> +More options are available: see the stest.c and ctest.c code itself, which +were used extensively to debug XPA. + +<P> +The file test.tcl in the XPA source directory gives examples for using the +<A HREF="./tcl.html">XPATcl</A>Interface. + +<!-- =section xpacode SEE ALSO --> +<!-- =text See xpa(n) for a list of XPA help pages --> +<!-- =stop --> + +<P> +<A HREF="./help.html">Go to XPA Help Index</A> + +<H5>Last updated: September 10, 2003</H5> +</BODY> +</HTML> diff --git a/xpa/doc/help.html b/xpa/doc/help.html new file mode 100644 index 0000000..dfe51f9 --- /dev/null +++ b/xpa/doc/help.html @@ -0,0 +1,162 @@ +<!-- =defdoc xpa xpa n --> +<HTML> +<HEAD> +<TITLE>The XPA Help Facility</TITLE> +</HEAD> +<BODY> + +<!-- =section xpa NAME --> +<H2><A NAME="xpa">XPA: Public Access to Data and Algorithms</A></H2> + +<!-- =section xpa SYNOPSIS --> +<H2>Summary</H2> +This document is the Table of Contents for XPA. + +<!-- =section xpa DESCRIPTION --> +<H2>Description</H2> +<P> +The XPA messaging system provides seamless communication between many +kinds of Unix programs, including X programs and Tcl/Tk programs. It +also provides an easy way for users to communicate with XPA-enabled +programs by executing XPA client commands in the shell or by utilizing +such commands in scripts. Because XPA works both at the programming +level and the shell level, it is a powerful tool for unifying any +analysis environment: users and programmers have great flexibility in +choosing the best level or levels at which to access XPA services, and +client access can be extended or modified easily at any time. + +<P> +A program becomes an XPA-enabled server by defining named points of +public access through which data and commands can be exchanged with +other client programs (and users). Using standard TCP sockets as a +transport mechanism, XPA supports both single-point and broadcast +messaging to and from these servers. It supports direct communication +between clients and servers, or indirect communication via an +intermediate message bus emulation program. Host-based access control +is implemented, as is as the ability to communicate with XPA servers +across a network. + +<P> +XPA implements a layered interface that is designed to be useful both +to software developers and to users. The interface consists of a +library of XPA client and server routines for use in C/C++ programs and +a suite of high-level user programs built on top of these libraries. +Using the XPA library, access points can be added to Tcl/Tk programs, +Xt programs, or to Unix programs that use the XPA event loop or any +event loop based on select(). Client access subroutines can be added +to any Tcl/Tk, Xt, or Unix program. Client access also is supported at +the command line via a suite of high-level programs. + +<P> +Choose from the following topics: + +<UL> +<LI><A HREF="./intro.html">Introduction to XPA</A> +<!-- =text [xpaintro(n)] --> +<LI><A HREF="./template.html">Access Point Names and Templates</A> +<!-- =text [xpatemplate(n)] --> +<LI><A HREF="./info.html">Getting Common Information About Access Points</A> +<!-- =text [xpacommon(n)] --> +<LI><A HREF="./method.html">Communication Methods</A> +<!-- =text [xpamethod(n)] --> +<LI><A HREF="./inet.html">Communication Between Hosts</A> +<!-- =text [xpainet(n)] --> +<LI><A HREF="./users.html">Distinguishing Users</A> +<!-- =text [xpausers(n)] --> + +<LI><A HREF="./programs.html">XPA User Programs</A> +<UL> +<LI><A HREF="./programs.html#xpaget">xpaget: get data and info</A> +<!-- =text [xpaget(1)] --> +<LI><A HREF="./programs.html#xpaset">xpaset: send data and info</A> +<!-- =text [xpaset(1)] --> +<LI><A HREF="./programs.html#xpainfo">xpainfo: send info alert</A> +<!-- =text [xpainfo(1)] --> +<LI><A HREF="./programs.html#xpaaccess">xpaaccess: get access point info</A> +<!-- =text [xpaaccess(1)] --> +<LI><A HREF="./xpamb.html">xpamb: message bus emulation</A> +<!-- =text [xpamb(1)] --> +<LI><A HREF="./xpans.html">xpans: the XPA name server</A> +<!-- =text [xpans(1)] --> +</UL> + +<LI><A HREF="./server.html">XPA Server Routines</A> +<UL> +<LI><A HREF="./server.html#xpanew">XPANew: define a new access point</A> +<!-- =text [xpanew(3)] --> +<LI><A HREF="./server.html#xpacmdnew">XPACmdNew: define a new command access point</A> +<!-- =text [xpacmdnew(3)] --> +<LI><A HREF="./server.html#xpacmdadd">XPACmdAdd: add a command</A> +<!-- =text [xpacmdadd(3)] --> +<LI><A HREF="./server.html#xpacmddel">XPACmdDel: delete a command</A> +<!-- =text [xpacmddel(3)] --> +<LI><A HREF="./server.html#xpainfonew">XPAInfoNew: define an info access point</A> +<!-- =text [xpainfonew(3)] --> +<LI><A HREF="./server.html#xpafree">XPAFree: free an access point</A> +<!-- =text [xpafree(3)] --> +<LI><A HREF="./server.html#xpamainloop">XPAMainLoop: event loop for select server</A> +<!-- =text [xpamainloop(3)] --> +<LI><A HREF="./server.html#xpapoll">XPAPoll: poll for XPA events</A> +<!-- =text [xpapoll(3)] --> +<LI><A HREF="./server.html#xpacleanup">XPACleanup: release reserved XPA memory</A> +<!-- =text [xpacleanup(3)] --> +<LI><A HREF="./server.html#macros">XPA Server Macros: accessing structure internals</A> +<!-- =text [xpamacros(3)] --> +<LI><A HREF="./server.html#race">XPA Race Conditions: how to avoid them</A> +<!-- =text [xparace(3)] --> +<LI><A HREF="./oom.html">XPA Out of Memory (OOM) errors</A> +<!-- =text [xpaoom(3)] --> +</UL> + +<LI><A HREF="./client.html">XPA Client Routines</A> +<UL> +<LI><A HREF="./client.html#xpaopen">XPAOpen: open a persistent client connection</A> +<!-- =text [xpaopen(3)] --> +<LI><A HREF="./client.html#xpaclose">XPAClose: close persistent client connection</A> +<!-- =text [xpaclose(3)] --> +<LI><A HREF="./client.html#xpaget">XPAGet: get data</A> +<!-- =text [xpaget(3)] --> +<LI><A HREF="./client.html#xpaset">XPASet: send data or commands</A> +<!-- =text [xpaset(3)] --> +<LI><A HREF="./client.html#xpainfo">XPAInfo: send an info alert</A> +<!-- =text [xpainfo(3)] --> +<LI><A HREF="./client.html#xpagetfd">XPAGetFd: get data and write to an fd</A> +<!-- =text [xpagetfd(3)] --> +<LI><A HREF="./client.html#xpasetfd">XPASetFd: read data from and fd and send</A> +<!-- =text [xpasetfd(3)] --> +<LI><A HREF="./client.html#xpanslookup">XPANSLookup: look up an access point</A> +<!-- =text [xpanslookup(3)] --> +<LI><A HREF="./client.html#xpaaccess">XPAAccess: get access info</A> +<!-- =text [xpaaccess(3)] --> +<LI><A HREF="./xt.html">The XPA/Xt Interface: Xt interface to XPA</A> +<!-- =text [xpaxt(n)] --> +<LI><A HREF="./tcl.html">The XPA/Tcl Interface: Tcl interface to XPA</A> +<!-- =text [xpatcl(n)] --> +</UL> + +<LI> Tailoring the XPA Environment +<UL> +<LI><A HREF="./env.html">Environment Variables</A> +<!-- =text [xpaenv(n)] --> +<LI><A HREF="./acl.html">Access Control</A> +<!-- =text [xpaacl(n)] --> +</UL> + +<LI> Miscellaneous +<UL> +<!-- =stop --> +<LI><A HREF="./changelog.html">XPA ChangeLog</A> +<!-- =cont --> +<LI><A HREF="./examples.html">Where to Find Example/Test Code</A> +<LI><A HREF="./changes.html">User Changes Between XPA 1.0 and 2.0</A> +<LI><A HREF="./convert.html">API Changes Between XPA 1.0 and 2.0</A> +<LI><A HREF="./name.html">What Does XPA Stand For, Anyway?</A> +</UL> + +</UL> + +<!-- =stop --> + +<H5>Last updated: September 10, 2003</H5> +</BODY> +</HTML> diff --git a/xpa/doc/html2man b/xpa/doc/html2man new file mode 100755 index 0000000..4e60799 --- /dev/null +++ b/xpa/doc/html2man @@ -0,0 +1,258 @@ +#!/usr/bin/perl +# +# See COPYRIGHT +# +# Script to generate a pod file from an html source (the same one as for text files too) +# and later this pod file it passed through pod2man +# +# Use: +# html2man [ <man-dir> [<version-dir>] ] <file.html +# +# <Man-dir> is the directory where the man pages will be created +# (current directory by default). If a file name is given instead of +# directory then the directory of that file is used. +# <Version-dir> is the directory containing the ttf2pt1 files version.h +# and CHANGES.html which are used to generate the release name and date +# for the man page (by default looks in current directory and then in up to +# 5 ancestor directories). +# If the version files can not be found then the release defaults to +# "current" and the date defaults to today. +# +# Special formatting in the html file is: +# All controls are hidden within HTML comments that must occupy a whole separate line +# Such a line looks like: +# <!-- =<html2man_directive> <arguments> --> +# <!-- ==<pod_directive> <arguments> --> +# Any sort of directive must be followed by a space. The pod directives are +# automatically surrounded by empty lines in the output file. +# The html2man directives are: +# +# <!-- =defdoc <docid> <file> <section> --> +# Define a man page. Multiple man pages can be defined in the same HTML +# file. <Docid> is a short name by which this man page will be referred in the +# other directives. <File> is the name of the man page, and <section> is the +# section of the manual (do not confuse with sections within a man page). +# +# <!-- =section <docid> <page_section_name> --> +# All the text following this directive is copied (with translation) +# into the specified section of the specified man page. The sections +# may appear in arbitrary order, they will be rearranged to the standard +# order before output. Only standard section names are permitted (see @stdsect +# below). The pod directives which occur outside of man sections are ignored, +# just like the common text. The translation of HTML tags is: +# +# <br> - to paragraph break +# <b> - to B<> +# <i> - to I<> +# <tt> - to C<> +# <a href> - to F<> +# <ul>, <li>, </ul> - to =over 2, =item *, =back +# , &, <, > - to their symbols, appropriately encoded +# +# The rest of HTML tags is removed +# +# If the same section is started more than once, the text from the +# second appearance will be added to the first, etc. +# +# <!-- =stop --> +# Stop copying text to the man page. +# +# <!-- =cont --> +# Continue copying text to the man page, same section as before. +# +# <!-- =text <text> --> +# Insert this <text> into the man page (works only when copying is enabled). +# Characters <, >, & are converted as usual. + +@mons = qw(January February March April May June July August September October November December); + +$dir = $ARGV[0]; +$maindir = $ARGV[1]; + +if($dir eq "") { + $dir = "."; +} elsif( ! -d $dir ) { + if( ! ($dir =~ s|\/[^/]*$||) ) { + $dir = "."; + } +} +if($maindir eq "") { + $maindir = "."; + for($i=0; $i<5; $i++) { + if(-f "$maindir/version.h") { + last; + } + $maindir = "../$maindir"; + } +} + +if( open(VERFILE, "<$maindir/version.h") ) { + while(<VERFILE>) { + if( /^\s*\#define\s+TTF2PT1_VERSION\s+\"(.*)\"/ ) { + $release = "version $1"; + } + } + close(VERFILE); + if( $release =~ /SNAP-([0-9][0-9])([0-9][0-9])([0-9][0-9])/ ) { + $date = sprintf("%s %d, 20%02d", $mons[$2-1], $3, $1); + } elsif( open(CFILE, "<$maindir/CHANGES.html") ) { + while(<CFILE>) { + if( /\<H4\>/) { + last; + } + } + $_ = <CFILE>; + chomp; + if( $_ =~ s/^.*?-- // ) { + $date = $_; + } + close(CFILE); + } +} + +if($release eq "") { + if( open(VERFILE, "<../Makefile") ) { + while(<VERFILE>) { + if( /^VERSION\s+=\s+(.*)/ ) { + $release = "version $1"; + } + } + close(VERFILE); + } +} + +if($release eq "") { + $release = "current"; +} +if($date eq "") { + @lt = localtime(time); + $date = sprintf("%s %d, %d", $mons[$lt[4]], $lt[3], 1900+$lt[5]); +} + +#printf(STDERR "date=%s release=%s\n", $date, $release); + +$writemode = 0; + +while(<STDIN>) { + if( s/^\<\!\-\- \=(\S+)\s+//) { + $cmd = $1; + s/\s*\-\-\>\s*$//; + #printf(STDERR "cmd=%s args=%s\n", $cmd, $_); + if($cmd =~ /^=/) { + if($writemode) { + $text{$tosect} .= "\n\n$cmd $_\n\n"; + } + } elsif($cmd eq "defdoc") { + @sl = split; + push(@allids, $sl[0]); + $file{$sl[0]} = $sl[1]; + $mansect{$sl[0]} = $sl[2]; + } elsif($cmd eq "section") { + # tosect includes the file id + $tosect = $_; + $text{$tosect} .= "\n\n"; + $writemode = 1; + } elsif($cmd eq "stop") { + $writemode = 0; + $text{$tosect} .= "\n"; + } elsif($cmd eq "cont") { + $writemode = 1; + } elsif($cmd eq "text") { + if($writemode) { + s/\<\;/</gi; + s/\>\;/>/gi; + s/\&\;/\&/gi; + $text{$tosect} .= "$_\n"; + } + } + } elsif($writemode) { +# s/^\s+//; + + s/\{/\&lbr;/g; + s/\}/\&rbr;/g; + + s/\<br\>/\n\n/gi; + #s/\<blockquote\>/\n\n=over 4\n\n/gi; + #s/\<\/blockquote\>/\n\n=back\n\n/gi; + s/\<ul\>/\n\n=over 4\n\n/gi; + s/\<\/ul\>/\n\n=back\n\n/gi; + s/\<li\>\s*/\n\n=item \*\n\n/gi; + + s/\<dl\>/\n\n=over 4\n\n/gi; + s/\<\/dl\>/\n\n=back\n\n/gi; + s/\<dt\>\s*/\n\n=item \*\n\n/gi; + s/\<dd\>\s*/\n\n/gi; + + s/\<i\>(.*?)\<\/i\>/I\{\1\}/gi; + s/\<em\>(.*?)\<\/em\>/I\{\1\}/gi; + s/\<b\>(.*?)\<\/b\>/B\{\1\}/gi; + s/\<tt\>(.*?)\<\/tt\>/C\{\1\}/gi; + s/\<a href\=\.*?\>(.*?)\<\/a\>/F\{\1\}/gi; + s/\<h2\>summary\<\/h2\>//gi; + s/\<h2\>description\<\/h2\>//gi; + s/\<h2\>examples\<\/h2\>//gi; + s/\<h2\>options\<\/h2\>//gi; + s/\<h2\>(.*?)\<\/h2\>/B\{\1\}/gi; + s/\<.*?\>//g; + s/\{/\</g; + s/\}/\>/g; + + s/\ \;/S< >/gi; + s/\&\;/\&/gi; +# s/\<\;/E<lt>/gi; +# s/\>\;/E<gt>/gi; + s/\<\;/\</gi; + s/\>\;/\>/gi; + #s/\|/E<verbar>/g; + #s/\//E<sol>/g; + s/\&lbr\;/\{/g; + s/\&rbr\;/\}/g; + + #printf(STDERR "section=%s add=%s", $tosect, $_); + $text{$tosect} .= $_; + } +} + +@stdsect = ( + "NAME", + "SYNOPSIS", + "OPTIONS", + "DESCRIPTION", + "RETURN VALUE", + "ERRORS", + "EXAMPLES", + "ENVIRONMENT", + "FILES", + "SEE ALSO", + "NOTES", + "CAVEATS", + "DIAGNOSTICS", + "BUGS", + "RESTRICTIONS", + "AUTHOR", + "HISTORY" ); + +#printf(STDERR "allids= @allids\n"); +for $id (@allids) { + print(STDERR "creating man page $id $file{$id} $mansect{$id}\n\n"); + die "Unable to create pod file $dir/$file{$id}.pod" + unless open(PODF, ">./pod/$file{$id}.pod"); + print(PODF "=pod\n\n"); + for $sect (@stdsect) { + $sid = "$id $sect"; + #printf(STDERR "trying %s\n", $sid); + if(defined $text{$sid}) { + #printf(STDERR " section %s\n", $sid); + print(PODF "=head1 $sect\n\n$text{$sid}\n\n"); + } + } + print(PODF "=cut\n"); + close(PODF); + die "Unable to generate the man page $dir/$file{$id}.1" + if system("pod2man --section=\"$mansect{$id}\" --release=\"$release\" " + . "--center=\"SAORD Documentation\" --date=\"$date\" " + . "--name=\"$file{$id}\" " + . "./pod/$file{$id}.pod > $dir/man$mansect{$id}/$file{$id}.$mansect{$id}"); + + unlink("$dir/$file{$id}.pod"); +} diff --git a/xpa/doc/html2ps.dbg b/xpa/doc/html2ps.dbg new file mode 100644 index 0000000..2c7bc86 --- /dev/null +++ b/xpa/doc/html2ps.dbg @@ -0,0 +1,94 @@ +***** html2ps version 1.0 beta5 +***** Command: /proj/rd/linux64/bin/html2ps -C fb -d -g -n -u -W b -x 1 -o xpa.ps help.html +***** Perl: 5.010001 +***** HTML2PSPATH= +***** Global file /proj/rd/linux64/lib/html2ps/html2psrc: +/* Global configuration file for html2ps */ + +@html2ps { + package { + ImageMagick: 1; + djpeg: 1; + TeX: 1; + dvips: 1; + Ghostscript: 1; + libwww-perl: 1; + path: "/usr/bin"; + } + paper { + type: letter; + } + hyphenation { + en { + file: "/proj/rd/linux64/lib/html2ps/hyphen.tex"; + } + } +} +***** +html2ps version 1.0 beta5 +Reading help.html +Link: intro.html +Link: template.html +Link: info.html +Link: method.html +Link: inet.html +Link: users.html +Link: programs.html +Link: xpamb.html +Link: xpans.html +Link: server.html +Link: oom.html +Link: client.html +Link: xt.html +Link: tcl.html +Link: env.html +Link: acl.html +Link: changelog.html +Link: examples.html +Link: changes.html +Link: convert.html +Link: name.html +At least 21 documents remaining +Reading intro.html +At least 20 documents remaining +Reading template.html +At least 19 documents remaining +Reading info.html +At least 18 documents remaining +Reading method.html +At least 17 documents remaining +Reading inet.html +At least 16 documents remaining +Reading users.html +At least 15 documents remaining +Reading programs.html +At least 14 documents remaining +Reading xpamb.html +At least 13 documents remaining +Reading xpans.html +At least 12 documents remaining +Reading server.html +At least 11 documents remaining +Reading oom.html +At least 10 documents remaining +Reading client.html +At least 9 documents remaining +Reading xt.html +At least 8 documents remaining +Reading tcl.html +At least 7 documents remaining +Reading env.html +At least 6 documents remaining +Reading acl.html +At least 5 documents remaining +Reading changelog.html +At least 4 documents remaining +Reading examples.html +At least 3 documents remaining +Reading changes.html +At least 2 documents remaining +Reading convert.html +At least 1 document remaining +Reading name.html +Inserting cross references + diff --git a/xpa/doc/inet.html b/xpa/doc/inet.html new file mode 100644 index 0000000..3155885 --- /dev/null +++ b/xpa/doc/inet.html @@ -0,0 +1,260 @@ +<!-- =defdoc xpainet xpainet n --> +<HTML> +<HEAD> +<TITLE>XPA Communication Between Hosts</TITLE> +</HEAD> +<BODY> + +<!-- =section xpainet NAME --> +<H2><A NAME="xpainet">XPAInet: XPA Communication Between Hosts</A></H2> + +<!-- =section xpainet SYNOPSIS --> +<H2>Summary</H2> +XPA uses standard inet sockets to support communication between two or +more host computers. + +<!-- =section xpainet DESCRIPTION --> +<H2>Description</H2> +<P> +When the <A HREF="./method.html">Communication Method</A> is set to +<B>inet</B> (as it is by default), XPA can be used to communicate +between different computers on the Internet. INET sockets utilize the +IP address of the given machine and a (usually random) port number to +communicate between processes on the same machine or between different +machines on the Internet. These standard Internet sockets are also +used by programs such as Netscape, ftp. etc. + +<P> +XPA supports a host-based <A HREF="./acl.html">Access Control</A> mechanism +to prevent unauthorized access of XPA access points by other computers +on the Net. By default, only the machine on which the XPA server is +running can access XPA services. Therefore, setting up communication +between a local XPA server machine and a remote client machine +requires a two-part registration process: + +<UL> +<LI> the XPA service on the local machine must be made known to the +remote machine +<LI> the remote machine must be given permission to access the local +XPA service +</UL> + +Three methods by which this remote registration can be accomplished +are described below. + +<H2>Manual Registration</H2> + +The first method is the most basic and does not require the remote +client to have xpans running. To use it, the local server simply +gives a remote client machine access to one or more XPA access points +using xpaset and the <B>-acl</B> sub-command. For example, +consider the XPA test program "stest" running on a local machine. By +default the access control for the access point named "xpa" is +restricted to that machine: +<PRE> + [sh]$ xpaget xpa -acl + *:* 123.456.78.910 gisa + *:* localhost gisa +</PRE> +Using xpaset and the <B>-acl</B> sub-command, a remote client +machine can be given permission to perform xpaget, xpaset, xpaaccess, +or xpainfo operations. For example, to allow the xpaget operation, the +following command can be issued on the local machine: +<PRE> + [sh]$ xpaset -p xpa -acl "remote_machine g" +</PRE> +This results in the following access permissions on the local machine: +<PRE> + [sh]$ xpaget xpa -acl + XPA:xpa 234.567.89.012 g + *:* 123.456.78.910 gisa + *:* localhost gisa +</PRE> + +The remote client can now use the local server's xpans name server to +establish communication with the local XPA service. This can be done +on a call-by-call basis using the <B>-i</B> switch on xpaset, xpaget, etc: +<PRE> + [sh]$ xpaget -i "local_machine:12345" xpa + class: XPA + name: xpa + method: 88877766:2778 + sendian: little + cendian: big +</PRE> +Alternatively, the XPA_NSINET variable on the remote machine can be +set to point directly to xpans on the local machine, removing +the need to override this value each time an XPA program is run: +<PRE> + [csh]$ setenv XPA_NSINET 'karapet:$port' + [csh]$ xpaget xpa + class: XPA + name: xpa + method: 88877766:2778 + sendian: little + cendian: big +</PRE> +Here, '$port' means to use the default XPA name service port (14285). +not a port environment variable. + +<p> +Access permission for remote client machines can be stored in a file +on the local machine pointed to by the <B>XPA_ACLFILE</B> environment +variable or using the <B>XPA_DEFACL</B> environment variable. See <A +HREF="./acl.html">XPA Access Control</A> for more information. + +<H2>Remote Registration</H2> + +If xpans is running on the remote client machine, then a local xpaset +command can be used with the <B>-remote</B> sub-command to +register the local XPA service in the remote name service, while at +the same time giving the remote machine permission to access the local +service. For example, assume again that "stest" is running on the +local machine and that xpans is also running on the remote machine. +To register access of this local xpa on the remote machine, use +the xpaset and the <B>-remote</B> sub-command: +<PRE> + [sh]$ ./xpaset -p xpa -remote 'remote_machine:$port' + +</PRE> +To register the local xpa access point on the remote machine with xpaget +access only, execute: +<PRE> + [sh]$ ./xpaset -p xpa -remote 'remote_machine:$port' g +</PRE> +Once the remote registration command is executed, the remote client +machine will have an entry such as the following in its own xpans name +service: +<PRE> + [csh]$ xpaget xpans + XPA xpa gs 88877766:2839 eric +</PRE> +The xpa access point can now be utilized on the remote machine without +further setup: +<PRE> + [csh]$ xpaget xpa + class: XPA + name: xpa + method: 838e2f68:2839 + sendian: little + cendian: big +</PRE> +To unregister remote access from the local machine, use the same +command but with a '-' argument: +<PRE> + [sh]$ xpaset -p xpa -remote 'remote_machine:$port' - +</PRE> +The benefit of using remote registration is that communication with +remote access points can be mixed with that of other access points +on the remote machine. Using <A HREF="./template.html">Access Point +Names and Templates</A>, one XPA command can be used to send or +receive messages to the remote and local services. + +<H2>XPANS Proxy Registration</H2> + +The two methods described above are useful when the local and remote +machines are able to communicate freely to one another. This would be +the case on most Local Area Networks (LANs) where all machines are +behind the same firewall and there is no port blocking between +machines on the same LAN. The situation is more complicated when the +XPA server is behind a firewall, where outgoing connections are +allowed, but incoming port blocking is implemented to prevent machines +outside the firewall from connecting to machines inside the +firewall. Such incoming port blocking will prevent xpaset and xpaget +from connecting to an XPA server inside a firewall. + +<P> +To allow locally fire-walled XPA services to register with remote +machines, we have implemented a proxy service within the xpans name +server. To register remote proxy service, xpaset and the +<B>-remote</B> sub-command is again used, but with an additional +<B>-proxy</B> argument added to the end of the command: +<PRE> + [sh]$ ./xpaset -p xpa -remote 'remote_machine:$port' g -proxy +</PRE> +Once a remote proxy registration command is executed, the remote +machine will have an entry such as the following in its own xpans name +service: +<PRE> + [csh]$ xpaget xpans + XPA xpa gs @88877766:2839 eric +</PRE> +The '@' sign in the name service entry indicates that xpans proxy +processing is being used for this access point. Other than that, from +the user's point of view, there is no difference in how this XPA +access point is contacted using XPA programs (xpaset, xpaget, etc.) or +libraries: +<PRE> + [csh]$ xpaget xpa + class: XPA + name: xpa + method: 88877766:3053 + sendian: little + cendian: big +</PRE> +<P> +Of course, the underlying processing of the XPA requests is very much +different when xpans proxy is involved. Instead of an XPA program such +contacting the XPA service directly, it contacts the local xpans. +Acting as a proxy server, xpans communicates with the XPA service +using the command channel established at registration time. Commands +(including establishing a new data channel) are sent between xpans and +the XPA service to set up a new message transfer, and then data is fed +to/from the xpa request, through xpans, from/to the XPA service. In +this way, it can be arranged so that connections between the +fire-walled XPA service and the remote client are always initiated by +the XPA service itself. Thus, incoming connections that would be +blocked by the firewall are avoided. Note that there is a performance +penalty for using the xpans/proxy service. Aside from extra overhead +to set up proxy communication, all data must be sent through the +intermediate proxy process. + +<P> +The xpans proxy scheme requires that the remote client allow the local +XPA server machine to connect to the remote xpans/proxy server. If the +remote client machine also is behind a port-blocking firewall, such +connections will be disallowed. In this case, the only solution is to +open up some ports on the remote client machine to allow incoming +connections to xpans/proxy. Two ports must be opened (for command and +data channel connections). By default, these two ports are 14285 and +14287. The port numbers can be changed using the <B>XPA_NSINET</B> +environment variable. This variable takes the form: +<PRE> + setenv XPA_NSINET machine:port1[,port2[,port3]] +</PRE> +where port1 is the main connecting port, port2 is the XPA access port, +and port3 is the secondary data connecting port. The second and third +ports are optional and default to port1+1 and port1+2, respectively. +It is port1 and port3 that must be left open for incoming connections. + +<P> +For example, to change the port assignments so that xpans listens +for registration commands on port 12345 and data commands on port 28573: +<PRE> + setenv XPA_NSINET myhost:12345 +</PRE> +Alternatively, all three ports can be assigned explicitly: +<PRE> + setenv XPA_NSINET remote:12345,3000,12346 +</PRE> +In this case 12345 and 12346 should be open for incoming connections. +The XPA access port (which need not be open to the outside +world) is set to 3000. + +<P> +Finally, note that we currently have no mechanism to cope with +Internet proxy servers (such as SOCKS servers). If an XPA service is +running on a machine that cannot connect directly to outside machines, +but goes through a proxy server instead, there currently is no way to +register that XPA service with a remote machine. We hope to implement +support for SOCKS proxy in a future release. + +<!-- =section xpainet SEE ALSO --> +<!-- =text See xpa(n) for a list of XPA help pages --> +<!-- =stop --> + +<P> +<A HREF="./help.html">Go to XPA Help Index</A> + +<H5>Last updated: September 10, 2003</H5> +</BODY> +</HTML> diff --git a/xpa/doc/info.html b/xpa/doc/info.html new file mode 100644 index 0000000..75837bd --- /dev/null +++ b/xpa/doc/info.html @@ -0,0 +1,193 @@ +<!-- =defdoc xpacommon xpacommon n --> +<HTML> +<HEAD> +<TITLE>Getting Common Information About Access Points</TITLE> +</HEAD> +<BODY> + +<!-- =section xpacommon NAME --> +<H2><A NAME="xpacommon">XPACommon: Getting Common Information About Access Points</A></H2> + +<!-- =section xpacommon SYNOPSIS --> +<H2>Summary</H2> +<P> +There are various kinds of generic information you can retrieve about +an XPA access point by using the xpaget command. + +<!-- =section xpacommon DESCRIPTION --> +<H2>Description</H2> +<P> +You can find out which XPA access points have been registered with +the currently running +<A HREF="./xpans.html">XPA name server</A> +by executing the +<A HREF="./programs.html#xpaget">xpaget</A> +command to retrieve info from the XPA name server: +<PRE> + xpaget xpans +</PRE> +If, for example, the +<A HREF="./examples.html">stest</A> test server program +is running, the following XPA access points will be returned (the specifics +of the returned info will vary for different machines and users): +<PRE> + XPA xpa gs 838e2f67:1262 eric + XPA xpa1 gs 838e2f67:1266 eric + XPA c_xpa gs 838e2f67:1267 eric + XPA i_xpa i 838e2f67:1268 eric +</PRE> +Note that access to this information is subject to the usual +<A HREF="./acl.html">XPA Access Control</A> restrictions. + +<P> +Each XPA access point supports a number of reserved sub-commands that provide +access to different kinds of information, e.g. the access control for +that access point. These sub-commands can be executed by using +<A HREF="./programs.html#xpaset">xpaset</A> +or +<A HREF="./programs.html#xpaget">xpaget</A> +at the command line, or +<A HREF="./client.html#xpaget">XPAGet()</A> +or +<A HREF="./client.html#xpaset">XPASet()</A> +in programs, e.g: +<PRE> + xpaget ds9 -acl + xpaget ds9 -help + xpaget ds9 env FOO + + xpaset -p ds9 env FOO foofoo +</PRE> +With the exception of <B>-help</B> and <B>-version</B>, reserved +sub-commands are available only on the machine on which the XPA server +itself is running. + +The following reserved sub-commands are defined for all access points: +<DL> + +<P> +<DT><B>-acl</B> get (set) the access control list [options: host type acl, for set] +<DD> +The 'xpaset' option allows you to add a new acl for a given host, or change +the acl for an existing host. See +<A HREF="./acl.html">XPA Access Control</A> +for more information. +This access point is available only on the server machine. + +<P> +<DT><B>-env</B> get (set) an environment variable [options: name (value, for set)] +<DD> +The 'xpaget' option will return the value of the named environment +variable. The 'xpaset' option will set the value of the names +variable to the specified value. +This access point is available only on the server machine. +(Please be advised that we have had problems setting environment +variables in static Tcl/Tk programs such as ds9 running under Linux.) + +<P> +<DT> <B>-clipboard</B> set(get) information on a named clipboard +<DD> Clients can store ASCII state information on any number of named +clipboards. Clipboards of the same name created by clients on +different machines are kept separate. The syntax for creating a +clipboard is: +<PRE> + [data] | xpaset [server] -clipboard add|append [clipboard_name] + xpaset -p [server] -clipboard delete [clipboard_name] +</PRE> +Use "add" to create a new clipboard or replace the contents of an existing +one. Use "append" to append to an existing clipboard. +<P> +Information on a named clipboard is retrieved using: +<PRE> + xpaget [server] -clipboard [clipboard_name] +</PRE> +<P> +<DT><B>-exec</B> set: execute commands from buffer [options: none] +<DD> +If -exec is specified in the paramlist of an 'xpaset' call, then further +sub-commands will be retrieved from the data buffer. + +<P> +<DT><B>-help</B> get: return help string for this XPA or sub-command [options: name (for sub-commands)] +<DD> +Each XPA access point and each XPA sub-command can have a help string +associated with it that is specified when the access point is defined. +The -help option will return this help string. For XPA access points +that contain user-defined sub-commands, you can get the help string +for a particular sub-command by specifying its name, or else get the +help strings for all sub-commands if not name is specified. + +<P> +<DT><B>-ltimeout</B> get (set) the long timeout value [options: seconds|reset] +<DD> +The 'xpaget' option will return the value of the long timeout (in seconds). +The 'xpaset' option will set the value of the long timeout. If "reset" is +specified, then the timeout value will be reset to the default value. + +<P> +<DT><B>-nsconnect</B> set: re-establish name server connection to all XPA's [options: none] +<DD> +If the +<A HREF="./xpans.html">XPA Name Server (xpans)</A> +process has terminated unexpectedly and then re-started, this +sub-command can be used to re-establish the connection. You use it by +sending the command to the [name:port] or [file] of the access point +instead of to the XPA name (since the latter requires the xpans +connection!): +<PRE> + xpaset -p 838e2f67:1268 -nsconnect +</PRE> +See <A HREF="./xpans.html">xpans</A> for more information. + +<P> +<DT><B>-nsdisconnect</B> set: break name server connection to all XPA's [options: none] +<DD> +This sub-command will terminate the connection to the +<A HREF="./xpans.html">XPA Name Server (xpans)</A>, thereby making +all access points inaccessible except through their underlying [name:port] +or [file] identifiers. I forget why we added it, it seems pretty useless. + +<P> +<DT><B>-stimeout</B> get (set) the short timeout value [options: seconds|reset] +<DD> +The 'xpaget' option will return the value of the short timeout (in seconds). +The 'xpaset' option will set the value of the short timeout. If "reset" is +specified, then the timeout value will be reset to the default value. + +<P> +<DT><B>-remote</B> set: register xpa with remote server [options: host[:port] [acl]] [-proxy] +<DD> +This sub-command will register the XPA access point with the XPA name +server (xpans) on the specified host (which must already be running). +The specified host also is given access control to the access point, +using the specified acl or the default acl of "+" (meaning the remote +host can xpaset, xpaget, xpainfo or xpaaccess). If the acl is +specified as "-", then the access point is unregistered. +See <A HREF="./inet.html">Communication Between Machines</A> +for more information on how this sub-command is used. + +<P> +<DT><B>-version</B> get: return XPA version string [options: none] +<DD> +The version refers to the version of XPA used to define this access point +(currently something like 2.0). + +</DL> + +<P> +You can add your own reserved commands to all XPA access points by using the +<A HREF="./server.html#xpacmdadd">XPACmdAdd()</A> +routine, passing the XPA handle returned by <EM>XPA XPAGetReserved(void)</EM> +as the first argument. Note again that these will only be available on the +machine where the XPA service is running. + +<!-- =section xpacommon SEE ALSO --> +<!-- =text See xpa(n) for a list of XPA help pages --> +<!-- =stop --> + +<P> +<A HREF="./help.html">Go to XPA Help Index</A> + +<H5>Last updated: September 10, 2003</H5> +</BODY> +</HTML> diff --git a/xpa/doc/intro.html b/xpa/doc/intro.html new file mode 100644 index 0000000..f9c9947 --- /dev/null +++ b/xpa/doc/intro.html @@ -0,0 +1,148 @@ +<!-- =defdoc xpaintro xpaintro n --> +<HTML> +<HEAD> +<TITLE>Introduction to XPA</TITLE> +</HEAD> +<BODY> + +<!-- =section xpaintro NAME --> +<H2><A NAME="xpaintro">XPAIntro: Introduction to the XPA Messaging System</A></H2> + +<!-- =section xpaintro SYNOPSIS --> +<H2>Summary</H2> +<P> +A brief introduction to the XPA messaging system, which provides +seamless communication between all kinds of Unix event-driven +programs, including X programs, Tcl/Tk programs, and Perl programs. + +<!-- =section xpaintro DESCRIPTION --> +<H2>Description</H2> +<P> +The XPA messaging system provides seamless communication between all +kinds of Unix programs, including X programs, Tcl/Tk programs, and +Perl programs. It also provides an easy way for users to communicate +with these XPA-enabled programs by executing XPA client commands in +the shell or by utilizing such commands in scripts. Because XPA works +both at the programming level and the shell level, it is a powerful +tool for unifying any analysis environment: users and programmers have +great flexibility in choosing the best level or levels at which to +access XPA services, and client access can be extended or modified +easily at any time. + +<P> +A program becomes an XPA-enabled server by defining named points of +public access through which data and commands can be exchanged with +other client programs (and users). Using standard TCP sockets as +a transport mechanism, XPA supports both single-point and broadcast +messaging to and from these servers. It supports direct communication +between clients and servers, or indirect communication via an +intermediate message bus emulation program. Host-based access control +is implemented, as is as the ability to communicate with XPA servers +across a network. + +<P> +XPA implements a layered interface that is designed to be useful both +to software developers and to users. The interface consists of a +library of XPA client and server routines for use in programs and a +suite of high-level user programs built on top of these libraries. +Using the XPA library, access points can be added to +<A HREF="./tcl.html#">Tcl/Tk</A> +programs, +<A HREF="./xt.html#">Xt</A> +programs, or to Unix programs that use the XPA event loop or any +event loop based on select(). Client access subroutines can be added +to any Tcl/Tk or Unix program. Client access also is supported at the +command line via a suite of high-level programs. + +<P> +The major components of the XPA layered interface are: +<UL> +<LI> +A set of XPA server routines, centered on +<A HREF="./server.html#xpanew">XPANew(),</A> +which are used by XPA server programs to tag public access points with +string identifiers and to register send and receive callbacks for +these access points. + +<LI> +A set of XPA client routines, centered on the +<A HREF="./client.html#xpaset">XPASet()</A> +and +<A HREF="./client.html#xpaget">XPAGet(),</A> +which are used by external client applications to exchange data and +commands with an XPA server. + +<LI> +High-level programs, centered on +<A HREF="./programs.html#xpaset">xpaset</A> +and +<A HREF="./programs.html#xpaget">xpaget,</A> +which allow data +and information to be exchanged with XPA server programs from the +command line and from scripts. These programs have the command syntax: +<PRE> + [data] | xpaset <XPA name> [qualifiers ...] + xpaget <XPA name> [qualifiers ...] +</PRE> +<LI> +An XPA name server program, +<A HREF="./xpans.html">xpans,</A> +through which XPA access point names are +registered by servers and distributed to clients. +</UL> + +<P> +Defining an XPA access point is easy: a server application calls +<A HREF="./server.html#xpanew">XPANew(),</A> +<A HREF="./server.html#xpacmdnew">XPACmdNew(),</A> +or the experimental +<A HREF="./server.html#xpainfonew">XPAInfoNew()</A> +routine to +create a named public access point. An XPA service can specify "send" +and "receive" callback procedures (or an "info" procedure in the case +of XPAInfoNew()) to be executed by the program when an external +process either sends data or commands to this access point or requests +data or information from this access point. Either of the callbacks +can be omitted, so that a particular access point can be specified as +read-only, read-write, or write-only. Application-specific client +data can be associated with these callbacks. Having defined one or +more public access points in this way, an XPA server program enters +its usual event loop (or uses the standard XPA event loop). + +<P> +Clients communicate with these XPA public access points +using programs such as +<A HREF="./programs.html#xpaget">xpaget</A>, +<A HREF="./programs.html#xpaset">xpaset</A>, and +<A HREF="./programs.html#xpainfo">xpainfo</A> +(at the command line), +or routines such as +<A HREF="./client.html#xpaget">XPAGet(),</A> +<A HREF="./client.html#xpaset">XPASet(),</A> +and +<A HREF="./client.html#xpainfo">XPAInfo()</A> +within a program. Both methods require specification of the name of +the access point. The xpaget program returns data or other +information from an XPA server to its standard output, while the +xpaset program sends data or commands from its standard input to an +XPA application. The corresponding API routines set/get data to/from +memory, returning error messages and other info as needed. If a +<A HREF="./template.html">template</A> +is used to specify the access point name (e.g., "ds9*"), then +communication will take place with all servers matching that template. + +<p> +Please note that XPA currently is not thread-safe. All XPA calls must be +in the same thread. + +<!-- =section xpaintro SEE ALSO --> +<!-- =text See xpa(n) for a list of XPA help pages --> +<!-- =stop --> + +<P> +<A HREF="./help.html">Go to XPA Help Index</A> + +<H5>Last updated: March 10, 2007</H5> +</BODY> +</HTML> + diff --git a/xpa/doc/method.html b/xpa/doc/method.html new file mode 100644 index 0000000..d85fc89 --- /dev/null +++ b/xpa/doc/method.html @@ -0,0 +1,90 @@ +<!-- =defdoc xpamethod xpamethod n --> +<HTML> +<HEAD> +<TITLE>XPA Communication Methods</TITLE> +</HEAD> +<BODY> + +<!-- =section xpamethod NAME --> +<H2><A NAME="xpamethod">XPAMethod: </A>XPA Communication Methods</H2> + +<!-- =section xpamethod SYNOPSIS --> +<H2>Summary</H2> +<P> +XPA supports both inet and unix (local) socket communication. + +<!-- =section xpamethod DESCRIPTION --> +<H2>Description</H2> +<P> +XPA uses sockets for communication between processes. It supports +three methods of socket communication: inet, localhost, and unix. In +general, the same method should be employed for all XPA processes in a +session and the global environment variable XPA_METHOD should be used +to set up the desired method. By default, the preferred method is +"inet", which is appropriate for most users. You can set up a +different method by typing something like: +<PRE> + setenv XPA_METHOD local # unix csh + XPA_METHOD=local; export XPA_METHOD # unix sh, bash, windows/cygwin + set XPA_METHOD=localhost # dos/windows +</PRE> +The options for XPA_METHOD are: <B>inet</B>, <B>unix</B> (or +<B>local</B>), and <B>localhost</B>. On Unix machines, this +environment setup command can be placed in your shell init file +(.cshrc, .profile, .bashrc, etc.) On Windows platforms, it can be +placed in your AUTOEXEC.BAT file (I think!). + +<P> +By default, <B>inet</B> sockets are used by XPA. These are the standard +Internet sockets that are used by programs such as Netscape, +ftp. etc. Inet sockets utilize the IP address of the given machine and +a (usually random) port number to communicate between processes on the +same machine or between different machines on the Internet. (Note that +XPA has an <A HREF="./acl.html">Access Control</A> mechanism to +prevent unauthorized access of XPA access points by other computers on +the Net). For users connected to the Internet, this usually is the +appropriate communication method. For more information about setting +up XPA communication between machines, see +<A HREF="./inet.html">Communication Between Machines</A>. + +<P> +In you are using XPA on a machine without an Internet connection, then +inet sockets are not appropriate. In fact, an XPA process often will +hang for many seconds while waiting for a response from the Domain +Name Service (DNS) when using inet sockets. Instead of inet sockets, +users on Unix platforms can also use <B>unix</B> sockets (also known +as local sockets). These sockets are based on the local file system +and do not make use of the DNS. They generally are considered to be +faster than inet sockets, but they are not implemented under +Windows. Use local sockets as a first resort if you are on a Unix +machine that is not connected to the Internet. + +<P> +Users not connected to the Internet also can use <B>localhost</B> +sockets. These are also inet-type sockets but the IP address used for +the local machine is the <B>localhost</B> address, 0x7F000001, instead +of the real IP of the machine. Depending on how sockets are set up for +a given platform, communication with the DNS usually is not required in +this case (though of course, XPA cannot interact with other machines). +The localhost method will generally work on both Unix and Windows +platforms, but whether the DNS is required or not is subject to +individual configurations. + +<P> +A final warning/reminder: if your XPA-enabled server hangs at startup +time and your XPA_METHOD is <B>inet</B>, the problem probably is +related to an incorrect Internet configuration. This can be confirmed +by using the <B>unix</B> method or (usually) the <B>localhost</B> +method. You can use these alternate methods if other hosts do not need +access to the XPA server. + +<!-- =section xpamethod SEE ALSO --> +<!-- =text See xpa(n) for a list of XPA help pages --> +<!-- =stop --> + +<P> +<A HREF="./help.html">Go to XPA Help Index</A> + +<H5>Last updated: September 10, 2003</H5> +</BODY> +</HTML> diff --git a/xpa/doc/name.html b/xpa/doc/name.html new file mode 100644 index 0000000..5269378 --- /dev/null +++ b/xpa/doc/name.html @@ -0,0 +1,48 @@ +<!-- =defdoc xpaname xpaname n --> +<HTML> +<HEAD> +<TITLE>What does XPA stand for?</TITLE> +</HEAD> +<BODY> + +<!-- =section xpaname NAME --> +<H2><A NAME="xpaname">XPAName: What does XPA stand for?</A></H2> + +<!-- =section xpaname SYNOPSIS --> +<H2>Summary</H2> +<P> +What does XPA stand for? Who knows anymore! + +<!-- =section xpaname DESCRIPTION --> +<H2>Description</H2> +<P> +What does XPA stand for? Dunno! The XPA messaging system originally +was built on top of the X Window System and XPA was the mnemonic for +<EM>X Public Access</EM>, to emphasize that we were providing public +access to previously private data and algorithms in Xt programs. Now +that XPA no longer is tied to X, it can be argued that we ought to +change the name (how about <EM>SPAM: simple public access mechanism +</EM>), but XPA is in wide-spread use in the astronomical community of +its birth, and the name has taken on a life of its own. If anyone can +think of what XPA now means, please let us know. + +<P> +If you think this is bad, consider the MMT Telescope on Mount Hopkins, +Arizona. When first installed twenty years ago, it featured an array +of six 72-inch diameter mirrors. from which came its name: the +<EM>Multiple Mirror Telescope</EM>. In spring of 1999, these mirrors +were replaced by a single 21 and 1/2 -foot diameter primary mirror, +the largest single-piece glass reflector on the North American +continent. And now MMT stands for ... MMT! + +<!-- =section xpaname SEE ALSO --> +<!-- =text See xpa(n) for a list of XPA help pages --> +<!-- =stop --> + +<P> +<A HREF="./help.html">Go to XPA Help Index</A> + +<H5>Last updated: September 10, 2003</H5> +</BODY> +</HTML> + diff --git a/xpa/doc/oom.html b/xpa/doc/oom.html new file mode 100644 index 0000000..360740e --- /dev/null +++ b/xpa/doc/oom.html @@ -0,0 +1,52 @@ +<!-- =defdoc xpaoom xpaoom n --> +<HTML> +<HEAD> +<TITLE>Out of Memory</TITLE> +</HEAD> +<BODY> + +<!-- =section xpaoom NAME --> +<H2><A NAME="xpaoom">Xpaoom: What happens when XPA runs out of memory?</A></H2> + +<!-- =section xpaoom SYNOPSIS --> +<H2>Summary</H2> +<P> +When XPA can't allocate memory, it exits. You can arrange to have it call +longjmp() instead. + +<!-- =section xpaoom DESCRIPTION --> +<H2>Description</H2> +<P> +When an XPA server or client cannot allocate memory, it will attempt to +output an error message and then exit. If this is not satisfactory (e.g., +perhaps your program is interactive and can recover from OOM errors), you +can tell XPA to call longjmp() to go to a recovery branch. To pass the +requisite jmp_buf variable to XPA, make the following call: +<PRE> + XPASaveJmp(void *env); +</PRE> +The value of env is the address of a jmp_buf variable that was previously +passed to setjmp(). For example: +<PRE> + jmp_buf env; + ... + if( setjmp(jmp_buf) != 0 ){ + /* out of memory -- take corrective action, if possible */ + } else { + /* save env for XPA */ + XPASaveJmp((void *)&jmp_buf); + } + // enter main loop ... +</PRE> + +<!-- =section xpaoom SEE ALSO --> +<!-- =text See xpa(n) for a list of XPA help pages --> +<!-- =stop --> + +<P> +<A HREF="./help.html">Go to XPA Help Index</A> + +<H5>Last updated: April 7, 2009</H5> +</BODY> +</HTML> + diff --git a/xpa/doc/pod/xpa.pod b/xpa/doc/pod/xpa.pod new file mode 100644 index 0000000..7787d4b --- /dev/null +++ b/xpa/doc/pod/xpa.pod @@ -0,0 +1,399 @@ +=pod + +=head1 NAME + + + +B<XPA: Public Access to Data and Algorithms> + + + +=head1 SYNOPSIS + + + + +This document is the Table of Contents for XPA. + + + +=head1 DESCRIPTION + + + + + +The XPA messaging system provides seamless communication between many +kinds of Unix programs, including X programs and Tcl/Tk programs. It +also provides an easy way for users to communicate with XPA-enabled +programs by executing XPA client commands in the shell or by utilizing +such commands in scripts. Because XPA works both at the programming +level and the shell level, it is a powerful tool for unifying any +analysis environment: users and programmers have great flexibility in +choosing the best level or levels at which to access XPA services, and +client access can be extended or modified easily at any time. + + +A program becomes an XPA-enabled server by defining named points of +public access through which data and commands can be exchanged with +other client programs (and users). Using standard TCP sockets as a +transport mechanism, XPA supports both single-point and broadcast +messaging to and from these servers. It supports direct communication +between clients and servers, or indirect communication via an +intermediate message bus emulation program. Host-based access control +is implemented, as is as the ability to communicate with XPA servers +across a network. + + +XPA implements a layered interface that is designed to be useful both +to software developers and to users. The interface consists of a +library of XPA client and server routines for use in C/C++ programs and +a suite of high-level user programs built on top of these libraries. +Using the XPA library, access points can be added to Tcl/Tk programs, +Xt programs, or to Unix programs that use the XPA event loop or any +event loop based on select(). Client access subroutines can be added +to any Tcl/Tk, Xt, or Unix program. Client access also is supported at +the command line via a suite of high-level programs. + + +Choose from the following topics: + + + +=over 4 + + + + +=item * + +Introduction to XPA +[xpaintro(n)] + + +=item * + +Access Point Names and Templates +[xpatemplate(n)] + + +=item * + +Getting Common Information About Access Points +[xpacommon(n)] + + +=item * + +Communication Methods +[xpamethod(n)] + + +=item * + +Communication Between Hosts +[xpainet(n)] + + +=item * + +Distinguishing Users +[xpausers(n)] + + + +=item * + +XPA User Programs + + +=over 4 + + + + +=item * + +xpaget: get data and info +[xpaget(1)] + + +=item * + +xpaset: send data and info +[xpaset(1)] + + +=item * + +xpainfo: send info alert +[xpainfo(1)] + + +=item * + +xpaaccess: get access point info +[xpaaccess(1)] + + +=item * + +xpamb: message bus emulation +[xpamb(1)] + + +=item * + +xpans: the XPA name server +[xpans(1)] + + +=back + + + + + +=item * + +XPA Server Routines + + +=over 4 + + + + +=item * + +XPANew: define a new access point +[xpanew(3)] + + +=item * + +XPACmdNew: define a new command access point +[xpacmdnew(3)] + + +=item * + +XPACmdAdd: add a command +[xpacmdadd(3)] + + +=item * + +XPACmdDel: delete a command +[xpacmddel(3)] + + +=item * + +XPAInfoNew: define an info access point +[xpainfonew(3)] + + +=item * + +XPAFree: free an access point +[xpafree(3)] + + +=item * + +XPAMainLoop: event loop for select server +[xpamainloop(3)] + + +=item * + +XPAPoll: poll for XPA events +[xpapoll(3)] + + +=item * + +XPACleanup: release reserved XPA memory +[xpacleanup(3)] + + +=item * + +XPA Server Macros: accessing structure internals +[xpamacros(3)] + + +=item * + +XPA Race Conditions: how to avoid them +[xparace(3)] + + +=item * + +XPA Out of Memory (OOM) errors +[xpaoom(3)] + + +=back + + + + + +=item * + +XPA Client Routines + + +=over 4 + + + + +=item * + +XPAOpen: open a persistent client connection +[xpaopen(3)] + + +=item * + +XPAClose: close persistent client connection +[xpaclose(3)] + + +=item * + +XPAGet: get data +[xpaget(3)] + + +=item * + +XPASet: send data or commands +[xpaset(3)] + + +=item * + +XPAInfo: send an info alert +[xpainfo(3)] + + +=item * + +XPAGetFd: get data and write to an fd +[xpagetfd(3)] + + +=item * + +XPASetFd: read data from and fd and send +[xpasetfd(3)] + + +=item * + +XPANSLookup: look up an access point +[xpanslookup(3)] + + +=item * + +XPAAccess: get access info +[xpaaccess(3)] + + +=item * + +The XPA/Xt Interface: Xt interface to XPA +[xpaxt(n)] + + +=item * + +The XPA/Tcl Interface: Tcl interface to XPA +[xpatcl(n)] + + +=back + + + + + +=item * + +Tailoring the XPA Environment + + +=over 4 + + + + +=item * + +Environment Variables +[xpaenv(n)] + + +=item * + +Access Control +[xpaacl(n)] + + +=back + + + + + +=item * + +Miscellaneous + + +=over 4 + + + + + +=item * + +Where to Find Example/Test Code + + +=item * + +User Changes Between XPA 1.0 and 2.0 + + +=item * + +API Changes Between XPA 1.0 and 2.0 + + +=item * + +What Does XPA Stand For, Anyway? + + +=back + + + + + +=back + + + + + + +=cut diff --git a/xpa/doc/pod/xpaaccess.pod b/xpa/doc/pod/xpaaccess.pod new file mode 100644 index 0000000..ab34b9b --- /dev/null +++ b/xpa/doc/pod/xpaaccess.pod @@ -0,0 +1,102 @@ +=pod + +=head1 NAME + + + +B<xpaaccess: see if template matches registered XPA access points> + + + +=head1 SYNOPSIS + + + + + +xpaaccess [-c] [-h] [-i nsinet] [-m method] [-n] [-t sval,lval] [-u users] -v <template> [type] + + + + + +=head1 OPTIONS + + + + + + -c contact each access point individually + -h print help message + -i access XPA point on different machine (override XPA_NSINET) + -m override XPA_METHOD environment variable + -n return number of matches instead of "yes" or "no" + -t [s,l] set short and long timeouts (override XPA_[SHORT,LONG]_TIMEOUT) + -u [users] XPA points can be from specified users (override XPA_NSUSERS) + -v print info about each successful access point + -V print info or error about each access point + --version display version and exit + + + + +=head1 DESCRIPTION + + + + +xpaaccess returns "yes" to stdout (with a return error code if 1) if there are +existing XPA access points that match the +template +(and optional access type: g,i,s). Otherwise, it returns "no" (with a +return error code of 0). If -n is specified, the number of matches is +returned instead (both to stdout and in the returned error code). If +-v is specified, each access point is displayed to stdout instead of +the number of matches. + + +By default, xpaaccess simply contacts the xpans name server to find +the list of registered access points that match the specified +template. It also checks to make sure the specified types are +supported by that access point. This is the fastest way to determine +available access points. However, an access point might registered but +not yet available, if, for example, the server program has not entered +its event loop to process XPA requests. To find access points that are +guaranteed to be available for processing, use the -c (contact) +switch. With this switch, xpaaccess contacts each matching XPA server +(rather than the name server) to make sure the registered access point +really is ready for processing. In this mode, if an access point is +registered but not available, xpaaccess will pause for a period of +time equal to the XPA_LONG_TIMEOUT, in order to give the server a +chance to ready itself. By default, this timeout is 30 seconds. You +can shorten the time of delay using the -t "short,long" switch. For +example, to shorten the delay time to 2 seconds, use: + + xpaaccess -c -t "2,2" ds9 + +The first argument is the short delay value, and is ignored in this +operation. The second is the long delay timeout. + + +Note also that the default xpaaccess method (no -c switch) does not +check access control (acls) but rather only checks whether the access +point is both registered with the xpans name server and provides the +specified type of access. In other words, the default xpaaccess could +return 'yes' when you might not actually have access. This mode also +always returns 'yes' for the xpans name server itself, regardless of +whether the name server is active. The -c (contact) switch, which +contacts the access point directly, can and does check the access +control (only for servers using version 2.1 and above) and also +returns the real status of xpans. + + + +=head1 SEE ALSO + + + +See xpa(n) for a list of XPA help pages + + + +=cut diff --git a/xpa/doc/pod/xpaacl.pod b/xpa/doc/pod/xpaacl.pod new file mode 100644 index 0000000..3be9d4c --- /dev/null +++ b/xpa/doc/pod/xpaacl.pod @@ -0,0 +1,145 @@ +=pod + +=head1 NAME + + + +B<XPAAcl: Access Control for XPA Messaging> + + + +=head1 SYNOPSIS + + + + + +XPA supports host-based access control for each XPA access point. You +can enable/disable access control using the XPA_ACL environment +variable. You can specify access to specific XPA access points for +specific machines using the XPA_DEFACL and XPA_ACLFILE environment +variables. By default, an XPA access point is accessible only to +processes running on the same machine (same as X Windows). + + + +=head1 DESCRIPTION + + + + + +When INET sockets are in use (the default, as specified by the +I<XPA_METHOD> environment variable), XPA supports a host-based +access control mechanism for individual access points. This mean that +access can be specified for get, set, or info operations for each +access point on a machine by machine basis. For LOCAL sockets, access +is restricted (by definition) to the host machine. + + +XPA access control is enabled by default, but can be turned off by +setting the I<XPA_ACL> environment variable to I<false>. +In this case, any process can access any XPA server. + + +Assuming that access control is turned on, the ACL for an individual +XPA access point is set up when that access point is registered +(although it can be changed later on; see below). This can be done in +one of two ways: + +Firstly, the I<XPA_ACLFILE> environment variable can defined to +point to a file of access controls for individual access points. The format +of this file is: + + class:name ip acl + +The first argument is a template that specifies the class:name of the +access point covered by this ACL. See +XPA Access Points and Templates +for more information about xpa templates. + + +The second argument is the IP address (in human-readable format) of +the machine which is being given access. This argument can be +I<*> to match all IP addresses. It also can be I<$host> +to match the IP address of the current host. + + +The third argument is a string combination of I<s>, I<g>, +or I<i> to allow I<xpaset>, I<xpaget>, or +I<xpainfo> access respectively. The ACL argument can be +I<+> to give I<sgi> access or it can be I<-> to turn +off all access. + + +For example, + + *:xpa1 somehost sg + *:xpa1 myhost + + * * g + +will allow processes on the machine somehost to make xpaget and xpaset calls, +allow processes on myhost to make any call, and allow all other hosts to +make xpaget (but not xpaset) calls. + +Secondly, if the I<XPA_ACLFILE> does not exist, then a single +default value for all access points can be specified using the +I<XPA_DEFACL> environment variable. The default value for this +variable is: + + #define XPA_DEFACL "*:* $host +" + +meaning that all access points are fully accessible to all processes +on the current host. Thus, in the absence of any ACL environment variables, +processes on the current host have full access to all access points +created on that host. This parallels the X11 xhost mechanism. + + +Access to an individual XPA access point can be changed using the -acl +parameter for that access point. For example: + + xpaset -p xpa1 -acl "somehost -" + +will turn off all access control for somehost to the xpa1 access point, while: + + xpaset -p XPA:xpa1 -acl "beberly gs" + +will give beberly xpaget and xpaset access to the access point whose +class is XPA and whose name is xpa1. + +Similarly, the current ACL for a given access point can be retrieved using: + + xpaget xpa1 -acl + +Of course, you must have xpaget access to this XPA access point to +retrieve its ACL. + + +Note that the XPA access points registered in the I<xpans> +program also behave according to the ACL rules. That is, you cannot +use xpaget to view the access points registered with xpans unless +you have the proper ACL. + + +Note also when a client request is made to an XPA server, the access +control is checked when the initial connection is established. This +access in effect at this time remains in effect so long as the client +connection is maintained, regardless of whether the access fro that +XPA is changed later on. + + +We recognize that host-based access control is only relatively secure +and will consider more stringent security (e.g., private key) in the +future if the community requires such support. + + + +=head1 SEE ALSO + + + +See xpa(n) for a list of XPA help pages + + + +=cut diff --git a/xpa/doc/pod/xpaatexit.pod b/xpa/doc/pod/xpaatexit.pod new file mode 100644 index 0000000..4310835 --- /dev/null +++ b/xpa/doc/pod/xpaatexit.pod @@ -0,0 +1,41 @@ +=pod + +=head1 NAME + + + +B<XPAAtExit: install exit handler> + + + +=head1 SYNOPSIS + + + + + + #include <xpa.h> + + void XPAAtExit(void); + + + + + +=head1 DESCRIPTION + + + + +XPAAtExit() will install an exit handler using atexit() to run XPAFree on all +XPA access points. This might be useful in cases where Unix sockets are being +used: if an explicit call to XPAFree() is not made by the program, the Unix +socket file will not be deleted immediately without an atexit handler. (NB: this +call should not be made in a Tcl/Tk application. Accessing the Tcl native file +system after Tcl has shut down all file systems causes the Tcl/Tl program to +crash). + + + + +=cut diff --git a/xpa/doc/pod/xpachanges.pod b/xpa/doc/pod/xpachanges.pod new file mode 100644 index 0000000..bce7be0 --- /dev/null +++ b/xpa/doc/pod/xpachanges.pod @@ -0,0 +1,102 @@ +=pod + +=head1 NAME + + + +B<XPA Changes: Changes For Users from XPA 1.0 and 2.0> + + + +=head1 SYNOPSIS + + + + + +This document describes changes that will affect users who migrate +from XPA 1.0 to XPA 2.0. + + + +=head1 DESCRIPTION + + + + + +There have been a few changes that affect users who upgrade XPA +from version 1.0 to version 2.0. These changes are detailed below. + + +=over 4 + + + + + +=item * + +XPA commands no longer have a resolver routine (this is open to +negotiations, but we decided the idea was dumb). For the SAOtng +program, this means that you must explicitly specify the access +point, i.e.,: + + cat foo.fits | xpaset SAOtng fits + + + +instead of: + + cat foo.fits | xpaset SAOtng + + + + +=item * + +By default, xpaset, xpaget, etc. now wait for the server callback to +complete; i.e., the old -W is implied (and the switch is ignored). +This allows support for better error handling. If you want xpaset, etc. +to return before the callback is complete, use -n switch: + + echo "file foo.fits" | xpaset -n SAOtng + + + + +=item * + +The old -w switch in xpaset and xpaget is no longer necessary (and is +ignored), since you can have more than one process communicating with +an xpa access point at one time. + + + + +=item * + +The new -p switch on xpaset means you need not read from stdout: + + xpaset -p SAOtng colormap I8 + + +will send the paramlist to the SAOtng callback without reading from stdin. + + + +=back + + + + + +=head1 SEE ALSO + + + +See xpa(n) for a list of XPA help pages + + + +=cut diff --git a/xpa/doc/pod/xpacleanup.pod b/xpa/doc/pod/xpacleanup.pod new file mode 100644 index 0000000..2d55e5a --- /dev/null +++ b/xpa/doc/pod/xpacleanup.pod @@ -0,0 +1,47 @@ +=pod + +=head1 NAME + + + +B<XPACleanup: release reserved XPA memory> + + + +=head1 SYNOPSIS + + + + + + #include <xpa.h> + + void XPACleanup(void); + + + + + +=head1 DESCRIPTION + + + + +When XPA is initialized, it allocates a small amount of memory for the +access control list, temp directory path, and reserved commands. This +memory is found by valgrind to be "still reachable", meaning that "your +program didn't free some memory it could have". Calling the +XPACleanup() routine before exiting the program will free this memory +and make valgrind happy. + + + + +=head1 SEE ALSO + + + +See xpa(n) for a list of XPA help pages + + +=cut diff --git a/xpa/doc/pod/xpaclient.pod b/xpa/doc/pod/xpaclient.pod new file mode 100644 index 0000000..858a8a8 --- /dev/null +++ b/xpa/doc/pod/xpaclient.pod @@ -0,0 +1,95 @@ +=pod + +=head1 NAME + + + +B<XPAClient: The XPA Client-side Programming Interface> + + + +=head1 SYNOPSIS + + + + +A description of the XPA client-side programming interface. + + + +=head1 DESCRIPTION + + + +B<Introduction to XPA Client Programming> + +Sending/receiving data to/from an XPA access point is easy: you +generally only need to call the XPAGet() or XPASet() subroutines. + + #include <xpa.h> + + int XPAGet(XPA xpa, + char *template, char *paramlist, char *mode, + char **bufs, size_t *lens, char **names, char **messages, int n); + + int XPASet(XPA xpa, + char *template, char *paramlist, char *mode, + char *buf, size_t len, char **names, char **messages, int n); + + int XPAInfo(XPA xpa, + char *template, char *paramlist, char *mode, + char **names, char **messages, int n); + + int XPAAccess(XPA xpa, + char *template, char *paramlist, char *mode, + char **names, char **messages, int n); + + int XPAGetFd(XPA xpa, + char *template, char *paramlist, char *mode, + int *fds, char **names, char **messages, int n); + + int XPASetFd(XPA xpa, + char *template, char *paramlist, char *mode, + int fd, char **names, char **messages, int n); + + XPA XPAOpen(char *mode); + + void XPAClose(XPA xpa); + + int XPANSLookup(XPA xpa, + char *template, char *type, + char ***classes, char ***names, char ***methods, char ***infos); + + +B<Introduction> + +To use the XPA application programming interface, a software developer +generally will include the xpa.h definitions file: + + #include <xpa.h> + +in the software module that defines or accesses an XPA access point and +then will link against the libxpa.a library: + + gcc -o foo foo.c libxpa.a + +XPA has been compiled using both C and C++ compilers. + +Client communication with XPA public access points generally is +accomplished using XPAGet() or XPASet() within a program (or xpaget +and xpaset at the command line). Both routines require specification +of the name of the access point. If a template +is used to specify the access point name (e.g., "ds9*"), then +communication will take place with all servers matching that template. + + + + +=head1 SEE ALSO + + + +See xpa(n) for a list of XPA help pages + + +=cut diff --git a/xpa/doc/pod/xpaclose.pod b/xpa/doc/pod/xpaclose.pod new file mode 100644 index 0000000..7148752 --- /dev/null +++ b/xpa/doc/pod/xpaclose.pod @@ -0,0 +1,53 @@ +=pod + +=head1 NAME + + + +B<XPAClose: close a persistent XPA client handle> + + + +=head1 SYNOPSIS + + + + + + #include <xpa.h> + + void XPAClose(XPA xpa); + + + + + +=head1 DESCRIPTION + + + + +XPAClose closes the persistent connections associated with this XPA struct +and frees all allocated space. It also closes the open sockets connections +to all XPA servers that were opened using this handle. + + +B<Example:> + + #include <xpa.h> + + XPA xpa; + XPAClose(xpa); + + + + + +=head1 SEE ALSO + + + +See xpa(n) for a list of XPA help pages + + +=cut diff --git a/xpa/doc/pod/xpacmdadd.pod b/xpa/doc/pod/xpacmdadd.pod new file mode 100644 index 0000000..31859e5 --- /dev/null +++ b/xpa/doc/pod/xpacmdadd.pod @@ -0,0 +1,69 @@ +=pod + +=head1 NAME + + + +B<XPACmdAdd: add a command to an XPA command public access point> + + + +=head1 SYNOPSIS + + + + + + #include <xpa.h> + + XPACmd XPACmdAdd(XPA xpa, char *name, char *help, + int (*send_callback)(), + void *send_data, char *send_mode, + int (*rec_callback)(), + void *rec_data, char *rec_mode); + + + + + +=head1 DESCRIPTION + + + + +Add a command to an XPA command access point. The XPA argument specifies the +XPA struct returned by a call to XPANewCmd(). The name argument is the +name of the command. The other arguments function identically to the +arguments in the XPANew() command, i.e., the send_callback and rec_callback +routines have identical calling sequences to their XPANew() counterparts, +with the exceptions noted below. + + +When help is requested for a command access point using: + + xpaget -h class:name + + +all of the command help strings are listed. To get help for a given +command, use: + + xpaget -h class:name cmd + + +Also, the acl keyword in the send_mode and receive_mode strings is +global to the access point, not local to the command. Thus, the value +for the acl mode should be the same in all send_mode (or receive_mode) +strings for each command in a command access point. (The acl for +send_mode need not be the same as the acl for receive_mode, though). + + + + +=head1 SEE ALSO + + + +See xpa(n) for a list of XPA help pages + + +=cut diff --git a/xpa/doc/pod/xpacmddel.pod b/xpa/doc/pod/xpacmddel.pod new file mode 100644 index 0000000..95c545d --- /dev/null +++ b/xpa/doc/pod/xpacmddel.pod @@ -0,0 +1,43 @@ +=pod + +=head1 NAME + + + +B<XPACmdDel: remove a command from an XPA command public access point> + + + +=head1 SYNOPSIS + + + + + + #include <xpa.h> + + void XPACmdDel(XPA xpa, XPACmd cmd); + + + + + +=head1 DESCRIPTION + + + + +This routine removes a command from the list of available commands in +a given XPA. That command will no longer be available for processing. + + + + +=head1 SEE ALSO + + + +See xpa(n) for a list of XPA help pages + + +=cut diff --git a/xpa/doc/pod/xpacmdnew.pod b/xpa/doc/pod/xpacmdnew.pod new file mode 100644 index 0000000..429972b --- /dev/null +++ b/xpa/doc/pod/xpacmdnew.pod @@ -0,0 +1,90 @@ +=pod + +=head1 NAME + + + +B<XPACmdNew: create a new XPA public access point for commands> + + + +=head1 SYNOPSIS + + + + + + #include <xpa.h> + + XPA XPACmdNew(char *class, char *name); + + + + + +=head1 DESCRIPTION + + + + +Create a new XPA public access point for commands that will share a +common identifier class:name. Enter this access point into the XPA +name server, so that it can be accessed by external processes. +XPACmdNew() returns an XPA struct. + + +It often is more convenient to have one public access point that can +manage a number of commands, rather than having individual access +points for each command. For example, it is easier to command the +ds9 image display using: + + echo "colormap I8" | xpaset ds9 + echo "scale log" | xpaset ds9 + echo "file foo.fits" | xpaset ds9 + + +then to use: + + echo "I8" | xpaset ds9_colormap + echo "log" | xpaset ds9_scale + echo "foo.fits" | xpaset ds9_file + + +In the first case, the commands remain the same regardless of the +target XPA name. In the second case, the command names must change +for each instance of ds9. That is, if a second instance of ds9 +called DS9 were running, it would be commanded either as: + + echo "colormap I8" | xpaset DS9 + echo "scale log" | xpaset DS9 + echo "file foo.fits" | xpaset DS9 + + +or as: + + echo "I8" | xpaset DS9_colormap + echo "log" | xpaset DS9_scale + echo "foo.fits" | xpaset DS9_file + + +Thus, in cases where a program is going to manage many commands, it +generally is easier to define them as commands associated with the +XPACmdNew() routine, rather than as separate access points using +XPANew(). + + +When XPACmdNew() is called, only the class:name identifier is +specified. Each sub-command is subsequently defined using the +XPACmdAdd() routine. + + + + +=head1 SEE ALSO + + + +See xpa(n) for a list of XPA help pages + + +=cut diff --git a/xpa/doc/pod/xpacode.pod b/xpa/doc/pod/xpacode.pod new file mode 100644 index 0000000..c5ea647 --- /dev/null +++ b/xpa/doc/pod/xpacode.pod @@ -0,0 +1,73 @@ +=pod + +=head1 NAME + + + +B<XPACode: Where to Find Example/Test Code> + + + +=head1 SYNOPSIS + + + + + +The XPA source code directory contains two test programs, +I<stest.c>, and I<ctest.c> that can serve as +examples for writing XPA servers and clients, respectively. +They also can be used to test various features of XPA. + + + +=head1 DESCRIPTION + + + + + +To build the XPA test programs, execute: + + make All + +in the XPA source directory to generate the I<stest> and +I<ctest> programs. (NB: this should work on all platforms, +although we have had problems with unresolved externals on one +Sun/Solaris machine, for reasons still unknown.) + +The stest program can be executed with no arguments to start +an XPA server that contains the access points: xpa, xpa1, +c_xpa (containing sub-commands cmd1 and cmd2), and i_xpa. +You then can use xpaset and xpaget to interact with these access points: + + cat xpa.c | xpaset xpa # send to xpa + cat xpa.c | xpaset "xpa*" # send to xpa and xpa1 + xpaget xpa # receive from xpa + xpaget xpa* # receive from xpa and xpa1 + +etc. You also can use ctest to do the same thing, or to iterate: + + ctest -s -l 100 xpa # send to xpa 100 times + ctest -s -l 100 "xpa*" # send to xpa and xpa1 100 times + ctest -g -l 100 xpa # receive from xpa 100 times + ctest -g -l 100 "xpa*" # receive from xpa and xpa1 100 times + +More options are available: see the stest.c and ctest.c code itself, which +were used extensively to debug XPA. + + +The file test.tcl in the XPA source directory gives examples for using the +XPATclInterface. + + + +=head1 SEE ALSO + + + +See xpa(n) for a list of XPA help pages + + + +=cut diff --git a/xpa/doc/pod/xpacommon.pod b/xpa/doc/pod/xpacommon.pod new file mode 100644 index 0000000..9fc9746 --- /dev/null +++ b/xpa/doc/pod/xpacommon.pod @@ -0,0 +1,266 @@ +=pod + +=head1 NAME + + + +B<XPACommon: Getting Common Information About Access Points> + + + +=head1 SYNOPSIS + + + + + +There are various kinds of generic information you can retrieve about +an XPA access point by using the xpaget command. + + + +=head1 DESCRIPTION + + + + + +You can find out which XPA access points have been registered with +the currently running +XPA name server +by executing the +xpaget +command to retrieve info from the XPA name server: + + xpaget xpans + +If, for example, the +stest test server program +is running, the following XPA access points will be returned (the specifics +of the returned info will vary for different machines and users): + + XPA xpa gs 838e2f67:1262 eric + XPA xpa1 gs 838e2f67:1266 eric + XPA c_xpa gs 838e2f67:1267 eric + XPA i_xpa i 838e2f67:1268 eric + +Note that access to this information is subject to the usual +XPA Access Control restrictions. + + +Each XPA access point supports a number of reserved sub-commands that provide +access to different kinds of information, e.g. the access control for +that access point. These sub-commands can be executed by using +xpaset +or +xpaget +at the command line, or +XPAGet() +or +XPASet() +in programs, e.g: + + xpaget ds9 -acl + xpaget ds9 -help + xpaget ds9 env FOO + + xpaset -p ds9 env FOO foofoo + +With the exception of B<-help> and B<-version>, reserved +sub-commands are available only on the machine on which the XPA server +itself is running. + +The following reserved sub-commands are defined for all access points: + + +=over 4 + + + + + + +=item * + +B<-acl> get (set) the access control list [options: host type acl, for set] + + +The 'xpaset' option allows you to add a new acl for a given host, or change +the acl for an existing host. See +XPA Access Control +for more information. +This access point is available only on the server machine. + + + + +=item * + +B<-env> get (set) an environment variable [options: name (value, for set)] + + +The 'xpaget' option will return the value of the named environment +variable. The 'xpaset' option will set the value of the names +variable to the specified value. +This access point is available only on the server machine. +(Please be advised that we have had problems setting environment +variables in static Tcl/Tk programs such as ds9 running under Linux.) + + + + +=item * + +B<-clipboard> set(get) information on a named clipboard + + +Clients can store ASCII state information on any number of named +clipboards. Clipboards of the same name created by clients on +different machines are kept separate. The syntax for creating a +clipboard is: + + [data] | xpaset [server] -clipboard add|append [clipboard_name] + xpaset -p [server] -clipboard delete [clipboard_name] + +Use "add" to create a new clipboard or replace the contents of an existing +one. Use "append" to append to an existing clipboard. + +Information on a named clipboard is retrieved using: + + xpaget [server] -clipboard [clipboard_name] + + + + +=item * + +B<-exec> set: execute commands from buffer [options: none] + + +If -exec is specified in the paramlist of an 'xpaset' call, then further +sub-commands will be retrieved from the data buffer. + + + + +=item * + +B<-help> get: return help string for this XPA or sub-command [options: name (for sub-commands)] + + +Each XPA access point and each XPA sub-command can have a help string +associated with it that is specified when the access point is defined. +The -help option will return this help string. For XPA access points +that contain user-defined sub-commands, you can get the help string +for a particular sub-command by specifying its name, or else get the +help strings for all sub-commands if not name is specified. + + + + +=item * + +B<-ltimeout> get (set) the long timeout value [options: seconds|reset] + + +The 'xpaget' option will return the value of the long timeout (in seconds). +The 'xpaset' option will set the value of the long timeout. If "reset" is +specified, then the timeout value will be reset to the default value. + + + + +=item * + +B<-nsconnect> set: re-establish name server connection to all XPA's [options: none] + + +If the +XPA Name Server (xpans) +process has terminated unexpectedly and then re-started, this +sub-command can be used to re-establish the connection. You use it by +sending the command to the [name:port] or [file] of the access point +instead of to the XPA name (since the latter requires the xpans +connection!): + + xpaset -p 838e2f67:1268 -nsconnect + +See xpans for more information. + + + + +=item * + +B<-nsdisconnect> set: break name server connection to all XPA's [options: none] + + +This sub-command will terminate the connection to the +XPA Name Server (xpans), thereby making +all access points inaccessible except through their underlying [name:port] +or [file] identifiers. I forget why we added it, it seems pretty useless. + + + + +=item * + +B<-stimeout> get (set) the short timeout value [options: seconds|reset] + + +The 'xpaget' option will return the value of the short timeout (in seconds). +The 'xpaset' option will set the value of the short timeout. If "reset" is +specified, then the timeout value will be reset to the default value. + + + + +=item * + +B<-remote> set: register xpa with remote server [options: host[:port] [acl]] [-proxy] + + +This sub-command will register the XPA access point with the XPA name +server (xpans) on the specified host (which must already be running). +The specified host also is given access control to the access point, +using the specified acl or the default acl of "+" (meaning the remote +host can xpaset, xpaget, xpainfo or xpaaccess). If the acl is +specified as "-", then the access point is unregistered. +See Communication Between Machines +for more information on how this sub-command is used. + + + + +=item * + +B<-version> get: return XPA version string [options: none] + + +The version refers to the version of XPA used to define this access point +(currently something like 2.0). + + + +=back + + + + +You can add your own reserved commands to all XPA access points by using the +XPACmdAdd() +routine, passing the XPA handle returned by I<XPA XPAGetReserved(void)> +as the first argument. Note again that these will only be available on the +machine where the XPA service is running. + + + +=head1 SEE ALSO + + + +See xpa(n) for a list of XPA help pages + + + +=cut diff --git a/xpa/doc/pod/xpaconvert.pod b/xpa/doc/pod/xpaconvert.pod new file mode 100644 index 0000000..75597a7 --- /dev/null +++ b/xpa/doc/pod/xpaconvert.pod @@ -0,0 +1,202 @@ +=pod + +=head1 NAME + + + +B<XPAConvert: Converting the XPA API to 2.0> + + + +=head1 SYNOPSIS + + + + + +This document describes tips for converting from xpa 1.0 (Xt-based +xpa) to xpa 2.0 (socket-based xpa). + + + +=head1 DESCRIPTION + + + + + +The following are tips for converting from xpa 1.0 (Xt-based xpa) to +xpa 2.0 (socket-based xpa). The changes are straight-forward and +almost can be done automatically (we used editor macros for most of +the conversion). + + +=over 4 + + + + + +=item * + +The existence of the cpp XPA_VERSION directive to distinguish between 1.0 +(where it is not defined) and 2.0 (where it is defined). + + + + +=item * + +Remove the first widget argument from all send and receive server +callbacks. Also change first 2 arguments from XtPointer to void +*. For example: + +#ifdef XPA_VERSION +static void XPAReceiveFile(client_data, call_data, paramlist, buf, len) + void *client_data; + void *call_data; + char *paramlist; + char *buf; + int len; +#else +static void XPAReceiveFile(w, client_data, call_data, paramlist, buf, len) + Widget w; + XtPointer client_data; + XtPointer call_data; + char *paramlist; + char *buf; + int len; +#endif + + + + +=item * + +Server callbacks should be declared as returning int instead +of void. They now should return 0 for no errors, -1 for error. + + + + +=item * + +The mode flags have changed when defining XPA server callbacks. +The old I<S> flag (save buffer) is replaced by I<freebuf=false>. +The old I<E> flag (empty buffer is OK) is no longer used (it +was an artifact of the X implementation). + + + + +=item * + +Change NewXPACommand() to XPAcmdNew(), with the new calling sequence: + + xpa = NewXPACommand(toplevel, NULL, prefix, NULL); + +is changed to: + + xpa = XPACmdNew(xclass, name); + + + + +=item * + +Change the AddXPACommand() subroutine name to XPACmdAdd (with the same +calling sequence): + + AddXPACommand(xpa, "file", + "\tdisplay a new file\n\t\t requires: filename", + NULL, NULL, NULL, XPAReceiveFile, text, NULL); + +is changed to: + + XPACmdAdd(xpa, "file", + "\tdisplay a new file\n\t\t requires: filename", + NULL, NULL, NULL, XPAReceiveFile, text, NULL); + + + + +=item * + +The XPAXtAppInput() routine should be called just before XtAppMainLoop() +to add xpa fds to the Xt event loop: + + /* add the xpas to the Xt loop */ + XPAXtAddInput(app, NULL); + + /* process events */ + XtAppMainLoop(app); + + + + +=item * + +Change NewXPA() to XPANew() and call XPAXtAddInput() if the XtAppMainLoop +routine already has been entered: + + xpa = NewXPA(saotng->xim->toplevel, prefix, xparoot, + "FITS data or image filename\n\t\t options: file type", + XPASendData, new, NULL, + XPAReceiveData, new, "SE"); + +is changed to: + + sprintf(tbuf, "%s.%s", prefix, xparoot); + xpa = XPANew("SAOTNG", tbuf, + "FITS data or image filename\n\t\t options: file type", + XPASendData, new, NULL, + XPAReceiveData, new, "SE"); + XPAXtAddInput(XtWidgetToApplicationContext(saotng->xim->toplevel), xpa); + + + + +=item * + +Change XPAInternalReceiveCommand() to XPACmdInternalReceive() +remove first argument in the calling sequence): + + XPAInternalReceiveCommand(im->saotng->xim->toplevel, + im->saotng, im->saotng->commands, + "zoom reset", NULL, 0); + +is changed to: + + XPACmdInternalReceive(im->saotng, im->saotng->commands, + "zoom reset", NULL, 0); + + + + +=item * + +Change DestroyXPA to XPAFree: + + DestroyXPA(im->dataxpa); + +is changed to: + + XPAFree(im->dataxpa); + + + +=back + + + + + +=head1 SEE ALSO + + + +See xpa(n) for a list of XPA help pages + + + +=cut diff --git a/xpa/doc/pod/xpaenv.pod b/xpa/doc/pod/xpaenv.pod new file mode 100644 index 0000000..a1d095f --- /dev/null +++ b/xpa/doc/pod/xpaenv.pod @@ -0,0 +1,517 @@ +=pod + +=head1 NAME + + + +B<XPAEnv: Environment Variables for XPA Messaging> + + + +=head1 SYNOPSIS + + + + +Describes the environment variables which can be used to tailor the overall +XPA environment. + + + +=head1 DESCRIPTION + + + + + +The following environment variables are supported by XPA: + + +=over 4 + + + + + +=item * + +B<XPA_ACL> + + +If I<XPA_ACL> is I<true>, then +host-based XPA Access Control +is turned on and only specified machines can access specified access +points. If I<false>, then access control is turned off and any +machine can access point. The default is turn turn access control on. + + + + +=item * + +B<XPA_ACLFILE> + + +If +XPA Access Control +is turned on, this variable specifies the name of the file containing +access control information for all access points started by this user. +The default file name is: I<$HOME/acls.xpa>. + + + + +=item * + +B<XPA_CONNECT_TIMEOUT> + + +When an XPA server first starts up, it immediately tries to +connect to the XPA name server program (xpans) on the host specified by +the I<XPA_NSINET> variable. (If this connection fails on the +local host, and if xpans can be found in the path, then the name +server is started automatically.) Unfortunately, a mis-configured +network can cause this connect attempt to hang for many seconds while +the connect() system call times out. Therefore, an alarm is started +to interrupt the connect() call and prevent a long hang. The initial +value of the alarm timeout is 10 seconds, but can be changed by setting +this environment variable. If you want to disable the alarm and allow +the initial connect() to time out, set the value of this variable to +0. Normally, users would not change this variable at all. + + + + +=item * + +B<XPA_CLIENT_DOXPA> + + +Normally, an XPA client (xpaget, xpaset, etc.) will process incoming +XPA server requests while awaiting the completion of the client request. +Setting this variable to "false" will prevent XPA server requests from +being processed by the client. + + + + +=item * + +B<XPA_DEFACL> + + +If +XPA Access Control +is turned on, this variable specifies the default access control +condition for all access points, if the I<XPA_ACLFILE> file does +not exist. The default acl is: I<$host:* $host +>, meaning that +all processes on the host machine have full access to all access points. + + + + +=item * + +B<XPA_HOST> + + +For the INET socket method, XPA utilizes the canonical hostname (as +returned by the gethostname() routine) to construct the IP part of the +method id. Under some circumstances, this might not be a correct choice +of name and IP. For example, if an XPA server is started on a machine +running VPN, you might want to use the VPN name and IP instead of the +canonical host name, so that other machines in the VPN network can +access the server. In this case, you can set the XPA_HOST to be +the VPN name (if resolvable) or, more easily, the VPN IP. + + + + +=item * + +B<XPA_IOCALLSXPA> + + +Setting this variable causes all XPA socket IO calls to process +outstanding XPA requests whenever the primary socket is not ready for +IO. This means that a server making a client call will (recursively) +process incoming server requests while waiting for client completion. +This inter-IO XPA processing avoids a rare +XPA Race Condition: two or more +XPA servers sending messages to one another using an XPA client +routine such as XPASet() can deadlock while each waits for the other +server to respond. This can happen, for example, if the servers call +XPAPoll() with a time limit, and send messages in between the polling call. + + +By default, this option is turned off, because we judge that the added +code complication and overhead involved will not be justified by the +amount of its use. Moreover, processing XPA requests within socket IO +can lead to non-intuitive results, since incoming server requests will +not necessarily be processed to completion in the order in which they +are received. + + + + +=item * + +B<XPA_LOGNAME> + + +XPA preferentially uses the de facto standard environment variable +LOGNAME to determine the username when registering an access point in +the name server. If this environment variable has been used for +something other than the actual user name (such as a log file name), +unexpected results can ensue. In such cases, use the XPA_LOGNAME +variable to set the user name. (If neither exists, then getpwuid(geteuid()) +is used as a last resort). + + + + +=item * + +B<XPA_LONG_TIMEOUT> + + +XPA is designed to allow data to be sent from one process to +another over a long period of time (i.e., a program that generates +image data sends that data to an image display, but slowly) but it +also seeks to prevent hangs. This is done by supporting 2 timeout +periods: a I<short> timeout for protocol communication +and a I<long> for data communication. + +The I<XPA_LONG_TIMEOUT> variable controls the I<long> +timeout and is used to prevent hangs in cases where communication +between the client and server that is I<not> controlled by the +XPA interface itself. Transfer of data between client and server, or a +client's wait for a status message after completion of the server +callback, are two examples of this sort of communication. By default, +the I<long> timeout is set to 180 seconds. +Setting the value to -1 will disable I<long> timeouts and allow +an infinite amount of time. + + + + +=item * + +B<XPA_MAXHOSTS> + + +The maximum number of access points that the programs +I<xpaset>, I<xpaget>, and I<xpainfo> will +communicate with at one time. The default is 64, meaning, for +example, that the I<xpaset> program will not send a message +to more than 100 access points at one time and I<xpaget> will +not retrieve from more than 100 access points at one time. + + + + +=item * + +B<XPA_METHOD> + + +Determines the socket connection method used by this session of XPA. +The choices are: I<inet> (to use INET or Internet-based +sockets), I<localhost> (to use the machines localhost inet +socket), or I<local (unix)> (to use UNIX sockets). The default +is I<INET>. Using the I<inet> method will allow access +from other machines (subject to access controls) but using +I<localhost> or I<local> will not. Localhost is most useful +for private access and when the machine in question is not connected +to the Internet. The unix method also can be used for private access +and non-Internet connections (Unix platforms only). + +Once defined, the first registration of an XPA access point will +ensure that an instance of the +XPA Name Server (xpans) +is running that handles that connection method. All new access points +will use the new connection method but existing access points will use +the original method. + + + + +=item * + +B<XPA_NSINET> + + +For the I<inet> method of socket connection, this variable +specifies the host and port on which the +XPA Name Server (xpans) +is listens for new access points. The default is I<$host:$port>, +meaning that the default XPA port (14285) on the current machine +(as returned by gethostname()) is used. If several machines were all +accessing the same XPA access points, you would use this variable to +specify that they all use the same name server to find out about these +access points. For example, a value of I<myhost:$port> would +mean that the xpans name server is running on myhost and uses the +default port 12345. All machines would then get the XPA access points +registered with that name server, subject to access controls. + +The port used by xpans to register its XPA access point normally is +taken to be one greater than the port on which it receives new access +points from XPA servers. You can specify a specific access point port +using the syntax machine:port1,port2, i.e., the access point port is +specified after the comma. For example, $host:12345,23456 will listen +for new access ports on 12345 and will accept XPA commands on 23456. + + + + +=item * + +B<XPA_NSREGISTER> + + +This boolean variable specifies whether a server registers its XPA +access point with the specified xpans name server. The default is +I<true>. If set to I<false>, the access point still is +set up but it is not registered with xpans and therefore cannot be +accessed by name. (It can be accessed by method, if the latter is +known.) Note that an access point can be registered later on (using +-remote or -proxy, for example). This variable mainly is useful in +cases where the Internet configuration is broken (so that registration +causes a DNS hang) but you still wish to and can use the server with a +remote xpans (e.g., ds9's Virtual Observatory capability). + + + + +=item * + +B<XPA_NSUNIX> + + +For the I<local> method of socket connection, this variable +specifies the name of the Unix file that will be used to access the +XPA Name Server (xpans). The default is +I<xpans_unix>. This variable is not usually needed. Note that +is the I<local> socket method is used, then remote machines will +not be able to access the xpans name server or the registered XPA access +points. + + + + +=item * + +B<XPA_NSUSERS> + + +This variable specifies whether other users' access points will be +returned by the +XPA Name Server (xpans) for use by +I<xpaget>, I<xpaset>, etc. +Generally speaking, it is sufficient to run one xpans name server per +machine and register the access points for all users with that xpans. +This means, for example, that if you request information from +ds9 by running: + + xpaget ds9 colormap + +you might get information from your own ds9 as well as +from another user running ds9 on the same machine. The +I<XPA_NSUSERS> variable controls whether you want such access +to the access points of other users. +By default, only your own access points are returned, so +that, in the example above, you would only get the colormap information +from the ds9 you registered. If, however, you had set the value of the +I<XPA_NSUSERS> variable to I<eric,fred>, then you would be +able to communicate with both eric and fred's access points. Note that +this variable can be overridden using the I<-u> switch on the +I<xpaget>, I<xpaset>, and I<xpainfo> programs. + + + + +=item * + +B<XPA_PORT> + + +A semi-colon delimited list of user specified ports to use for specific +XPA access points. The format is each specification is: + +class:template port1[ port2] + +where B<port1> is the main (command) port for the access point and +B<port2> is the (secondary) data port. If port2 is not specified, +it defaults to a value of 0 (meaning the system assigns the port). + + +Specification of specific ports is useful, for example, when a machine +outside a firewall needs to communicate with a machine inside a +firewall. In such a case, the firewall should be configured to allow +socket connections to both the command and data port from the outside +machine, and the inside XPA program should be started up with the +outside machine in its ACL list. Then, when the inside program is +started with specified ports, outside XPA programs can use +"machine:port" to contact the inside access points, instead of the +access point names. That is, the machine outside the firewall does not +need access to the XPA name server: + +export XPA_PORT="DS9:ds9 12345 12346" # on machine "inside" +cat foo.fits | xpaset inside:12345 fits # on machine "outside" + +Note that 2 ports are required for full XPA communication and +therefore 2 ports should be specified to go through a firewall. The +second port assignment is not important if you simply are assigning +the command port in order to communicate commands with a known +port (e.g., to bypass the xpans name server). If only one (command) +port is specified, the system will negotiate a random data port and +everything will work properly. + + +This support is somewhat experimental. If you run into problems, please +let us know. + + + + +=item * + +B<XPA_PORTFILE> + + +A list of user-specified port to use for specific xpa access points. +The format of the file is: + +class:template port1 [port2] + +where B<port1> is the main port for the access point and +B<port2> is the data port. If port2 is not specified, it defaults +to a value of 0 (meaning the system assigns the port). See +B<XPA_PORT> above for an explanation of user-specified ports. + + + + +=item * + +B<XPA_SHORT_TIMEOUT> + + +XPA is designed to allow data to be sent from one process to +another over a long period of time (i.e., a program that generates +image data sends that data to an image display, but slowly) but it +also seeks to prevent hangs. This is done by supporting 2 timeout +periods: a I<short> timeout for protocol communication +and a I<long> for data communication. + +The I<XPA_SHORT_TIMEOUT> variable +controls the I<short> timeout and is used to prevent hangs +in cases where the XPA protocol requires internal communication between +the client and server that is controlled by the XPA interface +itself. Authentication is an example of this sort of communication, +as is the establishment of a data channel between the two processes. +The default value for the I<short> is 30 seconds (which is +a pretty long time, actually). Setting the value to -1 will disable +I<short> timeouts and allow an infinite amount of time. + + + + +=item * + +B<XPA_SIGUSR1> + + +If the value of this variable is I<true>, then XPA will +catch SIGUSR1 signals when performing an I/O operation in order to +curtail that operation. This facility allows users to send a SIGUSR1 +signal to an XPA server if a client is hanging up the server by +sending or receiving data too slowly (timeouts also can be used -- see +above). When enabled in this way, the SIGUSR1 signal is ignored at all other +times, so that its safe to send the signal at any time. If the +variable is set to I<false>, then SIGUSR1 is not used at +all. Turning off SIGUSR1 would be desired in cases there the program +uses SIGUSR1 for some other reason and does not want XPA interfering. +The default is to use the signal. + + + + +=item * + +B<XPA_TIMESTAMP_ERRORS> + + +If I<XPA_TIMESTAMP_ERRORS> is I<true>, then error +messages will include a date/time string. This can be useful when +XPA errors are being saved in an error log (e.g. Web/CGI use). The +default is false. + + +=back + + + + + + +=item * + +B<XPA_TMPDIR> + + +This variable specifies the directory into which XPA logs, Unix +socket files (when I<XPA_METHOD> is I<local>), etc. are +stored. The default is I</tmp/.xpa>. + + + + +=item * + +B<XPA_VERBOSITY> + + +Specify the verbosity level of error messages. If the value is +set to I<0>, I<false>, or I<off>, then no error +messages are printed to stderr. If the value is I<1>, then +important XPA error messages will be output. If the value is +set to I<2>, XPA warnings about out-of-sync messages will also +be output. These latter almost always can be ignored. + + + + +=item * + +B<XPA_VERSIONCHECK> + + +Specify whether a new access point should check its major and minor XPA +version number against the version used by the xpans name server at +registration time. The default is I<true>. When checking is +performed, a warning is issued if the server major version is found to +be greater than the xpans version. Note that the check is performed +both by the XPA server and by the xpans process and warnings will be +issued by each. Also, instead of the values of I<true> or +I<false>, you can give this variable an integer value n. In this +case, each version checking process (i.e., the XPA-enabled server or +xpans) will print out a maximum of n warning messages (after which +version warnings are silently swallowed). + +In general, it is a bad idea to run an XPA-enabled server program +using a version of XPA newer than the basic xpaset, xpaget, xpaaccess, +xpans programs. This sort of mismatch usually will not work due to +protocol changes. + + + +=head1 SEE ALSO + + + +See xpa(n) for a list of XPA help pages + + + +=cut diff --git a/xpa/doc/pod/xpafree.pod b/xpa/doc/pod/xpafree.pod new file mode 100644 index 0000000..4071fb2 --- /dev/null +++ b/xpa/doc/pod/xpafree.pod @@ -0,0 +1,49 @@ +=pod + +=head1 NAME + + + +B<XPAFree: remove an XPA public access point> + + + +=head1 SYNOPSIS + + + + + + #include <xpa.h> + + int XPAFree(XPA xpa); + + + + + +=head1 DESCRIPTION + + + + +Remove the specified XPA public access point from the name server and +free all associated storage. Note that removal from the name server +happens automatically when the process terminates, so this call is not +generally needed. It is used when public access points are being +defined temporarily and then destroyed when no longer needed. For +example, ds9 temporarily creates a public access point when it +loads a new image for display and destroys it when the image is +unloaded. + + + + +=head1 SEE ALSO + + + +See xpa(n) for a list of XPA help pages + + +=cut diff --git a/xpa/doc/pod/xpaget.pod b/xpa/doc/pod/xpaget.pod new file mode 100644 index 0000000..77e771b --- /dev/null +++ b/xpa/doc/pod/xpaget.pod @@ -0,0 +1,67 @@ +=pod + +=head1 NAME + + + +B<xpaget: retrieve data from one or more XPA servers> + + + +=head1 SYNOPSIS + + + + + +xpaget [-h] [-i nsinet] [-m method] [-s] [-t sval,lval] [-u users] <template|host:port> [paramlist] + + + + + +=head1 OPTIONS + + + + + + -h print help message + -i access XPA point on different machine (override XPA_NSINET) + -m override XPA_METHOD environment variable + -n don't wait for the status message after server completes + -s enter server mode + -t [s,l] set short and long timeouts (override XPA_[SHORT,LONG]_TIMEOUT) + -u [users] XPA points can be from specified users (override XPA_NSUSERS) + --version display version and exit + + + + +=head1 DESCRIPTION + + + + +Data will be retrieved from access points matching the +template +or host:port. +A set of qualifying parameters can be appended. + +B<Examples:> + + csh> xpaget ds9 images + csh> xpaget myhost.harvard.edu:12345 + + + + + +=head1 SEE ALSO + + + +See xpa(n) for a list of XPA help pages + + +=cut diff --git a/xpa/doc/pod/xpagetfd.pod b/xpa/doc/pod/xpagetfd.pod new file mode 100644 index 0000000..5be9cfc --- /dev/null +++ b/xpa/doc/pod/xpagetfd.pod @@ -0,0 +1,133 @@ +=pod + +=head1 NAME + + + +B<XPAGetFd: retrieve data from one or more XPA servers and write to files> + + + +=head1 SYNOPSIS + + + + + + #include <xpa.h> + + int XPAGetFd(XPA xpa, + char *template, char *paramlist, char *mode, + int *fds, char **names, char **messages, int n); + + + + + +=head1 DESCRIPTION + + + + +Retrieve data from one or more XPA servers whose class:name identifier +matches the specified +template +and write it to files associated with +one or more standard I/O fds (i.e, handles returned by open()). + + +A +template +of the form "class1:name1" is sent to the +XPA name server, which returns a list of at most ABS(n) matching XPA +servers. A connection is established with each of these servers and +the paramlist string is passed to the server as the data transfer +request is initiated. If an XPA struct is passed to the call, then the +persistent connections are updated as described above. Otherwise, +temporary connections are made to the servers (which will be closed +when the call completes). + + +The XPAGetFd() routine then retrieves data from the XPA servers, +and write these data to the fds associated with one or more fds +(i.e., results from open). Is n is positive, then there will be n fds +and the data from each server will be sent to a separate fd. If n is +negative, then there is only 1 fd and all data is sent to this single +fd. (The latter is how xpaget is implemented.) + + +A string containing the class:name and ip:port is stored in the name +array. If a given server returned an error or the server callback +sends a message back to the client, then the message will be stored in +the associated element of the messages array. NB: if specified, the +name and messages arrays must be of size n or greater. + + +The returned message string will be of the form: + + XPA$ERROR error-message (class:name ip:port) + +or + + XPA$MESSAGE message (class:name ip:port) + + +Note that when there is an error stored in an messages entry, the +corresponding bufs and lens entry may or may not be NULL and 0 +(respectively), depending on the particularities of the server. + + +The return value will contain the actual number of servers that were +processed. This value thus will hold the number of valid entries in +the bufs, lens, names, and messages arrays, and can be used to loop +through these arrays. In names and/or messages is NULL, no information is +passed back in that array. + + +The mode string is of the form: "key1=value1,key2=value2,..." +The following keywords are recognized: + + key value default explanation + ------ -------- -------- ----------- + ack true/false true if false, don't wait for ack from server (after callback completes) + + +The ack keyword is not very useful, since the server completes the callback +in order to return the data anyway. It is here for completion (and perhaps +for future usefulness). + + +B<Example:> + + #include <xpa.h> + #define NXPA 10 + int i, got; + int fds[NXPA]; + char *names[NXPA]; + char *messages[NXPA]; + for(i=0; i<NXPA; i++) + fds[i] = open(...); + got = XPAGetFd(NULL, "ds9", "file", NULL, fds, names, messages, NXPA); + for(i=0; i<got; i++){ + if( messages[i] != NULL ){ + /* error processing */ + fprintf(stderr, "ERROR: %s (%s)\n", messages[i], names[i]); + } + if( names[i] ) + free(names[i]); + if( messages[i] ) + free(messages[i]); + } + + + + + +=head1 SEE ALSO + + + +See xpa(n) for a list of XPA help pages + + +=cut diff --git a/xpa/doc/pod/xpainet.pod b/xpa/doc/pod/xpainet.pod new file mode 100644 index 0000000..40793a0 --- /dev/null +++ b/xpa/doc/pod/xpainet.pod @@ -0,0 +1,285 @@ +=pod + +=head1 NAME + + + +B<XPAInet: XPA Communication Between Hosts> + + + +=head1 SYNOPSIS + + + + +XPA uses standard inet sockets to support communication between two or +more host computers. + + + +=head1 DESCRIPTION + + + + + +When the Communication Method is set to +B<inet> (as it is by default), XPA can be used to communicate +between different computers on the Internet. INET sockets utilize the +IP address of the given machine and a (usually random) port number to +communicate between processes on the same machine or between different +machines on the Internet. These standard Internet sockets are also +used by programs such as Netscape, ftp. etc. + + +XPA supports a host-based Access Control mechanism +to prevent unauthorized access of XPA access points by other computers +on the Net. By default, only the machine on which the XPA server is +running can access XPA services. Therefore, setting up communication +between a local XPA server machine and a remote client machine +requires a two-part registration process: + + + +=over 4 + + + + +=item * + +the XPA service on the local machine must be made known to the +remote machine + + +=item * + +the remote machine must be given permission to access the local +XPA service + + +=back + + + +Three methods by which this remote registration can be accomplished +are described below. + +B<Manual Registration> + +The first method is the most basic and does not require the remote +client to have xpans running. To use it, the local server simply +gives a remote client machine access to one or more XPA access points +using xpaset and the B<-acl> sub-command. For example, +consider the XPA test program "stest" running on a local machine. By +default the access control for the access point named "xpa" is +restricted to that machine: + + [sh]$ xpaget xpa -acl + *:* 123.456.78.910 gisa + *:* localhost gisa + +Using xpaset and the B<-acl> sub-command, a remote client +machine can be given permission to perform xpaget, xpaset, xpaaccess, +or xpainfo operations. For example, to allow the xpaget operation, the +following command can be issued on the local machine: + + [sh]$ xpaset -p xpa -acl "remote_machine g" + +This results in the following access permissions on the local machine: + + [sh]$ xpaget xpa -acl + XPA:xpa 234.567.89.012 g + *:* 123.456.78.910 gisa + *:* localhost gisa + + +The remote client can now use the local server's xpans name server to +establish communication with the local XPA service. This can be done +on a call-by-call basis using the B<-i> switch on xpaset, xpaget, etc: + + [sh]$ xpaget -i "local_machine:12345" xpa + class: XPA + name: xpa + method: 88877766:2778 + sendian: little + cendian: big + +Alternatively, the XPA_NSINET variable on the remote machine can be +set to point directly to xpans on the local machine, removing +the need to override this value each time an XPA program is run: + + [csh]$ setenv XPA_NSINET 'karapet:$port' + [csh]$ xpaget xpa + class: XPA + name: xpa + method: 88877766:2778 + sendian: little + cendian: big + +Here, '$port' means to use the default XPA name service port (14285). +not a port environment variable. + + +Access permission for remote client machines can be stored in a file +on the local machine pointed to by the B<XPA_ACLFILE> environment +variable or using the B<XPA_DEFACL> environment variable. See <A +HREF="./acl.html">XPA Access Control for more information. + +B<Remote Registration> + +If xpans is running on the remote client machine, then a local xpaset +command can be used with the B<-remote> sub-command to +register the local XPA service in the remote name service, while at +the same time giving the remote machine permission to access the local +service. For example, assume again that "stest" is running on the +local machine and that xpans is also running on the remote machine. +To register access of this local xpa on the remote machine, use +the xpaset and the B<-remote> sub-command: + + [sh]$ ./xpaset -p xpa -remote 'remote_machine:$port' + + +To register the local xpa access point on the remote machine with xpaget +access only, execute: + + [sh]$ ./xpaset -p xpa -remote 'remote_machine:$port' g + +Once the remote registration command is executed, the remote client +machine will have an entry such as the following in its own xpans name +service: + + [csh]$ xpaget xpans + XPA xpa gs 88877766:2839 eric + +The xpa access point can now be utilized on the remote machine without +further setup: + + [csh]$ xpaget xpa + class: XPA + name: xpa + method: 838e2f68:2839 + sendian: little + cendian: big + +To unregister remote access from the local machine, use the same +command but with a '-' argument: + + [sh]$ xpaset -p xpa -remote 'remote_machine:$port' - + +The benefit of using remote registration is that communication with +remote access points can be mixed with that of other access points +on the remote machine. Using Access Point +Names and Templates, one XPA command can be used to send or +receive messages to the remote and local services. + +B<XPANS Proxy Registration> + +The two methods described above are useful when the local and remote +machines are able to communicate freely to one another. This would be +the case on most Local Area Networks (LANs) where all machines are +behind the same firewall and there is no port blocking between +machines on the same LAN. The situation is more complicated when the +XPA server is behind a firewall, where outgoing connections are +allowed, but incoming port blocking is implemented to prevent machines +outside the firewall from connecting to machines inside the +firewall. Such incoming port blocking will prevent xpaset and xpaget +from connecting to an XPA server inside a firewall. + + +To allow locally fire-walled XPA services to register with remote +machines, we have implemented a proxy service within the xpans name +server. To register remote proxy service, xpaset and the +B<-remote> sub-command is again used, but with an additional +B<-proxy> argument added to the end of the command: + + [sh]$ ./xpaset -p xpa -remote 'remote_machine:$port' g -proxy + +Once a remote proxy registration command is executed, the remote +machine will have an entry such as the following in its own xpans name +service: + + [csh]$ xpaget xpans + XPA xpa gs @88877766:2839 eric + +The '@' sign in the name service entry indicates that xpans proxy +processing is being used for this access point. Other than that, from +the user's point of view, there is no difference in how this XPA +access point is contacted using XPA programs (xpaset, xpaget, etc.) or +libraries: + + [csh]$ xpaget xpa + class: XPA + name: xpa + method: 88877766:3053 + sendian: little + cendian: big + + +Of course, the underlying processing of the XPA requests is very much +different when xpans proxy is involved. Instead of an XPA program such +contacting the XPA service directly, it contacts the local xpans. +Acting as a proxy server, xpans communicates with the XPA service +using the command channel established at registration time. Commands +(including establishing a new data channel) are sent between xpans and +the XPA service to set up a new message transfer, and then data is fed +to/from the xpa request, through xpans, from/to the XPA service. In +this way, it can be arranged so that connections between the +fire-walled XPA service and the remote client are always initiated by +the XPA service itself. Thus, incoming connections that would be +blocked by the firewall are avoided. Note that there is a performance +penalty for using the xpans/proxy service. Aside from extra overhead +to set up proxy communication, all data must be sent through the +intermediate proxy process. + + +The xpans proxy scheme requires that the remote client allow the local +XPA server machine to connect to the remote xpans/proxy server. If the +remote client machine also is behind a port-blocking firewall, such +connections will be disallowed. In this case, the only solution is to +open up some ports on the remote client machine to allow incoming +connections to xpans/proxy. Two ports must be opened (for command and +data channel connections). By default, these two ports are 14285 and +14287. The port numbers can be changed using the B<XPA_NSINET> +environment variable. This variable takes the form: + + setenv XPA_NSINET machine:port1[,port2[,port3]] + +where port1 is the main connecting port, port2 is the XPA access port, +and port3 is the secondary data connecting port. The second and third +ports are optional and default to port1+1 and port1+2, respectively. +It is port1 and port3 that must be left open for incoming connections. + + +For example, to change the port assignments so that xpans listens +for registration commands on port 12345 and data commands on port 28573: + + setenv XPA_NSINET myhost:12345 + +Alternatively, all three ports can be assigned explicitly: + + setenv XPA_NSINET remote:12345,3000,12346 + +In this case 12345 and 12346 should be open for incoming connections. +The XPA access port (which need not be open to the outside +world) is set to 3000. + + +Finally, note that we currently have no mechanism to cope with +Internet proxy servers (such as SOCKS servers). If an XPA service is +running on a machine that cannot connect directly to outside machines, +but goes through a proxy server instead, there currently is no way to +register that XPA service with a remote machine. We hope to implement +support for SOCKS proxy in a future release. + + + +=head1 SEE ALSO + + + +See xpa(n) for a list of XPA help pages + + + +=cut diff --git a/xpa/doc/pod/xpainfo.pod b/xpa/doc/pod/xpainfo.pod new file mode 100644 index 0000000..65fdb3e --- /dev/null +++ b/xpa/doc/pod/xpainfo.pod @@ -0,0 +1,66 @@ +=pod + +=head1 NAME + + + +B<xpainfo: send short message to one or more XPA servers> + + + +=head1 SYNOPSIS + + + + + +xpainfo [-h] [-i nsinet] [-m method] [-n] [-s] [-t sval,lval] [-u users] <template|host:port> [paramlist] + + + + + +=head1 OPTIONS + + + + + + -h print help message + -i access XPA point on different machine (override XPA_NSINET) + -m override XPA_METHOD environment variable + -n don't wait for the status message after server completes + -s enter server mode + -t [s,l] set short and long timeouts (override XPA_[SHORT,LONG]_TIMEOUT) + -u [users] XPA points can be from specified users (override XPA_NSUSERS) + --version display version and exit + + + + +=head1 DESCRIPTION + + + + +Info will be sent to access points matching the +template +or host:port. +A set of qualifying parameters can be appended. + +B<Examples:> + + csh> xpainfo IMAGE ds9 image + + + + + +=head1 SEE ALSO + + + +See xpa(n) for a list of XPA help pages + + +=cut diff --git a/xpa/doc/pod/xpainfonew.pod b/xpa/doc/pod/xpainfonew.pod new file mode 100644 index 0000000..ae54f54 --- /dev/null +++ b/xpa/doc/pod/xpainfonew.pod @@ -0,0 +1,92 @@ +=pod + +=head1 NAME + + + +B<XPAInfoNew: define an XPA info public access point> + + + +=head1 SYNOPSIS + + + + + + #include <xpa.h> + + XPA XPAInfoNew(char *class, char *name, + int (*info_callback)(), + void *info_data, char *info_mode); + + + + + +=head1 DESCRIPTION + + + + +[NB: this is an experimental interface, new to XPA 2.0, whose value +and best use is evolving.] + + +A program can register interest in receiving a short message about a +particular topic from any other process that cares to send such a +message. Neither has to be an XPA server. For example, if a user +starts to work with a new image file called new.fits, she might +wish to alert interested programs about this new file by sending a +short message using xpainfo: + + xpainfo IMAGEFILE /data/new.fits + + + +In this example, each process that has used the XPAInfoNew() call to +register interest in messages associated with the identifier IMAGEFILE +will have its info_callback() executed with the following calling +sequence: + + int info_cb(void *info_data, void *call_data, char *paramlist) + { + XPA xpa = (XPA)call_data; + } + + +The arguments passed to this routine are equivalent to those sent in +the send_callback() routine. The main difference is that there is no +buf sent to the info callback: this mechanism is meant for short +announcement of messages of interest to many clients. + + +The mode string is of the form: "key1=value1,key2=value2,..." +The following keywords are recognized: + + key value default explanation + ------ -------- -------- ----------- + acl true/false true enable access control + + +Because no buf is passed to this callback, the usual buf-related keywords +are not applicable here. + + +The information sent in the parameter list is arbitrary. However, we +envision sending information such as file names or XPA access points +from which to collect more data. Note that the xpainfo program and +the XPAInfo() routine that cause the info_callback to execute do not +wait for the callback to complete before returning. + + + + +=head1 SEE ALSO + + + +See xpa(n) for a list of XPA help pages + + +=cut diff --git a/xpa/doc/pod/xpaintro.pod b/xpa/doc/pod/xpaintro.pod new file mode 100644 index 0000000..31ce14f --- /dev/null +++ b/xpa/doc/pod/xpaintro.pod @@ -0,0 +1,176 @@ +=pod + +=head1 NAME + + + +B<XPAIntro: Introduction to the XPA Messaging System> + + + +=head1 SYNOPSIS + + + + + +A brief introduction to the XPA messaging system, which provides +seamless communication between all kinds of Unix event-driven +programs, including X programs, Tcl/Tk programs, and Perl programs. + + + +=head1 DESCRIPTION + + + + + +The XPA messaging system provides seamless communication between all +kinds of Unix programs, including X programs, Tcl/Tk programs, and +Perl programs. It also provides an easy way for users to communicate +with these XPA-enabled programs by executing XPA client commands in +the shell or by utilizing such commands in scripts. Because XPA works +both at the programming level and the shell level, it is a powerful +tool for unifying any analysis environment: users and programmers have +great flexibility in choosing the best level or levels at which to +access XPA services, and client access can be extended or modified +easily at any time. + + +A program becomes an XPA-enabled server by defining named points of +public access through which data and commands can be exchanged with +other client programs (and users). Using standard TCP sockets as +a transport mechanism, XPA supports both single-point and broadcast +messaging to and from these servers. It supports direct communication +between clients and servers, or indirect communication via an +intermediate message bus emulation program. Host-based access control +is implemented, as is as the ability to communicate with XPA servers +across a network. + + +XPA implements a layered interface that is designed to be useful both +to software developers and to users. The interface consists of a +library of XPA client and server routines for use in programs and a +suite of high-level user programs built on top of these libraries. +Using the XPA library, access points can be added to +Tcl/Tk +programs, +Xt +programs, or to Unix programs that use the XPA event loop or any +event loop based on select(). Client access subroutines can be added +to any Tcl/Tk or Unix program. Client access also is supported at the +command line via a suite of high-level programs. + + +The major components of the XPA layered interface are: + + +=over 4 + + + + +=item * + +A set of XPA server routines, centered on +XPANew(), +which are used by XPA server programs to tag public access points with +string identifiers and to register send and receive callbacks for +these access points. + + + +=item * + +A set of XPA client routines, centered on the +XPASet() +and +XPAGet(), +which are used by external client applications to exchange data and +commands with an XPA server. + + + +=item * + +High-level programs, centered on +xpaset +and +xpaget, +which allow data +and information to be exchanged with XPA server programs from the +command line and from scripts. These programs have the command syntax: + + [data] | xpaset [qualifiers ...] + xpaget [qualifiers ...] + + + +=item * + +An XPA name server program, +xpans, +through which XPA access point names are +registered by servers and distributed to clients. + + +=back + + + + +Defining an XPA access point is easy: a server application calls +XPANew(), +XPACmdNew(), +or the experimental +XPAInfoNew() +routine to +create a named public access point. An XPA service can specify "send" +and "receive" callback procedures (or an "info" procedure in the case +of XPAInfoNew()) to be executed by the program when an external +process either sends data or commands to this access point or requests +data or information from this access point. Either of the callbacks +can be omitted, so that a particular access point can be specified as +read-only, read-write, or write-only. Application-specific client +data can be associated with these callbacks. Having defined one or +more public access points in this way, an XPA server program enters +its usual event loop (or uses the standard XPA event loop). + + +Clients communicate with these XPA public access points +using programs such as +xpaget, +xpaset, and +xpainfo +(at the command line), +or routines such as +XPAGet(), +XPASet(), +and +XPAInfo() +within a program. Both methods require specification of the name of +the access point. The xpaget program returns data or other +information from an XPA server to its standard output, while the +xpaset program sends data or commands from its standard input to an +XPA application. The corresponding API routines set/get data to/from +memory, returning error messages and other info as needed. If a +template +is used to specify the access point name (e.g., "ds9*"), then +communication will take place with all servers matching that template. + + +Please note that XPA currently is not thread-safe. All XPA calls must be +in the same thread. + + + +=head1 SEE ALSO + + + +See xpa(n) for a list of XPA help pages + + + +=cut diff --git a/xpa/doc/pod/xpamacros.pod b/xpa/doc/pod/xpamacros.pod new file mode 100644 index 0000000..786e04b --- /dev/null +++ b/xpa/doc/pod/xpamacros.pod @@ -0,0 +1,76 @@ +=pod + +=head1 NAME + + + +B<XPA Server Callback Macros> + + + +=head1 SYNOPSIS + + + + + + #include <xpa.h> + + xpa_class, xpa_name, xpa_method, xpa_cmdfd, xpa_datafd, + xpa_sendian, xpa_cendian + + + + + +=head1 DESCRIPTION + + + + +Server routines have access to information about the XPA being called via +the following macros (each of which takes the xpa handle as an argument): + + macro explanation + ------ ----------- + xpa_class class of this xpa + xpa_name name of this xpa + xpa_method method string (inet or local connect info) + xpa_cmdfd fd of command socket + xpa_datafd fd of data socket + xpa_sendian endian-ness of server ("little" or "big") + xpa_cendian endian-ness of client ("little" or "big" + + +The argument to these macros is the call_data pointer that is passed +to the server procedure. This pointer should be type case to XPA +in the server routine: + + XPA xpa = (XPA)call_data; + + + +The most important of these macros is xpa_datafd(). A server routine +that sets "fillbuf=false" in receive_mode or send_mode can use this +macro to perform I/O directly to/from the client, rather than using +buf. + + +The xpa_cendian and xpa_sendian macros can be used together to determine +if the data transferred from the client is byte swapped with respect +to the server. Values for these macros are: "little", "big", or "?". +In order to do a proper conversion, you still need to know the format +of the data (i.e., byte swapping is dependent on the size of the data +element being converted). + + + + +=head1 SEE ALSO + + + +See xpa(n) for a list of XPA help pages + + +=cut diff --git a/xpa/doc/pod/xpamainloop.pod b/xpa/doc/pod/xpamainloop.pod new file mode 100644 index 0000000..4fabf8e --- /dev/null +++ b/xpa/doc/pod/xpamainloop.pod @@ -0,0 +1,108 @@ +=pod + +=head1 NAME + + + +B<XPAMainLoop: optional main loop for XPA> + + + +=head1 SYNOPSIS + + + + + + #include <xpa.h> + + void XPAMainLoop(); + + + + + +=head1 DESCRIPTION + + + + +Once XPA access points have been defined, a program must enter an +event loop to watch for requests from external programs. This can be +done in a variety of ways, depending on whether the event loop is +processing events other than XPA events. In cases where there are no +non-XPA events to be processed, the program can simply call the +XPAMainLoop() event loop. This loop is implemented essentially as +follows (error checking is simplified in this example): + + FD_ZERO(&readfds); + while( XPAAddSelect(NULL, &readfds) ){ + if( sgot = select(swidth, &readfds, NULL, NULL, NULL) >0 ) + XPAProcessSelect(&readfds, 0); + else + break; + FD_ZERO(&readfds); + } + + +The XPAAddSelect() routine sets up the select() readfds variable so +that select() will wait for I/O on all the active XPA channels. It +returns the number of XPAs that are active; the loop will end when +there are no active XPAs. The standard select() routine is called to +wait for an external I/O request. Since no timeout struct is passed +in argument 5, the select() call hangs until there is an external +request. When an external I/O request is made, the XPAProcessSelect() +routine is executed to process the pending requests. In this routine, +the maxreq value determines how many requests will be processed: if +maxreq <=0, then all currently pending requests will be processed. +Otherwise, up to maxreq requests will be processed. (The most usual +values for maxreq is 0 to process all requests.) + + +If a program has its own Unix select() loop, then XPA access points can +be added to it by using a variation of the standard XPAMainLoop: + + XPAAddSelect(xpa, &readfds); + [app-specific ...] + if( select(width, &readfds, ...) ){ + XPAProcessSelect(&readfds, maxreq); + [app-specific ...] + FD_ZERO(&readfds); + } + + +XPAAddSelect() is called before select() to add the access points. +If the first argument is NULL, then all active XPA access points +are added. Otherwise only the specified access point is added. +After select() is called, the XPAProcessSelect() routine can be called +to process XPA requests. Once again, the maxreq value determines how +many requests will be processed: if maxreq <=0, then all currently +pending requests will be processed. Otherwise, up to maxreq requests +will be processed. + + +XPA access points can be added to +Xt event loops (using XtAppMainLoop()) +and +Tcl/Tk event loops (using vwait and the Tk loop). +When using XPA with these event loops, you only need to call: + +int XPAXtAddInput(XtAppContext app, XPA xpa) + +or + + int XPATclAddInput(XPA xpa) + +respectively before entering the loop. + + + + +=head1 SEE ALSO + + + +See xpa(n) for a list of XPA help pages + + +=cut diff --git a/xpa/doc/pod/xpamb.pod b/xpa/doc/pod/xpamb.pod new file mode 100644 index 0000000..b1b97d4 --- /dev/null +++ b/xpa/doc/pod/xpamb.pod @@ -0,0 +1,249 @@ +=pod + +=head1 NAME + + + +B<xpamb: the XPA Message Bus> + + + +=head1 SYNOPSIS + + + + + +The xpamb program can act as a "classical" message bus interface +between clients and servers. A client can send a data request to +the message bus, which then interfaces with multiple servers and +returns the data back to the client. + + + +=head1 OPTIONS + + + + + +For xpaset, several optional switches are used to save data and +manipulate the stored data: + + +=over 4 + + + + + + +=item * + +B<-data [name]> + + +Add the supplied data buffer to a pool of stored data buffers, +using the specified name as a unique identifier for later retrieval. +An error occurs if the name already exists (use either B<replace> +or B<del> to rectify this). The B<-add> switch is supported +for backwards compatibility with xpa 2.0. + + + + +=item * + +B<-replace [name]> + + +Replace previously existing stored data having the same unique name +with new data. This essentially is a combination of the B<del> +and B<data> commands. + + + + +=item * + +B<-info ["'info string'"]> + + +When adding a data buffer, you can specify an informational +string to be stored with that data. This string will be returned +by xpaget: + + xpaget xpamb foo -info + +(along with other information such as the date/time of storage and the size of +the data buffer) if the -info switch is specified. If the info string contains +spaces, you must enclose it in B<two> sets of quotes: + + cat foo | xpaset xpamb -store foo -info "'this is info on foo'" + +The first set of quotes is removed by the shell while the second is used to +delineate the info string. + + + + +=item * + +B<-send [name]> + + +Broadcast the stored data buffer to the named template. + + + + +=item * + +B<-del [name]> + + +Delete the named data buffer and free all allocated space. + + +=back + + + + +Switches can be used in any combination that makes sense. For example: + + cat foo.fits | xpaset xpamb -store foo -info "FITS" "DS9:*" fits foo.fits + +will broadcast the foo.fits image to all access points of class +B<DS9>. In addition, the foo.fits file will be stored under the +name of B<foo> for later manipulation such as: + + xpaset -p xpamb -send foo "DS9:*" fits foo.fits + +will re-broadcast the foo.fits image to all access points of class "DS9". + + + +=head1 DESCRIPTION + + + + + +A "classical" message bus (such as ToolTalk) consists of servers and +clients, along with a mediating program that transfers data between +different processes. XPA takes a slightly different approach in that +communication between clients and servers is direct. This generally +is the correct technique when there is only one connection (or even a +small number of connections), but can become inefficient for the +serving program if a large amount of data is being transferred to many +clients. For example, if a real-time data acquisition program is +broadcasting a FITS image to several clients, it would need to +transmit that image to each client individually. This might interfere +with its own processing cycles. The preferable mechanism would be to +pass the image off to an intermediate program that can then broadcast +the data to the several clients. + +The B<xpamb> program can alleviate such problems by functioning +as a message bus in cases where such an intermediary process is +wanted. It pre-defines a single access point named +B<XPAMB:xpamb> to which data can be sent for re-broadcast. You +also can tell B<xpamb> to save the data, and associate with that +data a new access point, so that it can be retrieved later on. + + +All interaction with B<xpamb> is performed through +B<xpaset> and B<xpaget> (or the corresponding API +routines, B<XPASet()> and B<XPAGet()>) to the +B<XPAMB:xpamb> access point. That is, B<xpamb> is just +another XPA-enabled program that responds to requests from +clients. The paramlist is used to specify the targets to which +the data will be for re-broadcast, as well as the re-broadcast paramlist: + + data | xpaset xpamb [switches] broadcast-target broadcast-paramlist + +Optional switches are used to store data, and manipulate stored data, +and are described below. + + +In its simplest form, you can, for example, send a FITS image to xpamb for +broadcasting to all ds9 image simply by executing: + + cat foo.fits | xpaset xpamb "DS9:*" fits foo.fits + +Since B<DS9> is the class name for the ds9 image display +program, this will result in the FITS image being re-sent to all fits +access points for all active image display programs. + + +You can send stored data and new data to the same set of access points at +the same time. The stored data always is send first, followed by the new +data: + + cat foo2.fits | xpaset xpamb -send foo "DS9:*" fits foo.fits + +will first send the foo.fits file, and then the foo2.fits file to all +access points of class B<DS9>. Notice that in this example, +the foo2.fits file is not stored, but it could be stored by using the +B<-store [name]> switch on the command line. + + +The B<xpaget> command can be used to retrieve a data from XPA +access points or from a stored data buffer, or retrieve information +about a stored data buffer. If no arguments are given: + + xpaget xpamb + +then information about all currently stored data buffers is returned. This +information includes the data and time at which the data was stored, the +size in bytes of the data, and the supplied info string. + + +If arguments are specified, they will be in the form: + + xpaget xpamb [-info] [-data] [name [paramlist]] + +If the optional B<-info> and/or B<-data> switches are specified, then +information and/or data will be returned for the named data buffer +following the switches. You can use either or both of these switches +in a single command. For example, if the -info switch is used: + + xpaget xpamb -info foo + +then the info about that stored data buffer will be returned. +If the -data is used with a specific name: + + xpaget xpamb -data foo + +then the stored data itself will be returned. If both are used: + + xpaget xpamb -info -data foo + +then the info will be returned, followed by the data. Note that it is an +error to specify one of these switches without a data buffer name and that +the paramlist will be ignored. + + +If neither the B<-info> or B<-data> switch is specified, then +the name refers to an XPA access point (with an optional paramlist +following). +For example: + + xpaget xpamb ds9 file + +is equivalent to: + + xpaget ds9 file + + + + +=head1 SEE ALSO + + + +See xpa(n) for a list of XPA help pages + + + +=cut diff --git a/xpa/doc/pod/xpamethod.pod b/xpa/doc/pod/xpamethod.pod new file mode 100644 index 0000000..038ac4e --- /dev/null +++ b/xpa/doc/pod/xpamethod.pod @@ -0,0 +1,99 @@ +=pod + +=head1 NAME + + + +B<XPAMethod: XPA Communication Methods> + + + +=head1 SYNOPSIS + + + + + +XPA supports both inet and unix (local) socket communication. + + + +=head1 DESCRIPTION + + + + + +XPA uses sockets for communication between processes. It supports +three methods of socket communication: inet, localhost, and unix. In +general, the same method should be employed for all XPA processes in a +session and the global environment variable XPA_METHOD should be used +to set up the desired method. By default, the preferred method is +"inet", which is appropriate for most users. You can set up a +different method by typing something like: + + setenv XPA_METHOD local # unix csh + XPA_METHOD=local; export XPA_METHOD # unix sh, bash, windows/cygwin + set XPA_METHOD=localhost # dos/windows + +The options for XPA_METHOD are: B<inet>, B<unix> (or +B<local>), and B<localhost>. On Unix machines, this +environment setup command can be placed in your shell init file +(.cshrc, .profile, .bashrc, etc.) On Windows platforms, it can be +placed in your AUTOEXEC.BAT file (I think!). + + +By default, B<inet> sockets are used by XPA. These are the standard +Internet sockets that are used by programs such as Netscape, +ftp. etc. Inet sockets utilize the IP address of the given machine and +a (usually random) port number to communicate between processes on the +same machine or between different machines on the Internet. (Note that +XPA has an Access Control mechanism to +prevent unauthorized access of XPA access points by other computers on +the Net). For users connected to the Internet, this usually is the +appropriate communication method. For more information about setting +up XPA communication between machines, see +Communication Between Machines. + + +In you are using XPA on a machine without an Internet connection, then +inet sockets are not appropriate. In fact, an XPA process often will +hang for many seconds while waiting for a response from the Domain +Name Service (DNS) when using inet sockets. Instead of inet sockets, +users on Unix platforms can also use B<unix> sockets (also known +as local sockets). These sockets are based on the local file system +and do not make use of the DNS. They generally are considered to be +faster than inet sockets, but they are not implemented under +Windows. Use local sockets as a first resort if you are on a Unix +machine that is not connected to the Internet. + + +Users not connected to the Internet also can use B<localhost> +sockets. These are also inet-type sockets but the IP address used for +the local machine is the B<localhost> address, 0x7F000001, instead +of the real IP of the machine. Depending on how sockets are set up for +a given platform, communication with the DNS usually is not required in +this case (though of course, XPA cannot interact with other machines). +The localhost method will generally work on both Unix and Windows +platforms, but whether the DNS is required or not is subject to +individual configurations. + + +A final warning/reminder: if your XPA-enabled server hangs at startup +time and your XPA_METHOD is B<inet>, the problem probably is +related to an incorrect Internet configuration. This can be confirmed +by using the B<unix> method or (usually) the B<localhost> +method. You can use these alternate methods if other hosts do not need +access to the XPA server. + + + +=head1 SEE ALSO + + + +See xpa(n) for a list of XPA help pages + + + +=cut diff --git a/xpa/doc/pod/xpaname.pod b/xpa/doc/pod/xpaname.pod new file mode 100644 index 0000000..7c0ea8d --- /dev/null +++ b/xpa/doc/pod/xpaname.pod @@ -0,0 +1,56 @@ +=pod + +=head1 NAME + + + +B<XPAName: What does XPA stand for?> + + + +=head1 SYNOPSIS + + + + + +What does XPA stand for? Who knows anymore! + + + +=head1 DESCRIPTION + + + + + +What does XPA stand for? Dunno! The XPA messaging system originally +was built on top of the X Window System and XPA was the mnemonic for +I<X Public Access>, to emphasize that we were providing public +access to previously private data and algorithms in Xt programs. Now +that XPA no longer is tied to X, it can be argued that we ought to +change the name (how about SPAM: simple public access mechanism +), but XPA is in wide-spread use in the astronomical community of +its birth, and the name has taken on a life of its own. If anyone can +think of what XPA now means, please let us know. + + +If you think this is bad, consider the MMT Telescope on Mount Hopkins, +Arizona. When first installed twenty years ago, it featured an array +of six 72-inch diameter mirrors. from which came its name: the +I<Multiple Mirror Telescope>. In spring of 1999, these mirrors +were replaced by a single 21 and 1/2 -foot diameter primary mirror, +the largest single-piece glass reflector on the North American +continent. And now MMT stands for ... MMT! + + + +=head1 SEE ALSO + + + +See xpa(n) for a list of XPA help pages + + + +=cut diff --git a/xpa/doc/pod/xpanew.pod b/xpa/doc/pod/xpanew.pod new file mode 100644 index 0000000..1a3800f --- /dev/null +++ b/xpa/doc/pod/xpanew.pod @@ -0,0 +1,243 @@ +=pod + +=head1 NAME + + + +B<XPANew: create a new XPA access point> + + + +=head1 SYNOPSIS + + + + + + #include <xpa.h> + + XPA XPANew(char *class, char *name, char *help, + int (*send_callback)(), + void *send_data, char *send_mode, + int (*rec_callback)(), + void *rec_data, char *rec_mode); + + + + + +=head1 DESCRIPTION + + + + +Create a new XPA public access point with the class:name +identifier template +and enter this access point into the XPA name server, so that it +can be accessed by external processes. XPANew() returns an XPA struct. +Note that the length of the class and name designations must be less +than or equal to 1024 characters each. + + +The XPA name server daemon, xpans, will be started automatically if it +is not running already (assuming it can be found in the path). The +program's ip address and listening port are specified by the +environment variable XPA_NSINET, which takes the form :. If +no such environment variable exists, then xpans is started on the +current machine listening on port 14285. It also uses 14286 as a +known port for its public access point (so that routines do not have +to go to the name server to find the name server ip and port!) +As of XPA 2.1.1, version information is exchanged between the xpans +process and the new access point. If the access point uses an XPA +major/minor version newer than xpans, a warning is issued by both processes, +since mixing of new servers and old xpa programs (xpaset, xpaget, +xpans, etc.) is not likely to work. You can turn off the warning +message by setting the XPA_VERSIONCHECK environment variable to "false". + + +The help string is meant to be returned by a request from xpaget: + + xpaget class:name -help + + +A send_callback and/or a receive_callback can be specified; at +least one of them must be specified. + + +A send_callback can be specified that will be executed in response to +an external request from the xpaget program, the XPAGet() routine, or +XPAGetFd() routine. This callback is used to send data to the +requesting client. + + +The calling sequence for send_callback() is: + + int send_callback(void *send_data, void *call_data, + char *paramlist, char **buf, size_t *len) + { + XPA xpa = (XPA)call_data; + ... + return(stat); + } + + +The send_mode string is of the form: "key1=value1,key2=value2,..." +The following keywords are recognized: + + key value default explanation + ------ -------- -------- ----------- + acl true/false true enable access control + freebuf true/false true free buf after callback completes + + +The call_data should be recast to the XPA struct as shown. In +addition, client-specific data can be passed to the callback in +send_data. + + +The paramlist will be supplied by the client as qualifying parameters +for the callback. There are two ways in which the send_callback() +routine can send data back to the client: + + +1. The send_callback() routine can fill in a buffer and pass back a +pointer to this buffer. An integer len also is returned to specify the +number of bytes of data in buf. XPA will send this buffer to the +client after the callback is complete. + + +2. The send_callback can send data directly to the client by writing +to the fd pointed by the macro: + + xpa_datafd(xpa) + + +Note that this fd is of the kind returned by socket() or open(). + + +If a buf has been allocated by a standard malloc routine, filled, and +returned to XPA, then freebuf generally is set so that the buffer will +be freed automatically when the callback is completed and data has +been sent to the client. If a static buf is returned, freebuf should +be set to false to avoid a system error when freeing static storage. +Note that default value for freebuf implies that the callback will +allocate a buffer rather than use static storage. + + +On the other hand, if buf is dynamically allocated using a method +other than a standard malloc/calloc/realloc routine (e.g. using Perl's +memory allocation and garbage collection scheme), then it is necessary +to tell XPA how to free the allocated buffer. To do this, use the +XPASetFree() routine within your callback: + + void XPASetFree(XPA xpa, void (*myfree)(void *), void *myfree_ptr); + +The first argument is the usual XPA handle. The second argument is the +special routine to call to free your allocated memory. The third +argument is an optional pointer. If not NULL, the specified free +routine is called with that pointer as its sole argument. If NULL, the +free routine is called with the standard buf pointer as its sole +argument. This is useful in cases where there is a mapping between the +buffer pointer and the actual allocated memory location, and the +special routine is expecting to be passed the former. + + +If, while the callback performs its processing, an error occurs that +should be communicated to the client, then the routine XPAError should be +called: + + XPAError(XPA xpa, char *s); + + +where s is an arbitrary error message. The returned error message +string will be of the form: + + XPA$ERROR [error] (class:name ip:port) + + +If the callback wants to send a specific acknowledgment message back +to the client, the routine XPAMessage can be called: + + XPAMessage(XPA xpa, char *s); + + +where s is an arbitrary error message. The returned error message +string will be of the form: + + XPA$MESSAGE [message] (class:name ip:port) + + +Otherwise, a standard acknowledgment is sent back to the client +after the callback is completed. + + +The callback routine should return 0 if no error occurs, or -1 to +signal an error. + + +A receive_callback can be specified that will be executed in response +to an external request from the xpaset program, or the XPASet (or +XPASetFd()) routine. This callback is used to process data received +from an external process. + + +The calling sequence for receive_callback is: + + int receive_callback(void *receive_data, void *call_data, + char *paramlist, char *buf, size_t len) + { + XPA xpa = (XPA)call_data; + ... + return(stat); + } + + +The mode string is of the form: "key1=value1,key2=value2,..." +The following keywords are recognized: + + key value default explanation + ------ -------- -------- ----------- + acl true/false true enable access control + buf true/false true server expects data bytes from client + fillbuf true/false true read data into buf before executing callback + freebuf true/false true free buf after callback completes + + +The call_data should be recast to the XPA struct as shown. In +addition, client-specific data can be passed to the callback in +receive_data. + + +The paramlist will be supplied by the client. In addition, if the +receive_mode keywords buf and fillbuf are true, then on entry into the +receive_callback() routine, buf will contain the data sent by the +client. If buf is true but fillbuf is false, it becomes the callback's +responsibility to retrieve the data from the client, using the data fd +pointed to by the macro xpa_datafd(xpa). If freebuf is true, then buf +will be freed when the callback is complete. + + +If, while the callback is performing its processing, an error occurs +that should be communicated to the client, then the routine XPAError +can be called: + + XPAError(XPA xpa, char *s); + + +where s is an arbitrary error message. + + +The callback routine should return 0 if no error occurs, or -1 to +signal an error. + + + + +=head1 SEE ALSO + + + +See xpa(n) for a list of XPA help pages + + +=cut diff --git a/xpa/doc/pod/xpans.pod b/xpa/doc/pod/xpans.pod new file mode 100644 index 0000000..071dd68 --- /dev/null +++ b/xpa/doc/pod/xpans.pod @@ -0,0 +1,226 @@ +=pod + +=head1 NAME + + + +B<xpans: the XPA Name Server> + + + +=head1 SYNOPSIS + + + + + + xpans [-h] [-e] [-k sec] [-p port] [-l log] [-s security log] [-P n] + + + + +=head1 OPTIONS + + + + + + -h print help message + -e exit when there are no more XPA connections + -k send keepalive messages every n sec + -l log data base entries to specified file + -p listen for connections on specified port + -s log security info for each connection to specified file + -P accept proxy requests (P=1) using separate thread (P=2) + --version display version and exit + + + + +=head1 DESCRIPTION + + + + +The xpans name server is an XPA-enabled program that is used to +manage the names and ports of XPA access points. It is started +automatically when an XPA access point is registered. You can access +the name server using xpaget to get a list of registered access points. + +The I<xpans> name server provides a crucial link between XPA +clients and servers. When an XPA server defines an access point using +XPANew(), XPACmdNew(), or XPAInfoNew(), the name of the access point +is registered in the name service, along with connection information. +The name server then matches class:name templates passed to it by XPA +clients with these registered entries, so that the clients can +communicate with the appropriate servers. + + +The socket connection between an XPA-enabled program and +I<xpans> is kept open until the former exits (or explicitly +closes the connection). Apparently, some Internet equipment (e.g. DSL +modems) can cause such a connection to time-out after a period of +inactivity. To prevent this from happening, you can use the -k +[sec] switch to send a short keep-alive message to each open +connection after the specified time delay. (Note that this +application level use of keep-alive is necessary only if you are +serving XPA-enabled clients over the Internet and have to deal with +long-term connections involving DSL or similar equipment. XPA uses +the ordinary socket-level keep-alive, which works for all other cases.) +NB (12/2/2009): Out-of-band (URG) TCP data, used by xpans +keep-alive, is changed by some Cisco routers into in-band data. +Encountering such a router will break the keep-alive function and may +break your XPA server as well. Proceed with caution! + + +The I<xpans> program will be started automatically (assuming it +can be found in the user's path) when the first XPA access point is +registered. It therefore need not be started explicitly. However, +when started automatically, the I<-e> switch is used, so that +the name server will exit when there are no more XPA access points +registered. If you wish to keep the name server running continually, +simply start it manually without the I<-e> switch. + + +The name server will keep a log of registered access points if the +I<-l [log]> switch is used on the command line (this is the +case for automatic start-up). The log contains enough name and connection +information to allow you to re-register all XPA access points in case +the name server process is terminated prematurely. For example, after +the ds9 access point is registered,the log will contain the entry: + + add 838e2f67:1863 ds9 ds9 gs eric + +If I<xpans> is terminated but ds9 still is running, you +can re-register both access points for the ds9 process by running: + + xpaset -p 838e2f67:1863 -nsconnect + +Notice that the ip:port specifier is used with I<xpaset> to bypass +the need for contacting the name server (which does not have the name +registered yet!) + + +The name server will keep a log of security information if the -s +[security log] switch is used on the command line. For each +accepted connection, (including connections via the I<xpaget> +command), information will be logged about the host issuing the +command and the parameters passed into the program. This is most +useful when I<xpans> is accepting connections from untrusted +machines. + + +When an XPA access point is removed by a server using I<XPAFree()>, +the access information is removed from the name server. If an +XPA-enabled process is terminated, all names registered by that process +will be removed automatically. The log file is always updated to +reflect the currently registered access points. + + +The name server itself has an XPA access point names I<xpans> +registered through which you can find out information about currently +registered access points (assuming you have access to the name server; +see XPA Access Control for more information). +For each registered access point, the following information is returned: + + class # class of the access point + name # name of the access point + access # allowed access (g=xpaget,s=xpaset,i=xpainfo) + id # socket access method (host:port for inet, file for local/unix) + user # user name of access point owner + + + +For example, to display all currently registered access points, simply execute: + + xpaget xpans + +Continuing the example of ds9 above, this will return: + + DS9 ds9 gs 838e2f67:1863 eric + +If the same program has been started with different XPA access names, +you can look up only names matching a specified template. For example, +assume that ds9 has been started up using: + + ds9 & + ds9 -title ds9-1-eric & + ds9 -title ds9-2-eric & + +To lookup all ds9 access points which end in ".eric" and which can +be accessed using I<xpaset>, use: + + xpaget xpans "DS9:*.eric" "s" "*" + +This will return: + + DS9 ds9-2-eric gs 838e29d3:42102 eric + DS9 ds9-1-eric gs 838e29d3:42105 eric + +The third argument "*" requests all access points from all users. +You also can specify a specific user name and only access points +registered by that user will be returned. + + +The name server uses the I<XPA_METHOD> environment variable +to determine whether it should listen for requests on INET or LOCAL +sockets. Since XPA access points also use this environment variable, +the choice of socket method will be consistent. Note that, when INET +sockets are used, a local server can be accessed from remote machines +if the I<XPA_NSINET> environment variable is set to point to +the local machine. See +XPA Environment Variables +for more information. + + +An experimental feature of xpans is its ability to act as a proxy to +XPA servers behind firewalls that want to communicate with external +processes. The basic idea is the following: an XPA server (call it +"foo") on host1, possibly behind a firewall, makes a remote connection +to a proxy-enabled xpans program on host2 (specifying host2's XPA method). +For example: + + xpaset -p foo -remote 'host2:28571' + -proxy # on host1 + +When this is done, host2 can use xpaset, xpaget, and xpainfo calls to +communicate with the XPA server foo. All command communication is +performed via the xpans socket connection between foo on host1 and +xpans on host2 (which was initiated by foo from inside the firewall). +Data communication is similarly performed using a socket connection +initiated on host1 (usually with a port value two greater than the +port value of the main xpans socket connection). An xpaset or xpaget +call on host2 contacts xpans, which performs an XPASet() or XPAGet() +call to foo, passing commands and data back and forth between the two +programs. + + +By default, proxy connections are not allowed by xpans. If the -P switch is +specified with a value of 1, proxy connection are allowed, but all proxy +communication is performed in the same thread as xpans processing. If +a value of 2 is specified, the proxy processing is performed in a +separate thread (assuming pthreads are supported on your system). +Because xpa callback processing of any type can take a long time and +therefore can interfere with normal xpans processing, threaded proxy +connections (-P 2) are recommended. When using proxy connections, it +might also be useful to set the XPA_IOCALLSXPA environment variable, so +that multiple proxy requests can be handled at the same time, instead of +serially. + + +Note that this proxy interface to xpans is experimental. It is used +to provide remote data analysis capabilities on the Chandra-Ed system +using ds9. (See http://chandra-ed.cfa.harvard.edu and +http://hea-www.harvard.edu/saord/ds9 for more details). As always, please +contact us if you have problems or questions. + + + +=head1 SEE ALSO + + + +See xpa(n) for a list of XPA help pages + + + +=cut diff --git a/xpa/doc/pod/xpanslookup.pod b/xpa/doc/pod/xpanslookup.pod new file mode 100644 index 0000000..e0f4cdc --- /dev/null +++ b/xpa/doc/pod/xpanslookup.pod @@ -0,0 +1,126 @@ +=pod + +=head1 NAME + + + +B<XPANSLookup: lookup registered XPA access points> + + + +=head1 SYNOPSIS + + + + + + #include <xpa.h> + + int XPANSLookup(XPA xpa, + char *template, char type, + char ***classes, char ***names, + char ***methods, char ***infos) + + + + + +=head1 DESCRIPTION + + + + +XPA routines act on a class:name identifier in such a way +that all access points that match the identifier are processed. It is +sometimes desirable to choose specific access points from the +candidates that match the +template. In order to do this, the +XPANSLookup routine can be called to return a list of matches, so that +specific class:name instances can then be fed to XPAGet(), XPASet(), etc. + + The first argument is an optional XPA struct. If non-NULL, the +existing name server connection associated with the specified xpa is +used to query the xpans name server for matching templates. Otherwise, +a new (temporary) connection is established with the name server. + + +The second argument to XPANSLookup is the class:name +template +to match. + + +The third argument for XPANSLookup() is the type of access and can be +any combination of: + + type explanation + ------ ----------- + g xpaget calls can be made on this access point + s xpaset calls can be made on this access point + i xpainfo calls can be made on this access point + + +The call typically specifies only one of these at a time. + + +The final arguments are pointers to arrays that will be filled +in and returned by the name server. The name server will allocate and +return arrays filled with the classes, names, and methods of all XPA +access points that match the template +and have the specified type. Also returned are info strings, which +generally are used internally by the client routines. These can be +ignored (but the strings must be freed). The function returns the +number of matches. The returned value can be used to loop through the +matches: + +B<Example:> + + #include <xpa.h> + + char **classes; + char **names; + char **methods; + char **infos; + int i, n; + n = XPANSLookup(NULL, "foo*", "g", &classes, &names, &methods, &infos); + for(i=0; i<n; i++){ + [more specific checks on possibilities ...] + [perhaps a call to XPAGet for those that pass, etc. ...] + /* don't forget to free alloc'ed strings when done */ + free(classes[i]); + free(names[i]); + free(methods[i]); + free(infos[i]); + } + /* free up arrays alloc'ed by names server */ + if( n > 0 ){ + free(classes); + free(names); + free(methods); + free(infos); + } + + +The specified +template +also can be a host:port specification, for example: + + myhost:12345 + + +In this case, no connection is made to the name server. Instead, the +call will return one entry such that the ip array contains the ip for +the specified host and the port array contains the port. The class +and name entries are set to the character "?", since the class and +name of the access point are not known. + + + + +=head1 SEE ALSO + + + +See xpa(n) for a list of XPA help pages + + +=cut diff --git a/xpa/doc/pod/xpaoom.pod b/xpa/doc/pod/xpaoom.pod new file mode 100644 index 0000000..b8b2431 --- /dev/null +++ b/xpa/doc/pod/xpaoom.pod @@ -0,0 +1,60 @@ +=pod + +=head1 NAME + + + +B<Xpaoom: What happens when XPA runs out of memory?> + + + +=head1 SYNOPSIS + + + + + +When XPA can't allocate memory, it exits. You can arrange to have it call +longjmp() instead. + + + +=head1 DESCRIPTION + + + + + +When an XPA server or client cannot allocate memory, it will attempt to +output an error message and then exit. If this is not satisfactory (e.g., +perhaps your program is interactive and can recover from OOM errors), you +can tell XPA to call longjmp() to go to a recovery branch. To pass the +requisite jmp_buf variable to XPA, make the following call: + + XPASaveJmp(void *env); + +The value of env is the address of a jmp_buf variable that was previously +passed to setjmp(). For example: + + jmp_buf env; + ... + if( setjmp(jmp_buf) != 0 ){ + /* out of memory -- take corrective action, if possible */ + } else { + /* save env for XPA */ + XPASaveJmp((void *)&jmp_buf); + } + // enter main loop ... + + + + +=head1 SEE ALSO + + + +See xpa(n) for a list of XPA help pages + + + +=cut diff --git a/xpa/doc/pod/xpaopen.pod b/xpa/doc/pod/xpaopen.pod new file mode 100644 index 0000000..d88df02 --- /dev/null +++ b/xpa/doc/pod/xpaopen.pod @@ -0,0 +1,69 @@ +=pod + +=head1 NAME + + + +B<XPAOpen: allocate a persistent client handle> + + + +=head1 SYNOPSIS + + + + + + #include <xpa.h> + + XPA XPAOpen(char *mode); + + + + + +=head1 DESCRIPTION + + + + +XPAOpen() allocates a persistent XPA struct that can be used with +calls to XPAGet(), XPASet(), XPAInfo(), XPAGetFd(), and +XPASetFd(). Persistence means that a connection to an XPA server is +not closed when one of the above calls is completed but will be +re-used on successive calls. Using XPAOpen() therefore saves the time +it takes to connect to a server, which could be significant with slow +connections or if there will be a large number of exchanges with a +given access point. The mode argument currently is ignored ("reserved +for future use"). + + +An XPA struct is returned if XPAOpen() was successful; otherwise NULL +is returned. This returned struct can be passed as the first argument +to XPAGet(), etc. Those calls will update the list of active XPA +connections. Already connected servers (from a previous call) are +left connected and new servers also will be connected. Old servers +(from a previous call) that are no longer needed are disconnected. +The connected servers will remain connected when the next call to +XPAGet() is made and connections are once again updated. + + +B<Example:> + + #include <xpa.h> + + XPA xpa; + xpa = XPAOpen(NULL); + + + + + +=head1 SEE ALSO + + + +See xpa(n) for a list of XPA help pages + + +=cut diff --git a/xpa/doc/pod/xpapoll.pod b/xpa/doc/pod/xpapoll.pod new file mode 100644 index 0000000..1f26ee1 --- /dev/null +++ b/xpa/doc/pod/xpapoll.pod @@ -0,0 +1,58 @@ +=pod + +=head1 NAME + + + +B<XPAPoll: execute existing XPA requests> + + + +=head1 SYNOPSIS + + + + + + #include <xpa.h> + + int XPAPoll(int msec, int maxreq); + + + + + +=head1 DESCRIPTION + + + + +It is sometimes desirable to implement a polling loop, i.e., where one +checks for and processes XPA requests without blocking. For this +situation, use the XPAPoll() routine: + + XPAPoll(int msec, int maxreq); + + +The XPAPoll() routine will perform XPAAddSelect() and select(), but with a +timeout specified in millisecs by the msec argument. If one or more +XPA requests are made before the timeout expires, the XPAProcessSelect() +routine is called to process those requests. The maxreq value determines +how many requests will be processed: if maxreq < 0, then no events are +processed, but instead, the return value indicates the number of events +that are pending. If maxreq == 0, then all currently pending requests +will be processed. Otherwise, up to maxreq requests will be processed. +(The most usual values for maxreq are 0 to process all requests and 1 +to process one request). + + + + +=head1 SEE ALSO + + + +See xpa(n) for a list of XPA help pages + + +=cut diff --git a/xpa/doc/pod/xparace.pod b/xpa/doc/pod/xparace.pod new file mode 100644 index 0000000..418b8a0 --- /dev/null +++ b/xpa/doc/pod/xparace.pod @@ -0,0 +1,89 @@ +=pod + +=head1 NAME + + + +B<XPA Race Conditions> + + + +=head1 SYNOPSIS + + + +Potential XPA race conditions and how to avoid them. + + + +=head1 DESCRIPTION + + + + +Currently, there is only one known circumstance in which XPA can get +(temporarily) deadlocked in a race condition: if two or more XPA +servers send messages to one another using an XPA client routine such +as XPASet(), they can deadlock while each waits for the other server +to respond. (This can happen if the servers call XPAPoll() with a +time limit, and send messages in between the polling call.) The +reason this happens is that both client routines send a string to the +other server to establish the handshake and then wait for the server +response. Since each client is waiting for a response, neither is able +to enter its event-handling loop and respond to the other's +request. This deadlock will continue until one of the timeout periods +expire, at which point an error condition will be triggered and the +timed-out server will return to its event loop. + + +Starting with version 2.1.6, this rare race condition can be +avoided by setting the XPA_IOCALLSXPA environment variable for servers +that will make client calls. Setting this variable causes all XPA +socket IO calls to process outstanding XPA requests whenever the +primary socket is not ready for IO. This means that a server making a +client call will (recursively) process incoming server requests while +waiting for client completion. It also means that a server callback +routine can handle incoming XPA messages if it makes its own XPA call. +The semi-public routine oldvalue=XPAIOCallsXPA(newvalue) can be used +to turn this behavior off and on temporarily. Passing a 0 will turn +off IO processing, 1 will turn it back on. The old value is returned +by the call. + + +By default, the XPA_IOCALLSXPA option is turned off, because we judge +that the added code complication and overhead involved will not be +justified by the amount of its use. Moreover, processing XPA requests +within socket IO can lead to non-intuitive results, since incoming +server requests will not necessarily be processed to completion in the +order in which they are received. + + +Aside from setting XPA_IOCALLSXPA, the simplest way to avoid this race +condition is to multi-process: when you want to send a client message, +simply start a separate process to call the client routine, so that +the server is not stopped. It probably is fastest and easiest to use +fork() and then have the child call the client routine and exit. But +you also can use either the system() or popen() routine to start one +of the command line programs and do the same thing. Alternatively, you +can use XPA's internal launch() routine instead of system(). Based on +fork() and exec(), this routine is more secure than system() because +it does not call /bin/sh. + + +Starting with version 2.1.5, you also can send an XPAInfo() message with +the mode string "ack=false". This will cause the client to send a message +to the server and then exit without waiting for any return message from +the server. This UDP-like behavior will avoid the server deadlock when +sending short XPAInfo messages. + + + +=head1 SEE ALSO + + + +See xpa(n) for a list of XPA help pages + + + +=cut diff --git a/xpa/doc/pod/xpaserver.pod b/xpa/doc/pod/xpaserver.pod new file mode 100644 index 0000000..275defd --- /dev/null +++ b/xpa/doc/pod/xpaserver.pod @@ -0,0 +1,96 @@ +=pod + +=head1 NAME + + + +B<XPAServer: The XPA Server-side Programming Interface> + + + +=head1 SYNOPSIS + + + + +A description of the XPA server-side programming interface. + + + +=head1 DESCRIPTION + + + +B<Introduction to XPA Server Programming> + +Creating an XPA server is easy: you generally only need to call the +XPANew() subroutine to define a named XPA access point and set up the +send and receive callback routines. You then enter an event loop such +as XPAMainLoop() to field XPA requests. + + #include <xpa.h> + + XPA XPANew(char *class, char *name, char *help, + int (*send_callback)(), void *send_data, char *send_mode, + int (*rec_callback)(), void *rec_data, char *rec_mode); + + XPA XPACmdNew(char *class, char *name); + + XPACmd XPACmdAdd(XPA xpa, + char *name, char *help, + int (*send_callback)(), void *send_data, char *send_mode, + int (*rec_callback)(), void *rec_data, char *rec_mode); + + void XPACmdDel(XPA xpa, XPACmd cmd); + + XPA XPAInfoNew(char *class, char *name, + int (*info_callback)(), void *info_data, char *info_mode); + + int XPAFree(XPA xpa); + + void XPAMainLoop(void); + + int XPAPoll(int msec, int maxreq); + + void XPAAtExit(void); + + void XPACleanup(void); + + + +B<Introduction> + +To use the XPA application programming interface, a software developer +generally will include the xpa.h definitions file: + + #include <xpa.h> + +in the software module that defines or accesses an XPA access point, and +then will link against the libxpa.a library: + + gcc -o foo foo.c libxpa.a + +XPA has been compiled using both C and C++ compilers. + + +A server program generally defines an XPA access point by calling the +XPANew() routine and specifies "send" and/or "receive" callback +procedures to be executed by the program when an external process +either sends data or commands to this access point or requests data or +information from this access point. A program also can define several +sub-commands for a single access point by calling XPACmdNew() and +XPACmdAdd() instead. Having defined one or more public access points +in this way, an XPA server program enters its usual event loop (or +uses the standard XPA event loop). + + + + +=head1 SEE ALSO + + + +See xpa(n) for a list of XPA help pages + + +=cut diff --git a/xpa/doc/pod/xpaset.pod b/xpa/doc/pod/xpaset.pod new file mode 100644 index 0000000..19c2dbe --- /dev/null +++ b/xpa/doc/pod/xpaset.pod @@ -0,0 +1,115 @@ +=pod + +=head1 NAME + + + +B<xpaset: send data to one or more XPA servers> + + + +=head1 SYNOPSIS + + + + + +<data> | xpaset [-h] [-i nsinet] [-m method] [-n] [-p] [-s] [-t sval,lval] [-u users] [-v] <template|host:port> [paramlist] + + + + + +=head1 OPTIONS + + + + + + -h print help message + -i access XPA point on different machine (override XPA_NSINET) + -m override XPA_METHOD environment variable + -n don't wait for the status message after server completes + -p don't read (or send) buf data from stdin + -s enter server mode + -t [s,l] set short and long timeouts (override XPA_[SHORT,LONG]_TIMEOUT) + -u [users] XPA points can be from specified users (override XPA_NSUSERS) + -v verify message to stdout + --version display version and exit + + + + +=head1 DESCRIPTION + + + + +Data read from stdin will be sent to access points matching the +template +or host:port. +A set of qualifying parameters can be appended. + +Normally, xpaset reads data input from stdin until EOF and sends those +data to the XPA target, along with parameters entered on the command +line. For example to send a FITS file to the ds9 image display: + + cat foo.fits | xpaset ds9 fits + + +Sometimes, however, it is desirable to send only parameters to an XPA +access point, without sending data. For such cases, use the -p switch to +indicate that there is no data being send to stdin. For example, to +change the colormap used by the ds9 image display program, use: + + csh> xpaset -p ds9 cmap Heat + +Of course, this also can be accomplished by sending EOF to stdin in +any of the usual ways: + + csh> echo "" | xpaset ds9 cmap Heat + csh> xpaget ds9 cmap Heat < /dev/null + csh> xpaset ds9 cmap Heat + ^D # Ctl-D signals EOF + + +The -s switch puts xpaset into server mode, in which commands and data +can be sent to access points without having to run xpaset multiple times. +(Its not clear if this buys you much!) The syntax for sending commands +in server mode is: + + + csh> xpaset -s + xpaset ds9 colormap I8 + ^D + xpaset ds9 regions + circle 200 300 40 + circle 300 400 50 + ^D +etc. + +After the required "xpaset" command is specified, optional ASCII data +can be appended (as in the region example). A single data/command set is +delimited by ^D. Note that typing ^D when a command is expected terminates +the program. + +NB: server mode only works from the terminal and only ASCII data can be +sent in this way. + +B<Examples:> + + csh> xpaset ds9 file < foo.fits + csh> echo "stop" | xpaset myhost:12345 + + + + + +=head1 SEE ALSO + + + +See xpa(n) for a list of XPA help pages + + +=cut diff --git a/xpa/doc/pod/xpasetfd.pod b/xpa/doc/pod/xpasetfd.pod new file mode 100644 index 0000000..6a49684 --- /dev/null +++ b/xpa/doc/pod/xpasetfd.pod @@ -0,0 +1,113 @@ +=pod + +=head1 NAME + + + +B<XPASetFd: send data from stdin to one or more XPA servers> + + + +=head1 SYNOPSIS + + + + + + #include <xpa.h> + + int XPASetFd(XPA xpa, + char *template, char *paramlist, char *mode, + int fd, char **names, char **messages, int n) + + + + + +=head1 DESCRIPTION + + + + +Read data from a standard I/O fd and send it to one or more XPA +servers whose class:name identifier matches the specified +template. + + +A +template +of the form "class1:name1" is sent to the +XPA name server, which returns a list of at most n matching XPA +servers. A connection is established with each of these servers and +the paramlist string is passed to the server as the data transfer +request is initiated. If an XPA struct is passed to the call, then the +persistent connections are updated as described above. Otherwise, +temporary connections are made to the servers (which will be closed +when the call completes). + + +The XPASetFd() routine then reads bytes from the specified fd +until EOF and sends these bytes to the XPA servers. +The final parameter n specifies the maximum number of servers to contact. +A string containing the class:name and ip:port of each server is returned in +the name array. If a given server returned an error, then the error +message will be stored in the associated element of the messages array. +NB: if specified, the name and messages arrays must be of size n or greater. + + +The return value will contain the actual number of servers that were +processed. This value thus will hold the number of valid entries in +the names and messages arrays, and can be used to loop through these +arrays. In names and/or messages is NULL, no information is passed back +in that array. + + +The mode string is of the form: "key1=value1,key2=value2,..." +The following keywords are recognized: + + key value default explanation + ------ -------- -------- ----------- + ack true/false true if false, don't wait for ack from server (after callback completes) + verify true/false false send buf from XPASet[Fd] to stdout + + +The ack keyword is useful in cases where one does not want to wait for +the server to complete, e.g. is a lot of processing needs to be done +on the passed data or when the success of the server operation is not +relevant to the client. + + +B<Example:> + + #include <xpa.h> + + #define NXPA 10 + int i, got; + int fd; + char *names[NXPA]; + char *messages[NXPA]; + fd = open(...); + got = XPASetFd(NULL, "ds9", "fits", NULL, fd, names, messages, NXPA); + for(i=0; i<got; i++){ + if( messages[i] != NULL ){ + /* error processing */ + fprintf(stderr, "ERROR: %s (%s)\n", messages[i], names[i]); + } + if( names[i] ) + free(names[i]); + if( messages[i] ) + free(messages[i]); + } + + + + + +=head1 SEE ALSO + + + +See xpa(n) for a list of XPA help pages + + +=cut diff --git a/xpa/doc/pod/xpatcl.pod b/xpa/doc/pod/xpatcl.pod new file mode 100644 index 0000000..008a4f3 --- /dev/null +++ b/xpa/doc/pod/xpatcl.pod @@ -0,0 +1,258 @@ +=pod + +=head1 NAME + + + +B<XPATcl: the XPA Interface to the Tcl/Tk Environment> + + + +=head1 SYNOPSIS + + + + + + +Tcl/Tk programs can act as XPA clients and/or servers using the Tcl +interface to XPA that is contained in the libtclxpa.so shared object. + +B<Server Routines> + + + set xpa [xpanew class name help sproc sdata smode rproc rdata rmode] + xpafree xpa + set xpa [xpanew class name help iproc idata imode] + set xpa [xpacmdnew class name] + xpacmdadd xpa name help sproc sdata smode rproc rdata rmode + xpacmddel xpa cmd + set val [xparec xpa option] + options: name, class, method, cmdfd, datafd, cmdchan, datachan + xpasetbuf xpa buf len + xpaerror xpa message + xpamessage xpa message + + +B<Client Routines> + + + set xpa [xpaopen mode] + xpaclose xpa + set got [xpaget xpa template paramlist mode bufs lens names errs n] + set got [xpaget xpa template paramlist mode chans names errs n] + set got [xpaset xpa template paramlist mode buf len names errs n] + set got [xpasetfd xpa template paramlist mode chan names errs n] + set got [xpainfo xpa template paramlist mode names errs n] + # NB: 2.1 calling sequence change + # set got [xpaaccess template type] (2.0.5) + set got [xpaaccess xpa template paramlist mode names errs n] + set got [xpanslookup template type classes names methods] + + + + +=head1 DESCRIPTION + + + + + +You can call XPANew(), XPACmdNew(), or XPAInfoNew() within a C +routine to add C-based XPA server callbacks to a TCL/Tk program that +uses a Tcl/Tk event loop (either vwait() or the Tk event loop); +Such a program does not need or want to use the XPA event loop. +Therefore, in order to add XPA access points to the Tcl/Tk loop, the +following routine should be called beforehand: + + int XPATclAddInput(XPA xpa); + + +Normally, the xpa argument is NULL, meaning that all current XPA +access points are registered with the event loop. However, if a +single XPA access point is to be added (i.e., after the event loop is +started) then the handle of that XPA access point can be passed to +this routine. + + +The significance of the XPA/TCL interface goes beyond the support for +using XPA inside C code. The interface allows you to write XPA +servers and to make calls to the XPA client interface within the Tcl +environment using the Tcl language directly. The XPA/Tcl +interface can be loaded using the following package command: + + package require tclxpa 2.0 + +Alternatively, you can load the shared object (called libtclxpa.so ) directly: + + load .../libtclxpa.so tclxpa + + +Once the tclxpa package is loaded, you can use Tcl versions of XPA +routines to define XPA servers or make client XPA calls. The +interface for these routines is designed to match the Unix XPA +interface as nearly as possible. Please refer to +XPA Servers +and +XPA Clients +for general information about these routines. + + +The file test.tcl in the XPA source directory gives examples for using the +XPA/Tcl interface. + + +The following notes describe the minor differences between the interfaces. + +B<XPANew> + + + set xpa [xpanew class name help sproc sdata smode rproc rdata rmode] + + + +rproc and sproc routines are routines. The calling sequence of the +rproc routine is identical to its C counterpart: + + proc rec_cb { xpa client_data paramlist buf len } { ... } + + +The sproc routine, however is slightly different from its C counterpart +because of the difficulty of passing data back from the callback to C: + + proc sendcb { xpa client_data paramlist } { ... } + + +Note that the C-based server's char **buf and int *len arguments are +missing from the Tcl callback. This is because we did not know how to +fill buf with data and pass it back to the C routines for communication +with the client. Instead, the Tcl server callback uses the following +routine to set buf and len: + + xpasetbuf xpa buf len + +where: + + arg explanation + ------ ----------- + xpa the first argument of the server callback + buf the data to be returned to the client + len data length in bytes, (if absent, use length of the buf object) + + +When this routine is called, a copy of buf is saved for transmission to +the client. + + +The fact that buf is duplicated means that TCL server writers might wish to +perform the I/O directly within the callback, rather than have XPA do it +automatically at the end of the routine. To do this, set: + + fillbuf=false + + +in the xpanew smode and then perform I/O through the Tcl channel +obtained from: + + set dchan [xparec $xpa datachan] + + +where: + + arg explanation + ------ ----------- + xpa the first argument of the server callback + datachan literal string "datachan" that returns the data channel + len data length in bytes, (if absent, use length of the buf object) + + + +NB: datachan and cmdchan are not available under Windows. It is +necessary to use the "raw" equivalents: datafd and cmdfd. + + + +The same considerations apply to the rproc for receive servers: a copy +of the incoming data is generated to pass to the receive callback. This +copy again can be avoided by using "fillbuf=false" in the rmode and then +reading the incoming data from datachan. + + +The send and receive callback routines can use the xpaerror and xpamessage +routines to send errors and messages back to the client. If you also +want tcl itself to field an error condition, use the standard return call: + + return ?-code c? ?-errorinfo i? ?-errorcode ec? string + + +See the Tcl man page for more info. + +B<XPARec> + +The Tcl xparec procedure supplies server routines with access to information +that is available via macros in the C interface: + + set val [xparec xpa <option>] + + +where option is: name, class, method, cmdfd, datafd, cmdchan, +datachan. Note that two additional identifiers, cmdchan and datachan, +have been added to to provide Tcl channels corresponding to datafd and +cmdfd. (These latter might still be retrieved in Tcl and passed back +to a C routines.) An additional option called "version" can be used to +determine the XPA version used to build the Tcl interface. Note that +the standard options require a valid XPA handle, but "version" does +not (since it simply reports the value of the XPA_VERSION definition +in the XPA source include file). + + + +NB: datachan and cmdchan are not available under Windows. It is +necessary to use the "raw" equivalents: datafd and cmdfd. + + + macro explanation + ------ ----------- + class class of this xpa + name name of this xpa + method method string (inet or local connect info) + cmdchan Tcl channel of command socket + datachan Tcl channel of data socket + cmdfd fd of command socket + datafd fd of data socket + sendian endian-ness of server ("little" or "big") + cendian endian-ness of client ("little" or "big" + version XPA version used to build this code + + + +Under Windows, the Tcl event handler cannot automatically sense when an +XPA socket is ready for IO (i.e. Tcl_CreateFileHandler() is not available +under Windows). The Windows Tcl event handler therefore must be awakened +occasionally for check for XPA events. This is done using the standard +Tcl_SetMaxBlockTime() call. The time parameter is defined in tclloop.c +and is currently set to 1000 microseconds (1/1000 of a second). + + +The version option can be used to differentiate between source code versions. +It was created to support legacy Tcl code that needs to maintain the 2.0.5 +calling sequence for xpaaccess. You can use a version test such as: + + if [catch { xparec "" version } version] { + puts "pre-2.1.0e" + } else { + puts [split $version .] + } + + + + +=head1 SEE ALSO + + + +See xpa(n) for a list of XPA help pages + + + +=cut diff --git a/xpa/doc/pod/xpatemplate.pod b/xpa/doc/pod/xpatemplate.pod new file mode 100644 index 0000000..1524934 --- /dev/null +++ b/xpa/doc/pod/xpatemplate.pod @@ -0,0 +1,120 @@ +=pod + +=head1 NAME + + + +B<XPATemplate: Access Point Names and Templates> + + +=head1 SYNOPSIS + + + + + +XPA access points are composed of two parts: a general class and a +specific name. Both parts accept template characters so that you +can send/retrieve data to/from multiple servers at one time. + + + +=head1 DESCRIPTION + + + + + +When XPA servers call +XPANew(), +or +XPACmdNew() +to define XPA access points, they specify a string identifier composed of a +class and a name. When clients communicate with XPA access points, +they specify which access points to communicate with using +an identifier of the form: + + class:name + +All registered XPA access points that match the specified identifier +will be available for communication (subject to access control rules, +etc.) + + +As of XPA 2.1.5, the length of both the class and name designations are +limited to 1024 characters. + + +The XPA class:name identifier actually is a template: it accepts wild +cards in its syntax, so a single specifier can match more than one XPA +access point. (Note that the class is optional and defaults to "*".) +The allowed syntax for clients to specify the class:name template is +of the form shown below. (Note that "*" is used to denote a generic +wild card, but other wild cards characters are supported, as described +below). + + template explanation + -------- ----------- + class:name exact match of class and name + name match any class with this name + *:name match any class with this name + class:* match any name of this class + *:* match any access point + + +In general, the following wild-cards can be applied to class and name: + + wildcard explanation + -------- ----------- + ? match any character, but there must be one + * match anything, or nothing + [...] match an inclusive set + + +Although the class:name template normally is used to refer to XPA +access points, these also can be specified using their individual +socket identifiers. For inet sockets, the socket identifier is +B<ip:port>, where ip can be the DNS-registered name, +the ASCII IP number (e.g. 123.45.67.890) or the hex IP number +(e.g. 838f3a60). For unix sockets, the identifier is the socket file +name. These socket identifiers are displayed as the fourth argument +in the xpans display of registered access points. For example, +consider the ds9 program started using inet sockets. The xpans name +server will register something like this: + + csh> xpaget xpans + DS9 ds9 gs saord.harvard.edu:3236 eric + +You can access ds9 using ip:3236 in any of the three forms: + + csh> xpaget saord:3236 file + /home/eric/data/snr.ev + + csh> xpaget 123.45.67.890:3236 file + /home/eric/data/snr.ev + + csh> xpaget 838f3a60:3236 file + /home/eric/data/snr.ev + +In the case of unix sockets, the socket identifier is a file: + + csh> xpaget xpans + DS9 ds9 gs /tmp/.xpa/DS9_ds9.2631 eric + + csh> xpaget /tmp/.xpa/DS9_ds9.2631 file + /home/eric/data/snr.ev + +This feature can be useful in distinguishing between multiple +instances of a program that all have the same class:name designation. + + + +=head1 SEE ALSO + + + +See xpa(n) for a list of XPA help pages + + + +=cut diff --git a/xpa/doc/pod/xpausers.pod b/xpa/doc/pod/xpausers.pod new file mode 100644 index 0000000..4c3353b --- /dev/null +++ b/xpa/doc/pod/xpausers.pod @@ -0,0 +1,76 @@ +=pod + +=head1 NAME + + + +B<XPAUsers: Distinguishing Users> + + + +=head1 SYNOPSIS + + + + + +XPA normally distinguishes between users on a given host, but it is possible +to send data to access points belonging to other users. + + + +=head1 DESCRIPTION + + + + + +A single XPA name service typically serves all users on a given +machine. Two users can register the same XPA access points on the +same machine without conflict, because the user's username is +registered with each access point and, by default, programs such as +xpaget and xpaset only process access points of the appropriate user. +For example: + + XPA xpa1 gs 838e2f67:1262 eric + XPA xpa2 gs 838e2f67:1266 eric + XPA xpa1 gs 838e2f67:2523 john + XPA xpa2 gs 838e2f67:2527 john + +Here the users "eric" and "john" both have registered the access +points xpa1 and xpa2. When either "john" or "eric" retrieves +information from xpa1, they will process only the access point +registered in their user name. + + +If you want to access another user's XPA access points on a single +machine, use the -u [user] option on xpaset, xpaget, etc. For example, +if eric executes: + + xpaget -u john xpa1 + +he will access John's xpa1 access point.Use "*" to access all users +on a given machine: + + xpaget -u "*" xpa1 + +Note that the XPA Environment Variable +XPA_NSUSERS can be used to specify the default list of users to +process: + + setenv XPA_NSUSERS "eric,john" + +will cause access points from both "eric" and "john" to be processed +by default. + + + +=head1 SEE ALSO + + + +See xpa(n) for a list of XPA help pages + + + +=cut diff --git a/xpa/doc/pod/xpaxt.pod b/xpa/doc/pod/xpaxt.pod new file mode 100644 index 0000000..34e1049 --- /dev/null +++ b/xpa/doc/pod/xpaxt.pod @@ -0,0 +1,56 @@ +=pod + +=head1 NAME + + + +B<XPAXt: the XPA Interface to Xt (X Windows)> + + + +=head1 SYNOPSIS + + + + +Describes how XPA access points can be added to X Toolkit (Xt) programs. + + + +=head1 DESCRIPTION + + + + + +XPA supports Xt programs: you can call XPANew(), XPACmdNew(), or +XPAInfoNew() within any C routine to add XPA server callbacks to an Xt +program. Since an Xt program has its own event loop call (i.e., +XtAppMainLoop()), it therefore does not need or want to use the XPA +even loop. Thus, in order to add XPA access points to the standard Xt +event loop, the following routine should be called before entering the +loop: + + int XPAXtAddInput(XtAppContext app, XPA xpa) + + +The XPAAddAddInput() routine will add XPA access points to the Xt event +loop by making calls to the standard XtAppAddInput() routine. (If the +XtAppContext argument is NULL, then the alternate XtAddInput() routine +is used instead.) If the xpa argument is NULL, then all active XPA +access points are added to the loop. If xpa is not NULL, then only +the specified access point is added. The latter type of call is used +to add new access points from within a callback, after the program has +entered the XtAppMainLoop() even loop. + + + +=head1 SEE ALSO + + + +See xpa(n) for a list of XPA help pages + + + +=cut diff --git a/xpa/doc/programs.html b/xpa/doc/programs.html new file mode 100644 index 0000000..b37031f --- /dev/null +++ b/xpa/doc/programs.html @@ -0,0 +1,274 @@ +<HTML> +<HEAD> +<TITLE>XPA Programs</TITLE> +</HEAD> +<BODY> +<H2>XPA Programs</H2> + +<H2>Summary</H2> + +<P> +Use the XPA programs to send/receive data to/from XPA servers from the +command line or from scripts. + +<P> +<PRE> + <data> | xpaset [-h] [-i nsinet] [-m method] [-n] [-p] [-s] [-t sval,lval] [-u users] [-v] <template> [paramlist] + + xpaget [-h] [-i nsinet] [-m method] [-s] [-t sval,lval] [-u users] <template> [paramlist] + + xpainfo [-h] [-i nsinet] [-m method] [-n] [-s] [-t sval,lval] [-u users] <template> [paramlist] + + xpaaccess [-c] [-h] [-i nsinet] [-m method] [-n] [-u users] [-v|-V] <template> [type] +</PRE> + +<!-- =defdoc xpaset xpaset 1 --> + +<!-- =section xpaset NAME --> +<H2><A NAME="xpaset">xpaset: send data to one or more XPA servers</A></H2> + +<!-- =section xpaset SYNOPSIS --> +<B> +<PRE> +<data> | xpaset [-h] [-i nsinet] [-m method] [-n] [-p] [-s] [-t sval,lval] [-u users] [-v] <template|host:port> [paramlist] +</PRE> +</B> + +<!-- =section xpaset OPTIONS --> +<P> +<PRE> + -h print help message + -i access XPA point on different machine (override XPA_NSINET) + -m override XPA_METHOD environment variable + -n don't wait for the status message after server completes + -p don't read (or send) buf data from stdin + -s enter server mode + -t [s,l] set short and long timeouts (override XPA_[SHORT,LONG]_TIMEOUT) + -u [users] XPA points can be from specified users (override XPA_NSUSERS) + -v verify message to stdout + --version display version and exit +</PRE> + +<!-- =section xpaset DESCRIPTION --> +<P> +Data read from stdin will be sent to access points matching the +<A HREF="./template.html">template</A> +or host:port. +A set of qualifying parameters can be appended. +<P> +Normally, xpaset reads data input from stdin until EOF and sends those +data to the XPA target, along with parameters entered on the command +line. For example to send a FITS file to the ds9 image display: +<PRE> + cat foo.fits | xpaset ds9 fits +</PRE> +<P> +Sometimes, however, it is desirable to send only parameters to an XPA +access point, without sending data. For such cases, use the -p switch to +indicate that there is no data being send to stdin. For example, to +change the colormap used by the ds9 image display program, use: +<PRE> + csh> xpaset -p ds9 cmap Heat +</PRE> +Of course, this also can be accomplished by sending EOF to stdin in +any of the usual ways: +<PRE> + csh> echo "" | xpaset ds9 cmap Heat + csh> xpaget ds9 cmap Heat < /dev/null + csh> xpaset ds9 cmap Heat + ^D # Ctl-D signals EOF +</PRE> +<P> +The -s switch puts xpaset into server mode, in which commands and data +can be sent to access points without having to run xpaset multiple times. +(Its not clear if this buys you much!) The syntax for sending commands +in server mode is: +<P> +<PRE> + csh> xpaset -s + xpaset ds9 colormap I8 + ^D + xpaset ds9 regions + circle 200 300 40 + circle 300 400 50 + ^D +etc. +</PRE> +After the required "xpaset" command is specified, optional ASCII data +can be appended (as in the region example). A single data/command set is +delimited by ^D. Note that typing ^D when a command is expected terminates +the program. +<P> +NB: server mode only works from the terminal and only ASCII data can be +sent in this way. +<P> +<B>Examples:</B> +<PRE> + csh> xpaset ds9 file < foo.fits + csh> echo "stop" | xpaset myhost:12345 +</PRE> + +<!-- =defdoc xpaget xpaget 1 --> + +<!-- =section xpaget NAME --> +<H2><A NAME="xpaget">xpaget: retrieve data from one or more XPA servers</A></H2> + +<!-- =section xpaget SYNOPSIS --> +<B> +<PRE> +xpaget [-h] [-i nsinet] [-m method] [-s] [-t sval,lval] [-u users] <template|host:port> [paramlist] +</PRE> +</B> + +<!-- =section xpaget OPTIONS --> +<P> +<PRE> + -h print help message + -i access XPA point on different machine (override XPA_NSINET) + -m override XPA_METHOD environment variable + -n don't wait for the status message after server completes + -s enter server mode + -t [s,l] set short and long timeouts (override XPA_[SHORT,LONG]_TIMEOUT) + -u [users] XPA points can be from specified users (override XPA_NSUSERS) + --version display version and exit +</PRE> + +<!-- =section xpaget DESCRIPTION --> +<P> +Data will be retrieved from access points matching the +<A HREF="./template.html">template</A> +or host:port. +A set of qualifying parameters can be appended. +<P> +<B>Examples:</B> +<PRE> + csh> xpaget ds9 images + csh> xpaget myhost.harvard.edu:12345 +</PRE> + +<!-- =defdoc xpainfo xpainfo 1 --> + +<!-- =section xpainfo NAME --> +<H2><A NAME="xpainfo">xpainfo: send short message to one or more XPA servers</A></H2> + +<!-- =section xpainfo SYNOPSIS --> +<B> +<PRE> +xpainfo [-h] [-i nsinet] [-m method] [-n] [-s] [-t sval,lval] [-u users] <template|host:port> [paramlist] +</PRE> +</B> + +<!-- =section xpainfo OPTIONS --> +<P> +<PRE> + -h print help message + -i access XPA point on different machine (override XPA_NSINET) + -m override XPA_METHOD environment variable + -n don't wait for the status message after server completes + -s enter server mode + -t [s,l] set short and long timeouts (override XPA_[SHORT,LONG]_TIMEOUT) + -u [users] XPA points can be from specified users (override XPA_NSUSERS) + --version display version and exit +</PRE> + +<!-- =section xpainfo DESCRIPTION --> +<P> +Info will be sent to access points matching the +<A HREF="./template.html">template</A> +or host:port. +A set of qualifying parameters can be appended. +<P> +<B>Examples:</B> +<PRE> + csh> xpainfo IMAGE ds9 image +</PRE> + +<!-- =defdoc xpaaccess xpaaccess 1 --> + +<!-- =section xpaaccess NAME --> +<H2><A NAME="xpaaccess">xpaaccess: see if template matches registered XPA access points</A></H2> + +<!-- =section xpaaccess SYNOPSIS --> +<B> +<PRE> +xpaaccess [-c] [-h] [-i nsinet] [-m method] [-n] [-t sval,lval] [-u users] -v <template> [type] +</PRE> +</B> + +<!-- =section xpaaccess OPTIONS --> +<P> +<PRE> + -c contact each access point individually + -h print help message + -i access XPA point on different machine (override XPA_NSINET) + -m override XPA_METHOD environment variable + -n return number of matches instead of "yes" or "no" + -t [s,l] set short and long timeouts (override XPA_[SHORT,LONG]_TIMEOUT) + -u [users] XPA points can be from specified users (override XPA_NSUSERS) + -v print info about each successful access point + -V print info or error about each access point + --version display version and exit +</PRE> + +<!-- =section xpaaccess DESCRIPTION --> +<P> +xpaaccess returns "yes" to stdout (with a return error code if 1) if there are +existing XPA access points that match the +<A HREF="./template.html">template</A> +(and optional access type: g,i,s). Otherwise, it returns "no" (with a +return error code of 0). If -n is specified, the number of matches is +returned instead (both to stdout and in the returned error code). If +-v is specified, each access point is displayed to stdout instead of +the number of matches. + +<P> +By default, xpaaccess simply contacts the xpans name server to find +the list of registered access points that match the specified +template. It also checks to make sure the specified types are +supported by that access point. This is the fastest way to determine +available access points. However, an access point might registered but +not yet available, if, for example, the server program has not entered +its event loop to process XPA requests. To find access points that are +guaranteed to be available for processing, use the -c (contact) +switch. With this switch, xpaaccess contacts each matching XPA server +(rather than the name server) to make sure the registered access point +really is ready for processing. In this mode, if an access point is +registered but not available, xpaaccess will pause for a period of +time equal to the XPA_LONG_TIMEOUT, in order to give the server a +chance to ready itself. By default, this timeout is 30 seconds. You +can shorten the time of delay using the -t "short,long" switch. For +example, to shorten the delay time to 2 seconds, use: +<PRE> + xpaaccess -c -t "2,2" ds9 +</PRE> +The first argument is the short delay value, and is ignored in this +operation. The second is the long delay timeout. + +<P> +Note also that the default xpaaccess method (no -c switch) does not +check access control (acls) but rather only checks whether the access +point is both registered with the xpans name server and provides the +specified type of access. In other words, the default xpaaccess could +return 'yes' when you might not actually have access. This mode also +always returns 'yes' for the xpans name server itself, regardless of +whether the name server is active. The -c (contact) switch, which +contacts the access point directly, can and does check the access +control (only for servers using version 2.1 and above) and also +returns the real status of xpans. + +<!-- =section xpaget SEE ALSO --> +<!-- =text See xpa(n) for a list of XPA help pages --> +<!-- =section xpaset SEE ALSO --> +<!-- =text See xpa(n) for a list of XPA help pages --> +<!-- =section xpainfo SEE ALSO --> +<!-- =text See xpa(n) for a list of XPA help pages --> +<!-- =section xpaaccess SEE ALSO --> +<!-- =text See xpa(n) for a list of XPA help pages --> +<!-- =stop --> + +<P> +<A HREF="./help.html">Go to XPA Help Index</A> + +<H5>Last updated: September 10, 2003</H5> +</BODY> +</HTML> diff --git a/xpa/doc/server.html b/xpa/doc/server.html new file mode 100644 index 0000000..2e10b11 --- /dev/null +++ b/xpa/doc/server.html @@ -0,0 +1,833 @@ +<!-- =defdoc xpaserver xpaserver 3 --> +<HTML> +<HEAD> +<TITLE>XPA Server API</TITLE> +</HEAD> +<BODY> + +<!-- =section xpaserver NAME --> +<H2><A NAME="xpaserver">XPAServer: The XPA Server-side Programming Interface</A></H2> + +<!-- =section xpaserver SYNOPSIS --> +<H2>Summary</H2> +A description of the XPA server-side programming interface. + +<!-- =section xpaserver DESCRIPTION --> +<H2><A NAME="intro">Introduction to XPA Server Programming</H2></A> +<P> +Creating an XPA server is easy: you generally only need to call the +XPANew() subroutine to define a named XPA access point and set up the +send and receive callback routines. You then enter an event loop such +as XPAMainLoop() to field XPA requests. +<PRE> + #include <xpa.h> + + XPA <A HREF="./server.html#xpanew">XPANew</A>(char *class, char *name, char *help, + int (*send_callback)(), void *send_data, char *send_mode, + int (*rec_callback)(), void *rec_data, char *rec_mode); + + XPA <A HREF="./server.html#xpacmdnew">XPACmdNew</A>(char *class, char *name); + + XPACmd <A HREF="./server.html#xpacmdadd">XPACmdAdd</A>(XPA xpa, + char *name, char *help, + int (*send_callback)(), void *send_data, char *send_mode, + int (*rec_callback)(), void *rec_data, char *rec_mode); + + void <A HREF="./server.html#xpacmddel">XPACmdDel</A>(XPA xpa, XPACmd cmd); + + XPA <A HREF="./server.html#xpainfonew">XPAInfoNew</A>(char *class, char *name, + int (*info_callback)(), void *info_data, char *info_mode); + + int <A HREF="./server.html#xpafree">XPAFree</A>(XPA xpa); + + void <A HREF="./server.html#xpamainloop">XPAMainLoop</A>(void); + + int <A HREF="./server.html#xpapoll">XPAPoll</A>(int msec, int maxreq); + + void <A HREF="./server.html#xpaatexit">XPAAtExit</A>(void); + + void <A HREF="./server.html#xpacleanup">XPACleanup</A>(void); + +</PRE> + +<H2>Introduction</H2> + +To use the XPA application programming interface, a software developer +generally will include the xpa.h definitions file: +<PRE> + #include <xpa.h> +</PRE> +in the software module that defines or accesses an XPA access point, and +then will link against the libxpa.a library: +<PRE> + gcc -o foo foo.c libxpa.a +</PRE> +XPA has been compiled using both C and C++ compilers. + +<P> +A server program generally defines an XPA access point by calling the +XPANew() routine and specifies "send" and/or "receive" callback +procedures to be executed by the program when an external process +either sends data or commands to this access point or requests data or +information from this access point. A program also can define several +sub-commands for a single access point by calling XPACmdNew() and +XPACmdAdd() instead. Having defined one or more public access points +in this way, an XPA server program enters its usual event loop (or +uses the standard XPA event loop). + +<!-- =defdoc xpanew xpanew 3 --> + +<!-- =section xpanew NAME --> +<H2><A NAME="xpanew">XPANew: create a new XPA access point</A></H2> + +<!-- =section xpanew SYNOPSIS --> +<B> +<PRE> + #include <xpa.h> + + XPA XPANew(char *class, char *name, char *help, + int (*send_callback)(), + void *send_data, char *send_mode, + int (*rec_callback)(), + void *rec_data, char *rec_mode); +</PRE> +</B> + +<!-- =section xpanew DESCRIPTION --> +<P> +Create a new XPA public access point with the class:name +identifier <A HREF="./template.html">template</A> +and enter this access point into the XPA name server, so that it +can be accessed by external processes. XPANew() returns an XPA struct. +Note that the length of the class and name designations must be less +than or equal to 1024 characters each. + +<P> +The XPA name server daemon, xpans, will be started automatically if it +is not running already (assuming it can be found in the path). The +program's ip address and listening port are specified by the +environment variable XPA_NSINET, which takes the form <ip>:<port>. If +no such environment variable exists, then xpans is started on the +current machine listening on port 14285. It also uses 14286 as a +known port for its public access point (so that routines do not have +to go to the name server to find the name server ip and port!) +As of XPA 2.1.1, version information is exchanged between the xpans +process and the new access point. If the access point uses an XPA +major/minor version newer than xpans, a warning is issued by both processes, +since mixing of new servers and old xpa programs (xpaset, xpaget, +xpans, etc.) is not likely to work. You can turn off the warning +message by setting the XPA_VERSIONCHECK environment variable to "false". + +<P> +The help string is meant to be returned by a request from xpaget: +<PRE> + xpaget class:name -help +</PRE> +<P> +A send_callback and/or a receive_callback can be specified; at +least one of them must be specified. + +<P> +A send_callback can be specified that will be executed in response to +an external request from the xpaget program, the XPAGet() routine, or +XPAGetFd() routine. This callback is used to send data to the +requesting client. + +<P> +The calling sequence for send_callback() is: +<PRE> + int send_callback(void *send_data, void *call_data, + char *paramlist, char **buf, size_t *len) + { + XPA xpa = (XPA)call_data; + ... + return(stat); + } +</PRE> +<P> +The send_mode string is of the form: "key1=value1,key2=value2,..." +The following keywords are recognized: +<PRE> + key value default explanation + ------ -------- -------- ----------- + acl true/false true enable access control + freebuf true/false true free buf after callback completes +</PRE> +<P> +The call_data should be recast to the XPA struct as shown. In +addition, client-specific data can be passed to the callback in +send_data. + +<P> +The paramlist will be supplied by the client as qualifying parameters +for the callback. There are two ways in which the send_callback() +routine can send data back to the client: + +<P> +1. The send_callback() routine can fill in a buffer and pass back a +pointer to this buffer. An integer len also is returned to specify the +number of bytes of data in buf. XPA will send this buffer to the +client after the callback is complete. + +<P> +2. The send_callback can send data directly to the client by writing +to the fd pointed by the macro: +<PRE> + xpa_datafd(xpa) +</PRE> +<P> +Note that this fd is of the kind returned by socket() or open(). + +<P> +If a buf has been allocated by a standard malloc routine, filled, and +returned to XPA, then freebuf generally is set so that the buffer will +be freed automatically when the callback is completed and data has +been sent to the client. If a static buf is returned, freebuf should +be set to false to avoid a system error when freeing static storage. +Note that default value for freebuf implies that the callback will +allocate a buffer rather than use static storage. + +<P> +On the other hand, if buf is dynamically allocated using a method +other than a standard malloc/calloc/realloc routine (e.g. using Perl's +memory allocation and garbage collection scheme), then it is necessary +to tell XPA how to free the allocated buffer. To do this, use the +XPASetFree() routine within your callback: +<PRE> + void XPASetFree(XPA xpa, void (*myfree)(void *), void *myfree_ptr); +</PRE> +The first argument is the usual XPA handle. The second argument is the +special routine to call to free your allocated memory. The third +argument is an optional pointer. If not NULL, the specified free +routine is called with that pointer as its sole argument. If NULL, the +free routine is called with the standard buf pointer as its sole +argument. This is useful in cases where there is a mapping between the +buffer pointer and the actual allocated memory location, and the +special routine is expecting to be passed the former. + +<P> +If, while the callback performs its processing, an error occurs that +should be communicated to the client, then the routine XPAError should be +called: +<PRE> + XPAError(XPA xpa, char *s); +</PRE> +<P> +where s is an arbitrary error message. The returned error message +string will be of the form: +<PRE> + XPA$ERROR [error] (class:name ip:port) +</PRE> +<P> +If the callback wants to send a specific acknowledgment message back +to the client, the routine XPAMessage can be called: +<PRE> + XPAMessage(XPA xpa, char *s); +</PRE> +<P> +where s is an arbitrary error message. The returned error message +string will be of the form: +<PRE> + XPA$MESSAGE [message] (class:name ip:port) +</PRE> +<P> +Otherwise, a standard acknowledgment is sent back to the client +after the callback is completed. + +<P> +The callback routine should return 0 if no error occurs, or -1 to +signal an error. + +<P> +A receive_callback can be specified that will be executed in response +to an external request from the xpaset program, or the XPASet (or +XPASetFd()) routine. This callback is used to process data received +from an external process. + +<P> +The calling sequence for receive_callback is: +<PRE> + int receive_callback(void *receive_data, void *call_data, + char *paramlist, char *buf, size_t len) + { + XPA xpa = (XPA)call_data; + ... + return(stat); + } +</PRE> +<P> +The mode string is of the form: "key1=value1,key2=value2,..." +The following keywords are recognized: +<PRE> + key value default explanation + ------ -------- -------- ----------- + acl true/false true enable access control + buf true/false true server expects data bytes from client + fillbuf true/false true read data into buf before executing callback + freebuf true/false true free buf after callback completes +</PRE> +<P> +The call_data should be recast to the XPA struct as shown. In +addition, client-specific data can be passed to the callback in +receive_data. + +<P> +The paramlist will be supplied by the client. In addition, if the +receive_mode keywords buf and fillbuf are true, then on entry into the +receive_callback() routine, buf will contain the data sent by the +client. If buf is true but fillbuf is false, it becomes the callback's +responsibility to retrieve the data from the client, using the data fd +pointed to by the macro xpa_datafd(xpa). If freebuf is true, then buf +will be freed when the callback is complete. + +<P> +If, while the callback is performing its processing, an error occurs +that should be communicated to the client, then the routine XPAError +can be called: +<PRE> + XPAError(XPA xpa, char *s); +</PRE> +<P> +where s is an arbitrary error message. + +<P> +The callback routine should return 0 if no error occurs, or -1 to +signal an error. + +<!-- =defdoc xpacmdnew xpacmdnew 3 --> + +<!-- =section xpacmdnew NAME --> +<H2><A NAME="xpacmdnew">XPACmdNew: create a new XPA public access point for commands</A></H2> + +<!-- =section xpacmdnew SYNOPSIS --> +<B> +<PRE> + #include <xpa.h> + + XPA XPACmdNew(char *class, char *name); +</PRE> +</B> + +<!-- =section xpacmdnew DESCRIPTION --> +<P> +Create a new XPA public access point for commands that will share a +common identifier class:name. Enter this access point into the XPA +name server, so that it can be accessed by external processes. +XPACmdNew() returns an XPA struct. + +<P> +It often is more convenient to have one public access point that can +manage a number of commands, rather than having individual access +points for each command. For example, it is easier to command the +ds9 image display using: +<PRE> + echo "colormap I8" | xpaset ds9 + echo "scale log" | xpaset ds9 + echo "file foo.fits" | xpaset ds9 +</PRE> +<P> +then to use: +<PRE> + echo "I8" | xpaset ds9_colormap + echo "log" | xpaset ds9_scale + echo "foo.fits" | xpaset ds9_file +</PRE> +<P> +In the first case, the commands remain the same regardless of the +target XPA name. In the second case, the command names must change +for each instance of ds9. That is, if a second instance of ds9 +called DS9 were running, it would be commanded either as: +<PRE> + echo "colormap I8" | xpaset DS9 + echo "scale log" | xpaset DS9 + echo "file foo.fits" | xpaset DS9 +</PRE> +<P> +or as: +<PRE> + echo "I8" | xpaset DS9_colormap + echo "log" | xpaset DS9_scale + echo "foo.fits" | xpaset DS9_file +</PRE> +<P> +Thus, in cases where a program is going to manage many commands, it +generally is easier to define them as commands associated with the +XPACmdNew() routine, rather than as separate access points using +XPANew(). + +<P> +When XPACmdNew() is called, only the class:name identifier is +specified. Each sub-command is subsequently defined using the +XPACmdAdd() routine. + +<!-- =defdoc xpacmdadd xpacmdadd 3 --> + +<!-- =section xpacmdadd NAME --> +<H2><A NAME="xpacmdadd">XPACmdAdd: add a command to an XPA command public access point</A></H2> + +<!-- =section xpacmdadd SYNOPSIS --> +<B> +<PRE> + #include <xpa.h> + + XPACmd XPACmdAdd(XPA xpa, char *name, char *help, + int (*send_callback)(), + void *send_data, char *send_mode, + int (*rec_callback)(), + void *rec_data, char *rec_mode); +</PRE> +</B> + +<!-- =section xpacmdadd DESCRIPTION --> +<P> +Add a command to an XPA command access point. The XPA argument specifies the +XPA struct returned by a call to XPANewCmd(). The name argument is the +name of the command. The other arguments function identically to the +arguments in the XPANew() command, i.e., the send_callback and rec_callback +routines have identical calling sequences to their XPANew() counterparts, +with the exceptions noted below. + +<P> +When help is requested for a command access point using: +<PRE> + xpaget -h class:name +</PRE> +<P> +all of the command help strings are listed. To get help for a given +command, use: +<PRE> + xpaget -h class:name cmd +</PRE> +<P> +Also, the acl keyword in the send_mode and receive_mode strings is +global to the access point, not local to the command. Thus, the value +for the acl mode should be the same in all send_mode (or receive_mode) +strings for each command in a command access point. (The acl for +send_mode need not be the same as the acl for receive_mode, though). + +<!-- =defdoc xpacmddel xpacmddel 3 --> + +<!-- =section xpacmddel NAME --> +<H2><A NAME="xpacmddel">XPACmdDel: remove a command from an XPA command public access point</A></H2> + +<!-- =section xpacmddel SYNOPSIS --> +<B> +<PRE> + #include <xpa.h> + + void XPACmdDel(XPA xpa, XPACmd cmd); +</PRE> +</B> + +<!-- =section xpacmddel DESCRIPTION --> +<P> +This routine removes a command from the list of available commands in +a given XPA. That command will no longer be available for processing. + +<!-- =defdoc xpainfonew xpainfonew 3 --> + +<!-- =section xpainfonew NAME --> +<H2><A NAME="xpainfonew">XPAInfoNew: define an XPA info public access point</A></H2> + +<!-- =section xpainfonew SYNOPSIS --> +<B> +<PRE> + #include <xpa.h> + + XPA XPAInfoNew(char *class, char *name, + int (*info_callback)(), + void *info_data, char *info_mode); +</PRE> +</B> + +<!-- =section xpainfonew DESCRIPTION --> +<P> +[NB: this is an experimental interface, new to XPA 2.0, whose value +and best use is evolving.] + +<P> +A program can register interest in receiving a short message about a +particular topic from any other process that cares to send such a +message. Neither has to be an XPA server. For example, if a user +starts to work with a new image file called new.fits, she might +wish to alert interested programs about this new file by sending a +short message using xpainfo: +<PRE> + xpainfo IMAGEFILE /data/new.fits +</PRE> + +<P> +In this example, each process that has used the XPAInfoNew() call to +register interest in messages associated with the identifier IMAGEFILE +will have its info_callback() executed with the following calling +sequence: +<PRE> + int info_cb(void *info_data, void *call_data, char *paramlist) + { + XPA xpa = (XPA)call_data; + } +</PRE> +<P> +The arguments passed to this routine are equivalent to those sent in +the send_callback() routine. The main difference is that there is no +buf sent to the info callback: this mechanism is meant for short +announcement of messages of interest to many clients. + +<P> +The mode string is of the form: "key1=value1,key2=value2,..." +The following keywords are recognized: +<PRE> + key value default explanation + ------ -------- -------- ----------- + acl true/false true enable access control +</PRE> +<P> +Because no buf is passed to this callback, the usual buf-related keywords +are not applicable here. + +<P> +The information sent in the parameter list is arbitrary. However, we +envision sending information such as file names or XPA access points +from which to collect more data. Note that the xpainfo program and +the XPAInfo() routine that cause the info_callback to execute do not +wait for the callback to complete before returning. + +<!-- =defdoc xpafree xpafree 3 --> + +<!-- =section xpafree NAME --> +<H2><A NAME="xpafree">XPAFree: remove an XPA public access point</A></H2> + +<!-- =section xpafree SYNOPSIS --> +<PRE> +<B> + #include <xpa.h> + + int XPAFree(XPA xpa); +</B> +</PRE> + +<!-- =section xpafree DESCRIPTION --> +<P> +Remove the specified XPA public access point from the name server and +free all associated storage. Note that removal from the name server +happens automatically when the process terminates, so this call is not +generally needed. It is used when public access points are being +defined temporarily and then destroyed when no longer needed. For +example, ds9 temporarily creates a public access point when it +loads a new image for display and destroys it when the image is +unloaded. + +<!-- =defdoc xpamainloop xpamainloop 3 --> + +<!-- =section xpamainloop NAME --> +<H2><A NAME="xpamainloop">XPAMainLoop: optional main loop for XPA</A></H2> + +<!-- =section xpamainloop SYNOPSIS --> +<B> +<PRE> + #include <xpa.h> + + void XPAMainLoop(); +</PRE> +</B> + +<!-- =section xpamainloop DESCRIPTION --> +<P> +Once XPA access points have been defined, a program must enter an +event loop to watch for requests from external programs. This can be +done in a variety of ways, depending on whether the event loop is +processing events other than XPA events. In cases where there are no +non-XPA events to be processed, the program can simply call the +XPAMainLoop() event loop. This loop is implemented essentially as +follows (error checking is simplified in this example): +<PRE> + FD_ZERO(&readfds); + while( XPAAddSelect(NULL, &readfds) ){ + if( sgot = select(swidth, &readfds, NULL, NULL, NULL) >0 ) + XPAProcessSelect(&readfds, 0); + else + break; + FD_ZERO(&readfds); + } +</PRE> +<P> +The XPAAddSelect() routine sets up the select() readfds variable so +that select() will wait for I/O on all the active XPA channels. It +returns the number of XPAs that are active; the loop will end when +there are no active XPAs. The standard select() routine is called to +wait for an external I/O request. Since no timeout struct is passed +in argument 5, the select() call hangs until there is an external +request. When an external I/O request is made, the XPAProcessSelect() +routine is executed to process the pending requests. In this routine, +the maxreq value determines how many requests will be processed: if +maxreq <=0, then all currently pending requests will be processed. +Otherwise, up to maxreq requests will be processed. (The most usual +values for maxreq is 0 to process all requests.) + +<P> +If a program has its own Unix select() loop, then XPA access points can +be added to it by using a variation of the standard XPAMainLoop: +<PRE> + XPAAddSelect(xpa, &readfds); + [app-specific ...] + if( select(width, &readfds, ...) ){ + XPAProcessSelect(&readfds, maxreq); + [app-specific ...] + FD_ZERO(&readfds); + } +</PRE> +<P> +XPAAddSelect() is called before select() to add the access points. +If the first argument is NULL, then all active XPA access points +are added. Otherwise only the specified access point is added. +After select() is called, the XPAProcessSelect() routine can be called +to process XPA requests. Once again, the maxreq value determines how +many requests will be processed: if maxreq <=0, then all currently +pending requests will be processed. Otherwise, up to maxreq requests +will be processed. + +<P> +XPA access points can be added to +<A HREF="./xt.html">Xt event loops</A> (using XtAppMainLoop()) +and +<A HREF="./tcl.html">Tcl/Tk event loops</A> (using vwait and the Tk loop). +When using XPA with these event loops, you only need to call: +<PRE> +int XPAXtAddInput(XtAppContext app, XPA xpa) +</PRE> +or +<PRE> + int XPATclAddInput(XPA xpa) +</PRE> +respectively before entering the loop. + +<!-- =defdoc xpapoll xpapoll 3 --> + +<!-- =section xpapoll NAME --> +<H2><A NAME="xpapoll">XPAPoll: execute existing XPA requests</A></H2> + +<!-- =section xpapoll SYNOPSIS --> +<B> +<PRE> + #include <xpa.h> + + int XPAPoll(int msec, int maxreq); +</PRE> +</B> + +<!-- =section xpapoll DESCRIPTION --> +<P> +It is sometimes desirable to implement a polling loop, i.e., where one +checks for and processes XPA requests without blocking. For this +situation, use the XPAPoll() routine: +<PRE> + XPAPoll(int msec, int maxreq); +</PRE> +<P> +The XPAPoll() routine will perform XPAAddSelect() and select(), but with a +timeout specified in millisecs by the msec argument. If one or more +XPA requests are made before the timeout expires, the XPAProcessSelect() +routine is called to process those requests. The maxreq value determines +how many requests will be processed: if maxreq < 0, then no events are +processed, but instead, the return value indicates the number of events +that are pending. If maxreq == 0, then all currently pending requests +will be processed. Otherwise, up to maxreq requests will be processed. +(The most usual values for maxreq are 0 to process all requests and 1 +to process one request). + +<!-- =defdoc xpaatexit xpaatexit 3 --> + +<!-- =section xpaatexit NAME --> +<H2><A NAME="xpaatexit">XPAAtExit: install exit handler</A></H2> + +<!-- =section xpaatexit SYNOPSIS --> +<PRE> +<B> + #include <xpa.h> + + void XPAAtExit(void); +</B> +</PRE> + +<!-- =section xpaatexit DESCRIPTION --> +<P> +XPAAtExit() will install an exit handler using atexit() to run XPAFree on all +XPA access points. This might be useful in cases where Unix sockets are being +used: if an explicit call to XPAFree() is not made by the program, the Unix +socket file will not be deleted immediately without an atexit handler. (NB: this +call should not be made in a Tcl/Tk application. Accessing the Tcl native file +system after Tcl has shut down all file systems causes the Tcl/Tl program to +crash). + +<!-- =defdoc xpacleanup xpacleanup 3 --> + +<!-- =section xpacleanup NAME --> +<H2><A NAME="xpacleanup">XPACleanup: release reserved XPA memory</A></H2> + +<!-- =section xpacleanup SYNOPSIS --> +<PRE> +<B> + #include <xpa.h> + + void XPACleanup(void); +</B> +</PRE> + +<!-- =section xpacleanup DESCRIPTION --> +<P> +When XPA is initialized, it allocates a small amount of memory for the +access control list, temp directory path, and reserved commands. This +memory is found by valgrind to be "still reachable", meaning that "your +program didn't free some memory it could have". Calling the +XPACleanup() routine before exiting the program will free this memory +and make valgrind happy. + +<!-- =defdoc xpamacros xpamacros 3 --> + +<!-- =section xpamacros NAME --> +<H2><A NAME="macros">XPA Server Callback Macros</A></H2> + +<!-- =section xpamacros SYNOPSIS --> +<B> +<PRE> + #include <xpa.h> + + xpa_class, xpa_name, xpa_method, xpa_cmdfd, xpa_datafd, + xpa_sendian, xpa_cendian +</PRE> +</B> + +<!-- =section xpamacros DESCRIPTION --> +<P> +Server routines have access to information about the XPA being called via +the following macros (each of which takes the xpa handle as an argument): +<PRE> + macro explanation + ------ ----------- + xpa_class class of this xpa + xpa_name name of this xpa + xpa_method method string (inet or local connect info) + xpa_cmdfd fd of command socket + xpa_datafd fd of data socket + xpa_sendian endian-ness of server ("little" or "big") + xpa_cendian endian-ness of client ("little" or "big" +</PRE> +<P> +The argument to these macros is the call_data pointer that is passed +to the server procedure. This pointer should be type case to XPA +in the server routine: +<PRE> + XPA xpa = (XPA)call_data; +</PRE> + +<P> +The most important of these macros is xpa_datafd(). A server routine +that sets "fillbuf=false" in receive_mode or send_mode can use this +macro to perform I/O directly to/from the client, rather than using +buf. + +<P> +The xpa_cendian and xpa_sendian macros can be used together to determine +if the data transferred from the client is byte swapped with respect +to the server. Values for these macros are: "little", "big", or "?". +In order to do a proper conversion, you still need to know the format +of the data (i.e., byte swapping is dependent on the size of the data +element being converted). + +<!-- =defdoc xparace xparace 3 --> + +<!-- =section xparace NAME --> +<H2><A NAME="race">XPA Race Conditions</A></H2> + +<!-- =section xparace SYNOPSIS --> +Potential XPA race conditions and how to avoid them. + +<!-- =section xparace DESCRIPTION --> +<P> +Currently, there is only one known circumstance in which XPA can get +(temporarily) deadlocked in a race condition: if two or more XPA +servers send messages to one another using an XPA client routine such +as XPASet(), they can deadlock while each waits for the other server +to respond. (This can happen if the servers call XPAPoll() with a +time limit, and send messages in between the polling call.) The +reason this happens is that both client routines send a string to the +other server to establish the handshake and then wait for the server +response. Since each client is waiting for a response, neither is able +to enter its event-handling loop and respond to the other's +request. This deadlock will continue until one of the timeout periods +expire, at which point an error condition will be triggered and the +timed-out server will return to its event loop. + +<P> +Starting with version 2.1.6, this rare race condition can be +avoided by setting the XPA_IOCALLSXPA environment variable for servers +that will make client calls. Setting this variable causes all XPA +socket IO calls to process outstanding XPA requests whenever the +primary socket is not ready for IO. This means that a server making a +client call will (recursively) process incoming server requests while +waiting for client completion. It also means that a server callback +routine can handle incoming XPA messages if it makes its own XPA call. +The semi-public routine oldvalue=XPAIOCallsXPA(newvalue) can be used +to turn this behavior off and on temporarily. Passing a 0 will turn +off IO processing, 1 will turn it back on. The old value is returned +by the call. + +<P> +By default, the XPA_IOCALLSXPA option is turned off, because we judge +that the added code complication and overhead involved will not be +justified by the amount of its use. Moreover, processing XPA requests +within socket IO can lead to non-intuitive results, since incoming +server requests will not necessarily be processed to completion in the +order in which they are received. + +<P> +Aside from setting XPA_IOCALLSXPA, the simplest way to avoid this race +condition is to multi-process: when you want to send a client message, +simply start a separate process to call the client routine, so that +the server is not stopped. It probably is fastest and easiest to use +fork() and then have the child call the client routine and exit. But +you also can use either the system() or popen() routine to start one +of the command line programs and do the same thing. Alternatively, you +can use XPA's internal launch() routine instead of system(). Based on +fork() and exec(), this routine is more secure than system() because +it does not call /bin/sh. + +<P> +Starting with version 2.1.5, you also can send an XPAInfo() message with +the mode string "ack=false". This will cause the client to send a message +to the server and then exit without waiting for any return message from +the server. This UDP-like behavior will avoid the server deadlock when +sending short XPAInfo messages. + +<!-- =section xpaserver SEE ALSO --> +<!-- =text See xpa(n) for a list of XPA help pages --> +<!-- =section xpanew SEE ALSO --> +<!-- =text See xpa(n) for a list of XPA help pages --> +<!-- =section xpacmdnew SEE ALSO --> +<!-- =text See xpa(n) for a list of XPA help pages --> +<!-- =section xpacmdadd SEE ALSO --> +<!-- =text See xpa(n) for a list of XPA help pages --> +<!-- =section xpacmddel SEE ALSO --> +<!-- =text See xpa(n) for a list of XPA help pages --> +<!-- =section xpainfonew SEE ALSO --> +<!-- =text See xpa(n) for a list of XPA help pages --> +<!-- =section xpafree SEE ALSO --> +<!-- =text See xpa(n) for a list of XPA help pages --> +<!-- =section xpacleanup SEE ALSO --> +<!-- =text See xpa(n) for a list of XPA help pages --> +<!-- =section xpamainloop SEE ALSO --> +<!-- =text See xpa(n) for a list of XPA help pages --> +<!-- =section xpapoll SEE ALSO --> +<!-- =text See xpa(n) for a list of XPA help pages --> +<!-- =section xpamacros SEE ALSO --> +<!-- =text See xpa(n) for a list of XPA help pages --> +<!-- =section xparace SEE ALSO --> +<!-- =text See xpa(n) for a list of XPA help pages --> +<!-- =stop --> + +<P> +<A HREF="./help.html">Go to XPA Help Index</A> + +<H5>Last updated: September 10, 2003</H5> +</BODY> +</HTML> diff --git a/xpa/doc/sman/xpa4.index b/xpa/doc/sman/xpa4.index Binary files differnew file mode 100644 index 0000000..7c5a98a --- /dev/null +++ b/xpa/doc/sman/xpa4.index diff --git a/xpa/doc/sman/xpa4.index.prop b/xpa/doc/sman/xpa4.index.prop Binary files differnew file mode 100644 index 0000000..0d0dd69 --- /dev/null +++ b/xpa/doc/sman/xpa4.index.prop diff --git a/xpa/doc/sman/xpa4.index.version b/xpa/doc/sman/xpa4.index.version new file mode 100644 index 0000000..accb620 --- /dev/null +++ b/xpa/doc/sman/xpa4.index.version @@ -0,0 +1,2 @@ +SMAN_DATA_VERSION 1.2 +VERSION 1.01 diff --git a/xpa/doc/sman/xpa8.index b/xpa/doc/sman/xpa8.index Binary files differnew file mode 100644 index 0000000..e9f998c --- /dev/null +++ b/xpa/doc/sman/xpa8.index diff --git a/xpa/doc/sman/xpa8.index.prop b/xpa/doc/sman/xpa8.index.prop Binary files differnew file mode 100644 index 0000000..54b3108 --- /dev/null +++ b/xpa/doc/sman/xpa8.index.prop diff --git a/xpa/doc/sman/xpa8.index.version b/xpa/doc/sman/xpa8.index.version new file mode 100644 index 0000000..accb620 --- /dev/null +++ b/xpa/doc/sman/xpa8.index.version @@ -0,0 +1,2 @@ +SMAN_DATA_VERSION 1.2 +VERSION 1.01 diff --git a/xpa/doc/sman_conf.tmpl b/xpa/doc/sman_conf.tmpl new file mode 100644 index 0000000..abac8e4 --- /dev/null +++ b/xpa/doc/sman_conf.tmpl @@ -0,0 +1,96 @@ +# $Id: sman-defaults.conf,v 1.33 2006/05/02 02:09:18 joshr Exp $ +# by Josh Rabinowitz, 2005-2006. <joshr> +# this is the default sman configuration file. +# if you need to make changes, copy this file to +# /usr/local/etc/sman.conf and make changes to that file. +# NOTE: if you do use a custom sman.conf you may need to manually +# NOTE: merge changes from this file to your configuration file +# NOTE: after upgrading sman versions + +# See 'perldoc sman.conf' for more documentation + +# sman-defaults.conf +# holds the defaults for sman. +# the directive names are case-insensitive + +SWISHECMD @SW@ -v 0 + +# MANCMD specifies how to manually convert the manpages to +# ASCII. For 'manual' parsing. +# %F is the quoted full [F]ilename of the manpage (ie, '/usr/share/man/man1/ls.1.gz) +# %S is the quoted [S]ection of the manpage (ie, '1') +# %C is the quoted (apparent) [C]ommand of the manpage (ie, 'ls') + +# NOTE: lack of a MANCMD (or a value of AUTOCONFIG) causes sman-update +# to autoconfigure the value of MANCMD. It will most likely choose +# one of the below: + +# this works for most linuxes we've tested. ie 'man /man/man1/ls.1' +# MANCMD man -c %F +# this works for freebsd 4.4 and Mac OS X. ie 'man 1 ls' +#MANCMD man -c %S %C +# -c means reparse man page sources (for line re-wrapping) + +# works for Solaris and OS X +MANCMD man -s %S %C + +# the COL program is used to strip out backspaces and +# such from the MAN output. + +COLCMD col -b + +# all vars starting with ENV_ get set in the +# environment, sans the ENV_ prefix. + +# Try to make MAN wrap lines at 256 chars (not 80!) +ENV_MANWIDTH 256 + +# where to put sman's temp files. +# (Use SWISHE_TMPDIR to set affect SWISH-E at index time) + +TMPDIR /tmp + +# meta and property aliases. If your XML has different tags. +# refentrytitle, manvolnum and refpurpose are the names from rman +# each ALIASES line turns into 2 lines for SWISH-E like this: +#MetaNameAlias swishtitle refentrytitle +#PropertyNameAlias swishtitle refentrytitle + +TITLEALIASES RefEntryTitle +SECALIASES ManVolNum +DESCALIASES RefPurpose +#MANPAGEALIASES swishdefault + +# All parameters beginning with SWISHE_ have the SWISHE_ prefix stripped +# and are written into a tmp config file for SWISH-E at index time. + +# SWISHE_IndexFile is also used by sman as which index to search. + +# SWISHE_IndexFile specifies which index to create and search +# NOTE: if the containing dir (ie, /var/lib/sman) is owned by an unprivileged +# user, then sman-update can be run as that user. + +SWISHE_IndexFile /var/lib/sman/sman.index + +# these have 'SWISHE_' stripped off and are used +# when indexing the man pages. + +SWISHE_IndexComments no + # don't index text in comments + +# These are important! You probably don't want to mess with these. +SWISHE_IndexPointer "format=%V;" + # for future use. %V becomes $Sman::SMAN_DATA_VERSION +#SWISHE_FuzzyIndexingMode Stem + # above was deprecated in 2.4.3, does not work in 2.4.4 +SWISHE_FuzzyIndexingMode Stemming_en2 +SWISHE_MetaNames desc sec swishtitle manpage digest +SWISHE_PropertyNames desc sec manpage digest + +# SWISHE_IgnoreWords File: ./stopwords/english.txt +# allow _ and : but not / +# .'s in middle of word are word chars, for files like 'named.conf'. +SWISHE_WordCharacters 0123456789abcdefghijklmnopqrstuvwxyz_:. +SWISHE_BeginCharacters 0123456789abcdefghijklmnopqrstuvwxyz_: +SWISHE_EndCharacters 0123456789abcdefghijklmnopqrstuvwxyz_: +SWISHE_IgnoreTotalWordCountWhenRanking 0 diff --git a/xpa/doc/szlong.c b/xpa/doc/szlong.c new file mode 100644 index 0000000..b0e84bc --- /dev/null +++ b/xpa/doc/szlong.c @@ -0,0 +1,8 @@ +#include <stdio.h> + +int main(int argc, char **argv) +{ + fprintf(stdout, "%d\n", (int)sizeof(long)); + return 0; +} + diff --git a/xpa/doc/tcl.html b/xpa/doc/tcl.html new file mode 100644 index 0000000..8feb46a --- /dev/null +++ b/xpa/doc/tcl.html @@ -0,0 +1,249 @@ +<!-- =defdoc xpatcl xpatcl n --> +<HTML> +<HEAD> +<TITLE>XPA/Tcl Interface</TITLE> +</HEAD> +<BODY> + +<!-- =section xpatcl NAME --> +<H2><A NAME="xpatcl">XPATcl: the XPA Interface to the Tcl/Tk Environment</A></H2> + +<!-- =section xpatcl SYNOPSIS --> +<H2>Summary</H2> + +<P> +Tcl/Tk programs can act as XPA clients and/or servers using the Tcl +interface to XPA that is contained in the libtclxpa.so shared object. + +<H2>Server Routines</H2> + +<PRE> + set xpa [xpanew class name help sproc sdata smode rproc rdata rmode] + xpafree xpa + set xpa [xpanew class name help iproc idata imode] + set xpa [xpacmdnew class name] + xpacmdadd xpa name help sproc sdata smode rproc rdata rmode + xpacmddel xpa cmd + set val [xparec xpa option] + options: name, class, method, cmdfd, datafd, cmdchan, datachan + xpasetbuf xpa buf len + xpaerror xpa message + xpamessage xpa message +</PRE> + +<H2>Client Routines</H2> + +<PRE> + set xpa [xpaopen mode] + xpaclose xpa + set got [xpaget xpa template paramlist mode bufs lens names errs n] + set got [xpaget xpa template paramlist mode chans names errs n] + set got [xpaset xpa template paramlist mode buf len names errs n] + set got [xpasetfd xpa template paramlist mode chan names errs n] + set got [xpainfo xpa template paramlist mode names errs n] + # NB: 2.1 calling sequence change + # set got [xpaaccess template type] (2.0.5) + set got [xpaaccess xpa template paramlist mode names errs n] + set got [xpanslookup template type classes names methods] +</PRE> + +<!-- =section xpatcl DESCRIPTION --> +<H2>Description</H2> +<P> +You can call XPANew(), XPACmdNew(), or XPAInfoNew() within a C +routine to add C-based XPA server callbacks to a TCL/Tk program that +uses a Tcl/Tk event loop (either vwait() or the Tk event loop); +Such a program does not need or want to use the XPA event loop. +Therefore, in order to add XPA access points to the Tcl/Tk loop, the +following routine should be called beforehand: +<PRE> + int XPATclAddInput(XPA xpa); +</PRE> +<P> +Normally, the xpa argument is NULL, meaning that all current XPA +access points are registered with the event loop. However, if a +single XPA access point is to be added (i.e., after the event loop is +started) then the handle of that XPA access point can be passed to +this routine. + +<P> +The significance of the XPA/TCL interface goes beyond the support for +using XPA inside C code. The interface allows you to write XPA +servers and to make calls to the XPA client interface within the Tcl +environment using the Tcl language directly. The XPA/Tcl +interface can be loaded using the following package command: +<PRE> + package require tclxpa 2.0 +</PRE> +Alternatively, you can load the shared object (called libtclxpa.so ) directly: +<PRE> + load .../libtclxpa.so tclxpa +</PRE> +<P> +Once the tclxpa package is loaded, you can use Tcl versions of XPA +routines to define XPA servers or make client XPA calls. The +interface for these routines is designed to match the Unix XPA +interface as nearly as possible. Please refer to +<A HREF="./server.html">XPA Servers</A> +and +<A HREF="./client.html">XPA Clients</A> +for general information about these routines. + +<P> +The file test.tcl in the XPA source directory gives examples for using the +XPA/Tcl interface. + +<P> +The following notes describe the minor differences between the interfaces. + +<H2><A NAME="xpanew">XPANew</A></H2> +<PRE> +<B> + set xpa [xpanew class name help sproc sdata smode rproc rdata rmode] +</B> +</PRE> +<P> +rproc and sproc routines are routines. The calling sequence of the +rproc routine is identical to its C counterpart: +<PRE> + proc rec_cb { xpa client_data paramlist buf len } { ... } +</PRE> +<P> +The sproc routine, however is slightly different from its C counterpart +because of the difficulty of passing data back from the callback to C: +<PRE> + proc sendcb { xpa client_data paramlist } { ... } +</PRE> +<P> +Note that the C-based server's char **buf and int *len arguments are +missing from the Tcl callback. This is because we did not know how to +fill buf with data and pass it back to the C routines for communication +with the client. Instead, the Tcl server callback uses the following +routine to set buf and len: +<PRE> + xpasetbuf xpa buf len +</PRE> +where: +<PRE> + arg explanation + ------ ----------- + xpa the first argument of the server callback + buf the data to be returned to the client + len data length in bytes, (if absent, use length of the buf object) +</PRE> +<P> +When this routine is called, a copy of buf is saved for transmission to +the client. + +<P> +The fact that buf is duplicated means that TCL server writers might wish to +perform the I/O directly within the callback, rather than have XPA do it +automatically at the end of the routine. To do this, set: +<PRE> + fillbuf=false +</PRE> +<P> +in the xpanew smode and then perform I/O through the Tcl channel +obtained from: +<PRE> + set dchan [xparec $xpa datachan] +</PRE> +<P> +where: +<PRE> + arg explanation + ------ ----------- + xpa the first argument of the server callback + datachan literal string "datachan" that returns the data channel + len data length in bytes, (if absent, use length of the buf object) +</PRE> +<P> +<B> +NB: datachan and cmdchan are not available under Windows. It is +necessary to use the "raw" equivalents: datafd and cmdfd. +</B> + +<P> +The same considerations apply to the rproc for receive servers: a copy +of the incoming data is generated to pass to the receive callback. This +copy again can be avoided by using "fillbuf=false" in the rmode and then +reading the incoming data from datachan. + +<P> +The send and receive callback routines can use the xpaerror and xpamessage +routines to send errors and messages back to the client. If you also +want tcl itself to field an error condition, use the standard return call: +<PRE> + return ?-code c? ?-errorinfo i? ?-errorcode ec? string +</PRE> +<P> +See the Tcl man page for more info. + +<H2><A NAME="xpanew">XPARec</A></H2> +<P> +The Tcl xparec procedure supplies server routines with access to information +that is available via macros in the C interface: +<PRE> + set val [xparec xpa <option>] +</PRE> +<P> +where option is: name, class, method, cmdfd, datafd, cmdchan, +datachan. Note that two additional identifiers, cmdchan and datachan, +have been added to to provide Tcl channels corresponding to datafd and +cmdfd. (These latter might still be retrieved in Tcl and passed back +to a C routines.) An additional option called "version" can be used to +determine the XPA version used to build the Tcl interface. Note that +the standard options require a valid XPA handle, but "version" does +not (since it simply reports the value of the XPA_VERSION definition +in the XPA source include file). + +<P> +<B> +NB: datachan and cmdchan are not available under Windows. It is +necessary to use the "raw" equivalents: datafd and cmdfd. +</B> +<PRE> + macro explanation + ------ ----------- + class class of this xpa + name name of this xpa + method method string (inet or local connect info) + cmdchan Tcl channel of command socket + datachan Tcl channel of data socket + cmdfd fd of command socket + datafd fd of data socket + sendian endian-ness of server ("little" or "big") + cendian endian-ness of client ("little" or "big" + version XPA version used to build this code +</PRE> + +<p> +Under Windows, the Tcl event handler cannot automatically sense when an +XPA socket is ready for IO (i.e. Tcl_CreateFileHandler() is not available +under Windows). The Windows Tcl event handler therefore must be awakened +occasionally for check for XPA events. This is done using the standard +Tcl_SetMaxBlockTime() call. The time parameter is defined in tclloop.c +and is currently set to 1000 microseconds (1/1000 of a second). + +<P> +The version option can be used to differentiate between source code versions. +It was created to support legacy Tcl code that needs to maintain the 2.0.5 +calling sequence for xpaaccess. You can use a version test such as: +<PRE> + if [catch { xparec "" version } version] { + puts "pre-2.1.0e" + } else { + puts [split $version .] + } +<PRE> + +<!-- =section xpatcl SEE ALSO --> +<!-- =text See xpa(n) for a list of XPA help pages --> +<!-- =stop --> + +<P> +<A HREF="./help.html">Go to XPA Help Index</A> + +<H5>Last updated: September 10, 2003</H5> +</BODY> +</HTML> diff --git a/xpa/doc/template.html b/xpa/doc/template.html new file mode 100644 index 0000000..6a9a0d0 --- /dev/null +++ b/xpa/doc/template.html @@ -0,0 +1,112 @@ +<!-- =defdoc xpatemplate xpatemplate n --> +<HTML> +<HEAD> +<TITLE>Access Point Names and Templates</TITLE> +</HEAD> +<BODY> + +<!-- =section xpatemplate NAME --> +<H2><A NAME="xpatemplate">XPATemplate: Access Point Names and Templates</A></H2> +<!-- =section xpatemplate SYNOPSIS --> +<H2>Summary</H2> +<P> +XPA access points are composed of two parts: a general class and a +specific name. Both parts accept template characters so that you +can send/retrieve data to/from multiple servers at one time. + +<!-- =section xpatemplate DESCRIPTION --> +<H2>Description</H2> +<P> +When XPA servers call +<A HREF="./server.html#xpanew">XPANew(),</A> +or +<A HREF="./server.html#xpacmdnew">XPACmdNew()</A> +to define XPA access points, they specify a string identifier composed of a +class and a name. When clients communicate with XPA access points, +they specify which access points to communicate with using +an identifier of the form: +<PRE> + class:name +</PRE> +All registered XPA access points that match the specified identifier +will be available for communication (subject to access control rules, +etc.) + +<P> +As of XPA 2.1.5, the length of both the class and name designations are +limited to 1024 characters. + +<P> +The XPA class:name identifier actually is a template: it accepts wild +cards in its syntax, so a single specifier can match more than one XPA +access point. (Note that the class is optional and defaults to "*".) +The allowed syntax for clients to specify the class:name template is +of the form shown below. (Note that "*" is used to denote a generic +wild card, but other wild cards characters are supported, as described +below). +<PRE> + template explanation + -------- ----------- + class:name exact match of class and name + name match any class with this name + *:name match any class with this name + class:* match any name of this class + *:* match any access point +</PRE> +<P> +In general, the following wild-cards can be applied to class and name: +<PRE> + wildcard explanation + -------- ----------- + ? match any character, but there must be one + * match anything, or nothing + [...] match an inclusive set +</PRE> +<P> +Although the class:name template normally is used to refer to XPA +access points, these also can be specified using their individual +socket identifiers. For inet sockets, the socket identifier is +<B>ip:port</B>, where ip can be the DNS-registered name, +the ASCII IP number (e.g. 123.45.67.890) or the hex IP number +(e.g. 838f3a60). For unix sockets, the identifier is the <B>socket file +name</B>. These socket identifiers are displayed as the fourth argument +in the xpans display of registered access points. For example, +consider the ds9 program started using inet sockets. The xpans name +server will register something like this: +<PRE> + csh> xpaget xpans + DS9 ds9 gs saord.harvard.edu:3236 eric +</PRE> +You can access ds9 using ip:3236 in any of the three forms: +<PRE> + csh> xpaget saord:3236 file + /home/eric/data/snr.ev + + csh> xpaget 123.45.67.890:3236 file + /home/eric/data/snr.ev + + csh> xpaget 838f3a60:3236 file + /home/eric/data/snr.ev +</PRE> +In the case of unix sockets, the socket identifier is a file: +<PRE> + csh> xpaget xpans + DS9 ds9 gs /tmp/.xpa/DS9_ds9.2631 eric + + csh> xpaget /tmp/.xpa/DS9_ds9.2631 file + /home/eric/data/snr.ev +</PRE> +This feature can be useful in distinguishing between multiple +instances of a program that all have the same class:name designation. + +<!-- =section xpatemplate SEE ALSO --> +<!-- =text See xpa(n) for a list of XPA help pages --> +<!-- =stop --> + +<P> +<A HREF="./help.html">Go to XPA Help Index</A> + +<H5>Last updated: September 10, 2003</H5> +</BODY> +</HTML> + diff --git a/xpa/doc/users.html b/xpa/doc/users.html new file mode 100644 index 0000000..a849442 --- /dev/null +++ b/xpa/doc/users.html @@ -0,0 +1,67 @@ +<!-- =defdoc xpausers xpausers n --> +<HTML> +<HEAD> +<TITLE>Distinguishing Users</TITLE> +</HEAD> +<BODY> + +<!-- =section xpausers NAME --> +<H2><A NAME="xpausers">XPAUsers: Distinguishing Users</A></H2> + +<!-- =section xpausers SYNOPSIS --> +<H2>Summary</H2> +<P> +XPA normally distinguishes between users on a given host, but it is possible +to send data to access points belonging to other users. + +<!-- =section xpausers DESCRIPTION --> +<H2>Description</H2> +<P> +A single XPA name service typically serves all users on a given +machine. Two users can register the same XPA access points on the +same machine without conflict, because the user's username is +registered with each access point and, by default, programs such as +xpaget and xpaset only process access points of the appropriate user. +For example: +<PRE> + XPA xpa1 gs 838e2f67:1262 eric + XPA xpa2 gs 838e2f67:1266 eric + XPA xpa1 gs 838e2f67:2523 john + XPA xpa2 gs 838e2f67:2527 john +</PRE> +Here the users "eric" and "john" both have registered the access +points xpa1 and xpa2. When either "john" or "eric" retrieves +information from xpa1, they will process only the access point +registered in their user name. + +<P> +If you want to access another user's XPA access points on a single +machine, use the -u [user] option on xpaset, xpaget, etc. For example, +if eric executes: +<PRE> + xpaget -u john xpa1 +</PRE> +he will access John's xpa1 access point.Use "*" to access all users +on a given machine: +<PRE> + xpaget -u "*" xpa1 +</PRE> +Note that the <A HREF="./env.html">XPA Environment Variable</A> +XPA_NSUSERS can be used to specify the default list of users to +process: +<PRE> + setenv XPA_NSUSERS "eric,john" +</PRE> +will cause access points from both "eric" and "john" to be processed +by default. + +<!-- =section xpausers SEE ALSO --> +<!-- =text See xpa(n) for a list of XPA help pages --> +<!-- =stop --> + +<P> +<A HREF="./help.html">Go to XPA Help Index</A> + +<H5>Last updated: September 10, 2003</H5> +</BODY> +</HTML> diff --git a/xpa/doc/xpa.pdf b/xpa/doc/xpa.pdf Binary files differnew file mode 100644 index 0000000..e2c4855 --- /dev/null +++ b/xpa/doc/xpa.pdf diff --git a/xpa/doc/xpa.ps b/xpa/doc/xpa.ps new file mode 100644 index 0000000..21d4910 --- /dev/null +++ b/xpa/doc/xpa.ps @@ -0,0 +1,5294 @@ +%!PS +%%Title: The XPA Help Facility +%%Creator: html2ps version 1.0 beta5 +%%EndComments +save +2000 dict begin +/d {bind def} bind def +/D {def} d +/t true D +/f false D +/FL [/Times-Roman +/Times-Italic +/Times-Bold +/Times-BoldItalic +/Courier +/Courier-Oblique +/Courier-Bold +/Courier-BoldOblique +/Helvetica +/Helvetica-Oblique +/Helvetica-Bold +/Helvetica-BoldOblique] D +/WF t D +/WI 0 D +/F 1 D +/IW 471 F div D +/IL 621 F div D +/PS 791 D +/EF [0 1 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 2 2] D +/EZ [11 9 19 17 15 13 12 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 8 8] D +/Ey [0 0 2 2 2 2 2 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0] D +/EG [-1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1] D +/Tm [1 1 0.8 0.8 0.8 0.8 0.8 0.8 0 0 0 0 0 0 0.5 1 1 1 1 0 0 1.3 0 0] D +/Bm [1 1 0.5 0.5 0.5 0.5 0.5 0.5 0 0 0 0 0 0 0.5 1 1 1 1 0 0 1 0 0] D +/Lm [0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 2 2 0 0 2 0 0 0] D +/Rm [0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0] D +/EU [-1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 0 0] D +/NO t D +/YY [[{()}1][{()}0][{()}2]] D +/ZZ [[{()}1][{()}0][{()}2]] D +/Ts EZ 0 get D +/TU f D +/Xp t D +/AU t D +/SN 0 D +/Cf f D +/Tp f D +/Fe f D +/TI 1 Ts mul D +/Fm 14 D +/xL 71 D +/xR 71 D +/yL 706 D +/yR 706 D +/Wl 471 F div D +/Wr 471 F div D +/hL 621 F div D +/hR 621 F div D +/FE {newpath Fm neg Fm M CP BB IW Fm add Fm L IW Fm add IL Fm add neg L CP BB + Fm neg IL Fm add neg L closepath} D +/LA {PM 0 eq{/IW Wl D /IL hL D}{/IW Wr D /IL hR D}ie /W IW D /LL W D /LS W D + TU PM 0 eq and{IW 56 F div add SA{Sf div}if 0 translate} + {PM 0 eq{xL yL}{xR yR}ie translate F SA{Sf mul}if dup scale + CS CF FS Cf{CA CL get VC}if /Bb f D}ie 0 0 M + TF not Tc or {Cf{gsave SA{1 Sf div dup scale}if Cb VC FE fill grestore}if}if}D +/Pi 0 Ts mul D +/SG [0.8 1 1] D +/Ab 15 D +/J 0 D +/Tc t D +/NH 6 D +/Nf f D +/Pa f D +/LH 1.2 D +/XR f D +/Xr {/pN E D ( [p ) WB pN WB (] )WB} D +/Db [16#FF 16#FF 16#FF] D +/Dt [16#00 16#00 16#00] D +/eA f D +/Fi f D +/bT f D +/Lc t D +/Dl [16#00 16#00 16#00] D +/LX f D +/Br 0.25 D +/IA ([IMAGE]) D +/DS {/PF f D()WB NL NP()pop RC ZF} D +/Gb f D +/Mb t D +/Hc [16#00 16#00 16#00] D +/Bl 3 D +/MI -15.2 D +/DX (DRAFT) D +/Di 0 D +/Tt 113.385826771654 D +/Th {()2 Al()BR ( + ) 0 1 -1 H()4 FZ Ti ES()EH ( + ) 0 2 -1 H() ME 0 get join EH()Ea()BR()} D +/tH {()0 1 -1 H (Table of Contents) EH()} D +/FD 2 D +/Dy 2 D +/cD [16#F0 16#F0 16#F0] D +/FW 0.6 D +/FU [16#00 16#00 16#00] D +/ET {/RM f D /A0 0 D /PN SN D /OU t D /Ou t D /W IW D /LL W D D1 + Ms not TP and{Ip}if /TF f D} D +[{true statusdict/setduplexmode get exec} stopped cleartomark +%-- End of variable part -- +/MySymbol 10 dict dup begin + /FontType 3 D /FontMatrix [.001 0 0 .001 0 0 ] D /FontBBox [25 -10 600 600] D + /Encoding 256 array D 0 1 255{Encoding exch /.notdef put}for + Encoding (e) 0 get /euro put + /Metrics 2 dict D Metrics begin + /.notdef 0 D + /euro 651 D + end + /BBox 2 dict D BBox begin + /.notdef [0 0 0 0] D + /euro [25 -10 600 600] D + end + /CharacterDefs 2 dict D CharacterDefs begin + /.notdef {} D + /euro{newpath 114 600 moveto 631 600 lineto 464 200 lineto 573 200 lineto + 573 0 lineto -94 0 lineto 31 300 lineto -10 300 lineto closepath clip + 50 setlinewidth newpath 656 300 moveto 381 300 275 0 360 arc stroke + -19 350 moveto 600 0 rlineto -19 250 moveto 600 0 rlineto stroke}d + end + /BuildChar{0 begin + /char E D /fontdict E D /charname fontdict /Encoding get char get D + fontdict begin + Metrics charname get 0 BBox charname get aload pop setcachedevice + CharacterDefs charname get exec + end + end}D + /BuildChar load 0 3 dict put /UniqueID 1 D +end +definefont pop + +/Cd {aload length 2 idiv dup dict begin {D} repeat currentdict end} D +/EX {EC cvx exec} D +/DU {} d +/BB {pop pop}d +/ie {ifelse} d +/E {exch} d +/M {moveto} d +/R {rmoveto} d +/L {lineto} d +/RL {rlineto} d +/CP {currentpoint} d +/SW {stringwidth} d +/GI {getinterval} d +/PI {putinterval} d +/Sg {setgray} d +/LW {setlinewidth} d +/S {dup () ne OU and{0 Co R AT 3 eq LB and HF not and A1 0 ne A2 0 ne or and + {A2 0 32 A1 0 6 -1 roll awidthshow}{show}ie 0 Co neg R}{pop}ie + OU PH 3 eq or{/Ms t D}if} D +/U {OU{gsave CP currentfont /FontInfo get /UnderlinePosition get + 0 E currentfont /FontMatrix get dtransform E pop add newpath M dup SW pop + CJ 0 RL stroke grestore}if} D +/B {OU Br 0 gt and{CP Ts neg Ts .33 mul R gsave 0 Sg + CP newpath Ts Br mul 0 360 arc closepath UI 2 mod 0 eq{stroke}{fill}ie + grestore M CP E Ts Br 1 add mul sub E BB /Ms t D}if}D +/NP {Ms TP not or PA and OU and{TP{OR}if f1{mF k2 /mF E D /YC 0 D}if + TP TU not PM 0 eq or and{showpage}if DU Ip TE not{LA}if 0.6 LW + /CI 0 D /TP t D /Hs f D /hl 6 D /Hv 6 D /HI hi D /Ms f D}if Bs XO BO M} D +/Np {LE sub CP E pop gt PL 0 eq and{NP}if}D +/Ip {/PN PN 1 add D /Pn RM{1}{4}ie PN Ns D /PM PN SN sub 2 mod D} D +/GP {E dup 3 -1 roll get PN 1 add 2 mod get dup type /integertype eq + {get 0 get}{E pop}ie}d +/Fc {dup 2 GP exec SW pop /S1 E D dup 1 GP exec SW pop /S2 E D 0 GP exec SW + pop /S3 E D S1 0 gt{S2 2 mul S1 add S3 2 mul S1 add 2 copy lt{E}if pop}{0}ie + S2 S3 add 2 copy lt{E}if pop IW .9 mul div dup 1 gt{1 E div}{pop 1}ie}D +/OR {Df{Sd}if tp not{gsave SA{1 Sf div dup scale}if Fe{Cf{FU VC}if FW LW + 1 setlinejoin FE stroke}if /YO {60 F div dup 40 gt{pop 40}if}D /cs CS D + /cf CF D /CF 0 D /pf PF D /PF f D /Fn FN D /At AT D /AT 0 D /FN EF Hf 1 add + get D Fz Fs FS ZZ Fc Fz mul Fs FS EU Hf 1 add get dup type /arraytype eq + Cf and{VC}{pop 0 Sg}ie IW IL neg YO sub M ZZ 1 GP exec dup SW pop neg 0 R Sh + 0 IL neg YO sub M ZZ 0 GP exec Sh ZZ 2 GP exec dup SW pop IW E sub 2 div + IL neg YO sub M Sh Fz Fs FS NO{/AW IW Pn SW pop sub D AW 2 div IL neg YO sub + S1 0 gt S2 AW .45 mul gt or S3 AW .45 mul gt or{Fz 2 mul sub}if M Pn Sh}if + EU Hf get dup type /arraytype eq Cf and{VC}{pop 0 Sg}ie YY Fc /FN EF Hf get D + Hz mul HS FS IW YO M YY 1 GP exec dup SW pop neg 0 R Sh 0 YO M YY 0 GP exec Sh + YY 2 GP exec dup SW pop IW E sub 2 div YO M Sh /FN Fn D /AT At D t Pb XO SZ + SL get neg R /PF pf D grestore /CF 0 D cs cf FS}if}D +/Sh {dup () ne{CP Hz 4 div sub BB show CP CS add BB}{pop}ie}D +/Pb {/OU E D /Ou OU D /PB t D 0 0 M Ba{/Sa save D /BP t D /Fl t D RC /PL 0 D + /PH 0 D /W IW D /LE IL .7 mul D /EO 0 D SI ZF /YA 0 D /BO 0 D /C1 () D + BA 0 Ts neg R Bb{Xl Yl Xh Yh}if Bb CP Sa restore M + {/Yh E D /Xh E D /Yl E D /Xl E D}if /Fl t D}if + BL /OU t D /HM f D /Ou t D /PB f D} D +/Bs {/BP Ba not D}D +/reencodeISO { + dup dup findfont dup length dict begin{1 index /FID ne{D}{pop pop}ie}forall + /Encoding ISOLatin1Encoding D currentdict end definefont} D +/ISOLatin1Encoding [ +/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef +/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef +/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef +/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef +/space/exclam/quotedbl/numbersign/dollar/percent/ampersand/quoteright +/parenleft/parenright/asterisk/plus/comma/hyphen/period/slash +/zero/one/two/three/four/five/six/seven/eight/nine/colon/semicolon +/less/equal/greater/question/at/A/B/C/D/E/F/G/H/I/J/K/L/M/N +/O/P/Q/R/S/T/U/V/W/X/Y/Z/bracketleft/backslash/bracketright +/asciicircum/underscore/quoteleft/a/b/c/d/e/f/g/h/i/j/k/l/m +/n/o/p/q/r/s/t/u/v/w/x/y/z/braceleft/bar/braceright/asciitilde +/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef +/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef +/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef +/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef +/.notdef/space/exclamdown/cent/sterling/currency/yen/brokenbar +/section/dieresis/copyright/ordfeminine/guillemotleft/logicalnot +/hyphen/registered/macron/degree/plusminus/twosuperior/threesuperior +/acute/mu/paragraph/periodcentered/cedilla/onesuperior/ordmasculine +/guillemotright/onequarter/onehalf/threequarters/questiondown +/Agrave/Aacute/Acircumflex/Atilde/Adieresis/Aring/AE/Ccedilla +/Egrave/Eacute/Ecircumflex/Edieresis/Igrave/Iacute/Icircumflex +/Idieresis/Eth/Ntilde/Ograve/Oacute/Ocircumflex/Otilde/Odieresis +/multiply/Oslash/Ugrave/Uacute/Ucircumflex/Udieresis/Yacute +/Thorn/germandbls/agrave/aacute/acircumflex/atilde/adieresis +/aring/ae/ccedilla/egrave/eacute/ecircumflex/edieresis/igrave +/iacute/icircumflex/idieresis/eth/ntilde/ograve/oacute/ocircumflex +/otilde/odieresis/divide/oslash/ugrave/uacute/ucircumflex/udieresis +/yacute/thorn/ydieresis +] D +[128/backslash 129/parenleft 130/parenright 141/circumflex 142/tilde +143/perthousand 144/dagger 145/daggerdbl 146/Ydieresis 147/scaron 148/Scaron +149/oe 150/OE 151/guilsinglleft 152/guilsinglright 153/quotesinglbase +154/quotedblbase 155/quotedblleft 156/quotedblright 157/endash 158/emdash +159/trademark] +aload length 2 idiv 1 1 3 -1 roll{pop ISOLatin1Encoding 3 1 roll put}for +/colorimage where{pop}{ + /colorimage { + pop pop /Pr E D {/Cv Pr D /Gr Cv length 3 idiv string D 0 1 Gr length 1 sub + {Gr E dup /i E 3 mul D Cv i get 0.299 mul Cv i 1 add get 0.587 mul add + Cv i 2 add get 0.114 mul add cvi put}for Gr} image} D +}ie +/pdfmark where{pop}{userdict /pdfmark /cleartomark load put}ie +WF{FL{reencodeISO D}forall}{4 1 FL length 1 sub{FL E get reencodeISO D}for}ie +/Symbol dup dup findfont dup length dict begin + {1 index /FID ne{D}{pop pop}ie}forall /Encoding [Encoding aload pop] + dup 128 /therefore put D currentdict end definefont D + +/SF {/CS E D SZ SL CS put FO SL FN put /YI CS LH neg mul D dup ST cvs ( ) join + CS ST cvs join C1 E join ( NF ) join /C1 E D CS NF /Wf WF FN 0 gt or D + /BW Wf{( ) SW pop}{0}ie D}D +/NF {/cS E D /cF E D cF 0 ge{FL cF get}{cF -1 eq{/Symbol}{/MySymbol}ie}ie + findfont cS scalefont setfont} D +/FS {CF or /CF E D FR SL CF put CF CF 0 ge{FN 4 mul add}if E SF} D +/PC {SH /BP f D fin not GL not and{NL}if /HM t D /LL LS D} D +/BS {/TX E D Wf{/fin f D /CW 0 D /LK 0 D /SC 0 D + /RT TX D {RT ( ) search{/NW E D pop /RT E D /WH NW SW pop D CW WH add LL gt + {TX SC LK SC sub 1 sub NN GI GL{SH cF cS OC + 2 copy cS ne E cF ne or{NF}{pop pop}ie}{PC /CW WH BW add D}ie + /SC LK D} + {GL{JC}if + /CW CW WH add BW add D /HM t D}ie /GL f D /Ph f D + /LK LK NW length 1 add add D}{pop exit}ie}loop + /fin t D TX SC LK SC sub GI SH RT () ne{GL not{CC}if}if + /LC TX length D /WH RT SW pop D CW WH add Hy{HC SW pop add}if LL gt + {RT GL{SH cF cS OC 2 copy cS ne E cF ne or{NF}{pop pop}ie + Hy{/Ph t D}if /LL LS D}{NL /LL LS D SH}ie} + {RT PC Hy{CC}if /Ph Ph Hy or D}ie RT () ne{/GL t D /HM t D}if} + {TX SW pop LL le{TX SH}{/NW () D 0 2 TX length 1 sub + {/CW E D TX 0 CW GI dup SW pop LL gt{pop NW SH /HM t D NL/LL W XO sub MR sub D + /CW CW 2 sub NN D /TX TX CW TX length CW sub GI D TX BS exit} + {/NW E D}ie}for}ie}ie /HM t D}D +/CC {C0 length 0 gt{JC}if /C0 [C1 L1 YA YB Mf NS NB TB AF Bw] D + /C1 () D /L0 L1 D /YA 0 D /YB 0 D /Mf 0 D /NS 0 D /NB 0 D}D +/JC {C0 aload length 0 gt{pop pop pop NB add /NB E D NS add /NS E D + dup Mf gt{/Mf E D}{pop}ie dup YB gt{/YB E D}{pop}ie + dup YA gt{/YA E D}{pop}ie pop C1 join /C1 E D /C0 [] D}if}D +/OC {C0 length 0 gt{C1 L1 L0 sub YA YB Mf NS NB TB AF Bw GL C0 aload pop + /Bw E D /AF E D /TB E D /NB E D /NS E D /Mf E D /YB E D /YA E D /C0 [] D + /L1 E D /C1 E D Ph{HC SH}if NL /GL E D /Bw E D /AF E D /TB E D /NB E D /NS E D + /Mf E D /YB E D /YA E D /L1 E D /LL W L1 sub XO sub MR sub WH sub D /CW 0 D + C1 E join /C1 E D}if}D +/BT {/LB t D dup length string copy RS dup dup () ne E ( ) ne and + {/CI 0 D /LS LL D /LL W L1 sub XO sub MR sub D BS} + {dup ( ) eq{/GL f D}if dup () eq L1 0 eq or{pop}{SH /BP f D /Ph f D}ie}ie + /LB f D} D +/BL {CP E pop XO E M} D +/NL {JC /GL f D /SK W XO sub MR sub L1 sub TB{Bw add}if D + /YA LF{Mf HM Fl not and PF or{LH mul}if}{0 /LF t D}ie YA 2 copy lt{E}if pop D + C1 () ne{/FB YB Mf SA{Sf mul}if 4 div 2 copy lt{E}if pop D}if Fl{/Ya YA D}if + CP E pop YA sub YB sub LE neg lt Fl not and PB not and{NP}if NT TL BL + OU PF not and PB or{/RE L1 TB{Bw sub}if + W XO sub MR sub div YA YB add LE BO add div 2 copy lt{E}if pop D + RE 1 gt{BL 1 RE div dup scale}if}if + AT 2 le{SK AT mul 2 div YA neg R}if + AT 3 eq{0 YA neg R TB{/NB NB 1 sub D /NS NS 1 sub D}if /NB NB 1 sub NN D + /A3 NS 6 mul NB add D NS NB add 0 eq + {/A1 0 D /A2 0 D} + {NS 0 eq{/A1 SK NB div dup J gt{pop 0}if D /A2 0 D}{J A3 mul SK lt + {/A1 J D /A2 SK J NB mul sub NS div dup Ab gt{/A1 0 D pop 0}if D} + {/A1 SK A3 div D /A2 A1 6 mul D}ie}ie}ie /A1 A1 NN D /A2 A2 NN D}if + AT 4 eq{0 YA neg R PH 2 le{PD 0 lt{/PD L1 D}if PD M1 gt{/M1 PD D}if + L1 PD sub M2 gt{/M2 L1 PD sub D}if}{DV ID 1 sub get 0 ge{Lo 0 R}if}ie}if + F0 cF ne Cs cS ne or{F0 Cs NF}if + /ms Ms D /Ms f D CP FB sub + C1 cvx exec XO EO sub L1 add TB{BW sub}if dup LM gt{/LM E D}{pop}ie + PH 0 eq PH 4 eq or Ms and{HF not{/PO t D /AH t D}if + BB CP YA add E AT 3 eq LB and{A1 sub}if TB{BW sub}if E BB} + {pop pop}ie Ms HM PH 3 eq and or{/BP f D /Fl f D}if + /Lo 0 D /L1 0 D /F0 cF D /Cs cS D BP not{0 YB NN neg R}if + OU f1 and mF not and{k2 /f1 f D}if + OU PF not and PB or{RE 1 gt{RE dup scale}if}if /Ms ms Ms or D + /C1 AF{(Cp )}{()}ie D /YA 0 D /YB 0 D BL + AT 4 eq LB not and PH 3 ge and + {ID DV length lt{DV ID get dup 0 ge{DO E sub /Lo E D /L1 Lo D}{pop}ie + /ID ID 1 add D}if}if /T t D CD{/LN LN 1 add D PD}if + /PD -1 D /NS 0 D /NB 0 D /TB f D /Ph f D /Mf 0 D /HM f D} D +/RS {/TM E D /CN 0 D TM{10 eq{TM CN ( ) PI}if /CN CN 1 add D}forall + /CN 0 D /BK HM EN and{0}{1}ie D TM + {dup 32 ne{TM CN 3 2 roll put /CN CN 1 add D /BK 0 D} + {pop BK 0 eq{TM CN 32 put /CN CN 1 add D}if /BK 1 D}ie}forall + TM 0 CN GI dup dup () ne E ( ) ne and + {dup CN 1 sub get 32 eq{/EN f D}{/EN t D}ie}if} D +/join {2 copy length E length add string dup 4 2 roll 2 index 0 3 index + PI E length E PI}d +/WR {(\n) search{dup () ne BP not or + {Li 4 le CP E pop YI Li mul add LE add 0 lt and PL 0 eq and{NP}if + SH NL pop /Li Li 1 sub D WR}{pop pop WR}ie}{SH}ie /CI 0 D /BP f D} D +/SH {dup dup () ne E ( ) ne and PF or CS Mf gt and{/Mf CS D}if + T not Wf and{( ) E join /T t D}if dup BP{/MF CS D}if + AT 3 eq{2 copy length dup 0 gt{/NB E NB add D + {( ) search{/NS NS 1 add D pop pop}{pop exit}ie}loop}{pop pop}ie}if + CD PD 0 lt and{dup DC search{SW pop /PD E L1 add D pop pop}{pop}ie}if + 0 Np dup SW pop L1 add /L1 E D dup () ne + {C1 (\() join E join (\)) join AU AF and UF or Wf and{( U ) join}if + sF{( s ) join}if ( S ) join + /C1 E D dup length 1 sub get 32 eq /TB E D /Bw BW D}{pop pop}ie} D +/BG {AI LG BC add add 0 eq} D +/ON {OU{Ty AR AI NN get dup 1 add Ln Ns Ty 2 mod 0 eq{(. )}{(\) )}ie join + dup SW pop neg 0 R CP E 0 lt{0 E M}{pop}ie CP BB show /Ms t D}if} D +/Ln {AR AI 3 -1 roll put}D +/SP {dup CI lt BP not and{dup CI sub 0 E R /CI E D}{pop}ie} D +/BN {PF{WR /HM f D}{BT NL}ie} D +/NN {dup 0 lt{pop 0}if} D +/h {(h) HI ST cvs join cvx exec dup 1 get E Nf{0 get E join}{pop}ie} D +/H {/fn FN D /Hi E 1 add D 1 sub /HL E D /H2 HL 2 add D /GS EZ H2 get D + E Tm H2 get GS mul BE dup 0 gt{1 sub}{pop EG H2 get dup 0 lt{pop AT}if}ie NA + WW Np /SL SL 1 add D /FN EF H2 get D GS Ey H2 get FS + EU H2 get Sc Hs not HL Hl lt and Hs HL hl lt and or Hi 0 eq or + {/HI Hi D /Hs t D /hl HL D /Hv HL D}if HL Hl lt{/hi Hi D}if + Nf HI 0 gt and{(h) Hi ST cvs join cvx exec 0 get WB}if + /HF t D /AH f D /PO f D} D +/EH {Bm H2 get GS mul BE OA /SL SL 1 sub NN D /CF 0 D /FN fn D + SZ SL get FR SL get FS /HF f D /GS Ts D ()Ec} D +/P {E PF{WR}{PO{EP}{BN}ie Ts 4 mul Np AE not{Tm 0 get Ts mul neg SP}if + dup 0 ge AH and{Pi Pd}if}ie 1 sub dup 0 lt{pop AV AL get}if /AT E D /PO t D} D +/EP {PF{WR}{BN Ts 4 mul Np}ie AE not{Bm 0 get Ts mul neg SP}if + /AT AV AL get D /PO f D} D +/BE {E PO{EP}{BN}ie Ts 4 mul Np neg SP} D +/HR {/Aw W EO sub D /RW E dup 0 gt{Aw mul}{neg}ie dup Aw gt{pop Aw}if D /RZ E D + E BN Ts neg SP 1 sub 2 div Aw RW sub mul EO add CP E pop M PF{0 Ps neg R}if + 0 Np OU{gsave RZ LW Cf{Hc VC}{0 Sg}ie CP BB RW 0 RL CP BB stroke grestore}if + /CI 0 D /BP f D PF not{Ts neg SP}if /Ms t D} D +/AD {I NL EG 14 get dup 0 lt{pop AT}if NA /AE t D Tm 14 get Ts mul neg SP + Cf{EU 14 get dup -1 eq{pop CA CL get}if Sc}if} D +/DA {BN ()ES OA /AE f D ()Ec Bm 14 get Ts mul neg SP} D +/PR {/MW E D /Li E D Tm 1 get Ps mul BE 0 NA /FN Fp D /PF t D SI /SL SL 1 add D + /CF 0 D Ps CS mul Ts div MW WC mul CS mul Ts div dup LL gt PL 0 eq and + {LL div div}{pop}ie Ey 1 get FS CP E pop LE add YI neg div cvi dup Li lt + AH and{4 lt YI Li mul 5 mul LE add 0 gt or PL 0 eq and{NP}if}{pop}ie + EU 1 get Sc /GS Ps D}D +/RP {WR NL () /PF f D SI /FN 0 D ES Bm 1 get Ps mul neg SP OA /GS Ts D} D +/SI {/XO Lm 15 get BC NN mul Lm 16 get AI UI sub NN mul add + Lm 17 get UI NN mul add Lm 20 get LG NN mul add Ts mul + PF{Lm 1 get Ps mul add}if EO add D + /MR Rm 15 get BC NN mul Rm 16 get AI UI sub NN mul add + Rm 17 get UI NN mul add Rm 20 get LG NN mul add Ts mul + PF{Rm 1 get Ps mul add}if D /LL W XO sub MR sub D} D +/DT {/cC E D BN /LG LG 1 sub D SI /LG LG 1 add D WW 2 div Np BL} D +/DD {WB Cc 0 eq cC 0 eq and L1 0 eq or Lm 20 get Ts mul L1 sub TB{BW add}if + Ts 2 div lt or NL /LF E D SI BL /cC 0 D} D +/DL {Dc LG Cc put /Cc E D BG{Tm 18 get Ts mul BE}{BN}ie /LG LG 1 add D BL} D +/LD {BN LG 0 gt{/LG LG 1 sub D}if /Cc Dc LG get D SI + BG{()Bm 18 get Ts mul BE}if BL} D +/UL {BG{Tm 17 get Ts mul BE}{BN}ie NR AI NN 0 put /UI UI 1 add D + /AI AI 1 add D SI BL} D +/LU {BN /UI UI 1 sub D /AI AI 1 sub D SI BG{()Bm 17 get Ts mul BE}if BL} D +/OL {E BG{Tm 16 get Ts mul BE}{BN}ie TR AI NN Ty put /Ty E D NR AI NN 1 put + /AI AI 1 add D SI BL 1 Ln} D +/LO {BN /AI AI 1 sub D /Ty TR AI get D SI BG{()Bm 16 get Ts mul BE}if BL} D +/LI {E BN -1 SP /BP f D /CI 0 D 0 Np NR AI 1 sub NN get 1 eq + {dup dup 0 gt E 4 le and{/Ty E D}{pop}ie + /L1 L1 Ty AR AI NN get Ns SW pop XO sub dup 0 lt{pop 0}if add D ( ON )} + {pop ( B )}ie C1 E join /C1 E D CS Mf gt{/Mf CS D}if BL} D +/BQ {Tm 15 get Ts mul BE /BC BC 1 add D SI BL} D +/QB {Bm 15 get Ts mul BE /BC BC 1 sub D SI BL} D +/Al {E EP 1 sub dup 0 lt{pop AV AL get}if NA} D +/Ea {EP OA} D +/WB {PF{WR}{BT}ie} D +/F1 {WB /FN 0 D CS 0 FS} D +/F2 {WB /FN WI D CS 0 FS} D +/HY {/Hy t D WB /Hy f D} D +/YH {WB} D +/A {/LT E D LT 1 eq{/RN E D}if /Lh E D WB /C1 C1 ( Cp ) join D + Lc AF not and{Cl Sc}if /AF t D} D +/EA {Lc AF and{Ec}{WB}ie TL Pa AF and Lh 0 ne and + {( \() Lh join (\)) join /AF f D WB}if /AF f D} D +/TL {C1 ( Tl ) apa /C1 E D} d +/apa {AF OU and Lh 0 ne LT 1 eq or and{LT 1 eq{RN ( /) E ST cvs join} + {(\() Lh join (\)) join}ie E join join}{pop}ie} d +/Cp {/Xc CP /Yc E D D} D +/SS {Cf{dup 0 ge{EU E get dup -1 eq{pop CA CL get}if}{pop CA CL get}ie Sc} + {pop}ie SZ SL get /SL SL 1 add D} D +/I {WB 8 SS 1 FS} D +/EM {WB 8 SS /CF CF 1 xor D 0 FS} D +/BD {WB 9 SS 2 FS} D +/TT {WB 10 SS /FN Fp D 0 FS} D +/KB {WB 11 SS /FN Fp D 2 FS} D +/CT {WB 12 SS 1 FS} D +/SM {WB 13 SS /FN Fp D 0 FS} D +/Q {/QL QL 1 add D QO QL 2 mod get La get join WB} D +/EQ {QC QL 2 mod get La get join WB /QL QL 1 sub D} D +/RO {WB -1 SS /CF 0 D 0 FS} D +/SY {WB -1 SS -1 FS} D +/MY {WB -1 SS -2 FS} D +/ES {WB /SL SL 1 sub NN D /CF 0 D /FN FO SL get D SZ SL get FR SL get FS ()Ec}D +/FZ {3 sub 1.2 E exp GS mul E WB TL /C1 C1 ( Cp ) join D /SL SL 1 add D 0 FS} D +/Ef {WB TL ()ES /C1 C1 ( Cp ) join D} D +/BZ {dup /Bf E D FZ}D +/Sc {dup -1 ne Cf and{/CL CL 1 add D dup 0 eq{pop [0 0 0]}if + dup CA E CL E put VS ( VC ) join C1 E join /C1 E D}{pop}ie} D +/Ec {WB Cf{/CL CL 1 sub NN D CA CL get VS ( VC ) join C1 E join /C1 E D}if} D +/VS {dup type /arraytype eq{([) E {ST cvs join ( ) join}forall (]) join}if} D +/VC {{255 div}forall setrgbcolor} D +/Sl {dup type /integertype ne{Ds}if /La E D WB}d +/UN {WB /UF t D} D +/NU {WB /UF f D} D +/SE {WB /sF t D} D +/XE {WB /sF f D} D +/sM {/C1 C1 ( k1 ) join D}d +/eM {/C1 C1 ( k2 ) join D}d +/k1 {/YC CP E pop Ts add D /mF t D /f1 t D}d +/k2 {gsave 3 LW -9 CP E pop Ts 0.2 mul sub M -9 YC L stroke grestore /mF f D}d +/Ac {/AC E D WB}d +/Ca {eA{( \()join AC join(\) )join}if WB}d +/s {OU{gsave 0 CS .25 mul R dup SW pop CJ 0 RL stroke grestore}if}D +/CJ {AT 3 eq LB and{E dup dup length 1 sub A1 mul E + {( ) search{pop pop E A2 add E}{pop exit}ie}loop 3 -1 roll add + W CP pop sub 2 copy gt{E}if pop}if}D +/So {/Co E D} D +/SO {C1 Yo ST cvs join ( So ) join /C1 E D (j) SW pop 2 div Pd} D +/Se {E WB CS E div Pd}D +/Pd {dup type /stringtype eq{SW pop}if dup /L1 E L1 add D + ST cvs ( 0 R ) join C1 E join /C1 E D} D +/Sp {0.35 CO} D +/Sb {-0.2 CO} D +/CO {OV Io Yo put /Yo E CS mul Yo add D /Io Io 1 add D -1.5 Io mul 3 add FZ SO + CS Yo add dup YA gt{/YA E D}{pop}ie + Yo neg dup YB gt{/YB E D}{pop}ie} D +/Es {ES /Io Io 1 sub NN D /Yo OV Io get D SO} D +/SB {/N2 0 D 0 1 NI{/N E D{IX N2 get 0 lt{/N2 N2 1 add D}{exit}ie}loop + /K WS N get FC N get mul D /NY AY N2 get D /BV NY array D + 0 1 NY 1 sub{/TM K string D currentfile TM readhexstring pop pop BV E TM put} + for BM N BV put /N2 N2 1 add D}for} D +/IC [{/MA E D /MB 0 D}{2 div /MA E D /MB MA D}{/MB E CS sub D /MA CS D} + {pop /MA YS AB mul D /MB 1 AB sub YS mul D}{pop /MA 0 D /MB 0 D}] D +/IP {BV N get /N N 1 add D} D +/II {/K E D IX K get 0 lt{/EC E D}if /TY E D + TY 4 eq{/Y E D /X E D}if TY 3 eq{/AB E D}if + /XW AX K get D /YW AY K get D /IS SG IT K get get D /XS XW IS mul D + /YS YW IS mul D YS IC TY get exec /MA MA Fl not{3 add}if D} D +/IM {II /ty TY D /xs XS D /ys YS D /ya YA D /yb YB D /ma MA D /mb MB D /k K D + /ec EC D /BP f D /CI 0 D WB TL L1 xs add dup XO add MR add W gt + {pop /ma ma Fl{3 add}if D NL /YA ma D /YB mb D /YS ys D /L1 xs D} + {/L1 E D ma YA gt{/YA ma D}if mb YB gt{/YB mb D}if}ie /TB f D + OU{CP E pop YS sub LE neg lt Fl not and PB not and{NP /YA ma D /YB mb D}if + /BP f D ty ST cvs ( ) join IX k get 0 lt{(\() join ec join (\) ) join}if + k ST cvs join ty 3 eq{AB ST cvs ( ) join E join}if + ty 4 eq{X ST cvs ( ) join Y ST cvs join ( ) join E join}if C1 E join + ( DI ) join FP 2 eq FP 1 eq AF and or{( FM ) join}if + ( Il Cp ) apa /C1 E D /EN f D}if /HM t D /T f D} D +/DI {II /Xc CP /Yc E D D /YN YW neg D /HM t D /CI 0 D /K2 IX K get D gsave + TY 4 eq{OX X IS mul add OY FY add YS sub Y IS mul sub} + {/FY YS D CP MB sub 2 copy /OY E D /OX E D}ie + translate K2 0 ge{/DP AZ K2 get D /BV BM K2 get D XS YS scale /N 0 D XW YW DP + [XW 0 0 YN 0 YW] {IP} FC K2 get 1 eq{image}{f 3 colorimage}ie} + {EX}ie grestore XS 0 R /Ms t D} D +/FM {gsave 0 Sg CP MB sub translate XS neg 0 M 0 YS RL XS 0 RL 0 YS neg RL + XS neg 0 RL stroke grestore} D +/NA {/AT E D /AL AL 1 add D AV AL AT put} D +/OA {AL 0 gt{/AL AL 1 sub D /AT AV AL get D}if} D +/D1 {/BR {CP E pop E BN Mb{CP E pop eq{0 YI R}if}{pop}ie} D + /Sn {OU{C1 E ST cvs join ( Ld ) join /C1 E D}{pop}ie} D} D +/D1 {/BR {BN} D /Sn {OU {C1 E ST cvs join ( Ld ) join /C1 E D} {pop} ie} D} D +/TC {/TF t D /ML 0 D HN{SW pop dup ML gt{/ML E D}{pop}ie}forall NP /RM RM not D + RC /OU Tc D Ep /PN 0 D Ms not TP and{Ip}if /W IW ML sub Ts sub D + /A0 0 D TH{/BR {( ) join BT} D /Sn {pop} D /Au () D}if} D +/TN {0 eq{E EA PF HF or not XR and{HN E get Xr}{pop}ie} + {OU{Tn 0 ge{() BN}if /Tn E D}{pop}ie WB}ie} D +/NT {OU LB not and Tn 0 ge and{PL 0 eq{Ms not{CS CF FS}if CP dup + /y E YA sub D W 9 sub CS -1.8 mul XO L1 add 2 add{y M (.) show}for + HN Tn get dup SW pop IW E sub y M show CP BB M}if /Tn -1 D}if} D +/Ld {/DN E D HN DN Pn put [/View [/XYZ -4 Fl{PS}{CP YA add US E pop}ie null] + /Dest DN ST cvs cvn /DEST pdfmark} D +/C {ND 1 eq{1 sub}if TI mul /XO E D NL Nf not{pop()}if 0 3 -1 roll 1 A} D +/OP {BP not{NP}if PN 2 mod 0 eq{/Ms t D NP}if}D +/Ep {Xp PN 2 mod 0 eq and OU and{/Pn (-) D showpage /PM 1 D LA}if}D +/Dg [73 86 88 76 67 68 77] D +/Rd [0 [1 1 0][2 1 0][3 1 0][2 1 1][1 1 1][2 2 1][3 3 1][4 4 1][2 1 2]] D +/Ns {/m E D /c E 32 mul D /j m 1000 idiv D /p j 12 add string D + c 96 le m 0 gt and{c 32 le {/i 0 D /d 77 D /l 100 D /m m j 1000 mul sub D + j -1 1 {pop p i d c add put /i i 1 add D}for + 4 -2 0 {/j E D /n m l idiv D /m m n l mul sub D /d Dg j get D + n 0 gt {/x Rd n get D x 0 get -1 1 {pop p i d c add put /i i 1 add D}for + p i x 1 get sub Dg x 2 get j add get c add put}if /l l 10 idiv D + }for p 0 i GI} + {/i ST length 1 sub D m {1 sub dup 0 ge{dup 26 mod c add 1 add + ST i 3 -1 roll put 26 idiv dup 0 eq{pop exit}if}if /i i 1 sub D}loop + ST i ST length i sub GI}ie} + {m p cvs}ie} D +/US {matrix currentmatrix matrix defaultmatrix matrix invertmatrix + matrix concatmatrix transform} D +/GB {Gb{US}if}D +/Tl {/Rn E D Xc CP pop ne{ + [/Rect [Xc 1 sub Yc cS 0.25 mul sub GB CP E 1 add E cS 0.85 mul add GB] + /Subtype /Link /Border [0 0 Cf Lc and LX and AU or{0}{1}ie] Rn type + /nametype eq {/Dest Rn}{/Action [/Subtype /URI /URI Rn] Cd}ie + /ANN pdfmark}if} D +/Il {/Rn E D [/Rect [Xc Yc GB Xc XS add Yc YS add GB] /Subtype /Link + /Border [0 0 0] Rn type /nametype eq{/Dest Rn} + {/Action [/Subtype /URI /URI Rn] Cd}ie /ANN pdfmark} D +/XP {[{/Z Bz 2 div D Z 0 R Z Z RL Z neg Z RL Z neg Z neg RL Z Z neg RL + Fi cH 1 eq and{fill}if} {Bz 0 RL 0 Bz RL Bz neg 0 RL 0 Bz neg RL + Fi cH 1 eq and{fill}if} {0 -5 R Bz 0 RL 0 21 RL Bz neg 0 RL 0 -21 RL}]} D +/MS {/Sm E D WB}D +/O {BN()Sm BX} D +/O {BN()0 Sm BX} D +/BX {/Bt E D Bt 2 lt{/Ch E D CS 0.8 mul}{11 mul}ie W XO sub MR sub + 2 copy gt{E}if pop /HZ E D Bt 2 eq{Fi not{pop()}if ( )E join /Ft E D TT + /PF t D /MW 1 D /Li 1 D /Fw Ft SW pop D Fw HZ gt{/HZ Fw 8 add D}if + HZ ST cvs( )join}{WB Ch ST cvs( )join}ie L1 HZ add XO add MR add W gt{NL}if + Bt 2 eq{Ft ES Fw neg HM{CS sub}if Pd}if Bt ST cvs join( Bx )join + Bt 2 eq HM and{CS Pd}if C1 E join /C1 E D /L1 L1 HZ add D /T f D + ( ) Pd /PF f D Bt 2 lt{YA CS .8 mul lt{/YA CS .8 mul D}if} + {YB 5 lt{/YB 5 D}if YA 21 lt{/YA 21 D}if}ie /CI 0 D} D +/Bx {dup 2 eq{E /Bz E D}{E /cH E D /Bz CS .8 mul D}ie + OU {gsave 0 Sg XP E get exec stroke grestore}{pop}ie Bz 0 R /Ms t D}D +/SD {FD 4 mul Dy add DZ NF newpath 0 0 M DX t charpath pathbbox + 3 -1 roll sub /DY E D E dup /X1 E D sub WM mul WX DY mul add WM DG mul E div + /DF E D /DR WX DF mul DY mul WM div 2 div D} d +/Sd {gsave 0 IL Di mul neg translate IL IW atan Di 0 eq{neg}if rotate + FD 4 mul Dy add DZ NF DR X1 sub DY 2 div neg M cD VC DX show grestore} d +/Pt {/tp t D Tp{NP /Pn (TP) D 0 Tt neg R Th BN NP Ep ET RC ZF}if /tp f D} D +/RC {/AI 0 D /LG 0 D /BC 0 D /UI 0 D /PF f D /Cc 0 D /cC 0 D /Dc 10 array D + /NR [0 1 9{pop 0}for] D /La Ds D /AR 10 array D /TR 10 array D /AV 30 array D + SI /AL -1 D /AT A0 D AT NA /OV 9 array D /Yo 0 D /Co 0 D /Io 0 D /Hy f D + /Ph f D /CL -1 D Ct Sc}D +/ZF {/FR [0 1 30{pop 0}for] D /SZ [0 1 30{pop 0}for] D /FO [0 1 30{pop 0}for] D + /SL 0 D /CF 0 D /FN 0 D 0 Ts SF}D +/QO [[(\234)(\233)(\253\240)(\232)(\273)(\253)][(')(`)(\253\240)(\231)(\273)(\253)]] D +/QC [[(\234)(\234)(\240\273)(\233)(\253)(\273)][(')(')(\240\273)(`)(\253)(\273)]] D +/Hf EF length 2 sub D +/Hz EZ Hf get D +/HS Ey Hf get D +/Fz EZ Hf 1 add get D +/Fs Ey Hf 1 add get D +/LE IL D +/Ps EZ 1 get D +/Fp EF 1 get D +/XO 0 D +/YI 0 D +/CI 0 D +/FP 0 D +/WW Ts 7 mul D +/Mf 0 D +/YA 0 D +/YB 0 D +/Cs Ts D +/GS Ts D +/F0 0 D +/NS 0 D +/NB 0 D +/N 0 D +/C0 [] D +/C1 () D +/Lo 0 D +/L1 0 D +/LM 0 D +/PH 0 D +/EC 0 D +/Lh 0 D +/LT 0 D +/CH 1 string D +/ST 16 string D +/CA 9 array D +/HC (\255) D +/HM f D +/PF f D +/EN f D +/TB f D +/UF f D +/sF f D +/AE f D +/AF f D +/BP t D +/CD f D +/PA t D +/GL f D +/T t D +/HF f D +/AH f D +/SA f D +/PB f D +/f1 f D +/mF f D +/OX 0 D +/OY 0 D +/FY 0 D +/EO 0 D +/FB 0 D +/PL 0 D +/Bw 0 D +/PD -1 D +/TP f D +/tp f D +/TH f D +/Ty 4 D +/Tn -1 D +/Fl t D +/LB t D +/PM 1 D +/Ms f D +/Ba f D +/Bb f D +/Hl 3 D +/hl 6 D +/Hv 6 D +/Hs f D +/HI 0 D +/hi 0 D +/PO t D +/TE f D +/LF t D +/BO 0 D +/Sm 1 D +/Bf 3 D +/A1 0 D +/A2 0 D +/Ds 1 D +/QL -1 D +/Cb Db D +/Ct Dt D +/Cl Dl D +[/Creator (html2ps version 1.0 beta5) /Author () /Keywords () /Subject () + /Title (The XPA Help Facility) /DOCINFO pdfmark +/ND 22 D +/HN [(1) (1) (1) (3) (5) (8) (10) (14) (15) (16) (15) (16) (17) (19) (22) (25) +(26) (29) (30) (30) (31) (32) (32) (33) (34) (34) (35) (37) (38) (46) (46) +(39) (40) (42) (43) (44) (47) (48) (50) (51) (55) (61) (63) (75) (76) (77) +(80) (1) (1) (1) (2) (1) (??) (??) (1) (1) (1) (2) (3) (3) (3) (3) (4) (5) +(5) (5) (5) (7) (8) (8) (8) (8) (9) (10) (10) (10) (10) (10) (11) (12) (13) +(14) (14) (14) (14) (14) (15) (15) (15) (16) (16) (17) (18) (19) (19) (19) +(19) (20) (21) (22) (22) (22) (24) (25) (25) (33) (25) (25) (25) (25) (26) +(29) (30) (30) (31) (32) (32) (33) (33) (34) (34) (35) (36) (37) (37) (37) +(37) (37) (38) (38) (38) (38) (38) (38) (39) (40) (42) (43) (44) (46) (46) +(47) (48) (49) (50) (50) (50) (50) (50) (51) (53) (51) (51) (51) (51) (51) +(52) (53) (54) (55) (55) (55) (55) (60) (61) (61) (61) (61) (62) (63) (63) +(63) (63) (63) (63) (64) (64) (64) (65) (65) (66) (67) (67) (67) (68) (68) +(68) (68) (69) (69) (69) (70) (70) (70) (70) (70) (71) (71) (71) (71) (72) +(72) (73) (73) (73) (74) (74) (74) (74) (75) (75) (75) (75) (75) (76) (76) +(76) (76) (76) (77) (77) (77) (77) (79) (80) (80) (80) (80) (80)] D +/h0 [()(Table of Contents)] D +/h1 [(0.1\240\240)(XPA: Public Access to Data and Algorithms)] D +/h2 [(0.2\240\240)(Summary)] D +/h3 [(0.3\240\240)(Description)] D +/h4 [(0.3.0.0.1\240\240)(Last updated: September 10, 2003)] D +/h5 [(0.4\240\240)(XPAIntro: Introduction to the XPA Messaging System)] D +/h6 [(0.5\240\240)(Summary)] D +/h7 [(0.6\240\240)(Description)] D +/h8 [(0.6.0.0.1\240\240)(Last updated: March 10, 2007)] D +/h9 [(0.7\240\240)(XPATemplate: Access Point Names and Templates)] D +/h10 [(0.8\240\240)(Summary)] D +/h11 [(0.9\240\240)(Description)] D +/h12 [(0.9.0.0.1\240\240)(Last updated: September 10, 2003)] D +/h13 [(0.10\240\240)(XPACommon: Getting Common Information About Access Points)] D +/h14 [(0.11\240\240)(Summary)] D +/h15 [(0.12\240\240)(Description)] D +/h16 [(0.12.0.0.1\240\240)(Last updated: September 10, 2003)] D +/h17 [(0.13\240\240)(XPAMethod: XPA Communication Methods)] D +/h18 [(0.14\240\240)(Summary)] D +/h19 [(0.15\240\240)(Description)] D +/h20 [(0.15.0.0.1\240\240)(Last updated: September 10, 2003)] D +/h21 [(0.16\240\240)(XPAInet: XPA Communication Between Hosts)] D +/h22 [(0.17\240\240)(Summary)] D +/h23 [(0.18\240\240)(Description)] D +/h24 [(0.19\240\240)(Manual Registration)] D +/h25 [(0.20\240\240)(Remote Registration)] D +/h26 [(0.21\240\240)(XPANS Proxy Registration)] D +/h27 [(0.21.0.0.1\240\240)(Last updated: September 10, 2003)] D +/h28 [(0.22\240\240)(XPAUsers: Distinguishing Users)] D +/h29 [(0.23\240\240)(Summary)] D +/h30 [(0.24\240\240)(Description)] D +/h31 [(0.24.0.0.1\240\240)(Last updated: September 10, 2003)] D +/h32 [(0.25\240\240)(XPA Programs)] D +/h33 [(0.26\240\240)(Summary)] D +/h34 [(0.27\240\240)(xpaset: send data to one or more XPA servers)] D +/h35 [(0.28\240\240)(xpaget: retrieve data from one or more XPA servers)] D +/h36 [(0.29\240\240)(xpainfo: send short message to one or more XPA servers)] D +/h37 [(0.30\240\240)(xpaaccess: see if template matches registered XPA access points)] D +/h38 [(0.30.0.0.1\240\240)(Last updated: September 10, 2003)] D +/h39 [(0.31\240\240)(xpamb: the XPA Message Bus)] D +/h40 [(0.32\240\240)(Summary)] D +/h41 [(0.33\240\240)(Description)] D +/h42 [(0.34\240\240)(Options)] D +/h43 [(0.34.0.0.1\240\240)(Last updated: September 10, 2003)] D +/h44 [(0.35\240\240)(xpans: the XPA Name Server)] D +/h45 [(0.36\240\240)(Summary)] D +/h46 [(0.36.0.0.1\240\240)(Last updated: January 24, 2005)] D +/h47 [(0.37\240\240)(XPAServer: The XPA Server-side Programming Interface)] D +/h48 [(0.38\240\240)(Summary)] D +/h49 [(0.39\240\240)(Introduction to XPA Server Programming)] D +/h50 [(0.40\240\240)(Introduction)] D +/h51 [(0.41\240\240)(XPANew: create a new XPA access point)] D +/h52 [(0.42\240\240)(XPACmdNew: create a new XPA public access point for commands)] D +/h53 [(0.43\240\240)(XPACmdAdd: add a command to an XPA command public access point)] D +/h54 [(0.44\240\240)(XPACmdDel: remove a command from an XPA command public access point)] D +/h55 [(0.45\240\240)(XPAInfoNew: define an XPA info public access point)] D +/h56 [(0.46\240\240)(XPAFree: remove an XPA public access point)] D +/h57 [(0.47\240\240)(XPAMainLoop: optional main loop for XPA)] D +/h58 [(0.48\240\240)(XPAPoll: execute existing XPA requests)] D +/h59 [(0.49\240\240)(XPAAtExit: install exit handler)] D +/h60 [(0.50\240\240)(XPACleanup: release reserved XPA memory)] D +/h61 [(0.51\240\240)(XPA Server Callback Macros)] D +/h62 [(0.52\240\240)(XPA Race Conditions)] D +/h63 [(0.52.0.0.1\240\240)(Last updated: September 10, 2003)] D +/h64 [(0.53\240\240)(Xpaoom: What happens when XPA runs out of memory?)] D +/h65 [(0.54\240\240)(Summary)] D +/h66 [(0.55\240\240)(Description)] D +/h67 [(0.55.0.0.1\240\240)(Last updated: April 7, 2009)] D +/h68 [(0.56\240\240)(XPAClient: The XPA Client-side Programming Interface)] D +/h69 [(0.57\240\240)(Summary)] D +/h70 [(0.58\240\240)(Introduction to XPA Client Programming)] D +/h71 [(0.59\240\240)(Introduction)] D +/h72 [(0.60\240\240)(XPAGet: retrieve data from one or more XPA servers)] D +/h73 [(0.61\240\240)(XPASet: send data to one or more XPA servers)] D +/h74 [(0.62\240\240)(XPAInfo: send short message to one or more XPA servers)] D +/h75 [(0.63\240\240)(XPAGetFd: retrieve data from one or more XPA servers and write to files)] D +/h76 [(0.64\240\240)(XPASetFd: send data from stdin to one or more XPA servers)] D +/h77 [(0.65\240\240)(XPAOpen: allocate a persistent client handle)] D +/h78 [(0.66\240\240)(XPAClose: close a persistent XPA client handle)] D +/h79 [(0.67\240\240)(XPANSLookup: lookup registered XPA access points)] D +/h80 [(0.68\240\240)(XPAAccess: return XPA access points matching template \(XPA 2.1 and above\))] D +/h81 [(0.68.0.0.1\240\240)(Last updated: March 10, 2007)] D +/h82 [(0.69\240\240)(XPAXt: the XPA Interface to Xt \(X Windows\))] D +/h83 [(0.70\240\240)(Summary)] D +/h84 [(0.71\240\240)(Description)] D +/h85 [(0.71.0.0.1\240\240)(Last updated: September 10, 2003)] D +/h86 [(0.72\240\240)(XPATcl: the XPA Interface to the Tcl/Tk Environment)] D +/h87 [(0.73\240\240)(Summary)] D +/h88 [(0.74\240\240)(Server Routines)] D +/h89 [(0.75\240\240)(Client Routines)] D +/h90 [(0.76\240\240)(Description)] D +/h91 [(0.77\240\240)(XPANew)] D +/h92 [(0.78\240\240)(XPARec)] D +/h93 [(0.78.0.0.1\240\240)(Last updated: September 10, 2003)] D +/h94 [(0.79\240\240)(XPAEnv: Environment Variables for XPA Messaging)] D +/h95 [(0.80\240\240)(Summary)] D +/h96 [(0.81\240\240)(Description)] D +/h97 [(0.81.0.0.1\240\240)(Last updated: December 23, 2009)] D +/h98 [(0.82\240\240)(XPAAcl: Access Control for XPA Messaging)] D +/h99 [(0.83\240\240)(Summary)] D +/h100 [(0.84\240\240)(Description)] D +/h101 [(0.84.0.0.1\240\240)(Last updated: September 10, 2003)] D +/h102 [(0.85\240\240)(XPA ChangeLog)] D +/h103 [(0.86\240\240)(Public Release 2.1.15 \(July 23, 2013\))] D +/h104 [(0.87\240\240)(Public Release 2.1.14 \(June 7, 2012\))] D +/h105 [(0.88\240\240)(Public Release 2.1.13 \(April 14, 2011\))] D +/h106 [(0.89\240\240)(Public Release 2.1.12 \(January 26, 2010\))] D +/h107 [(0.90\240\240)(Public Release 2.1.11 \(December 7, 2009\))] D +/h108 [(0.91\240\240)(Public Release 2.1.10 \(September 1, 2009\))] D +/h109 [(0.92\240\240)(Internal Release 2.1.9)] D +/h110 [(0.93\240\240)(Public Release 2.1.8 \(1 November 2007\))] D +/h111 [(0.94\240\240)(Patch Release 2.1.7b[1,2] \(Feb 22, 2006; March 8, 2007\))] D +/h112 [(0.95\240\240)(Patch Release 2.1.6 \(4 May 2005\))] D +/h113 [(0.96\240\240)(Patch Release 2.1.5 \(12 January 2004\))] D +/h114 [(0.97\240\240)(Patch Release 2.1.4 \(24 March 2003\))] D +/h115 [(0.98\240\240)(Patch Release 2.1.3 \(26 September 2002\))] D +/h116 [(0.99\240\240)(Patch Release 2.1.2 \(18 July 2002\))] D +/h117 [(0.100\240\240)(Patch Release 2.1.1 \(20 June 2002\))] D +/h118 [(0.101\240\240)(Public Release 2.1.0 \(22 April 2002\))] D +/h119 [(0.102\240\240)(Pre-Release 2.1.0e \(2 April 2002\))] D +/h120 [(0.103\240\240)(Pre-Release 2.1.0e \(1 April 2002\))] D +/h121 [(0.104\240\240)(Pre-Release 2.1.0e \(25 March 2002\))] D +/h122 [(0.105\240\240)(Pre-Release 2.1.0e \(19 March 2002\))] D +/h123 [(0.106\240\240)(Pre-Release 2.1.0e \(14 February 2002\))] D +/h124 [(0.107\240\240)(Pre-Release 2.1.0e \(11 February 2002\))] D +/h125 [(0.108\240\240)(Beta Release 2.1.0b10 \(31 January 2002\))] D +/h126 [(0.109\240\240)(Beta Release 2.1.0b9 \(26 January 2002\))] D +/h127 [(0.110\240\240)(Beta Release 2.1.0b8 \(4 January 2002\))] D +/h128 [(0.111\240\240)(Beta Release 2.1.0b7 \(21 December 2001\))] D +/h129 [(0.112\240\240)(Beta Release 2.1.0b6 \(29 October 2001\))] D +/h130 [(0.113\240\240)(Beta Release 2.1.0b5 \(22 October 2001\))] D +/h131 [(0.114\240\240)(Beta Release 2.1.0b4 \(24 September 2001\))] D +/h132 [(0.115\240\240)(Beta Release 2.1.0b3 \(6 September 2001\))] D +/h133 [(0.116\240\240)(Beta Release 2.1.0b2 \(17 August 2001\))] D +/h134 [(0.117\240\240)(Beta Release 2.1.0b1 \(6 August 2001\))] D +/h135 [(0.118\240\240)(Patch Release 2.0.5 \(10 November 2000\))] D +/h136 [(0.119\240\240)(Patch Release 2.0.4 \(20 September 2000\))] D +/h137 [(0.120\240\240)(Patch Release 2.0.3 \(15 June 2000\))] D +/h138 [(0.121\240\240)(Patch Release 2.0.2 \(9 September 1999\))] D +/h139 [(0.122\240\240)(Patch Release 2.0.1 \(6 August 1999\))] D +/h140 [(0.123\240\240)(Public Release 2.0 \(27 May 1999\))] D +/h141 [(0.123.0.0.1\240\240)(Last updated: 22 April 2002)] D +/h142 [(0.124\240\240)(XPACode: Where to Find Example/Test Code)] D +/h143 [(0.125\240\240)(Summary)] D +/h144 [(0.126\240\240)(Description)] D +/h145 [(0.126.0.0.1\240\240)(Last updated: September 10, 2003)] D +/h146 [(0.127\240\240)(XPA Changes: Changes For Users from XPA 1.0 and 2.0)] D +/h147 [(0.128\240\240)(Summary)] D +/h148 [(0.129\240\240)(Description)] D +/h149 [(0.129.0.0.1\240\240)(Last updated: September 10, 2003)] D +/h150 [(0.130\240\240)(XPAConvert: Converting the XPA API to 2.0)] D +/h151 [(0.131\240\240)(Summary)] D +/h152 [(0.132\240\240)(Description)] D +/h153 [(0.132.0.0.1\240\240)(Last updated: September 10, 2003)] D +/h154 [(0.133\240\240)(XPAName: What does XPA stand for?)] D +/h155 [(0.134\240\240)(Summary)] D +/h156 [(0.135\240\240)(Description)] D +/h157 [(0.135.0.0.1\240\240)(Last updated: September 10, 2003)] D +/Hr [-47 47 48 49 -50 -50 50 -54 54 55 56 -57 -57 57 -59 59 60 61 -62 -62 +62 -64 64 65 66 -67 -67 67 -69 69 70 71 -72 -72 72 -74 74 75 76 77 78 79 +-80 -80 80 -82 82 83 84 -85 -85 85 -86 86 87 88 89 90 91 -92 -92 92 -94 +94 95 96 97 -98 -98 98 -100 100 101 -102 -102 102 -106 106 107 108 109 110 +111 112 113 114 115 116 117 118 119 120 121 -122 -122 122 -124 124 125 126 +-127 -127 127 -130 130 131 132 133 134 135 136 137 138 139 140 141 142 -143 +-143 143 -145 145 146 147 -148 -148 148 -151 151 152 153 154 155 156 157 +-158 -158 158 -160 160 161 162 -163 -163 163 -165 165 166 167 -168 -168 +168 -169 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 +185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 +203 204 205 206 207 -208 -208 208 -210 210 211 212 -213 -213 213 -215 215 +216 217 -218 -218 218 -220 220 221 222 -223 -223 223 -225 225 226 227 -228 +-228 228]D +/HV [1 2 2 2 3 4 5 1 2 2 2 3 4 5 1 2 2 2 3 4 5 1 2 2 2 3 4 5 1 2 2 2 3 +4 5 1 2 2 2 2 2 2 3 4 5 1 2 2 2 3 4 5 1 2 2 2 2 2 2 3 4 5 1 2 2 2 2 3 4 +5 1 2 2 3 4 5 1 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 3 4 5 1 2 2 2 3 4 5 1 2 +2 2 2 2 2 2 2 2 2 2 2 2 3 4 5 1 2 2 2 3 4 5 1 2 2 2 2 2 2 2 3 4 5 1 2 2 +2 3 4 5 1 2 2 2 3 4 5 1 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 3 4 5 1 2 2 2 3 4 5 1 2 2 2 3 4 5 1 2 2 2 +3 4 5 1 2 2 2 3 4 5]D +/Cn [3 0 0 1 1 1 0 3 0 0 1 1 1 0 3 0 0 1 1 1 0 3 0 0 1 1 1 0 3 0 0 1 1 +1 0 6 0 0 0 0 0 1 1 1 0 3 0 0 1 1 1 0 6 0 0 0 0 0 1 1 1 0 4 0 0 0 1 1 1 +0 2 0 1 1 1 0 16 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 3 0 0 1 1 1 0 13 +0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 3 0 0 1 1 1 0 7 0 0 0 0 0 0 1 1 1 0 3 0 +0 1 1 1 0 3 0 0 1 1 1 0 39 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 3 0 0 1 1 1 0 3 0 0 1 1 1 0 3 0 0 +1 1 1 0 3 0 0 1 1 1 0]D +Hr length 0 gt{[/PageMode /UseOutlines /DOCVIEW pdfmark}if +/Hn 1 D +0 1 Hr length 1 sub{ + /Bn E D [Cn Bn get dup 0 gt{/Count E HV Bn get Bl ge{neg}if}{pop}ie + /Dest Hr Bn get dup abs ST cvs cvn E 0 ge{(h)Hn ST cvs join cvx exec + dup 1 get E Nf{0 get E join}{pop}ie /Hn Hn 1 add D}{()}ie + /Title E dup length 255 gt{0 255 getinterval}if /OUT pdfmark}for +ZF /FN Fp D Ps 0 FS /WC Wf{( )}{<A1A1>}ie SW pop D +ET RC ZF +/Df f D +/R1 (http://hea-www.harvard.edu/RD/xpa/changelog.html) D +/Ba f D /BO 0 D Bs +/UR (help.html) D +/Ti (The XPA Help Facility) D +/Au () D +/Df f D +/ME [()] D + TC + +/Cb Db D /Ct [16#00 16#00 16#00] D /Cl [16#00 16#00 16#00] D /CL -1 D Ct Sc + +/Ba f D /BO 0 D Bs +/UR (help.html) D +/Ti (The XPA Help Facility) D +/Au () D +/Df f D +/ME [()] D + TC + +NP RC ZF +()1 Sl()WB 0 Sn( + + +)0 2 0 H(XPA:)WB 47 Sn()WB 1 Sn( Public Access to Data and Algorithms)EA()EH( + + +)0 2 1 H(Summary)WB 48 Sn()EH( +This document is the Table of Contents for XPA. + + +)0 2 2 H(Description)WB 49 Sn()EH( +)0 P(The XPA messaging system provides seamless communication between many +kinds of Unix programs, including X programs and Tcl/Tk programs. It +also provides an easy way for users to communicate with XPA-enabled +programs by executing XPA client commands in the shell or by utilizing +such commands in scripts. Because XPA works both at the programming +level and the shell level, it is a powerful tool for unifying any +analysis environment: users and programmers have great flexibility in +choosing the best level or levels at which to access XPA services, and +client access can be extended or modified easily at any time. + +)0 P(A program becomes an XPA-enabled server by defining named points of +public access through which data and commands can be exchanged with +other client programs \201and users\202. Using standard TCP sockets as a +transport mechanism, XPA supports both single-point and broadcast +messaging to and from these servers. It supports direct communication +between clients and servers, or indirect communication via an +intermediate message bus emulation program. Host-based access control +is implemented, as is as the ability to communicate with XPA servers +across a network. + +)0 P(XPA implements a layered interface that is designed to be useful both +to software developers and to users. The interface consists of a +library of XPA client and server routines for use in C/C++ programs and +a suite of high-level user programs built on top of these libraries. +Using the XPA library, access points can be added to Tcl/Tk programs, +Xt programs, or to Unix programs that use the XPA event loop or any +event loop based on select\201\202. Client access subroutines can be added +to any Tcl/Tk, Xt, or Unix program. Client access also is supported at +the command line via a suite of high-level programs. + +)0 P(Choose from the following topics: + +)UL( +)-1 LI()0 2 1 A(Introduction to XPA)2 1 TN TL()Ec /AF f D( + +)-1 LI()0 3 1 A(Access Point Names and Templates)3 1 TN TL()Ec /AF f D( + +)-1 LI()0 4 1 A(Getting Common Information About Access Points)4 1 TN TL()Ec /AF f D( + +)-1 LI()0 5 1 A(Communication Methods)5 1 TN TL()Ec /AF f D( + +)-1 LI()0 6 1 A(Communication Between Hosts)6 1 TN TL()Ec /AF f D( + +)-1 LI()0 7 1 A(Distinguishing Users)7 1 TN TL()Ec /AF f D( + + +)-1 LI()0 8 1 A(XPA User Programs)8 1 TN TL()Ec /AF f D( +)UL()-1 LI()0 9 1 A(xpaget: get data and info)9 1 TN TL()Ec /AF f D( + +)-1 LI()0 10 1 A(xpaset: send data and info)10 1 TN TL()Ec /AF f D( + +)-1 LI()0 11 1 A(xpainfo: send info alert)11 1 TN TL()Ec /AF f D( + +)-1 LI()0 12 1 A(xpaaccess: get access point info)12 1 TN TL()Ec /AF f D( + +)-1 LI()0 13 1 A(xpamb: message bus emulation)13 1 TN TL()Ec /AF f D( + +)-1 LI()0 14 1 A(xpans: the XPA name server)14 1 TN TL()Ec /AF f D( +)LU( + +)-1 LI()0 15 1 A(XPA Server Routines)15 1 TN TL()Ec /AF f D( +)UL()-1 LI()0 16 1 A(XPANew: define a new access point)16 1 TN TL()Ec /AF f D( + +)-1 LI()0 17 1 A(XPACmdNew: define a new command access point)17 1 TN TL()Ec /AF f D( + +)-1 LI()0 18 1 A(XPACmdAdd: add a command)18 1 TN TL()Ec /AF f D( + +)-1 LI()0 19 1 A(XPACmdDel: delete a command)19 1 TN TL()Ec /AF f D( + +)-1 LI()0 20 1 A(XPAInfoNew: define an info access point)20 1 TN TL()Ec /AF f D( + +)-1 LI()0 21 1 A(XPAFree: free an access point)21 1 TN TL()Ec /AF f D( + +)-1 LI()0 22 1 A(XPAMainLoop: event loop for select server)22 1 TN TL()Ec /AF f D( + +)-1 LI()0 23 1 A(XPAPoll: poll for XPA events)23 1 TN TL()Ec /AF f D( + +)-1 LI()0 24 1 A(XPACleanup: release reserved XPA memory)24 1 TN TL()Ec /AF f D( + +)-1 LI()0 25 1 A(XPA Server Macros: accessing structure internals)25 1 TN TL()Ec /AF f D( + +)-1 LI()0 26 1 A(XPA Race Conditions: how to avoid them)26 1 TN TL()Ec /AF f D( + +)-1 LI()0 27 1 A(XPA Out of Memory \201OOM\202 errors)27 1 TN TL()Ec /AF f D( +)LU( + +)-1 LI()0 28 1 A(XPA Client Routines)28 1 TN TL()Ec /AF f D( +)UL()-1 LI()0 29 1 A(XPAOpen: open a persistent client connection)29 1 TN TL()Ec /AF f D( + +)-1 LI()0 30 1 A(XPAClose: close persistent client connection)30 1 TN TL()Ec /AF f D( + +)-1 LI()0 31 1 A(XPAGet: get data)31 1 TN TL()Ec /AF f D( + +)-1 LI()0 32 1 A(XPASet: send data or commands)32 1 TN TL()Ec /AF f D( + +)-1 LI()0 33 1 A(XPAInfo: send an info alert)33 1 TN TL()Ec /AF f D( + +)-1 LI()0 34 1 A(XPAGetFd: get data and write to an fd)34 1 TN TL()Ec /AF f D( + +)-1 LI()0 35 1 A(XPASetFd: read data from and fd and send)35 1 TN TL()Ec /AF f D( + +)-1 LI()0 36 1 A(XPANSLookup: look up an access point)36 1 TN TL()Ec /AF f D( + +)-1 LI()0 37 1 A(XPAAccess: get access info)37 1 TN TL()Ec /AF f D( + +)-1 LI()0 38 1 A(The XPA/Xt Interface: Xt interface to XPA)38 1 TN TL()Ec /AF f D( + +)-1 LI()0 39 1 A(The XPA/Tcl Interface: Tcl interface to XPA)39 1 TN TL()Ec /AF f D( +)LU( + +)-1 LI( Tailoring the XPA Environment +)UL()-1 LI()0 40 1 A(Environment Variables)40 1 TN TL()Ec /AF f D( + +)-1 LI()0 41 1 A(Access Control)41 1 TN TL()Ec /AF f D( +)LU( + +)-1 LI( Miscellaneous +)UL( +)-1 LI()0 42 1 A(XPA ChangeLog)42 1 TN TL()Ec /AF f D( + +)-1 LI()0 43 1 A(Where to Find Example/Test Code)43 1 TN TL()Ec /AF f D( +)-1 LI()0 44 1 A(User Changes Between XPA 1.0 and 2.0)44 1 TN TL()Ec /AF f D( +)-1 LI()0 45 1 A(API Changes Between XPA 1.0 and 2.0)45 1 TN TL()Ec /AF f D( +)-1 LI()0 46 1 A(What Does XPA Stand For, Anyway?)46 1 TN TL()Ec /AF f D()LU( +)LU( + + + +)0 5 3 H(Last)WB 50 Sn( updated: September 10, 2003)EH( +)WB NL NP Ep ET /Tc f D +/Cb Db D /Ct [16#00 16#00 16#00] D /Cl [16#00 16#00 16#00] D /CL -1 D Ct Sc +DS +/Ba f D /BO 0 D Bs +/UR (intro.html) D +/Ti (Introduction to XPA) D +/Au () D +/Df f D +/ME [()] D + +0 BO R +()1 Sl()WB 2 Sn( + + +)0 2 4 H(XPAIntro:)WB 54 Sn()WB 51 Sn( Introduction to the XPA Messaging System)EA()EH( + + +)0 2 5 H(Summary)WB 55 Sn()EH( +)0 P(A brief introduction to the XPA messaging system, which provides +seamless communication between all kinds of Unix event-driven +programs, including X programs, Tcl/Tk programs, and Perl programs. + + +)0 2 6 H(Description)WB 56 Sn()EH( +)0 P(The XPA messaging system provides seamless communication between all +kinds of Unix programs, including X programs, Tcl/Tk programs, and +Perl programs. It also provides an easy way for users to communicate +with these XPA-enabled programs by executing XPA client commands in +the shell or by utilizing such commands in scripts. Because XPA works +both at the programming level and the shell level, it is a powerful +tool for unifying any analysis environment: users and programmers have +great flexibility in choosing the best level or levels at which to +access XPA services, and client access can be extended or modified +easily at any time. + +)0 P(A program becomes an XPA-enabled server by defining named points of +public access through which data and commands can be exchanged with +other client programs \201and users\202. Using standard TCP sockets as +a transport mechanism, XPA supports both single-point and broadcast +messaging to and from these servers. It supports direct communication +between clients and servers, or indirect communication via an +intermediate message bus emulation program. Host-based access control +is implemented, as is as the ability to communicate with XPA servers +across a network. + +)0 P(XPA implements a layered interface that is designed to be useful both +to software developers and to users. The interface consists of a +library of XPA client and server routines for use in programs and a +suite of high-level user programs built on top of these libraries. +Using the XPA library, access points can be added to +)0 52 1 A(Tcl/Tk)52 0 TN TL()Ec /AF f D( +programs, +)0 53 1 A(Xt)53 0 TN TL()Ec /AF f D( +programs, or to Unix programs that use the XPA event loop or any +event loop based on select\201\202. Client access subroutines can be added +to any Tcl/Tk or Unix program. Client access also is supported at the +command line via a suite of high-level programs. + +)0 P(The major components of the XPA layered interface are: +)UL()-1 LI(A set of XPA server routines, centered on +)0 16 1 A(XPANew\201\202,)16 0 TN TL()Ec /AF f D( +which are used by XPA server programs to tag public access points with +string identifiers and to register send and receive callbacks for +these access points. + +)-1 LI(A set of XPA client routines, centered on the +)0 32 1 A(XPASet\201\202)32 0 TN TL()Ec /AF f D( +and +)0 31 1 A(XPAGet\201\202,)31 0 TN TL()Ec /AF f D( +which are used by external client applications to exchange data and +commands with an XPA server. + +)-1 LI(High-level programs, centered on +)0 10 1 A(xpaset)10 0 TN TL()Ec /AF f D( +and +)0 9 1 A(xpaget,)9 0 TN TL()Ec /AF f D( +which allow data +and information to be exchanged with XPA server programs from the +command line and from scripts. These programs have the command syntax: +) 2 35 PR( [data] | xpaset [qualifiers ...] + xpaget [qualifiers ...])RP( +)-1 LI(An XPA name server program, +)0 14 1 A(xpans,)14 0 TN TL()Ec /AF f D( +through which XPA access point names are +registered by servers and distributed to clients.)LU( + +)0 P(Defining an XPA access point is easy: a server application calls +)0 16 1 A(XPANew\201\202,)16 0 TN TL()Ec /AF f D( +)0 17 1 A(XPACmdNew\201\202,)17 0 TN TL()Ec /AF f D( +or the experimental +)0 20 1 A(XPAInfoNew\201\202)20 0 TN TL()Ec /AF f D( +routine to +create a named public access point. An XPA service can specify "send" +and "receive" callback procedures \201or an "info" procedure in the case +of XPAInfoNew\201\202\202 to be executed by the program when an external +process either sends data or commands to this access point or requests +data or information from this access point. Either of the callbacks +can be omitted, so that a particular access point can be specified as +read-only, read-write, or write-only. Application-specific client +data can be associated with these callbacks. Having defined one or +more public access points in this way, an XPA server program enters +its usual event loop \201or uses the standard XPA event loop\202. + +)0 P(Clients communicate with these XPA public access points +using programs such as +)0 9 1 A(xpaget)9 0 TN TL()Ec /AF f D(, +)0 10 1 A(xpaset)10 0 TN TL()Ec /AF f D(, and +)0 11 1 A(xpainfo)11 0 TN TL()Ec /AF f D( +\201at the command line\202, +or routines such as +)0 31 1 A(XPAGet\201\202,)31 0 TN TL()Ec /AF f D( +)0 32 1 A(XPASet\201\202,)32 0 TN TL()Ec /AF f D( +and +)0 33 1 A(XPAInfo\201\202)33 0 TN TL()Ec /AF f D( +within a program. Both methods require specification of the name of +the access point. The xpaget program returns data or other +information from an XPA server to its standard output, while the +xpaset program sends data or commands from its standard input to an +XPA application. The corresponding API routines set/get data to/from +memory, returning error messages and other info as needed. If a +)0 3 1 A(template)3 0 TN TL()Ec /AF f D( +is used to specify the access point name \201e.g., "ds9*"\202, then +communication will take place with all servers matching that template. + +)0 P(Please note that XPA currently is not thread-safe. All XPA calls must be +in the same thread. + + + + + +)0 P()0 0 1 A(Go to XPA Help Index)0 0 TN TL()Ec /AF f D( + +)0 5 7 H(Last)WB 57 Sn( updated: March 10, 2007)EH( + +)WB NL +/Cb Db D /Ct [16#00 16#00 16#00] D /Cl [16#00 16#00 16#00] D /CL -1 D Ct Sc +DS +/Ba f D /BO 0 D Bs +/UR (template.html) D +/Ti (Access Point Names and Templates) D +/Au () D +/Df f D +/ME [()] D + +0 BO R +()1 Sl()WB 3 Sn( + + +)0 2 8 H(XPATemplate:)WB 59 Sn()WB 58 Sn( Access Point Names and Templates)EA()EH( + +)0 2 9 H(Summary)WB 60 Sn()EH( +)0 P(XPA access points are composed of two parts: a general class and a +specific name. Both parts accept template characters so that you +can send/retrieve data to/from multiple servers at one time. + + +)0 2 10 H(Description)WB 61 Sn()EH( +)0 P(When XPA servers call +)0 16 1 A(XPANew\201\202,)16 0 TN TL()Ec /AF f D( +or +)0 17 1 A(XPACmdNew\201\202)17 0 TN TL()Ec /AF f D( +to define XPA access points, they specify a string identifier composed of a +class and a name. When clients communicate with XPA access points, +they specify which access points to communicate with using +an identifier of the form: +) 1 12 PR( class:name)RP( +All registered XPA access points that match the specified identifier +will be available for communication \201subject to access control rules, +etc.\202 + +)0 P(As of XPA 2.1.5, the length of both the class and name designations are +limited to 1024 characters. + +)0 P(The XPA class:name identifier actually is a template: it accepts wild +cards in its syntax, so a single specifier can match more than one XPA +access point. \201Note that the class is optional and defaults to "*".\202 +The allowed syntax for clients to specify the class:name template is +of the form shown below. \201Note that "*" is used to denote a generic +wild card, but other wild cards characters are supported, as described +below\202. +) 7 46 PR( template explanation + -------- ----------- + class:name exact match of class and name + name match any class with this name + *:name match any class with this name + class:* match any name of this class + *:* match any access point)RP( +)0 P(In general, the following wild-cards can be applied to class and name: +) 5 58 PR( wildcard explanation + -------- ----------- + ? match any character, but there must be one + * match anything, or nothing + [...] match an inclusive set)RP( +)0 P(Although the class:name template normally is used to refer to XPA +access points, these also can be specified using their individual +socket identifiers. For inet sockets, the socket identifier is +)BD(ip:port)ES(, where ip can be the DNS-registered name, +the ASCII IP number \201e.g. 123.45.67.890\202 or the hex IP number +\201e.g. 838f3a60\202. For unix sockets, the identifier is the )BD(socket file +name)ES(. These socket identifiers are displayed as the fourth argument +in the xpans display of registered access points. For example, +consider the ds9 program started using inet sockets. The xpans name +server will register something like this: +) 2 40 PR( csh> xpaget xpans + DS9 ds9 gs saord.harvard.edu:3236 eric)RP( +You can access ds9 using ip:3236 in any of the three forms: +) 8 37 PR( csh> xpaget saord:3236 file + /home/eric/data/snr.ev + + csh> xpaget 123.45.67.890:3236 file + /home/eric/data/snr.ev + + csh> xpaget 838f3a60:3236 file + /home/eric/data/snr.ev)RP( +In the case of unix sockets, the socket identifier is a file: +) 5 41 PR( csh> xpaget xpans + DS9 ds9 gs /tmp/.xpa/DS9_ds9.2631 eric + + csh> xpaget /tmp/.xpa/DS9_ds9.2631 file + /home/eric/data/snr.ev)RP( +This feature can be useful in distinguishing between multiple +instances of a program that all have the same class:name designation. + + + + + +)0 P()0 0 1 A(Go to XPA Help Index)0 0 TN TL()Ec /AF f D( + +)0 5 11 H(Last)WB 62 Sn( updated: September 10, 2003)EH( + +)WB NL +/Cb Db D /Ct [16#00 16#00 16#00] D /Cl [16#00 16#00 16#00] D /CL -1 D Ct Sc +DS +/Ba f D /BO 0 D Bs +/UR (info.html) D +/Ti (Getting Common Information About Access Points) D +/Au () D +/Df f D +/ME [()] D + +0 BO R +()1 Sl()WB 4 Sn( + + +)0 2 12 H(XPACommon:)WB 64 Sn()WB 63 Sn( Getting Common Information About Access Points)EA()EH( + + +)0 2 13 H(Summary)WB 65 Sn()EH( +)0 P(There are various kinds of generic information you can retrieve about +an XPA access point by using the xpaget command. + + +)0 2 14 H(Description)WB 66 Sn()EH( +)0 P(You can find out which XPA access points have been registered with +the currently running +)0 14 1 A(XPA name server)14 0 TN TL()Ec /AF f D( +by executing the +)0 9 1 A(xpaget)9 0 TN TL()Ec /AF f D( +command to retrieve info from the XPA name server: +) 1 14 PR( xpaget xpans)RP( +If, for example, the +)0 43 1 A(stest)43 0 TN TL()Ec /AF f D( test server program +is running, the following XPA access points will be returned \201the specifics +of the returned info will vary for different machines and users\202: +) 4 33 PR( XPA xpa gs 838e2f67:1262 eric + XPA xpa1 gs 838e2f67:1266 eric + XPA c_xpa gs 838e2f67:1267 eric + XPA i_xpa i 838e2f67:1268 eric)RP( +Note that access to this information is subject to the usual +)0 41 1 A(XPA Access Control)41 0 TN TL()Ec /AF f D( restrictions. + +)0 P(Each XPA access point supports a number of reserved sub-commands that provide +access to different kinds of information, e.g. the access control for +that access point. These sub-commands can be executed by using +)0 10 1 A(xpaset)10 0 TN TL()Ec /AF f D( +or +)0 9 1 A(xpaget)9 0 TN TL()Ec /AF f D( +at the command line, or +)0 31 1 A(XPAGet\201\202)31 0 TN TL()Ec /AF f D( +or +)0 32 1 A(XPASet\201\202)32 0 TN TL()Ec /AF f D( +in programs, e.g: +) 5 30 PR( xpaget ds9 -acl + xpaget ds9 -help + xpaget ds9 env FOO + + xpaset -p ds9 env FOO foofoo)RP( +With the exception of )BD(-help)ES( and )BD(-version)ES(, reserved +sub-commands are available only on the machine on which the XPA server +itself is running. + +The following reserved sub-commands are defined for all access points: +)0 DL( +)0 P()0 DT()BD(-acl)ES( get \201set\202 the access control list [options: host type acl, for set] +)DD( +The 'xpaset' option allows you to add a new acl for a given host, or change +the acl for an existing host. See +)0 41 1 A(XPA Access Control)41 0 TN TL()Ec /AF f D( +for more information. +This access point is available only on the server machine. + +)0 P()0 DT()BD(-env)ES( get \201set\202 an environment variable [options: name \201value, for set\202] +)DD(The 'xpaget' option will return the value of the named environment +variable. The 'xpaset' option will set the value of the names +variable to the specified value. +This access point is available only on the server machine. +\201Please be advised that we have had problems setting environment +variables in static Tcl/Tk programs such as ds9 running under Linux.\202 + +)0 P()0 DT( )BD(-clipboard)ES( set\201get\202 information on a named clipboard +)DD( Clients can store ASCII state information on any number of named +clipboards. Clipboards of the same name created by clients on +different machines are kept separate. The syntax for creating a +clipboard is: +) 2 65 PR( [data] | xpaset [server] -clipboard add|append [clipboard_name] + xpaset -p [server] -clipboard delete [clipboard_name])RP( +Use "add" to create a new clipboard or replace the contents of an existing +one. Use "append" to append to an existing clipboard. +)0 P(Information on a named clipboard is retrieved using: +) 1 45 PR( xpaget [server] -clipboard [clipboard_name])RP( +)0 P()0 DT()BD(-exec)ES( set: execute commands from buffer [options: none] +)DD(If -exec is specified in the paramlist of an 'xpaset' call, then further +sub-commands will be retrieved from the data buffer. + +)0 P()0 DT()BD(-help)ES( get: return help string for this XPA or sub-command [options: name \201for sub-commands\202] +)DD(Each XPA access point and each XPA sub-command can have a help string +associated with it that is specified when the access point is defined. +The -help option will return this help string. For XPA access points +that contain user-defined sub-commands, you can get the help string +for a particular sub-command by specifying its name, or else get the +help strings for all sub-commands if not name is specified. + +)0 P()0 DT()BD(-ltimeout)ES( get \201set\202 the long timeout value [options: seconds|reset] +)DD(The 'xpaget' option will return the value of the long timeout \201in seconds\202. +The 'xpaset' option will set the value of the long timeout. If "reset" is +specified, then the timeout value will be reset to the default value. + +)0 P()0 DT()BD(-nsconnect)ES( set: re-establish name server connection to all XPA's [options: none] +)DD(If the +)0 14 1 A(XPA Name Server \201xpans\202)14 0 TN TL()Ec /AF f D( +process has terminated unexpectedly and then re-started, this +sub-command can be used to re-establish the connection. You use it by +sending the command to the [name:port] or [file] of the access point +instead of to the XPA name \201since the latter requires the xpans +connection!\202: +) 1 36 PR( xpaset -p 838e2f67:1268 -nsconnect)RP( +See )0 14 1 A(xpans)14 0 TN TL()Ec /AF f D( for more information. + +)0 P()0 DT()BD(-nsdisconnect)ES( set: break name server connection to all XPA's [options: none] +)DD(This sub-command will terminate the connection to the +)0 14 1 A(XPA Name Server \201xpans\202)14 0 TN TL()Ec /AF f D(, thereby making +all access points inaccessible except through their underlying [name:port] +or [file] identifiers. I forget why we added it, it seems pretty useless. + +)0 P()0 DT()BD(-stimeout)ES( get \201set\202 the short timeout value [options: seconds|reset] +)DD(The 'xpaget' option will return the value of the short timeout \201in seconds\202. +The 'xpaset' option will set the value of the short timeout. If "reset" is +specified, then the timeout value will be reset to the default value. + +)0 P()0 DT()BD(-remote)ES( set: register xpa with remote server [options: host[:port] [acl]] [-proxy] +)DD(This sub-command will register the XPA access point with the XPA name +server \201xpans\202 on the specified host \201which must already be running\202. +The specified host also is given access control to the access point, +using the specified acl or the default acl of "+" \201meaning the remote +host can xpaset, xpaget, xpainfo or xpaaccess\202. If the acl is +specified as "-", then the access point is unregistered. +See )0 6 1 A(Communication Between Machines)6 0 TN TL()Ec /AF f D( +for more information on how this sub-command is used. + +)0 P()0 DT()BD(-version)ES( get: return XPA version string [options: none] +)DD(The version refers to the version of XPA used to define this access point +\201currently something like 2.0\202. +)LD( + +)0 P(You can add your own reserved commands to all XPA access points by using the +)0 18 1 A(XPACmdAdd\201\202)18 0 TN TL()Ec /AF f D( +routine, passing the XPA handle returned by )EM(XPA XPAGetReserved\201void\202)ES( +as the first argument. Note again that these will only be available on the +machine where the XPA service is running. + + + + + +)0 P()0 0 1 A(Go to XPA Help Index)0 0 TN TL()Ec /AF f D( + +)0 5 15 H(Last)WB 67 Sn( updated: September 10, 2003)EH( +)WB NL +/Cb Db D /Ct [16#00 16#00 16#00] D /Cl [16#00 16#00 16#00] D /CL -1 D Ct Sc +DS +/Ba f D /BO 0 D Bs +/UR (method.html) D +/Ti (XPA Communication Methods) D +/Au () D +/Df f D +/ME [()] D + +0 BO R +()1 Sl()WB 5 Sn( + + +)0 2 16 H(XPAMethod:)WB 69 Sn()WB 68 Sn( )EA(XPA Communication Methods)EH( + + +)0 2 17 H(Summary)WB 70 Sn()EH( +)0 P(XPA supports both inet and unix \201local\202 socket communication. + + +)0 2 18 H(Description)WB 71 Sn()EH( +)0 P(XPA uses sockets for communication between processes. It supports +three methods of socket communication: inet, localhost, and unix. In +general, the same method should be employed for all XPA processes in a +session and the global environment variable XPA_METHOD should be used +to set up the desired method. By default, the preferred method is +"inet", which is appropriate for most users. You can set up a +different method by typing something like: +) 3 70 PR( setenv XPA_METHOD local # unix csh + XPA_METHOD=local; export XPA_METHOD # unix sh, bash, windows/cygwin + set XPA_METHOD=localhost # dos/windows)RP( +The options for XPA_METHOD are: )BD(inet)ES(, )BD(unix)ES( \201or +)BD(local)ES(\202, and )BD(localhost)ES(. On Unix machines, this +environment setup command can be placed in your shell init file +\201.cshrc, .profile, .bashrc, etc.\202 On Windows platforms, it can be +placed in your AUTOEXEC.BAT file \201I think!\202. + +)0 P(By default, )BD(inet)ES( sockets are used by XPA. These are the standard +Internet sockets that are used by programs such as Netscape, +ftp. etc. Inet sockets utilize the IP address of the given machine and +a \201usually random\202 port number to communicate between processes on the +same machine or between different machines on the Internet. \201Note that +XPA has an )0 41 1 A(Access Control)41 0 TN TL()Ec /AF f D( mechanism to +prevent unauthorized access of XPA access points by other computers on +the Net\202. For users connected to the Internet, this usually is the +appropriate communication method. For more information about setting +up XPA communication between machines, see +)0 6 1 A(Communication Between Machines)6 0 TN TL()Ec /AF f D(. + +)0 P(In you are using XPA on a machine without an Internet connection, then +inet sockets are not appropriate. In fact, an XPA process often will +hang for many seconds while waiting for a response from the Domain +Name Service \201DNS\202 when using inet sockets. Instead of inet sockets, +users on Unix platforms can also use )BD(unix)ES( sockets \201also known +as local sockets\202. These sockets are based on the local file system +and do not make use of the DNS. They generally are considered to be +faster than inet sockets, but they are not implemented under +Windows. Use local sockets as a first resort if you are on a Unix +machine that is not connected to the Internet. + +)0 P(Users not connected to the Internet also can use )BD(localhost)ES( +sockets. These are also inet-type sockets but the IP address used for +the local machine is the )BD(localhost)ES( address, 0x7F000001, instead +of the real IP of the machine. Depending on how sockets are set up for +a given platform, communication with the DNS usually is not required in +this case \201though of course, XPA cannot interact with other machines\202. +The localhost method will generally work on both Unix and Windows +platforms, but whether the DNS is required or not is subject to +individual configurations. + +)0 P(A final warning/reminder: if your XPA-enabled server hangs at startup +time and your XPA_METHOD is )BD(inet)ES(, the problem probably is +related to an incorrect Internet configuration. This can be confirmed +by using the )BD(unix)ES( method or \201usually\202 the )BD(localhost)ES( +method. You can use these alternate methods if other hosts do not need +access to the XPA server. + + + + + +)0 P()0 0 1 A(Go to XPA Help Index)0 0 TN TL()Ec /AF f D( + +)0 5 19 H(Last)WB 72 Sn( updated: September 10, 2003)EH( +)WB NL +/Cb Db D /Ct [16#00 16#00 16#00] D /Cl [16#00 16#00 16#00] D /CL -1 D Ct Sc +DS +/Ba f D /BO 0 D Bs +/UR (inet.html) D +/Ti (XPA Communication Between Hosts) D +/Au () D +/Df f D +/ME [()] D + +0 BO R +()1 Sl()WB 6 Sn( + + +)0 2 20 H(XPAInet:)WB 74 Sn()WB 73 Sn( XPA Communication Between Hosts)EA()EH( + + +)0 2 21 H(Summary)WB 75 Sn()EH( +XPA uses standard inet sockets to support communication between two or +more host computers. + + +)0 2 22 H(Description)WB 76 Sn()EH( +)0 P(When the )0 5 1 A(Communication Method)5 0 TN TL()Ec /AF f D( is set to +)BD(inet)ES( \201as it is by default\202, XPA can be used to communicate +between different computers on the Internet. INET sockets utilize the +IP address of the given machine and a \201usually random\202 port number to +communicate between processes on the same machine or between different +machines on the Internet. These standard Internet sockets are also +used by programs such as Netscape, ftp. etc. + +)0 P(XPA supports a host-based )0 41 1 A(Access Control)41 0 TN TL()Ec /AF f D( mechanism +to prevent unauthorized access of XPA access points by other computers +on the Net. By default, only the machine on which the XPA server is +running can access XPA services. Therefore, setting up communication +between a local XPA server machine and a remote client machine +requires a two-part registration process: + +)UL()-1 LI( the XPA service on the local machine must be made known to the +remote machine +)-1 LI( the remote machine must be given permission to access the local +XPA service)LU( + +Three methods by which this remote registration can be accomplished +are described below. + +)0 2 23 H(Manual)WB 77 Sn( Registration)EH( + +The first method is the most basic and does not require the remote +client to have xpans running. To use it, the local server simply +gives a remote client machine access to one or more XPA access points +using xpaset and the )BD(-acl)ES( sub-command. For example, +consider the XPA test program "stest" running on a local machine. By +default the access control for the access point named "xpa" is +restricted to that machine: +) 3 25 PR( [sh]$ xpaget xpa -acl + *:* 123.456.78.910 gisa + *:* localhost gisa)RP( +Using xpaset and the )BD(-acl)ES( sub-command, a remote client +machine can be given permission to perform xpaget, xpaset, xpaaccess, +or xpainfo operations. For example, to allow the xpaget operation, the +following command can be issued on the local machine: +) 1 45 PR( [sh]$ xpaset -p xpa -acl "remote_machine g")RP( +This results in the following access permissions on the local machine: +) 4 26 PR( [sh]$ xpaget xpa -acl + XPA:xpa 234.567.89.012 g + *:* 123.456.78.910 gisa + *:* localhost gisa)RP( + +The remote client can now use the local server's xpans name server to +establish communication with the local XPA service. This can be done +on a call-by-call basis using the )BD(-i)ES( switch on xpaset, xpaget, etc: +) 6 43 PR( [sh]$ xpaget -i "local_machine:12345" xpa + class: XPA + name: xpa + method: 88877766:2778 + sendian: little + cendian: big)RP( +Alternatively, the XPA_NSINET variable on the remote machine can be +set to point directly to xpans on the local machine, removing +the need to override this value each time an XPA program is run: +) 7 42 PR( [csh]$ setenv XPA_NSINET 'karapet:$port' + [csh]$ xpaget xpa + class: XPA + name: xpa + method: 88877766:2778 + sendian: little + cendian: big)RP( +Here, '$port' means to use the default XPA name service port \20114285\202. +not a port environment variable. + +)0 P(Access permission for remote client machines can be stored in a file +on the local machine pointed to by the )BD(XPA_ACLFILE)ES( environment +variable or using the )BD(XPA_DEFACL)ES( environment variable. See )0 41 1 A(XPA Access Control)41 0 TN TL()Ec /AF f D( for more information. + +)0 2 24 H(Remote)WB 78 Sn( Registration)EH( + +If xpans is running on the remote client machine, then a local xpaset +command can be used with the )BD(-remote)ES( sub-command to +register the local XPA service in the remote name service, while at +the same time giving the remote machine permission to access the local +service. For example, assume again that "stest" is running on the +local machine and that xpans is also running on the remote machine. +To register access of this local xpa on the remote machine, use +the xpaset and the )BD(-remote)ES( sub-command: +) 1 56 PR( [sh]$ ./xpaset -p xpa -remote 'remote_machine:$port' +)RP( +To register the local xpa access point on the remote machine with xpaget +access only, execute: +) 1 56 PR( [sh]$ ./xpaset -p xpa -remote 'remote_machine:$port' g)RP( +Once the remote registration command is executed, the remote client +machine will have an entry such as the following in its own xpans name +service: +) 2 31 PR( [csh]$ xpaget xpans + XPA xpa gs 88877766:2839 eric)RP( +The xpa access point can now be utilized on the remote machine without +further setup: +) 6 23 PR( [csh]$ xpaget xpa + class: XPA + name: xpa + method: 838e2f68:2839 + sendian: little + cendian: big)RP( +To unregister remote access from the local machine, use the same +command but with a '-' argument: +) 1 54 PR( [sh]$ xpaset -p xpa -remote 'remote_machine:$port' -)RP( +The benefit of using remote registration is that communication with +remote access points can be mixed with that of other access points +on the remote machine. Using )0 3 1 A(Access Point +Names and Templates)3 0 TN TL()Ec /AF f D(, one XPA command can be used to send or +receive messages to the remote and local services. + +)0 2 25 H(XPANS)WB 79 Sn( Proxy Registration)EH( + +The two methods described above are useful when the local and remote +machines are able to communicate freely to one another. This would be +the case on most Local Area Networks \201LANs\202 where all machines are +behind the same firewall and there is no port blocking between +machines on the same LAN. The situation is more complicated when the +XPA server is behind a firewall, where outgoing connections are +allowed, but incoming port blocking is implemented to prevent machines +outside the firewall from connecting to machines inside the +firewall. Such incoming port blocking will prevent xpaset and xpaget +from connecting to an XPA server inside a firewall. + +)0 P(To allow locally fire-walled XPA services to register with remote +machines, we have implemented a proxy service within the xpans name +server. To register remote proxy service, xpaset and the +)BD(-remote)ES( sub-command is again used, but with an additional +)BD(-proxy)ES( argument added to the end of the command: +) 1 63 PR( [sh]$ ./xpaset -p xpa -remote 'remote_machine:$port' g -proxy)RP( +Once a remote proxy registration command is executed, the remote +machine will have an entry such as the following in its own xpans name +service: +) 2 32 PR( [csh]$ xpaget xpans + XPA xpa gs @88877766:2839 eric)RP( +The '@' sign in the name service entry indicates that xpans proxy +processing is being used for this access point. Other than that, from +the user's point of view, there is no difference in how this XPA +access point is contacted using XPA programs \201xpaset, xpaget, etc.\202 or +libraries: +) 6 23 PR( [csh]$ xpaget xpa + class: XPA + name: xpa + method: 88877766:3053 + sendian: little + cendian: big)RP( +)0 P(Of course, the underlying processing of the XPA requests is very much +different when xpans proxy is involved. Instead of an XPA program such +contacting the XPA service directly, it contacts the local xpans. +Acting as a proxy server, xpans communicates with the XPA service +using the command channel established at registration time. Commands +\201including establishing a new data channel\202 are sent between xpans and +the XPA service to set up a new message transfer, and then data is fed +to/from the xpa request, through xpans, from/to the XPA service. In +this way, it can be arranged so that connections between the +fire-walled XPA service and the remote client are always initiated by +the XPA service itself. Thus, incoming connections that would be +blocked by the firewall are avoided. Note that there is a performance +penalty for using the xpans/proxy service. Aside from extra overhead +to set up proxy communication, all data must be sent through the +intermediate proxy process. + +)0 P(The xpans proxy scheme requires that the remote client allow the local +XPA server machine to connect to the remote xpans/proxy server. If the +remote client machine also is behind a port-blocking firewall, such +connections will be disallowed. In this case, the only solution is to +open up some ports on the remote client machine to allow incoming +connections to xpans/proxy. Two ports must be opened \201for command and +data channel connections\202. By default, these two ports are 14285 and +14287. The port numbers can be changed using the )BD(XPA_NSINET)ES( +environment variable. This variable takes the form: +) 1 49 PR( setenv XPA_NSINET machine:port1[,port2[,port3]])RP( +where port1 is the main connecting port, port2 is the XPA access port, +and port3 is the secondary data connecting port. The second and third +ports are optional and default to port1+1 and port1+2, respectively. +It is port1 and port3 that must be left open for incoming connections. + +)0 P(For example, to change the port assignments so that xpans listens +for registration commands on port 12345 and data commands on port 28573: +) 1 32 PR( setenv XPA_NSINET myhost:12345)RP( +Alternatively, all three ports can be assigned explicitly: +) 1 43 PR( setenv XPA_NSINET remote:12345,3000,12346)RP( +In this case 12345 and 12346 should be open for incoming connections. +The XPA access port \201which need not be open to the outside +world\202 is set to 3000. + +)0 P(Finally, note that we currently have no mechanism to cope with +Internet proxy servers \201such as SOCKS servers\202. If an XPA service is +running on a machine that cannot connect directly to outside machines, +but goes through a proxy server instead, there currently is no way to +register that XPA service with a remote machine. We hope to implement +support for SOCKS proxy in a future release. + + + + + +)0 P()0 0 1 A(Go to XPA Help Index)0 0 TN TL()Ec /AF f D( + +)0 5 26 H(Last)WB 80 Sn( updated: September 10, 2003)EH( +)WB NL +/Cb Db D /Ct [16#00 16#00 16#00] D /Cl [16#00 16#00 16#00] D /CL -1 D Ct Sc +DS +/Ba f D /BO 0 D Bs +/UR (users.html) D +/Ti (Distinguishing Users) D +/Au () D +/Df f D +/ME [()] D + +0 BO R +()1 Sl()WB 7 Sn( + + +)0 2 27 H(XPAUsers:)WB 82 Sn()WB 81 Sn( Distinguishing Users)EA()EH( + + +)0 2 28 H(Summary)WB 83 Sn()EH( +)0 P(XPA normally distinguishes between users on a given host, but it is possible +to send data to access points belonging to other users. + + +)0 2 29 H(Description)WB 84 Sn()EH( +)0 P(A single XPA name service typically serves all users on a given +machine. Two users can register the same XPA access points on the +same machine without conflict, because the user's username is +registered with each access point and, by default, programs such as +xpaget and xpaset only process access points of the appropriate user. +For example: +) 4 32 PR( XPA xpa1 gs 838e2f67:1262 eric + XPA xpa2 gs 838e2f67:1266 eric + XPA xpa1 gs 838e2f67:2523 john + XPA xpa2 gs 838e2f67:2527 john)RP( +Here the users "eric" and "john" both have registered the access +points xpa1 and xpa2. When either "john" or "eric" retrieves +information from xpa1, they will process only the access point +registered in their user name. + +)0 P(If you want to access another user's XPA access points on a single +machine, use the -u [user] option on xpaset, xpaget, etc. For example, +if eric executes: +) 1 21 PR( xpaget -u john xpa1)RP( +he will access John's xpa1 access point.Use "*" to access all users +on a given machine: +) 1 20 PR( xpaget -u "*" xpa1)RP( +Note that the )0 40 1 A(XPA Environment Variable)40 0 TN TL()Ec /AF f D( +XPA_NSUSERS can be used to specify the default list of users to +process: +) 1 32 PR( setenv XPA_NSUSERS "eric,john")RP( +will cause access points from both "eric" and "john" to be processed +by default. + + + + + +)0 P()0 0 1 A(Go to XPA Help Index)0 0 TN TL()Ec /AF f D( + +)0 5 30 H(Last)WB 85 Sn( updated: September 10, 2003)EH( +)WB NL +/Cb Db D /Ct [16#00 16#00 16#00] D /Cl [16#00 16#00 16#00] D /CL -1 D Ct Sc +DS +/Ba f D /BO 0 D Bs +/UR (programs.html) D +/Ti (XPA Programs) D +/Au () D +/Df f D +/ME [()] D + +0 BO R +()1 Sl()WB 8 Sn( +)0 2 31 H(XPA)WB 86 Sn( Programs)EH( + +)0 2 32 H(Summary)WB 87 Sn()EH( + +)0 P(Use the XPA programs to send/receive data to/from XPA servers from the +command line or from scripts. + +)0 P() 7 116 PR( <data> | xpaset [-h] [-i nsinet] [-m method] [-n] [-p] [-s] [-t sval,lval] [-u users] [-v] <template> [paramlist] + + xpaget [-h] [-i nsinet] [-m method] [-s] [-t sval,lval] [-u users] <template> [paramlist] + + xpainfo [-h] [-i nsinet] [-m method] [-n] [-s] [-t sval,lval] [-u users] <template> [paramlist] + + xpaaccess [-c] [-h] [-i nsinet] [-m method] [-n] [-u users] [-v|-V] <template> [type])RP( + + + + +)0 2 33 H(xpaset:)WB 88 Sn()WB 10 Sn( send data to one or more XPA servers)EA()EH( + + +)BD() 1 124 PR(<data> | xpaset [-h] [-i nsinet] [-m method] [-n] [-p] [-s] [-t sval,lval] [-u users] [-v] <template|host:port> [paramlist])RP()ES( + + +)0 P() 10 79 PR( -h print help message + -i access XPA point on different machine \201override XPA_NSINET\202 + -m override XPA_METHOD environment variable + -n don't wait for the status message after server completes + -p don't read \201or send\202 buf data from stdin + -s enter server mode + -t [s,l] set short and long timeouts \201override XPA_[SHORT,LONG]_TIMEOUT\202 + -u [users] XPA points can be from specified users \201override XPA_NSUSERS\202 + -v verify message to stdout + --version display version and exit)RP( + + +)0 P(Data read from stdin will be sent to access points matching the +)0 3 1 A(template)3 0 TN TL()Ec /AF f D( +or host:port. +A set of qualifying parameters can be appended. +)0 P(Normally, xpaset reads data input from stdin until EOF and sends those +data to the XPA target, along with parameters entered on the command +line. For example to send a FITS file to the ds9 image display: +) 1 32 PR( cat foo.fits | xpaset ds9 fits)RP( +)0 P(Sometimes, however, it is desirable to send only parameters to an XPA +access point, without sending data. For such cases, use the -p switch to +indicate that there is no data being send to stdin. For example, to +change the colormap used by the ds9 image display program, use: +) 1 30 PR( csh> xpaset -p ds9 cmap Heat)RP( +Of course, this also can be accomplished by sending EOF to stdin in +any of the usual ways: +) 4 43 PR( csh> echo "" | xpaset ds9 cmap Heat + csh> xpaget ds9 cmap Heat < /dev/null + csh> xpaset ds9 cmap Heat + ^D # Ctl-D signals EOF)RP( +)0 P(The -s switch puts xpaset into server mode, in which commands and data +can be sent to access points without having to run xpaset multiple times. +\201Its not clear if this buys you much!\202 The syntax for sending commands +in server mode is: +)0 P() 8 24 PR( csh> xpaset -s + xpaset ds9 colormap I8 + ^D + xpaset ds9 regions + circle 200 300 40 + circle 300 400 50 + ^D +etc.)RP( +After the required "xpaset" command is specified, optional ASCII data +can be appended \201as in the region example\202. A single data/command set is +delimited by ^D. Note that typing ^D when a command is expected terminates +the program. +)0 P(NB: server mode only works from the terminal and only ASCII data can be +sent in this way. +)0 P()BD(Examples:)ES( +) 2 40 PR( csh> xpaset ds9 file < foo.fits + csh> echo "stop" | xpaset myhost:12345)RP( + + + + +)0 2 34 H(xpaget:)WB 89 Sn()WB 9 Sn( retrieve data from one or more XPA servers)EA()EH( + + +)BD() 1 99 PR(xpaget [-h] [-i nsinet] [-m method] [-s] [-t sval,lval] [-u users] <template|host:port> [paramlist])RP()ES( + + +)0 P() 8 79 PR( -h print help message + -i access XPA point on different machine \201override XPA_NSINET\202 + -m override XPA_METHOD environment variable + -n don't wait for the status message after server completes + -s enter server mode + -t [s,l] set short and long timeouts \201override XPA_[SHORT,LONG]_TIMEOUT\202 + -u [users] XPA points can be from specified users \201override XPA_NSUSERS\202 + --version display version and exit)RP( + + +)0 P(Data will be retrieved from access points matching the +)0 3 1 A(template)3 0 TN TL()Ec /AF f D( +or host:port. +A set of qualifying parameters can be appended. +)0 P()BD(Examples:)ES( +) 2 38 PR( csh> xpaget ds9 images + csh> xpaget myhost.harvard.edu:12345)RP( + + + + +)0 2 35 H(xpainfo:)WB 90 Sn()WB 11 Sn( send short message to one or more XPA servers)EA()EH( + + +)BD() 1 105 PR(xpainfo [-h] [-i nsinet] [-m method] [-n] [-s] [-t sval,lval] [-u users] <template|host:port> [paramlist])RP()ES( + + +)0 P() 8 79 PR( -h print help message + -i access XPA point on different machine \201override XPA_NSINET\202 + -m override XPA_METHOD environment variable + -n don't wait for the status message after server completes + -s enter server mode + -t [s,l] set short and long timeouts \201override XPA_[SHORT,LONG]_TIMEOUT\202 + -u [users] XPA points can be from specified users \201override XPA_NSUSERS\202 + --version display version and exit)RP( + + +)0 P(Info will be sent to access points matching the +)0 3 1 A(template)3 0 TN TL()Ec /AF f D( +or host:port. +A set of qualifying parameters can be appended. +)0 P()BD(Examples:)ES( +) 1 30 PR( csh> xpainfo IMAGE ds9 image)RP( + + + + +)0 2 36 H(xpaaccess:)WB 91 Sn()WB 12 Sn( see if template matches registered XPA access points)EA()EH( + + +)BD() 1 95 PR(xpaaccess [-c] [-h] [-i nsinet] [-m method] [-n] [-t sval,lval] [-u users] -v <template> [type])RP()ES( + + +)0 P() 10 79 PR( -c contact each access point individually + -h print help message + -i access XPA point on different machine \201override XPA_NSINET\202 + -m override XPA_METHOD environment variable + -n return number of matches instead of "yes" or "no" + -t [s,l] set short and long timeouts \201override XPA_[SHORT,LONG]_TIMEOUT\202 + -u [users] XPA points can be from specified users \201override XPA_NSUSERS\202 + -v print info about each successful access point + -V print info or error about each access point + --version display version and exit)RP( + + +)0 P(xpaaccess returns "yes" to stdout \201with a return error code if 1\202 if there are +existing XPA access points that match the +)0 3 1 A(template)3 0 TN TL()Ec /AF f D( +\201and optional access type: g,i,s\202. Otherwise, it returns "no" \201with a +return error code of 0\202. If -n is specified, the number of matches is +returned instead \201both to stdout and in the returned error code\202. If +-v is specified, each access point is displayed to stdout instead of +the number of matches. + +)0 P(By default, xpaaccess simply contacts the xpans name server to find +the list of registered access points that match the specified +template. It also checks to make sure the specified types are +supported by that access point. This is the fastest way to determine +available access points. However, an access point might registered but +not yet available, if, for example, the server program has not entered +its event loop to process XPA requests. To find access points that are +guaranteed to be available for processing, use the -c \201contact\202 +switch. With this switch, xpaaccess contacts each matching XPA server +\201rather than the name server\202 to make sure the registered access point +really is ready for processing. In this mode, if an access point is +registered but not available, xpaaccess will pause for a period of +time equal to the XPA_LONG_TIMEOUT, in order to give the server a +chance to ready itself. By default, this timeout is 30 seconds. You +can shorten the time of delay using the -t "short,long" switch. For +example, to shorten the delay time to 2 seconds, use: +) 1 27 PR( xpaaccess -c -t "2,2" ds9)RP( +The first argument is the short delay value, and is ignored in this +operation. The second is the long delay timeout. + +)0 P(Note also that the default xpaaccess method \201no -c switch\202 does not +check access control \201acls\202 but rather only checks whether the access +point is both registered with the xpans name server and provides the +specified type of access. In other words, the default xpaaccess could +return 'yes' when you might not actually have access. This mode also +always returns 'yes' for the xpans name server itself, regardless of +whether the name server is active. The -c \201contact\202 switch, which +contacts the access point directly, can and does check the access +control \201only for servers using version 2.1 and above\202 and also +returns the real status of xpans. + + + + + + + + + + + +)0 P()0 0 1 A(Go to XPA Help Index)0 0 TN TL()Ec /AF f D( + +)0 5 37 H(Last)WB 92 Sn( updated: September 10, 2003)EH( +)WB NL +/Cb Db D /Ct [16#00 16#00 16#00] D /Cl [16#00 16#00 16#00] D /CL -1 D Ct Sc +DS +/Ba f D /BO 0 D Bs +/UR (xpamb.html) D +/Ti (The XPA Message Bus \201xpamb\202) D +/Au () D +/Df f D +/ME [()] D + +0 BO R +()1 Sl()WB 13 Sn( + + +)0 2 38 H(xpamb:)WB 94 Sn()WB 93 Sn( the XPA Message Bus)EA()EH( + + +)0 2 39 H(Summary)WB 95 Sn()EH( +)0 P(The xpamb program can act as a "classical" message bus interface +between clients and servers. A client can send a data request to +the message bus, which then interfaces with multiple servers and +returns the data back to the client. + + +)0 2 40 H(Description)WB 96 Sn()EH( +)0 P(A "classical" message bus \201such as ToolTalk\202 consists of servers and +clients, along with a mediating program that transfers data between +different processes. XPA takes a slightly different approach in that +communication between clients and servers is direct. This generally +is the correct technique when there is only one connection \201or even a +small number of connections\202, but can become inefficient for the +serving program if a large amount of data is being transferred to many +clients. For example, if a real-time data acquisition program is +broadcasting a FITS image to several clients, it would need to +transmit that image to each client individually. This might interfere +with its own processing cycles. The preferable mechanism would be to +pass the image off to an intermediate program that can then broadcast +the data to the several clients. +)0 P(The )BD(xpamb)ES( program can alleviate such problems by functioning +as a message bus in cases where such an intermediary process is +wanted. It pre-defines a single access point named +)BD(XPAMB:xpamb)ES( to which data can be sent for re-broadcast. You +also can tell )BD(xpamb)ES( to save the data, and associate with that +data a new access point, so that it can be retrieved later on. + +)0 P(All interaction with )BD(xpamb)ES( is performed through +)BD(xpaset)ES( and )BD(xpaget)ES( \201or the corresponding API +routines, )BD(XPASet\201\202)ES( and )BD(XPAGet\201\202)ES(\202 to the +)BD(XPAMB:xpamb)ES( access point. That is, )BD(xpamb)ES( is just +another XPA-enabled program that responds to requests from +clients. The paramlist is used to specify the targets to which +the data will be for re-broadcast, as well as the re-broadcast paramlist: +) 1 69 PR( data | xpaset xpamb [switches] broadcast-target broadcast-paramlist)RP( +Optional switches are used to store data, and manipulate stored data, +and are described below. + +)0 P(In its simplest form, you can, for example, send a FITS image to xpamb for +broadcasting to all ds9 image simply by executing: +) 1 51 PR( cat foo.fits | xpaset xpamb "DS9:*" fits foo.fits)RP( +Since )BD(DS9)ES( is the class name for the ds9 image display +program, this will result in the FITS image being re-sent to all fits +access points for all active image display programs. + +)0 P(You can send stored data and new data to the same set of access points at +the same time. The stored data always is send first, followed by the new +data: +) 1 62 PR( cat foo2.fits | xpaset xpamb -send foo "DS9:*" fits foo.fits)RP( +will first send the foo.fits file, and then the foo2.fits file to all +access points of class )BD(DS9)ES(. Notice that in this example, +the foo2.fits file is not stored, but it could be stored by using the +)BD(-store [name])ES( switch on the command line. + +)0 P(The )BD(xpaget)ES( command can be used to retrieve a data from XPA +access points or from a stored data buffer, or retrieve information +about a stored data buffer. If no arguments are given: +) 1 14 PR( xpaget xpamb)RP( +then information about all currently stored data buffers is returned. This +information includes the data and time at which the data was stored, the +size in bytes of the data, and the supplied info string. + +)0 P(If arguments are specified, they will be in the form: +) 1 49 PR( xpaget xpamb [-info] [-data] [name [paramlist]])RP( +If the optional )BD(-info)ES( and/or )BD(-data)ES( switches are specified, then +information and/or data will be returned for the named data buffer +following the switches. You can use either or both of these switches +in a single command. For example, if the -info switch is used: +) 1 24 PR( xpaget xpamb -info foo)RP( +then the info about that stored data buffer will be returned. +If the -data is used with a specific name: +) 1 24 PR( xpaget xpamb -data foo)RP( +then the stored data itself will be returned. If both are used: +) 1 30 PR( xpaget xpamb -info -data foo)RP( +then the info will be returned, followed by the data. Note that it is an +error to specify one of these switches without a data buffer name and that +the paramlist will be ignored. + +)0 P(If neither the )BD(-info)ES( or )BD(-data)ES( switch is specified, then +the name refers to an XPA access point \201with an optional paramlist +following\202. +For example: +) 1 23 PR( xpaget xpamb ds9 file)RP( +is equivalent to: +) 1 17 PR( xpaget ds9 file)RP( + + +)0 2 41 H(Options)WB 97 Sn()EH( +)0 P(For xpaset, several optional switches are used to save data and +manipulate the stored data: +)0 DL( +)0 P()0 DT()BD(-data [name])ES( +)DD( Add the supplied data buffer to a pool of stored data buffers, +using the specified name as a unique identifier for later retrieval. +An error occurs if the name already exists \201use either )BD(replace)ES( +or )BD(del)ES( to rectify this\202. The )BD(-add)ES( switch is supported +for backwards compatibility with xpa 2.0. + +)0 P()0 DT()BD(-replace [name])ES( +)DD( Replace previously existing stored data having the same unique name +with new data. This essentially is a combination of the )BD(del)ES( +and )BD(data)ES( commands. + +)0 P()0 DT()BD(-info ["'info string'"])ES( +)DD( When adding a data buffer, you can specify an informational +string to be stored with that data. This string will be returned +by xpaget: +) 1 24 PR( xpaget xpamb foo -info)RP( +\201along with other information such as the date/time of storage and the size of +the data buffer\202 if the -info switch is specified. If the info string contains +spaces, you must enclose it in )BD(two)ES( sets of quotes: +) 1 65 PR( cat foo | xpaset xpamb -store foo -info "'this is info on foo'")RP( +The first set of quotes is removed by the shell while the second is used to +delineate the info string. + +)0 P()0 DT()BD(-send [name])ES( +)DD( Broadcast the stored data buffer to the named template. + +)0 P()0 DT()BD(-del [name])ES( +)DD( Delete the named data buffer and free all allocated space.)LD( + +)0 P(Switches can be used in any combination that makes sense. For example: +) 1 75 PR( cat foo.fits | xpaset xpamb -store foo -info "FITS" "DS9:*" fits foo.fits)RP( +will broadcast the foo.fits image to all access points of class +)BD(DS9)ES(. In addition, the foo.fits file will be stored under the +name of )BD(foo)ES( for later manipulation such as: +) 1 49 PR( xpaset -p xpamb -send foo "DS9:*" fits foo.fits)RP( +will re-broadcast the foo.fits image to all access points of class "DS9". + + + + + +)0 P()0 0 1 A(Go to XPA Help Index)0 0 TN TL()Ec /AF f D( + +)0 5 42 H(Last)WB 98 Sn( updated: September 10, 2003)EH( +)WB NL +/Cb Db D /Ct [16#00 16#00 16#00] D /Cl [16#00 16#00 16#00] D /CL -1 D Ct Sc +DS +/Ba f D /BO 0 D Bs +/UR (xpans.html) D +/Ti (The XPA Name Server \201xpans\202) D +/Au () D +/Df f D +/ME [()] D + +0 BO R +()1 Sl()WB 14 Sn( + + +)0 2 43 H(xpans:)WB 100 Sn()WB 99 Sn( the XPA Name Server)EA()EH( + + +)0 2 44 H(Summary)WB 101 Sn()EH( +) 1 70 PR( xpans [-h] [-e] [-k sec] [-p port] [-l log] [-s security log] [-P n])RP( + + +)0 P() 8 71 PR( -h print help message + -e exit when there are no more XPA connections + -k send keepalive messages every n sec + -l log data base entries to specified file + -p listen for connections on specified port + -s log security info for each connection to specified file + -P accept proxy requests \201P=1\202 using separate thread \201P=2\202 + --version display version and exit)RP( + + +)0 P(The xpans name server is an XPA-enabled program that is used to +manage the names and ports of XPA access points. It is started +automatically when an XPA access point is registered. You can access +the name server using xpaget to get a list of registered access points. +)0 P(The )EM(xpans)ES( name server provides a crucial link between XPA +clients and servers. When an XPA server defines an access point using +XPANew\201\202, XPACmdNew\201\202, or XPAInfoNew\201\202, the name of the access point +is registered in the name service, along with connection information. +The name server then matches class:name templates passed to it by XPA +clients with these registered entries, so that the clients can +communicate with the appropriate servers. + +)0 P(The socket connection between an XPA-enabled program and +)EM(xpans)ES( is kept open until the former exits \201or explicitly +closes the connection\202. Apparently, some Internet equipment \201e.g. DSL +modems\202 can cause such a connection to time-out after a period of +inactivity. To prevent this from happening, you can use the )EM(-k +[sec])ES( switch to send a short keep-alive message to each open +connection after the specified time delay. \201Note that this +application level use of keep-alive is necessary only if you are +serving XPA-enabled clients over the Internet and have to deal with +long-term connections involving DSL or similar equipment. XPA uses +the ordinary socket-level keep-alive, which works for all other cases.\202 +)BD(NB \20112/2/2009\202: Out-of-band \201URG\202 TCP data, used by xpans +keep-alive, is changed by some Cisco routers into in-band data. +Encountering such a router will break the keep-alive function and may +break your XPA server as well. Proceed with caution!)ES( + +)0 P(The )EM(xpans)ES( program will be started automatically \201assuming it +can be found in the user's path\202 when the first XPA access point is +registered. It therefore need not be started explicitly. However, +when started automatically, the )EM(-e)ES( switch is used, so that +the name server will exit when there are no more XPA access points +registered. If you wish to keep the name server running continually, +simply start it manually without the )EM(-e)ES( switch. + +)0 P(The name server will keep a log of registered access points if the +)EM(-l [log])ES( switch is used on the command line \201this is the +case for automatic start-up\202. The log contains enough name and connection +information to allow you to re-register all XPA access points in case +the name server process is terminated prematurely. For example, after +the ds9 access point is registered,the log will contain the entry: +) 1 35 PR( add 838e2f67:1863 ds9 ds9 gs eric)RP( +If )EM(xpans)ES( is terminated but ds9 still is running, you +can re-register both access points for the ds9 process by running: +) 1 36 PR( xpaset -p 838e2f67:1863 -nsconnect)RP( +Notice that the ip:port specifier is used with )EM(xpaset)ES( to bypass +the need for contacting the name server \201which does not have the name +registered yet!\202 + +)0 P(The name server will keep a log of security information if the )EM(-s +[security log])ES( switch is used on the command line. For each +accepted connection, \201including connections via the )EM(xpaget)ES( +command\202, information will be logged about the host issuing the +command and the parameters passed into the program. This is most +useful when )EM(xpans)ES( is accepting connections from untrusted +machines. + +)0 P(When an XPA access point is removed by a server using )EM(XPAFree\201\202)ES(, +the access information is removed from the name server. If an +XPA-enabled process is terminated, all names registered by that process +will be removed automatically. The log file is always updated to +reflect the currently registered access points. + +)0 P(The name server itself has an XPA access point names )EM(xpans)ES( +registered through which you can find out information about currently +registered access points \201assuming you have access to the name server; +see )0 41 1 A(XPA Access Control)41 0 TN TL()Ec /AF f D( for more information\202. +For each registered access point, the following information is returned: +) 5 80 PR( class # class of the access point + name # name of the access point + access # allowed access \201g=xpaget,s=xpaset,i=xpainfo\202 + id # socket access method \201host:port for inet, file for local/unix\202 + user # user name of access point owner)RP( + +)0 P(For example, to display all currently registered access points, simply execute: +) 1 14 PR( xpaget xpans)RP( +Continuing the example of ds9 above, this will return: +) 1 31 PR( DS9 ds9 gs 838e2f67:1863 eric)RP( +If the same program has been started with different XPA access names, +you can look up only names matching a specified template. For example, +assume that ds9 has been started up using: +) 3 25 PR( ds9 & + ds9 -title ds9-1-eric & + ds9 -title ds9-2-eric &)RP( +To lookup all ds9 access points which end in ".eric" and which can +be accessed using )EM(xpaset)ES(, use: +) 1 35 PR( xpaget xpans "DS9:*.eric" "s" "*")RP( +This will return: +) 2 39 PR( DS9 ds9-2-eric gs 838e29d3:42102 eric + DS9 ds9-1-eric gs 838e29d3:42105 eric)RP( +The third argument "*" requests all access points from all users. +You also can specify a specific user name and only access points +registered by that user will be returned. + +)0 P(The name server uses the )EM(XPA_METHOD)ES( environment variable +to determine whether it should listen for requests on INET or LOCAL +sockets. Since XPA access points also use this environment variable, +the choice of socket method will be consistent. Note that, when INET +sockets are used, a local server can be accessed from remote machines +if the )EM(XPA_NSINET)ES( environment variable is set to point to +the local machine. See +)0 40 1 A(XPA Environment Variables)40 0 TN TL()Ec /AF f D( +for more information. + +)0 P(An experimental feature of xpans is its ability to act as a proxy to +XPA servers behind firewalls that want to communicate with external +processes. The basic idea is the following: an XPA server \201call it +"foo"\202 on host1, possibly behind a firewall, makes a remote connection +to a proxy-enabled xpans program on host2 \201specifying host2's XPA method\202. +For example: +) 1 59 PR( xpaset -p foo -remote 'host2:28571' + -proxy # on host1)RP( +When this is done, host2 can use xpaset, xpaget, and xpainfo calls to +communicate with the XPA server foo. All command communication is +performed via the xpans socket connection between foo on host1 and +xpans on host2 \201which was initiated by foo from inside the firewall\202. +Data communication is similarly performed using a socket connection +initiated on host1 \201usually with a port value two greater than the +port value of the main xpans socket connection\202. An xpaset or xpaget +call on host2 contacts xpans, which performs an XPASet\201\202 or XPAGet\201\202 +call to foo, passing commands and data back and forth between the two +programs. + +)0 P(By default, proxy connections are not allowed by xpans. If the -P switch is +specified with a value of 1, proxy connection are allowed, but all proxy +communication is performed in the same thread as xpans processing. If +a value of 2 is specified, the proxy processing is performed in a +separate thread \201assuming pthreads are supported on your system\202. +Because xpa callback processing of any type can take a long time and +therefore can interfere with normal xpans processing, threaded proxy +connections \201-P 2\202 are recommended. When using proxy connections, it +might also be useful to set the XPA_IOCALLSXPA environment variable, so +that multiple proxy requests can be handled at the same time, instead of +serially. + +)0 P(Note that this proxy interface to xpans is experimental. It is used +to provide remote data analysis capabilities on the Chandra-Ed system +using ds9. \201See http://chandra-ed.cfa.harvard.edu and +http://hea-www.harvard.edu/saord/ds9 for more details\202. As always, please +contact us if you have problems or questions. + + + + + +)0 P()0 0 1 A(Go to XPA Help Index)0 0 TN TL()Ec /AF f D( + +)0 5 45 H(Last)WB 102 Sn( updated: January 24, 2005)EH( +)WB NL +/Cb Db D /Ct [16#00 16#00 16#00] D /Cl [16#00 16#00 16#00] D /CL -1 D Ct Sc +DS +/Ba f D /BO 0 D Bs +/UR (server.html) D +/Ti (XPA Server API) D +/Au () D +/Df f D +/ME [()] D + +0 BO R +()1 Sl()WB 15 Sn( + + +)0 2 46 H(XPAServer:)WB 106 Sn()WB 103 Sn( The XPA Server-side Programming Interface)EA()EH( + + +)0 2 47 H(Summary)WB 107 Sn()EH( +A description of the XPA server-side programming interface. + + +)0 2 48 H(Introduction)WB 108 Sn()WB 104 Sn( to XPA Server Programming)EH()EA( +)0 P(Creating an XPA server is easy: you generally only need to call the +XPANew\201\202 subroutine to define a named XPA access point and set up the +send and receive callback routines. You then enter an event loop such +as XPAMainLoop\201\202 to field XPA requests. +) 27 66 PR( #include <xpa.h> + + XPA )0 16 1 A(XPANew)16 0 TN TL()Ec /AF f D(\201char *class, char *name, char *help, + int \201*send_callback\202\201\202, void *send_data, char *send_mode, + int \201*rec_callback\202\201\202, void *rec_data, char *rec_mode\202; + + XPA )0 17 1 A(XPACmdNew)17 0 TN TL()Ec /AF f D(\201char *class, char *name\202; + + XPACmd )0 18 1 A(XPACmdAdd)18 0 TN TL()Ec /AF f D(\201XPA xpa, + char *name, char *help, + int \201*send_callback\202\201\202, void *send_data, char *send_mode, + int \201*rec_callback\202\201\202, void *rec_data, char *rec_mode\202; + + void )0 19 1 A(XPACmdDel)19 0 TN TL()Ec /AF f D(\201XPA xpa, XPACmd cmd\202; + + XPA )0 20 1 A(XPAInfoNew)20 0 TN TL()Ec /AF f D(\201char *class, char *name, + int \201*info_callback\202\201\202, void *info_data, char *info_mode\202; + + int )0 21 1 A(XPAFree)21 0 TN TL()Ec /AF f D(\201XPA xpa\202; + + void )0 22 1 A(XPAMainLoop)22 0 TN TL()Ec /AF f D(\201void\202; + + int )0 23 1 A(XPAPoll)23 0 TN TL()Ec /AF f D(\201int msec, int maxreq\202; + + void )0 105 1 A(XPAAtExit)105 0 TN TL()Ec /AF f D(\201void\202; + + void )0 24 1 A(XPACleanup)24 0 TN TL()Ec /AF f D(\201void\202;)RP( + +)0 2 49 H(Introduction)WB 109 Sn()EH( + +To use the XPA application programming interface, a software developer +generally will include the xpa.h definitions file: +) 1 18 PR( #include <xpa.h>)RP( +in the software module that defines or accesses an XPA access point, and +then will link against the libxpa.a library: +) 1 27 PR( gcc -o foo foo.c libxpa.a)RP( +XPA has been compiled using both C and C++ compilers. + +)0 P(A server program generally defines an XPA access point by calling the +XPANew\201\202 routine and specifies "send" and/or "receive" callback +procedures to be executed by the program when an external process +either sends data or commands to this access point or requests data or +information from this access point. A program also can define several +sub-commands for a single access point by calling XPACmdNew\201\202 and +XPACmdAdd\201\202 instead. Having defined one or more public access points +in this way, an XPA server program enters its usual event loop \201or +uses the standard XPA event loop\202. + + + + +)0 2 50 H(XPANew:)WB 110 Sn()WB 16 Sn( create a new XPA access point)EA()EH( + + +)BD() 7 49 PR( #include <xpa.h> + + XPA XPANew\201char *class, char *name, char *help, + int \201*send_callback\202\201\202, + void *send_data, char *send_mode, + int \201*rec_callback\202\201\202, + void *rec_data, char *rec_mode\202;)RP()ES( + + +)0 P(Create a new XPA public access point with the class:name +identifier )0 3 1 A(template)3 0 TN TL()Ec /AF f D( +and enter this access point into the XPA name server, so that it +can be accessed by external processes. XPANew\201\202 returns an XPA struct. +Note that the length of the class and name designations must be less +than or equal to 1024 characters each. + +)0 P(The XPA name server daemon, xpans, will be started automatically if it +is not running already \201assuming it can be found in the path\202. The +program's ip address and listening port are specified by the +environment variable XPA_NSINET, which takes the form :. If +no such environment variable exists, then xpans is started on the +current machine listening on port 14285. It also uses 14286 as a +known port for its public access point \201so that routines do not have +to go to the name server to find the name server ip and port!\202 +As of XPA 2.1.1, version information is exchanged between the xpans +process and the new access point. If the access point uses an XPA +major/minor version newer than xpans, a warning is issued by both processes, +since mixing of new servers and old xpa programs \201xpaset, xpaget, +xpans, etc.\202 is not likely to work. You can turn off the warning +message by setting the XPA_VERSIONCHECK environment variable to "false". + +)0 P(The help string is meant to be returned by a request from xpaget: +) 1 25 PR( xpaget class:name -help)RP( +)0 P(A send_callback and/or a receive_callback can be specified; at +least one of them must be specified. + +)0 P(A send_callback can be specified that will be executed in response to +an external request from the xpaget program, the XPAGet\201\202 routine, or +XPAGetFd\201\202 routine. This callback is used to send data to the +requesting client. + +)0 P(The calling sequence for send_callback\201\202 is: +) 7 53 PR( int send_callback\201void *send_data, void *call_data, + char *paramlist, char **buf, size_t *len\202 + { + XPA xpa = \201XPA\202call_data; + ... + return\201stat\202; + })RP( +)0 P(The send_mode string is of the form: "key1=value1,key2=value2,..." +The following keywords are recognized: +) 4 81 PR( key value default explanation + ------ -------- -------- ----------- + acl true/false true enable access control + freebuf true/false true free buf after callback completes)RP( +)0 P(The call_data should be recast to the XPA struct as shown. In +addition, client-specific data can be passed to the callback in +send_data. + +)0 P(The paramlist will be supplied by the client as qualifying parameters +for the callback. There are two ways in which the send_callback\201\202 +routine can send data back to the client: + +)0 P(1. The send_callback\201\202 routine can fill in a buffer and pass back a +pointer to this buffer. An integer len also is returned to specify the +number of bytes of data in buf. XPA will send this buffer to the +client after the callback is complete. + +)0 P(2. The send_callback can send data directly to the client by writing +to the fd pointed by the macro: +) 1 17 PR( xpa_datafd\201xpa\202)RP( +)0 P(Note that this fd is of the kind returned by socket\201\202 or open\201\202. + +)0 P(If a buf has been allocated by a standard malloc routine, filled, and +returned to XPA, then freebuf generally is set so that the buffer will +be freed automatically when the callback is completed and data has +been sent to the client. If a static buf is returned, freebuf should +be set to false to avoid a system error when freeing static storage. +Note that default value for freebuf implies that the callback will +allocate a buffer rather than use static storage. + +)0 P(On the other hand, if buf is dynamically allocated using a method +other than a standard malloc/calloc/realloc routine \201e.g. using Perl's +memory allocation and garbage collection scheme\202, then it is necessary +to tell XPA how to free the allocated buffer. To do this, use the +XPASetFree\201\202 routine within your callback: +) 1 69 PR( void XPASetFree\201XPA xpa, void \201*myfree\202\201void *\202, void *myfree_ptr\202;)RP( +The first argument is the usual XPA handle. The second argument is the +special routine to call to free your allocated memory. The third +argument is an optional pointer. If not NULL, the specified free +routine is called with that pointer as its sole argument. If NULL, the +free routine is called with the standard buf pointer as its sole +argument. This is useful in cases where there is a mapping between the +buffer pointer and the actual allocated memory location, and the +special routine is expecting to be passed the former. + +)0 P(If, while the callback performs its processing, an error occurs that +should be communicated to the client, then the routine XPAError should be +called: +) 1 29 PR( XPAError\201XPA xpa, char *s\202;)RP( +)0 P(where s is an arbitrary error message. The returned error message +string will be of the form: +) 1 42 PR( XPA$ERROR [error] \201class:name ip:port\202)RP( +)0 P(If the callback wants to send a specific acknowledgment message back +to the client, the routine XPAMessage can be called: +) 1 31 PR( XPAMessage\201XPA xpa, char *s\202;)RP( +)0 P(where s is an arbitrary error message. The returned error message +string will be of the form: +) 1 44 PR( XPA$MESSAGE [message] \201class:name ip:port\202)RP( +)0 P(Otherwise, a standard acknowledgment is sent back to the client +after the callback is completed. + +)0 P(The callback routine should return 0 if no error occurs, or -1 to +signal an error. + +)0 P(A receive_callback can be specified that will be executed in response +to an external request from the xpaset program, or the XPASet \201or +XPASetFd\201\202\202 routine. This callback is used to process data received +from an external process. + +)0 P(The calling sequence for receive_callback is: +) 7 59 PR( int receive_callback\201void *receive_data, void *call_data, + char *paramlist, char *buf, size_t len\202 + { + XPA xpa = \201XPA\202call_data; + ... + return\201stat\202; + })RP( +)0 P(The mode string is of the form: "key1=value1,key2=value2,..." +The following keywords are recognized: +) 6 92 PR( key value default explanation + ------ -------- -------- ----------- + acl true/false true enable access control + buf true/false true server expects data bytes from client + fillbuf true/false true read data into buf before executing callback + freebuf true/false true free buf after callback completes)RP( +)0 P(The call_data should be recast to the XPA struct as shown. In +addition, client-specific data can be passed to the callback in +receive_data. + +)0 P(The paramlist will be supplied by the client. In addition, if the +receive_mode keywords buf and fillbuf are true, then on entry into the +receive_callback\201\202 routine, buf will contain the data sent by the +client. If buf is true but fillbuf is false, it becomes the callback's +responsibility to retrieve the data from the client, using the data fd +pointed to by the macro xpa_datafd\201xpa\202. If freebuf is true, then buf +will be freed when the callback is complete. + +)0 P(If, while the callback is performing its processing, an error occurs +that should be communicated to the client, then the routine XPAError +can be called: +) 1 29 PR( XPAError\201XPA xpa, char *s\202;)RP( +)0 P(where s is an arbitrary error message. + +)0 P(The callback routine should return 0 if no error occurs, or -1 to +signal an error. + + + + +)0 2 51 H(XPACmdNew:)WB 111 Sn()WB 17 Sn( create a new XPA public access point for commands)EA()EH( + + +)BD() 3 41 PR( #include <xpa.h> + + XPA XPACmdNew\201char *class, char *name\202;)RP()ES( + + +)0 P(Create a new XPA public access point for commands that will share a +common identifier class:name. Enter this access point into the XPA +name server, so that it can be accessed by external processes. +XPACmdNew\201\202 returns an XPA struct. + +)0 P(It often is more convenient to have one public access point that can +manage a number of commands, rather than having individual access +points for each command. For example, it is easier to command the +ds9 image display using: +) 3 35 PR( echo "colormap I8" | xpaset ds9 + echo "scale log" | xpaset ds9 + echo "file foo.fits" | xpaset ds9)RP( +)0 P(then to use: +) 3 39 PR( echo "I8" | xpaset ds9_colormap + echo "log" | xpaset ds9_scale + echo "foo.fits" | xpaset ds9_file)RP( +)0 P(In the first case, the commands remain the same regardless of the +target XPA name. In the second case, the command names must change +for each instance of ds9. That is, if a second instance of ds9 +called DS9 were running, it would be commanded either as: +) 3 35 PR( echo "colormap I8" | xpaset DS9 + echo "scale log" | xpaset DS9 + echo "file foo.fits" | xpaset DS9)RP( +)0 P(or as: +) 3 39 PR( echo "I8" | xpaset DS9_colormap + echo "log" | xpaset DS9_scale + echo "foo.fits" | xpaset DS9_file)RP( +)0 P(Thus, in cases where a program is going to manage many commands, it +generally is easier to define them as commands associated with the +XPACmdNew\201\202 routine, rather than as separate access points using +XPANew\201\202. + +)0 P(When XPACmdNew\201\202 is called, only the class:name identifier is +specified. Each sub-command is subsequently defined using the +XPACmdAdd\201\202 routine. + + + + +)0 2 52 H(XPACmdAdd:)WB 112 Sn()WB 18 Sn( add a command to an XPA command public access point)EA()EH( + + +)BD() 7 52 PR( #include <xpa.h> + + XPACmd XPACmdAdd\201XPA xpa, char *name, char *help, + int \201*send_callback\202\201\202, + void *send_data, char *send_mode, + int \201*rec_callback\202\201\202, + void *rec_data, char *rec_mode\202;)RP()ES( + + +)0 P(Add a command to an XPA command access point. The XPA argument specifies the +XPA struct returned by a call to XPANewCmd\201\202. The name argument is the +name of the command. The other arguments function identically to the +arguments in the XPANew\201\202 command, i.e., the send_callback and rec_callback +routines have identical calling sequences to their XPANew\201\202 counterparts, +with the exceptions noted below. + +)0 P(When help is requested for a command access point using: +) 1 22 PR( xpaget -h class:name)RP( +)0 P(all of the command help strings are listed. To get help for a given +command, use: +) 1 26 PR( xpaget -h class:name cmd)RP( +)0 P(Also, the acl keyword in the send_mode and receive_mode strings is +global to the access point, not local to the command. Thus, the value +for the acl mode should be the same in all send_mode \201or receive_mode\202 +strings for each command in a command access point. \201The acl for +send_mode need not be the same as the acl for receive_mode, though\202. + + + + +)0 2 53 H(XPACmdDel:)WB 113 Sn()WB 19 Sn( remove a command from an XPA command public access point)EA()EH( + + +)BD() 3 38 PR( #include <xpa.h> + + void XPACmdDel\201XPA xpa, XPACmd cmd\202;)RP()ES( + + +)0 P(This routine removes a command from the list of available commands in +a given XPA. That command will no longer be available for processing. + + + + +)0 2 54 H(XPAInfoNew:)WB 114 Sn()WB 20 Sn( define an XPA info public access point)EA()EH( + + +)BD() 5 51 PR( #include <xpa.h> + + XPA XPAInfoNew\201char *class, char *name, + int \201*info_callback\202\201\202, + void *info_data, char *info_mode\202;)RP()ES( + + +)0 P([NB: this is an experimental interface, new to XPA 2.0, whose value +and best use is evolving.] + +)0 P(A program can register interest in receiving a short message about a +particular topic from any other process that cares to send such a +message. Neither has to be an XPA server. For example, if a user +starts to work with a new image file called new.fits, she might +wish to alert interested programs about this new file by sending a +short message using xpainfo: +) 1 34 PR( xpainfo IMAGEFILE /data/new.fits)RP( + +)0 P(In this example, each process that has used the XPAInfoNew\201\202 call to +register interest in messages associated with the identifier IMAGEFILE +will have its info_callback\201\202 executed with the following calling +sequence: +) 4 64 PR( int info_cb\201void *info_data, void *call_data, char *paramlist\202 + { + XPA xpa = \201XPA\202call_data; + })RP( +)0 P(The arguments passed to this routine are equivalent to those sent in +the send_callback\201\202 routine. The main difference is that there is no +buf sent to the info callback: this mechanism is meant for short +announcement of messages of interest to many clients. + +)0 P(The mode string is of the form: "key1=value1,key2=value2,..." +The following keywords are recognized: +) 3 69 PR( key value default explanation + ------ -------- -------- ----------- + acl true/false true enable access control)RP( +)0 P(Because no buf is passed to this callback, the usual buf-related keywords +are not applicable here. + +)0 P(The information sent in the parameter list is arbitrary. However, we +envision sending information such as file names or XPA access points +from which to collect more data. Note that the xpainfo program and +the XPAInfo\201\202 routine that cause the info_callback to execute do not +wait for the callback to complete before returning. + + + + +)0 2 55 H(XPAFree:)WB 115 Sn()WB 21 Sn( remove an XPA public access point)EA()EH( + + +) 3 23 PR()BD( #include <xpa.h> + + int XPAFree\201XPA xpa\202;)ES()RP( + + +)0 P(Remove the specified XPA public access point from the name server and +free all associated storage. Note that removal from the name server +happens automatically when the process terminates, so this call is not +generally needed. It is used when public access points are being +defined temporarily and then destroyed when no longer needed. For +example, ds9 temporarily creates a public access point when it +loads a new image for display and destroys it when the image is +unloaded. + + + + +)0 2 56 H(XPAMainLoop:)WB 116 Sn()WB 22 Sn( optional main loop for XPA)EA()EH( + + +)BD() 3 21 PR( #include <xpa.h> + + void XPAMainLoop\201\202;)RP()ES( + + +)0 P(Once XPA access points have been defined, a program must enter an +event loop to watch for requests from external programs. This can be +done in a variety of ways, depending on whether the event loop is +processing events other than XPA events. In cases where there are no +non-XPA events to be processed, the program can simply call the +XPAMainLoop\201\202 event loop. This loop is implemented essentially as +follows \201error checking is simplified in this example\202: +) 8 62 PR( FD_ZERO\201&readfds\202; + while\201 XPAAddSelect\201NULL, &readfds\202 \202{ + if\201 sgot = select\201swidth, &readfds, NULL, NULL, NULL\202 >0 \202 + XPAProcessSelect\201&readfds, 0\202; + else + break; + FD_ZERO\201&readfds\202; + })RP( +)0 P(The XPAAddSelect\201\202 routine sets up the select\201\202 readfds variable so +that select\201\202 will wait for I/O on all the active XPA channels. It +returns the number of XPAs that are active; the loop will end when +there are no active XPAs. The standard select\201\202 routine is called to +wait for an external I/O request. Since no timeout struct is passed +in argument 5, the select\201\202 call hangs until there is an external +request. When an external I/O request is made, the XPAProcessSelect\201\202 +routine is executed to process the pending requests. In this routine, +the maxreq value determines how many requests will be processed: if +maxreq <=0, then all currently pending requests will be processed. +Otherwise, up to maxreq requests will be processed. \201The most usual +values for maxreq is 0 to process all requests.\202 + +)0 P(If a program has its own Unix select\201\202 loop, then XPA access points can +be added to it by using a variation of the standard XPAMainLoop: +) 7 39 PR( XPAAddSelect\201xpa, &readfds\202; + [app-specific ...] + if\201 select\201width, &readfds, ...\202 \202{ + XPAProcessSelect\201&readfds, maxreq\202; + [app-specific ...] + FD_ZERO\201&readfds\202; + })RP( +)0 P(XPAAddSelect\201\202 is called before select\201\202 to add the access points. +If the first argument is NULL, then all active XPA access points +are added. Otherwise only the specified access point is added. +After select\201\202 is called, the XPAProcessSelect\201\202 routine can be called +to process XPA requests. Once again, the maxreq value determines how +many requests will be processed: if maxreq <=0, then all currently +pending requests will be processed. Otherwise, up to maxreq requests +will be processed. + +)0 P(XPA access points can be added to +)0 38 1 A(Xt event loops)38 0 TN TL()Ec /AF f D( \201using XtAppMainLoop\201\202\202 +and +)0 39 1 A(Tcl/Tk event loops)39 0 TN TL()Ec /AF f D( \201using vwait and the Tk loop\202. +When using XPA with these event loops, you only need to call: +) 1 44 PR(int XPAXtAddInput\201XtAppContext app, XPA xpa\202)RP( +or +) 1 29 PR( int XPATclAddInput\201XPA xpa\202)RP( +respectively before entering the loop. + + + + +)0 2 57 H(XPAPoll:)WB 117 Sn()WB 23 Sn( execute existing XPA requests)EA()EH( + + +)BD() 3 36 PR( #include <xpa.h> + + int XPAPoll\201int msec, int maxreq\202;)RP()ES( + + +)0 P(It is sometimes desirable to implement a polling loop, i.e., where one +checks for and processes XPA requests without blocking. For this +situation, use the XPAPoll\201\202 routine: +) 1 32 PR( XPAPoll\201int msec, int maxreq\202;)RP( +)0 P(The XPAPoll\201\202 routine will perform XPAAddSelect\201\202 and select\201\202, but with a +timeout specified in millisecs by the msec argument. If one or more +XPA requests are made before the timeout expires, the XPAProcessSelect\201\202 +routine is called to process those requests. The maxreq value determines +how many requests will be processed: if maxreq < 0, then no events are +processed, but instead, the return value indicates the number of events +that are pending. If maxreq == 0, then all currently pending requests +will be processed. Otherwise, up to maxreq requests will be processed. +\201The most usual values for maxreq are 0 to process all requests and 1 +to process one request\202. + + + + +)0 2 58 H(XPAAtExit:)WB 118 Sn()WB 105 Sn( install exit handler)EA()EH( + + +) 3 23 PR()BD( #include <xpa.h> + + void XPAAtExit\201void\202;)ES()RP( + + +)0 P(XPAAtExit\201\202 will install an exit handler using atexit\201\202 to run XPAFree on all +XPA access points. This might be useful in cases where Unix sockets are being +used: if an explicit call to XPAFree\201\202 is not made by the program, the Unix +socket file will not be deleted immediately without an atexit handler. \201NB: this +call should not be made in a Tcl/Tk application. Accessing the Tcl native file +system after Tcl has shut down all file systems causes the Tcl/Tl program to +crash\202. + + + + +)0 2 59 H(XPACleanup:)WB 119 Sn()WB 24 Sn( release reserved XPA memory)EA()EH( + + +) 3 24 PR()BD( #include <xpa.h> + + void XPACleanup\201void\202;)ES()RP( + + +)0 P(When XPA is initialized, it allocates a small amount of memory for the +access control list, temp directory path, and reserved commands. This +memory is found by valgrind to be "still reachable", meaning that "your +program didn't free some memory it could have". Calling the +XPACleanup\201\202 routine before exiting the program will free this memory +and make valgrind happy. + + + + +)0 2 60 H(XPA)WB 120 Sn()WB 25 Sn( Server Callback Macros)EA()EH( + + +)BD() 4 57 PR( #include <xpa.h> + + xpa_class, xpa_name, xpa_method, xpa_cmdfd, xpa_datafd, + xpa_sendian, xpa_cendian)RP()ES( + + +)0 P(Server routines have access to information about the XPA being called via +the following macros \201each of which takes the xpa handle as an argument\202: +) 9 66 PR( macro explanation + ------ ----------- + xpa_class class of this xpa + xpa_name name of this xpa + xpa_method method string \201inet or local connect info\202 + xpa_cmdfd fd of command socket + xpa_datafd fd of data socket + xpa_sendian endian-ness of server \201"little" or "big"\202 + xpa_cendian endian-ness of client \201"little" or "big")RP( +)0 P(The argument to these macros is the call_data pointer that is passed +to the server procedure. This pointer should be type case to XPA +in the server routine: +) 1 27 PR( XPA xpa = \201XPA\202call_data;)RP( + +)0 P(The most important of these macros is xpa_datafd\201\202. A server routine +that sets "fillbuf=false" in receive_mode or send_mode can use this +macro to perform I/O directly to/from the client, rather than using +buf. + +)0 P(The xpa_cendian and xpa_sendian macros can be used together to determine +if the data transferred from the client is byte swapped with respect +to the server. Values for these macros are: "little", "big", or "?". +In order to do a proper conversion, you still need to know the format +of the data \201i.e., byte swapping is dependent on the size of the data +element being converted\202. + + + + +)0 2 61 H(XPA)WB 121 Sn()WB 26 Sn( Race Conditions)EA()EH( + + +Potential XPA race conditions and how to avoid them. + + +)0 P(Currently, there is only one known circumstance in which XPA can get +\201temporarily\202 deadlocked in a race condition: if two or more XPA +servers send messages to one another using an XPA client routine such +as XPASet\201\202, they can deadlock while each waits for the other server +to respond. \201This can happen if the servers call XPAPoll\201\202 with a +time limit, and send messages in between the polling call.\202 The +reason this happens is that both client routines send a string to the +other server to establish the handshake and then wait for the server +response. Since each client is waiting for a response, neither is able +to enter its event-handling loop and respond to the other's +request. This deadlock will continue until one of the timeout periods +expire, at which point an error condition will be triggered and the +timed-out server will return to its event loop. + +)0 P(Starting with version 2.1.6, this rare race condition can be +avoided by setting the XPA_IOCALLSXPA environment variable for servers +that will make client calls. Setting this variable causes all XPA +socket IO calls to process outstanding XPA requests whenever the +primary socket is not ready for IO. This means that a server making a +client call will \201recursively\202 process incoming server requests while +waiting for client completion. It also means that a server callback +routine can handle incoming XPA messages if it makes its own XPA call. +The semi-public routine oldvalue=XPAIOCallsXPA\201newvalue\202 can be used +to turn this behavior off and on temporarily. Passing a 0 will turn +off IO processing, 1 will turn it back on. The old value is returned +by the call. + +)0 P(By default, the XPA_IOCALLSXPA option is turned off, because we judge +that the added code complication and overhead involved will not be +justified by the amount of its use. Moreover, processing XPA requests +within socket IO can lead to non-intuitive results, since incoming +server requests will not necessarily be processed to completion in the +order in which they are received. + +)0 P(Aside from setting XPA_IOCALLSXPA, the simplest way to avoid this race +condition is to multi-process: when you want to send a client message, +simply start a separate process to call the client routine, so that +the server is not stopped. It probably is fastest and easiest to use +fork\201\202 and then have the child call the client routine and exit. But +you also can use either the system\201\202 or popen\201\202 routine to start one +of the command line programs and do the same thing. Alternatively, you +can use XPA's internal launch\201\202 routine instead of system\201\202. Based on +fork\201\202 and exec\201\202, this routine is more secure than system\201\202 because +it does not call /bin/sh. + +)0 P(Starting with version 2.1.5, you also can send an XPAInfo\201\202 message with +the mode string "ack=false". This will cause the client to send a message +to the server and then exit without waiting for any return message from +the server. This UDP-like behavior will avoid the server deadlock when +sending short XPAInfo messages. + + + + + + + + + + + + + + + + + + + + + + + + + + + +)0 P()0 0 1 A(Go to XPA Help Index)0 0 TN TL()Ec /AF f D( + +)0 5 62 H(Last)WB 122 Sn( updated: September 10, 2003)EH( +)WB NL +/Cb Db D /Ct [16#00 16#00 16#00] D /Cl [16#00 16#00 16#00] D /CL -1 D Ct Sc +DS +/Ba f D /BO 0 D Bs +/UR (oom.html) D +/Ti (Out of Memory) D +/Au () D +/Df f D +/ME [()] D + +0 BO R +()1 Sl()WB 27 Sn( + + +)0 2 63 H(Xpaoom:)WB 124 Sn()WB 123 Sn( What happens when XPA runs out of memory?)EA()EH( + + +)0 2 64 H(Summary)WB 125 Sn()EH( +)0 P(When XPA can't allocate memory, it exits. You can arrange to have it call +longjmp\201\202 instead. + + +)0 2 65 H(Description)WB 126 Sn()EH( +)0 P(When an XPA server or client cannot allocate memory, it will attempt to +output an error message and then exit. If this is not satisfactory \201e.g., +perhaps your program is interactive and can recover from OOM errors\202, you +can tell XPA to call longjmp\201\202 to go to a recovery branch. To pass the +requisite jmp_buf variable to XPA, make the following call: +) 1 24 PR( XPASaveJmp\201void *env\202;)RP( +The value of env is the address of a jmp_buf variable that was previously +passed to setjmp\201\202. For example: +) 9 62 PR( jmp_buf env; + ... + if\201 setjmp\201jmp_buf\202 != 0 \202{ + /* out of memory -- take corrective action, if possible */ + } else { + /* save env for XPA */ + XPASaveJmp\201\201void *\202&jmp_buf\202; + } + // enter main loop ...)RP( + + + + + +)0 P()0 0 1 A(Go to XPA Help Index)0 0 TN TL()Ec /AF f D( + +)0 5 66 H(Last)WB 127 Sn( updated: April 7, 2009)EH( + +)WB NL +/Cb Db D /Ct [16#00 16#00 16#00] D /Cl [16#00 16#00 16#00] D /CL -1 D Ct Sc +DS +/Ba f D /BO 0 D Bs +/UR (client.html) D +/Ti (XPA Client API) D +/Au () D +/Df f D +/ME [()] D + +0 BO R +()1 Sl()WB 28 Sn( + + +)0 2 67 H(XPAClient:)WB 130 Sn()WB 128 Sn( The XPA Client-side Programming Interface)EA()EH( + + +)0 2 68 H(Summary)WB 131 Sn()EH( +A description of the XPA client-side programming interface. + + +)0 2 69 H(Introduction)WB 132 Sn()WB 129 Sn( to XPA Client Programming)EH()EA( +)0 P(Sending/receiving data to/from an XPA access point is easy: you +generally only need to call the XPAGet\201\202 or XPASet\201\202 subroutines. +) 33 71 PR( #include <xpa.h> + + int )0 31 1 A(XPAGet)31 0 TN TL()Ec /AF f D(\201XPA xpa, + char *template, char *paramlist, char *mode, + char **bufs, size_t *lens, char **names, char **messages, int n\202; + + int )0 32 1 A(XPASet)32 0 TN TL()Ec /AF f D(\201XPA xpa, + char *template, char *paramlist, char *mode, + char *buf, size_t len, char **names, char **messages, int n\202; + + int )0 33 1 A(XPAInfo)33 0 TN TL()Ec /AF f D(\201XPA xpa, + char *template, char *paramlist, char *mode, + char **names, char **messages, int n\202; + + int )0 37 1 A(XPAAccess)37 0 TN TL()Ec /AF f D(\201XPA xpa, + char *template, char *paramlist, char *mode, + char **names, char **messages, int n\202; + + int )0 34 1 A(XPAGetFd)34 0 TN TL()Ec /AF f D(\201XPA xpa, + char *template, char *paramlist, char *mode, + int *fds, char **names, char **messages, int n\202; + + int )0 35 1 A(XPASetFd)35 0 TN TL()Ec /AF f D(\201XPA xpa, + char *template, char *paramlist, char *mode, + int fd, char **names, char **messages, int n\202; + + XPA )0 29 1 A(XPAOpen)29 0 TN TL()Ec /AF f D(\201char *mode\202; + + void )0 30 1 A(XPAClose)30 0 TN TL()Ec /AF f D(\201XPA xpa\202; + + int )0 36 1 A(XPANSLookup)36 0 TN TL()Ec /AF f D(\201XPA xpa,)WR( + char *template, char *type, + char ***classes, char ***names, char ***methods, char ***infos\202;)RP( + +)0 2 70 H(Introduction)WB 133 Sn()EH( + +To use the XPA application programming interface, a software developer +generally will include the xpa.h definitions file: +) 1 18 PR( #include <xpa.h>)RP( +in the software module that defines or accesses an XPA access point and +then will link against the libxpa.a library: +) 1 27 PR( gcc -o foo foo.c libxpa.a)RP( +XPA has been compiled using both C and C++ compilers. +)0 P(Client communication with XPA public access points generally is +accomplished using XPAGet\201\202 or XPASet\201\202 within a program \201or xpaget +and xpaset at the command line\202. Both routines require specification +of the name of the access point. If a )0 3 1 A(template)3 0 TN TL()Ec /AF f D( +is used to specify the access point name \201e.g., "ds9*"\202, then +communication will take place with all servers matching that template. + + + + +)0 2 71 H(XPAGet:)WB 134 Sn()WB 31 Sn( retrieve data from one or more XPA servers)EA()EH( + + +)BD() 6 70 PR( #include <xpa.h> + + int XPAGet\201XPA xpa, + char *template, char *paramlist, char *mode, + char **bufs, size_t *lens, char **names, char **messages, + int n\202;)RP()ES( + + +)0 P(Retrieve data from one or more XPA servers whose class:name identifier +matches the specified template. + +)0 P(A +)0 3 1 A(template)3 0 TN TL()Ec /AF f D( +of the form "class1:name1" is sent to the +XPA name server, which returns a list of at most n matching XPA +servers. A connection is established with each of these servers and +the paramlist string is passed to the server as the data transfer +request is initiated. If an XPA struct is passed to the call, then the +persistent connections are updated as described above. Otherwise, +temporary connections are made to the servers \201which will be closed +when the call completes\202. + +)0 P(The XPAGet\201\202 routine then retrieves data from at most n XPA servers, +places these data into n allocated buffers and places the buffer +pointers in the bufs array. The length of each buffer is stored in the +lens array. A string containing the class:name and ip:port is stored +in the name array. If a given server returned an error or the server +callback sends a message back to the client, then the message will be +stored in the associated element of the messages array. NB: if +specified, the name and messages arrays must be of size n or greater. + +)0 P(The returned message string will be of the form: +) 1 46 PR( XPA$ERROR error-message \201class:name ip:port\202)RP( +or +) 1 42 PR( XPA$MESSAGE message \201class:name ip:port\202)RP( +)0 P(Note that when there is an error stored in an messages entry, the +corresponding bufs and lens entry may or may not be NULL and 0 +\201respectively\202, depending on the particularities of the server. + +)0 P(The return value will contain the actual number of servers that were +processed. This value thus will hold the number of valid entries in +the bufs, lens, names, and messages arrays, and can be used to loop +through these arrays. In names and/or messages is NULL, no information is +passed back in that array. + +)0 P(The bufs, names, and messages arrays should be freed upon completion \201if +they are not NULL\202; + +)0 P(The mode string is of the form: "key1=value1,key2=value2,..." +The following keywords are recognized: +) 4 115 PR( key value default explanation + ------ -------- -------- ----------- + ack true/false true if false, don't wait for ack from server \201after callback completes\202 + doxpa true/false true client processes xpa requests)RP( +)0 P(The ack keyword is not very useful, since the server completes the callback +in order to return the data anyway. It is here for completion \201and perhaps +for future usefulness\202. + +)0 P(Normally, an XPA client will process incoming XPA server requests +while awaiting the completion of the client request. Setting this +variable to "false" will prevent XPA server requests from being +processed by the client. + +)0 P()BD(Example:)ES( +) 25 70 PR( #include <xpa.h> + + #define NXPA 10 + int i, got; + size_t lens[NXPA]; + char *bufs[NXPA]; + char *names[NXPA]; + char *messages[NXPA]; + got = XPAGet\201NULL, "ds9", "file", NULL, bufs, lens, names, messages, + NXPA\202; + for\201i=0; i<got; i++\202{ + if\201 messages[i] == NULL \202{ + /* process buf contents */ + ProcessImage\201bufs[i], ...\202; + free\201bufs[i]\202; + } + else{ + /* error processing */ + fprintf\201stderr, "ERROR: %s \201%s\202\200n", messages[i], names[i]\202; + } + if\201 names[i] \202 + free\201names[i]\202; + if\201 messages[i] \202 + free\201messages[i]\202; + })RP( + + + + +)0 2 72 H(XPASet:)WB 135 Sn()WB 32 Sn( send data to one or more XPA servers)EA()EH( + + +)BD() 6 66 PR( #include <xpa.h> + + int XPASet\201XPA xpa, + char *template, char *paramlist, char *mode, + char *buf, size_t len, char **names, char **messages, + int n\202;)RP()ES( + + +)0 P(Send data to one or more XPA servers whose class:name identifier +matches the specified template. + +)0 P(A +)0 3 1 A(template)3 0 TN TL()Ec /AF f D( +of the form "class1:name1" is sent to the +XPA name server, which returns a list of at most n matching XPA +servers. A connection is established with each of these servers and +the paramlist string is passed to the server as the data transfer +request is initiated. If an XPA struct is passed to the call, the +persistent connections are updated as described above. Otherwise, +temporary connections are made to the servers \201which will be closed +when the call completes\202. + +)0 P(The XPASet\201\202 routine transfers data from buf to the XPA servers. +The length of buf \201in bytes\202 should be placed in the len variable. + +)0 P(A string containing the class:name and ip:port of each of these server +is returned in the name array. If a given server returned an error or +the server callback sends a message back to the client, then the +message will be stored in the associated element of the messages +array. NB: if specified, the name and messages arrays must be of size +n or greater. + +)0 P(The returned message string will be of the form: + +) 1 42 PR( XPA$ERROR [error] \201class:name ip:port\202)RP( +or +) 1 44 PR( XPA$MESSAGE [message] \201class:name ip:port\202)RP( +)0 P(The return value will contain the actual number of servers that were +processed. This value thus will hold the number of valid entries in +the names and messages arrays, and can be used to loop through these +arrays. In names and/or messages is NULL, no information is passed back +in that particular array. + +)0 P(The mode string is of the form: "key1=value1,key2=value2,..." +The following keywords are recognized: +) 5 115 PR( key value default explanation + ------ -------- -------- ----------- + ack true/false true if false, don't wait for ack from server \201after callback completes\202 + verify true/false false send buf from XPASet[Fd] to stdout + doxpa true/false true client processes xpa requests)RP( +)0 P(The ack keyword is useful in cases where one does not want to wait for +the server to complete, e.g. if a lot of processing needs to be done +by the server on the passed data or when the success of the server +operation is not relevant to the client. + +)0 P(Normally, an XPA client will process incoming XPA server requests +while awaiting the completion of the client request. Setting this +variable to "false" will prevent XPA server requests from being +processed by the client. + +)0 P()BD(Example:)ES( +) 21 75 PR( #include <xpa.h> + + #define NXPA 10 + int i, got; + size_t len; + char *buf; + char *names[NXPA]; + char *messages[NXPA]; + ... + [fill buf with data and set len to the length, in bytes, of the data] + ... + /* send data to all access points */ + got = XPASet\201NULL, "ds9", "fits", NULL, buf, len, names, messages, NXPA\202; + /* error processing */ + for\201i=0; i<got; i++\202{ + if\201 messages[i] \202{ + fprintf\201stderr, "ERROR: %s \201%s\202\200n", messages[i], names[i]\202; + } + if\201 names[i] \202 free\201names[i]\202; + if\201 messages[i] \202 free\201messages[i]\202; + })RP( + + + + +)0 2 73 H(XPAInfo:)WB 136 Sn()WB 33 Sn( send short message to one or more XPA servers)EA()EH( + + +)BD() 5 58 PR( #include <xpa.h> + + int XPAInfo\201XPA xpa, + char *template, char *paramlist, char *mode, + char **names, char **messages, int n\202;)RP()ES( + + +)0 P(Send a short paramlist message to one or more XPA servers whose +class:name identifier matches the specified +)0 3 1 A(template)3 0 TN TL()Ec /AF f D(. + +)0 P(A +)0 3 1 A(template)3 0 TN TL()Ec /AF f D( +of the form "class1:name1" is sent to the +XPA name server, which returns a list of at most n matching XPA +servers. A connection is established with each of these servers and +the paramlist string is passed to the server as the data transfer +request is initiated. If an XPA struct is passed to the call, then the +persistent connections are updated as described above. Otherwise, +temporary connections are made to the servers \201which will be closed +when the call completes\202. + +)0 P(The XPAInfo\201\202 routine does not send data from a buf to the XPA +servers. Only the paramlist is sent. The semantics of the paramlist +is not formalized, but at a minimum is should tell the server how to +get more information. For example, it might contain the class:name +of the XPA access point from which the server \201acting as a client\202 +can obtain more info using XPAGet. + +)0 P(A string containing the class:name and ip:port of each server is +returned in the name array. If a given server returned an error or +the server callback sends a message back to the client, then the +message will be stored in the associated element of the messages +array. The returned message string will be of the form: +) 1 48 PR( XPA$ERROR error-message \201class:name ip:port\202)RP( +or +) 1 46 PR( XPA$MESSAGE message \201class:name ip:port\202)RP( +)0 P(The return value will contain the actual number of servers that were +processed. This value thus will hold the number of valid entries in +the names and messages arrays, and can be used to loop through these +arrays. In names and/or messages is NULL, no information is passed back +in that array. + +)0 P(The following keywords are recognized: +) 3 88 PR( key value default explanation + ------ -------- -------- ----------- + ack true/false true if false, don't wait for ack from server)RP( +)0 P(When ack is false, XPAInfo\201\202 will not wait for an error return from the XPA +server. This means, in effect, that XPAInfo will send its paramlist string +to the XPA server and then exit: no information will be sent from the server +to the client. This UDP-like behavior is essential to avoid race +conditions in cases where XPA servers are sending info messages to +other servers. If two servers try to send each other an info message +at the same time and then wait for an ack, a race condition will result and +one or both will time out. + +)0 P()BD(Example:)ES( +) 1 65 PR( \201void\202XPAInfo\201NULL, "IMAGE", "ds9 image", NULL, NULL, NULL, 0\202;)RP( + + + + +)0 2 74 H(XPAGetFd:)WB 137 Sn()WB 34 Sn( retrieve data from one or more XPA servers and write to files)EA()EH( + + +)BD() 5 63 PR( #include <xpa.h> + + int XPAGetFd\201XPA xpa, + char *template, char *paramlist, char *mode, + int *fds, char **names, char **messages, int n\202;)RP()ES( + + +)0 P(Retrieve data from one or more XPA servers whose class:name identifier +matches the specified +)0 3 1 A(template)3 0 TN TL()Ec /AF f D( +and write it to files associated with +one or more standard I/O fds \201i.e, handles returned by open\201\202\202. + +)0 P(A +)0 3 1 A(template)3 0 TN TL()Ec /AF f D( +of the form "class1:name1" is sent to the +XPA name server, which returns a list of at most ABS\201n\202 matching XPA +servers. A connection is established with each of these servers and +the paramlist string is passed to the server as the data transfer +request is initiated. If an XPA struct is passed to the call, then the +persistent connections are updated as described above. Otherwise, +temporary connections are made to the servers \201which will be closed +when the call completes\202. + +)0 P(The XPAGetFd\201\202 routine then retrieves data from the XPA servers, +and write these data to the fds associated with one or more fds +\201i.e., results from open\202. Is n is positive, then there will be n fds +and the data from each server will be sent to a separate fd. If n is +negative, then there is only 1 fd and all data is sent to this single +fd. \201The latter is how xpaget is implemented.\202 + +)0 P(A string containing the class:name and ip:port is stored in the name +array. If a given server returned an error or the server callback +sends a message back to the client, then the message will be stored in +the associated element of the messages array. NB: if specified, the +name and messages arrays must be of size n or greater. + +)0 P(The returned message string will be of the form: +) 1 48 PR( XPA$ERROR error-message \201class:name ip:port\202)RP( +or +) 1 46 PR( XPA$MESSAGE message \201class:name ip:port\202)RP( +)0 P(Note that when there is an error stored in an messages entry, the +corresponding bufs and lens entry may or may not be NULL and 0 +\201respectively\202, depending on the particularities of the server. + +)0 P(The return value will contain the actual number of servers that were +processed. This value thus will hold the number of valid entries in +the bufs, lens, names, and messages arrays, and can be used to loop +through these arrays. In names and/or messages is NULL, no information is +passed back in that array. + +)0 P(The mode string is of the form: "key1=value1,key2=value2,..." +The following keywords are recognized: +) 3 115 PR( key value default explanation + ------ -------- -------- ----------- + ack true/false true if false, don't wait for ack from server \201after callback completes\202)RP( +)0 P(The ack keyword is not very useful, since the server completes the callback +in order to return the data anyway. It is here for completion \201and perhaps +for future usefulness\202. + +)0 P()BD(Example:)ES( +) 19 72 PR( #include <xpa.h> + #define NXPA 10 + int i, got; + int fds[NXPA]; + char *names[NXPA]; + char *messages[NXPA]; + for\201i=0; i<NXPA; i++\202 + fds[i] = open\201...\202; + got = XPAGetFd\201NULL, "ds9", "file", NULL, fds, names, messages, NXPA\202; + for\201i=0; i<got; i++\202{ + if\201 messages[i] != NULL \202{ + /* error processing */ + fprintf\201stderr, "ERROR: %s \201%s\202\200n", messages[i], names[i]\202; + } + if\201 names[i] \202 + free\201names[i]\202; + if\201 messages[i] \202 + free\201messages[i]\202; + })RP( + + + + +)0 2 75 H(XPASetFd:)WB 138 Sn()WB 35 Sn( send data from stdin to one or more XPA servers)EA()EH( + +)ES( +) 5 60 PR( #include <xpa.h> + + int XPASetFd\201XPA xpa, + char *template, char *paramlist, char *mode, + int fd, char **names, char **messages, int n\202)RP()ES( + + +)0 P(Read data from a standard I/O fd and send it to one or more XPA +servers whose class:name identifier matches the specified +)0 3 1 A(template. + +)0 P(A +)0 3 1 A(template)3 0 TN TL()Ec /AF f D( +of the form "class1:name1" is sent to the +XPA name server, which returns a list of at most n matching XPA +servers. A connection is established with each of these servers and +the paramlist string is passed to the server as the data transfer +request is initiated. If an XPA struct is passed to the call, then the +persistent connections are updated as described above. Otherwise, +temporary connections are made to the servers \201which will be closed +when the call completes\202. + +)0 P(The XPASetFd\201\202 routine then reads bytes from the specified fd +until EOF and sends these bytes to the XPA servers. +The final parameter n specifies the maximum number of servers to contact. +A string containing the class:name and ip:port of each server is returned in +the name array. If a given server returned an error, then the error +message will be stored in the associated element of the messages array. +NB: if specified, the name and messages arrays must be of size n or greater. + +)0 P(The return value will contain the actual number of servers that were +processed. This value thus will hold the number of valid entries in +the names and messages arrays, and can be used to loop through these +arrays. In names and/or messages is NULL, no information is passed back +in that array. + +)0 P(The mode string is of the form: "key1=value1,key2=value2,..." +The following keywords are recognized: +) 4 115 PR( key value default explanation + ------ -------- -------- ----------- + ack true/false true if false, don't wait for ack from server \201after callback completes\202 + verify true/false false send buf from XPASet[Fd] to stdout)RP( +)0 P(The ack keyword is useful in cases where one does not want to wait for +the server to complete, e.g. is a lot of processing needs to be done +on the passed data or when the success of the server operation is not +relevant to the client. + +)0 P()BD(Example:)ES( +) 19 71 PR( #include <xpa.h> + + #define NXPA 10 + int i, got; + int fd; + char *names[NXPA]; + char *messages[NXPA]; + fd = open\201...\202; + got = XPASetFd\201NULL, "ds9", "fits", NULL, fd, names, messages, NXPA\202; + for\201i=0; i<got; i++\202{ + if\201 messages[i] != NULL \202{ + /* error processing */ + fprintf\201stderr, "ERROR: %s \201%s\202\200n", messages[i], names[i]\202; + } + if\201 names[i] \202 + free\201names[i]\202; + if\201 messages[i] \202 + free\201messages[i]\202; + })RP( + + + + +)0 2 76 H(XPAOpen:)WB 139 Sn()WB 29 Sn( allocate a persistent client handle)3 0 TN TL()Ec /AF f D()EH( + + +)BD() 3 26 PR( #include <xpa.h> + + XPA XPAOpen\201char *mode\202;)RP()ES( + + +)0 P(XPAOpen\201\202 allocates a persistent XPA struct that can be used with +calls to XPAGet\201\202, XPASet\201\202, XPAInfo\201\202, XPAGetFd\201\202, and +XPASetFd\201\202. Persistence means that a connection to an XPA server is +not closed when one of the above calls is completed but will be +re-used on successive calls. Using XPAOpen\201\202 therefore saves the time +it takes to connect to a server, which could be significant with slow +connections or if there will be a large number of exchanges with a +given access point. The mode argument currently is ignored \201"reserved +for future use"\202. + +)0 P(An XPA struct is returned if XPAOpen\201\202 was successful; otherwise NULL +is returned. This returned struct can be passed as the first argument +to XPAGet\201\202, etc. Those calls will update the list of active XPA +connections. Already connected servers \201from a previous call\202 are +left connected and new servers also will be connected. Old servers +\201from a previous call\202 that are no longer needed are disconnected. +The connected servers will remain connected when the next call to +XPAGet\201\202 is made and connections are once again updated. + +)0 P()BD(Example:)ES( +) 4 22 PR( #include <xpa.h> + + XPA xpa; + xpa = XPAOpen\201NULL\202;)RP( + + + + +)0 2 77 H(XPAClose:)WB 140 Sn()WB 30 Sn( close a persistent XPA client handle)EA()EH( + + +)BD() 3 25 PR( #include <xpa.h> + + void XPAClose\201XPA xpa\202;)RP()ES( + + +)0 P(XPAClose closes the persistent connections associated with this XPA struct +and frees all allocated space. It also closes the open sockets connections +to all XPA servers that were opened using this handle. + +)0 P()BD(Example:)ES( +) 4 18 PR( #include <xpa.h> + + XPA xpa; + XPAClose\201xpa\202;)RP( + + + + +)0 2 78 H(XPANSLookup:)WB 141 Sn()WB 36 Sn( lookup registered XPA access points)EA()EH( + + +)BD() 6 49 PR( #include <xpa.h> + + int XPANSLookup\201XPA xpa, + char *template, char type, + char ***classes, char ***names, + char ***methods, char ***infos\202)RP()ES( + + +)0 P(XPA routines act on a class:name identifier in such a way +that all access points that match the identifier are processed. It is +sometimes desirable to choose specific access points from the +candidates that match the +)0 3 1 A(template)3 0 TN TL()Ec /AF f D(. In order to do this, the +XPANSLookup routine can be called to return a list of matches, so that +specific class:name instances can then be fed to XPAGet\201\202, XPASet\201\202, etc. + +)0 P( The first argument is an optional XPA struct. If non-NULL, the +existing name server connection associated with the specified xpa is +used to query the xpans name server for matching templates. Otherwise, +a new \201temporary\202 connection is established with the name server. + +)0 P(The second argument to XPANSLookup is the class:name +)0 3 1 A(template)3 0 TN TL()Ec /AF f D( +to match. + +)0 P(The third argument for XPANSLookup\201\202 is the type of access and can be +any combination of: +) 5 62 PR( type explanation + ------ ----------- + g xpaget calls can be made on this access point + s xpaset calls can be made on this access point + i xpainfo calls can be made on this access point)RP( +)0 P(The call typically specifies only one of these at a time. + +)0 P(The final arguments are pointers to arrays that will be filled +in and returned by the name server. The name server will allocate and +return arrays filled with the classes, names, and methods of all XPA +access points that match the )0 3 1 A(template)3 0 TN TL()Ec /AF f D( +and have the specified type. Also returned are info strings, which +generally are used internally by the client routines. These can be +ignored \201but the strings must be freed\202. The function returns the +number of matches. The returned value can be used to loop through the +matches: + +)BD(Example:)ES( +) 24 73 PR( #include <xpa.h> + + char **classes; + char **names; + char **methods; + char **infos; + int i, n; + n = XPANSLookup\201NULL, "foo*", "g", &classes, &names, &methods, &infos\202; + for\201i=0; i<n; i++\202{ + [more specific checks on possibilities ...] + [perhaps a call to XPAGet for those that pass, etc. ...] + /* don't forget to free alloc'ed strings when done */ + free\201classes[i]\202; + free\201names[i]\202; + free\201methods[i]\202; + free\201infos[i]\202; + } + /* free up arrays alloc'ed by names server */ + if\201 n > 0 \202{ + free\201classes\202; + free\201names\202; + free\201methods\202; + free\201infos\202; + })RP( +)0 P(The specified +)0 3 1 A(template)3 0 TN TL()Ec /AF f D( +also can be a host:port specification, for example: +) 1 14 PR( myhost:12345)RP( +)0 P(In this case, no connection is made to the name server. Instead, the +call will return one entry such that the ip array contains the ip for +the specified host and the port array contains the port. The class +and name entries are set to the character "?", since the class and +name of the access point are not known. + + + + +)0 2 79 H(XPAAccess:)WB 142 Sn()WB 37 Sn( return XPA access points matching +template \201XPA 2.1 and above\202)EA()EH( + + +)BD() 5 60 PR( #include <xpa.h> + + int XPAAccess\201XPA xpa, + char *template, char *paramlist, char *mode, + char **names, char **messages, int n\202;)RP()ES( + + +)0 P(The XPAAccess routine returns the public access points that match the +specified second argument )0 3 1 A(template)3 0 TN TL()Ec /AF f D( and +have the specified access type. + +)0 P(A +)0 3 1 A(template)3 0 TN TL()Ec /AF f D( +of the form "class1:name1" is sent to the +XPA name server, which returns a list of at most n matching XPA +servers. A connection is established with each of these servers and +the paramlist string is passed to the server as the data transfer +request is initiated. If an XPA struct is passed to the call, then the +persistent connections are updated as described above. Otherwise, +temporary connections are made to the servers \201which will be closed +when the call completes\202. + +)0 P(The XPAAccess\201\202 routine retrieves names from at most n XPA servers +that match the specified template and that were checked for access +using the specified mode. The return string contains both the +class:name and ip:port. If a given server returned an error or the +server callback sends a message back to the client, then the message +will be stored in the associated element of the messages array. +NB: if specified, the name and messages arrays must be of size n or greater. + +)0 P(The returned message string will be of the form: +) 1 46 PR( XPA$ERROR error-message \201class:name ip:port\202)RP( +)0 P(Note that names of matching registered access points are always +returned but may not be valid; it is not sufficient to assume that the +returned number of access points is the number of valid access points. +Rather, it is essential to check the messages array for error +messages. Any string in the messages array is an error message and +indicated that the associated access point is not available. + +)0 P(For example, assume that a server registers a number of access points +but delays entering its event loop. If a call to XPAAccess\201\202 is made +before the event loop is entered, the call will timeout \201after waiting +for the long timeout period\202 and return an error of the form: +) 1 65 PR( XPA$ERROR: timeout waiting for server authentication \201XPA:xpa1\202)RP( +The error means that the XPA access point has been registered but is +not yet available \201because events are not being processed\202. When the +server finally enters its event loop, subsequent calls to XPAAccess\201\202 +will return successfully. + +)0 P(NB: This routine only works with XPA servers built with XPA 2.1.x and later. +Servers with older versions of XPA will return the error message: + + XPA$ERROR invalid xpa command in initialization string + +If you get this error message, then the old server actually is ready +for access, since it got to the point of fielding the query! The +xpaaccess program, for example, ignores this message in order to work +properly with older servers. + +)0 P(The third argument for XPAAccess\201\202 is the type of access and can be +any combination of: +) 5 62 PR( type explanation + ------ ----------- + g xpaget calls can be made on this access point + s xpaset calls can be made on this access point + i xpainfo calls can be made on this access point)RP( +)0 P(The mode string argument is of the form: "key1=value1,key2=value2,..." +The following keywords are recognized: +) 3 115 PR( key value default explanation + ------ -------- -------- ----------- + ack true/false true if false, don't wait for ack from server \201after callback completes\202)RP( +)0 P(The ack keyword is not very useful, since the server completes the callback +in order to return the data anyway. It is here for completion \201and perhaps +for future usefulness\202. + + + + + + + + + + + + + + + + + + + + + + + +)0 P()0 0 1 A(Go to XPA Help Index)0 0 TN TL()Ec /AF f D( + +)0 5 80 H(Last)WB 143 Sn( updated: March 10, 2007)EH( + +)WB NL +/Cb Db D /Ct [16#00 16#00 16#00] D /Cl [16#00 16#00 16#00] D /CL -1 D Ct Sc +DS +/Ba f D /BO 0 D Bs +/UR (xt.html) D +/Ti (XPA/Xt Interface) D +/Au () D +/Df f D +/ME [()] D + +0 BO R +()1 Sl()WB 38 Sn( + + +)0 2 81 H(XPAXt:)WB 145 Sn()WB 144 Sn( the XPA Interface to Xt \201X Windows\202)EA()EH( + + +)0 2 82 H(Summary)WB 146 Sn()EH( +Describes how XPA access points can be added to X Toolkit \201Xt\202 programs. + + +)0 2 83 H(Description)WB 147 Sn()EH( +)0 P(XPA supports Xt programs: you can call XPANew\201\202, XPACmdNew\201\202, or +XPAInfoNew\201\202 within any C routine to add XPA server callbacks to an Xt +program. Since an Xt program has its own event loop call \201i.e., +XtAppMainLoop\201\202\202, it therefore does not need or want to use the XPA +even loop. Thus, in order to add XPA access points to the standard Xt +event loop, the following routine should be called before entering the +loop: +) 1 46 PR( int XPAXtAddInput\201XtAppContext app, XPA xpa\202)RP( +)0 P(The XPAAddAddInput\201\202 routine will add XPA access points to the Xt event +loop by making calls to the standard XtAppAddInput\201\202 routine. \201If the +XtAppContext argument is NULL, then the alternate XtAddInput\201\202 routine +is used instead.\202 If the xpa argument is NULL, then all active XPA +access points are added to the loop. If xpa is not NULL, then only +the specified access point is added. The latter type of call is used +to add new access points from within a callback, after the program has +entered the XtAppMainLoop\201\202 even loop. + + + + + +)0 P()0 0 1 A(Go to XPA Help Index)0 0 TN TL()Ec /AF f D( + +)0 5 84 H(Last)WB 148 Sn( updated: September 10, 2003)EH( +)WB NL +/Cb Db D /Ct [16#00 16#00 16#00] D /Cl [16#00 16#00 16#00] D /CL -1 D Ct Sc +DS +/Ba f D /BO 0 D Bs +/UR (tcl.html) D +/Ti (XPA/Tcl Interface) D +/Au () D +/Df f D +/ME [()] D + +0 BO R +()1 Sl()WB 39 Sn( + + +)0 2 85 H(XPATcl:)WB 151 Sn()WB 149 Sn( the XPA Interface to the Tcl/Tk Environment)EA()EH( + + +)0 2 86 H(Summary)WB 152 Sn()EH( + +)0 P(Tcl/Tk programs can act as XPA clients and/or servers using the Tcl +interface to XPA that is contained in the libtclxpa.so shared object. + +)0 2 87 H(Server)WB 153 Sn( Routines)EH( + +) 11 70 PR( set xpa [xpanew class name help sproc sdata smode rproc rdata rmode] + xpafree xpa + set xpa [xpanew class name help iproc idata imode] + set xpa [xpacmdnew class name] + xpacmdadd xpa name help sproc sdata smode rproc rdata rmode + xpacmddel xpa cmd + set val [xparec xpa option] + options: name, class, method, cmdfd, datafd, cmdchan, datachan + xpasetbuf xpa buf len + xpaerror xpa message + xpamessage xpa message)RP( + +)0 2 88 H(Client)WB 154 Sn( Routines)EH( + +) 11 69 PR( set xpa [xpaopen mode] + xpaclose xpa + set got [xpaget xpa template paramlist mode bufs lens names errs n] + set got [xpaget xpa template paramlist mode chans names errs n] + set got [xpaset xpa template paramlist mode buf len names errs n] + set got [xpasetfd xpa template paramlist mode chan names errs n] + set got [xpainfo xpa template paramlist mode names errs n] + # NB: 2.1 calling sequence change + # set got [xpaaccess template type] \2012.0.5\202 + set got [xpaaccess xpa template paramlist mode names errs n] + set got [xpanslookup template type classes names methods])RP( + + +)0 2 89 H(Description)WB 155 Sn()EH( +)0 P(You can call XPANew\201\202, XPACmdNew\201\202, or XPAInfoNew\201\202 within a C +routine to add C-based XPA server callbacks to a TCL/Tk program that +uses a Tcl/Tk event loop \201either vwait\201\202 or the Tk event loop\202; +Such a program does not need or want to use the XPA event loop. +Therefore, in order to add XPA access points to the Tcl/Tk loop, the +following routine should be called beforehand: +) 1 30 PR( int XPATclAddInput\201XPA xpa\202;)RP( +)0 P(Normally, the xpa argument is NULL, meaning that all current XPA +access points are registered with the event loop. However, if a +single XPA access point is to be added \201i.e., after the event loop is +started\202 then the handle of that XPA access point can be passed to +this routine. + +)0 P(The significance of the XPA/TCL interface goes beyond the support for +using XPA inside C code. The interface allows you to write XPA +servers and to make calls to the XPA client interface within the Tcl +environment using the Tcl language directly. The XPA/Tcl +interface can be loaded using the following package command: +) 1 28 PR( package require tclxpa 2.0)RP( +Alternatively, you can load the shared object \201called libtclxpa.so \202 directly: +) 1 30 PR( load .../libtclxpa.so tclxpa)RP( +)0 P(Once the tclxpa package is loaded, you can use Tcl versions of XPA +routines to define XPA servers or make client XPA calls. The +interface for these routines is designed to match the Unix XPA +interface as nearly as possible. Please refer to +)0 15 1 A(XPA Servers)15 0 TN TL()Ec /AF f D( +and +)0 28 1 A(XPA Clients)28 0 TN TL()Ec /AF f D( +for general information about these routines. + +)0 P(The file test.tcl in the XPA source directory gives examples for using the +XPA/Tcl interface. + +)0 P(The following notes describe the minor differences between the interfaces. + +)0 2 90 H(XPANew)WB 156 Sn()WB 150 Sn()EA()EH( +) 1 70 PR()BD( set xpa [xpanew class name help sproc sdata smode rproc rdata rmode])ES()RP( +)0 P(rproc and sproc routines are routines. The calling sequence of the +rproc routine is identical to its C counterpart: +) 1 59 PR( proc rec_cb { xpa client_data paramlist buf len } { ... })RP( +)0 P(The sproc routine, however is slightly different from its C counterpart +because of the difficulty of passing data back from the callback to C: +) 1 51 PR( proc sendcb { xpa client_data paramlist } { ... })RP( +)0 P(Note that the C-based server's char **buf and int *len arguments are +missing from the Tcl callback. This is because we did not know how to +fill buf with data and pass it back to the C routines for communication +with the client. Instead, the Tcl server callback uses the following +routine to set buf and len: +) 1 23 PR( xpasetbuf xpa buf len)RP( +where: +) 5 79 PR( arg explanation + ------ ----------- + xpa the first argument of the server callback + buf the data to be returned to the client + len data length in bytes, \201if absent, use length of the buf object\202)RP( +)0 P(When this routine is called, a copy of buf is saved for transmission to +the client. + +)0 P(The fact that buf is duplicated means that TCL server writers might wish to +perform the I/O directly within the callback, rather than have XPA do it +automatically at the end of the routine. To do this, set: +) 1 15 PR( fillbuf=false)RP( +)0 P(in the xpanew smode and then perform I/O through the Tcl channel +obtained from: +) 1 34 PR( set dchan [xparec $xpa datachan])RP( +)0 P(where: +) 5 79 PR( arg explanation + ------ ----------- + xpa the first argument of the server callback + datachan literal string "datachan" that returns the data channel + len data length in bytes, \201if absent, use length of the buf object\202)RP( +)0 P()BD(NB: datachan and cmdchan are not available under Windows. It is +necessary to use the "raw" equivalents: datafd and cmdfd.)ES( + +)0 P(The same considerations apply to the rproc for receive servers: a copy +of the incoming data is generated to pass to the receive callback. This +copy again can be avoided by using "fillbuf=false" in the rmode and then +reading the incoming data from datachan. + +)0 P(The send and receive callback routines can use the xpaerror and xpamessage +routines to send errors and messages back to the client. If you also +want tcl itself to field an error condition, use the standard return call: +) 1 56 PR( return ?-code c? ?-errorinfo i? ?-errorcode ec? string)RP( +)0 P(See the Tcl man page for more info. + +)0 2 91 H(XPARec)WB 157 Sn()WB 150 Sn()EA()EH( +)0 P(The Tcl xparec procedure supplies server routines with access to information +that is available via macros in the C interface: +) 1 31 PR( set val [xparec xpa <option>])RP( +)0 P(where option is: name, class, method, cmdfd, datafd, cmdchan, +datachan. Note that two additional identifiers, cmdchan and datachan, +have been added to to provide Tcl channels corresponding to datafd and +cmdfd. \201These latter might still be retrieved in Tcl and passed back +to a C routines.\202 An additional option called "version" can be used to +determine the XPA version used to build the Tcl interface. Note that +the standard options require a valid XPA handle, but "version" does +not \201since it simply reports the value of the XPA_VERSION definition +in the XPA source include file\202. + +)0 P()BD(NB: datachan and cmdchan are not available under Windows. It is +necessary to use the "raw" equivalents: datafd and cmdfd.)ES( +) 12 58 PR( macro explanation + ------ ----------- + class class of this xpa + name name of this xpa + method method string \201inet or local connect info\202 + cmdchan Tcl channel of command socket + datachan Tcl channel of data socket + cmdfd fd of command socket + datafd fd of data socket + sendian endian-ness of server \201"little" or "big"\202 + cendian endian-ness of client \201"little" or "big" + version XPA version used to build this code)RP( + +)0 P(Under Windows, the Tcl event handler cannot automatically sense when an +XPA socket is ready for IO \201i.e. Tcl_CreateFileHandler\201\202 is not available +under Windows\202. The Windows Tcl event handler therefore must be awakened +occasionally for check for XPA events. This is done using the standard +Tcl_SetMaxBlockTime\201\202 call. The time parameter is defined in tclloop.c +and is currently set to 1000 microseconds \2011/1000 of a second\202. + +)0 P(The version option can be used to differentiate between source code versions. +It was created to support legacy Tcl code that needs to maintain the 2.0.5 +calling sequence for xpaaccess. You can use a version test such as: +) 12 44 PR( if [catch { xparec "" version } version] { + puts "pre-2.1.0e" + } else { + puts [split $version .] + } +) 7 32 PR( + + + +)0 P()0 0 1 A(Go to XPA Help Index)0 0 TN TL()Ec /AF f D( + +)0 5 92 H(Last)WB 158 Sn( updated: September 10, 2003)EH( +)WB NL +/Cb Db D /Ct [16#00 16#00 16#00] D /Cl [16#00 16#00 16#00] D /CL -1 D Ct Sc +DS +/Ba f D /BO 0 D Bs +/UR (env.html) D +/Ti (The XPA Environment) D +/Au () D +/Df f D +/ME [()] D + +0 BO R +()1 Sl()WB 40 Sn( + + +)0 2 93 H(XPAEnv:)WB 160 Sn()WB 159 Sn( Environment Variables for XPA Messaging)EA()EH( + + +)0 2 94 H(Summary)WB 161 Sn()EH( +Describes the environment variables which can be used to tailor the overall +XPA environment. + + +)0 2 95 H(Description)WB 162 Sn()EH( +)0 P(The following environment variables are supported by XPA: +)0 DL()0 P()0 DT()BD(XPA_ACL)ES( +)DD( If )EM(XPA_ACL)ES( is )EM(true)ES(, then +host-based )0 41 1 A(XPA Access Control)41 0 TN TL()Ec /AF f D( +is turned on and only specified machines can access specified access +points. If )EM(false)ES(, then access control is turned off and any +machine can access point. The default is turn turn access control on. + +)0 P()0 DT()BD(XPA_ACLFILE)ES( +)DD( If +)0 41 1 A(XPA Access Control)41 0 TN TL()Ec /AF f D( +is turned on, this variable specifies the name of the file containing +access control information for all access points started by this user. +The default file name is: )EM($HOME/acls.xpa)ES(. + +)0 P()0 DT()BD(XPA_CONNECT_TIMEOUT)ES( +)DD( When an XPA server first starts up, it immediately tries to +connect to the XPA name server program \201xpans\202 on the host specified by +the )EM(XPA_NSINET)ES( variable. \201If this connection fails on the +local host, and if xpans can be found in the path, then the name +server is started automatically.\202 Unfortunately, a mis-configured +network can cause this connect attempt to hang for many seconds while +the connect\201\202 system call times out. Therefore, an alarm is started +to interrupt the connect\201\202 call and prevent a long hang. The initial +value of the alarm timeout is 10 seconds, but can be changed by setting +this environment variable. If you want to disable the alarm and allow +the initial connect\201\202 to time out, set the value of this variable to +0. Normally, users would not change this variable at all. + +)0 P()0 DT()BD(XPA_CLIENT_DOXPA)ES( +)DD( Normally, an XPA client \201xpaget, xpaset, etc.\202 will process incoming +XPA server requests while awaiting the completion of the client request. +Setting this variable to "false" will prevent XPA server requests from +being processed by the client. + +)0 P()0 DT()BD(XPA_DEFACL)ES( +)DD( If +)0 41 1 A(XPA Access Control)41 0 TN TL()Ec /AF f D( +is turned on, this variable specifies the default access control +condition for all access points, if the )EM(XPA_ACLFILE)ES( file does +not exist. The default acl is: )EM($host:* $host +)ES(, meaning that +all processes on the host machine have full access to all access points. + +)0 P()0 DT()BD(XPA_HOST)ES( +)DD(For the INET socket method, XPA utilizes the canonical hostname \201as +returned by the gethostname\201\202 routine\202 to construct the IP part of the +method id. Under some circumstances, this might not be a correct choice +of name and IP. For example, if an XPA server is started on a machine +running VPN, you might want to use the VPN name and IP instead of the +canonical host name, so that other machines in the VPN network can +access the server. In this case, you can set the XPA_HOST to be +the VPN name \201if resolvable\202 or, more easily, the VPN IP. + +)0 P()0 DT()BD(XPA_IOCALLSXPA)ES( +)DD( +Setting this variable causes all XPA socket IO calls to process +outstanding XPA requests whenever the primary socket is not ready for +IO. This means that a server making a client call will \201recursively\202 +process incoming server requests while waiting for client completion. +This inter-IO XPA processing avoids a rare +)0 26 1 A(XPA Race Condition)26 0 TN TL()Ec /AF f D(: two or more +XPA servers sending messages to one another using an XPA client +routine such as XPASet\201\202 can deadlock while each waits for the other +server to respond. This can happen, for example, if the servers call +XPAPoll\201\202 with a time limit, and send messages in between the polling call. + +)0 P(By default, this option is turned off, because we judge that the added +code complication and overhead involved will not be justified by the +amount of its use. Moreover, processing XPA requests within socket IO +can lead to non-intuitive results, since incoming server requests will +not necessarily be processed to completion in the order in which they +are received. + +)0 P()0 DT()BD(XPA_LOGNAME)ES( +)DD(XPA preferentially uses the de facto standard environment variable +LOGNAME to determine the username when registering an access point in +the name server. If this environment variable has been used for +something other than the actual user name \201such as a log file name\202, +unexpected results can ensue. In such cases, use the XPA_LOGNAME +variable to set the user name. \201If neither exists, then getpwuid\201geteuid\201\202\202 +is used as a last resort\202. + +)0 P()0 DT()BD(XPA_LONG_TIMEOUT)ES( +)DD( XPA is designed to allow data to be sent from one process to +another over a long period of time \201i.e., a program that generates +image data sends that data to an image display, but slowly\202 but it +also seeks to prevent hangs. This is done by supporting 2 timeout +periods: a )EM(short)ES( timeout for protocol communication +and a )EM(long)ES( for data communication. +)0 P(The )EM(XPA_LONG_TIMEOUT)ES( variable controls the )EM(long)ES( +timeout and is used to prevent hangs in cases where communication +between the client and server that is )EM(not)ES( controlled by the +XPA interface itself. Transfer of data between client and server, or a +client's wait for a status message after completion of the server +callback, are two examples of this sort of communication. By default, +the )EM(long)ES( timeout is set to 180 seconds. +Setting the value to -1 will disable )EM(long)ES( timeouts and allow +an infinite amount of time. + +)0 P()0 DT()BD(XPA_MAXHOSTS)ES( +)DD( The maximum number of access points that the programs +)EM(xpaset)ES(, )EM(xpaget)ES(, and )EM(xpainfo)ES( will +communicate with at one time. The default is 64, meaning, for +example, that the )EM(xpaset)ES( program will not send a message +to more than 100 access points at one time and )EM(xpaget)ES( will +not retrieve from more than 100 access points at one time. + +)0 P()0 DT()BD(XPA_METHOD)ES( +)DD(Determines the socket connection method used by this session of XPA. +The choices are: )EM(inet)ES( \201to use INET or Internet-based +sockets\202, )EM(localhost)ES( \201to use the machines localhost inet +socket\202, or )EM(local \201unix\202)ES( \201to use UNIX sockets\202. The default +is )EM(INET)ES(. Using the )EM(inet)ES( method will allow access +from other machines \201subject to access controls\202 but using +)EM(localhost)ES( or )EM(local)ES( will not. Localhost is most useful +for private access and when the machine in question is not connected +to the Internet. The unix method also can be used for private access +and non-Internet connections \201Unix platforms only\202. +)0 P(Once defined, the first registration of an XPA access point will +ensure that an instance of the +)0 14 1 A(XPA Name Server \201xpans\202)14 0 TN TL()Ec /AF f D( +is running that handles that connection method. All new access points +will use the new connection method but existing access points will use +the original method. + +)0 P()0 DT()BD(XPA_NSINET)ES( +)DD( For the )EM(inet)ES( method of socket connection, this variable +specifies the host and port on which the +)0 14 1 A(XPA Name Server \201xpans\202)14 0 TN TL()Ec /AF f D( +is listens for new access points. The default is )EM($host:$port)ES(, +meaning that the default XPA port \20114285\202 on the current machine +\201as returned by gethostname\201\202\202 is used. If several machines were all +accessing the same XPA access points, you would use this variable to +specify that they all use the same name server to find out about these +access points. For example, a value of )EM(myhost:$port)ES( would +mean that the xpans name server is running on myhost and uses the +default port 12345. All machines would then get the XPA access points +registered with that name server, subject to access controls. +)0 P(The port used by xpans to register its XPA access point normally is +taken to be one greater than the port on which it receives new access +points from XPA servers. You can specify a specific access point port +using the syntax machine:port1,port2, i.e., the access point port is +specified after the comma. For example, $host:12345,23456 will listen +for new access ports on 12345 and will accept XPA commands on 23456. + +)0 P()0 DT()BD(XPA_NSREGISTER)ES( +)DD(This boolean variable specifies whether a server registers its XPA +access point with the specified xpans name server. The default is +)EM(true)ES(. If set to )EM(false)ES(, the access point still is +set up but it is not registered with xpans and therefore cannot be +accessed by name. \201It can be accessed by method, if the latter is +known.\202 Note that an access point can be registered later on \201using +-remote or -proxy, for example\202. This variable mainly is useful in +cases where the Internet configuration is broken \201so that registration +causes a DNS hang\202 but you still wish to and can use the server with a +remote xpans \201e.g., ds9's Virtual Observatory capability\202. + +)0 P()0 DT()BD(XPA_NSUNIX)ES( +)DD( For the )EM(local)ES( method of socket connection, this variable +specifies the name of the Unix file that will be used to access the +)0 14 1 A(XPA Name Server \201xpans\202)14 0 TN TL()Ec /AF f D(. The default is +)EM(xpans_unix)ES(. This variable is not usually needed. Note that +is the )EM(local)ES( socket method is used, then remote machines will +not be able to access the xpans name server or the registered XPA access +points. + +)0 P()0 DT()BD(XPA_NSUSERS)ES( +)DD(This variable specifies whether other users' access points will be +returned by the +)0 14 1 A(XPA Name Server \201xpans\202)14 0 TN TL()Ec /AF f D( for use by +)EM(xpaget)ES(, )EM(xpaset)ES(, etc. +Generally speaking, it is sufficient to run one xpans name server per +machine and register the access points for all users with that xpans. +This means, for example, that if you request information from +ds9 by running: +) 1 21 PR( xpaget ds9 colormap)RP( +you might get information from your own ds9 as well as +from another user running ds9 on the same machine. The +)EM(XPA_NSUSERS)ES( variable controls whether you want such access +to the access points of other users. +By default, only your own access points are returned, so +that, in the example above, you would only get the colormap information +from the ds9 you registered. If, however, you had set the value of the +)EM(XPA_NSUSERS)ES( variable to )EM(eric,fred)ES(, then you would be +able to communicate with both eric and fred's access points. Note that +this variable can be overridden using the )EM(-u)ES( switch on the +)EM(xpaget)ES(, )EM(xpaset)ES(, and )EM(xpainfo)ES( programs. + +)0 P()0 DT()BD(XPA_PORT)ES( +)DD( +A semi-colon delimited list of user specified ports to use for specific +XPA access points. The format is each specification is: +) 1 28 PR(class:template port1[ port2])RP( +where )BD(port1)ES( is the main \201command\202 port for the access point and +)BD(port2)ES( is the \201secondary\202 data port. If port2 is not specified, +it defaults to a value of 0 \201meaning the system assigns the port\202. + +)0 P(Specification of specific ports is useful, for example, when a machine +outside a firewall needs to communicate with a machine inside a +firewall. In such a case, the firewall should be configured to allow +socket connections to both the command and data port from the outside +machine, and the inside XPA program should be started up with the +outside machine in its ACL list. Then, when the inside program is +started with specified ports, outside XPA programs can use +"machine:port" to contact the inside access points, instead of the +access point names. That is, the machine outside the firewall does not +need access to the XPA name server: +) 2 62 PR(export XPA_PORT="DS9:ds9 12345 12346" # on machine "inside" +cat foo.fits | xpaset inside:12345 fits # on machine "outside")RP( +Note that 2 ports are required for full XPA communication and +therefore 2 ports should be specified to go through a firewall. The +second port assignment is not important if you simply are assigning +the command port in order to communicate commands with a known +port \201e.g., to bypass the xpans name server\202. If only one \201command\202 +port is specified, the system will negotiate a random data port and +everything will work properly. + +)0 P(This support is somewhat experimental. If you run into problems, please +let us know. + +)0 P()0 DT()BD(XPA_PORTFILE)ES( +)DD( +A list of user-specified port to use for specific xpa access points. +The format of the file is: +) 1 28 PR(class:template port1 [port2])RP( +where )BD(port1)ES( is the main port for the access point and +)BD(port2)ES( is the data port. If port2 is not specified, it defaults +to a value of 0 \201meaning the system assigns the port\202. See +)BD(XPA_PORT)ES( above for an explanation of user-specified ports. + +)0 P()0 DT()BD(XPA_SHORT_TIMEOUT)ES( +)DD( XPA is designed to allow data to be sent from one process to +another over a long period of time \201i.e., a program that generates +image data sends that data to an image display, but slowly\202 but it +also seeks to prevent hangs. This is done by supporting 2 timeout +periods: a )EM(short)ES( timeout for protocol communication +and a )EM(long)ES( for data communication. +)0 P(The )EM(XPA_SHORT_TIMEOUT)ES( variable +controls the )EM(short)ES( timeout and is used to prevent hangs +in cases where the XPA protocol requires internal communication between +the client and server that is controlled by the XPA interface +itself. Authentication is an example of this sort of communication, +as is the establishment of a data channel between the two processes. +The default value for the )EM(short)ES( is 30 seconds \201which is +a pretty long time, actually\202. Setting the value to -1 will disable +)EM(short)ES( timeouts and allow an infinite amount of time. + +)0 P()0 DT()BD(XPA_SIGUSR1)ES( +)DD( If the value of this variable is )EM(true)ES(, then XPA will +catch SIGUSR1 signals when performing an I/O operation in order to +curtail that operation. This facility allows users to send a SIGUSR1 +signal to an XPA server if a client is hanging up the server by +sending or receiving data too slowly \201timeouts also can be used -- see +above\202. When enabled in this way, the SIGUSR1 signal is ignored at all other +times, so that its safe to send the signal at any time. If the +variable is set to )EM(false)ES(, then SIGUSR1 is not used at +all. Turning off SIGUSR1 would be desired in cases there the program +uses SIGUSR1 for some other reason and does not want XPA interfering. +The default is to use the signal. + +)0 P()0 DT()BD(XPA_TIMESTAMP_ERRORS)ES( +)DD( If )EM(XPA_TIMESTAMP_ERRORS)ES( is )EM(true)ES(, then error +messages will include a date/time string. This can be useful when +XPA errors are being saved in an error log \201e.g. Web/CGI use\202. The +default is false.)LD( + +)0 P()0 DT()BD(XPA_TMPDIR)ES( +)DD( This variable specifies the directory into which XPA logs, Unix +socket files \201when )EM(XPA_METHOD)ES( is )EM(local)ES(\202, etc. are +stored. The default is )EM(/tmp/.xpa)ES(. + +)0 P()0 DT()BD(XPA_VERBOSITY)ES( +)DD( Specify the verbosity level of error messages. If the value is +set to )EM(0)ES(, )EM(false)ES(, or )EM(off)ES(, then no error +messages are printed to stderr. If the value is )EM(1)ES(, then +important XPA error messages will be output. If the value is +set to )EM(2)ES(, XPA warnings about out-of-sync messages will also +be output. These latter almost always can be ignored. + +)0 P()0 DT()BD(XPA_VERSIONCHECK)ES( +)DD( Specify whether a new access point should check its major and minor XPA +version number against the version used by the xpans name server at +registration time. The default is )EM(true)ES(. When checking is +performed, a warning is issued if the server major version is found to +be greater than the xpans version. Note that the check is performed +both by the XPA server and by the xpans process and warnings will be +issued by each. Also, instead of the values of )EM(true)ES( or +)EM(false)ES(, you can give this variable an integer value n. In this +case, each version checking process \201i.e., the XPA-enabled server or +xpans\202 will print out a maximum of n warning messages \201after which +version warnings are silently swallowed\202. +)0 P(In general, it is a bad idea to run an XPA-enabled server program +using a version of XPA newer than the basic xpaset, xpaget, xpaaccess, +xpans programs. This sort of mismatch usually will not work due to +protocol changes. + + + + + +)0 P()0 0 1 A(Go to XPA Help Index)0 0 TN TL()Ec /AF f D( + +)0 5 96 H(Last)WB 163 Sn( updated: December 23, 2009)EH( + +)WB NL +/Cb Db D /Ct [16#00 16#00 16#00] D /Cl [16#00 16#00 16#00] D /CL -1 D Ct Sc +DS +/Ba f D /BO 0 D Bs +/UR (acl.html) D +/Ti (XPA Access Control) D +/Au () D +/Df f D +/ME [()] D + +0 BO R +()1 Sl()WB 41 Sn( + + +)0 2 97 H(XPAAcl:)WB 165 Sn()WB 164 Sn( Access Control for XPA Messaging)EA()EH( + + +)0 2 98 H(Summary)WB 166 Sn()EH( +)0 P(XPA supports host-based access control for each XPA access point. You +can enable/disable access control using the XPA_ACL environment +variable. You can specify access to specific XPA access points for +specific machines using the XPA_DEFACL and XPA_ACLFILE environment +variables. By default, an XPA access point is accessible only to +processes running on the same machine \201same as X Windows\202. + + +)0 2 99 H(Description)WB 167 Sn()EH( +)0 P(When INET sockets are in use \201the default, as specified by the +)EM(XPA_METHOD)ES( environment variable\202, XPA supports a host-based +access control mechanism for individual access points. This mean that +access can be specified for get, set, or info operations for each +access point on a machine by machine basis. For LOCAL sockets, access +is restricted \201by definition\202 to the host machine. + +)0 P(XPA access control is enabled by default, but can be turned off by +setting the )EM(XPA_ACL)ES( environment variable to )EM(false)ES(. +In this case, any process can access any XPA server. + +)0 P(Assuming that access control is turned on, the ACL for an individual +XPA access point is set up when that access point is registered +\201although it can be changed later on; see below\202. This can be done in +one of two ways: + +Firstly, the )EM(XPA_ACLFILE)ES( environment variable can defined to +point to a file of access controls for individual access points. The format +of this file is: +) 1 18 PR( class:name ip acl)RP( +The first argument is a template that specifies the class:name of the +access point covered by this ACL. See +)0 3 1 A(XPA Access Points and Templates)3 0 TN TL()Ec /AF f D( +for more information about xpa templates. + +)0 P(The second argument is the IP address \201in human-readable format\202 of +the machine which is being given access. This argument can be +)EM(*)ES( to match all IP addresses. It also can be )EM($host)ES( +to match the IP address of the current host. + +)0 P(The third argument is a string combination of )EM(s)ES(, )EM(g)ES(, +or )EM(i)ES( to allow )EM(xpaset)ES(, )EM(xpaget)ES(, or +)EM(xpainfo)ES( access respectively. The ACL argument can be +)EM(+)ES( to give )EM(sgi)ES( access or it can be )EM(-)ES( to turn +off all access. + +)0 P(For example, +) 3 21 PR( *:xpa1 somehost sg + *:xpa1 myhost + + * * g)RP( +will allow processes on the machine somehost to make xpaget and xpaset calls, +allow processes on myhost to make any call, and allow all other hosts to +make xpaget \201but not xpaset\202 calls. + +Secondly, if the )EM(XPA_ACLFILE)ES( does not exist, then a single +default value for all access points can be specified using the +)EM(XPA_DEFACL)ES( environment variable. The default value for this +variable is: +) 1 34 PR( #define XPA_DEFACL "*:* $host +")RP( +meaning that all access points are fully accessible to all processes +on the current host. Thus, in the absence of any ACL environment variables, +processes on the current host have full access to all access points +created on that host. This parallels the X11 xhost mechanism. + +)0 P(Access to an individual XPA access point can be changed using the -acl +parameter for that access point. For example: +) 1 34 PR( xpaset -p xpa1 -acl "somehost -")RP( +will turn off all access control for somehost to the xpa1 access point, while: +) 1 38 PR( xpaset -p XPA:xpa1 -acl "beberly gs")RP( +will give beberly xpaget and xpaset access to the access point whose +class is XPA and whose name is xpa1. +)0 P(Similarly, the current ACL for a given access point can be retrieved using: +) 1 18 PR( xpaget xpa1 -acl)RP( +Of course, you must have xpaget access to this XPA access point to +retrieve its ACL. + +)0 P(Note that the XPA access points registered in the )EM(xpans)ES( +program also behave according to the ACL rules. That is, you cannot +use xpaget to view the access points registered with xpans unless +you have the proper ACL. + +)0 P(Note also when a client request is made to an XPA server, the access +control is checked when the initial connection is established. This +access in effect at this time remains in effect so long as the client +connection is maintained, regardless of whether the access fro that +XPA is changed later on. + +)0 P(We recognize that host-based access control is only relatively secure +and will consider more stringent security \201e.g., private key\202 in the +future if the community requires such support. + + + + + +)0 P()0 0 1 A(Go to XPA Help Index)0 0 TN TL()Ec /AF f D( + +)0 5 100 H(Last)WB 168 Sn( updated: September 10, 2003)EH( + +)WB NL +/Cb Db D /Ct [16#00 16#00 16#00] D /Cl [16#00 16#00 16#00] D /CL -1 D Ct Sc +DS +/Ba f D /BO 0 D Bs +/UR (changelog.html) D +/Ti (XPA ChangeLog) D +/Au () D +/Df f D +/ME [()] D + +0 BO R +()1 Sl()WB 42 Sn( +)0 2 101 H(XPA)WB 169 Sn( ChangeLog)EH( + +)0 P(This ChangeLog covers the XPA 2 implementation. It will be updated +as we continue to develop and improve XPA. The up-to-date version can be +found )R1 2 A(here)EA(. + +)0 2 102 H()WB 170 Sn( Public Release 2.1.15 \201July 23, 2013\202)EH( +)UL()0 P()-1 LI( Added support for large data transfers +)0 P()-1 LI( XPAGet and XPASet now pass size_t instead of int for lengths +)0 P()-1 LI( Send and receive callbacks now pass size_t instead of int for lengths +)0 P()-1 LI( Port to mingw \201Windows\202)LU( + + +)0 2 103 H()WB 171 Sn( Public Release 2.1.14 \201June 7, 2012\202)EH( +)UL()0 P()-1 LI( Fixed several memory leaks in the Tcl wrappers \201tcl.c\202. +)0 P()-1 LI( Use Tcl stubs library for linking shared Tcl, if available.)LU( + +)0 2 104 H()WB 172 Sn( Public Release 2.1.13 \201April 14, 2011\202)EH( +)UL()0 P()-1 LI( An atexit handler is no longer installed automatically \201it crashes +Tcl 8.5.8 applications\202. Call XPAAtExit\201void\202 to install the handler. +)0 P()-1 LI( Removed permission checking from Find\201\202 on cygwin systems. This was broken +by Windows 7. +)0 P()-1 LI( Removed addition of -no-cpp-precomp flag from gcc 4.2 and beyond \201Mac\202.)LU( + +)0 2 105 H()WB 173 Sn( Public Release 2.1.12 \201January 26, 2010\202)EH( +)UL()0 P()-1 LI( Added XPA_HOST environment variable to allow users to specify +the hostname \201and hence, ip\202 component of the INET method id. This is +useful, for example, if you want to register an access point using a +VPN-generated IP instead of the canonical IP. +)0 P()-1 LI( Fix typo in Tcl binding to xpainfo causing a crash after 2 invocations.)LU( + +)0 2 106 H()WB 174 Sn( Public Release 2.1.11 \201December 7, 2009\202)EH( +)UL()0 P()-1 LI( Generalized XPANSKeepAlive\201\202 to send messages to xpans, proxy xpans, or +both. The default is to send just to proxies \201e.g. chandra-ed\202. +)0 P()-1 LI( Changed XPANSKeepAlive\201\202 to send an in-band new-line char to +xpans, changed xpans to handle an in-band new-line as a keep-alive +message. Necessitated by Cisco routers that clear the URG flag in +a TCP packet, breaking OOB data transfer for the whole Internet, as +well as the OOB-based keep-alive implemented in xpans. +)0 P()-1 LI( In xpans, print warning when the keep-alive option switch is used. +)0 P()-1 LI( Port to mingw \201thanks to B.Schoenhammer\202 +)0 P()-1 LI( Change OOB character sent by xpans keepalive to a space, trying to working around cisco routers that force OOB data into the inbound stream. +)0 P()-1 LI( fix gcc fprintf warning in xpans.c)LU( + +)0 2 107 H()WB 175 Sn( Public Release 2.1.10 \201September 1, 2009\202)EH( +)UL()0 P()-1 LI( Update mklib and configure.ac to support 64-bit builds on Macs. +)0 P()-1 LI( Fixed bug in XPAAccess\201\202 in which the returned names could have an extra +\201bogus\202 character when the target is an explicit ip:port or local socket file. +)0 P()-1 LI( Add setjmp/longjmp support to xalloc. +)0 P()-1 LI( Add XPASaveJmp\201void *env\202 as a high-level interface to xalloc_savejmp\201\202;)LU( + +)0 2 108 H()WB 176 Sn( Internal Release 2.1.9)EH( +)UL()0 P()-1 LI( Fixed a bug that prevented an access point starting with a number +from being recognized peoperly. NB: a pure number still signifies a +port on the current machine. Also num:num signifies ip:port, where ip +can be a pure hex value or the canonical form vvv.xxx.yyy.zzz. +)0 P()-1 LI( Modified internal Launch\201\202 routine to use posix_spawn\201\202, if necessary. +This is required for OS X 10.5 \201leopard\202, which frowns upon use of fork\201\202 +and exec\201\202. Also modified zprocess routines to use Launch\201\202. +)0 P()-1 LI( Added XPASetFree\201xpa, void \201*myfree\202\201void *\202\202 routine to allow callbacks +to specify a free routine other than malloc free \201e.g. Perl garbage collection\202. +)0 P()-1 LI( XPACmdAdd\201\202 now checks to ensure that it was passed an XPA struct created +by XPACmdNew\201\202. +)0 P()-1 LI( Change launch.h to xlaunch.h to avoid conflict with OS X.)LU( + +)0 2 109 H()WB 177 Sn( Public Release 2.1.8 \2011 November 2007\202)EH( +)UL()0 P()-1 LI( A public release to complete current XPA development work.)LU( + +)0 2 110 H()WB 178 Sn( Patch Release 2.1.7b[1,2] \201Feb 22, 2006; March 8, 2007\202)EH( +)UL( +)0 P()-1 LI( Added a convenience null to the end of the buffers returned by XPAGet. + +)0 P()-1 LI( Added code to avoid calling atexit routine if a fork'ed child +calls exit\201\202 instead of _exit\201\202. + +)0 P()-1 LI( Added XPA_CLIENT_DOXPA environment variable to turn off client +processing of xpa server requests. + +)0 P()-1 LI( Added --version to xpaset, xpaget, xpainfo, xpaaccess, xpans to +display XPA version and exit. + +)0 P()-1 LI( Added support for integrating XPA into a Gtk loop. + +)0 P()-1 LI( xpaaccess now returns its answer in the error code as well as to stdout +\201without the -n switch, it returns 1 for a match, with the -n switch, +the number of matches is returned\202. + +)0 P()-1 LI( Fixed bug which prevented xpans from being started up automatically +by an xpa server if its pathname contained a space character. + +)0 P()-1 LI( Fixed bug in MINGW port of xpans in which an XPA server that +terminated via an interrupt was not being properly removed from the +list of registered access points. + +)0 P()-1 LI( Added XPA_LOGNAME to override LOGNAME when registering username + +)0 P()-1 LI( Upgraded swish-e indexing code to 2.4.5. +)LU( + +)0 2 111 H()WB 179 Sn( Patch Release 2.1.6 \2014 May 2005\202)EH( +)UL( +)0 P()-1 LI( Added -P switch to xpans to enable experimental proxy support +\201default is disabled\202. An argument of 1 processes proxy requests in +the same thread as xpans requests, while an argument of 2 processes +proxy requests in a separate thread. \201The latter is recommended to +avoid xpans timeouts, since xpa callback processing can take a long +time.\202 + +)0 P( +)-1 LI( Added ability to build shared libraries \201done automatically with +configure --enable-shared\202 with compilers other than gcc. + +)0 P()-1 LI( Made yet another attempt to build shared libraries under OS X. + +)0 P()-1 LI( Fixed a server bug in Tcl support under Windows \201introduced early +in 2.1.6\202 which caused an occasional SEGV. + +)0 P()-1 LI( Fixed race condition in cases where 2 or more servers makes client calls +to one another. + +)0 P()-1 LI( Fixed bug in the XPA handler routine in which an access point was +turned off if an error occurred in that routine \201as opposed to the +user-defined callback routine\202. + +)0 P()-1 LI( Fixed race condition when "ack=false" flag \201or -n\202 is used with XPASet\201\202 +\201or xpaset\202. + +)0 P()-1 LI( Added defensive code to XPA handler to ensure that the passed XPA record +is valid. + +)0 P()-1 LI( Tcl/XPA servers such as ds9 were not turning off select\201\202 on the +xpa channels inside an xpa callback, as required. This is now fixed. + +)0 P()-1 LI( Added timestamps to most server and client error messages if the +XPA_TIMESTAMP_ERRORS variable is set. This is useful when XPA errors are +being logged in an error log \201e.g. Web/CGI use\202. + +)0 P()-1 LI( Generated PostScript and PDF versions of the help pages. + +)0 P()-1 LI( Moved OPTIONS section before \201often-lengthy\202 DESCRIPTION section in +man pages. + +)0 P()-1 LI( All memory allocation now performs error checking on the result. + +)0 P()-1 LI( Removed some compiler warnings that surfaced when using gcc -O2. + +)0 P()-1 LI( Updated configure.ac to better support Tcl in Panther with Apple +Frameworks. +)LU( + +)0 2 112 H()WB 180 Sn( Patch Release 2.1.5 \20112 January 2004\202)EH( +)UL( +)0 P()-1 LI( Fixed bug in XPAPoll\201\202. Erroneously, no requests were being +processed when maxreq==0. Now, all pending events are processed, as +per the documentation. + +)0 P()-1 LI( Added ack=false to XPAInfo\201\202 \201and corresponding -n to xpainfo\202 +so that client does not wait for a response from the server. This is +essential in cases where XPA servers wish to send info messages to +one another without causing a race condition. + +)0 P()-1 LI( Generated man pages from the html pages. These are installed +automatically at build time. + +)0 P()-1 LI( The xpans program with Unix sockets now uses a lock file to signal +that it is running, in order to avoid a potential \201but rare\202 race +condition at startup. + +)0 P()-1 LI( Code that calls Unix-type bind\201\202 now manipulate umask\201\202 to ensure that +all users have write permissions to the socket file \201OS X apparently uses +these permissions while previous platforms ignore them\202. + +)0 P()-1 LI( Configure now checks for socklen_t type \201OS X does not define it\202. + +)0 P( +)-1 LI( Added an atexit function to run XPAFree. The aim here is to delete Unix +socket files on exiting. + +)0 P()-1 LI( Under Windows, the Tcl event-handling code now blocks for 1/1000 of a +second instead of not blocking at all \201which inadvertently used 100% of cpu\202. + +)0 P()-1 LI( Upgraded Tcl/Tk support to 8.4. + +)0 P()-1 LI( Made another round of checks was made through all instances of +strcat, strcpy, etc. to look for potential buffer overflows. Changed +all instances of sprintf\201\202 to snprintf\201\202. + +)0 P()-1 LI( Class and name designators are now limited to 1024 characters, for +no particular reason. + +)0 P()-1 LI( The obsolete $SAORD_BIN variable was being added to the path when +searching for xpans. This is no longer the case. + +)0 P()-1 LI( Fixed non-ANSI compiler errors in both xpa.c and xpans.c. + +)0 P()-1 LI( Fixed minor problems to support compilation with g++. + +)0 P()-1 LI( Ported to Intel icc and gcc 3.3 compilers. + +)0 P()-1 LI( Upgraded autoconf to 2.57. Included in this upgrade is a change that +makes gcc the default compiler \201use "configure CC=cc" to change this\202. +Also, by default, the Tcl shared object is no longer automatically built +if the Tcl libraries are used. Use the --enable-tclshlib switch in +configure to enable this feature. + +)0 P()-1 LI( Changed license from public domain to GNU GPL. +)LU( + +)0 2 113 H()WB 181 Sn( Patch Release 2.1.4 \20124 March 2003\202)EH( +)UL( +)0 P()-1 LI( Made inet method unique, even when hosts are behind a firewall using +the same ports \201on different local machines\202. + +)0 P()-1 LI( The initial connection from an xpa server to a local xpans now is +controlled by a timeout \201default 5 sec, controlled by XPA_CONNECT_TIMEOUT +variable\202. This should prevent a hang on connect\201\202 if the network +is not set up correctly. + +)0 P()-1 LI( Fixed rare race condition when an XPA server callback performed its own +XPAGet or XPASet call to another XPA server. + +)0 P()-1 LI( Use POSIX O_NONBLOCK for non-blocking I/O in fcntl call if it +exists, instead of O_NDELAY. +)LU( + +)0 2 114 H()WB 182 Sn( Patch Release 2.1.3 \20126 September 2002\202)EH( +)UL( +)0 P()-1 LI( Added -k [sec] switch to xpans to support sending one-byte keepalive +messages from xpans to registered xpa servers. + +)0 P()-1 LI( Added XPANSKeepAlive routine \201and Tcl equivalent\202 to allow +xpa servers to send a one-byte keepalive message to xpans. +)LU( + +)0 2 115 H()WB 183 Sn( Patch Release 2.1.2 \20118 July 2002\202)EH( +)UL( +)0 P()-1 LI( The "-help" reserved command now also displays the XPA version, if +no explicit sub-commands are specified. + +)0 P()-1 LI( Change internal state of xpans proxy to save ip:port value of a +server behind a NAT firewall. This is required to give some hope of +distinguishing multiple instances of ds9 running behind NAT. +)LU( + +)0 2 116 H()WB 184 Sn( Patch Release 2.1.1 \20120 June 2002\202)EH( +)UL( +)0 P()-1 LI( Added a version check between xpans and an access point, +performed when it gets registered by an XPA server. If the server +has a version greater than the xpans version, a warning is issued by +both programs. + +)0 P()-1 LI( Added a boolean XPA_NSREGISTER environment variable to allow an +XPA server to skip xpans registration. The default is to register with +the name server. If set to "false", the access point still is set up +but it is not registered with an xpans. It can be registered later on +\201using -remote or -proxy, for example\202. + +)0 P()-1 LI( Fixed bug in which xpans was still listening on any interface when +XPA_METHOD was localhost \201instead of just listening on localhost\202. +)LU( + +)0 2 117 H()WB 185 Sn( Public Release 2.1.0 \20122 April 2002\202)EH( + +)0 P(New features include: + +)UL()0 P()-1 LI( Support for proxy access to XPA servers \201e.g. ds9\202 situated +behind a firewall \201useful for NVO-type applications\202. + +)0 P()-1 LI( Improved support for allowing remote machines access rights to the +XPA access points \201useful for NVO-type applications\202. + +)0 P()-1 LI( Ability for XPAAccess\201\202 routine and xpaaccess program to contact XPA + directly. + +)0 P()-1 LI( Support for a clipboard access point that allows clients to store ASCII +state information in an XPA-enabled server. + +)0 P()-1 LI( Improved support for Windows platform, as well as new support for Mac OSX.)LU( + +)0 2 118 H()WB 186 Sn( Pre-Release 2.1.0e \2012 April 2002\202)EH( +)UL( +)0 P()-1 LI( Removed the environment variable generated by each XPA access +point \201of the form XPA_name=method\202. The putenv\201\202 call was causing ds9 +to crash under both Linux and LinuxPPC during a socket operation. We +suspect a bug in putenv but cannot prove it and this feature is not +essential, so ... +)LU( + +)0 2 119 H()WB 187 Sn( Pre-Release 2.1.0e \2011 April 2002\202)EH( +)UL( +)0 P()-1 LI( Fixed an uninitialized variable in xpamb which prevented it from +working at all on some systems. + +)0 P()-1 LI( Changed xpamb switch from "-add" to "-data" \201to store named data\202. + +)0 P()-1 LI( Changed how xpamb works with xpaget so that xpamb can return data +from XPA access points as well as from stored data. \201Previous versions +only returned stored data.\202 Now, you can retrieve stored data +explicitly using the -info and/or -data switches. For example: +) 1 24 PR( xpaget xpamb -info foo)RP( +will return info about the previously stored data named foo. If +neither switch is present, then the name is assumed to be an XPA access +point.)LU( + +)0 2 120 H()WB 188 Sn( Pre-Release 2.1.0e \20125 March 2002\202)EH( +)UL( +)0 P()-1 LI( Changed symbol for default port from "*" to "$port" to avoid +a syntactical conflict between class:* and machine:* when processing an +XPA access point class:name specification. Thus, the default inet +method now is '$host:$port' instead of '$host:*'. +)LU( + +)0 2 121 H()WB 189 Sn( Pre-Release 2.1.0e \20119 March 2002\202)EH( +)UL( +)0 P()-1 LI( Removed timeout check when reading data \201in clients using xpaget +and servers filling the data buffer\202. We have more and more cases +where we need to wait a long time to retrieve data \201e.g., slow +networks or receiving data being compressed on the fly\202. + +)0 P()-1 LI( Moved call to sigaction\201SIGCHLD,...\202 out of XPAOpen\201\202, so that it +is only executed when needed by XPAGet\201\202/XPASet\201\202 routines called from +within xpans/proxy. But then changed logic to use a double fork\201\202 instead +of sigaction\201\202 to prevent zombies \201Stevens Adv. Programming p 202\202. + +)0 P()-1 LI( Each XPA access point now generates an environment variable of the +form XPA_name=method so that children can communicate with the parent access +point more easily. + +)0 P()-1 LI( Added version option to Tcl xparec: +) 5 44 PR( if [catch { xparec "" version } version] { + puts "pre-2.1.0e" + } else { + puts [split $version .] + })RP( +to help differentiate between XPA versions within Tcl code. +)LU( + +)0 2 122 H()WB 190 Sn( Pre-Release 2.1.0e \20114 February 2002\202)EH( +)UL()0 P()-1 LI( Fixed client handling of out-of-sync messages.)LU( + +)0 2 123 H()WB 191 Sn( Pre-Release 2.1.0e \20111 February 2002\202)EH( +)UL( +)0 P()-1 LI( Fixed client.c/xopen\201\202 so that it does not open an extra socket. + +)0 P()-1 LI( Fixed xpainfo/xopen\201\202 to prevent client from hanging waiting for ack. + +)0 P( +)-1 LI( Modified stest to generate xpaaccess points xpa, xpa1, c_xpa, and +i_xpa \201or more generally, , 1, c_, i\202 to allow +more flexible testing of templates. Also added -a for testing XPAAccess\201\202. +)LU( + +)0 2 124 H()WB 192 Sn( Beta Release 2.1.0b10 \20131 January 2002\202)EH( +)UL( +)0 P()-1 LI( Added support for Mac OSX/Darwin to configure file. +)LU( + +)0 2 125 H()WB 193 Sn( Beta Release 2.1.0b9 \20126 January 2002\202)EH( +)UL( +)0 P()-1 LI( Fixed bug in client library that caused XPAAccess\201\202 call to hang. +)LU( + +)0 2 126 H()WB 194 Sn( Beta Release 2.1.0b8 \2014 January 2002\202)EH( +)UL( +)0 P()-1 LI( Made modifications to Makefile.in to make releases easier. + +)0 P()-1 LI( Added instructions to Makefile.in so that xpa.h will always have +correct #defines for XPA_VERSION, XPA_MAJOR_VERSION, XPA_MINOR_VERSION, +and XPA_PATCH_LEVEL. +)LU( + +)0 2 127 H()WB 195 Sn( Beta Release 2.1.0b7 \20121 December 2001\202)EH( +)UL( +)0 P()-1 LI( Added -proxy switch to -remote sub-command to allow remote access +through a firewall, using xpans as a proxy server. The support for proxy +processing required a change to the client/server protocol. This means +that new xpa servers will not work with old xpa clients \201although new +xpa clients will work with old xpa servers\202. For details about proxy +firewall support, see http://hea-www.harvard.edu/RD/xpa/inet.html. + +)0 P()-1 LI( Fixed Tcl support for XPA under Windows/Cygwin by re-writing +the code used to add XPA to the Tcl event loop. This fix makes ds9 +support for XPA much more stable under Windows. + +)0 P()-1 LI( Added the shutdown\201\202 call to XPA under Cygwin/Windows before +closing send\201\202 sockets. It appears that a Cygwin recv\201\202 socket call +does not always sense when the other end closes the socket using +close\201\202. This measure must be considered a hack, since the actual +problem was never resolved. + +)0 P()-1 LI( Added code to protect accept\201\202 and select\201\202 calls from interrupts. + +)0 P()-1 LI( Extended syntax of the environment variable XPA_NSINET to: +) 1 43 PR( setenv XPA_NSINET host:port[,port[,port]])RP( +to allow specification of the XPA access point port for xpans, +as well as the proxy data port. + +)0 P()-1 LI( Modified xpans log file so that it contains the xpaset commands +required to reconnect with xpa servers. + +)0 P()-1 LI( xpans now deletes its Unix socket files. +)LU( + +)0 2 128 H()WB 196 Sn( Beta Release 2.1.0b6 \20129 October 2001\202)EH( +)UL( +)0 P()-1 LI( Implemented a reserve public access point named -clipboard so +that clients can store ASCII state information on any number of named +clipboards. Clipboards of the same name created by clients on +different machines are kept separate. The syntax for creating a +clipboard is: +) 3 65 PR( [data] | xpaset [server] -clipboard add|append [clipboard_name] + xpaset -p [server] -clipboard delete [clipboard_name] + xpaget [server] -clipboard [clipboard_name])RP( +Use "add" to create a new clipboard or replace the contents of an existing +one. Use "append" to append to an existing clipboard. +)LU( + +)0 2 129 H()WB 197 Sn( Beta Release 2.1.0b5 \20122 October 2001\202)EH( +)UL( +)0 P()-1 LI( Use FD_SETSIZE instead of getdtablesize\201\202 to determine how many files +to check during select\201\202; + +)0 P()-1 LI( Under Cygwin, the launch\201\202 routine now uses the Cygwin spawnvp\201\202 +instead of fork\201\202/exec\201\202 where possible \201i.e., if no stdfiles are +being redirected\202. This is recommended by Cygwin's \201skimpy\202 on-line +documentation and seems to fix the problems ds9 had when starting xpans +automatically. + +)0 P()-1 LI( Added error check to select\201\202 call in xpans. +)LU( + +)0 2 130 H()WB 198 Sn( Beta Release 2.1.0b4 \20124 September 2001\202)EH( +)UL( +)0 P()-1 LI( The launch\201\202 now can return an error code if the execv\201\202 system +call fails \201something system\201\202 does not do\202. + +)0 P()-1 LI( INET socket calls between xpa clients and servers now will use +localhost if they are on the same machine. This protects against +Linux systems where the hostname is hardwired \201wrongly\202 in a DHCP +environment. +)LU( + +)0 2 131 H()WB 199 Sn( Beta Release 2.1.0b3 \2016 September 2001\202)EH( +)UL( +)0 P()-1 LI( Modified xpans so that, in the case of a firewall, it tries to +correct the specified ip:port by matching against the ip found in +the socket packet at accept\201\202 time. + +)0 P()-1 LI( Replaced system\201\202 call used to start xpans automatically with +a special launch\201\202 call, which performs execvp\201\202 directly without going +through sh. \201launch\201\202 works under DOS and has fewer security problems.\202 + +)0 P()-1 LI( Fixed bug in xpans in which its xpa port was always being set to 14286. +)LU( + +)0 2 132 H()WB 200 Sn( Beta Release 2.1.0b2 \20117 August 2001\202)EH( +)UL( +)0 P()-1 LI(Added support for -remote command, which registers the access +point in the XPA name server of the specified remote server, and gives +the remote server access rights to the access point. This is used, for +example, to give data servers xpa access to ds9 so that data can be +sent to ds9 as a result of a CGI-based Web query. + +)0 P()-1 LI(Reserved commands \201except "-help" and "-version"\202 now can only be +executed on the machine on which the xpa service is running \201not +through -remote servers\202. + +)0 P()-1 LI(Fixed bug in xpans in which a bad telnet command could hang the program. + +)0 P()-1 LI(Added -s [security file] to xpans to allow logging of all external +connections. +)LU( + +)0 2 133 H()WB 201 Sn( Beta Release 2.1.0b1 \2016 August 2001\202)EH( +)UL()0 P()-1 LI( The xpaaccess client program and XPAAccess\201\202 client subroutine +were modified so that an access-type query can directly contact the +xpa servers matching the requested xpa template, instead of just +querying the name server for registered access points. This avoid the +race condition in which an access point is registered but is not yet +available, perhaps because the server has not yet entered its event +loop. Note that the calling sequence of the XPAAccess\201\202 routine was +changed to return all matching access points and their availability +status \201instead of just returning the number of registered access +points\202. Because of this, we are calling this a minor release instead +of a patch. + +)0 P()-1 LI( Added support for XPA_PORT and XPA_PORTFILE environment variables +to allow specification of the port to be used by the command channel +\201and data channel, if an optional second port is specified\202 for a given +access point. + +)0 P()-1 LI( Added -m switch to xpaget, xpaset, xpainfo, xpaaccess to allow +override of the XPA_METHOD environment variable. + +)0 P()-1 LI( Changed the default name of the ACL file from xpa.acl to acls.xpa. + +)0 P()-1 LI( Fixed bug in which it was not possible to send a "set ACL" +command to an XPA server which did not have a receive callback \201i.e., +did not allow xpaset\202. The xpans program is one such server. It now is +possible to set the ACL on xpans. + +)0 P()-1 LI( We have discovered that Tcl support for datachan and cmdchan is +broken under Windows due to an unexplained incompatibility between +Cygwin sockets and Win32 sockets. We therefore have removed datachan +and cmdchan from the Windows/Tcl support until further notice. + +)0 P()-1 LI( Extended the behavior of the XPA_DEFACL environment variable so that +it can support more than one acl, using a list of semi-colon delimited +controls such as: setenv XPA_DEFACL '*:* $host +; *:foo1 otherhost +'. + +)0 P()-1 LI( Fixed bug in which the class:name specifier "*:*" was erroneously +trying to access the xpans name server, instead of accessing all +access points. + +)0 P()-1 LI( Support TMPDIR and TMP environment variables as well as XPA_TMPDIR. +)LU( + +)0 2 134 H()WB 202 Sn( Patch Release 2.0.5 \20110 November 2000\202)EH( +)UL()0 P()-1 LI( Added support for Tcl on Windows where there is no select\201\202-based +event loop \201i.e., where there is no Tcl_CreateFileHandler call in Tcl\202 +)0 P()-1 LI( Minor fixes in Makefile for installing on Windows +)0 P()-1 LI( Minor compiler fixes from gcc -Wall.)LU( + +)0 2 135 H()WB 203 Sn( Patch Release 2.0.4 \20120 September 2000\202 )EH( +)UL()0 P()-1 LI( Removed extraneous include of varargs.h from find.c. +)0 P()-1 LI( Ported to SGI C compiler, which caught lots of unused variables, etc. +)0 P()-1 LI( Ported to Cygwin/Windows, which required that we change socket read\201\202 +and write\201\202 calls to recv\201\202 and send\201\202 respectively. Also had to ensure that +we only did socket I/O on sockets \201no fileio\202.)LU( + +)0 2 136 H()WB 204 Sn( Patch Release 2.0.3 \20115 June 2000\202 )EH( +)UL( +)0 P()-1 LI( Fixed the client XPASet\201\202 and XPASetFd\201\202 calls to handle the specified +max number of connections \201they were ignoring this argument, leading to +memory overwrites\202. +)0 P()-1 LI( Fixed Makefile.in so that CFLAGS and LDFLAGS are not hard-wired values. +)0 P()-1 LI( Fixed word.h to load malloc.h and stdlib.h only if they exist. +)0 P()-1 LI( Documentation fixes to programs.html \201in xpaaccess\202 and client.html +\201XPANSLookup\202. +)0 P()-1 LI( Added explicit typecast to strlen\201\202 argument to MAX #define in +XPAClientStart \201strlen\201\202 is unsigned in Linux, which can break MAX\202. +)0 P()-1 LI( Removed bogus Imakefile from directory. +)0 P()-1 LI( Changed directory name to include patch level \201i.e., xpa-2.0.3\202.)LU( + +)0 2 137 H()WB 205 Sn( Patch Release 2.0.2 \2019 September 1999\202)EH( +)UL( +)0 P()-1 LI( Fixed server mode \201-s\202 in the xpaset program by properly cleaning up +the input buffers \201sending commands and data in server mode was broken\202.)LU( + +)0 2 138 H()WB 206 Sn( Patch Release 2.0.1 \2016 August 1999\202)EH( +)UL( +)0 P()-1 LI( Fixed the Tcl binding code \201tcl.c\202 for 64-bit machines \201Dec Alpha\202 +\201erroneously used %x instead of %p when converting pointers to ASCII\202. +)0 P()-1 LI( Got rid of a few compiler warnings on 64-bit machines \201a few are +unavoidable since we must cast int to void * and back when passing around +client data\202.)LU( + +)0 2 139 H()WB 207 Sn( Public Release 2.0 \20127 May 1999\202)EH( +)UL( +)0 P()-1 LI( "a new day with no mistakes ... yet")LU( + +)2 1 1 HR()0 P()0 0 1 A(Index to the XPA Help Pages)0 0 TN TL()Ec /AF f D( + +)2 1 1 HR()0 5 140 H(Last)WB 208 Sn( updated: 22 April 2002)EH( +)WB NL +/Cb Db D /Ct [16#00 16#00 16#00] D /Cl [16#00 16#00 16#00] D /CL -1 D Ct Sc +DS +/Ba f D /BO 0 D Bs +/UR (examples.html) D +/Ti (Where to Find Example/Test Code) D +/Au () D +/Df f D +/ME [()] D + +0 BO R +()1 Sl()WB 43 Sn( + + +)0 2 141 H(XPACode:)WB 210 Sn()WB 209 Sn( Where to Find Example/Test Code)EA()EH( + + +)0 2 142 H(Summary)WB 211 Sn()EH( +)0 P(The XPA source code directory contains two test programs, +)EM(stest.c)ES(, and )EM(ctest.c)ES( that can serve as +examples for writing XPA servers and clients, respectively. +They also can be used to test various features of XPA. + + +)0 2 143 H(Description)WB 212 Sn()EH( +)0 P(To build the XPA test programs, execute: +) 1 11 PR( make All)RP( +in the XPA source directory to generate the )EM(stest)ES( and +)EM(ctest)ES( programs. \201NB: this should work on all platforms, +although we have had problems with unresolved externals on one +Sun/Solaris machine, for reasons still unknown.\202 +)0 P(The stest program can be executed with no arguments to start +an XPA server that contains the access points: xpa, xpa1, +c_xpa \201containing sub-commands cmd1 and cmd2\202, and i_xpa. +You then can use xpaset and xpaget to interact with these access points: +) 4 57 PR( cat xpa.c | xpaset xpa # send to xpa + cat xpa.c | xpaset "xpa*" # send to xpa and xpa1 + xpaget xpa # receive from xpa + xpaget xpa* # receive from xpa and xpa1)RP( +etc. You also can use ctest to do the same thing, or to iterate: +) 4 66 PR( ctest -s -l 100 xpa # send to xpa 100 times + ctest -s -l 100 "xpa*" # send to xpa and xpa1 100 times + ctest -g -l 100 xpa # receive from xpa 100 times + ctest -g -l 100 "xpa*" # receive from xpa and xpa1 100 times)RP( +More options are available: see the stest.c and ctest.c code itself, which +were used extensively to debug XPA. + +)0 P(The file test.tcl in the XPA source directory gives examples for using the +)0 39 1 A(XPATcl)39 0 TN TL()Ec /AF f D(Interface. + + + + + +)0 P()0 0 1 A(Go to XPA Help Index)0 0 TN TL()Ec /AF f D( + +)0 5 144 H(Last)WB 213 Sn( updated: September 10, 2003)EH( +)WB NL +/Cb Db D /Ct [16#00 16#00 16#00] D /Cl [16#00 16#00 16#00] D /CL -1 D Ct Sc +DS +/Ba f D /BO 0 D Bs +/UR (changes.html) D +/Ti (Changes For Users from XPA 1.0 and 2.0) D +/Au () D +/Df f D +/ME [()] D + +0 BO R +()1 Sl()WB 44 Sn( + + +)0 2 145 H(XPA)WB 215 Sn()WB 214 Sn( Changes: Changes For Users from XPA 1.0 and 2.0)EA()EH( + + +)0 2 146 H(Summary)WB 216 Sn()EH( +)0 P(This document describes changes that will affect users who migrate +from XPA 1.0 to XPA 2.0. + + +)0 2 147 H(Description)WB 217 Sn()EH( +)0 P(There have been a few changes that affect users who upgrade XPA +from version 1.0 to version 2.0. These changes are detailed below. +)UL()0 P()-1 LI(XPA commands no longer have a resolver routine \201this is open to +negotiations, but we decided the idea was dumb\202. For the SAOtng +program, this means that you must explicitly specify the access +point, i.e.,: +) 1 35 PR( cat foo.fits | xpaset SAOtng fits)RP( + +)0 P(instead of: +) 1 30 PR( cat foo.fits | xpaset SAOtng)RP( +)0 P()-1 LI(By default, xpaset, xpaget, etc. now wait for the server callback to +complete; i.e., the old -W is implied \201and the switch is ignored\202. +This allows support for better error handling. If you want xpaset, etc. +to return before the callback is complete, use -n switch: +) 1 41 PR( echo "file foo.fits" | xpaset -n SAOtng)RP( +)0 P()-1 LI(The old -w switch in xpaset and xpaget is no longer necessary \201and is +ignored\202, since you can have more than one process communicating with +an xpa access point at one time. + +)0 P()-1 LI(The new -p switch on xpaset means you need not read from stdout: +) 2 30 PR( + xpaset -p SAOtng colormap I8)RP( +)0 P(will send the paramlist to the SAOtng callback without reading from stdin. +)LU( + + + + + +)0 P()0 0 1 A(Go to XPA Help Index)0 0 TN TL()Ec /AF f D( + +)0 5 148 H(Last)WB 218 Sn( updated: September 10, 2003)EH( +)WB NL +/Cb Db D /Ct [16#00 16#00 16#00] D /Cl [16#00 16#00 16#00] D /CL -1 D Ct Sc +DS +/Ba f D /BO 0 D Bs +/UR (convert.html) D +/Ti (Converting the XPA API to 2.0) D +/Au () D +/Df f D +/ME [()] D + +0 BO R +()1 Sl()WB 45 Sn( + + +)0 2 149 H(XPAConvert:)WB 220 Sn()WB 219 Sn( Converting the XPA API to 2.0)EA()EH( + + +)0 2 150 H(Summary)WB 221 Sn()EH( +)0 P(This document describes tips for converting from xpa 1.0 \201Xt-based +xpa\202 to xpa 2.0 \201socket-based xpa\202. + + +)0 2 151 H(Description)WB 222 Sn()EH( +)0 P(The following are tips for converting from xpa 1.0 \201Xt-based xpa\202 to +xpa 2.0 \201socket-based xpa\202. The changes are straight-forward and +almost can be done automatically \201we used editor macros for most of +the conversion\202. +)UL()0 P()-1 LI(The existence of the cpp XPA_VERSION directive to distinguish between 1.0 +\201where it is not defined\202 and 2.0 \201where it is defined\202. + +)0 P()-1 LI(Remove the first widget argument from all send and receive server +callbacks. Also change first 2 arguments from XtPointer to void +*. For example: +) 16 74 PR(#ifdef XPA_VERSION +static void XPAReceiveFile\201client_data, call_data, paramlist, buf, len\202 + void *client_data; + void *call_data; + char *paramlist; + char *buf; + int len; +#else +static void XPAReceiveFile\201w, client_data, call_data, paramlist, buf, len\202 + Widget w; + XtPointer client_data; + XtPointer call_data; + char *paramlist; + char *buf; + int len; +#endif)RP( +)0 P()-1 LI(Server callbacks should be declared as returning int instead +of void. They now should return 0 for no errors, -1 for error. + +)0 P()-1 LI( The mode flags have changed when defining XPA server callbacks. +The old )EM(S)ES( flag \201save buffer\202 is replaced by )EM(freebuf=false)ES(. +The old )EM(E)ES( flag \201empty buffer is OK\202 is no longer used \201it +was an artifact of the X implementation\202. + +)0 P()-1 LI(Change NewXPACommand\201\202 to XPAcmdNew\201\202, with the new calling sequence: +) 1 52 PR( xpa = NewXPACommand\201toplevel, NULL, prefix, NULL\202;)RP( +is changed to: +) 1 32 PR( xpa = XPACmdNew\201xclass, name\202;)RP( +)0 P()-1 LI(Change the AddXPACommand\201\202 subroutine name to XPACmdAdd \201with the same +calling sequence\202: +) 3 53 PR( AddXPACommand\201xpa, "file", + "\200tdisplay a new file\200n\200t\200t requires: filename", + NULL, NULL, NULL, XPAReceiveFile, text, NULL\202;)RP( +is changed to: +) 3 53 PR( XPACmdAdd\201xpa, "file", + "\200tdisplay a new file\200n\200t\200t requires: filename", + NULL, NULL, NULL, XPAReceiveFile, text, NULL\202;)RP( +)0 P()-1 LI(The XPAXtAppInput\201\202 routine should be called just before XtAppMainLoop\201\202 +to add xpa fds to the Xt event loop: +) 5 35 PR( /* add the xpas to the Xt loop */ + XPAXtAddInput\201app, NULL\202; + + /* process events */ + XtAppMainLoop\201app\202;)RP( +)0 P()-1 LI(Change NewXPA\201\202 to XPANew\201\202 and call XPAXtAddInput\201\202 if the XtAppMainLoop +routine already has been entered: +) 4 71 PR( xpa = NewXPA\201saotng->xim->toplevel, prefix, xparoot, + "FITS data or image filename\200n\200t\200t options: file type", + XPASendData, new, NULL, + XPAReceiveData, new, "SE"\202;)RP( +is changed to: +) 6 74 PR( sprintf\201tbuf, "%s.%s", prefix, xparoot\202; + xpa = XPANew\201"SAOTNG", tbuf, + "FITS data or image filename\200n\200t\200t options: file type", + XPASendData, new, NULL, + XPAReceiveData, new, "SE"\202; + XPAXtAddInput\201XtWidgetToApplicationContext\201saotng->xim->toplevel\202, xpa\202;)RP( +)0 P()-1 LI(Change XPAInternalReceiveCommand\201\202 to XPACmdInternalReceive\201\202 +remove first argument in the calling sequence\202: +) 3 61 PR( XPAInternalReceiveCommand\201im->saotng->xim->toplevel, + im->saotng, im->saotng->commands, + "zoom reset", NULL, 0\202;)RP( +is changed to: +) 2 57 PR( XPACmdInternalReceive\201im->saotng, im->saotng->commands, + "zoom reset", NULL, 0\202;)RP( +)0 P()-1 LI(Change DestroyXPA to XPAFree: +) 1 26 PR( DestroyXPA\201im->dataxpa\202;)RP( +is changed to: +) 1 23 PR( XPAFree\201im->dataxpa\202;)RP()LU( + + + + + +)0 P()0 0 1 A(Go to XPA Help Index)0 0 TN TL()Ec /AF f D( + +)0 5 152 H(Last)WB 223 Sn( updated: September 10, 2003)EH( + +)WB NL +/Cb Db D /Ct [16#00 16#00 16#00] D /Cl [16#00 16#00 16#00] D /CL -1 D Ct Sc +DS +/Ba f D /BO 0 D Bs +/UR (name.html) D +/Ti (What does XPA stand for?) D +/Au () D +/Df f D +/ME [()] D + +0 BO R +()1 Sl()WB 46 Sn( + + +)0 2 153 H(XPAName:)WB 225 Sn()WB 224 Sn( What does XPA stand for?)EA()EH( + + +)0 2 154 H(Summary)WB 226 Sn()EH( +)0 P(What does XPA stand for? Who knows anymore! + + +)0 2 155 H(Description)WB 227 Sn()EH( +)0 P(What does XPA stand for? Dunno! The XPA messaging system originally +was built on top of the X Window System and XPA was the mnemonic for +)EM(X Public Access)ES(, to emphasize that we were providing public +access to previously private data and algorithms in Xt programs. Now +that XPA no longer is tied to X, it can be argued that we ought to +change the name \201how about )EM(SPAM: simple public access mechanism)ES(\202, but XPA is in wide-spread use in the astronomical community of +its birth, and the name has taken on a life of its own. If anyone can +think of what XPA now means, please let us know. + +)0 P(If you think this is bad, consider the MMT Telescope on Mount Hopkins, +Arizona. When first installed twenty years ago, it featured an array +of six 72-inch diameter mirrors. from which came its name: the +)EM(Multiple Mirror Telescope)ES(. In spring of 1999, these mirrors +were replaced by a single 21 and 1/2 -foot diameter primary mirror, +the largest single-piece glass reflector on the North American +continent. And now MMT stands for ... MMT! + + + + + +)0 P()0 0 1 A(Go to XPA Help Index)0 0 TN TL()Ec /AF f D( + +)0 5 156 H(Last)WB 228 Sn( updated: September 10, 2003)EH( + +)WB NL +/TE t D NP TU PM 0 eq and{/Pn () D showpage}if end restore diff --git a/xpa/doc/xpamb.html b/xpa/doc/xpamb.html new file mode 100644 index 0000000..79e46e9 --- /dev/null +++ b/xpa/doc/xpamb.html @@ -0,0 +1,197 @@ +<!-- =defdoc xpamb xpamb 1 --> +<HTML> +<HEAD> +<TITLE>The XPA Message Bus (xpamb)</TITLE> +</HEAD> +<BODY> + +<!-- =section xpamb NAME --> +<H2><A NAME="xpamb">xpamb: the XPA Message Bus</A></H2> + +<!-- =section xpamb SYNOPSIS --> +<H2>Summary</H2> +<P> +The xpamb program can act as a "classical" message bus interface +between clients and servers. A client can send a data request to +the message bus, which then interfaces with multiple servers and +returns the data back to the client. + +<!-- =section xpamb DESCRIPTION --> +<H2>Description</H2> +<P> +A "classical" message bus (such as ToolTalk) consists of servers and +clients, along with a mediating program that transfers data between +different processes. XPA takes a slightly different approach in that +communication between clients and servers is direct. This generally +is the correct technique when there is only one connection (or even a +small number of connections), but can become inefficient for the +serving program if a large amount of data is being transferred to many +clients. For example, if a real-time data acquisition program is +broadcasting a FITS image to several clients, it would need to +transmit that image to each client individually. This might interfere +with its own processing cycles. The preferable mechanism would be to +pass the image off to an intermediate program that can then broadcast +the data to the several clients. +<P> +The <B>xpamb</B> program can alleviate such problems by functioning +as a message bus in cases where such an intermediary process is +wanted. It pre-defines a single access point named +<B>XPAMB:xpamb</B> to which data can be sent for re-broadcast. You +also can tell <B>xpamb</B> to save the data, and associate with that +data a new access point, so that it can be retrieved later on. + +<P> +All interaction with <B>xpamb</B> is performed through +<B>xpaset</B> and <B>xpaget</B> (or the corresponding API +routines, <B>XPASet()</B> and <B>XPAGet()</B>) to the +<B>XPAMB:xpamb</B> access point. That is, <B>xpamb</B> is just +another XPA-enabled program that responds to requests from +clients. The paramlist is used to specify the targets to which +the data will be for re-broadcast, as well as the re-broadcast paramlist: +<PRE> + data | xpaset xpamb [switches] broadcast-target broadcast-paramlist +</PRE> +Optional switches are used to store data, and manipulate stored data, +and are described below. + +<P> +In its simplest form, you can, for example, send a FITS image to xpamb for +broadcasting to all ds9 image simply by executing: +<PRE> + cat foo.fits | xpaset xpamb "DS9:*" fits foo.fits +</PRE> +Since <B>DS9</B> is the class name for the ds9 image display +program, this will result in the FITS image being re-sent to all fits +access points for all active image display programs. + +<P> +You can send stored data and new data to the same set of access points at +the same time. The stored data always is send first, followed by the new +data: +<PRE> + cat foo2.fits | xpaset xpamb -send foo "DS9:*" fits foo.fits +</PRE> +will first send the foo.fits file, and then the foo2.fits file to all +access points of class <B>DS9</B>. Notice that in this example, +the foo2.fits file is not stored, but it could be stored by using the +<B>-store [name]</B> switch on the command line. + +<P> +The <B>xpaget</B> command can be used to retrieve a data from XPA +access points or from a stored data buffer, or retrieve information +about a stored data buffer. If no arguments are given: +<PRE> + xpaget xpamb +</PRE> +then information about all currently stored data buffers is returned. This +information includes the data and time at which the data was stored, the +size in bytes of the data, and the supplied info string. + +<P> +If arguments are specified, they will be in the form: +<PRE> + xpaget xpamb [-info] [-data] [name [paramlist]] +</PRE> +If the optional <B>-info</B> and/or <B>-data</B> switches are specified, then +information and/or data will be returned for the named data buffer +following the switches. You can use either or both of these switches +in a single command. For example, if the -info switch is used: +<PRE> + xpaget xpamb -info foo +</PRE> +then the info about that stored data buffer will be returned. +If the -data is used with a specific name: +<PRE> + xpaget xpamb -data foo +</PRE> +then the stored data itself will be returned. If both are used: +<PRE> + xpaget xpamb -info -data foo +</PRE> +then the info will be returned, followed by the data. Note that it is an +error to specify one of these switches without a data buffer name and that +the paramlist will be ignored. + +<P> +If neither the <B>-info</B> or <B>-data</B> switch is specified, then +the name refers to an XPA access point (with an optional paramlist +following). +For example: +<PRE> + xpaget xpamb ds9 file +</PRE> +is equivalent to: +<PRE> + xpaget ds9 file +</PRE> + +<!-- =section xpamb OPTIONS --> +<H2>Options</H2> +<P> +For xpaset, several optional switches are used to save data and +manipulate the stored data: +<DL> + +<P> +<DT><B>-data [name]</B> +<DD> Add the supplied data buffer to a pool of stored data buffers, +using the specified name as a unique identifier for later retrieval. +An error occurs if the name already exists (use either <B>replace</B> +or <B>del</B> to rectify this). The <B>-add</B> switch is supported +for backwards compatibility with xpa 2.0. + +<P> +<DT><B>-replace [name]</B> +<DD> Replace previously existing stored data having the same unique name +with new data. This essentially is a combination of the <B>del</B> +and <B>data</B> commands. + +<P> +<DT><B>-info ["'info string'"]</B> +<DD> When adding a data buffer, you can specify an informational +string to be stored with that data. This string will be returned +by xpaget: +<PRE> + xpaget xpamb foo -info +</PRE> +(along with other information such as the date/time of storage and the size of +the data buffer) if the -info switch is specified. If the info string contains +spaces, you must enclose it in <B>two</B> sets of quotes: +<PRE> + cat foo | xpaset xpamb -store foo -info "'this is info on foo'" +</PRE> +The first set of quotes is removed by the shell while the second is used to +delineate the info string. + +<P> +<DT><B>-send [name]</B> +<DD> Broadcast the stored data buffer to the named template. + +<P> +<DT><B>-del [name]</B> +<DD> Delete the named data buffer and free all allocated space. +</DL> + +<P> +Switches can be used in any combination that makes sense. For example: +<PRE> + cat foo.fits | xpaset xpamb -store foo -info "FITS" "DS9:*" fits foo.fits +</PRE> +will broadcast the foo.fits image to all access points of class +<B>DS9</B>. In addition, the foo.fits file will be stored under the +name of <B>foo</B> for later manipulation such as: +<PRE> + xpaset -p xpamb -send foo "DS9:*" fits foo.fits +</PRE> +will re-broadcast the foo.fits image to all access points of class "DS9". + +<!-- =section xpamb SEE ALSO --> +<!-- =text See xpa(n) for a list of XPA help pages --> +<!-- =stop --> + +<P> +<A HREF="./help.html">Go to XPA Help Index</A> + +<H5>Last updated: September 10, 2003</H5> +</BODY> +</HTML> diff --git a/xpa/doc/xpans.html b/xpa/doc/xpans.html new file mode 100644 index 0000000..a0aebb2 --- /dev/null +++ b/xpa/doc/xpans.html @@ -0,0 +1,212 @@ +<!-- =defdoc xpans xpans 1 --> +<HTML> +<HEAD> +<TITLE>The XPA Name Server (xpans)</TITLE> +</HEAD> +<BODY> + +<!-- =section xpans NAME --> +<H2><A NAME="xpans">xpans: the XPA Name Server</A></H2> + +<!-- =section xpans SYNOPSIS --> +<H2>Summary</H2> +<PRE> + xpans [-h] [-e] [-k sec] [-p port] [-l log] [-s security log] [-P n] +</PRE> + +<!-- =section xpans OPTIONS --> +<P> +<PRE> + -h print help message + -e exit when there are no more XPA connections + -k send keepalive messages every n sec + -l log data base entries to specified file + -p listen for connections on specified port + -s log security info for each connection to specified file + -P accept proxy requests (P=1) using separate thread (P=2) + --version display version and exit +</PRE> + +<!-- =section xpans DESCRIPTION --> +<P> +The xpans name server is an XPA-enabled program that is used to +manage the names and ports of XPA access points. It is started +automatically when an XPA access point is registered. You can access +the name server using xpaget to get a list of registered access points. +<P> +The <EM>xpans</EM> name server provides a crucial link between XPA +clients and servers. When an XPA server defines an access point using +XPANew(), XPACmdNew(), or XPAInfoNew(), the name of the access point +is registered in the name service, along with connection information. +The name server then matches class:name templates passed to it by XPA +clients with these registered entries, so that the clients can +communicate with the appropriate servers. + +<P> +The socket connection between an XPA-enabled program and +<EM>xpans</EM> is kept open until the former exits (or explicitly +closes the connection). Apparently, some Internet equipment (e.g. DSL +modems) can cause such a connection to time-out after a period of +inactivity. To prevent this from happening, you can use the <EM>-k +[sec]</EM> switch to send a short keep-alive message to each open +connection after the specified time delay. (Note that this +application level use of keep-alive is necessary only if you are +serving XPA-enabled clients over the Internet and have to deal with +long-term connections involving DSL or similar equipment. XPA uses +the ordinary socket-level keep-alive, which works for all other cases.) +<B>NB (12/2/2009): Out-of-band (URG) TCP data, used by xpans +keep-alive, is changed by some Cisco routers into in-band data. +Encountering such a router will break the keep-alive function and may +break your XPA server as well. Proceed with caution!</B> + +<P> +The <EM>xpans</EM> program will be started automatically (assuming it +can be found in the user's path) when the first XPA access point is +registered. It therefore need not be started explicitly. However, +when started automatically, the <EM>-e</EM> switch is used, so that +the name server will exit when there are no more XPA access points +registered. If you wish to keep the name server running continually, +simply start it manually without the <EM>-e</EM> switch. + +<P> +The name server will keep a log of registered access points if the +<EM>-l [log]</EM> switch is used on the command line (this is the +case for automatic start-up). The log contains enough name and connection +information to allow you to re-register all XPA access points in case +the name server process is terminated prematurely. For example, after +the ds9 access point is registered,the log will contain the entry: +<PRE> + add 838e2f67:1863 ds9 ds9 gs eric +</PRE> +If <EM>xpans</EM> is terminated but ds9 still is running, you +can re-register both access points for the ds9 process by running: +<PRE> + xpaset -p 838e2f67:1863 -nsconnect +</PRE> +Notice that the ip:port specifier is used with <EM>xpaset</EM> to bypass +the need for contacting the name server (which does not have the name +registered yet!) + +<P> +The name server will keep a log of security information if the <EM>-s +[security log]</EM> switch is used on the command line. For each +accepted connection, (including connections via the <EM>xpaget</EM> +command), information will be logged about the host issuing the +command and the parameters passed into the program. This is most +useful when <EM>xpans</EM> is accepting connections from untrusted +machines. + +<P> +When an XPA access point is removed by a server using <EM>XPAFree()</EM>, +the access information is removed from the name server. If an +XPA-enabled process is terminated, all names registered by that process +will be removed automatically. The log file is always updated to +reflect the currently registered access points. + +<P> +The name server itself has an XPA access point names <EM>xpans</EM> +registered through which you can find out information about currently +registered access points (assuming you have access to the name server; +see <A HREF="./acl.html">XPA Access Control</A> for more information). +For each registered access point, the following information is returned: +<PRE> + class # class of the access point + name # name of the access point + access # allowed access (g=xpaget,s=xpaset,i=xpainfo) + id # socket access method (host:port for inet, file for local/unix) + user # user name of access point owner +</PRE> + +<P> +For example, to display all currently registered access points, simply execute: +<PRE> + xpaget xpans +</PRE> +Continuing the example of ds9 above, this will return: +<PRE> + DS9 ds9 gs 838e2f67:1863 eric +</PRE> +If the same program has been started with different XPA access names, +you can look up only names matching a specified template. For example, +assume that ds9 has been started up using: +<PRE> + ds9 & + ds9 -title ds9-1-eric & + ds9 -title ds9-2-eric & +</PRE> +To lookup all ds9 access points which end in ".eric" and which can +be accessed using <EM>xpaset</EM>, use: +<PRE> + xpaget xpans "DS9:*.eric" "s" "*" +</PRE> +This will return: +<PRE> + DS9 ds9-2-eric gs 838e29d3:42102 eric + DS9 ds9-1-eric gs 838e29d3:42105 eric +</PRE> +The third argument "*" requests all access points from all users. +You also can specify a specific user name and only access points +registered by that user will be returned. + +<P> +The name server uses the <EM>XPA_METHOD</EM> environment variable +to determine whether it should listen for requests on INET or LOCAL +sockets. Since XPA access points also use this environment variable, +the choice of socket method will be consistent. Note that, when INET +sockets are used, a local server can be accessed from remote machines +if the <EM>XPA_NSINET</EM> environment variable is set to point to +the local machine. See +<A HREF="./env.html">XPA Environment Variables</A> +for more information. + +<P> +An experimental feature of xpans is its ability to act as a proxy to +XPA servers behind firewalls that want to communicate with external +processes. The basic idea is the following: an XPA server (call it +"foo") on host1, possibly behind a firewall, makes a remote connection +to a proxy-enabled xpans program on host2 (specifying host2's XPA method). +For example: +<PRE> + xpaset -p foo -remote 'host2:28571' + -proxy # on host1 +</PRE> +When this is done, host2 can use xpaset, xpaget, and xpainfo calls to +communicate with the XPA server foo. All command communication is +performed via the xpans socket connection between foo on host1 and +xpans on host2 (which was initiated by foo from inside the firewall). +Data communication is similarly performed using a socket connection +initiated on host1 (usually with a port value two greater than the +port value of the main xpans socket connection). An xpaset or xpaget +call on host2 contacts xpans, which performs an XPASet() or XPAGet() +call to foo, passing commands and data back and forth between the two +programs. + +<P> +By default, proxy connections are not allowed by xpans. If the -P switch is +specified with a value of 1, proxy connection are allowed, but all proxy +communication is performed in the same thread as xpans processing. If +a value of 2 is specified, the proxy processing is performed in a +separate thread (assuming pthreads are supported on your system). +Because xpa callback processing of any type can take a long time and +therefore can interfere with normal xpans processing, threaded proxy +connections (-P 2) are recommended. When using proxy connections, it +might also be useful to set the XPA_IOCALLSXPA environment variable, so +that multiple proxy requests can be handled at the same time, instead of +serially. + +<P> +Note that this proxy interface to xpans is experimental. It is used +to provide remote data analysis capabilities on the Chandra-Ed system +using ds9. (See http://chandra-ed.cfa.harvard.edu and +http://hea-www.harvard.edu/saord/ds9 for more details). As always, please +contact us if you have problems or questions. + +<!-- =section xpans SEE ALSO --> +<!-- =text See xpa(n) for a list of XPA help pages --> +<!-- =stop --> + +<P> +<A HREF="./help.html">Go to XPA Help Index</A> + +<H5>Last updated: January 24, 2005</H5> +</BODY> +</HTML> diff --git a/xpa/doc/xt.html b/xpa/doc/xt.html new file mode 100644 index 0000000..2b68604 --- /dev/null +++ b/xpa/doc/xt.html @@ -0,0 +1,47 @@ +<!-- =defdoc xpaxt xpaxt n --> +<HTML> +<HEAD> +<TITLE>XPA/Xt Interface</TITLE> +</HEAD> +<BODY> + +<!-- =section xpaxt NAME --> +<H2><A NAME="xpatcl">XPAXt: the XPA Interface to Xt (X Windows)</A></H2> + +<!-- =section xpaxt SYNOPSIS --> +<H2>Summary</H2> +Describes how XPA access points can be added to X Toolkit (Xt) programs. + +<!-- =section xpaxt DESCRIPTION --> +<H2>Description</H2> +<P> +XPA supports Xt programs: you can call XPANew(), XPACmdNew(), or +XPAInfoNew() within any C routine to add XPA server callbacks to an Xt +program. Since an Xt program has its own event loop call (i.e., +XtAppMainLoop()), it therefore does not need or want to use the XPA +even loop. Thus, in order to add XPA access points to the standard Xt +event loop, the following routine should be called before entering the +loop: +<PRE> + int XPAXtAddInput(XtAppContext app, XPA xpa) +</PRE> +<P> +The XPAAddAddInput() routine will add XPA access points to the Xt event +loop by making calls to the standard XtAppAddInput() routine. (If the +XtAppContext argument is NULL, then the alternate XtAddInput() routine +is used instead.) If the xpa argument is NULL, then all active XPA +access points are added to the loop. If xpa is not NULL, then only +the specified access point is added. The latter type of call is used +to add new access points from within a callback, after the program has +entered the XtAppMainLoop() even loop. + +<!-- =section xpaxt SEE ALSO --> +<!-- =text See xpa(n) for a list of XPA help pages --> +<!-- =stop --> + +<P> +<A HREF="./help.html">Go to XPA Help Index</A> + +<H5>Last updated: September 10, 2003</H5> +</BODY> +</HTML> diff --git a/xpa/find.c b/xpa/find.c new file mode 100644 index 0000000..cf4d9ca --- /dev/null +++ b/xpa/find.c @@ -0,0 +1,456 @@ +/* + * Copyright (c) 1999-2003 Smithsonian Astrophysical Observatory + */ + +/* + * + * Find.c -- find files via the path environment variable + * (and related routines) + * + */ +#include <find.h> + +/* + * + * private routines + * + */ + +#define MAXBUFSIZE 8192 + +#ifndef HAVE_UNISTD_H +#define F_OK 0 /* does file exist */ +#define X_OK 1 /* is it executable by caller */ +#define W_OK 2 /* is it writable by caller */ +#define R_OK 4 /* is it readable by caller */ +#endif + +/* not part of unistd.h but we need to differentiate directories */ +#ifdef D_OK +#undef D_OK +#endif +#define D_OK 256 /* is it a directory */ + +#ifdef ANSI_FUNC +static int +amparse (char *mode) +#else +static int amparse(mode) + char *mode; +#endif +{ + int xmode = 0; + + xmode |= ( strpbrk(mode, "r") != NULL ? R_OK : 0 ); + xmode |= ( strpbrk(mode, "w") != NULL ? W_OK : 0 ); + xmode |= ( strpbrk(mode, "x") != NULL ? X_OK : 0 ); + xmode |= ( strpbrk(mode, "f") != NULL ? F_OK : 0 ); + xmode |= ( strpbrk(mode, "d") != NULL ? D_OK : 0 ); + + return xmode; +} + +#ifdef ANSI_FUNC +static char * +findpath (char *name, char *mode, char *path) +#else +static char *findpath(name, mode, path) + char *name; + char *mode; + char *path; +#endif +{ + char pathbuff[MAXBUFSIZE]; + char namebuff[MAXBUFSIZE]; + char tempbuff[MAXBUFSIZE]; + char backmode[MAXBUFSIZE]; + char *here, *found; + int len; + int mark = 0; + int skip = strpbrk(mode, ">") != NULL; + int pick = strpbrk(mode, "<") != NULL; + + if ( skip && pick ) return NULL; + + if ( (path==NULL) || ( name[0] == '.' && name[1] == '/' ) || name[0] == '/' ) + return Access(name, mode); + + strncpy(pathbuff, path, MAXBUFSIZE-1); + pathbuff[MAXBUFSIZE-1] = '\0'; + path = pathbuff; + + if ( (here = strpbrk(pathbuff, ":;")) ) { + mark = *here; + *here++ = '\0'; + } + while ( path ) { + /* if there is an environment variable ... */ + if ( strchr(path, '$') ) { + /* exand it */ + ExpandEnv(path, tempbuff, MAXBUFSIZE); + /* make sure we could expand it (otherwise we get an infinite loop) */ + if( !strchr(tempbuff, '$') ){ + if ( (found = findpath(name, mode, tempbuff)) ) + return found; + } + } else { + if ( !skip ) { + if ( !strcmp(".", path) ) path[0] = '\0'; + + strncpy(namebuff, path, MAXBUFSIZE-1); + namebuff[MAXBUFSIZE-1] = '\0'; + len = strlen(namebuff); + if ( namebuff[0] && namebuff[len-1] != '/' ){ + if( (len+1) <= (MAXBUFSIZE-1) ){ + strcat(namebuff, "/"); + len++; + } + /* filename is too large, so we can't find it */ + else + return NULL; + } + if( len+strlen(name) <= MAXBUFSIZE-1 ) + strcat(namebuff, name); + /* filename is too large, so we can't find it */ + else + return NULL; + + if ( (found = Access(namebuff, mode)) ) + return found; + } + } + + if ( mark == ';' ) { + if ( skip ) { + skip = 0; + /* Knock down the skip mode to select all + * directories in path after the first ";" + */ + strncpy(backmode, mode, MAXBUFSIZE-1); + backmode[MAXBUFSIZE-1] = '\0'; + mode = backmode; + } + if ( pick ) return NULL; + } + + path = here; + if ( here && (here = strpbrk(here, ":;")) ) { + mark = *here; + *here++ = '\0'; + } + } + + return NULL; +} + + +/* + * + * public routines + * + */ + +/* + * + * ResolvePath -- resolve the path to remove . and .. entries + * + */ +#ifdef ANSI_FUNC +char * +ResolvePath (char *ibuf, char *obuf, int maxlen) +#else +char *ResolvePath(ibuf, obuf, maxlen) + char *ibuf; + char *obuf; + int maxlen; +#endif +{ + char path[MAXBUFSIZE]; + char *part[MAXBUFSIZE]; + char *tbuf; + int i, j; + int len; + int npart=0; + + /* if we have no path separators, we really don't have much to do! */ + if( strchr(ibuf, '/') == NULL ){ + strncpy(obuf, ibuf, maxlen-1); + obuf[maxlen-1] = '\0'; + return(obuf); + } + + /* if its just "/" or "/.", its easy */ + if( !strcmp(ibuf, "/") || !strcmp(ibuf, "/.") ){ + strncpy(obuf, "/", maxlen-1); + obuf[maxlen-1] = '\0'; + return(obuf); + } + + /* if we have a relative path to deal with, get current directory */ + if( (*ibuf == '.') || ( (strchr(ibuf, '/') != NULL) && (*ibuf != '/') ) ){ + getcwd(path, MAXBUFSIZE); + } + else{ + *path = '\0'; + } + + /* construct the total string we have to deal with */ + len = strlen(path) + strlen(ibuf) + 1; + tbuf = (char *)xmalloc(len+1); + if( *path ){ + strcpy(tbuf, path); + strcat(tbuf, "/"); + strcat(tbuf, ibuf); + } + else{ + strcpy(tbuf, ibuf); + } + + /* construct the parts array from this string, removing / characters + and null-terminating each part */ + for(i=0; i<len; i++){ + if( tbuf[i] == '/' ){ + tbuf[i] = '\0'; + /* skip adjacent slashes */ + if( tbuf[i+1] == '/' ) continue; + part[npart] = &tbuf[i+1]; + npart++; + } + } + + /* loop through the parts array and resolve the . and .. entries */ + for(i=0; i<npart; i++){ + /* for ".", just remove it */ + if( !strcmp(part[i], ".") ){ + part[i] = NULL; + } + /* for "..", also remove the previous part -- if possible */ + else if( !strcmp(part[i], "..") ){ + part[i] = NULL; + for(j=i-1; j>=0; j--){ + if( part[j] ){ + part[j] = NULL; + break; + } + } + } + } + + /* construct a new string from the remaining parts */ + *obuf = '\0'; + len = 0; + for(i=0; i<npart; i++){ + if( part[i] != NULL ){ + if( len+(int)strlen(part[i])+1 <= maxlen-1 ){ + strcat(obuf, "/"); + strcat(obuf, part[i]); + len += strlen(part[i])+1; + } + else{ + break; + } + } + } + + /* free up buffer space */ + if( tbuf ) free(tbuf); + + /* return the string */ + return(obuf); +} + +#ifdef ANSI_FUNC +void +ExpandEnv (char *name, char *envname, int maxlen) +#else +void ExpandEnv(name, envname, maxlen) + char *name; + char *envname; + int maxlen; +#endif +{ + char brace[2]; + char tbuf[MAXBUFSIZE]; + char *fullname=NULL; + char *mip; + char *ip; + char *s; + int len; + int i=0, j=0; + + /* allocate temp working buffer (so dest can be same as source) */ + if( !(fullname=(char *)xcalloc(maxlen, sizeof(char))) ) return; + + /* process each character */ + for(ip=name; *ip; ip++){ + /* if its not beginning of an env, just store and loop */ + if( *ip != '$' ){ + fullname[i++] = *ip; + fullname[i] = '\0'; + } + else{ + mip = ip; + /* skip past '$' */ + ip++; + /* skip past brace, if necessary */ + if( *ip == '{' ){ + brace[0] = '{'; + ip++; + } + else if( *ip == '(' ){ + brace[0] = '('; + ip++; + } + else + brace[0] = '\0'; + /* get variable up to next white space */ + for(*tbuf='\0', j=0; + (!isspace((int)*ip)) && (*ip != '"') && (*ip != '\'') && (*ip); + ip++){ + /* look for trailing brace, if necessary */ + if( *brace && *ip == (*brace == '(' ? ')' : '}') ){ + ip++; + break; + } + /* a "/" will end the environment variable as well */ + if( *ip == '/' ){ + break; + } + tbuf[j++] = *ip; + tbuf[j] = '\0'; + } + /* back up so we can process the white space in the outer loop */ + ip--; + if( (s = (char *)getenv(tbuf)) != NULL ){ + i += strlen(s); + if( i <= maxlen ) + strcat(fullname, s); + } + /* if we don't recognize this macro, put it back onto the string */ + else{ + len = ip - mip + 1; + i += len; + if( i <= maxlen ) + strncat(fullname, mip, len); + } + } + } + + /* transfer to output buffer */ + strncpy(envname, fullname, maxlen); + + /* free up temp space */ + if( fullname ) xfree(fullname); +} + +#ifdef ANSI_FUNC +char * +Access (char *name, char *mode) +#else +char *Access (name, mode) + char *name; + char *mode; +#endif +{ + struct stat info; + char fullname[MAXBUFSIZE]; + char AccessName[MAXBUFSIZE]; + + + ExpandEnv(name, fullname, MAXBUFSIZE); + if ( stat(fullname, &info) !=0 ) return NULL; + +#if HAVE_MINGW32==0 && HAVE_CYGWIN==0 + if ( mode ) { + int m = amparse(mode); + + /* distinguish between directories and files */ + if ( (m & D_OK) && !(info.st_mode & S_IFDIR) ) return NULL; + if ( !(m & D_OK) && (info.st_mode & S_IFDIR) ) return NULL; + + if ( getuid() == info.st_uid ) { + if ( m & R_OK && !(info.st_mode & S_IRUSR) ) return NULL; + if ( m & W_OK && !(info.st_mode & S_IWUSR) ) return NULL; + if ( m & X_OK && !(info.st_mode & S_IXUSR) ) return NULL; + } else + if ( getgid() == info.st_gid ) { + if ( m & R_OK && !(info.st_mode & S_IRGRP) ) return NULL; + if ( m & W_OK && !(info.st_mode & S_IWGRP) ) return NULL; + if ( m & X_OK && !(info.st_mode & S_IXGRP) ) return NULL; + } else { + if ( m & R_OK && !(info.st_mode & S_IROTH) ) return NULL; + if ( m & W_OK && !(info.st_mode & S_IWOTH) ) return NULL; + if ( m & X_OK && !(info.st_mode & S_IXOTH) ) return NULL; + } + } +#endif + + ResolvePath(fullname, AccessName, MAXBUFSIZE); + return(xstrdup(AccessName)); +} + +#ifdef ANSI_FUNC +char * +Find (char *name, char *mode, char *exten, char *path) +#else +char *Find (name, mode, exten, path) + char *name; + char *mode; + char *exten; + char *path; +#endif +{ + char extenbuff[MAXBUFSIZE]; + char namebuff[MAXBUFSIZE]; + char *here, *found; + int len; + + /* sanity check */ + if( !name || !*name ) + return NULL; + + /* if its a WWW file, we just say 'yes' */ + if( !strncmp(name, "ftp://", 6) || + !strncmp(name, "http://", 7) ){ + return(xstrdup(name)); + } + + if ( exten == NULL ) + return findpath(name, mode, path); + + strncpy(extenbuff, exten, MAXBUFSIZE-1); + extenbuff[MAXBUFSIZE-1] = '\0'; + exten = extenbuff; + + if ( (here = strpbrk(extenbuff, ":;")) ) *here++ = '\0'; + + while ( exten ) { + if ( exten[0] == '$' ) { + if ( (exten = (char *)getenv(&exten[1])) ) + if ( (found = Find(name, mode, exten, path)) ) + return found; + } else { + char *e = strstr(name, exten); + + strncpy(namebuff, name, MAXBUFSIZE-1); + namebuff[MAXBUFSIZE-1] = '\0'; + len = strlen(namebuff); + if ( (e==NULL) || ( e && *(e + len)) ){ + if( len+strlen(exten) <= MAXBUFSIZE-1 ) + strcat(namebuff, exten); + /* filename is too large, so we can't find it */ + else + return NULL; + } + + if ( (found = findpath(namebuff, mode, path)) ) + return found; + + } + + exten = here; + if ( here && (here = strpbrk(here, ":;")) ) *here++ = '\0'; + } + + return NULL; +} diff --git a/xpa/find.h b/xpa/find.h new file mode 100644 index 0000000..96336a0 --- /dev/null +++ b/xpa/find.h @@ -0,0 +1,40 @@ +/* + * Copyright (c) 1999-2003 Smithsonian Astrophysical Observatory + */ + +/* + * + * find.h -- declarations for find finding + * + */ + +#ifndef __find_h +#define __find_h + +#if HAVE_CONFIG_H +#include <conf.h> +#endif + +#include <stdio.h> +#include <ctype.h> +#if HAVE_UNISTD_H +#include <unistd.h> +#endif +#if HAVE_STRING_H +#include <string.h> +#endif +#include <sys/types.h> +#include <sys/stat.h> +#include <xalloc.h> +#include <prsetup.h> + +_PRbeg + +char *ResolvePath _PRx((char *ibuf, char *obuf, int maxlen)); +void ExpandEnv _PRx((char *name, char *fullname, int maxlen)); +char *Access _PRx((char *name, char *mode)); +char *Find _PRx((char *name, char *mode, char *extn, char *path)); + +_PRend + +#endif diff --git a/xpa/gtkloop.c b/xpa/gtkloop.c new file mode 100644 index 0000000..df5137e --- /dev/null +++ b/xpa/gtkloop.c @@ -0,0 +1,190 @@ +/* + * Copyright (c) 2006 Smithsonian Astrophysical Observatory + */ + +#include <xpap.h> + +#ifdef HAVE_GTK + +#include <gtk/gtk.h> +#include <gtk/gtkmain.h> + +/*---------------------------------------------------------------------------- + * + * Private Routines and Data + * + *---------------------------------------------------------------------------- + */ + +/* record struct for maintining gtk info in gtk select loop */ +typedef struct xpagtkrec{ + int fd; + void *client_data; + int id; +} *XPAGtk, XPAGtkRec; + +/*---------------------------------------------------------------------------- + * + * Routine: XPAGtkHandler + * + * Purpose: handle one request for an xpaset or xpaget + * + * Return: none + * + *---------------------------------------------------------------------------- + */ +static gboolean XPAGtkHandler(GIOChannel *gio, GIOCondition condition, + gpointer data) +{ + XPAGtk xptr = (XPAGtk)data; + if( (xptr == NULL) || (xptr->client_data == NULL) ) + return TRUE; + XPAHandler((XPA)xptr->client_data, xptr->fd); + return TRUE; +} + +/*---------------------------------------------------------------------------- + * + * Routine: XPAGtkEnableOneInput + * + * Purpose: Enable 1 XPA entry from the Xt event loop + * + * Results: none + * + *---------------------------------------------------------------------------- + */ +static void XPAGtkEnableOneInput (void *client_data) +{ + XPAGtk xptr = (XPAGtk)client_data; + + if( xptr && !xptr->id ){ + GIOChannel* ioc = g_io_channel_unix_new(xptr->fd); + xptr->id = g_io_add_watch(ioc, (G_IO_IN | G_IO_HUP | G_IO_NVAL), + XPAGtkHandler, xptr); + } +} + +/*---------------------------------------------------------------------------- + * + * Routine: XPAGtkDisableOneInput + * + * Purpose: Disable 1 XPA entry from the Xt event loop + * + * Results: none + * + *---------------------------------------------------------------------------- + */ +static void XPAGtkDisableOneInput (void *client_data) +{ + XPAGtk xptr = (XPAGtk)client_data; + + if(xptr && xptr->id){ + g_source_remove(xptr->id); + xptr->id = 0; + } +} + +/*---------------------------------------------------------------------------- + * + * Routine: XPAGtkAddOneInput + * + * Purpose: Add 1 XPA entry to the gtk event loop + * + * Results: none + * + *---------------------------------------------------------------------------- + */ +static void* XPAGtkAddOneInput (void *client_data, int fd) +{ + XPAGtk xptr; + if( fd < 0 ) + return(NULL); + xptr = (XPAGtk)calloc(1, sizeof(XPAGtkRec)); + xptr->fd = fd; + xptr->client_data = client_data; + XPAGtkEnableOneInput(xptr); + return(xptr); +} + +/*---------------------------------------------------------------------------- + * + * Routine: XPAGtkDelOneInput + * + * Purpose: Delete 1 XPA entry from the gtk event loop (called by XPAFree) + * + * Results: none + * + *---------------------------------------------------------------------------- + */ + +static void XPAGtkDelOneInput (void *client_data) +{ + XPAGtk xptr = (XPAGtk)client_data; + if( xptr == NULL) + return; + XPAGtkDisableOneInput(xptr); + free(xptr); +} + +/*---------------------------------------------------------------------------- + * + * Public Routines and Data + * + *---------------------------------------------------------------------------- + */ + +/*---------------------------------------------------------------------------- + * + * Routine: XPAGtkAddInput + * + * Purpose: Add XPA entries to the Xt event loop + * + * Results: number of xpa entried added + * + *---------------------------------------------------------------------------- + */ +int XPAGtkAddInput (XPA xpa) +{ + XPA cur; + int got=0; + + /* if a specific xpa was specified, just add it */ + if( xpa != NULL ){ + /* remove old one */ + if( xpa->seldel && xpa->selptr ){ + (xpa->seldel)(xpa->selptr); + } + /* add new one */ + xpa->seldel = XPAGtkDelOneInput; + xpa->seladd = XPAGtkAddOneInput; + xpa->selon = XPAGtkEnableOneInput; + xpa->seloff = XPAGtkDisableOneInput; + xpa->selptr = XPAGtkAddOneInput((void *)xpa, xpa->fd); + got = 1; + } + /* otherwise set up all xpa's */ + else{ + for(cur=(XPA)XPAListHead(); cur!=NULL; cur=cur->next){ + /* remove old one */ + if( cur->seldel && cur->selptr ){ + (cur->seldel)(cur->selptr); + } + /* add new one */ + cur->seldel = XPAGtkDelOneInput; + cur->seladd = XPAGtkAddOneInput; + cur->selon = XPAGtkEnableOneInput; + cur->seloff = XPAGtkDisableOneInput; + cur->selptr = XPAGtkAddOneInput((void *)cur, cur->fd); + got++; + } + } + return(got); +} + +int xpa_gtk = 1; + +#else + +int xpa_gtk = 0; + +#endif diff --git a/xpa/install-sh b/xpa/install-sh new file mode 100755 index 0000000..36f96f3 --- /dev/null +++ b/xpa/install-sh @@ -0,0 +1,276 @@ +#!/bin/sh +# +# install - install a program, script, or datafile +# This comes from X11R5 (mit/util/scripts/install.sh). +# +# Copyright 1991 by the Massachusetts Institute of Technology +# +# Permission to use, copy, modify, distribute, and sell this software and its +# documentation for any purpose is hereby granted without fee, provided that +# the above copyright notice appear in all copies and that both that +# copyright notice and this permission notice appear in supporting +# documentation, and that the name of M.I.T. not be used in advertising or +# publicity pertaining to distribution of the software without specific, +# written prior permission. M.I.T. makes no representations about the +# suitability of this software for any purpose. It is provided "as is" +# without express or implied warranty. +# +# Calling this script install-sh is preferred over install.sh, to prevent +# `make' implicit rules from creating a file called install from it +# when there is no Makefile. +# +# This script is compatible with the BSD install script, but was written +# from scratch. It can only install one file at a time, a restriction +# shared with many OS's install programs. + + +# set DOITPROG to echo to test this script + +# Don't use :- since 4.3BSD and earlier shells don't like it. +doit="${DOITPROG-}" + + +# put in absolute paths if you don't have them in your path; or use env. vars. + +mvprog="${MVPROG-mv}" +cpprog="${CPPROG-cp}" +chmodprog="${CHMODPROG-chmod}" +chownprog="${CHOWNPROG-chown}" +chgrpprog="${CHGRPPROG-chgrp}" +stripprog="${STRIPPROG-strip}" +rmprog="${RMPROG-rm}" +mkdirprog="${MKDIRPROG-mkdir}" + +transformbasename="" +transform_arg="" +instcmd="$mvprog" +chmodcmd="$chmodprog 0755" +chowncmd="" +chgrpcmd="" +stripcmd="" +rmcmd="$rmprog -f" +mvcmd="$mvprog" +src="" +dst="" +dir_arg="" + +while [ x"$1" != x ]; do + case $1 in + -c) instcmd=$cpprog + shift + continue;; + + -d) dir_arg=true + shift + continue;; + + -m) chmodcmd="$chmodprog $2" + shift + shift + continue;; + + -o) chowncmd="$chownprog $2" + shift + shift + continue;; + + -g) chgrpcmd="$chgrpprog $2" + shift + shift + continue;; + + -s) stripcmd=$stripprog + shift + continue;; + + -t=*) transformarg=`echo $1 | sed 's/-t=//'` + shift + continue;; + + -b=*) transformbasename=`echo $1 | sed 's/-b=//'` + shift + continue;; + + *) if [ x"$src" = x ] + then + src=$1 + else + # this colon is to work around a 386BSD /bin/sh bug + : + dst=$1 + fi + shift + continue;; + esac +done + +if [ x"$src" = x ] +then + echo "$0: no input file specified" >&2 + exit 1 +else + : +fi + +if [ x"$dir_arg" != x ]; then + dst=$src + src="" + + if [ -d "$dst" ]; then + instcmd=: + chmodcmd="" + else + instcmd=$mkdirprog + fi +else + +# Waiting for this to be detected by the "$instcmd $src $dsttmp" command +# might cause directories to be created, which would be especially bad +# if $src (and thus $dsttmp) contains '*'. + + if [ -f "$src" ] || [ -d "$src" ] + then + : + else + echo "$0: $src does not exist" >&2 + exit 1 + fi + + if [ x"$dst" = x ] + then + echo "$0: no destination specified" >&2 + exit 1 + else + : + fi + +# If destination is a directory, append the input filename; if your system +# does not like double slashes in filenames, you may need to add some logic + + if [ -d "$dst" ] + then + dst=$dst/`basename "$src"` + else + : + fi +fi + +## this sed command emulates the dirname command +dstdir=`echo "$dst" | sed -e 's,[^/]*$,,;s,/$,,;s,^$,.,'` + +# Make sure that the destination directory exists. +# this part is taken from Noah Friedman's mkinstalldirs script + +# Skip lots of stat calls in the usual case. +if [ ! -d "$dstdir" ]; then +defaultIFS=' + ' +IFS="${IFS-$defaultIFS}" + +oIFS=$IFS +# Some sh's can't handle IFS=/ for some reason. +IFS='%' +set - `echo "$dstdir" | sed -e 's@/@%@g' -e 's@^%@/@'` +IFS=$oIFS + +pathcomp='' + +while [ $# -ne 0 ] ; do + pathcomp=$pathcomp$1 + shift + + if [ ! -d "$pathcomp" ] ; + then + $mkdirprog "$pathcomp" + else + : + fi + + pathcomp=$pathcomp/ +done +fi + +if [ x"$dir_arg" != x ] +then + $doit $instcmd "$dst" && + + if [ x"$chowncmd" != x ]; then $doit $chowncmd "$dst"; else : ; fi && + if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd "$dst"; else : ; fi && + if [ x"$stripcmd" != x ]; then $doit $stripcmd "$dst"; else : ; fi && + if [ x"$chmodcmd" != x ]; then $doit $chmodcmd "$dst"; else : ; fi +else + +# If we're going to rename the final executable, determine the name now. + + if [ x"$transformarg" = x ] + then + dstfile=`basename "$dst"` + else + dstfile=`basename "$dst" $transformbasename | + sed $transformarg`$transformbasename + fi + +# don't allow the sed command to completely eliminate the filename + + if [ x"$dstfile" = x ] + then + dstfile=`basename "$dst"` + else + : + fi + +# Make a couple of temp file names in the proper directory. + + dsttmp=$dstdir/#inst.$$# + rmtmp=$dstdir/#rm.$$# + +# Trap to clean up temp files at exit. + + trap 'status=$?; rm -f "$dsttmp" "$rmtmp" && exit $status' 0 + trap '(exit $?); exit' 1 2 13 15 + +# Move or copy the file name to the temp name + + $doit $instcmd "$src" "$dsttmp" && + +# and set any options; do chmod last to preserve setuid bits + +# If any of these fail, we abort the whole thing. If we want to +# ignore errors from any of these, just make sure not to ignore +# errors from the above "$doit $instcmd $src $dsttmp" command. + + if [ x"$chowncmd" != x ]; then $doit $chowncmd "$dsttmp"; else :;fi && + if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd "$dsttmp"; else :;fi && + if [ x"$stripcmd" != x ]; then $doit $stripcmd "$dsttmp"; else :;fi && + if [ x"$chmodcmd" != x ]; then $doit $chmodcmd "$dsttmp"; else :;fi && + +# Now remove or move aside any old file at destination location. We try this +# two ways since rm can't unlink itself on some systems and the destination +# file might be busy for other reasons. In this case, the final cleanup +# might fail but the new file should still install successfully. + +{ + if [ -f "$dstdir/$dstfile" ] + then + $doit $rmcmd -f "$dstdir/$dstfile" 2>/dev/null || + $doit $mvcmd -f "$dstdir/$dstfile" "$rmtmp" 2>/dev/null || + { + echo "$0: cannot unlink or rename $dstdir/$dstfile" >&2 + (exit 1); exit + } + else + : + fi +} && + +# Now rename the file to the real destination. + + $doit $mvcmd "$dsttmp" "$dstdir/$dstfile" + +fi && + +# The final little trick to "correctly" pass the exit status to the exit trap. + +{ + (exit 0); exit +} diff --git a/xpa/man/man1/xpaaccess.1 b/xpa/man/man1/xpaaccess.1 new file mode 100644 index 0000000..a3aa7a6 --- /dev/null +++ b/xpa/man/man1/xpaaccess.1 @@ -0,0 +1,198 @@ +.\" Automatically generated by Pod::Man 2.22 (Pod::Simple 3.13) +.\" +.\" Standard preamble: +.\" ======================================================================== +.de Sp \" Vertical space (when we can't use .PP) +.if t .sp .5v +.if n .sp +.. +.de Vb \" Begin verbatim text +.ft CW +.nf +.ne \\$1 +.. +.de Ve \" End verbatim text +.ft R +.fi +.. +.\" Set up some character translations and predefined strings. \*(-- will +.\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left +.\" double quote, and \*(R" will give a right double quote. \*(C+ will +.\" give a nicer C++. Capital omega is used to do unbreakable dashes and +.\" therefore won't be available. \*(C` and \*(C' expand to `' in nroff, +.\" nothing in troff, for use with C<>. +.tr \(*W- +.ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p' +.ie n \{\ +. ds -- \(*W- +. ds PI pi +. if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch +. if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch +. ds L" "" +. ds R" "" +. ds C` "" +. ds C' "" +'br\} +.el\{\ +. ds -- \|\(em\| +. ds PI \(*p +. ds L" `` +. ds R" '' +'br\} +.\" +.\" Escape single quotes in literal strings from groff's Unicode transform. +.ie \n(.g .ds Aq \(aq +.el .ds Aq ' +.\" +.\" If the F register is turned on, we'll generate index entries on stderr for +.\" titles (.TH), headers (.SH), subsections (.SS), items (.Ip), and index +.\" entries marked with X<> in POD. Of course, you'll have to process the +.\" output yourself in some meaningful fashion. +.ie \nF \{\ +. de IX +. tm Index:\\$1\t\\n%\t"\\$2" +.. +. nr % 0 +. rr F +.\} +.el \{\ +. de IX +.. +.\} +.\" +.\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2). +.\" Fear. Run. Save yourself. No user-serviceable parts. +. \" fudge factors for nroff and troff +.if n \{\ +. ds #H 0 +. ds #V .8m +. ds #F .3m +. ds #[ \f1 +. ds #] \fP +.\} +.if t \{\ +. ds #H ((1u-(\\\\n(.fu%2u))*.13m) +. ds #V .6m +. ds #F 0 +. ds #[ \& +. ds #] \& +.\} +. \" simple accents for nroff and troff +.if n \{\ +. ds ' \& +. ds ` \& +. ds ^ \& +. ds , \& +. ds ~ ~ +. ds / +.\} +.if t \{\ +. ds ' \\k:\h'-(\\n(.wu*8/10-\*(#H)'\'\h"|\\n:u" +. ds ` \\k:\h'-(\\n(.wu*8/10-\*(#H)'\`\h'|\\n:u' +. ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'^\h'|\\n:u' +. ds , \\k:\h'-(\\n(.wu*8/10)',\h'|\\n:u' +. ds ~ \\k:\h'-(\\n(.wu-\*(#H-.1m)'~\h'|\\n:u' +. ds / \\k:\h'-(\\n(.wu*8/10-\*(#H)'\z\(sl\h'|\\n:u' +.\} +. \" troff and (daisy-wheel) nroff accents +.ds : \\k:\h'-(\\n(.wu*8/10-\*(#H+.1m+\*(#F)'\v'-\*(#V'\z.\h'.2m+\*(#F'.\h'|\\n:u'\v'\*(#V' +.ds 8 \h'\*(#H'\(*b\h'-\*(#H' +.ds o \\k:\h'-(\\n(.wu+\w'\(de'u-\*(#H)/2u'\v'-.3n'\*(#[\z\(de\v'.3n'\h'|\\n:u'\*(#] +.ds d- \h'\*(#H'\(pd\h'-\w'~'u'\v'-.25m'\f2\(hy\fP\v'.25m'\h'-\*(#H' +.ds D- D\\k:\h'-\w'D'u'\v'-.11m'\z\(hy\v'.11m'\h'|\\n:u' +.ds th \*(#[\v'.3m'\s+1I\s-1\v'-.3m'\h'-(\w'I'u*2/3)'\s-1o\s+1\*(#] +.ds Th \*(#[\s+2I\s-2\h'-\w'I'u*3/5'\v'-.3m'o\v'.3m'\*(#] +.ds ae a\h'-(\w'a'u*4/10)'e +.ds Ae A\h'-(\w'A'u*4/10)'E +. \" corrections for vroff +.if v .ds ~ \\k:\h'-(\\n(.wu*9/10-\*(#H)'\s-2\u~\d\s+2\h'|\\n:u' +.if v .ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'\v'-.4m'^\v'.4m'\h'|\\n:u' +. \" for low resolution devices (crt and lpr) +.if \n(.H>23 .if \n(.V>19 \ +\{\ +. ds : e +. ds 8 ss +. ds o a +. ds d- d\h'-1'\(ga +. ds D- D\h'-1'\(hy +. ds th \o'bp' +. ds Th \o'LP' +. ds ae ae +. ds Ae AE +.\} +.rm #[ #] #H #V #F C +.\" ======================================================================== +.\" +.IX Title "xpaaccess 1" +.TH xpaaccess 1 "July 23, 2013" "version 2.1.15" "SAORD Documentation" +.\" For nroff, turn off justification. Always turn off hyphenation; it makes +.\" way too many mistakes in technical documents. +.if n .ad l +.nh +.SH "NAME" +\&\fBxpaaccess: see if template matches registered \s-1XPA\s0 access points\fR +.SH "SYNOPSIS" +.IX Header "SYNOPSIS" +xpaaccess [\-c] [\-h] [\-i nsinet] [\-m method] [\-n] [\-t sval,lval] [\-u users] \-v <template> [type] +.SH "OPTIONS" +.IX Header "OPTIONS" +.Vb 10 +\& \-c contact each access point individually +\& \-h print help message +\& \-i access XPA point on different machine (override XPA_NSINET) +\& \-m override XPA_METHOD environment variable +\& \-n return number of matches instead of "yes" or "no" +\& \-t [s,l] set short and long timeouts (override XPA_[SHORT,LONG]_TIMEOUT) +\& \-u [users] XPA points can be from specified users (override XPA_NSUSERS) +\& \-v print info about each successful access point +\& \-V print info or error about each access point +\& \-\-version display version and exit +.Ve +.SH "DESCRIPTION" +.IX Header "DESCRIPTION" +xpaaccess returns \*(L"yes\*(R" to stdout (with a return error code if 1) if there are +existing \s-1XPA\s0 access points that match the +template +(and optional access type: g,i,s). Otherwise, it returns \*(L"no\*(R" (with a +return error code of 0). If \-n is specified, the number of matches is +returned instead (both to stdout and in the returned error code). If +\&\-v is specified, each access point is displayed to stdout instead of +the number of matches. +.PP +By default, xpaaccess simply contacts the xpans name server to find +the list of registered access points that match the specified +template. It also checks to make sure the specified types are +supported by that access point. This is the fastest way to determine +available access points. However, an access point might registered but +not yet available, if, for example, the server program has not entered +its event loop to process \s-1XPA\s0 requests. To find access points that are +guaranteed to be available for processing, use the \-c (contact) +switch. With this switch, xpaaccess contacts each matching \s-1XPA\s0 server +(rather than the name server) to make sure the registered access point +really is ready for processing. In this mode, if an access point is +registered but not available, xpaaccess will pause for a period of +time equal to the \s-1XPA_LONG_TIMEOUT\s0, in order to give the server a +chance to ready itself. By default, this timeout is 30 seconds. You +can shorten the time of delay using the \-t \*(L"short,long\*(R" switch. For +example, to shorten the delay time to 2 seconds, use: +.PP +.Vb 1 +\& xpaaccess \-c \-t "2,2" ds9 +.Ve +.PP +The first argument is the short delay value, and is ignored in this +operation. The second is the long delay timeout. +.PP +Note also that the default xpaaccess method (no \-c switch) does not +check access control (acls) but rather only checks whether the access +point is both registered with the xpans name server and provides the +specified type of access. In other words, the default xpaaccess could +return 'yes' when you might not actually have access. This mode also +always returns 'yes' for the xpans name server itself, regardless of +whether the name server is active. The \-c (contact) switch, which +contacts the access point directly, can and does check the access +control (only for servers using version 2.1 and above) and also +returns the real status of xpans. +.SH "SEE ALSO" +.IX Header "SEE ALSO" +See xpa(n) for a list of \s-1XPA\s0 help pages diff --git a/xpa/man/man1/xpachanges.1 b/xpa/man/man1/xpachanges.1 new file mode 100644 index 0000000..f910bbe --- /dev/null +++ b/xpa/man/man1/xpachanges.1 @@ -0,0 +1,180 @@ +.\" Automatically generated by Pod::Man 2.22 (Pod::Simple 3.13) +.\" +.\" Standard preamble: +.\" ======================================================================== +.de Sp \" Vertical space (when we can't use .PP) +.if t .sp .5v +.if n .sp +.. +.de Vb \" Begin verbatim text +.ft CW +.nf +.ne \\$1 +.. +.de Ve \" End verbatim text +.ft R +.fi +.. +.\" Set up some character translations and predefined strings. \*(-- will +.\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left +.\" double quote, and \*(R" will give a right double quote. \*(C+ will +.\" give a nicer C++. Capital omega is used to do unbreakable dashes and +.\" therefore won't be available. \*(C` and \*(C' expand to `' in nroff, +.\" nothing in troff, for use with C<>. +.tr \(*W- +.ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p' +.ie n \{\ +. ds -- \(*W- +. ds PI pi +. if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch +. if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch +. ds L" "" +. ds R" "" +. ds C` "" +. ds C' "" +'br\} +.el\{\ +. ds -- \|\(em\| +. ds PI \(*p +. ds L" `` +. ds R" '' +'br\} +.\" +.\" Escape single quotes in literal strings from groff's Unicode transform. +.ie \n(.g .ds Aq \(aq +.el .ds Aq ' +.\" +.\" If the F register is turned on, we'll generate index entries on stderr for +.\" titles (.TH), headers (.SH), subsections (.SS), items (.Ip), and index +.\" entries marked with X<> in POD. Of course, you'll have to process the +.\" output yourself in some meaningful fashion. +.ie \nF \{\ +. de IX +. tm Index:\\$1\t\\n%\t"\\$2" +.. +. nr % 0 +. rr F +.\} +.el \{\ +. de IX +.. +.\} +.\" +.\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2). +.\" Fear. Run. Save yourself. No user-serviceable parts. +. \" fudge factors for nroff and troff +.if n \{\ +. ds #H 0 +. ds #V .8m +. ds #F .3m +. ds #[ \f1 +. ds #] \fP +.\} +.if t \{\ +. ds #H ((1u-(\\\\n(.fu%2u))*.13m) +. ds #V .6m +. ds #F 0 +. ds #[ \& +. ds #] \& +.\} +. \" simple accents for nroff and troff +.if n \{\ +. ds ' \& +. ds ` \& +. ds ^ \& +. ds , \& +. ds ~ ~ +. ds / +.\} +.if t \{\ +. ds ' \\k:\h'-(\\n(.wu*8/10-\*(#H)'\'\h"|\\n:u" +. ds ` \\k:\h'-(\\n(.wu*8/10-\*(#H)'\`\h'|\\n:u' +. ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'^\h'|\\n:u' +. ds , \\k:\h'-(\\n(.wu*8/10)',\h'|\\n:u' +. ds ~ \\k:\h'-(\\n(.wu-\*(#H-.1m)'~\h'|\\n:u' +. ds / \\k:\h'-(\\n(.wu*8/10-\*(#H)'\z\(sl\h'|\\n:u' +.\} +. \" troff and (daisy-wheel) nroff accents +.ds : \\k:\h'-(\\n(.wu*8/10-\*(#H+.1m+\*(#F)'\v'-\*(#V'\z.\h'.2m+\*(#F'.\h'|\\n:u'\v'\*(#V' +.ds 8 \h'\*(#H'\(*b\h'-\*(#H' +.ds o \\k:\h'-(\\n(.wu+\w'\(de'u-\*(#H)/2u'\v'-.3n'\*(#[\z\(de\v'.3n'\h'|\\n:u'\*(#] +.ds d- \h'\*(#H'\(pd\h'-\w'~'u'\v'-.25m'\f2\(hy\fP\v'.25m'\h'-\*(#H' +.ds D- D\\k:\h'-\w'D'u'\v'-.11m'\z\(hy\v'.11m'\h'|\\n:u' +.ds th \*(#[\v'.3m'\s+1I\s-1\v'-.3m'\h'-(\w'I'u*2/3)'\s-1o\s+1\*(#] +.ds Th \*(#[\s+2I\s-2\h'-\w'I'u*3/5'\v'-.3m'o\v'.3m'\*(#] +.ds ae a\h'-(\w'a'u*4/10)'e +.ds Ae A\h'-(\w'A'u*4/10)'E +. \" corrections for vroff +.if v .ds ~ \\k:\h'-(\\n(.wu*9/10-\*(#H)'\s-2\u~\d\s+2\h'|\\n:u' +.if v .ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'\v'-.4m'^\v'.4m'\h'|\\n:u' +. \" for low resolution devices (crt and lpr) +.if \n(.H>23 .if \n(.V>19 \ +\{\ +. ds : e +. ds 8 ss +. ds o a +. ds d- d\h'-1'\(ga +. ds D- D\h'-1'\(hy +. ds th \o'bp' +. ds Th \o'LP' +. ds ae ae +. ds Ae AE +.\} +.rm #[ #] #H #V #F C +.\" ======================================================================== +.\" +.IX Title "xpachanges 1" +.TH xpachanges 1 "July 23, 2013" "version 2.1.15" "SAORD Documentation" +.\" For nroff, turn off justification. Always turn off hyphenation; it makes +.\" way too many mistakes in technical documents. +.if n .ad l +.nh +.SH "NAME" +\&\fB\s-1XPA\s0 Changes: Changes For Users from \s-1XPA\s0 1.0 and 2.0\fR +.SH "SYNOPSIS" +.IX Header "SYNOPSIS" +This document describes changes that will affect users who migrate +from \s-1XPA\s0 1.0 to \s-1XPA\s0 2.0. +.SH "DESCRIPTION" +.IX Header "DESCRIPTION" +There have been a few changes that affect users who upgrade \s-1XPA\s0 +from version 1.0 to version 2.0. These changes are detailed below. +.IP "\(bu" 4 +\&\s-1XPA\s0 commands no longer have a resolver routine (this is open to +negotiations, but we decided the idea was dumb). For the SAOtng +program, this means that you must explicitly specify the access +point, i.e.,: +.Sp +.Vb 1 +\& cat foo.fits | xpaset SAOtng fits +.Ve +.Sp +instead of: +.Sp +.Vb 1 +\& cat foo.fits | xpaset SAOtng +.Ve +.IP "\(bu" 4 +By default, xpaset, xpaget, etc. now wait for the server callback to +complete; i.e., the old \-W is implied (and the switch is ignored). +This allows support for better error handling. If you want xpaset, etc. +to return before the callback is complete, use \-n switch: +.Sp +.Vb 1 +\& echo "file foo.fits" | xpaset \-n SAOtng +.Ve +.IP "\(bu" 4 +The old \-w switch in xpaset and xpaget is no longer necessary (and is +ignored), since you can have more than one process communicating with +an xpa access point at one time. +.IP "\(bu" 4 +The new \-p switch on xpaset means you need not read from stdout: +.Sp +.Vb 1 +\& xpaset \-p SAOtng colormap I8 +.Ve +.Sp +will send the paramlist to the SAOtng callback without reading from stdin. +.SH "SEE ALSO" +.IX Header "SEE ALSO" +See xpa(n) for a list of \s-1XPA\s0 help pages diff --git a/xpa/man/man1/xpaget.1 b/xpa/man/man1/xpaget.1 new file mode 100644 index 0000000..12d94d9 --- /dev/null +++ b/xpa/man/man1/xpaget.1 @@ -0,0 +1,164 @@ +.\" Automatically generated by Pod::Man 2.22 (Pod::Simple 3.13) +.\" +.\" Standard preamble: +.\" ======================================================================== +.de Sp \" Vertical space (when we can't use .PP) +.if t .sp .5v +.if n .sp +.. +.de Vb \" Begin verbatim text +.ft CW +.nf +.ne \\$1 +.. +.de Ve \" End verbatim text +.ft R +.fi +.. +.\" Set up some character translations and predefined strings. \*(-- will +.\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left +.\" double quote, and \*(R" will give a right double quote. \*(C+ will +.\" give a nicer C++. Capital omega is used to do unbreakable dashes and +.\" therefore won't be available. \*(C` and \*(C' expand to `' in nroff, +.\" nothing in troff, for use with C<>. +.tr \(*W- +.ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p' +.ie n \{\ +. ds -- \(*W- +. ds PI pi +. if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch +. if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch +. ds L" "" +. ds R" "" +. ds C` "" +. ds C' "" +'br\} +.el\{\ +. ds -- \|\(em\| +. ds PI \(*p +. ds L" `` +. ds R" '' +'br\} +.\" +.\" Escape single quotes in literal strings from groff's Unicode transform. +.ie \n(.g .ds Aq \(aq +.el .ds Aq ' +.\" +.\" If the F register is turned on, we'll generate index entries on stderr for +.\" titles (.TH), headers (.SH), subsections (.SS), items (.Ip), and index +.\" entries marked with X<> in POD. Of course, you'll have to process the +.\" output yourself in some meaningful fashion. +.ie \nF \{\ +. de IX +. tm Index:\\$1\t\\n%\t"\\$2" +.. +. nr % 0 +. rr F +.\} +.el \{\ +. de IX +.. +.\} +.\" +.\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2). +.\" Fear. Run. Save yourself. No user-serviceable parts. +. \" fudge factors for nroff and troff +.if n \{\ +. ds #H 0 +. ds #V .8m +. ds #F .3m +. ds #[ \f1 +. ds #] \fP +.\} +.if t \{\ +. ds #H ((1u-(\\\\n(.fu%2u))*.13m) +. ds #V .6m +. ds #F 0 +. ds #[ \& +. ds #] \& +.\} +. \" simple accents for nroff and troff +.if n \{\ +. ds ' \& +. ds ` \& +. ds ^ \& +. ds , \& +. ds ~ ~ +. ds / +.\} +.if t \{\ +. ds ' \\k:\h'-(\\n(.wu*8/10-\*(#H)'\'\h"|\\n:u" +. ds ` \\k:\h'-(\\n(.wu*8/10-\*(#H)'\`\h'|\\n:u' +. ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'^\h'|\\n:u' +. ds , \\k:\h'-(\\n(.wu*8/10)',\h'|\\n:u' +. ds ~ \\k:\h'-(\\n(.wu-\*(#H-.1m)'~\h'|\\n:u' +. ds / \\k:\h'-(\\n(.wu*8/10-\*(#H)'\z\(sl\h'|\\n:u' +.\} +. \" troff and (daisy-wheel) nroff accents +.ds : \\k:\h'-(\\n(.wu*8/10-\*(#H+.1m+\*(#F)'\v'-\*(#V'\z.\h'.2m+\*(#F'.\h'|\\n:u'\v'\*(#V' +.ds 8 \h'\*(#H'\(*b\h'-\*(#H' +.ds o \\k:\h'-(\\n(.wu+\w'\(de'u-\*(#H)/2u'\v'-.3n'\*(#[\z\(de\v'.3n'\h'|\\n:u'\*(#] +.ds d- \h'\*(#H'\(pd\h'-\w'~'u'\v'-.25m'\f2\(hy\fP\v'.25m'\h'-\*(#H' +.ds D- D\\k:\h'-\w'D'u'\v'-.11m'\z\(hy\v'.11m'\h'|\\n:u' +.ds th \*(#[\v'.3m'\s+1I\s-1\v'-.3m'\h'-(\w'I'u*2/3)'\s-1o\s+1\*(#] +.ds Th \*(#[\s+2I\s-2\h'-\w'I'u*3/5'\v'-.3m'o\v'.3m'\*(#] +.ds ae a\h'-(\w'a'u*4/10)'e +.ds Ae A\h'-(\w'A'u*4/10)'E +. \" corrections for vroff +.if v .ds ~ \\k:\h'-(\\n(.wu*9/10-\*(#H)'\s-2\u~\d\s+2\h'|\\n:u' +.if v .ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'\v'-.4m'^\v'.4m'\h'|\\n:u' +. \" for low resolution devices (crt and lpr) +.if \n(.H>23 .if \n(.V>19 \ +\{\ +. ds : e +. ds 8 ss +. ds o a +. ds d- d\h'-1'\(ga +. ds D- D\h'-1'\(hy +. ds th \o'bp' +. ds Th \o'LP' +. ds ae ae +. ds Ae AE +.\} +.rm #[ #] #H #V #F C +.\" ======================================================================== +.\" +.IX Title "xpaget 1" +.TH xpaget 1 "July 23, 2013" "version 2.1.15" "SAORD Documentation" +.\" For nroff, turn off justification. Always turn off hyphenation; it makes +.\" way too many mistakes in technical documents. +.if n .ad l +.nh +.SH "NAME" +\&\fBxpaget: retrieve data from one or more \s-1XPA\s0 servers\fR +.SH "SYNOPSIS" +.IX Header "SYNOPSIS" +xpaget [\-h] [\-i nsinet] [\-m method] [\-s] [\-t sval,lval] [\-u users] <template|host:port> [paramlist] +.SH "OPTIONS" +.IX Header "OPTIONS" +.Vb 8 +\& \-h print help message +\& \-i access XPA point on different machine (override XPA_NSINET) +\& \-m override XPA_METHOD environment variable +\& \-n don\*(Aqt wait for the status message after server completes +\& \-s enter server mode +\& \-t [s,l] set short and long timeouts (override XPA_[SHORT,LONG]_TIMEOUT) +\& \-u [users] XPA points can be from specified users (override XPA_NSUSERS) +\& \-\-version display version and exit +.Ve +.SH "DESCRIPTION" +.IX Header "DESCRIPTION" +Data will be retrieved from access points matching the +template +or host:port. +A set of qualifying parameters can be appended. +.PP +\&\fBExamples:\fR +.PP +.Vb 2 +\& csh> xpaget ds9 images +\& csh> xpaget myhost.harvard.edu:12345 +.Ve +.SH "SEE ALSO" +.IX Header "SEE ALSO" +See xpa(n) for a list of \s-1XPA\s0 help pages diff --git a/xpa/man/man1/xpainfo.1 b/xpa/man/man1/xpainfo.1 new file mode 100644 index 0000000..2ad7f81 --- /dev/null +++ b/xpa/man/man1/xpainfo.1 @@ -0,0 +1,163 @@ +.\" Automatically generated by Pod::Man 2.22 (Pod::Simple 3.13) +.\" +.\" Standard preamble: +.\" ======================================================================== +.de Sp \" Vertical space (when we can't use .PP) +.if t .sp .5v +.if n .sp +.. +.de Vb \" Begin verbatim text +.ft CW +.nf +.ne \\$1 +.. +.de Ve \" End verbatim text +.ft R +.fi +.. +.\" Set up some character translations and predefined strings. \*(-- will +.\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left +.\" double quote, and \*(R" will give a right double quote. \*(C+ will +.\" give a nicer C++. Capital omega is used to do unbreakable dashes and +.\" therefore won't be available. \*(C` and \*(C' expand to `' in nroff, +.\" nothing in troff, for use with C<>. +.tr \(*W- +.ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p' +.ie n \{\ +. ds -- \(*W- +. ds PI pi +. if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch +. if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch +. ds L" "" +. ds R" "" +. ds C` "" +. ds C' "" +'br\} +.el\{\ +. ds -- \|\(em\| +. ds PI \(*p +. ds L" `` +. ds R" '' +'br\} +.\" +.\" Escape single quotes in literal strings from groff's Unicode transform. +.ie \n(.g .ds Aq \(aq +.el .ds Aq ' +.\" +.\" If the F register is turned on, we'll generate index entries on stderr for +.\" titles (.TH), headers (.SH), subsections (.SS), items (.Ip), and index +.\" entries marked with X<> in POD. Of course, you'll have to process the +.\" output yourself in some meaningful fashion. +.ie \nF \{\ +. de IX +. tm Index:\\$1\t\\n%\t"\\$2" +.. +. nr % 0 +. rr F +.\} +.el \{\ +. de IX +.. +.\} +.\" +.\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2). +.\" Fear. Run. Save yourself. No user-serviceable parts. +. \" fudge factors for nroff and troff +.if n \{\ +. ds #H 0 +. ds #V .8m +. ds #F .3m +. ds #[ \f1 +. ds #] \fP +.\} +.if t \{\ +. ds #H ((1u-(\\\\n(.fu%2u))*.13m) +. ds #V .6m +. ds #F 0 +. ds #[ \& +. ds #] \& +.\} +. \" simple accents for nroff and troff +.if n \{\ +. ds ' \& +. ds ` \& +. ds ^ \& +. ds , \& +. ds ~ ~ +. ds / +.\} +.if t \{\ +. ds ' \\k:\h'-(\\n(.wu*8/10-\*(#H)'\'\h"|\\n:u" +. ds ` \\k:\h'-(\\n(.wu*8/10-\*(#H)'\`\h'|\\n:u' +. ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'^\h'|\\n:u' +. ds , \\k:\h'-(\\n(.wu*8/10)',\h'|\\n:u' +. ds ~ \\k:\h'-(\\n(.wu-\*(#H-.1m)'~\h'|\\n:u' +. ds / \\k:\h'-(\\n(.wu*8/10-\*(#H)'\z\(sl\h'|\\n:u' +.\} +. \" troff and (daisy-wheel) nroff accents +.ds : \\k:\h'-(\\n(.wu*8/10-\*(#H+.1m+\*(#F)'\v'-\*(#V'\z.\h'.2m+\*(#F'.\h'|\\n:u'\v'\*(#V' +.ds 8 \h'\*(#H'\(*b\h'-\*(#H' +.ds o \\k:\h'-(\\n(.wu+\w'\(de'u-\*(#H)/2u'\v'-.3n'\*(#[\z\(de\v'.3n'\h'|\\n:u'\*(#] +.ds d- \h'\*(#H'\(pd\h'-\w'~'u'\v'-.25m'\f2\(hy\fP\v'.25m'\h'-\*(#H' +.ds D- D\\k:\h'-\w'D'u'\v'-.11m'\z\(hy\v'.11m'\h'|\\n:u' +.ds th \*(#[\v'.3m'\s+1I\s-1\v'-.3m'\h'-(\w'I'u*2/3)'\s-1o\s+1\*(#] +.ds Th \*(#[\s+2I\s-2\h'-\w'I'u*3/5'\v'-.3m'o\v'.3m'\*(#] +.ds ae a\h'-(\w'a'u*4/10)'e +.ds Ae A\h'-(\w'A'u*4/10)'E +. \" corrections for vroff +.if v .ds ~ \\k:\h'-(\\n(.wu*9/10-\*(#H)'\s-2\u~\d\s+2\h'|\\n:u' +.if v .ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'\v'-.4m'^\v'.4m'\h'|\\n:u' +. \" for low resolution devices (crt and lpr) +.if \n(.H>23 .if \n(.V>19 \ +\{\ +. ds : e +. ds 8 ss +. ds o a +. ds d- d\h'-1'\(ga +. ds D- D\h'-1'\(hy +. ds th \o'bp' +. ds Th \o'LP' +. ds ae ae +. ds Ae AE +.\} +.rm #[ #] #H #V #F C +.\" ======================================================================== +.\" +.IX Title "xpainfo 1" +.TH xpainfo 1 "July 23, 2013" "version 2.1.15" "SAORD Documentation" +.\" For nroff, turn off justification. Always turn off hyphenation; it makes +.\" way too many mistakes in technical documents. +.if n .ad l +.nh +.SH "NAME" +\&\fBxpainfo: send short message to one or more \s-1XPA\s0 servers\fR +.SH "SYNOPSIS" +.IX Header "SYNOPSIS" +xpainfo [\-h] [\-i nsinet] [\-m method] [\-n] [\-s] [\-t sval,lval] [\-u users] <template|host:port> [paramlist] +.SH "OPTIONS" +.IX Header "OPTIONS" +.Vb 8 +\& \-h print help message +\& \-i access XPA point on different machine (override XPA_NSINET) +\& \-m override XPA_METHOD environment variable +\& \-n don\*(Aqt wait for the status message after server completes +\& \-s enter server mode +\& \-t [s,l] set short and long timeouts (override XPA_[SHORT,LONG]_TIMEOUT) +\& \-u [users] XPA points can be from specified users (override XPA_NSUSERS) +\& \-\-version display version and exit +.Ve +.SH "DESCRIPTION" +.IX Header "DESCRIPTION" +Info will be sent to access points matching the +template +or host:port. +A set of qualifying parameters can be appended. +.PP +\&\fBExamples:\fR +.PP +.Vb 1 +\& csh> xpainfo IMAGE ds9 image +.Ve +.SH "SEE ALSO" +.IX Header "SEE ALSO" +See xpa(n) for a list of \s-1XPA\s0 help pages diff --git a/xpa/man/man1/xpamb.1 b/xpa/man/man1/xpamb.1 new file mode 100644 index 0000000..37f06f4 --- /dev/null +++ b/xpa/man/man1/xpamb.1 @@ -0,0 +1,325 @@ +.\" Automatically generated by Pod::Man 2.22 (Pod::Simple 3.13) +.\" +.\" Standard preamble: +.\" ======================================================================== +.de Sp \" Vertical space (when we can't use .PP) +.if t .sp .5v +.if n .sp +.. +.de Vb \" Begin verbatim text +.ft CW +.nf +.ne \\$1 +.. +.de Ve \" End verbatim text +.ft R +.fi +.. +.\" Set up some character translations and predefined strings. \*(-- will +.\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left +.\" double quote, and \*(R" will give a right double quote. \*(C+ will +.\" give a nicer C++. Capital omega is used to do unbreakable dashes and +.\" therefore won't be available. \*(C` and \*(C' expand to `' in nroff, +.\" nothing in troff, for use with C<>. +.tr \(*W- +.ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p' +.ie n \{\ +. ds -- \(*W- +. ds PI pi +. if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch +. if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch +. ds L" "" +. ds R" "" +. ds C` "" +. ds C' "" +'br\} +.el\{\ +. ds -- \|\(em\| +. ds PI \(*p +. ds L" `` +. ds R" '' +'br\} +.\" +.\" Escape single quotes in literal strings from groff's Unicode transform. +.ie \n(.g .ds Aq \(aq +.el .ds Aq ' +.\" +.\" If the F register is turned on, we'll generate index entries on stderr for +.\" titles (.TH), headers (.SH), subsections (.SS), items (.Ip), and index +.\" entries marked with X<> in POD. Of course, you'll have to process the +.\" output yourself in some meaningful fashion. +.ie \nF \{\ +. de IX +. tm Index:\\$1\t\\n%\t"\\$2" +.. +. nr % 0 +. rr F +.\} +.el \{\ +. de IX +.. +.\} +.\" +.\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2). +.\" Fear. Run. Save yourself. No user-serviceable parts. +. \" fudge factors for nroff and troff +.if n \{\ +. ds #H 0 +. ds #V .8m +. ds #F .3m +. ds #[ \f1 +. ds #] \fP +.\} +.if t \{\ +. ds #H ((1u-(\\\\n(.fu%2u))*.13m) +. ds #V .6m +. ds #F 0 +. ds #[ \& +. ds #] \& +.\} +. \" simple accents for nroff and troff +.if n \{\ +. ds ' \& +. ds ` \& +. ds ^ \& +. ds , \& +. ds ~ ~ +. ds / +.\} +.if t \{\ +. ds ' \\k:\h'-(\\n(.wu*8/10-\*(#H)'\'\h"|\\n:u" +. ds ` \\k:\h'-(\\n(.wu*8/10-\*(#H)'\`\h'|\\n:u' +. ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'^\h'|\\n:u' +. ds , \\k:\h'-(\\n(.wu*8/10)',\h'|\\n:u' +. ds ~ \\k:\h'-(\\n(.wu-\*(#H-.1m)'~\h'|\\n:u' +. ds / \\k:\h'-(\\n(.wu*8/10-\*(#H)'\z\(sl\h'|\\n:u' +.\} +. \" troff and (daisy-wheel) nroff accents +.ds : \\k:\h'-(\\n(.wu*8/10-\*(#H+.1m+\*(#F)'\v'-\*(#V'\z.\h'.2m+\*(#F'.\h'|\\n:u'\v'\*(#V' +.ds 8 \h'\*(#H'\(*b\h'-\*(#H' +.ds o \\k:\h'-(\\n(.wu+\w'\(de'u-\*(#H)/2u'\v'-.3n'\*(#[\z\(de\v'.3n'\h'|\\n:u'\*(#] +.ds d- \h'\*(#H'\(pd\h'-\w'~'u'\v'-.25m'\f2\(hy\fP\v'.25m'\h'-\*(#H' +.ds D- D\\k:\h'-\w'D'u'\v'-.11m'\z\(hy\v'.11m'\h'|\\n:u' +.ds th \*(#[\v'.3m'\s+1I\s-1\v'-.3m'\h'-(\w'I'u*2/3)'\s-1o\s+1\*(#] +.ds Th \*(#[\s+2I\s-2\h'-\w'I'u*3/5'\v'-.3m'o\v'.3m'\*(#] +.ds ae a\h'-(\w'a'u*4/10)'e +.ds Ae A\h'-(\w'A'u*4/10)'E +. \" corrections for vroff +.if v .ds ~ \\k:\h'-(\\n(.wu*9/10-\*(#H)'\s-2\u~\d\s+2\h'|\\n:u' +.if v .ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'\v'-.4m'^\v'.4m'\h'|\\n:u' +. \" for low resolution devices (crt and lpr) +.if \n(.H>23 .if \n(.V>19 \ +\{\ +. ds : e +. ds 8 ss +. ds o a +. ds d- d\h'-1'\(ga +. ds D- D\h'-1'\(hy +. ds th \o'bp' +. ds Th \o'LP' +. ds ae ae +. ds Ae AE +.\} +.rm #[ #] #H #V #F C +.\" ======================================================================== +.\" +.IX Title "xpamb 1" +.TH xpamb 1 "July 23, 2013" "version 2.1.15" "SAORD Documentation" +.\" For nroff, turn off justification. Always turn off hyphenation; it makes +.\" way too many mistakes in technical documents. +.if n .ad l +.nh +.SH "NAME" +\&\fBxpamb: the \s-1XPA\s0 Message Bus\fR +.SH "SYNOPSIS" +.IX Header "SYNOPSIS" +The xpamb program can act as a \*(L"classical\*(R" message bus interface +between clients and servers. A client can send a data request to +the message bus, which then interfaces with multiple servers and +returns the data back to the client. +.SH "OPTIONS" +.IX Header "OPTIONS" +For xpaset, several optional switches are used to save data and +manipulate the stored data: +.IP "\(bu" 4 +\&\fB\-data [name]\fR +.Sp +Add the supplied data buffer to a pool of stored data buffers, +using the specified name as a unique identifier for later retrieval. +An error occurs if the name already exists (use either \fBreplace\fR +or \fBdel\fR to rectify this). The \fB\-add\fR switch is supported +for backwards compatibility with xpa 2.0. +.IP "\(bu" 4 +\&\fB\-replace [name]\fR +.Sp +Replace previously existing stored data having the same unique name +with new data. This essentially is a combination of the \fBdel\fR +and \fBdata\fR commands. +.IP "\(bu" 4 +\&\fB\-info [\*(L"'info string'\*(R"]\fR +.Sp +When adding a data buffer, you can specify an informational +string to be stored with that data. This string will be returned +by xpaget: +.Sp +.Vb 1 +\& xpaget xpamb foo \-info +.Ve +.Sp +(along with other information such as the date/time of storage and the size of +the data buffer) if the \-info switch is specified. If the info string contains +spaces, you must enclose it in \fBtwo\fR sets of quotes: +.Sp +.Vb 1 +\& cat foo | xpaset xpamb \-store foo \-info "\*(Aqthis is info on foo\*(Aq" +.Ve +.Sp +The first set of quotes is removed by the shell while the second is used to +delineate the info string. +.IP "\(bu" 4 +\&\fB\-send [name]\fR +.Sp +Broadcast the stored data buffer to the named template. +.IP "\(bu" 4 +\&\fB\-del [name]\fR +.Sp +Delete the named data buffer and free all allocated space. +.PP +Switches can be used in any combination that makes sense. For example: +.PP +.Vb 1 +\& cat foo.fits | xpaset xpamb \-store foo \-info "FITS" "DS9:*" fits foo.fits +.Ve +.PP +will broadcast the foo.fits image to all access points of class +\&\fB\s-1DS9\s0\fR. In addition, the foo.fits file will be stored under the +name of \fBfoo\fR for later manipulation such as: +.PP +.Vb 1 +\& xpaset \-p xpamb \-send foo "DS9:*" fits foo.fits +.Ve +.PP +will re-broadcast the foo.fits image to all access points of class \*(L"\s-1DS9\s0\*(R". +.SH "DESCRIPTION" +.IX Header "DESCRIPTION" +A \*(L"classical\*(R" message bus (such as ToolTalk) consists of servers and +clients, along with a mediating program that transfers data between +different processes. \s-1XPA\s0 takes a slightly different approach in that +communication between clients and servers is direct. This generally +is the correct technique when there is only one connection (or even a +small number of connections), but can become inefficient for the +serving program if a large amount of data is being transferred to many +clients. For example, if a real-time data acquisition program is +broadcasting a \s-1FITS\s0 image to several clients, it would need to +transmit that image to each client individually. This might interfere +with its own processing cycles. The preferable mechanism would be to +pass the image off to an intermediate program that can then broadcast +the data to the several clients. +.PP +The \fBxpamb\fR program can alleviate such problems by functioning +as a message bus in cases where such an intermediary process is +wanted. It pre-defines a single access point named +\&\fBXPAMB:xpamb\fR to which data can be sent for re-broadcast. You +also can tell \fBxpamb\fR to save the data, and associate with that +data a new access point, so that it can be retrieved later on. +.PP +All interaction with \fBxpamb\fR is performed through +\&\fBxpaset\fR and \fBxpaget\fR (or the corresponding \s-1API\s0 +routines, \fB\f(BIXPASet()\fB\fR and \fB\f(BIXPAGet()\fB\fR) to the +\&\fBXPAMB:xpamb\fR access point. That is, \fBxpamb\fR is just +another XPA-enabled program that responds to requests from +clients. The paramlist is used to specify the targets to which +the data will be for re-broadcast, as well as the re-broadcast paramlist: +.PP +.Vb 1 +\& data | xpaset xpamb [switches] broadcast\-target broadcast\-paramlist +.Ve +.PP +Optional switches are used to store data, and manipulate stored data, +and are described below. +.PP +In its simplest form, you can, for example, send a \s-1FITS\s0 image to xpamb for +broadcasting to all ds9 image simply by executing: +.PP +.Vb 1 +\& cat foo.fits | xpaset xpamb "DS9:*" fits foo.fits +.Ve +.PP +Since \fB\s-1DS9\s0\fR is the class name for the ds9 image display +program, this will result in the \s-1FITS\s0 image being re-sent to all fits +access points for all active image display programs. +.PP +You can send stored data and new data to the same set of access points at +the same time. The stored data always is send first, followed by the new +data: +.PP +.Vb 1 +\& cat foo2.fits | xpaset xpamb \-send foo "DS9:*" fits foo.fits +.Ve +.PP +will first send the foo.fits file, and then the foo2.fits file to all +access points of class \fB\s-1DS9\s0\fR. Notice that in this example, +the foo2.fits file is not stored, but it could be stored by using the +\&\fB\-store [name]\fR switch on the command line. +.PP +The \fBxpaget\fR command can be used to retrieve a data from \s-1XPA\s0 +access points or from a stored data buffer, or retrieve information +about a stored data buffer. If no arguments are given: +.PP +.Vb 1 +\& xpaget xpamb +.Ve +.PP +then information about all currently stored data buffers is returned. This +information includes the data and time at which the data was stored, the +size in bytes of the data, and the supplied info string. +.PP +If arguments are specified, they will be in the form: +.PP +.Vb 1 +\& xpaget xpamb [\-info] [\-data] [name [paramlist]] +.Ve +.PP +If the optional \fB\-info\fR and/or \fB\-data\fR switches are specified, then +information and/or data will be returned for the named data buffer +following the switches. You can use either or both of these switches +in a single command. For example, if the \-info switch is used: +.PP +.Vb 1 +\& xpaget xpamb \-info foo +.Ve +.PP +then the info about that stored data buffer will be returned. +If the \-data is used with a specific name: +.PP +.Vb 1 +\& xpaget xpamb \-data foo +.Ve +.PP +then the stored data itself will be returned. If both are used: +.PP +.Vb 1 +\& xpaget xpamb \-info \-data foo +.Ve +.PP +then the info will be returned, followed by the data. Note that it is an +error to specify one of these switches without a data buffer name and that +the paramlist will be ignored. +.PP +If neither the \fB\-info\fR or \fB\-data\fR switch is specified, then +the name refers to an \s-1XPA\s0 access point (with an optional paramlist +following). +For example: +.PP +.Vb 1 +\& xpaget xpamb ds9 file +.Ve +.PP +is equivalent to: +.PP +.Vb 1 +\& xpaget ds9 file +.Ve +.SH "SEE ALSO" +.IX Header "SEE ALSO" +See xpa(n) for a list of \s-1XPA\s0 help pages diff --git a/xpa/man/man1/xpans.1 b/xpa/man/man1/xpans.1 new file mode 100644 index 0000000..3573725 --- /dev/null +++ b/xpa/man/man1/xpans.1 @@ -0,0 +1,331 @@ +.\" Automatically generated by Pod::Man 2.22 (Pod::Simple 3.13) +.\" +.\" Standard preamble: +.\" ======================================================================== +.de Sp \" Vertical space (when we can't use .PP) +.if t .sp .5v +.if n .sp +.. +.de Vb \" Begin verbatim text +.ft CW +.nf +.ne \\$1 +.. +.de Ve \" End verbatim text +.ft R +.fi +.. +.\" Set up some character translations and predefined strings. \*(-- will +.\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left +.\" double quote, and \*(R" will give a right double quote. \*(C+ will +.\" give a nicer C++. Capital omega is used to do unbreakable dashes and +.\" therefore won't be available. \*(C` and \*(C' expand to `' in nroff, +.\" nothing in troff, for use with C<>. +.tr \(*W- +.ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p' +.ie n \{\ +. ds -- \(*W- +. ds PI pi +. if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch +. if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch +. ds L" "" +. ds R" "" +. ds C` "" +. ds C' "" +'br\} +.el\{\ +. ds -- \|\(em\| +. ds PI \(*p +. ds L" `` +. ds R" '' +'br\} +.\" +.\" Escape single quotes in literal strings from groff's Unicode transform. +.ie \n(.g .ds Aq \(aq +.el .ds Aq ' +.\" +.\" If the F register is turned on, we'll generate index entries on stderr for +.\" titles (.TH), headers (.SH), subsections (.SS), items (.Ip), and index +.\" entries marked with X<> in POD. Of course, you'll have to process the +.\" output yourself in some meaningful fashion. +.ie \nF \{\ +. de IX +. tm Index:\\$1\t\\n%\t"\\$2" +.. +. nr % 0 +. rr F +.\} +.el \{\ +. de IX +.. +.\} +.\" +.\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2). +.\" Fear. Run. Save yourself. No user-serviceable parts. +. \" fudge factors for nroff and troff +.if n \{\ +. ds #H 0 +. ds #V .8m +. ds #F .3m +. ds #[ \f1 +. ds #] \fP +.\} +.if t \{\ +. ds #H ((1u-(\\\\n(.fu%2u))*.13m) +. ds #V .6m +. ds #F 0 +. ds #[ \& +. ds #] \& +.\} +. \" simple accents for nroff and troff +.if n \{\ +. ds ' \& +. ds ` \& +. ds ^ \& +. ds , \& +. ds ~ ~ +. ds / +.\} +.if t \{\ +. ds ' \\k:\h'-(\\n(.wu*8/10-\*(#H)'\'\h"|\\n:u" +. ds ` \\k:\h'-(\\n(.wu*8/10-\*(#H)'\`\h'|\\n:u' +. ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'^\h'|\\n:u' +. ds , \\k:\h'-(\\n(.wu*8/10)',\h'|\\n:u' +. ds ~ \\k:\h'-(\\n(.wu-\*(#H-.1m)'~\h'|\\n:u' +. ds / \\k:\h'-(\\n(.wu*8/10-\*(#H)'\z\(sl\h'|\\n:u' +.\} +. \" troff and (daisy-wheel) nroff accents +.ds : \\k:\h'-(\\n(.wu*8/10-\*(#H+.1m+\*(#F)'\v'-\*(#V'\z.\h'.2m+\*(#F'.\h'|\\n:u'\v'\*(#V' +.ds 8 \h'\*(#H'\(*b\h'-\*(#H' +.ds o \\k:\h'-(\\n(.wu+\w'\(de'u-\*(#H)/2u'\v'-.3n'\*(#[\z\(de\v'.3n'\h'|\\n:u'\*(#] +.ds d- \h'\*(#H'\(pd\h'-\w'~'u'\v'-.25m'\f2\(hy\fP\v'.25m'\h'-\*(#H' +.ds D- D\\k:\h'-\w'D'u'\v'-.11m'\z\(hy\v'.11m'\h'|\\n:u' +.ds th \*(#[\v'.3m'\s+1I\s-1\v'-.3m'\h'-(\w'I'u*2/3)'\s-1o\s+1\*(#] +.ds Th \*(#[\s+2I\s-2\h'-\w'I'u*3/5'\v'-.3m'o\v'.3m'\*(#] +.ds ae a\h'-(\w'a'u*4/10)'e +.ds Ae A\h'-(\w'A'u*4/10)'E +. \" corrections for vroff +.if v .ds ~ \\k:\h'-(\\n(.wu*9/10-\*(#H)'\s-2\u~\d\s+2\h'|\\n:u' +.if v .ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'\v'-.4m'^\v'.4m'\h'|\\n:u' +. \" for low resolution devices (crt and lpr) +.if \n(.H>23 .if \n(.V>19 \ +\{\ +. ds : e +. ds 8 ss +. ds o a +. ds d- d\h'-1'\(ga +. ds D- D\h'-1'\(hy +. ds th \o'bp' +. ds Th \o'LP' +. ds ae ae +. ds Ae AE +.\} +.rm #[ #] #H #V #F C +.\" ======================================================================== +.\" +.IX Title "xpans 1" +.TH xpans 1 "July 23, 2013" "version 2.1.15" "SAORD Documentation" +.\" For nroff, turn off justification. Always turn off hyphenation; it makes +.\" way too many mistakes in technical documents. +.if n .ad l +.nh +.SH "NAME" +\&\fBxpans: the \s-1XPA\s0 Name Server\fR +.SH "SYNOPSIS" +.IX Header "SYNOPSIS" +.Vb 1 +\& xpans [\-h] [\-e] [\-k sec] [\-p port] [\-l log] [\-s security log] [\-P n] +.Ve +.SH "OPTIONS" +.IX Header "OPTIONS" +.Vb 8 +\& \-h print help message +\& \-e exit when there are no more XPA connections +\& \-k send keepalive messages every n sec +\& \-l log data base entries to specified file +\& \-p listen for connections on specified port +\& \-s log security info for each connection to specified file +\& \-P accept proxy requests (P=1) using separate thread (P=2) +\& \-\-version display version and exit +.Ve +.SH "DESCRIPTION" +.IX Header "DESCRIPTION" +The xpans name server is an XPA-enabled program that is used to +manage the names and ports of \s-1XPA\s0 access points. It is started +automatically when an \s-1XPA\s0 access point is registered. You can access +the name server using xpaget to get a list of registered access points. +.PP +The \fIxpans\fR name server provides a crucial link between \s-1XPA\s0 +clients and servers. When an \s-1XPA\s0 server defines an access point using +\&\fIXPANew()\fR, \fIXPACmdNew()\fR, or \fIXPAInfoNew()\fR, the name of the access point +is registered in the name service, along with connection information. +The name server then matches class:name templates passed to it by \s-1XPA\s0 +clients with these registered entries, so that the clients can +communicate with the appropriate servers. +.PP +The socket connection between an XPA-enabled program and +\&\fIxpans\fR is kept open until the former exits (or explicitly +closes the connection). Apparently, some Internet equipment (e.g. \s-1DSL\s0 +modems) can cause such a connection to time-out after a period of +inactivity. To prevent this from happening, you can use the \-k +[sec] switch to send a short keep-alive message to each open +connection after the specified time delay. (Note that this +application level use of keep-alive is necessary only if you are +serving XPA-enabled clients over the Internet and have to deal with +long-term connections involving \s-1DSL\s0 or similar equipment. \s-1XPA\s0 uses +the ordinary socket-level keep-alive, which works for all other cases.) +\&\s-1NB\s0 (12/2/2009): Out-of-band (\s-1URG\s0) \s-1TCP\s0 data, used by xpans +keep-alive, is changed by some Cisco routers into in-band data. +Encountering such a router will break the keep-alive function and may +break your \s-1XPA\s0 server as well. Proceed with caution! +.PP +The \fIxpans\fR program will be started automatically (assuming it +can be found in the user's path) when the first \s-1XPA\s0 access point is +registered. It therefore need not be started explicitly. However, +when started automatically, the \fI\-e\fR switch is used, so that +the name server will exit when there are no more \s-1XPA\s0 access points +registered. If you wish to keep the name server running continually, +simply start it manually without the \fI\-e\fR switch. +.PP +The name server will keep a log of registered access points if the +\&\fI\-l [log]\fR switch is used on the command line (this is the +case for automatic start-up). The log contains enough name and connection +information to allow you to re-register all \s-1XPA\s0 access points in case +the name server process is terminated prematurely. For example, after +the ds9 access point is registered,the log will contain the entry: +.PP +.Vb 1 +\& add 838e2f67:1863 ds9 ds9 gs eric +.Ve +.PP +If \fIxpans\fR is terminated but ds9 still is running, you +can re-register both access points for the ds9 process by running: +.PP +.Vb 1 +\& xpaset \-p 838e2f67:1863 \-nsconnect +.Ve +.PP +Notice that the ip:port specifier is used with \fIxpaset\fR to bypass +the need for contacting the name server (which does not have the name +registered yet!) +.PP +The name server will keep a log of security information if the \-s +[security log] switch is used on the command line. For each +accepted connection, (including connections via the \fIxpaget\fR +command), information will be logged about the host issuing the +command and the parameters passed into the program. This is most +useful when \fIxpans\fR is accepting connections from untrusted +machines. +.PP +When an \s-1XPA\s0 access point is removed by a server using \fI\fIXPAFree()\fI\fR, +the access information is removed from the name server. If an +XPA-enabled process is terminated, all names registered by that process +will be removed automatically. The log file is always updated to +reflect the currently registered access points. +.PP +The name server itself has an \s-1XPA\s0 access point names \fIxpans\fR +registered through which you can find out information about currently +registered access points (assuming you have access to the name server; +see \s-1XPA\s0 Access Control for more information). +For each registered access point, the following information is returned: +.PP +.Vb 5 +\& class # class of the access point +\& name # name of the access point +\& access # allowed access (g=xpaget,s=xpaset,i=xpainfo) +\& id # socket access method (host:port for inet, file for local/unix) +\& user # user name of access point owner +.Ve +.PP +For example, to display all currently registered access points, simply execute: +.PP +.Vb 1 +\& xpaget xpans +.Ve +.PP +Continuing the example of ds9 above, this will return: +.PP +.Vb 1 +\& DS9 ds9 gs 838e2f67:1863 eric +.Ve +.PP +If the same program has been started with different \s-1XPA\s0 access names, +you can look up only names matching a specified template. For example, +assume that ds9 has been started up using: +.PP +.Vb 3 +\& ds9 & +\& ds9 \-title ds9\-1\-eric & +\& ds9 \-title ds9\-2\-eric & +.Ve +.PP +To lookup all ds9 access points which end in \*(L".eric\*(R" and which can +be accessed using \fIxpaset\fR, use: +.PP +.Vb 1 +\& xpaget xpans "DS9:*.eric" "s" "*" +.Ve +.PP +This will return: +.PP +.Vb 2 +\& DS9 ds9\-2\-eric gs 838e29d3:42102 eric +\& DS9 ds9\-1\-eric gs 838e29d3:42105 eric +.Ve +.PP +The third argument \*(L"*\*(R" requests all access points from all users. +You also can specify a specific user name and only access points +registered by that user will be returned. +.PP +The name server uses the \fI\s-1XPA_METHOD\s0\fR environment variable +to determine whether it should listen for requests on \s-1INET\s0 or \s-1LOCAL\s0 +sockets. Since \s-1XPA\s0 access points also use this environment variable, +the choice of socket method will be consistent. Note that, when \s-1INET\s0 +sockets are used, a local server can be accessed from remote machines +if the \fI\s-1XPA_NSINET\s0\fR environment variable is set to point to +the local machine. See +\&\s-1XPA\s0 Environment Variables +for more information. +.PP +An experimental feature of xpans is its ability to act as a proxy to +\&\s-1XPA\s0 servers behind firewalls that want to communicate with external +processes. The basic idea is the following: an \s-1XPA\s0 server (call it +\&\*(L"foo\*(R") on host1, possibly behind a firewall, makes a remote connection +to a proxy-enabled xpans program on host2 (specifying host2's \s-1XPA\s0 method). +For example: +.PP +.Vb 1 +\& xpaset \-p foo \-remote \*(Aqhost2:28571\*(Aq + \-proxy # on host1 +.Ve +.PP +When this is done, host2 can use xpaset, xpaget, and xpainfo calls to +communicate with the \s-1XPA\s0 server foo. All command communication is +performed via the xpans socket connection between foo on host1 and +xpans on host2 (which was initiated by foo from inside the firewall). +Data communication is similarly performed using a socket connection +initiated on host1 (usually with a port value two greater than the +port value of the main xpans socket connection). An xpaset or xpaget +call on host2 contacts xpans, which performs an \fIXPASet()\fR or \fIXPAGet()\fR +call to foo, passing commands and data back and forth between the two +programs. +.PP +By default, proxy connections are not allowed by xpans. If the \-P switch is +specified with a value of 1, proxy connection are allowed, but all proxy +communication is performed in the same thread as xpans processing. If +a value of 2 is specified, the proxy processing is performed in a +separate thread (assuming pthreads are supported on your system). +Because xpa callback processing of any type can take a long time and +therefore can interfere with normal xpans processing, threaded proxy +connections (\-P 2) are recommended. When using proxy connections, it +might also be useful to set the \s-1XPA_IOCALLSXPA\s0 environment variable, so +that multiple proxy requests can be handled at the same time, instead of +serially. +.PP +Note that this proxy interface to xpans is experimental. It is used +to provide remote data analysis capabilities on the Chandra-Ed system +using ds9. (See http://chandra\-ed.cfa.harvard.edu and +http://hea\-www.harvard.edu/saord/ds9 for more details). As always, please +contact us if you have problems or questions. +.SH "SEE ALSO" +.IX Header "SEE ALSO" +See xpa(n) for a list of \s-1XPA\s0 help pages diff --git a/xpa/man/man1/xpaset.1 b/xpa/man/man1/xpaset.1 new file mode 100644 index 0000000..943a708 --- /dev/null +++ b/xpa/man/man1/xpaset.1 @@ -0,0 +1,217 @@ +.\" Automatically generated by Pod::Man 2.22 (Pod::Simple 3.13) +.\" +.\" Standard preamble: +.\" ======================================================================== +.de Sp \" Vertical space (when we can't use .PP) +.if t .sp .5v +.if n .sp +.. +.de Vb \" Begin verbatim text +.ft CW +.nf +.ne \\$1 +.. +.de Ve \" End verbatim text +.ft R +.fi +.. +.\" Set up some character translations and predefined strings. \*(-- will +.\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left +.\" double quote, and \*(R" will give a right double quote. \*(C+ will +.\" give a nicer C++. Capital omega is used to do unbreakable dashes and +.\" therefore won't be available. \*(C` and \*(C' expand to `' in nroff, +.\" nothing in troff, for use with C<>. +.tr \(*W- +.ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p' +.ie n \{\ +. ds -- \(*W- +. ds PI pi +. if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch +. if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch +. ds L" "" +. ds R" "" +. ds C` "" +. ds C' "" +'br\} +.el\{\ +. ds -- \|\(em\| +. ds PI \(*p +. ds L" `` +. ds R" '' +'br\} +.\" +.\" Escape single quotes in literal strings from groff's Unicode transform. +.ie \n(.g .ds Aq \(aq +.el .ds Aq ' +.\" +.\" If the F register is turned on, we'll generate index entries on stderr for +.\" titles (.TH), headers (.SH), subsections (.SS), items (.Ip), and index +.\" entries marked with X<> in POD. Of course, you'll have to process the +.\" output yourself in some meaningful fashion. +.ie \nF \{\ +. de IX +. tm Index:\\$1\t\\n%\t"\\$2" +.. +. nr % 0 +. rr F +.\} +.el \{\ +. de IX +.. +.\} +.\" +.\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2). +.\" Fear. Run. Save yourself. No user-serviceable parts. +. \" fudge factors for nroff and troff +.if n \{\ +. ds #H 0 +. ds #V .8m +. ds #F .3m +. ds #[ \f1 +. ds #] \fP +.\} +.if t \{\ +. ds #H ((1u-(\\\\n(.fu%2u))*.13m) +. ds #V .6m +. ds #F 0 +. ds #[ \& +. ds #] \& +.\} +. \" simple accents for nroff and troff +.if n \{\ +. ds ' \& +. ds ` \& +. ds ^ \& +. ds , \& +. ds ~ ~ +. ds / +.\} +.if t \{\ +. ds ' \\k:\h'-(\\n(.wu*8/10-\*(#H)'\'\h"|\\n:u" +. ds ` \\k:\h'-(\\n(.wu*8/10-\*(#H)'\`\h'|\\n:u' +. ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'^\h'|\\n:u' +. ds , \\k:\h'-(\\n(.wu*8/10)',\h'|\\n:u' +. ds ~ \\k:\h'-(\\n(.wu-\*(#H-.1m)'~\h'|\\n:u' +. ds / \\k:\h'-(\\n(.wu*8/10-\*(#H)'\z\(sl\h'|\\n:u' +.\} +. \" troff and (daisy-wheel) nroff accents +.ds : \\k:\h'-(\\n(.wu*8/10-\*(#H+.1m+\*(#F)'\v'-\*(#V'\z.\h'.2m+\*(#F'.\h'|\\n:u'\v'\*(#V' +.ds 8 \h'\*(#H'\(*b\h'-\*(#H' +.ds o \\k:\h'-(\\n(.wu+\w'\(de'u-\*(#H)/2u'\v'-.3n'\*(#[\z\(de\v'.3n'\h'|\\n:u'\*(#] +.ds d- \h'\*(#H'\(pd\h'-\w'~'u'\v'-.25m'\f2\(hy\fP\v'.25m'\h'-\*(#H' +.ds D- D\\k:\h'-\w'D'u'\v'-.11m'\z\(hy\v'.11m'\h'|\\n:u' +.ds th \*(#[\v'.3m'\s+1I\s-1\v'-.3m'\h'-(\w'I'u*2/3)'\s-1o\s+1\*(#] +.ds Th \*(#[\s+2I\s-2\h'-\w'I'u*3/5'\v'-.3m'o\v'.3m'\*(#] +.ds ae a\h'-(\w'a'u*4/10)'e +.ds Ae A\h'-(\w'A'u*4/10)'E +. \" corrections for vroff +.if v .ds ~ \\k:\h'-(\\n(.wu*9/10-\*(#H)'\s-2\u~\d\s+2\h'|\\n:u' +.if v .ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'\v'-.4m'^\v'.4m'\h'|\\n:u' +. \" for low resolution devices (crt and lpr) +.if \n(.H>23 .if \n(.V>19 \ +\{\ +. ds : e +. ds 8 ss +. ds o a +. ds d- d\h'-1'\(ga +. ds D- D\h'-1'\(hy +. ds th \o'bp' +. ds Th \o'LP' +. ds ae ae +. ds Ae AE +.\} +.rm #[ #] #H #V #F C +.\" ======================================================================== +.\" +.IX Title "xpaset 1" +.TH xpaset 1 "July 23, 2013" "version 2.1.15" "SAORD Documentation" +.\" For nroff, turn off justification. Always turn off hyphenation; it makes +.\" way too many mistakes in technical documents. +.if n .ad l +.nh +.SH "NAME" +\&\fBxpaset: send data to one or more \s-1XPA\s0 servers\fR +.SH "SYNOPSIS" +.IX Header "SYNOPSIS" +<data> | xpaset [\-h] [\-i nsinet] [\-m method] [\-n] [\-p] [\-s] [\-t sval,lval] [\-u users] [\-v] <template|host:port> [paramlist] +.SH "OPTIONS" +.IX Header "OPTIONS" +.Vb 10 +\& \-h print help message +\& \-i access XPA point on different machine (override XPA_NSINET) +\& \-m override XPA_METHOD environment variable +\& \-n don\*(Aqt wait for the status message after server completes +\& \-p don\*(Aqt read (or send) buf data from stdin +\& \-s enter server mode +\& \-t [s,l] set short and long timeouts (override XPA_[SHORT,LONG]_TIMEOUT) +\& \-u [users] XPA points can be from specified users (override XPA_NSUSERS) +\& \-v verify message to stdout +\& \-\-version display version and exit +.Ve +.SH "DESCRIPTION" +.IX Header "DESCRIPTION" +Data read from stdin will be sent to access points matching the +template +or host:port. +A set of qualifying parameters can be appended. +.PP +Normally, xpaset reads data input from stdin until \s-1EOF\s0 and sends those +data to the \s-1XPA\s0 target, along with parameters entered on the command +line. For example to send a \s-1FITS\s0 file to the ds9 image display: +.PP +.Vb 1 +\& cat foo.fits | xpaset ds9 fits +.Ve +.PP +Sometimes, however, it is desirable to send only parameters to an \s-1XPA\s0 +access point, without sending data. For such cases, use the \-p switch to +indicate that there is no data being send to stdin. For example, to +change the colormap used by the ds9 image display program, use: +.PP +.Vb 1 +\& csh> xpaset \-p ds9 cmap Heat +.Ve +.PP +Of course, this also can be accomplished by sending \s-1EOF\s0 to stdin in +any of the usual ways: +.PP +.Vb 4 +\& csh> echo "" | xpaset ds9 cmap Heat +\& csh> xpaget ds9 cmap Heat < /dev/null +\& csh> xpaset ds9 cmap Heat +\& ^D # Ctl\-D signals EOF +.Ve +.PP +The \-s switch puts xpaset into server mode, in which commands and data +can be sent to access points without having to run xpaset multiple times. +(Its not clear if this buys you much!) The syntax for sending commands +in server mode is: +.PP +.Vb 8 +\& csh> xpaset \-s +\& xpaset ds9 colormap I8 +\& ^D +\& xpaset ds9 regions +\& circle 200 300 40 +\& circle 300 400 50 +\& ^D +\&etc. +.Ve +.PP +After the required \*(L"xpaset\*(R" command is specified, optional \s-1ASCII\s0 data +can be appended (as in the region example). A single data/command set is +delimited by ^D. Note that typing ^D when a command is expected terminates +the program. +.PP +\&\s-1NB:\s0 server mode only works from the terminal and only \s-1ASCII\s0 data can be +sent in this way. +.PP +\&\fBExamples:\fR +.PP +.Vb 2 +\& csh> xpaset ds9 file < foo.fits +\& csh> echo "stop" | xpaset myhost:12345 +.Ve +.SH "SEE ALSO" +.IX Header "SEE ALSO" +See xpa(n) for a list of \s-1XPA\s0 help pages diff --git a/xpa/man/man3/xpaaccess.3 b/xpa/man/man3/xpaaccess.3 new file mode 100644 index 0000000..a7e25e8 --- /dev/null +++ b/xpa/man/man3/xpaaccess.3 @@ -0,0 +1,233 @@ +.\" Automatically generated by Pod::Man 2.22 (Pod::Simple 3.13) +.\" +.\" Standard preamble: +.\" ======================================================================== +.de Sp \" Vertical space (when we can't use .PP) +.if t .sp .5v +.if n .sp +.. +.de Vb \" Begin verbatim text +.ft CW +.nf +.ne \\$1 +.. +.de Ve \" End verbatim text +.ft R +.fi +.. +.\" Set up some character translations and predefined strings. \*(-- will +.\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left +.\" double quote, and \*(R" will give a right double quote. \*(C+ will +.\" give a nicer C++. Capital omega is used to do unbreakable dashes and +.\" therefore won't be available. \*(C` and \*(C' expand to `' in nroff, +.\" nothing in troff, for use with C<>. +.tr \(*W- +.ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p' +.ie n \{\ +. ds -- \(*W- +. ds PI pi +. if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch +. if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch +. ds L" "" +. ds R" "" +. ds C` "" +. ds C' "" +'br\} +.el\{\ +. ds -- \|\(em\| +. ds PI \(*p +. ds L" `` +. ds R" '' +'br\} +.\" +.\" Escape single quotes in literal strings from groff's Unicode transform. +.ie \n(.g .ds Aq \(aq +.el .ds Aq ' +.\" +.\" If the F register is turned on, we'll generate index entries on stderr for +.\" titles (.TH), headers (.SH), subsections (.SS), items (.Ip), and index +.\" entries marked with X<> in POD. Of course, you'll have to process the +.\" output yourself in some meaningful fashion. +.ie \nF \{\ +. de IX +. tm Index:\\$1\t\\n%\t"\\$2" +.. +. nr % 0 +. rr F +.\} +.el \{\ +. de IX +.. +.\} +.\" +.\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2). +.\" Fear. Run. Save yourself. No user-serviceable parts. +. \" fudge factors for nroff and troff +.if n \{\ +. ds #H 0 +. ds #V .8m +. ds #F .3m +. ds #[ \f1 +. ds #] \fP +.\} +.if t \{\ +. ds #H ((1u-(\\\\n(.fu%2u))*.13m) +. ds #V .6m +. ds #F 0 +. ds #[ \& +. ds #] \& +.\} +. \" simple accents for nroff and troff +.if n \{\ +. ds ' \& +. ds ` \& +. ds ^ \& +. ds , \& +. ds ~ ~ +. ds / +.\} +.if t \{\ +. ds ' \\k:\h'-(\\n(.wu*8/10-\*(#H)'\'\h"|\\n:u" +. ds ` \\k:\h'-(\\n(.wu*8/10-\*(#H)'\`\h'|\\n:u' +. ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'^\h'|\\n:u' +. ds , \\k:\h'-(\\n(.wu*8/10)',\h'|\\n:u' +. ds ~ \\k:\h'-(\\n(.wu-\*(#H-.1m)'~\h'|\\n:u' +. ds / \\k:\h'-(\\n(.wu*8/10-\*(#H)'\z\(sl\h'|\\n:u' +.\} +. \" troff and (daisy-wheel) nroff accents +.ds : \\k:\h'-(\\n(.wu*8/10-\*(#H+.1m+\*(#F)'\v'-\*(#V'\z.\h'.2m+\*(#F'.\h'|\\n:u'\v'\*(#V' +.ds 8 \h'\*(#H'\(*b\h'-\*(#H' +.ds o \\k:\h'-(\\n(.wu+\w'\(de'u-\*(#H)/2u'\v'-.3n'\*(#[\z\(de\v'.3n'\h'|\\n:u'\*(#] +.ds d- \h'\*(#H'\(pd\h'-\w'~'u'\v'-.25m'\f2\(hy\fP\v'.25m'\h'-\*(#H' +.ds D- D\\k:\h'-\w'D'u'\v'-.11m'\z\(hy\v'.11m'\h'|\\n:u' +.ds th \*(#[\v'.3m'\s+1I\s-1\v'-.3m'\h'-(\w'I'u*2/3)'\s-1o\s+1\*(#] +.ds Th \*(#[\s+2I\s-2\h'-\w'I'u*3/5'\v'-.3m'o\v'.3m'\*(#] +.ds ae a\h'-(\w'a'u*4/10)'e +.ds Ae A\h'-(\w'A'u*4/10)'E +. \" corrections for vroff +.if v .ds ~ \\k:\h'-(\\n(.wu*9/10-\*(#H)'\s-2\u~\d\s+2\h'|\\n:u' +.if v .ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'\v'-.4m'^\v'.4m'\h'|\\n:u' +. \" for low resolution devices (crt and lpr) +.if \n(.H>23 .if \n(.V>19 \ +\{\ +. ds : e +. ds 8 ss +. ds o a +. ds d- d\h'-1'\(ga +. ds D- D\h'-1'\(hy +. ds th \o'bp' +. ds Th \o'LP' +. ds ae ae +. ds Ae AE +.\} +.rm #[ #] #H #V #F C +.\" ======================================================================== +.\" +.IX Title "xpaaccess 3" +.TH xpaaccess 3 "July 23, 2013" "version 2.1.15" "SAORD Documentation" +.\" For nroff, turn off justification. Always turn off hyphenation; it makes +.\" way too many mistakes in technical documents. +.if n .ad l +.nh +.SH "NAME" +XPAAccess: return XPA access points matching +template (XPA 2.1 and above) +.SH "SYNOPSIS" +.IX Header "SYNOPSIS" +.Vb 1 +\& #include <xpa.h> +\& +\& int XPAAccess(XPA xpa, +\& char *template, char *paramlist, char *mode, +\& char **names, char **messages, int n); +.Ve +.SH "DESCRIPTION" +.IX Header "DESCRIPTION" +The XPAAccess routine returns the public access points that match the +specified second argument template and +have the specified access type. +.PP +A +template +of the form \*(L"class1:name1\*(R" is sent to the +\&\s-1XPA\s0 name server, which returns a list of at most n matching \s-1XPA\s0 +servers. A connection is established with each of these servers and +the paramlist string is passed to the server as the data transfer +request is initiated. If an \s-1XPA\s0 struct is passed to the call, then the +persistent connections are updated as described above. Otherwise, +temporary connections are made to the servers (which will be closed +when the call completes). +.PP +The \fIXPAAccess()\fR routine retrieves names from at most n \s-1XPA\s0 servers +that match the specified template and that were checked for access +using the specified mode. The return string contains both the +class:name and ip:port. If a given server returned an error or the +server callback sends a message back to the client, then the message +will be stored in the associated element of the messages array. +\&\s-1NB:\s0 if specified, the name and messages arrays must be of size n or greater. +.PP +The returned message string will be of the form: +.PP +.Vb 1 +\& XPA$ERROR error\-message (class:name ip:port) +.Ve +.PP +Note that names of matching registered access points are always +returned but may not be valid; it is not sufficient to assume that the +returned number of access points is the number of valid access points. +Rather, it is essential to check the messages array for error +messages. Any string in the messages array is an error message and +indicated that the associated access point is not available. +.PP +For example, assume that a server registers a number of access points +but delays entering its event loop. If a call to \fIXPAAccess()\fR is made +before the event loop is entered, the call will timeout (after waiting +for the long timeout period) and return an error of the form: +.PP +.Vb 1 +\& XPA$ERROR: timeout waiting for server authentication (XPA:xpa1) +.Ve +.PP +The error means that the \s-1XPA\s0 access point has been registered but is +not yet available (because events are not being processed). When the +server finally enters its event loop, subsequent calls to \fIXPAAccess()\fR +will return successfully. +.PP +\&\s-1NB:\s0 This routine only works with \s-1XPA\s0 servers built with \s-1XPA\s0 2.1.x and later. +Servers with older versions of \s-1XPA\s0 will return the error message: +.PP +.Vb 1 +\& XPA$ERROR invalid xpa command in initialization string +.Ve +.PP +If you get this error message, then the old server actually is ready +for access, since it got to the point of fielding the query! The +xpaaccess program, for example, ignores this message in order to work +properly with older servers. +.PP +The third argument for \fIXPAAccess()\fR is the type of access and can be +any combination of: +.PP +.Vb 5 +\& type explanation +\& \-\-\-\-\-\- \-\-\-\-\-\-\-\-\-\-\- +\& g xpaget calls can be made on this access point +\& s xpaset calls can be made on this access point +\& i xpainfo calls can be made on this access point +.Ve +.PP +The mode string argument is of the form: \*(L"key1=value1,key2=value2,...\*(R" +The following keywords are recognized: +.PP +.Vb 3 +\& key value default explanation +\& \-\-\-\-\-\- \-\-\-\-\-\-\-\- \-\-\-\-\-\-\-\- \-\-\-\-\-\-\-\-\-\-\- +\& ack true/false true if false, don\*(Aqt wait for ack from server (after callback completes) +.Ve +.PP +The ack keyword is not very useful, since the server completes the callback +in order to return the data anyway. It is here for completion (and perhaps +for future usefulness). +.SH "SEE ALSO" +.IX Header "SEE ALSO" +See xpa(n) for a list of \s-1XPA\s0 help pages diff --git a/xpa/man/man3/xpaatexit.3 b/xpa/man/man3/xpaatexit.3 new file mode 100644 index 0000000..4ff2c7d --- /dev/null +++ b/xpa/man/man3/xpaatexit.3 @@ -0,0 +1,149 @@ +.\" Automatically generated by Pod::Man 2.22 (Pod::Simple 3.13) +.\" +.\" Standard preamble: +.\" ======================================================================== +.de Sp \" Vertical space (when we can't use .PP) +.if t .sp .5v +.if n .sp +.. +.de Vb \" Begin verbatim text +.ft CW +.nf +.ne \\$1 +.. +.de Ve \" End verbatim text +.ft R +.fi +.. +.\" Set up some character translations and predefined strings. \*(-- will +.\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left +.\" double quote, and \*(R" will give a right double quote. \*(C+ will +.\" give a nicer C++. Capital omega is used to do unbreakable dashes and +.\" therefore won't be available. \*(C` and \*(C' expand to `' in nroff, +.\" nothing in troff, for use with C<>. +.tr \(*W- +.ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p' +.ie n \{\ +. ds -- \(*W- +. ds PI pi +. if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch +. if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch +. ds L" "" +. ds R" "" +. ds C` "" +. ds C' "" +'br\} +.el\{\ +. ds -- \|\(em\| +. ds PI \(*p +. ds L" `` +. ds R" '' +'br\} +.\" +.\" Escape single quotes in literal strings from groff's Unicode transform. +.ie \n(.g .ds Aq \(aq +.el .ds Aq ' +.\" +.\" If the F register is turned on, we'll generate index entries on stderr for +.\" titles (.TH), headers (.SH), subsections (.SS), items (.Ip), and index +.\" entries marked with X<> in POD. Of course, you'll have to process the +.\" output yourself in some meaningful fashion. +.ie \nF \{\ +. de IX +. tm Index:\\$1\t\\n%\t"\\$2" +.. +. nr % 0 +. rr F +.\} +.el \{\ +. de IX +.. +.\} +.\" +.\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2). +.\" Fear. Run. Save yourself. No user-serviceable parts. +. \" fudge factors for nroff and troff +.if n \{\ +. ds #H 0 +. ds #V .8m +. ds #F .3m +. ds #[ \f1 +. ds #] \fP +.\} +.if t \{\ +. ds #H ((1u-(\\\\n(.fu%2u))*.13m) +. ds #V .6m +. ds #F 0 +. ds #[ \& +. ds #] \& +.\} +. \" simple accents for nroff and troff +.if n \{\ +. ds ' \& +. ds ` \& +. ds ^ \& +. ds , \& +. ds ~ ~ +. ds / +.\} +.if t \{\ +. ds ' \\k:\h'-(\\n(.wu*8/10-\*(#H)'\'\h"|\\n:u" +. ds ` \\k:\h'-(\\n(.wu*8/10-\*(#H)'\`\h'|\\n:u' +. ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'^\h'|\\n:u' +. ds , \\k:\h'-(\\n(.wu*8/10)',\h'|\\n:u' +. ds ~ \\k:\h'-(\\n(.wu-\*(#H-.1m)'~\h'|\\n:u' +. ds / \\k:\h'-(\\n(.wu*8/10-\*(#H)'\z\(sl\h'|\\n:u' +.\} +. \" troff and (daisy-wheel) nroff accents +.ds : \\k:\h'-(\\n(.wu*8/10-\*(#H+.1m+\*(#F)'\v'-\*(#V'\z.\h'.2m+\*(#F'.\h'|\\n:u'\v'\*(#V' +.ds 8 \h'\*(#H'\(*b\h'-\*(#H' +.ds o \\k:\h'-(\\n(.wu+\w'\(de'u-\*(#H)/2u'\v'-.3n'\*(#[\z\(de\v'.3n'\h'|\\n:u'\*(#] +.ds d- \h'\*(#H'\(pd\h'-\w'~'u'\v'-.25m'\f2\(hy\fP\v'.25m'\h'-\*(#H' +.ds D- D\\k:\h'-\w'D'u'\v'-.11m'\z\(hy\v'.11m'\h'|\\n:u' +.ds th \*(#[\v'.3m'\s+1I\s-1\v'-.3m'\h'-(\w'I'u*2/3)'\s-1o\s+1\*(#] +.ds Th \*(#[\s+2I\s-2\h'-\w'I'u*3/5'\v'-.3m'o\v'.3m'\*(#] +.ds ae a\h'-(\w'a'u*4/10)'e +.ds Ae A\h'-(\w'A'u*4/10)'E +. \" corrections for vroff +.if v .ds ~ \\k:\h'-(\\n(.wu*9/10-\*(#H)'\s-2\u~\d\s+2\h'|\\n:u' +.if v .ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'\v'-.4m'^\v'.4m'\h'|\\n:u' +. \" for low resolution devices (crt and lpr) +.if \n(.H>23 .if \n(.V>19 \ +\{\ +. ds : e +. ds 8 ss +. ds o a +. ds d- d\h'-1'\(ga +. ds D- D\h'-1'\(hy +. ds th \o'bp' +. ds Th \o'LP' +. ds ae ae +. ds Ae AE +.\} +.rm #[ #] #H #V #F C +.\" ======================================================================== +.\" +.IX Title "xpaatexit 3" +.TH xpaatexit 3 "July 23, 2013" "version 2.1.15" "SAORD Documentation" +.\" For nroff, turn off justification. Always turn off hyphenation; it makes +.\" way too many mistakes in technical documents. +.if n .ad l +.nh +.SH "NAME" +\&\fBXPAAtExit: install exit handler\fR +.SH "SYNOPSIS" +.IX Header "SYNOPSIS" +.Vb 1 +\& #include <xpa.h> +\& +\& void XPAAtExit(void); +.Ve +.SH "DESCRIPTION" +.IX Header "DESCRIPTION" +\&\fIXPAAtExit()\fR will install an exit handler using \fIatexit()\fR to run XPAFree on all +\&\s-1XPA\s0 access points. This might be useful in cases where Unix sockets are being +used: if an explicit call to \fIXPAFree()\fR is not made by the program, the Unix +socket file will not be deleted immediately without an atexit handler. (\s-1NB:\s0 this +call should not be made in a Tcl/Tk application. Accessing the Tcl native file +system after Tcl has shut down all file systems causes the Tcl/Tl program to +crash). diff --git a/xpa/man/man3/xpacleanup.3 b/xpa/man/man3/xpacleanup.3 new file mode 100644 index 0000000..57ec12e --- /dev/null +++ b/xpa/man/man3/xpacleanup.3 @@ -0,0 +1,151 @@ +.\" Automatically generated by Pod::Man 2.22 (Pod::Simple 3.13) +.\" +.\" Standard preamble: +.\" ======================================================================== +.de Sp \" Vertical space (when we can't use .PP) +.if t .sp .5v +.if n .sp +.. +.de Vb \" Begin verbatim text +.ft CW +.nf +.ne \\$1 +.. +.de Ve \" End verbatim text +.ft R +.fi +.. +.\" Set up some character translations and predefined strings. \*(-- will +.\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left +.\" double quote, and \*(R" will give a right double quote. \*(C+ will +.\" give a nicer C++. Capital omega is used to do unbreakable dashes and +.\" therefore won't be available. \*(C` and \*(C' expand to `' in nroff, +.\" nothing in troff, for use with C<>. +.tr \(*W- +.ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p' +.ie n \{\ +. ds -- \(*W- +. ds PI pi +. if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch +. if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch +. ds L" "" +. ds R" "" +. ds C` "" +. ds C' "" +'br\} +.el\{\ +. ds -- \|\(em\| +. ds PI \(*p +. ds L" `` +. ds R" '' +'br\} +.\" +.\" Escape single quotes in literal strings from groff's Unicode transform. +.ie \n(.g .ds Aq \(aq +.el .ds Aq ' +.\" +.\" If the F register is turned on, we'll generate index entries on stderr for +.\" titles (.TH), headers (.SH), subsections (.SS), items (.Ip), and index +.\" entries marked with X<> in POD. Of course, you'll have to process the +.\" output yourself in some meaningful fashion. +.ie \nF \{\ +. de IX +. tm Index:\\$1\t\\n%\t"\\$2" +.. +. nr % 0 +. rr F +.\} +.el \{\ +. de IX +.. +.\} +.\" +.\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2). +.\" Fear. Run. Save yourself. No user-serviceable parts. +. \" fudge factors for nroff and troff +.if n \{\ +. ds #H 0 +. ds #V .8m +. ds #F .3m +. ds #[ \f1 +. ds #] \fP +.\} +.if t \{\ +. ds #H ((1u-(\\\\n(.fu%2u))*.13m) +. ds #V .6m +. ds #F 0 +. ds #[ \& +. ds #] \& +.\} +. \" simple accents for nroff and troff +.if n \{\ +. ds ' \& +. ds ` \& +. ds ^ \& +. ds , \& +. ds ~ ~ +. ds / +.\} +.if t \{\ +. ds ' \\k:\h'-(\\n(.wu*8/10-\*(#H)'\'\h"|\\n:u" +. ds ` \\k:\h'-(\\n(.wu*8/10-\*(#H)'\`\h'|\\n:u' +. ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'^\h'|\\n:u' +. ds , \\k:\h'-(\\n(.wu*8/10)',\h'|\\n:u' +. ds ~ \\k:\h'-(\\n(.wu-\*(#H-.1m)'~\h'|\\n:u' +. ds / \\k:\h'-(\\n(.wu*8/10-\*(#H)'\z\(sl\h'|\\n:u' +.\} +. \" troff and (daisy-wheel) nroff accents +.ds : \\k:\h'-(\\n(.wu*8/10-\*(#H+.1m+\*(#F)'\v'-\*(#V'\z.\h'.2m+\*(#F'.\h'|\\n:u'\v'\*(#V' +.ds 8 \h'\*(#H'\(*b\h'-\*(#H' +.ds o \\k:\h'-(\\n(.wu+\w'\(de'u-\*(#H)/2u'\v'-.3n'\*(#[\z\(de\v'.3n'\h'|\\n:u'\*(#] +.ds d- \h'\*(#H'\(pd\h'-\w'~'u'\v'-.25m'\f2\(hy\fP\v'.25m'\h'-\*(#H' +.ds D- D\\k:\h'-\w'D'u'\v'-.11m'\z\(hy\v'.11m'\h'|\\n:u' +.ds th \*(#[\v'.3m'\s+1I\s-1\v'-.3m'\h'-(\w'I'u*2/3)'\s-1o\s+1\*(#] +.ds Th \*(#[\s+2I\s-2\h'-\w'I'u*3/5'\v'-.3m'o\v'.3m'\*(#] +.ds ae a\h'-(\w'a'u*4/10)'e +.ds Ae A\h'-(\w'A'u*4/10)'E +. \" corrections for vroff +.if v .ds ~ \\k:\h'-(\\n(.wu*9/10-\*(#H)'\s-2\u~\d\s+2\h'|\\n:u' +.if v .ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'\v'-.4m'^\v'.4m'\h'|\\n:u' +. \" for low resolution devices (crt and lpr) +.if \n(.H>23 .if \n(.V>19 \ +\{\ +. ds : e +. ds 8 ss +. ds o a +. ds d- d\h'-1'\(ga +. ds D- D\h'-1'\(hy +. ds th \o'bp' +. ds Th \o'LP' +. ds ae ae +. ds Ae AE +.\} +.rm #[ #] #H #V #F C +.\" ======================================================================== +.\" +.IX Title "xpacleanup 3" +.TH xpacleanup 3 "July 23, 2013" "version 2.1.15" "SAORD Documentation" +.\" For nroff, turn off justification. Always turn off hyphenation; it makes +.\" way too many mistakes in technical documents. +.if n .ad l +.nh +.SH "NAME" +\&\fBXPACleanup: release reserved \s-1XPA\s0 memory\fR +.SH "SYNOPSIS" +.IX Header "SYNOPSIS" +.Vb 1 +\& #include <xpa.h> +\& +\& void XPACleanup(void); +.Ve +.SH "DESCRIPTION" +.IX Header "DESCRIPTION" +When \s-1XPA\s0 is initialized, it allocates a small amount of memory for the +access control list, temp directory path, and reserved commands. This +memory is found by valgrind to be \*(L"still reachable\*(R", meaning that \*(L"your +program didn't free some memory it could have\*(R". Calling the +\&\fIXPACleanup()\fR routine before exiting the program will free this memory +and make valgrind happy. +.SH "SEE ALSO" +.IX Header "SEE ALSO" +See xpa(n) for a list of \s-1XPA\s0 help pages diff --git a/xpa/man/man3/xpaclient.3 b/xpa/man/man3/xpaclient.3 new file mode 100644 index 0000000..804f57b --- /dev/null +++ b/xpa/man/man3/xpaclient.3 @@ -0,0 +1,206 @@ +.\" Automatically generated by Pod::Man 2.22 (Pod::Simple 3.13) +.\" +.\" Standard preamble: +.\" ======================================================================== +.de Sp \" Vertical space (when we can't use .PP) +.if t .sp .5v +.if n .sp +.. +.de Vb \" Begin verbatim text +.ft CW +.nf +.ne \\$1 +.. +.de Ve \" End verbatim text +.ft R +.fi +.. +.\" Set up some character translations and predefined strings. \*(-- will +.\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left +.\" double quote, and \*(R" will give a right double quote. \*(C+ will +.\" give a nicer C++. Capital omega is used to do unbreakable dashes and +.\" therefore won't be available. \*(C` and \*(C' expand to `' in nroff, +.\" nothing in troff, for use with C<>. +.tr \(*W- +.ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p' +.ie n \{\ +. ds -- \(*W- +. ds PI pi +. if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch +. if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch +. ds L" "" +. ds R" "" +. ds C` "" +. ds C' "" +'br\} +.el\{\ +. ds -- \|\(em\| +. ds PI \(*p +. ds L" `` +. ds R" '' +'br\} +.\" +.\" Escape single quotes in literal strings from groff's Unicode transform. +.ie \n(.g .ds Aq \(aq +.el .ds Aq ' +.\" +.\" If the F register is turned on, we'll generate index entries on stderr for +.\" titles (.TH), headers (.SH), subsections (.SS), items (.Ip), and index +.\" entries marked with X<> in POD. Of course, you'll have to process the +.\" output yourself in some meaningful fashion. +.ie \nF \{\ +. de IX +. tm Index:\\$1\t\\n%\t"\\$2" +.. +. nr % 0 +. rr F +.\} +.el \{\ +. de IX +.. +.\} +.\" +.\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2). +.\" Fear. Run. Save yourself. No user-serviceable parts. +. \" fudge factors for nroff and troff +.if n \{\ +. ds #H 0 +. ds #V .8m +. ds #F .3m +. ds #[ \f1 +. ds #] \fP +.\} +.if t \{\ +. ds #H ((1u-(\\\\n(.fu%2u))*.13m) +. ds #V .6m +. ds #F 0 +. ds #[ \& +. ds #] \& +.\} +. \" simple accents for nroff and troff +.if n \{\ +. ds ' \& +. ds ` \& +. ds ^ \& +. ds , \& +. ds ~ ~ +. ds / +.\} +.if t \{\ +. ds ' \\k:\h'-(\\n(.wu*8/10-\*(#H)'\'\h"|\\n:u" +. ds ` \\k:\h'-(\\n(.wu*8/10-\*(#H)'\`\h'|\\n:u' +. ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'^\h'|\\n:u' +. ds , \\k:\h'-(\\n(.wu*8/10)',\h'|\\n:u' +. ds ~ \\k:\h'-(\\n(.wu-\*(#H-.1m)'~\h'|\\n:u' +. ds / \\k:\h'-(\\n(.wu*8/10-\*(#H)'\z\(sl\h'|\\n:u' +.\} +. \" troff and (daisy-wheel) nroff accents +.ds : \\k:\h'-(\\n(.wu*8/10-\*(#H+.1m+\*(#F)'\v'-\*(#V'\z.\h'.2m+\*(#F'.\h'|\\n:u'\v'\*(#V' +.ds 8 \h'\*(#H'\(*b\h'-\*(#H' +.ds o \\k:\h'-(\\n(.wu+\w'\(de'u-\*(#H)/2u'\v'-.3n'\*(#[\z\(de\v'.3n'\h'|\\n:u'\*(#] +.ds d- \h'\*(#H'\(pd\h'-\w'~'u'\v'-.25m'\f2\(hy\fP\v'.25m'\h'-\*(#H' +.ds D- D\\k:\h'-\w'D'u'\v'-.11m'\z\(hy\v'.11m'\h'|\\n:u' +.ds th \*(#[\v'.3m'\s+1I\s-1\v'-.3m'\h'-(\w'I'u*2/3)'\s-1o\s+1\*(#] +.ds Th \*(#[\s+2I\s-2\h'-\w'I'u*3/5'\v'-.3m'o\v'.3m'\*(#] +.ds ae a\h'-(\w'a'u*4/10)'e +.ds Ae A\h'-(\w'A'u*4/10)'E +. \" corrections for vroff +.if v .ds ~ \\k:\h'-(\\n(.wu*9/10-\*(#H)'\s-2\u~\d\s+2\h'|\\n:u' +.if v .ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'\v'-.4m'^\v'.4m'\h'|\\n:u' +. \" for low resolution devices (crt and lpr) +.if \n(.H>23 .if \n(.V>19 \ +\{\ +. ds : e +. ds 8 ss +. ds o a +. ds d- d\h'-1'\(ga +. ds D- D\h'-1'\(hy +. ds th \o'bp' +. ds Th \o'LP' +. ds ae ae +. ds Ae AE +.\} +.rm #[ #] #H #V #F C +.\" ======================================================================== +.\" +.IX Title "xpaclient 3" +.TH xpaclient 3 "July 23, 2013" "version 2.1.15" "SAORD Documentation" +.\" For nroff, turn off justification. Always turn off hyphenation; it makes +.\" way too many mistakes in technical documents. +.if n .ad l +.nh +.SH "NAME" +\&\fBXPAClient: The \s-1XPA\s0 Client-side Programming Interface\fR +.SH "SYNOPSIS" +.IX Header "SYNOPSIS" +A description of the \s-1XPA\s0 client-side programming interface. +.SH "DESCRIPTION" +.IX Header "DESCRIPTION" +\&\fBIntroduction to \s-1XPA\s0 Client Programming\fR +.PP +Sending/receiving data to/from an \s-1XPA\s0 access point is easy: you +generally only need to call the \fIXPAGet()\fR or \fIXPASet()\fR subroutines. +.PP +.Vb 1 +\& #include <xpa.h> +\& +\& int XPAGet(XPA xpa, +\& char *template, char *paramlist, char *mode, +\& char **bufs, size_t *lens, char **names, char **messages, int n); +\& +\& int XPASet(XPA xpa, +\& char *template, char *paramlist, char *mode, +\& char *buf, size_t len, char **names, char **messages, int n); +\& +\& int XPAInfo(XPA xpa, +\& char *template, char *paramlist, char *mode, +\& char **names, char **messages, int n); +\& +\& int XPAAccess(XPA xpa, +\& char *template, char *paramlist, char *mode, +\& char **names, char **messages, int n); +\& +\& int XPAGetFd(XPA xpa, +\& char *template, char *paramlist, char *mode, +\& int *fds, char **names, char **messages, int n); +\& +\& int XPASetFd(XPA xpa, +\& char *template, char *paramlist, char *mode, +\& int fd, char **names, char **messages, int n); +\& +\& XPA XPAOpen(char *mode); +\& +\& void XPAClose(XPA xpa); +\& +\& int XPANSLookup(XPA xpa, +\& char *template, char *type, +\& char ***classes, char ***names, char ***methods, char ***infos); +.Ve +.PP +\&\fBIntroduction\fR +.PP +To use the \s-1XPA\s0 application programming interface, a software developer +generally will include the xpa.h definitions file: +.PP +.Vb 1 +\& #include <xpa.h> +.Ve +.PP +in the software module that defines or accesses an \s-1XPA\s0 access point and +then will link against the libxpa.a library: +.PP +.Vb 1 +\& gcc \-o foo foo.c libxpa.a +.Ve +.PP +\&\s-1XPA\s0 has been compiled using both C and \*(C+ compilers. +.PP +Client communication with \s-1XPA\s0 public access points generally is +accomplished using \fIXPAGet()\fR or \fIXPASet()\fR within a program (or xpaget +and xpaset at the command line). Both routines require specification +of the name of the access point. If a template +is used to specify the access point name (e.g., \*(L"ds9*\*(R"), then +communication will take place with all servers matching that template. +.SH "SEE ALSO" +.IX Header "SEE ALSO" +See xpa(n) for a list of \s-1XPA\s0 help pages diff --git a/xpa/man/man3/xpaclose.3 b/xpa/man/man3/xpaclose.3 new file mode 100644 index 0000000..15e5941 --- /dev/null +++ b/xpa/man/man3/xpaclose.3 @@ -0,0 +1,157 @@ +.\" Automatically generated by Pod::Man 2.22 (Pod::Simple 3.13) +.\" +.\" Standard preamble: +.\" ======================================================================== +.de Sp \" Vertical space (when we can't use .PP) +.if t .sp .5v +.if n .sp +.. +.de Vb \" Begin verbatim text +.ft CW +.nf +.ne \\$1 +.. +.de Ve \" End verbatim text +.ft R +.fi +.. +.\" Set up some character translations and predefined strings. \*(-- will +.\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left +.\" double quote, and \*(R" will give a right double quote. \*(C+ will +.\" give a nicer C++. Capital omega is used to do unbreakable dashes and +.\" therefore won't be available. \*(C` and \*(C' expand to `' in nroff, +.\" nothing in troff, for use with C<>. +.tr \(*W- +.ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p' +.ie n \{\ +. ds -- \(*W- +. ds PI pi +. if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch +. if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch +. ds L" "" +. ds R" "" +. ds C` "" +. ds C' "" +'br\} +.el\{\ +. ds -- \|\(em\| +. ds PI \(*p +. ds L" `` +. ds R" '' +'br\} +.\" +.\" Escape single quotes in literal strings from groff's Unicode transform. +.ie \n(.g .ds Aq \(aq +.el .ds Aq ' +.\" +.\" If the F register is turned on, we'll generate index entries on stderr for +.\" titles (.TH), headers (.SH), subsections (.SS), items (.Ip), and index +.\" entries marked with X<> in POD. Of course, you'll have to process the +.\" output yourself in some meaningful fashion. +.ie \nF \{\ +. de IX +. tm Index:\\$1\t\\n%\t"\\$2" +.. +. nr % 0 +. rr F +.\} +.el \{\ +. de IX +.. +.\} +.\" +.\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2). +.\" Fear. Run. Save yourself. No user-serviceable parts. +. \" fudge factors for nroff and troff +.if n \{\ +. ds #H 0 +. ds #V .8m +. ds #F .3m +. ds #[ \f1 +. ds #] \fP +.\} +.if t \{\ +. ds #H ((1u-(\\\\n(.fu%2u))*.13m) +. ds #V .6m +. ds #F 0 +. ds #[ \& +. ds #] \& +.\} +. \" simple accents for nroff and troff +.if n \{\ +. ds ' \& +. ds ` \& +. ds ^ \& +. ds , \& +. ds ~ ~ +. ds / +.\} +.if t \{\ +. ds ' \\k:\h'-(\\n(.wu*8/10-\*(#H)'\'\h"|\\n:u" +. ds ` \\k:\h'-(\\n(.wu*8/10-\*(#H)'\`\h'|\\n:u' +. ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'^\h'|\\n:u' +. ds , \\k:\h'-(\\n(.wu*8/10)',\h'|\\n:u' +. ds ~ \\k:\h'-(\\n(.wu-\*(#H-.1m)'~\h'|\\n:u' +. ds / \\k:\h'-(\\n(.wu*8/10-\*(#H)'\z\(sl\h'|\\n:u' +.\} +. \" troff and (daisy-wheel) nroff accents +.ds : \\k:\h'-(\\n(.wu*8/10-\*(#H+.1m+\*(#F)'\v'-\*(#V'\z.\h'.2m+\*(#F'.\h'|\\n:u'\v'\*(#V' +.ds 8 \h'\*(#H'\(*b\h'-\*(#H' +.ds o \\k:\h'-(\\n(.wu+\w'\(de'u-\*(#H)/2u'\v'-.3n'\*(#[\z\(de\v'.3n'\h'|\\n:u'\*(#] +.ds d- \h'\*(#H'\(pd\h'-\w'~'u'\v'-.25m'\f2\(hy\fP\v'.25m'\h'-\*(#H' +.ds D- D\\k:\h'-\w'D'u'\v'-.11m'\z\(hy\v'.11m'\h'|\\n:u' +.ds th \*(#[\v'.3m'\s+1I\s-1\v'-.3m'\h'-(\w'I'u*2/3)'\s-1o\s+1\*(#] +.ds Th \*(#[\s+2I\s-2\h'-\w'I'u*3/5'\v'-.3m'o\v'.3m'\*(#] +.ds ae a\h'-(\w'a'u*4/10)'e +.ds Ae A\h'-(\w'A'u*4/10)'E +. \" corrections for vroff +.if v .ds ~ \\k:\h'-(\\n(.wu*9/10-\*(#H)'\s-2\u~\d\s+2\h'|\\n:u' +.if v .ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'\v'-.4m'^\v'.4m'\h'|\\n:u' +. \" for low resolution devices (crt and lpr) +.if \n(.H>23 .if \n(.V>19 \ +\{\ +. ds : e +. ds 8 ss +. ds o a +. ds d- d\h'-1'\(ga +. ds D- D\h'-1'\(hy +. ds th \o'bp' +. ds Th \o'LP' +. ds ae ae +. ds Ae AE +.\} +.rm #[ #] #H #V #F C +.\" ======================================================================== +.\" +.IX Title "xpaclose 3" +.TH xpaclose 3 "July 23, 2013" "version 2.1.15" "SAORD Documentation" +.\" For nroff, turn off justification. Always turn off hyphenation; it makes +.\" way too many mistakes in technical documents. +.if n .ad l +.nh +.SH "NAME" +\&\fBXPAClose: close a persistent \s-1XPA\s0 client handle\fR +.SH "SYNOPSIS" +.IX Header "SYNOPSIS" +.Vb 1 +\& #include <xpa.h> +\& +\& void XPAClose(XPA xpa); +.Ve +.SH "DESCRIPTION" +.IX Header "DESCRIPTION" +XPAClose closes the persistent connections associated with this \s-1XPA\s0 struct +and frees all allocated space. It also closes the open sockets connections +to all \s-1XPA\s0 servers that were opened using this handle. +.PP +\&\fBExample:\fR +.PP +.Vb 1 +\& #include <xpa.h> +\& +\& XPA xpa; +\& XPAClose(xpa); +.Ve +.SH "SEE ALSO" +.IX Header "SEE ALSO" +See xpa(n) for a list of \s-1XPA\s0 help pages diff --git a/xpa/man/man3/xpacmdadd.3 b/xpa/man/man3/xpacmdadd.3 new file mode 100644 index 0000000..9c4b7e5 --- /dev/null +++ b/xpa/man/man3/xpacmdadd.3 @@ -0,0 +1,174 @@ +.\" Automatically generated by Pod::Man 2.22 (Pod::Simple 3.13) +.\" +.\" Standard preamble: +.\" ======================================================================== +.de Sp \" Vertical space (when we can't use .PP) +.if t .sp .5v +.if n .sp +.. +.de Vb \" Begin verbatim text +.ft CW +.nf +.ne \\$1 +.. +.de Ve \" End verbatim text +.ft R +.fi +.. +.\" Set up some character translations and predefined strings. \*(-- will +.\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left +.\" double quote, and \*(R" will give a right double quote. \*(C+ will +.\" give a nicer C++. Capital omega is used to do unbreakable dashes and +.\" therefore won't be available. \*(C` and \*(C' expand to `' in nroff, +.\" nothing in troff, for use with C<>. +.tr \(*W- +.ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p' +.ie n \{\ +. ds -- \(*W- +. ds PI pi +. if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch +. if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch +. ds L" "" +. ds R" "" +. ds C` "" +. ds C' "" +'br\} +.el\{\ +. ds -- \|\(em\| +. ds PI \(*p +. ds L" `` +. ds R" '' +'br\} +.\" +.\" Escape single quotes in literal strings from groff's Unicode transform. +.ie \n(.g .ds Aq \(aq +.el .ds Aq ' +.\" +.\" If the F register is turned on, we'll generate index entries on stderr for +.\" titles (.TH), headers (.SH), subsections (.SS), items (.Ip), and index +.\" entries marked with X<> in POD. Of course, you'll have to process the +.\" output yourself in some meaningful fashion. +.ie \nF \{\ +. de IX +. tm Index:\\$1\t\\n%\t"\\$2" +.. +. nr % 0 +. rr F +.\} +.el \{\ +. de IX +.. +.\} +.\" +.\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2). +.\" Fear. Run. Save yourself. No user-serviceable parts. +. \" fudge factors for nroff and troff +.if n \{\ +. ds #H 0 +. ds #V .8m +. ds #F .3m +. ds #[ \f1 +. ds #] \fP +.\} +.if t \{\ +. ds #H ((1u-(\\\\n(.fu%2u))*.13m) +. ds #V .6m +. ds #F 0 +. ds #[ \& +. ds #] \& +.\} +. \" simple accents for nroff and troff +.if n \{\ +. ds ' \& +. ds ` \& +. ds ^ \& +. ds , \& +. ds ~ ~ +. ds / +.\} +.if t \{\ +. ds ' \\k:\h'-(\\n(.wu*8/10-\*(#H)'\'\h"|\\n:u" +. ds ` \\k:\h'-(\\n(.wu*8/10-\*(#H)'\`\h'|\\n:u' +. ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'^\h'|\\n:u' +. ds , \\k:\h'-(\\n(.wu*8/10)',\h'|\\n:u' +. ds ~ \\k:\h'-(\\n(.wu-\*(#H-.1m)'~\h'|\\n:u' +. ds / \\k:\h'-(\\n(.wu*8/10-\*(#H)'\z\(sl\h'|\\n:u' +.\} +. \" troff and (daisy-wheel) nroff accents +.ds : \\k:\h'-(\\n(.wu*8/10-\*(#H+.1m+\*(#F)'\v'-\*(#V'\z.\h'.2m+\*(#F'.\h'|\\n:u'\v'\*(#V' +.ds 8 \h'\*(#H'\(*b\h'-\*(#H' +.ds o \\k:\h'-(\\n(.wu+\w'\(de'u-\*(#H)/2u'\v'-.3n'\*(#[\z\(de\v'.3n'\h'|\\n:u'\*(#] +.ds d- \h'\*(#H'\(pd\h'-\w'~'u'\v'-.25m'\f2\(hy\fP\v'.25m'\h'-\*(#H' +.ds D- D\\k:\h'-\w'D'u'\v'-.11m'\z\(hy\v'.11m'\h'|\\n:u' +.ds th \*(#[\v'.3m'\s+1I\s-1\v'-.3m'\h'-(\w'I'u*2/3)'\s-1o\s+1\*(#] +.ds Th \*(#[\s+2I\s-2\h'-\w'I'u*3/5'\v'-.3m'o\v'.3m'\*(#] +.ds ae a\h'-(\w'a'u*4/10)'e +.ds Ae A\h'-(\w'A'u*4/10)'E +. \" corrections for vroff +.if v .ds ~ \\k:\h'-(\\n(.wu*9/10-\*(#H)'\s-2\u~\d\s+2\h'|\\n:u' +.if v .ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'\v'-.4m'^\v'.4m'\h'|\\n:u' +. \" for low resolution devices (crt and lpr) +.if \n(.H>23 .if \n(.V>19 \ +\{\ +. ds : e +. ds 8 ss +. ds o a +. ds d- d\h'-1'\(ga +. ds D- D\h'-1'\(hy +. ds th \o'bp' +. ds Th \o'LP' +. ds ae ae +. ds Ae AE +.\} +.rm #[ #] #H #V #F C +.\" ======================================================================== +.\" +.IX Title "xpacmdadd 3" +.TH xpacmdadd 3 "July 23, 2013" "version 2.1.15" "SAORD Documentation" +.\" For nroff, turn off justification. Always turn off hyphenation; it makes +.\" way too many mistakes in technical documents. +.if n .ad l +.nh +.SH "NAME" +\&\fBXPACmdAdd: add a command to an \s-1XPA\s0 command public access point\fR +.SH "SYNOPSIS" +.IX Header "SYNOPSIS" +.Vb 1 +\& #include <xpa.h> +\& +\& XPACmd XPACmdAdd(XPA xpa, char *name, char *help, +\& int (*send_callback)(), +\& void *send_data, char *send_mode, +\& int (*rec_callback)(), +\& void *rec_data, char *rec_mode); +.Ve +.SH "DESCRIPTION" +.IX Header "DESCRIPTION" +Add a command to an \s-1XPA\s0 command access point. The \s-1XPA\s0 argument specifies the +\&\s-1XPA\s0 struct returned by a call to \fIXPANewCmd()\fR. The name argument is the +name of the command. The other arguments function identically to the +arguments in the \fIXPANew()\fR command, i.e., the send_callback and rec_callback +routines have identical calling sequences to their \fIXPANew()\fR counterparts, +with the exceptions noted below. +.PP +When help is requested for a command access point using: +.PP +.Vb 1 +\& xpaget \-h class:name +.Ve +.PP +all of the command help strings are listed. To get help for a given +command, use: +.PP +.Vb 1 +\& xpaget \-h class:name cmd +.Ve +.PP +Also, the acl keyword in the send_mode and receive_mode strings is +global to the access point, not local to the command. Thus, the value +for the acl mode should be the same in all send_mode (or receive_mode) +strings for each command in a command access point. (The acl for +send_mode need not be the same as the acl for receive_mode, though). +.SH "SEE ALSO" +.IX Header "SEE ALSO" +See xpa(n) for a list of \s-1XPA\s0 help pages diff --git a/xpa/man/man3/xpacmddel.3 b/xpa/man/man3/xpacmddel.3 new file mode 100644 index 0000000..21bf0be --- /dev/null +++ b/xpa/man/man3/xpacmddel.3 @@ -0,0 +1,147 @@ +.\" Automatically generated by Pod::Man 2.22 (Pod::Simple 3.13) +.\" +.\" Standard preamble: +.\" ======================================================================== +.de Sp \" Vertical space (when we can't use .PP) +.if t .sp .5v +.if n .sp +.. +.de Vb \" Begin verbatim text +.ft CW +.nf +.ne \\$1 +.. +.de Ve \" End verbatim text +.ft R +.fi +.. +.\" Set up some character translations and predefined strings. \*(-- will +.\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left +.\" double quote, and \*(R" will give a right double quote. \*(C+ will +.\" give a nicer C++. Capital omega is used to do unbreakable dashes and +.\" therefore won't be available. \*(C` and \*(C' expand to `' in nroff, +.\" nothing in troff, for use with C<>. +.tr \(*W- +.ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p' +.ie n \{\ +. ds -- \(*W- +. ds PI pi +. if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch +. if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch +. ds L" "" +. ds R" "" +. ds C` "" +. ds C' "" +'br\} +.el\{\ +. ds -- \|\(em\| +. ds PI \(*p +. ds L" `` +. ds R" '' +'br\} +.\" +.\" Escape single quotes in literal strings from groff's Unicode transform. +.ie \n(.g .ds Aq \(aq +.el .ds Aq ' +.\" +.\" If the F register is turned on, we'll generate index entries on stderr for +.\" titles (.TH), headers (.SH), subsections (.SS), items (.Ip), and index +.\" entries marked with X<> in POD. Of course, you'll have to process the +.\" output yourself in some meaningful fashion. +.ie \nF \{\ +. de IX +. tm Index:\\$1\t\\n%\t"\\$2" +.. +. nr % 0 +. rr F +.\} +.el \{\ +. de IX +.. +.\} +.\" +.\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2). +.\" Fear. Run. Save yourself. No user-serviceable parts. +. \" fudge factors for nroff and troff +.if n \{\ +. ds #H 0 +. ds #V .8m +. ds #F .3m +. ds #[ \f1 +. ds #] \fP +.\} +.if t \{\ +. ds #H ((1u-(\\\\n(.fu%2u))*.13m) +. ds #V .6m +. ds #F 0 +. ds #[ \& +. ds #] \& +.\} +. \" simple accents for nroff and troff +.if n \{\ +. ds ' \& +. ds ` \& +. ds ^ \& +. ds , \& +. ds ~ ~ +. ds / +.\} +.if t \{\ +. ds ' \\k:\h'-(\\n(.wu*8/10-\*(#H)'\'\h"|\\n:u" +. ds ` \\k:\h'-(\\n(.wu*8/10-\*(#H)'\`\h'|\\n:u' +. ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'^\h'|\\n:u' +. ds , \\k:\h'-(\\n(.wu*8/10)',\h'|\\n:u' +. ds ~ \\k:\h'-(\\n(.wu-\*(#H-.1m)'~\h'|\\n:u' +. ds / \\k:\h'-(\\n(.wu*8/10-\*(#H)'\z\(sl\h'|\\n:u' +.\} +. \" troff and (daisy-wheel) nroff accents +.ds : \\k:\h'-(\\n(.wu*8/10-\*(#H+.1m+\*(#F)'\v'-\*(#V'\z.\h'.2m+\*(#F'.\h'|\\n:u'\v'\*(#V' +.ds 8 \h'\*(#H'\(*b\h'-\*(#H' +.ds o \\k:\h'-(\\n(.wu+\w'\(de'u-\*(#H)/2u'\v'-.3n'\*(#[\z\(de\v'.3n'\h'|\\n:u'\*(#] +.ds d- \h'\*(#H'\(pd\h'-\w'~'u'\v'-.25m'\f2\(hy\fP\v'.25m'\h'-\*(#H' +.ds D- D\\k:\h'-\w'D'u'\v'-.11m'\z\(hy\v'.11m'\h'|\\n:u' +.ds th \*(#[\v'.3m'\s+1I\s-1\v'-.3m'\h'-(\w'I'u*2/3)'\s-1o\s+1\*(#] +.ds Th \*(#[\s+2I\s-2\h'-\w'I'u*3/5'\v'-.3m'o\v'.3m'\*(#] +.ds ae a\h'-(\w'a'u*4/10)'e +.ds Ae A\h'-(\w'A'u*4/10)'E +. \" corrections for vroff +.if v .ds ~ \\k:\h'-(\\n(.wu*9/10-\*(#H)'\s-2\u~\d\s+2\h'|\\n:u' +.if v .ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'\v'-.4m'^\v'.4m'\h'|\\n:u' +. \" for low resolution devices (crt and lpr) +.if \n(.H>23 .if \n(.V>19 \ +\{\ +. ds : e +. ds 8 ss +. ds o a +. ds d- d\h'-1'\(ga +. ds D- D\h'-1'\(hy +. ds th \o'bp' +. ds Th \o'LP' +. ds ae ae +. ds Ae AE +.\} +.rm #[ #] #H #V #F C +.\" ======================================================================== +.\" +.IX Title "xpacmddel 3" +.TH xpacmddel 3 "July 23, 2013" "version 2.1.15" "SAORD Documentation" +.\" For nroff, turn off justification. Always turn off hyphenation; it makes +.\" way too many mistakes in technical documents. +.if n .ad l +.nh +.SH "NAME" +\&\fBXPACmdDel: remove a command from an \s-1XPA\s0 command public access point\fR +.SH "SYNOPSIS" +.IX Header "SYNOPSIS" +.Vb 1 +\& #include <xpa.h> +\& +\& void XPACmdDel(XPA xpa, XPACmd cmd); +.Ve +.SH "DESCRIPTION" +.IX Header "DESCRIPTION" +This routine removes a command from the list of available commands in +a given \s-1XPA\s0. That command will no longer be available for processing. +.SH "SEE ALSO" +.IX Header "SEE ALSO" +See xpa(n) for a list of \s-1XPA\s0 help pages diff --git a/xpa/man/man3/xpacmdnew.3 b/xpa/man/man3/xpacmdnew.3 new file mode 100644 index 0000000..8a1cb94 --- /dev/null +++ b/xpa/man/man3/xpacmdnew.3 @@ -0,0 +1,196 @@ +.\" Automatically generated by Pod::Man 2.22 (Pod::Simple 3.13) +.\" +.\" Standard preamble: +.\" ======================================================================== +.de Sp \" Vertical space (when we can't use .PP) +.if t .sp .5v +.if n .sp +.. +.de Vb \" Begin verbatim text +.ft CW +.nf +.ne \\$1 +.. +.de Ve \" End verbatim text +.ft R +.fi +.. +.\" Set up some character translations and predefined strings. \*(-- will +.\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left +.\" double quote, and \*(R" will give a right double quote. \*(C+ will +.\" give a nicer C++. Capital omega is used to do unbreakable dashes and +.\" therefore won't be available. \*(C` and \*(C' expand to `' in nroff, +.\" nothing in troff, for use with C<>. +.tr \(*W- +.ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p' +.ie n \{\ +. ds -- \(*W- +. ds PI pi +. if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch +. if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch +. ds L" "" +. ds R" "" +. ds C` "" +. ds C' "" +'br\} +.el\{\ +. ds -- \|\(em\| +. ds PI \(*p +. ds L" `` +. ds R" '' +'br\} +.\" +.\" Escape single quotes in literal strings from groff's Unicode transform. +.ie \n(.g .ds Aq \(aq +.el .ds Aq ' +.\" +.\" If the F register is turned on, we'll generate index entries on stderr for +.\" titles (.TH), headers (.SH), subsections (.SS), items (.Ip), and index +.\" entries marked with X<> in POD. Of course, you'll have to process the +.\" output yourself in some meaningful fashion. +.ie \nF \{\ +. de IX +. tm Index:\\$1\t\\n%\t"\\$2" +.. +. nr % 0 +. rr F +.\} +.el \{\ +. de IX +.. +.\} +.\" +.\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2). +.\" Fear. Run. Save yourself. No user-serviceable parts. +. \" fudge factors for nroff and troff +.if n \{\ +. ds #H 0 +. ds #V .8m +. ds #F .3m +. ds #[ \f1 +. ds #] \fP +.\} +.if t \{\ +. ds #H ((1u-(\\\\n(.fu%2u))*.13m) +. ds #V .6m +. ds #F 0 +. ds #[ \& +. ds #] \& +.\} +. \" simple accents for nroff and troff +.if n \{\ +. ds ' \& +. ds ` \& +. ds ^ \& +. ds , \& +. ds ~ ~ +. ds / +.\} +.if t \{\ +. ds ' \\k:\h'-(\\n(.wu*8/10-\*(#H)'\'\h"|\\n:u" +. ds ` \\k:\h'-(\\n(.wu*8/10-\*(#H)'\`\h'|\\n:u' +. ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'^\h'|\\n:u' +. ds , \\k:\h'-(\\n(.wu*8/10)',\h'|\\n:u' +. ds ~ \\k:\h'-(\\n(.wu-\*(#H-.1m)'~\h'|\\n:u' +. ds / \\k:\h'-(\\n(.wu*8/10-\*(#H)'\z\(sl\h'|\\n:u' +.\} +. \" troff and (daisy-wheel) nroff accents +.ds : \\k:\h'-(\\n(.wu*8/10-\*(#H+.1m+\*(#F)'\v'-\*(#V'\z.\h'.2m+\*(#F'.\h'|\\n:u'\v'\*(#V' +.ds 8 \h'\*(#H'\(*b\h'-\*(#H' +.ds o \\k:\h'-(\\n(.wu+\w'\(de'u-\*(#H)/2u'\v'-.3n'\*(#[\z\(de\v'.3n'\h'|\\n:u'\*(#] +.ds d- \h'\*(#H'\(pd\h'-\w'~'u'\v'-.25m'\f2\(hy\fP\v'.25m'\h'-\*(#H' +.ds D- D\\k:\h'-\w'D'u'\v'-.11m'\z\(hy\v'.11m'\h'|\\n:u' +.ds th \*(#[\v'.3m'\s+1I\s-1\v'-.3m'\h'-(\w'I'u*2/3)'\s-1o\s+1\*(#] +.ds Th \*(#[\s+2I\s-2\h'-\w'I'u*3/5'\v'-.3m'o\v'.3m'\*(#] +.ds ae a\h'-(\w'a'u*4/10)'e +.ds Ae A\h'-(\w'A'u*4/10)'E +. \" corrections for vroff +.if v .ds ~ \\k:\h'-(\\n(.wu*9/10-\*(#H)'\s-2\u~\d\s+2\h'|\\n:u' +.if v .ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'\v'-.4m'^\v'.4m'\h'|\\n:u' +. \" for low resolution devices (crt and lpr) +.if \n(.H>23 .if \n(.V>19 \ +\{\ +. ds : e +. ds 8 ss +. ds o a +. ds d- d\h'-1'\(ga +. ds D- D\h'-1'\(hy +. ds th \o'bp' +. ds Th \o'LP' +. ds ae ae +. ds Ae AE +.\} +.rm #[ #] #H #V #F C +.\" ======================================================================== +.\" +.IX Title "xpacmdnew 3" +.TH xpacmdnew 3 "July 23, 2013" "version 2.1.15" "SAORD Documentation" +.\" For nroff, turn off justification. Always turn off hyphenation; it makes +.\" way too many mistakes in technical documents. +.if n .ad l +.nh +.SH "NAME" +\&\fBXPACmdNew: create a new \s-1XPA\s0 public access point for commands\fR +.SH "SYNOPSIS" +.IX Header "SYNOPSIS" +.Vb 1 +\& #include <xpa.h> +\& +\& XPA XPACmdNew(char *class, char *name); +.Ve +.SH "DESCRIPTION" +.IX Header "DESCRIPTION" +Create a new \s-1XPA\s0 public access point for commands that will share a +common identifier class:name. Enter this access point into the \s-1XPA\s0 +name server, so that it can be accessed by external processes. +\&\fIXPACmdNew()\fR returns an \s-1XPA\s0 struct. +.PP +It often is more convenient to have one public access point that can +manage a number of commands, rather than having individual access +points for each command. For example, it is easier to command the +ds9 image display using: +.PP +.Vb 3 +\& echo "colormap I8" | xpaset ds9 +\& echo "scale log" | xpaset ds9 +\& echo "file foo.fits" | xpaset ds9 +.Ve +.PP +then to use: +.PP +.Vb 3 +\& echo "I8" | xpaset ds9_colormap +\& echo "log" | xpaset ds9_scale +\& echo "foo.fits" | xpaset ds9_file +.Ve +.PP +In the first case, the commands remain the same regardless of the +target \s-1XPA\s0 name. In the second case, the command names must change +for each instance of ds9. That is, if a second instance of ds9 +called \s-1DS9\s0 were running, it would be commanded either as: +.PP +.Vb 3 +\& echo "colormap I8" | xpaset DS9 +\& echo "scale log" | xpaset DS9 +\& echo "file foo.fits" | xpaset DS9 +.Ve +.PP +or as: +.PP +.Vb 3 +\& echo "I8" | xpaset DS9_colormap +\& echo "log" | xpaset DS9_scale +\& echo "foo.fits" | xpaset DS9_file +.Ve +.PP +Thus, in cases where a program is going to manage many commands, it +generally is easier to define them as commands associated with the +\&\fIXPACmdNew()\fR routine, rather than as separate access points using +\&\fIXPANew()\fR. +.PP +When \fIXPACmdNew()\fR is called, only the class:name identifier is +specified. Each sub-command is subsequently defined using the +\&\fIXPACmdAdd()\fR routine. +.SH "SEE ALSO" +.IX Header "SEE ALSO" +See xpa(n) for a list of \s-1XPA\s0 help pages diff --git a/xpa/man/man3/xpafree.3 b/xpa/man/man3/xpafree.3 new file mode 100644 index 0000000..53783eb --- /dev/null +++ b/xpa/man/man3/xpafree.3 @@ -0,0 +1,153 @@ +.\" Automatically generated by Pod::Man 2.22 (Pod::Simple 3.13) +.\" +.\" Standard preamble: +.\" ======================================================================== +.de Sp \" Vertical space (when we can't use .PP) +.if t .sp .5v +.if n .sp +.. +.de Vb \" Begin verbatim text +.ft CW +.nf +.ne \\$1 +.. +.de Ve \" End verbatim text +.ft R +.fi +.. +.\" Set up some character translations and predefined strings. \*(-- will +.\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left +.\" double quote, and \*(R" will give a right double quote. \*(C+ will +.\" give a nicer C++. Capital omega is used to do unbreakable dashes and +.\" therefore won't be available. \*(C` and \*(C' expand to `' in nroff, +.\" nothing in troff, for use with C<>. +.tr \(*W- +.ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p' +.ie n \{\ +. ds -- \(*W- +. ds PI pi +. if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch +. if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch +. ds L" "" +. ds R" "" +. ds C` "" +. ds C' "" +'br\} +.el\{\ +. ds -- \|\(em\| +. ds PI \(*p +. ds L" `` +. ds R" '' +'br\} +.\" +.\" Escape single quotes in literal strings from groff's Unicode transform. +.ie \n(.g .ds Aq \(aq +.el .ds Aq ' +.\" +.\" If the F register is turned on, we'll generate index entries on stderr for +.\" titles (.TH), headers (.SH), subsections (.SS), items (.Ip), and index +.\" entries marked with X<> in POD. Of course, you'll have to process the +.\" output yourself in some meaningful fashion. +.ie \nF \{\ +. de IX +. tm Index:\\$1\t\\n%\t"\\$2" +.. +. nr % 0 +. rr F +.\} +.el \{\ +. de IX +.. +.\} +.\" +.\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2). +.\" Fear. Run. Save yourself. No user-serviceable parts. +. \" fudge factors for nroff and troff +.if n \{\ +. ds #H 0 +. ds #V .8m +. ds #F .3m +. ds #[ \f1 +. ds #] \fP +.\} +.if t \{\ +. ds #H ((1u-(\\\\n(.fu%2u))*.13m) +. ds #V .6m +. ds #F 0 +. ds #[ \& +. ds #] \& +.\} +. \" simple accents for nroff and troff +.if n \{\ +. ds ' \& +. ds ` \& +. ds ^ \& +. ds , \& +. ds ~ ~ +. ds / +.\} +.if t \{\ +. ds ' \\k:\h'-(\\n(.wu*8/10-\*(#H)'\'\h"|\\n:u" +. ds ` \\k:\h'-(\\n(.wu*8/10-\*(#H)'\`\h'|\\n:u' +. ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'^\h'|\\n:u' +. ds , \\k:\h'-(\\n(.wu*8/10)',\h'|\\n:u' +. ds ~ \\k:\h'-(\\n(.wu-\*(#H-.1m)'~\h'|\\n:u' +. ds / \\k:\h'-(\\n(.wu*8/10-\*(#H)'\z\(sl\h'|\\n:u' +.\} +. \" troff and (daisy-wheel) nroff accents +.ds : \\k:\h'-(\\n(.wu*8/10-\*(#H+.1m+\*(#F)'\v'-\*(#V'\z.\h'.2m+\*(#F'.\h'|\\n:u'\v'\*(#V' +.ds 8 \h'\*(#H'\(*b\h'-\*(#H' +.ds o \\k:\h'-(\\n(.wu+\w'\(de'u-\*(#H)/2u'\v'-.3n'\*(#[\z\(de\v'.3n'\h'|\\n:u'\*(#] +.ds d- \h'\*(#H'\(pd\h'-\w'~'u'\v'-.25m'\f2\(hy\fP\v'.25m'\h'-\*(#H' +.ds D- D\\k:\h'-\w'D'u'\v'-.11m'\z\(hy\v'.11m'\h'|\\n:u' +.ds th \*(#[\v'.3m'\s+1I\s-1\v'-.3m'\h'-(\w'I'u*2/3)'\s-1o\s+1\*(#] +.ds Th \*(#[\s+2I\s-2\h'-\w'I'u*3/5'\v'-.3m'o\v'.3m'\*(#] +.ds ae a\h'-(\w'a'u*4/10)'e +.ds Ae A\h'-(\w'A'u*4/10)'E +. \" corrections for vroff +.if v .ds ~ \\k:\h'-(\\n(.wu*9/10-\*(#H)'\s-2\u~\d\s+2\h'|\\n:u' +.if v .ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'\v'-.4m'^\v'.4m'\h'|\\n:u' +. \" for low resolution devices (crt and lpr) +.if \n(.H>23 .if \n(.V>19 \ +\{\ +. ds : e +. ds 8 ss +. ds o a +. ds d- d\h'-1'\(ga +. ds D- D\h'-1'\(hy +. ds th \o'bp' +. ds Th \o'LP' +. ds ae ae +. ds Ae AE +.\} +.rm #[ #] #H #V #F C +.\" ======================================================================== +.\" +.IX Title "xpafree 3" +.TH xpafree 3 "July 23, 2013" "version 2.1.15" "SAORD Documentation" +.\" For nroff, turn off justification. Always turn off hyphenation; it makes +.\" way too many mistakes in technical documents. +.if n .ad l +.nh +.SH "NAME" +\&\fBXPAFree: remove an \s-1XPA\s0 public access point\fR +.SH "SYNOPSIS" +.IX Header "SYNOPSIS" +.Vb 1 +\& #include <xpa.h> +\& +\& int XPAFree(XPA xpa); +.Ve +.SH "DESCRIPTION" +.IX Header "DESCRIPTION" +Remove the specified \s-1XPA\s0 public access point from the name server and +free all associated storage. Note that removal from the name server +happens automatically when the process terminates, so this call is not +generally needed. It is used when public access points are being +defined temporarily and then destroyed when no longer needed. For +example, ds9 temporarily creates a public access point when it +loads a new image for display and destroys it when the image is +unloaded. +.SH "SEE ALSO" +.IX Header "SEE ALSO" +See xpa(n) for a list of \s-1XPA\s0 help pages diff --git a/xpa/man/man3/xpaget.3 b/xpa/man/man3/xpaget.3 new file mode 100644 index 0000000..4f03cf6 --- /dev/null +++ b/xpa/man/man3/xpaget.3 @@ -0,0 +1,244 @@ +.\" Automatically generated by Pod::Man 2.22 (Pod::Simple 3.13) +.\" +.\" Standard preamble: +.\" ======================================================================== +.de Sp \" Vertical space (when we can't use .PP) +.if t .sp .5v +.if n .sp +.. +.de Vb \" Begin verbatim text +.ft CW +.nf +.ne \\$1 +.. +.de Ve \" End verbatim text +.ft R +.fi +.. +.\" Set up some character translations and predefined strings. \*(-- will +.\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left +.\" double quote, and \*(R" will give a right double quote. \*(C+ will +.\" give a nicer C++. Capital omega is used to do unbreakable dashes and +.\" therefore won't be available. \*(C` and \*(C' expand to `' in nroff, +.\" nothing in troff, for use with C<>. +.tr \(*W- +.ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p' +.ie n \{\ +. ds -- \(*W- +. ds PI pi +. if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch +. if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch +. ds L" "" +. ds R" "" +. ds C` "" +. ds C' "" +'br\} +.el\{\ +. ds -- \|\(em\| +. ds PI \(*p +. ds L" `` +. ds R" '' +'br\} +.\" +.\" Escape single quotes in literal strings from groff's Unicode transform. +.ie \n(.g .ds Aq \(aq +.el .ds Aq ' +.\" +.\" If the F register is turned on, we'll generate index entries on stderr for +.\" titles (.TH), headers (.SH), subsections (.SS), items (.Ip), and index +.\" entries marked with X<> in POD. Of course, you'll have to process the +.\" output yourself in some meaningful fashion. +.ie \nF \{\ +. de IX +. tm Index:\\$1\t\\n%\t"\\$2" +.. +. nr % 0 +. rr F +.\} +.el \{\ +. de IX +.. +.\} +.\" +.\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2). +.\" Fear. Run. Save yourself. No user-serviceable parts. +. \" fudge factors for nroff and troff +.if n \{\ +. ds #H 0 +. ds #V .8m +. ds #F .3m +. ds #[ \f1 +. ds #] \fP +.\} +.if t \{\ +. ds #H ((1u-(\\\\n(.fu%2u))*.13m) +. ds #V .6m +. ds #F 0 +. ds #[ \& +. ds #] \& +.\} +. \" simple accents for nroff and troff +.if n \{\ +. ds ' \& +. ds ` \& +. ds ^ \& +. ds , \& +. ds ~ ~ +. ds / +.\} +.if t \{\ +. ds ' \\k:\h'-(\\n(.wu*8/10-\*(#H)'\'\h"|\\n:u" +. ds ` \\k:\h'-(\\n(.wu*8/10-\*(#H)'\`\h'|\\n:u' +. ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'^\h'|\\n:u' +. ds , \\k:\h'-(\\n(.wu*8/10)',\h'|\\n:u' +. ds ~ \\k:\h'-(\\n(.wu-\*(#H-.1m)'~\h'|\\n:u' +. ds / \\k:\h'-(\\n(.wu*8/10-\*(#H)'\z\(sl\h'|\\n:u' +.\} +. \" troff and (daisy-wheel) nroff accents +.ds : \\k:\h'-(\\n(.wu*8/10-\*(#H+.1m+\*(#F)'\v'-\*(#V'\z.\h'.2m+\*(#F'.\h'|\\n:u'\v'\*(#V' +.ds 8 \h'\*(#H'\(*b\h'-\*(#H' +.ds o \\k:\h'-(\\n(.wu+\w'\(de'u-\*(#H)/2u'\v'-.3n'\*(#[\z\(de\v'.3n'\h'|\\n:u'\*(#] +.ds d- \h'\*(#H'\(pd\h'-\w'~'u'\v'-.25m'\f2\(hy\fP\v'.25m'\h'-\*(#H' +.ds D- D\\k:\h'-\w'D'u'\v'-.11m'\z\(hy\v'.11m'\h'|\\n:u' +.ds th \*(#[\v'.3m'\s+1I\s-1\v'-.3m'\h'-(\w'I'u*2/3)'\s-1o\s+1\*(#] +.ds Th \*(#[\s+2I\s-2\h'-\w'I'u*3/5'\v'-.3m'o\v'.3m'\*(#] +.ds ae a\h'-(\w'a'u*4/10)'e +.ds Ae A\h'-(\w'A'u*4/10)'E +. \" corrections for vroff +.if v .ds ~ \\k:\h'-(\\n(.wu*9/10-\*(#H)'\s-2\u~\d\s+2\h'|\\n:u' +.if v .ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'\v'-.4m'^\v'.4m'\h'|\\n:u' +. \" for low resolution devices (crt and lpr) +.if \n(.H>23 .if \n(.V>19 \ +\{\ +. ds : e +. ds 8 ss +. ds o a +. ds d- d\h'-1'\(ga +. ds D- D\h'-1'\(hy +. ds th \o'bp' +. ds Th \o'LP' +. ds ae ae +. ds Ae AE +.\} +.rm #[ #] #H #V #F C +.\" ======================================================================== +.\" +.IX Title "xpaget 3" +.TH xpaget 3 "July 23, 2013" "version 2.1.15" "SAORD Documentation" +.\" For nroff, turn off justification. Always turn off hyphenation; it makes +.\" way too many mistakes in technical documents. +.if n .ad l +.nh +.SH "NAME" +\&\fBXPAGet: retrieve data from one or more \s-1XPA\s0 servers\fR +.SH "SYNOPSIS" +.IX Header "SYNOPSIS" +.Vb 1 +\& #include <xpa.h> +\& +\& int XPAGet(XPA xpa, +\& char *template, char *paramlist, char *mode, +\& char **bufs, size_t *lens, char **names, char **messages, +\& int n); +.Ve +.SH "DESCRIPTION" +.IX Header "DESCRIPTION" +Retrieve data from one or more \s-1XPA\s0 servers whose class:name identifier +matches the specified template. +.PP +A +template +of the form \*(L"class1:name1\*(R" is sent to the +\&\s-1XPA\s0 name server, which returns a list of at most n matching \s-1XPA\s0 +servers. A connection is established with each of these servers and +the paramlist string is passed to the server as the data transfer +request is initiated. If an \s-1XPA\s0 struct is passed to the call, then the +persistent connections are updated as described above. Otherwise, +temporary connections are made to the servers (which will be closed +when the call completes). +.PP +The \fIXPAGet()\fR routine then retrieves data from at most n \s-1XPA\s0 servers, +places these data into n allocated buffers and places the buffer +pointers in the bufs array. The length of each buffer is stored in the +lens array. A string containing the class:name and ip:port is stored +in the name array. If a given server returned an error or the server +callback sends a message back to the client, then the message will be +stored in the associated element of the messages array. \s-1NB:\s0 if +specified, the name and messages arrays must be of size n or greater. +.PP +The returned message string will be of the form: +.PP +.Vb 1 +\& XPA$ERROR error\-message (class:name ip:port) +.Ve +.PP +or +.PP +.Vb 1 +\& XPA$MESSAGE message (class:name ip:port) +.Ve +.PP +Note that when there is an error stored in an messages entry, the +corresponding bufs and lens entry may or may not be \s-1NULL\s0 and 0 +(respectively), depending on the particularities of the server. +.PP +The return value will contain the actual number of servers that were +processed. This value thus will hold the number of valid entries in +the bufs, lens, names, and messages arrays, and can be used to loop +through these arrays. In names and/or messages is \s-1NULL\s0, no information is +passed back in that array. +.PP +The bufs, names, and messages arrays should be freed upon completion (if +they are not \s-1NULL\s0); +.PP +The mode string is of the form: \*(L"key1=value1,key2=value2,...\*(R" +The following keywords are recognized: +.PP +.Vb 4 +\& key value default explanation +\& \-\-\-\-\-\- \-\-\-\-\-\-\-\- \-\-\-\-\-\-\-\- \-\-\-\-\-\-\-\-\-\-\- +\& ack true/false true if false, don\*(Aqt wait for ack from server (after callback completes) +\& doxpa true/false true client processes xpa requests +.Ve +.PP +The ack keyword is not very useful, since the server completes the callback +in order to return the data anyway. It is here for completion (and perhaps +for future usefulness). +.PP +Normally, an \s-1XPA\s0 client will process incoming \s-1XPA\s0 server requests +while awaiting the completion of the client request. Setting this +variable to \*(L"false\*(R" will prevent \s-1XPA\s0 server requests from being +processed by the client. +.PP +\&\fBExample:\fR +.PP +.Vb 1 +\& #include <xpa.h> +\& +\& #define NXPA 10 +\& int i, got; +\& size_t lens[NXPA]; +\& char *bufs[NXPA]; +\& char *names[NXPA]; +\& char *messages[NXPA]; +\& got = XPAGet(NULL, "ds9", "file", NULL, bufs, lens, names, messages, +\& NXPA); +\& for(i=0; i<got; i++){ +\& if( messages[i] == NULL ){ +\& /* process buf contents */ +\& ProcessImage(bufs[i], ...); +\& free(bufs[i]); +\& } +\& else{ +\& /* error processing */ +\& fprintf(stderr, "ERROR: %s (%s)\en", messages[i], names[i]); +\& } +\& if( names[i] ) +\& free(names[i]); +\& if( messages[i] ) +\& free(messages[i]); +\& } +.Ve +.SH "SEE ALSO" +.IX Header "SEE ALSO" +See xpa(n) for a list of \s-1XPA\s0 help pages diff --git a/xpa/man/man3/xpagetfd.3 b/xpa/man/man3/xpagetfd.3 new file mode 100644 index 0000000..1899880 --- /dev/null +++ b/xpa/man/man3/xpagetfd.3 @@ -0,0 +1,235 @@ +.\" Automatically generated by Pod::Man 2.22 (Pod::Simple 3.13) +.\" +.\" Standard preamble: +.\" ======================================================================== +.de Sp \" Vertical space (when we can't use .PP) +.if t .sp .5v +.if n .sp +.. +.de Vb \" Begin verbatim text +.ft CW +.nf +.ne \\$1 +.. +.de Ve \" End verbatim text +.ft R +.fi +.. +.\" Set up some character translations and predefined strings. \*(-- will +.\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left +.\" double quote, and \*(R" will give a right double quote. \*(C+ will +.\" give a nicer C++. Capital omega is used to do unbreakable dashes and +.\" therefore won't be available. \*(C` and \*(C' expand to `' in nroff, +.\" nothing in troff, for use with C<>. +.tr \(*W- +.ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p' +.ie n \{\ +. ds -- \(*W- +. ds PI pi +. if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch +. if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch +. ds L" "" +. ds R" "" +. ds C` "" +. ds C' "" +'br\} +.el\{\ +. ds -- \|\(em\| +. ds PI \(*p +. ds L" `` +. ds R" '' +'br\} +.\" +.\" Escape single quotes in literal strings from groff's Unicode transform. +.ie \n(.g .ds Aq \(aq +.el .ds Aq ' +.\" +.\" If the F register is turned on, we'll generate index entries on stderr for +.\" titles (.TH), headers (.SH), subsections (.SS), items (.Ip), and index +.\" entries marked with X<> in POD. Of course, you'll have to process the +.\" output yourself in some meaningful fashion. +.ie \nF \{\ +. de IX +. tm Index:\\$1\t\\n%\t"\\$2" +.. +. nr % 0 +. rr F +.\} +.el \{\ +. de IX +.. +.\} +.\" +.\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2). +.\" Fear. Run. Save yourself. No user-serviceable parts. +. \" fudge factors for nroff and troff +.if n \{\ +. ds #H 0 +. ds #V .8m +. ds #F .3m +. ds #[ \f1 +. ds #] \fP +.\} +.if t \{\ +. ds #H ((1u-(\\\\n(.fu%2u))*.13m) +. ds #V .6m +. ds #F 0 +. ds #[ \& +. ds #] \& +.\} +. \" simple accents for nroff and troff +.if n \{\ +. ds ' \& +. ds ` \& +. ds ^ \& +. ds , \& +. ds ~ ~ +. ds / +.\} +.if t \{\ +. ds ' \\k:\h'-(\\n(.wu*8/10-\*(#H)'\'\h"|\\n:u" +. ds ` \\k:\h'-(\\n(.wu*8/10-\*(#H)'\`\h'|\\n:u' +. ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'^\h'|\\n:u' +. ds , \\k:\h'-(\\n(.wu*8/10)',\h'|\\n:u' +. ds ~ \\k:\h'-(\\n(.wu-\*(#H-.1m)'~\h'|\\n:u' +. ds / \\k:\h'-(\\n(.wu*8/10-\*(#H)'\z\(sl\h'|\\n:u' +.\} +. \" troff and (daisy-wheel) nroff accents +.ds : \\k:\h'-(\\n(.wu*8/10-\*(#H+.1m+\*(#F)'\v'-\*(#V'\z.\h'.2m+\*(#F'.\h'|\\n:u'\v'\*(#V' +.ds 8 \h'\*(#H'\(*b\h'-\*(#H' +.ds o \\k:\h'-(\\n(.wu+\w'\(de'u-\*(#H)/2u'\v'-.3n'\*(#[\z\(de\v'.3n'\h'|\\n:u'\*(#] +.ds d- \h'\*(#H'\(pd\h'-\w'~'u'\v'-.25m'\f2\(hy\fP\v'.25m'\h'-\*(#H' +.ds D- D\\k:\h'-\w'D'u'\v'-.11m'\z\(hy\v'.11m'\h'|\\n:u' +.ds th \*(#[\v'.3m'\s+1I\s-1\v'-.3m'\h'-(\w'I'u*2/3)'\s-1o\s+1\*(#] +.ds Th \*(#[\s+2I\s-2\h'-\w'I'u*3/5'\v'-.3m'o\v'.3m'\*(#] +.ds ae a\h'-(\w'a'u*4/10)'e +.ds Ae A\h'-(\w'A'u*4/10)'E +. \" corrections for vroff +.if v .ds ~ \\k:\h'-(\\n(.wu*9/10-\*(#H)'\s-2\u~\d\s+2\h'|\\n:u' +.if v .ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'\v'-.4m'^\v'.4m'\h'|\\n:u' +. \" for low resolution devices (crt and lpr) +.if \n(.H>23 .if \n(.V>19 \ +\{\ +. ds : e +. ds 8 ss +. ds o a +. ds d- d\h'-1'\(ga +. ds D- D\h'-1'\(hy +. ds th \o'bp' +. ds Th \o'LP' +. ds ae ae +. ds Ae AE +.\} +.rm #[ #] #H #V #F C +.\" ======================================================================== +.\" +.IX Title "xpagetfd 3" +.TH xpagetfd 3 "July 23, 2013" "version 2.1.15" "SAORD Documentation" +.\" For nroff, turn off justification. Always turn off hyphenation; it makes +.\" way too many mistakes in technical documents. +.if n .ad l +.nh +.SH "NAME" +\&\fBXPAGetFd: retrieve data from one or more \s-1XPA\s0 servers and write to files\fR +.SH "SYNOPSIS" +.IX Header "SYNOPSIS" +.Vb 1 +\& #include <xpa.h> +\& +\& int XPAGetFd(XPA xpa, +\& char *template, char *paramlist, char *mode, +\& int *fds, char **names, char **messages, int n); +.Ve +.SH "DESCRIPTION" +.IX Header "DESCRIPTION" +Retrieve data from one or more \s-1XPA\s0 servers whose class:name identifier +matches the specified +template +and write it to files associated with +one or more standard I/O fds (i.e, handles returned by \fIopen()\fR). +.PP +A +template +of the form \*(L"class1:name1\*(R" is sent to the +\&\s-1XPA\s0 name server, which returns a list of at most \s-1ABS\s0(n) matching \s-1XPA\s0 +servers. A connection is established with each of these servers and +the paramlist string is passed to the server as the data transfer +request is initiated. If an \s-1XPA\s0 struct is passed to the call, then the +persistent connections are updated as described above. Otherwise, +temporary connections are made to the servers (which will be closed +when the call completes). +.PP +The \fIXPAGetFd()\fR routine then retrieves data from the \s-1XPA\s0 servers, +and write these data to the fds associated with one or more fds +(i.e., results from open). Is n is positive, then there will be n fds +and the data from each server will be sent to a separate fd. If n is +negative, then there is only 1 fd and all data is sent to this single +fd. (The latter is how xpaget is implemented.) +.PP +A string containing the class:name and ip:port is stored in the name +array. If a given server returned an error or the server callback +sends a message back to the client, then the message will be stored in +the associated element of the messages array. \s-1NB:\s0 if specified, the +name and messages arrays must be of size n or greater. +.PP +The returned message string will be of the form: +.PP +.Vb 1 +\& XPA$ERROR error\-message (class:name ip:port) +.Ve +.PP +or +.PP +.Vb 1 +\& XPA$MESSAGE message (class:name ip:port) +.Ve +.PP +Note that when there is an error stored in an messages entry, the +corresponding bufs and lens entry may or may not be \s-1NULL\s0 and 0 +(respectively), depending on the particularities of the server. +.PP +The return value will contain the actual number of servers that were +processed. This value thus will hold the number of valid entries in +the bufs, lens, names, and messages arrays, and can be used to loop +through these arrays. In names and/or messages is \s-1NULL\s0, no information is +passed back in that array. +.PP +The mode string is of the form: \*(L"key1=value1,key2=value2,...\*(R" +The following keywords are recognized: +.PP +.Vb 3 +\& key value default explanation +\& \-\-\-\-\-\- \-\-\-\-\-\-\-\- \-\-\-\-\-\-\-\- \-\-\-\-\-\-\-\-\-\-\- +\& ack true/false true if false, don\*(Aqt wait for ack from server (after callback completes) +.Ve +.PP +The ack keyword is not very useful, since the server completes the callback +in order to return the data anyway. It is here for completion (and perhaps +for future usefulness). +.PP +\&\fBExample:\fR +.PP +.Vb 10 +\& #include <xpa.h> +\& #define NXPA 10 +\& int i, got; +\& int fds[NXPA]; +\& char *names[NXPA]; +\& char *messages[NXPA]; +\& for(i=0; i<NXPA; i++) +\& fds[i] = open(...); +\& got = XPAGetFd(NULL, "ds9", "file", NULL, fds, names, messages, NXPA); +\& for(i=0; i<got; i++){ +\& if( messages[i] != NULL ){ +\& /* error processing */ +\& fprintf(stderr, "ERROR: %s (%s)\en", messages[i], names[i]); +\& } +\& if( names[i] ) +\& free(names[i]); +\& if( messages[i] ) +\& free(messages[i]); +\& } +.Ve +.SH "SEE ALSO" +.IX Header "SEE ALSO" +See xpa(n) for a list of \s-1XPA\s0 help pages diff --git a/xpa/man/man3/xpainfo.3 b/xpa/man/man3/xpainfo.3 new file mode 100644 index 0000000..4f51a05 --- /dev/null +++ b/xpa/man/man3/xpainfo.3 @@ -0,0 +1,213 @@ +.\" Automatically generated by Pod::Man 2.22 (Pod::Simple 3.13) +.\" +.\" Standard preamble: +.\" ======================================================================== +.de Sp \" Vertical space (when we can't use .PP) +.if t .sp .5v +.if n .sp +.. +.de Vb \" Begin verbatim text +.ft CW +.nf +.ne \\$1 +.. +.de Ve \" End verbatim text +.ft R +.fi +.. +.\" Set up some character translations and predefined strings. \*(-- will +.\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left +.\" double quote, and \*(R" will give a right double quote. \*(C+ will +.\" give a nicer C++. Capital omega is used to do unbreakable dashes and +.\" therefore won't be available. \*(C` and \*(C' expand to `' in nroff, +.\" nothing in troff, for use with C<>. +.tr \(*W- +.ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p' +.ie n \{\ +. ds -- \(*W- +. ds PI pi +. if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch +. if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch +. ds L" "" +. ds R" "" +. ds C` "" +. ds C' "" +'br\} +.el\{\ +. ds -- \|\(em\| +. ds PI \(*p +. ds L" `` +. ds R" '' +'br\} +.\" +.\" Escape single quotes in literal strings from groff's Unicode transform. +.ie \n(.g .ds Aq \(aq +.el .ds Aq ' +.\" +.\" If the F register is turned on, we'll generate index entries on stderr for +.\" titles (.TH), headers (.SH), subsections (.SS), items (.Ip), and index +.\" entries marked with X<> in POD. Of course, you'll have to process the +.\" output yourself in some meaningful fashion. +.ie \nF \{\ +. de IX +. tm Index:\\$1\t\\n%\t"\\$2" +.. +. nr % 0 +. rr F +.\} +.el \{\ +. de IX +.. +.\} +.\" +.\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2). +.\" Fear. Run. Save yourself. No user-serviceable parts. +. \" fudge factors for nroff and troff +.if n \{\ +. ds #H 0 +. ds #V .8m +. ds #F .3m +. ds #[ \f1 +. ds #] \fP +.\} +.if t \{\ +. ds #H ((1u-(\\\\n(.fu%2u))*.13m) +. ds #V .6m +. ds #F 0 +. ds #[ \& +. ds #] \& +.\} +. \" simple accents for nroff and troff +.if n \{\ +. ds ' \& +. ds ` \& +. ds ^ \& +. ds , \& +. ds ~ ~ +. ds / +.\} +.if t \{\ +. ds ' \\k:\h'-(\\n(.wu*8/10-\*(#H)'\'\h"|\\n:u" +. ds ` \\k:\h'-(\\n(.wu*8/10-\*(#H)'\`\h'|\\n:u' +. ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'^\h'|\\n:u' +. ds , \\k:\h'-(\\n(.wu*8/10)',\h'|\\n:u' +. ds ~ \\k:\h'-(\\n(.wu-\*(#H-.1m)'~\h'|\\n:u' +. ds / \\k:\h'-(\\n(.wu*8/10-\*(#H)'\z\(sl\h'|\\n:u' +.\} +. \" troff and (daisy-wheel) nroff accents +.ds : \\k:\h'-(\\n(.wu*8/10-\*(#H+.1m+\*(#F)'\v'-\*(#V'\z.\h'.2m+\*(#F'.\h'|\\n:u'\v'\*(#V' +.ds 8 \h'\*(#H'\(*b\h'-\*(#H' +.ds o \\k:\h'-(\\n(.wu+\w'\(de'u-\*(#H)/2u'\v'-.3n'\*(#[\z\(de\v'.3n'\h'|\\n:u'\*(#] +.ds d- \h'\*(#H'\(pd\h'-\w'~'u'\v'-.25m'\f2\(hy\fP\v'.25m'\h'-\*(#H' +.ds D- D\\k:\h'-\w'D'u'\v'-.11m'\z\(hy\v'.11m'\h'|\\n:u' +.ds th \*(#[\v'.3m'\s+1I\s-1\v'-.3m'\h'-(\w'I'u*2/3)'\s-1o\s+1\*(#] +.ds Th \*(#[\s+2I\s-2\h'-\w'I'u*3/5'\v'-.3m'o\v'.3m'\*(#] +.ds ae a\h'-(\w'a'u*4/10)'e +.ds Ae A\h'-(\w'A'u*4/10)'E +. \" corrections for vroff +.if v .ds ~ \\k:\h'-(\\n(.wu*9/10-\*(#H)'\s-2\u~\d\s+2\h'|\\n:u' +.if v .ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'\v'-.4m'^\v'.4m'\h'|\\n:u' +. \" for low resolution devices (crt and lpr) +.if \n(.H>23 .if \n(.V>19 \ +\{\ +. ds : e +. ds 8 ss +. ds o a +. ds d- d\h'-1'\(ga +. ds D- D\h'-1'\(hy +. ds th \o'bp' +. ds Th \o'LP' +. ds ae ae +. ds Ae AE +.\} +.rm #[ #] #H #V #F C +.\" ======================================================================== +.\" +.IX Title "xpainfo 3" +.TH xpainfo 3 "July 23, 2013" "version 2.1.15" "SAORD Documentation" +.\" For nroff, turn off justification. Always turn off hyphenation; it makes +.\" way too many mistakes in technical documents. +.if n .ad l +.nh +.SH "NAME" +\&\fBXPAInfo: send short message to one or more \s-1XPA\s0 servers\fR +.SH "SYNOPSIS" +.IX Header "SYNOPSIS" +.Vb 1 +\& #include <xpa.h> +\& +\& int XPAInfo(XPA xpa, +\& char *template, char *paramlist, char *mode, +\& char **names, char **messages, int n); +.Ve +.SH "DESCRIPTION" +.IX Header "DESCRIPTION" +Send a short paramlist message to one or more \s-1XPA\s0 servers whose +class:name identifier matches the specified +template. +.PP +A +template +of the form \*(L"class1:name1\*(R" is sent to the +\&\s-1XPA\s0 name server, which returns a list of at most n matching \s-1XPA\s0 +servers. A connection is established with each of these servers and +the paramlist string is passed to the server as the data transfer +request is initiated. If an \s-1XPA\s0 struct is passed to the call, then the +persistent connections are updated as described above. Otherwise, +temporary connections are made to the servers (which will be closed +when the call completes). +.PP +The \fIXPAInfo()\fR routine does not send data from a buf to the \s-1XPA\s0 +servers. Only the paramlist is sent. The semantics of the paramlist +is not formalized, but at a minimum is should tell the server how to +get more information. For example, it might contain the class:name +of the \s-1XPA\s0 access point from which the server (acting as a client) +can obtain more info using XPAGet. +.PP +A string containing the class:name and ip:port of each server is +returned in the name array. If a given server returned an error or +the server callback sends a message back to the client, then the +message will be stored in the associated element of the messages +array. The returned message string will be of the form: +.PP +.Vb 1 +\& XPA$ERROR error\-message (class:name ip:port) +.Ve +.PP +or +.PP +.Vb 1 +\& XPA$MESSAGE message (class:name ip:port) +.Ve +.PP +The return value will contain the actual number of servers that were +processed. This value thus will hold the number of valid entries in +the names and messages arrays, and can be used to loop through these +arrays. In names and/or messages is \s-1NULL\s0, no information is passed back +in that array. +.PP +The following keywords are recognized: +.PP +.Vb 3 +\& key value default explanation +\& \-\-\-\-\-\- \-\-\-\-\-\-\-\- \-\-\-\-\-\-\-\- \-\-\-\-\-\-\-\-\-\-\- +\& ack true/false true if false, don\*(Aqt wait for ack from server +.Ve +.PP +When ack is false, \fIXPAInfo()\fR will not wait for an error return from the \s-1XPA\s0 +server. This means, in effect, that XPAInfo will send its paramlist string +to the \s-1XPA\s0 server and then exit: no information will be sent from the server +to the client. This UDP-like behavior is essential to avoid race +conditions in cases where \s-1XPA\s0 servers are sending info messages to +other servers. If two servers try to send each other an info message +at the same time and then wait for an ack, a race condition will result and +one or both will time out. +.PP +\&\fBExample:\fR +.PP +.Vb 1 +\& (void)XPAInfo(NULL, "IMAGE", "ds9 image", NULL, NULL, NULL, 0); +.Ve +.SH "SEE ALSO" +.IX Header "SEE ALSO" +See xpa(n) for a list of \s-1XPA\s0 help pages diff --git a/xpa/man/man3/xpainfonew.3 b/xpa/man/man3/xpainfonew.3 new file mode 100644 index 0000000..bab9739 --- /dev/null +++ b/xpa/man/man3/xpainfonew.3 @@ -0,0 +1,195 @@ +.\" Automatically generated by Pod::Man 2.22 (Pod::Simple 3.13) +.\" +.\" Standard preamble: +.\" ======================================================================== +.de Sp \" Vertical space (when we can't use .PP) +.if t .sp .5v +.if n .sp +.. +.de Vb \" Begin verbatim text +.ft CW +.nf +.ne \\$1 +.. +.de Ve \" End verbatim text +.ft R +.fi +.. +.\" Set up some character translations and predefined strings. \*(-- will +.\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left +.\" double quote, and \*(R" will give a right double quote. \*(C+ will +.\" give a nicer C++. Capital omega is used to do unbreakable dashes and +.\" therefore won't be available. \*(C` and \*(C' expand to `' in nroff, +.\" nothing in troff, for use with C<>. +.tr \(*W- +.ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p' +.ie n \{\ +. ds -- \(*W- +. ds PI pi +. if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch +. if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch +. ds L" "" +. ds R" "" +. ds C` "" +. ds C' "" +'br\} +.el\{\ +. ds -- \|\(em\| +. ds PI \(*p +. ds L" `` +. ds R" '' +'br\} +.\" +.\" Escape single quotes in literal strings from groff's Unicode transform. +.ie \n(.g .ds Aq \(aq +.el .ds Aq ' +.\" +.\" If the F register is turned on, we'll generate index entries on stderr for +.\" titles (.TH), headers (.SH), subsections (.SS), items (.Ip), and index +.\" entries marked with X<> in POD. Of course, you'll have to process the +.\" output yourself in some meaningful fashion. +.ie \nF \{\ +. de IX +. tm Index:\\$1\t\\n%\t"\\$2" +.. +. nr % 0 +. rr F +.\} +.el \{\ +. de IX +.. +.\} +.\" +.\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2). +.\" Fear. Run. Save yourself. No user-serviceable parts. +. \" fudge factors for nroff and troff +.if n \{\ +. ds #H 0 +. ds #V .8m +. ds #F .3m +. ds #[ \f1 +. ds #] \fP +.\} +.if t \{\ +. ds #H ((1u-(\\\\n(.fu%2u))*.13m) +. ds #V .6m +. ds #F 0 +. ds #[ \& +. ds #] \& +.\} +. \" simple accents for nroff and troff +.if n \{\ +. ds ' \& +. ds ` \& +. ds ^ \& +. ds , \& +. ds ~ ~ +. ds / +.\} +.if t \{\ +. ds ' \\k:\h'-(\\n(.wu*8/10-\*(#H)'\'\h"|\\n:u" +. ds ` \\k:\h'-(\\n(.wu*8/10-\*(#H)'\`\h'|\\n:u' +. ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'^\h'|\\n:u' +. ds , \\k:\h'-(\\n(.wu*8/10)',\h'|\\n:u' +. ds ~ \\k:\h'-(\\n(.wu-\*(#H-.1m)'~\h'|\\n:u' +. ds / \\k:\h'-(\\n(.wu*8/10-\*(#H)'\z\(sl\h'|\\n:u' +.\} +. \" troff and (daisy-wheel) nroff accents +.ds : \\k:\h'-(\\n(.wu*8/10-\*(#H+.1m+\*(#F)'\v'-\*(#V'\z.\h'.2m+\*(#F'.\h'|\\n:u'\v'\*(#V' +.ds 8 \h'\*(#H'\(*b\h'-\*(#H' +.ds o \\k:\h'-(\\n(.wu+\w'\(de'u-\*(#H)/2u'\v'-.3n'\*(#[\z\(de\v'.3n'\h'|\\n:u'\*(#] +.ds d- \h'\*(#H'\(pd\h'-\w'~'u'\v'-.25m'\f2\(hy\fP\v'.25m'\h'-\*(#H' +.ds D- D\\k:\h'-\w'D'u'\v'-.11m'\z\(hy\v'.11m'\h'|\\n:u' +.ds th \*(#[\v'.3m'\s+1I\s-1\v'-.3m'\h'-(\w'I'u*2/3)'\s-1o\s+1\*(#] +.ds Th \*(#[\s+2I\s-2\h'-\w'I'u*3/5'\v'-.3m'o\v'.3m'\*(#] +.ds ae a\h'-(\w'a'u*4/10)'e +.ds Ae A\h'-(\w'A'u*4/10)'E +. \" corrections for vroff +.if v .ds ~ \\k:\h'-(\\n(.wu*9/10-\*(#H)'\s-2\u~\d\s+2\h'|\\n:u' +.if v .ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'\v'-.4m'^\v'.4m'\h'|\\n:u' +. \" for low resolution devices (crt and lpr) +.if \n(.H>23 .if \n(.V>19 \ +\{\ +. ds : e +. ds 8 ss +. ds o a +. ds d- d\h'-1'\(ga +. ds D- D\h'-1'\(hy +. ds th \o'bp' +. ds Th \o'LP' +. ds ae ae +. ds Ae AE +.\} +.rm #[ #] #H #V #F C +.\" ======================================================================== +.\" +.IX Title "xpainfonew 3" +.TH xpainfonew 3 "July 23, 2013" "version 2.1.15" "SAORD Documentation" +.\" For nroff, turn off justification. Always turn off hyphenation; it makes +.\" way too many mistakes in technical documents. +.if n .ad l +.nh +.SH "NAME" +\&\fBXPAInfoNew: define an \s-1XPA\s0 info public access point\fR +.SH "SYNOPSIS" +.IX Header "SYNOPSIS" +.Vb 1 +\& #include <xpa.h> +\& +\& XPA XPAInfoNew(char *class, char *name, +\& int (*info_callback)(), +\& void *info_data, char *info_mode); +.Ve +.SH "DESCRIPTION" +.IX Header "DESCRIPTION" +[\s-1NB:\s0 this is an experimental interface, new to \s-1XPA\s0 2.0, whose value +and best use is evolving.] +.PP +A program can register interest in receiving a short message about a +particular topic from any other process that cares to send such a +message. Neither has to be an \s-1XPA\s0 server. For example, if a user +starts to work with a new image file called new.fits, she might +wish to alert interested programs about this new file by sending a +short message using xpainfo: +.PP +.Vb 1 +\& xpainfo IMAGEFILE /data/new.fits +.Ve +.PP +In this example, each process that has used the \fIXPAInfoNew()\fR call to +register interest in messages associated with the identifier \s-1IMAGEFILE\s0 +will have its \fIinfo_callback()\fR executed with the following calling +sequence: +.PP +.Vb 4 +\& int info_cb(void *info_data, void *call_data, char *paramlist) +\& { +\& XPA xpa = (XPA)call_data; +\& } +.Ve +.PP +The arguments passed to this routine are equivalent to those sent in +the \fIsend_callback()\fR routine. The main difference is that there is no +buf sent to the info callback: this mechanism is meant for short +announcement of messages of interest to many clients. +.PP +The mode string is of the form: \*(L"key1=value1,key2=value2,...\*(R" +The following keywords are recognized: +.PP +.Vb 3 +\& key value default explanation +\& \-\-\-\-\-\- \-\-\-\-\-\-\-\- \-\-\-\-\-\-\-\- \-\-\-\-\-\-\-\-\-\-\- +\& acl true/false true enable access control +.Ve +.PP +Because no buf is passed to this callback, the usual buf-related keywords +are not applicable here. +.PP +The information sent in the parameter list is arbitrary. However, we +envision sending information such as file names or \s-1XPA\s0 access points +from which to collect more data. Note that the xpainfo program and +the \fIXPAInfo()\fR routine that cause the info_callback to execute do not +wait for the callback to complete before returning. +.SH "SEE ALSO" +.IX Header "SEE ALSO" +See xpa(n) for a list of \s-1XPA\s0 help pages diff --git a/xpa/man/man3/xpamacros.3 b/xpa/man/man3/xpamacros.3 new file mode 100644 index 0000000..c9a6ab5 --- /dev/null +++ b/xpa/man/man3/xpamacros.3 @@ -0,0 +1,180 @@ +.\" Automatically generated by Pod::Man 2.22 (Pod::Simple 3.13) +.\" +.\" Standard preamble: +.\" ======================================================================== +.de Sp \" Vertical space (when we can't use .PP) +.if t .sp .5v +.if n .sp +.. +.de Vb \" Begin verbatim text +.ft CW +.nf +.ne \\$1 +.. +.de Ve \" End verbatim text +.ft R +.fi +.. +.\" Set up some character translations and predefined strings. \*(-- will +.\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left +.\" double quote, and \*(R" will give a right double quote. \*(C+ will +.\" give a nicer C++. Capital omega is used to do unbreakable dashes and +.\" therefore won't be available. \*(C` and \*(C' expand to `' in nroff, +.\" nothing in troff, for use with C<>. +.tr \(*W- +.ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p' +.ie n \{\ +. ds -- \(*W- +. ds PI pi +. if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch +. if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch +. ds L" "" +. ds R" "" +. ds C` "" +. ds C' "" +'br\} +.el\{\ +. ds -- \|\(em\| +. ds PI \(*p +. ds L" `` +. ds R" '' +'br\} +.\" +.\" Escape single quotes in literal strings from groff's Unicode transform. +.ie \n(.g .ds Aq \(aq +.el .ds Aq ' +.\" +.\" If the F register is turned on, we'll generate index entries on stderr for +.\" titles (.TH), headers (.SH), subsections (.SS), items (.Ip), and index +.\" entries marked with X<> in POD. Of course, you'll have to process the +.\" output yourself in some meaningful fashion. +.ie \nF \{\ +. de IX +. tm Index:\\$1\t\\n%\t"\\$2" +.. +. nr % 0 +. rr F +.\} +.el \{\ +. de IX +.. +.\} +.\" +.\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2). +.\" Fear. Run. Save yourself. No user-serviceable parts. +. \" fudge factors for nroff and troff +.if n \{\ +. ds #H 0 +. ds #V .8m +. ds #F .3m +. ds #[ \f1 +. ds #] \fP +.\} +.if t \{\ +. ds #H ((1u-(\\\\n(.fu%2u))*.13m) +. ds #V .6m +. ds #F 0 +. ds #[ \& +. ds #] \& +.\} +. \" simple accents for nroff and troff +.if n \{\ +. ds ' \& +. ds ` \& +. ds ^ \& +. ds , \& +. ds ~ ~ +. ds / +.\} +.if t \{\ +. ds ' \\k:\h'-(\\n(.wu*8/10-\*(#H)'\'\h"|\\n:u" +. ds ` \\k:\h'-(\\n(.wu*8/10-\*(#H)'\`\h'|\\n:u' +. ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'^\h'|\\n:u' +. ds , \\k:\h'-(\\n(.wu*8/10)',\h'|\\n:u' +. ds ~ \\k:\h'-(\\n(.wu-\*(#H-.1m)'~\h'|\\n:u' +. ds / \\k:\h'-(\\n(.wu*8/10-\*(#H)'\z\(sl\h'|\\n:u' +.\} +. \" troff and (daisy-wheel) nroff accents +.ds : \\k:\h'-(\\n(.wu*8/10-\*(#H+.1m+\*(#F)'\v'-\*(#V'\z.\h'.2m+\*(#F'.\h'|\\n:u'\v'\*(#V' +.ds 8 \h'\*(#H'\(*b\h'-\*(#H' +.ds o \\k:\h'-(\\n(.wu+\w'\(de'u-\*(#H)/2u'\v'-.3n'\*(#[\z\(de\v'.3n'\h'|\\n:u'\*(#] +.ds d- \h'\*(#H'\(pd\h'-\w'~'u'\v'-.25m'\f2\(hy\fP\v'.25m'\h'-\*(#H' +.ds D- D\\k:\h'-\w'D'u'\v'-.11m'\z\(hy\v'.11m'\h'|\\n:u' +.ds th \*(#[\v'.3m'\s+1I\s-1\v'-.3m'\h'-(\w'I'u*2/3)'\s-1o\s+1\*(#] +.ds Th \*(#[\s+2I\s-2\h'-\w'I'u*3/5'\v'-.3m'o\v'.3m'\*(#] +.ds ae a\h'-(\w'a'u*4/10)'e +.ds Ae A\h'-(\w'A'u*4/10)'E +. \" corrections for vroff +.if v .ds ~ \\k:\h'-(\\n(.wu*9/10-\*(#H)'\s-2\u~\d\s+2\h'|\\n:u' +.if v .ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'\v'-.4m'^\v'.4m'\h'|\\n:u' +. \" for low resolution devices (crt and lpr) +.if \n(.H>23 .if \n(.V>19 \ +\{\ +. ds : e +. ds 8 ss +. ds o a +. ds d- d\h'-1'\(ga +. ds D- D\h'-1'\(hy +. ds th \o'bp' +. ds Th \o'LP' +. ds ae ae +. ds Ae AE +.\} +.rm #[ #] #H #V #F C +.\" ======================================================================== +.\" +.IX Title "xpamacros 3" +.TH xpamacros 3 "July 23, 2013" "version 2.1.15" "SAORD Documentation" +.\" For nroff, turn off justification. Always turn off hyphenation; it makes +.\" way too many mistakes in technical documents. +.if n .ad l +.nh +.SH "NAME" +\&\fB\s-1XPA\s0 Server Callback Macros\fR +.SH "SYNOPSIS" +.IX Header "SYNOPSIS" +.Vb 1 +\& #include <xpa.h> +\& +\& xpa_class, xpa_name, xpa_method, xpa_cmdfd, xpa_datafd, +\& xpa_sendian, xpa_cendian +.Ve +.SH "DESCRIPTION" +.IX Header "DESCRIPTION" +Server routines have access to information about the \s-1XPA\s0 being called via +the following macros (each of which takes the xpa handle as an argument): +.PP +.Vb 9 +\& macro explanation +\& \-\-\-\-\-\- \-\-\-\-\-\-\-\-\-\-\- +\& xpa_class class of this xpa +\& xpa_name name of this xpa +\& xpa_method method string (inet or local connect info) +\& xpa_cmdfd fd of command socket +\& xpa_datafd fd of data socket +\& xpa_sendian endian\-ness of server ("little" or "big") +\& xpa_cendian endian\-ness of client ("little" or "big" +.Ve +.PP +The argument to these macros is the call_data pointer that is passed +to the server procedure. This pointer should be type case to \s-1XPA\s0 +in the server routine: +.PP +.Vb 1 +\& XPA xpa = (XPA)call_data; +.Ve +.PP +The most important of these macros is \fIxpa_datafd()\fR. A server routine +that sets \*(L"fillbuf=false\*(R" in receive_mode or send_mode can use this +macro to perform I/O directly to/from the client, rather than using +buf. +.PP +The xpa_cendian and xpa_sendian macros can be used together to determine +if the data transferred from the client is byte swapped with respect +to the server. Values for these macros are: \*(L"little\*(R", \*(L"big\*(R", or \*(L"?\*(R". +In order to do a proper conversion, you still need to know the format +of the data (i.e., byte swapping is dependent on the size of the data +element being converted). +.SH "SEE ALSO" +.IX Header "SEE ALSO" +See xpa(n) for a list of \s-1XPA\s0 help pages diff --git a/xpa/man/man3/xpamainloop.3 b/xpa/man/man3/xpamainloop.3 new file mode 100644 index 0000000..ff01099 --- /dev/null +++ b/xpa/man/man3/xpamainloop.3 @@ -0,0 +1,214 @@ +.\" Automatically generated by Pod::Man 2.22 (Pod::Simple 3.13) +.\" +.\" Standard preamble: +.\" ======================================================================== +.de Sp \" Vertical space (when we can't use .PP) +.if t .sp .5v +.if n .sp +.. +.de Vb \" Begin verbatim text +.ft CW +.nf +.ne \\$1 +.. +.de Ve \" End verbatim text +.ft R +.fi +.. +.\" Set up some character translations and predefined strings. \*(-- will +.\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left +.\" double quote, and \*(R" will give a right double quote. \*(C+ will +.\" give a nicer C++. Capital omega is used to do unbreakable dashes and +.\" therefore won't be available. \*(C` and \*(C' expand to `' in nroff, +.\" nothing in troff, for use with C<>. +.tr \(*W- +.ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p' +.ie n \{\ +. ds -- \(*W- +. ds PI pi +. if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch +. if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch +. ds L" "" +. ds R" "" +. ds C` "" +. ds C' "" +'br\} +.el\{\ +. ds -- \|\(em\| +. ds PI \(*p +. ds L" `` +. ds R" '' +'br\} +.\" +.\" Escape single quotes in literal strings from groff's Unicode transform. +.ie \n(.g .ds Aq \(aq +.el .ds Aq ' +.\" +.\" If the F register is turned on, we'll generate index entries on stderr for +.\" titles (.TH), headers (.SH), subsections (.SS), items (.Ip), and index +.\" entries marked with X<> in POD. Of course, you'll have to process the +.\" output yourself in some meaningful fashion. +.ie \nF \{\ +. de IX +. tm Index:\\$1\t\\n%\t"\\$2" +.. +. nr % 0 +. rr F +.\} +.el \{\ +. de IX +.. +.\} +.\" +.\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2). +.\" Fear. Run. Save yourself. No user-serviceable parts. +. \" fudge factors for nroff and troff +.if n \{\ +. ds #H 0 +. ds #V .8m +. ds #F .3m +. ds #[ \f1 +. ds #] \fP +.\} +.if t \{\ +. ds #H ((1u-(\\\\n(.fu%2u))*.13m) +. ds #V .6m +. ds #F 0 +. ds #[ \& +. ds #] \& +.\} +. \" simple accents for nroff and troff +.if n \{\ +. ds ' \& +. ds ` \& +. ds ^ \& +. ds , \& +. ds ~ ~ +. ds / +.\} +.if t \{\ +. ds ' \\k:\h'-(\\n(.wu*8/10-\*(#H)'\'\h"|\\n:u" +. ds ` \\k:\h'-(\\n(.wu*8/10-\*(#H)'\`\h'|\\n:u' +. ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'^\h'|\\n:u' +. ds , \\k:\h'-(\\n(.wu*8/10)',\h'|\\n:u' +. ds ~ \\k:\h'-(\\n(.wu-\*(#H-.1m)'~\h'|\\n:u' +. ds / \\k:\h'-(\\n(.wu*8/10-\*(#H)'\z\(sl\h'|\\n:u' +.\} +. \" troff and (daisy-wheel) nroff accents +.ds : \\k:\h'-(\\n(.wu*8/10-\*(#H+.1m+\*(#F)'\v'-\*(#V'\z.\h'.2m+\*(#F'.\h'|\\n:u'\v'\*(#V' +.ds 8 \h'\*(#H'\(*b\h'-\*(#H' +.ds o \\k:\h'-(\\n(.wu+\w'\(de'u-\*(#H)/2u'\v'-.3n'\*(#[\z\(de\v'.3n'\h'|\\n:u'\*(#] +.ds d- \h'\*(#H'\(pd\h'-\w'~'u'\v'-.25m'\f2\(hy\fP\v'.25m'\h'-\*(#H' +.ds D- D\\k:\h'-\w'D'u'\v'-.11m'\z\(hy\v'.11m'\h'|\\n:u' +.ds th \*(#[\v'.3m'\s+1I\s-1\v'-.3m'\h'-(\w'I'u*2/3)'\s-1o\s+1\*(#] +.ds Th \*(#[\s+2I\s-2\h'-\w'I'u*3/5'\v'-.3m'o\v'.3m'\*(#] +.ds ae a\h'-(\w'a'u*4/10)'e +.ds Ae A\h'-(\w'A'u*4/10)'E +. \" corrections for vroff +.if v .ds ~ \\k:\h'-(\\n(.wu*9/10-\*(#H)'\s-2\u~\d\s+2\h'|\\n:u' +.if v .ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'\v'-.4m'^\v'.4m'\h'|\\n:u' +. \" for low resolution devices (crt and lpr) +.if \n(.H>23 .if \n(.V>19 \ +\{\ +. ds : e +. ds 8 ss +. ds o a +. ds d- d\h'-1'\(ga +. ds D- D\h'-1'\(hy +. ds th \o'bp' +. ds Th \o'LP' +. ds ae ae +. ds Ae AE +.\} +.rm #[ #] #H #V #F C +.\" ======================================================================== +.\" +.IX Title "xpamainloop 3" +.TH xpamainloop 3 "July 23, 2013" "version 2.1.15" "SAORD Documentation" +.\" For nroff, turn off justification. Always turn off hyphenation; it makes +.\" way too many mistakes in technical documents. +.if n .ad l +.nh +.SH "NAME" +\&\fBXPAMainLoop: optional main loop for \s-1XPA\s0\fR +.SH "SYNOPSIS" +.IX Header "SYNOPSIS" +.Vb 1 +\& #include <xpa.h> +\& +\& void XPAMainLoop(); +.Ve +.SH "DESCRIPTION" +.IX Header "DESCRIPTION" +Once \s-1XPA\s0 access points have been defined, a program must enter an +event loop to watch for requests from external programs. This can be +done in a variety of ways, depending on whether the event loop is +processing events other than \s-1XPA\s0 events. In cases where there are no +non-XPA events to be processed, the program can simply call the +\&\fIXPAMainLoop()\fR event loop. This loop is implemented essentially as +follows (error checking is simplified in this example): +.PP +.Vb 8 +\& FD_ZERO(&readfds); +\& while( XPAAddSelect(NULL, &readfds) ){ +\& if( sgot = select(swidth, &readfds, NULL, NULL, NULL) >0 ) +\& XPAProcessSelect(&readfds, 0); +\& else +\& break; +\& FD_ZERO(&readfds); +\& } +.Ve +.PP +The \fIXPAAddSelect()\fR routine sets up the \fIselect()\fR readfds variable so +that \fIselect()\fR will wait for I/O on all the active \s-1XPA\s0 channels. It +returns the number of XPAs that are active; the loop will end when +there are no active XPAs. The standard \fIselect()\fR routine is called to +wait for an external I/O request. Since no timeout struct is passed +in argument 5, the \fIselect()\fR call hangs until there is an external +request. When an external I/O request is made, the \fIXPAProcessSelect()\fR +routine is executed to process the pending requests. In this routine, +the maxreq value determines how many requests will be processed: if +maxreq <=0, then all currently pending requests will be processed. +Otherwise, up to maxreq requests will be processed. (The most usual +values for maxreq is 0 to process all requests.) +.PP +If a program has its own Unix \fIselect()\fR loop, then \s-1XPA\s0 access points can +be added to it by using a variation of the standard XPAMainLoop: +.PP +.Vb 7 +\& XPAAddSelect(xpa, &readfds); +\& [app\-specific ...] +\& if( select(width, &readfds, ...) ){ +\& XPAProcessSelect(&readfds, maxreq); +\& [app\-specific ...] +\& FD_ZERO(&readfds); +\& } +.Ve +.PP +\&\fIXPAAddSelect()\fR is called before \fIselect()\fR to add the access points. +If the first argument is \s-1NULL\s0, then all active \s-1XPA\s0 access points +are added. Otherwise only the specified access point is added. +After \fIselect()\fR is called, the \fIXPAProcessSelect()\fR routine can be called +to process \s-1XPA\s0 requests. Once again, the maxreq value determines how +many requests will be processed: if maxreq <=0, then all currently +pending requests will be processed. Otherwise, up to maxreq requests +will be processed. +.PP +\&\s-1XPA\s0 access points can be added to +Xt event loops (using \fIXtAppMainLoop()\fR) +and +Tcl/Tk event loops (using vwait and the Tk loop). +When using \s-1XPA\s0 with these event loops, you only need to call: +.PP +int XPAXtAddInput(XtAppContext app, \s-1XPA\s0 xpa) +.PP +or +.PP +.Vb 1 +\& int XPATclAddInput(XPA xpa) +.Ve +.PP +respectively before entering the loop. +.SH "SEE ALSO" +.IX Header "SEE ALSO" +See xpa(n) for a list of \s-1XPA\s0 help pages diff --git a/xpa/man/man3/xpanew.3 b/xpa/man/man3/xpanew.3 new file mode 100644 index 0000000..f4f72b6 --- /dev/null +++ b/xpa/man/man3/xpanew.3 @@ -0,0 +1,344 @@ +.\" Automatically generated by Pod::Man 2.22 (Pod::Simple 3.13) +.\" +.\" Standard preamble: +.\" ======================================================================== +.de Sp \" Vertical space (when we can't use .PP) +.if t .sp .5v +.if n .sp +.. +.de Vb \" Begin verbatim text +.ft CW +.nf +.ne \\$1 +.. +.de Ve \" End verbatim text +.ft R +.fi +.. +.\" Set up some character translations and predefined strings. \*(-- will +.\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left +.\" double quote, and \*(R" will give a right double quote. \*(C+ will +.\" give a nicer C++. Capital omega is used to do unbreakable dashes and +.\" therefore won't be available. \*(C` and \*(C' expand to `' in nroff, +.\" nothing in troff, for use with C<>. +.tr \(*W- +.ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p' +.ie n \{\ +. ds -- \(*W- +. ds PI pi +. if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch +. if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch +. ds L" "" +. ds R" "" +. ds C` "" +. ds C' "" +'br\} +.el\{\ +. ds -- \|\(em\| +. ds PI \(*p +. ds L" `` +. ds R" '' +'br\} +.\" +.\" Escape single quotes in literal strings from groff's Unicode transform. +.ie \n(.g .ds Aq \(aq +.el .ds Aq ' +.\" +.\" If the F register is turned on, we'll generate index entries on stderr for +.\" titles (.TH), headers (.SH), subsections (.SS), items (.Ip), and index +.\" entries marked with X<> in POD. Of course, you'll have to process the +.\" output yourself in some meaningful fashion. +.ie \nF \{\ +. de IX +. tm Index:\\$1\t\\n%\t"\\$2" +.. +. nr % 0 +. rr F +.\} +.el \{\ +. de IX +.. +.\} +.\" +.\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2). +.\" Fear. Run. Save yourself. No user-serviceable parts. +. \" fudge factors for nroff and troff +.if n \{\ +. ds #H 0 +. ds #V .8m +. ds #F .3m +. ds #[ \f1 +. ds #] \fP +.\} +.if t \{\ +. ds #H ((1u-(\\\\n(.fu%2u))*.13m) +. ds #V .6m +. ds #F 0 +. ds #[ \& +. ds #] \& +.\} +. \" simple accents for nroff and troff +.if n \{\ +. ds ' \& +. ds ` \& +. ds ^ \& +. ds , \& +. ds ~ ~ +. ds / +.\} +.if t \{\ +. ds ' \\k:\h'-(\\n(.wu*8/10-\*(#H)'\'\h"|\\n:u" +. ds ` \\k:\h'-(\\n(.wu*8/10-\*(#H)'\`\h'|\\n:u' +. ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'^\h'|\\n:u' +. ds , \\k:\h'-(\\n(.wu*8/10)',\h'|\\n:u' +. ds ~ \\k:\h'-(\\n(.wu-\*(#H-.1m)'~\h'|\\n:u' +. ds / \\k:\h'-(\\n(.wu*8/10-\*(#H)'\z\(sl\h'|\\n:u' +.\} +. \" troff and (daisy-wheel) nroff accents +.ds : \\k:\h'-(\\n(.wu*8/10-\*(#H+.1m+\*(#F)'\v'-\*(#V'\z.\h'.2m+\*(#F'.\h'|\\n:u'\v'\*(#V' +.ds 8 \h'\*(#H'\(*b\h'-\*(#H' +.ds o \\k:\h'-(\\n(.wu+\w'\(de'u-\*(#H)/2u'\v'-.3n'\*(#[\z\(de\v'.3n'\h'|\\n:u'\*(#] +.ds d- \h'\*(#H'\(pd\h'-\w'~'u'\v'-.25m'\f2\(hy\fP\v'.25m'\h'-\*(#H' +.ds D- D\\k:\h'-\w'D'u'\v'-.11m'\z\(hy\v'.11m'\h'|\\n:u' +.ds th \*(#[\v'.3m'\s+1I\s-1\v'-.3m'\h'-(\w'I'u*2/3)'\s-1o\s+1\*(#] +.ds Th \*(#[\s+2I\s-2\h'-\w'I'u*3/5'\v'-.3m'o\v'.3m'\*(#] +.ds ae a\h'-(\w'a'u*4/10)'e +.ds Ae A\h'-(\w'A'u*4/10)'E +. \" corrections for vroff +.if v .ds ~ \\k:\h'-(\\n(.wu*9/10-\*(#H)'\s-2\u~\d\s+2\h'|\\n:u' +.if v .ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'\v'-.4m'^\v'.4m'\h'|\\n:u' +. \" for low resolution devices (crt and lpr) +.if \n(.H>23 .if \n(.V>19 \ +\{\ +. ds : e +. ds 8 ss +. ds o a +. ds d- d\h'-1'\(ga +. ds D- D\h'-1'\(hy +. ds th \o'bp' +. ds Th \o'LP' +. ds ae ae +. ds Ae AE +.\} +.rm #[ #] #H #V #F C +.\" ======================================================================== +.\" +.IX Title "xpanew 3" +.TH xpanew 3 "July 23, 2013" "version 2.1.15" "SAORD Documentation" +.\" For nroff, turn off justification. Always turn off hyphenation; it makes +.\" way too many mistakes in technical documents. +.if n .ad l +.nh +.SH "NAME" +\&\fBXPANew: create a new \s-1XPA\s0 access point\fR +.SH "SYNOPSIS" +.IX Header "SYNOPSIS" +.Vb 1 +\& #include <xpa.h> +\& +\& XPA XPANew(char *class, char *name, char *help, +\& int (*send_callback)(), +\& void *send_data, char *send_mode, +\& int (*rec_callback)(), +\& void *rec_data, char *rec_mode); +.Ve +.SH "DESCRIPTION" +.IX Header "DESCRIPTION" +Create a new \s-1XPA\s0 public access point with the class:name +identifier template +and enter this access point into the \s-1XPA\s0 name server, so that it +can be accessed by external processes. \fIXPANew()\fR returns an \s-1XPA\s0 struct. +Note that the length of the class and name designations must be less +than or equal to 1024 characters each. +.PP +The \s-1XPA\s0 name server daemon, xpans, will be started automatically if it +is not running already (assuming it can be found in the path). The +program's ip address and listening port are specified by the +environment variable \s-1XPA_NSINET\s0, which takes the form :. If +no such environment variable exists, then xpans is started on the +current machine listening on port 14285. It also uses 14286 as a +known port for its public access point (so that routines do not have +to go to the name server to find the name server ip and port!) +As of \s-1XPA\s0 2.1.1, version information is exchanged between the xpans +process and the new access point. If the access point uses an \s-1XPA\s0 +major/minor version newer than xpans, a warning is issued by both processes, +since mixing of new servers and old xpa programs (xpaset, xpaget, +xpans, etc.) is not likely to work. You can turn off the warning +message by setting the \s-1XPA_VERSIONCHECK\s0 environment variable to \*(L"false\*(R". +.PP +The help string is meant to be returned by a request from xpaget: +.PP +.Vb 1 +\& xpaget class:name \-help +.Ve +.PP +A send_callback and/or a receive_callback can be specified; at +least one of them must be specified. +.PP +A send_callback can be specified that will be executed in response to +an external request from the xpaget program, the \fIXPAGet()\fR routine, or +\&\fIXPAGetFd()\fR routine. This callback is used to send data to the +requesting client. +.PP +The calling sequence for \fIsend_callback()\fR is: +.PP +.Vb 7 +\& int send_callback(void *send_data, void *call_data, +\& char *paramlist, char **buf, size_t *len) +\& { +\& XPA xpa = (XPA)call_data; +\& ... +\& return(stat); +\& } +.Ve +.PP +The send_mode string is of the form: \*(L"key1=value1,key2=value2,...\*(R" +The following keywords are recognized: +.PP +.Vb 4 +\& key value default explanation +\& \-\-\-\-\-\- \-\-\-\-\-\-\-\- \-\-\-\-\-\-\-\- \-\-\-\-\-\-\-\-\-\-\- +\& acl true/false true enable access control +\& freebuf true/false true free buf after callback completes +.Ve +.PP +The call_data should be recast to the \s-1XPA\s0 struct as shown. In +addition, client-specific data can be passed to the callback in +send_data. +.PP +The paramlist will be supplied by the client as qualifying parameters +for the callback. There are two ways in which the \fIsend_callback()\fR +routine can send data back to the client: +.PP +1. The \fIsend_callback()\fR routine can fill in a buffer and pass back a +pointer to this buffer. An integer len also is returned to specify the +number of bytes of data in buf. \s-1XPA\s0 will send this buffer to the +client after the callback is complete. +.PP +2. The send_callback can send data directly to the client by writing +to the fd pointed by the macro: +.PP +.Vb 1 +\& xpa_datafd(xpa) +.Ve +.PP +Note that this fd is of the kind returned by \fIsocket()\fR or \fIopen()\fR. +.PP +If a buf has been allocated by a standard malloc routine, filled, and +returned to \s-1XPA\s0, then freebuf generally is set so that the buffer will +be freed automatically when the callback is completed and data has +been sent to the client. If a static buf is returned, freebuf should +be set to false to avoid a system error when freeing static storage. +Note that default value for freebuf implies that the callback will +allocate a buffer rather than use static storage. +.PP +On the other hand, if buf is dynamically allocated using a method +other than a standard malloc/calloc/realloc routine (e.g. using Perl's +memory allocation and garbage collection scheme), then it is necessary +to tell \s-1XPA\s0 how to free the allocated buffer. To do this, use the +\&\fIXPASetFree()\fR routine within your callback: +.PP +.Vb 1 +\& void XPASetFree(XPA xpa, void (*myfree)(void *), void *myfree_ptr); +.Ve +.PP +The first argument is the usual \s-1XPA\s0 handle. The second argument is the +special routine to call to free your allocated memory. The third +argument is an optional pointer. If not \s-1NULL\s0, the specified free +routine is called with that pointer as its sole argument. If \s-1NULL\s0, the +free routine is called with the standard buf pointer as its sole +argument. This is useful in cases where there is a mapping between the +buffer pointer and the actual allocated memory location, and the +special routine is expecting to be passed the former. +.PP +If, while the callback performs its processing, an error occurs that +should be communicated to the client, then the routine XPAError should be +called: +.PP +.Vb 1 +\& XPAError(XPA xpa, char *s); +.Ve +.PP +where s is an arbitrary error message. The returned error message +string will be of the form: +.PP +.Vb 1 +\& XPA$ERROR [error] (class:name ip:port) +.Ve +.PP +If the callback wants to send a specific acknowledgment message back +to the client, the routine XPAMessage can be called: +.PP +.Vb 1 +\& XPAMessage(XPA xpa, char *s); +.Ve +.PP +where s is an arbitrary error message. The returned error message +string will be of the form: +.PP +.Vb 1 +\& XPA$MESSAGE [message] (class:name ip:port) +.Ve +.PP +Otherwise, a standard acknowledgment is sent back to the client +after the callback is completed. +.PP +The callback routine should return 0 if no error occurs, or \-1 to +signal an error. +.PP +A receive_callback can be specified that will be executed in response +to an external request from the xpaset program, or the XPASet (or +\&\fIXPASetFd()\fR) routine. This callback is used to process data received +from an external process. +.PP +The calling sequence for receive_callback is: +.PP +.Vb 7 +\& int receive_callback(void *receive_data, void *call_data, +\& char *paramlist, char *buf, size_t len) +\& { +\& XPA xpa = (XPA)call_data; +\& ... +\& return(stat); +\& } +.Ve +.PP +The mode string is of the form: \*(L"key1=value1,key2=value2,...\*(R" +The following keywords are recognized: +.PP +.Vb 6 +\& key value default explanation +\& \-\-\-\-\-\- \-\-\-\-\-\-\-\- \-\-\-\-\-\-\-\- \-\-\-\-\-\-\-\-\-\-\- +\& acl true/false true enable access control +\& buf true/false true server expects data bytes from client +\& fillbuf true/false true read data into buf before executing callback +\& freebuf true/false true free buf after callback completes +.Ve +.PP +The call_data should be recast to the \s-1XPA\s0 struct as shown. In +addition, client-specific data can be passed to the callback in +receive_data. +.PP +The paramlist will be supplied by the client. In addition, if the +receive_mode keywords buf and fillbuf are true, then on entry into the +\&\fIreceive_callback()\fR routine, buf will contain the data sent by the +client. If buf is true but fillbuf is false, it becomes the callback's +responsibility to retrieve the data from the client, using the data fd +pointed to by the macro xpa_datafd(xpa). If freebuf is true, then buf +will be freed when the callback is complete. +.PP +If, while the callback is performing its processing, an error occurs +that should be communicated to the client, then the routine XPAError +can be called: +.PP +.Vb 1 +\& XPAError(XPA xpa, char *s); +.Ve +.PP +where s is an arbitrary error message. +.PP +The callback routine should return 0 if no error occurs, or \-1 to +signal an error. +.SH "SEE ALSO" +.IX Header "SEE ALSO" +See xpa(n) for a list of \s-1XPA\s0 help pages diff --git a/xpa/man/man3/xpanslookup.3 b/xpa/man/man3/xpanslookup.3 new file mode 100644 index 0000000..8725e3e --- /dev/null +++ b/xpa/man/man3/xpanslookup.3 @@ -0,0 +1,232 @@ +.\" Automatically generated by Pod::Man 2.22 (Pod::Simple 3.13) +.\" +.\" Standard preamble: +.\" ======================================================================== +.de Sp \" Vertical space (when we can't use .PP) +.if t .sp .5v +.if n .sp +.. +.de Vb \" Begin verbatim text +.ft CW +.nf +.ne \\$1 +.. +.de Ve \" End verbatim text +.ft R +.fi +.. +.\" Set up some character translations and predefined strings. \*(-- will +.\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left +.\" double quote, and \*(R" will give a right double quote. \*(C+ will +.\" give a nicer C++. Capital omega is used to do unbreakable dashes and +.\" therefore won't be available. \*(C` and \*(C' expand to `' in nroff, +.\" nothing in troff, for use with C<>. +.tr \(*W- +.ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p' +.ie n \{\ +. ds -- \(*W- +. ds PI pi +. if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch +. if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch +. ds L" "" +. ds R" "" +. ds C` "" +. ds C' "" +'br\} +.el\{\ +. ds -- \|\(em\| +. ds PI \(*p +. ds L" `` +. ds R" '' +'br\} +.\" +.\" Escape single quotes in literal strings from groff's Unicode transform. +.ie \n(.g .ds Aq \(aq +.el .ds Aq ' +.\" +.\" If the F register is turned on, we'll generate index entries on stderr for +.\" titles (.TH), headers (.SH), subsections (.SS), items (.Ip), and index +.\" entries marked with X<> in POD. Of course, you'll have to process the +.\" output yourself in some meaningful fashion. +.ie \nF \{\ +. de IX +. tm Index:\\$1\t\\n%\t"\\$2" +.. +. nr % 0 +. rr F +.\} +.el \{\ +. de IX +.. +.\} +.\" +.\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2). +.\" Fear. Run. Save yourself. No user-serviceable parts. +. \" fudge factors for nroff and troff +.if n \{\ +. ds #H 0 +. ds #V .8m +. ds #F .3m +. ds #[ \f1 +. ds #] \fP +.\} +.if t \{\ +. ds #H ((1u-(\\\\n(.fu%2u))*.13m) +. ds #V .6m +. ds #F 0 +. ds #[ \& +. ds #] \& +.\} +. \" simple accents for nroff and troff +.if n \{\ +. ds ' \& +. ds ` \& +. ds ^ \& +. ds , \& +. ds ~ ~ +. ds / +.\} +.if t \{\ +. ds ' \\k:\h'-(\\n(.wu*8/10-\*(#H)'\'\h"|\\n:u" +. ds ` \\k:\h'-(\\n(.wu*8/10-\*(#H)'\`\h'|\\n:u' +. ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'^\h'|\\n:u' +. ds , \\k:\h'-(\\n(.wu*8/10)',\h'|\\n:u' +. ds ~ \\k:\h'-(\\n(.wu-\*(#H-.1m)'~\h'|\\n:u' +. ds / \\k:\h'-(\\n(.wu*8/10-\*(#H)'\z\(sl\h'|\\n:u' +.\} +. \" troff and (daisy-wheel) nroff accents +.ds : \\k:\h'-(\\n(.wu*8/10-\*(#H+.1m+\*(#F)'\v'-\*(#V'\z.\h'.2m+\*(#F'.\h'|\\n:u'\v'\*(#V' +.ds 8 \h'\*(#H'\(*b\h'-\*(#H' +.ds o \\k:\h'-(\\n(.wu+\w'\(de'u-\*(#H)/2u'\v'-.3n'\*(#[\z\(de\v'.3n'\h'|\\n:u'\*(#] +.ds d- \h'\*(#H'\(pd\h'-\w'~'u'\v'-.25m'\f2\(hy\fP\v'.25m'\h'-\*(#H' +.ds D- D\\k:\h'-\w'D'u'\v'-.11m'\z\(hy\v'.11m'\h'|\\n:u' +.ds th \*(#[\v'.3m'\s+1I\s-1\v'-.3m'\h'-(\w'I'u*2/3)'\s-1o\s+1\*(#] +.ds Th \*(#[\s+2I\s-2\h'-\w'I'u*3/5'\v'-.3m'o\v'.3m'\*(#] +.ds ae a\h'-(\w'a'u*4/10)'e +.ds Ae A\h'-(\w'A'u*4/10)'E +. \" corrections for vroff +.if v .ds ~ \\k:\h'-(\\n(.wu*9/10-\*(#H)'\s-2\u~\d\s+2\h'|\\n:u' +.if v .ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'\v'-.4m'^\v'.4m'\h'|\\n:u' +. \" for low resolution devices (crt and lpr) +.if \n(.H>23 .if \n(.V>19 \ +\{\ +. ds : e +. ds 8 ss +. ds o a +. ds d- d\h'-1'\(ga +. ds D- D\h'-1'\(hy +. ds th \o'bp' +. ds Th \o'LP' +. ds ae ae +. ds Ae AE +.\} +.rm #[ #] #H #V #F C +.\" ======================================================================== +.\" +.IX Title "xpanslookup 3" +.TH xpanslookup 3 "July 23, 2013" "version 2.1.15" "SAORD Documentation" +.\" For nroff, turn off justification. Always turn off hyphenation; it makes +.\" way too many mistakes in technical documents. +.if n .ad l +.nh +.SH "NAME" +\&\fBXPANSLookup: lookup registered \s-1XPA\s0 access points\fR +.SH "SYNOPSIS" +.IX Header "SYNOPSIS" +.Vb 1 +\& #include <xpa.h> +\& +\& int XPANSLookup(XPA xpa, +\& char *template, char type, +\& char ***classes, char ***names, +\& char ***methods, char ***infos) +.Ve +.SH "DESCRIPTION" +.IX Header "DESCRIPTION" +\&\s-1XPA\s0 routines act on a class:name identifier in such a way +that all access points that match the identifier are processed. It is +sometimes desirable to choose specific access points from the +candidates that match the +template. In order to do this, the +XPANSLookup routine can be called to return a list of matches, so that +specific class:name instances can then be fed to \fIXPAGet()\fR, \fIXPASet()\fR, etc. +.PP +.Vb 4 +\& The first argument is an optional XPA struct. If non\-NULL, the +\&existing name server connection associated with the specified xpa is +\&used to query the xpans name server for matching templates. Otherwise, +\&a new (temporary) connection is established with the name server. +.Ve +.PP +The second argument to XPANSLookup is the class:name +template +to match. +.PP +The third argument for \fIXPANSLookup()\fR is the type of access and can be +any combination of: +.PP +.Vb 5 +\& type explanation +\& \-\-\-\-\-\- \-\-\-\-\-\-\-\-\-\-\- +\& g xpaget calls can be made on this access point +\& s xpaset calls can be made on this access point +\& i xpainfo calls can be made on this access point +.Ve +.PP +The call typically specifies only one of these at a time. +.PP +The final arguments are pointers to arrays that will be filled +in and returned by the name server. The name server will allocate and +return arrays filled with the classes, names, and methods of all \s-1XPA\s0 +access points that match the template +and have the specified type. Also returned are info strings, which +generally are used internally by the client routines. These can be +ignored (but the strings must be freed). The function returns the +number of matches. The returned value can be used to loop through the +matches: +.PP +\&\fBExample:\fR +.PP +.Vb 1 +\& #include <xpa.h> +\& +\& char **classes; +\& char **names; +\& char **methods; +\& char **infos; +\& int i, n; +\& n = XPANSLookup(NULL, "foo*", "g", &classes, &names, &methods, &infos); +\& for(i=0; i<n; i++){ +\& [more specific checks on possibilities ...] +\& [perhaps a call to XPAGet for those that pass, etc. ...] +\& /* don\*(Aqt forget to free alloc\*(Aqed strings when done */ +\& free(classes[i]); +\& free(names[i]); +\& free(methods[i]); +\& free(infos[i]); +\& } +\& /* free up arrays alloc\*(Aqed by names server */ +\& if( n > 0 ){ +\& free(classes); +\& free(names); +\& free(methods); +\& free(infos); +\& } +.Ve +.PP +The specified +template +also can be a host:port specification, for example: +.PP +.Vb 1 +\& myhost:12345 +.Ve +.PP +In this case, no connection is made to the name server. Instead, the +call will return one entry such that the ip array contains the ip for +the specified host and the port array contains the port. The class +and name entries are set to the character \*(L"?\*(R", since the class and +name of the access point are not known. +.SH "SEE ALSO" +.IX Header "SEE ALSO" +See xpa(n) for a list of \s-1XPA\s0 help pages diff --git a/xpa/man/man3/xpaopen.3 b/xpa/man/man3/xpaopen.3 new file mode 100644 index 0000000..c62af06 --- /dev/null +++ b/xpa/man/man3/xpaopen.3 @@ -0,0 +1,172 @@ +.\" Automatically generated by Pod::Man 2.22 (Pod::Simple 3.13) +.\" +.\" Standard preamble: +.\" ======================================================================== +.de Sp \" Vertical space (when we can't use .PP) +.if t .sp .5v +.if n .sp +.. +.de Vb \" Begin verbatim text +.ft CW +.nf +.ne \\$1 +.. +.de Ve \" End verbatim text +.ft R +.fi +.. +.\" Set up some character translations and predefined strings. \*(-- will +.\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left +.\" double quote, and \*(R" will give a right double quote. \*(C+ will +.\" give a nicer C++. Capital omega is used to do unbreakable dashes and +.\" therefore won't be available. \*(C` and \*(C' expand to `' in nroff, +.\" nothing in troff, for use with C<>. +.tr \(*W- +.ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p' +.ie n \{\ +. ds -- \(*W- +. ds PI pi +. if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch +. if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch +. ds L" "" +. ds R" "" +. ds C` "" +. ds C' "" +'br\} +.el\{\ +. ds -- \|\(em\| +. ds PI \(*p +. ds L" `` +. ds R" '' +'br\} +.\" +.\" Escape single quotes in literal strings from groff's Unicode transform. +.ie \n(.g .ds Aq \(aq +.el .ds Aq ' +.\" +.\" If the F register is turned on, we'll generate index entries on stderr for +.\" titles (.TH), headers (.SH), subsections (.SS), items (.Ip), and index +.\" entries marked with X<> in POD. Of course, you'll have to process the +.\" output yourself in some meaningful fashion. +.ie \nF \{\ +. de IX +. tm Index:\\$1\t\\n%\t"\\$2" +.. +. nr % 0 +. rr F +.\} +.el \{\ +. de IX +.. +.\} +.\" +.\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2). +.\" Fear. Run. Save yourself. No user-serviceable parts. +. \" fudge factors for nroff and troff +.if n \{\ +. ds #H 0 +. ds #V .8m +. ds #F .3m +. ds #[ \f1 +. ds #] \fP +.\} +.if t \{\ +. ds #H ((1u-(\\\\n(.fu%2u))*.13m) +. ds #V .6m +. ds #F 0 +. ds #[ \& +. ds #] \& +.\} +. \" simple accents for nroff and troff +.if n \{\ +. ds ' \& +. ds ` \& +. ds ^ \& +. ds , \& +. ds ~ ~ +. ds / +.\} +.if t \{\ +. ds ' \\k:\h'-(\\n(.wu*8/10-\*(#H)'\'\h"|\\n:u" +. ds ` \\k:\h'-(\\n(.wu*8/10-\*(#H)'\`\h'|\\n:u' +. ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'^\h'|\\n:u' +. ds , \\k:\h'-(\\n(.wu*8/10)',\h'|\\n:u' +. ds ~ \\k:\h'-(\\n(.wu-\*(#H-.1m)'~\h'|\\n:u' +. ds / \\k:\h'-(\\n(.wu*8/10-\*(#H)'\z\(sl\h'|\\n:u' +.\} +. \" troff and (daisy-wheel) nroff accents +.ds : \\k:\h'-(\\n(.wu*8/10-\*(#H+.1m+\*(#F)'\v'-\*(#V'\z.\h'.2m+\*(#F'.\h'|\\n:u'\v'\*(#V' +.ds 8 \h'\*(#H'\(*b\h'-\*(#H' +.ds o \\k:\h'-(\\n(.wu+\w'\(de'u-\*(#H)/2u'\v'-.3n'\*(#[\z\(de\v'.3n'\h'|\\n:u'\*(#] +.ds d- \h'\*(#H'\(pd\h'-\w'~'u'\v'-.25m'\f2\(hy\fP\v'.25m'\h'-\*(#H' +.ds D- D\\k:\h'-\w'D'u'\v'-.11m'\z\(hy\v'.11m'\h'|\\n:u' +.ds th \*(#[\v'.3m'\s+1I\s-1\v'-.3m'\h'-(\w'I'u*2/3)'\s-1o\s+1\*(#] +.ds Th \*(#[\s+2I\s-2\h'-\w'I'u*3/5'\v'-.3m'o\v'.3m'\*(#] +.ds ae a\h'-(\w'a'u*4/10)'e +.ds Ae A\h'-(\w'A'u*4/10)'E +. \" corrections for vroff +.if v .ds ~ \\k:\h'-(\\n(.wu*9/10-\*(#H)'\s-2\u~\d\s+2\h'|\\n:u' +.if v .ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'\v'-.4m'^\v'.4m'\h'|\\n:u' +. \" for low resolution devices (crt and lpr) +.if \n(.H>23 .if \n(.V>19 \ +\{\ +. ds : e +. ds 8 ss +. ds o a +. ds d- d\h'-1'\(ga +. ds D- D\h'-1'\(hy +. ds th \o'bp' +. ds Th \o'LP' +. ds ae ae +. ds Ae AE +.\} +.rm #[ #] #H #V #F C +.\" ======================================================================== +.\" +.IX Title "xpaopen 3" +.TH xpaopen 3 "July 23, 2013" "version 2.1.15" "SAORD Documentation" +.\" For nroff, turn off justification. Always turn off hyphenation; it makes +.\" way too many mistakes in technical documents. +.if n .ad l +.nh +.SH "NAME" +\&\fBXPAOpen: allocate a persistent client handle\fR +.SH "SYNOPSIS" +.IX Header "SYNOPSIS" +.Vb 1 +\& #include <xpa.h> +\& +\& XPA XPAOpen(char *mode); +.Ve +.SH "DESCRIPTION" +.IX Header "DESCRIPTION" +\&\fIXPAOpen()\fR allocates a persistent \s-1XPA\s0 struct that can be used with +calls to \fIXPAGet()\fR, \fIXPASet()\fR, \fIXPAInfo()\fR, \fIXPAGetFd()\fR, and +\&\fIXPASetFd()\fR. Persistence means that a connection to an \s-1XPA\s0 server is +not closed when one of the above calls is completed but will be +re-used on successive calls. Using \fIXPAOpen()\fR therefore saves the time +it takes to connect to a server, which could be significant with slow +connections or if there will be a large number of exchanges with a +given access point. The mode argument currently is ignored (\*(L"reserved +for future use\*(R"). +.PP +An \s-1XPA\s0 struct is returned if \fIXPAOpen()\fR was successful; otherwise \s-1NULL\s0 +is returned. This returned struct can be passed as the first argument +to \fIXPAGet()\fR, etc. Those calls will update the list of active \s-1XPA\s0 +connections. Already connected servers (from a previous call) are +left connected and new servers also will be connected. Old servers +(from a previous call) that are no longer needed are disconnected. +The connected servers will remain connected when the next call to +\&\fIXPAGet()\fR is made and connections are once again updated. +.PP +\&\fBExample:\fR +.PP +.Vb 1 +\& #include <xpa.h> +\& +\& XPA xpa; +\& xpa = XPAOpen(NULL); +.Ve +.SH "SEE ALSO" +.IX Header "SEE ALSO" +See xpa(n) for a list of \s-1XPA\s0 help pages diff --git a/xpa/man/man3/xpapoll.3 b/xpa/man/man3/xpapoll.3 new file mode 100644 index 0000000..61d3c28 --- /dev/null +++ b/xpa/man/man3/xpapoll.3 @@ -0,0 +1,163 @@ +.\" Automatically generated by Pod::Man 2.22 (Pod::Simple 3.13) +.\" +.\" Standard preamble: +.\" ======================================================================== +.de Sp \" Vertical space (when we can't use .PP) +.if t .sp .5v +.if n .sp +.. +.de Vb \" Begin verbatim text +.ft CW +.nf +.ne \\$1 +.. +.de Ve \" End verbatim text +.ft R +.fi +.. +.\" Set up some character translations and predefined strings. \*(-- will +.\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left +.\" double quote, and \*(R" will give a right double quote. \*(C+ will +.\" give a nicer C++. Capital omega is used to do unbreakable dashes and +.\" therefore won't be available. \*(C` and \*(C' expand to `' in nroff, +.\" nothing in troff, for use with C<>. +.tr \(*W- +.ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p' +.ie n \{\ +. ds -- \(*W- +. ds PI pi +. if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch +. if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch +. ds L" "" +. ds R" "" +. ds C` "" +. ds C' "" +'br\} +.el\{\ +. ds -- \|\(em\| +. ds PI \(*p +. ds L" `` +. ds R" '' +'br\} +.\" +.\" Escape single quotes in literal strings from groff's Unicode transform. +.ie \n(.g .ds Aq \(aq +.el .ds Aq ' +.\" +.\" If the F register is turned on, we'll generate index entries on stderr for +.\" titles (.TH), headers (.SH), subsections (.SS), items (.Ip), and index +.\" entries marked with X<> in POD. Of course, you'll have to process the +.\" output yourself in some meaningful fashion. +.ie \nF \{\ +. de IX +. tm Index:\\$1\t\\n%\t"\\$2" +.. +. nr % 0 +. rr F +.\} +.el \{\ +. de IX +.. +.\} +.\" +.\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2). +.\" Fear. Run. Save yourself. No user-serviceable parts. +. \" fudge factors for nroff and troff +.if n \{\ +. ds #H 0 +. ds #V .8m +. ds #F .3m +. ds #[ \f1 +. ds #] \fP +.\} +.if t \{\ +. ds #H ((1u-(\\\\n(.fu%2u))*.13m) +. ds #V .6m +. ds #F 0 +. ds #[ \& +. ds #] \& +.\} +. \" simple accents for nroff and troff +.if n \{\ +. ds ' \& +. ds ` \& +. ds ^ \& +. ds , \& +. ds ~ ~ +. ds / +.\} +.if t \{\ +. ds ' \\k:\h'-(\\n(.wu*8/10-\*(#H)'\'\h"|\\n:u" +. ds ` \\k:\h'-(\\n(.wu*8/10-\*(#H)'\`\h'|\\n:u' +. ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'^\h'|\\n:u' +. ds , \\k:\h'-(\\n(.wu*8/10)',\h'|\\n:u' +. ds ~ \\k:\h'-(\\n(.wu-\*(#H-.1m)'~\h'|\\n:u' +. ds / \\k:\h'-(\\n(.wu*8/10-\*(#H)'\z\(sl\h'|\\n:u' +.\} +. \" troff and (daisy-wheel) nroff accents +.ds : \\k:\h'-(\\n(.wu*8/10-\*(#H+.1m+\*(#F)'\v'-\*(#V'\z.\h'.2m+\*(#F'.\h'|\\n:u'\v'\*(#V' +.ds 8 \h'\*(#H'\(*b\h'-\*(#H' +.ds o \\k:\h'-(\\n(.wu+\w'\(de'u-\*(#H)/2u'\v'-.3n'\*(#[\z\(de\v'.3n'\h'|\\n:u'\*(#] +.ds d- \h'\*(#H'\(pd\h'-\w'~'u'\v'-.25m'\f2\(hy\fP\v'.25m'\h'-\*(#H' +.ds D- D\\k:\h'-\w'D'u'\v'-.11m'\z\(hy\v'.11m'\h'|\\n:u' +.ds th \*(#[\v'.3m'\s+1I\s-1\v'-.3m'\h'-(\w'I'u*2/3)'\s-1o\s+1\*(#] +.ds Th \*(#[\s+2I\s-2\h'-\w'I'u*3/5'\v'-.3m'o\v'.3m'\*(#] +.ds ae a\h'-(\w'a'u*4/10)'e +.ds Ae A\h'-(\w'A'u*4/10)'E +. \" corrections for vroff +.if v .ds ~ \\k:\h'-(\\n(.wu*9/10-\*(#H)'\s-2\u~\d\s+2\h'|\\n:u' +.if v .ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'\v'-.4m'^\v'.4m'\h'|\\n:u' +. \" for low resolution devices (crt and lpr) +.if \n(.H>23 .if \n(.V>19 \ +\{\ +. ds : e +. ds 8 ss +. ds o a +. ds d- d\h'-1'\(ga +. ds D- D\h'-1'\(hy +. ds th \o'bp' +. ds Th \o'LP' +. ds ae ae +. ds Ae AE +.\} +.rm #[ #] #H #V #F C +.\" ======================================================================== +.\" +.IX Title "xpapoll 3" +.TH xpapoll 3 "July 23, 2013" "version 2.1.15" "SAORD Documentation" +.\" For nroff, turn off justification. Always turn off hyphenation; it makes +.\" way too many mistakes in technical documents. +.if n .ad l +.nh +.SH "NAME" +\&\fBXPAPoll: execute existing \s-1XPA\s0 requests\fR +.SH "SYNOPSIS" +.IX Header "SYNOPSIS" +.Vb 1 +\& #include <xpa.h> +\& +\& int XPAPoll(int msec, int maxreq); +.Ve +.SH "DESCRIPTION" +.IX Header "DESCRIPTION" +It is sometimes desirable to implement a polling loop, i.e., where one +checks for and processes \s-1XPA\s0 requests without blocking. For this +situation, use the \fIXPAPoll()\fR routine: +.PP +.Vb 1 +\& XPAPoll(int msec, int maxreq); +.Ve +.PP +The \fIXPAPoll()\fR routine will perform \fIXPAAddSelect()\fR and \fIselect()\fR, but with a +timeout specified in millisecs by the msec argument. If one or more +\&\s-1XPA\s0 requests are made before the timeout expires, the \fIXPAProcessSelect()\fR +routine is called to process those requests. The maxreq value determines +how many requests will be processed: if maxreq < 0, then no events are +processed, but instead, the return value indicates the number of events +that are pending. If maxreq == 0, then all currently pending requests +will be processed. Otherwise, up to maxreq requests will be processed. +(The most usual values for maxreq are 0 to process all requests and 1 +to process one request). +.SH "SEE ALSO" +.IX Header "SEE ALSO" +See xpa(n) for a list of \s-1XPA\s0 help pages diff --git a/xpa/man/man3/xparace.3 b/xpa/man/man3/xparace.3 new file mode 100644 index 0000000..6100196 --- /dev/null +++ b/xpa/man/man3/xparace.3 @@ -0,0 +1,191 @@ +.\" Automatically generated by Pod::Man 2.22 (Pod::Simple 3.13) +.\" +.\" Standard preamble: +.\" ======================================================================== +.de Sp \" Vertical space (when we can't use .PP) +.if t .sp .5v +.if n .sp +.. +.de Vb \" Begin verbatim text +.ft CW +.nf +.ne \\$1 +.. +.de Ve \" End verbatim text +.ft R +.fi +.. +.\" Set up some character translations and predefined strings. \*(-- will +.\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left +.\" double quote, and \*(R" will give a right double quote. \*(C+ will +.\" give a nicer C++. Capital omega is used to do unbreakable dashes and +.\" therefore won't be available. \*(C` and \*(C' expand to `' in nroff, +.\" nothing in troff, for use with C<>. +.tr \(*W- +.ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p' +.ie n \{\ +. ds -- \(*W- +. ds PI pi +. if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch +. if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch +. ds L" "" +. ds R" "" +. ds C` "" +. ds C' "" +'br\} +.el\{\ +. ds -- \|\(em\| +. ds PI \(*p +. ds L" `` +. ds R" '' +'br\} +.\" +.\" Escape single quotes in literal strings from groff's Unicode transform. +.ie \n(.g .ds Aq \(aq +.el .ds Aq ' +.\" +.\" If the F register is turned on, we'll generate index entries on stderr for +.\" titles (.TH), headers (.SH), subsections (.SS), items (.Ip), and index +.\" entries marked with X<> in POD. Of course, you'll have to process the +.\" output yourself in some meaningful fashion. +.ie \nF \{\ +. de IX +. tm Index:\\$1\t\\n%\t"\\$2" +.. +. nr % 0 +. rr F +.\} +.el \{\ +. de IX +.. +.\} +.\" +.\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2). +.\" Fear. Run. Save yourself. No user-serviceable parts. +. \" fudge factors for nroff and troff +.if n \{\ +. ds #H 0 +. ds #V .8m +. ds #F .3m +. ds #[ \f1 +. ds #] \fP +.\} +.if t \{\ +. ds #H ((1u-(\\\\n(.fu%2u))*.13m) +. ds #V .6m +. ds #F 0 +. ds #[ \& +. ds #] \& +.\} +. \" simple accents for nroff and troff +.if n \{\ +. ds ' \& +. ds ` \& +. ds ^ \& +. ds , \& +. ds ~ ~ +. ds / +.\} +.if t \{\ +. ds ' \\k:\h'-(\\n(.wu*8/10-\*(#H)'\'\h"|\\n:u" +. ds ` \\k:\h'-(\\n(.wu*8/10-\*(#H)'\`\h'|\\n:u' +. ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'^\h'|\\n:u' +. ds , \\k:\h'-(\\n(.wu*8/10)',\h'|\\n:u' +. ds ~ \\k:\h'-(\\n(.wu-\*(#H-.1m)'~\h'|\\n:u' +. ds / \\k:\h'-(\\n(.wu*8/10-\*(#H)'\z\(sl\h'|\\n:u' +.\} +. \" troff and (daisy-wheel) nroff accents +.ds : \\k:\h'-(\\n(.wu*8/10-\*(#H+.1m+\*(#F)'\v'-\*(#V'\z.\h'.2m+\*(#F'.\h'|\\n:u'\v'\*(#V' +.ds 8 \h'\*(#H'\(*b\h'-\*(#H' +.ds o \\k:\h'-(\\n(.wu+\w'\(de'u-\*(#H)/2u'\v'-.3n'\*(#[\z\(de\v'.3n'\h'|\\n:u'\*(#] +.ds d- \h'\*(#H'\(pd\h'-\w'~'u'\v'-.25m'\f2\(hy\fP\v'.25m'\h'-\*(#H' +.ds D- D\\k:\h'-\w'D'u'\v'-.11m'\z\(hy\v'.11m'\h'|\\n:u' +.ds th \*(#[\v'.3m'\s+1I\s-1\v'-.3m'\h'-(\w'I'u*2/3)'\s-1o\s+1\*(#] +.ds Th \*(#[\s+2I\s-2\h'-\w'I'u*3/5'\v'-.3m'o\v'.3m'\*(#] +.ds ae a\h'-(\w'a'u*4/10)'e +.ds Ae A\h'-(\w'A'u*4/10)'E +. \" corrections for vroff +.if v .ds ~ \\k:\h'-(\\n(.wu*9/10-\*(#H)'\s-2\u~\d\s+2\h'|\\n:u' +.if v .ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'\v'-.4m'^\v'.4m'\h'|\\n:u' +. \" for low resolution devices (crt and lpr) +.if \n(.H>23 .if \n(.V>19 \ +\{\ +. ds : e +. ds 8 ss +. ds o a +. ds d- d\h'-1'\(ga +. ds D- D\h'-1'\(hy +. ds th \o'bp' +. ds Th \o'LP' +. ds ae ae +. ds Ae AE +.\} +.rm #[ #] #H #V #F C +.\" ======================================================================== +.\" +.IX Title "xparace 3" +.TH xparace 3 "July 23, 2013" "version 2.1.15" "SAORD Documentation" +.\" For nroff, turn off justification. Always turn off hyphenation; it makes +.\" way too many mistakes in technical documents. +.if n .ad l +.nh +.SH "NAME" +\&\fB\s-1XPA\s0 Race Conditions\fR +.SH "SYNOPSIS" +.IX Header "SYNOPSIS" +Potential \s-1XPA\s0 race conditions and how to avoid them. +.SH "DESCRIPTION" +.IX Header "DESCRIPTION" +Currently, there is only one known circumstance in which \s-1XPA\s0 can get +(temporarily) deadlocked in a race condition: if two or more \s-1XPA\s0 +servers send messages to one another using an \s-1XPA\s0 client routine such +as \fIXPASet()\fR, they can deadlock while each waits for the other server +to respond. (This can happen if the servers call \fIXPAPoll()\fR with a +time limit, and send messages in between the polling call.) The +reason this happens is that both client routines send a string to the +other server to establish the handshake and then wait for the server +response. Since each client is waiting for a response, neither is able +to enter its event-handling loop and respond to the other's +request. This deadlock will continue until one of the timeout periods +expire, at which point an error condition will be triggered and the +timed-out server will return to its event loop. +.PP +Starting with version 2.1.6, this rare race condition can be +avoided by setting the \s-1XPA_IOCALLSXPA\s0 environment variable for servers +that will make client calls. Setting this variable causes all \s-1XPA\s0 +socket \s-1IO\s0 calls to process outstanding \s-1XPA\s0 requests whenever the +primary socket is not ready for \s-1IO\s0. This means that a server making a +client call will (recursively) process incoming server requests while +waiting for client completion. It also means that a server callback +routine can handle incoming \s-1XPA\s0 messages if it makes its own \s-1XPA\s0 call. +The semi-public routine oldvalue=XPAIOCallsXPA(newvalue) can be used +to turn this behavior off and on temporarily. Passing a 0 will turn +off \s-1IO\s0 processing, 1 will turn it back on. The old value is returned +by the call. +.PP +By default, the \s-1XPA_IOCALLSXPA\s0 option is turned off, because we judge +that the added code complication and overhead involved will not be +justified by the amount of its use. Moreover, processing \s-1XPA\s0 requests +within socket \s-1IO\s0 can lead to non-intuitive results, since incoming +server requests will not necessarily be processed to completion in the +order in which they are received. +.PP +Aside from setting \s-1XPA_IOCALLSXPA\s0, the simplest way to avoid this race +condition is to multi-process: when you want to send a client message, +simply start a separate process to call the client routine, so that +the server is not stopped. It probably is fastest and easiest to use +\&\fIfork()\fR and then have the child call the client routine and exit. But +you also can use either the \fIsystem()\fR or \fIpopen()\fR routine to start one +of the command line programs and do the same thing. Alternatively, you +can use \s-1XPA\s0's internal \fIlaunch()\fR routine instead of \fIsystem()\fR. Based on +\&\fIfork()\fR and \fIexec()\fR, this routine is more secure than \fIsystem()\fR because +it does not call /bin/sh. +.PP +Starting with version 2.1.5, you also can send an \fIXPAInfo()\fR message with +the mode string \*(L"ack=false\*(R". This will cause the client to send a message +to the server and then exit without waiting for any return message from +the server. This UDP-like behavior will avoid the server deadlock when +sending short XPAInfo messages. +.SH "SEE ALSO" +.IX Header "SEE ALSO" +See xpa(n) for a list of \s-1XPA\s0 help pages diff --git a/xpa/man/man3/xpaserver.3 b/xpa/man/man3/xpaserver.3 new file mode 100644 index 0000000..a0803aa --- /dev/null +++ b/xpa/man/man3/xpaserver.3 @@ -0,0 +1,205 @@ +.\" Automatically generated by Pod::Man 2.22 (Pod::Simple 3.13) +.\" +.\" Standard preamble: +.\" ======================================================================== +.de Sp \" Vertical space (when we can't use .PP) +.if t .sp .5v +.if n .sp +.. +.de Vb \" Begin verbatim text +.ft CW +.nf +.ne \\$1 +.. +.de Ve \" End verbatim text +.ft R +.fi +.. +.\" Set up some character translations and predefined strings. \*(-- will +.\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left +.\" double quote, and \*(R" will give a right double quote. \*(C+ will +.\" give a nicer C++. Capital omega is used to do unbreakable dashes and +.\" therefore won't be available. \*(C` and \*(C' expand to `' in nroff, +.\" nothing in troff, for use with C<>. +.tr \(*W- +.ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p' +.ie n \{\ +. ds -- \(*W- +. ds PI pi +. if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch +. if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch +. ds L" "" +. ds R" "" +. ds C` "" +. ds C' "" +'br\} +.el\{\ +. ds -- \|\(em\| +. ds PI \(*p +. ds L" `` +. ds R" '' +'br\} +.\" +.\" Escape single quotes in literal strings from groff's Unicode transform. +.ie \n(.g .ds Aq \(aq +.el .ds Aq ' +.\" +.\" If the F register is turned on, we'll generate index entries on stderr for +.\" titles (.TH), headers (.SH), subsections (.SS), items (.Ip), and index +.\" entries marked with X<> in POD. Of course, you'll have to process the +.\" output yourself in some meaningful fashion. +.ie \nF \{\ +. de IX +. tm Index:\\$1\t\\n%\t"\\$2" +.. +. nr % 0 +. rr F +.\} +.el \{\ +. de IX +.. +.\} +.\" +.\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2). +.\" Fear. Run. Save yourself. No user-serviceable parts. +. \" fudge factors for nroff and troff +.if n \{\ +. ds #H 0 +. ds #V .8m +. ds #F .3m +. ds #[ \f1 +. ds #] \fP +.\} +.if t \{\ +. ds #H ((1u-(\\\\n(.fu%2u))*.13m) +. ds #V .6m +. ds #F 0 +. ds #[ \& +. ds #] \& +.\} +. \" simple accents for nroff and troff +.if n \{\ +. ds ' \& +. ds ` \& +. ds ^ \& +. ds , \& +. ds ~ ~ +. ds / +.\} +.if t \{\ +. ds ' \\k:\h'-(\\n(.wu*8/10-\*(#H)'\'\h"|\\n:u" +. ds ` \\k:\h'-(\\n(.wu*8/10-\*(#H)'\`\h'|\\n:u' +. ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'^\h'|\\n:u' +. ds , \\k:\h'-(\\n(.wu*8/10)',\h'|\\n:u' +. ds ~ \\k:\h'-(\\n(.wu-\*(#H-.1m)'~\h'|\\n:u' +. ds / \\k:\h'-(\\n(.wu*8/10-\*(#H)'\z\(sl\h'|\\n:u' +.\} +. \" troff and (daisy-wheel) nroff accents +.ds : \\k:\h'-(\\n(.wu*8/10-\*(#H+.1m+\*(#F)'\v'-\*(#V'\z.\h'.2m+\*(#F'.\h'|\\n:u'\v'\*(#V' +.ds 8 \h'\*(#H'\(*b\h'-\*(#H' +.ds o \\k:\h'-(\\n(.wu+\w'\(de'u-\*(#H)/2u'\v'-.3n'\*(#[\z\(de\v'.3n'\h'|\\n:u'\*(#] +.ds d- \h'\*(#H'\(pd\h'-\w'~'u'\v'-.25m'\f2\(hy\fP\v'.25m'\h'-\*(#H' +.ds D- D\\k:\h'-\w'D'u'\v'-.11m'\z\(hy\v'.11m'\h'|\\n:u' +.ds th \*(#[\v'.3m'\s+1I\s-1\v'-.3m'\h'-(\w'I'u*2/3)'\s-1o\s+1\*(#] +.ds Th \*(#[\s+2I\s-2\h'-\w'I'u*3/5'\v'-.3m'o\v'.3m'\*(#] +.ds ae a\h'-(\w'a'u*4/10)'e +.ds Ae A\h'-(\w'A'u*4/10)'E +. \" corrections for vroff +.if v .ds ~ \\k:\h'-(\\n(.wu*9/10-\*(#H)'\s-2\u~\d\s+2\h'|\\n:u' +.if v .ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'\v'-.4m'^\v'.4m'\h'|\\n:u' +. \" for low resolution devices (crt and lpr) +.if \n(.H>23 .if \n(.V>19 \ +\{\ +. ds : e +. ds 8 ss +. ds o a +. ds d- d\h'-1'\(ga +. ds D- D\h'-1'\(hy +. ds th \o'bp' +. ds Th \o'LP' +. ds ae ae +. ds Ae AE +.\} +.rm #[ #] #H #V #F C +.\" ======================================================================== +.\" +.IX Title "xpaserver 3" +.TH xpaserver 3 "July 23, 2013" "version 2.1.15" "SAORD Documentation" +.\" For nroff, turn off justification. Always turn off hyphenation; it makes +.\" way too many mistakes in technical documents. +.if n .ad l +.nh +.SH "NAME" +\&\fBXPAServer: The \s-1XPA\s0 Server-side Programming Interface\fR +.SH "SYNOPSIS" +.IX Header "SYNOPSIS" +A description of the \s-1XPA\s0 server-side programming interface. +.SH "DESCRIPTION" +.IX Header "DESCRIPTION" +\&\fBIntroduction to \s-1XPA\s0 Server Programming\fR +.PP +Creating an \s-1XPA\s0 server is easy: you generally only need to call the +\&\fIXPANew()\fR subroutine to define a named \s-1XPA\s0 access point and set up the +send and receive callback routines. You then enter an event loop such +as \fIXPAMainLoop()\fR to field \s-1XPA\s0 requests. +.PP +.Vb 1 +\& #include <xpa.h> +\& +\& XPA XPANew(char *class, char *name, char *help, +\& int (*send_callback)(), void *send_data, char *send_mode, +\& int (*rec_callback)(), void *rec_data, char *rec_mode); +\& +\& XPA XPACmdNew(char *class, char *name); +\& +\& XPACmd XPACmdAdd(XPA xpa, +\& char *name, char *help, +\& int (*send_callback)(), void *send_data, char *send_mode, +\& int (*rec_callback)(), void *rec_data, char *rec_mode); +\& +\& void XPACmdDel(XPA xpa, XPACmd cmd); +\& +\& XPA XPAInfoNew(char *class, char *name, +\& int (*info_callback)(), void *info_data, char *info_mode); +\& +\& int XPAFree(XPA xpa); +\& +\& void XPAMainLoop(void); +\& +\& int XPAPoll(int msec, int maxreq); +\& +\& void XPAAtExit(void); +\& +\& void XPACleanup(void); +.Ve +.PP +\&\fBIntroduction\fR +.PP +To use the \s-1XPA\s0 application programming interface, a software developer +generally will include the xpa.h definitions file: +.PP +.Vb 1 +\& #include <xpa.h> +.Ve +.PP +in the software module that defines or accesses an \s-1XPA\s0 access point, and +then will link against the libxpa.a library: +.PP +.Vb 1 +\& gcc \-o foo foo.c libxpa.a +.Ve +.PP +\&\s-1XPA\s0 has been compiled using both C and \*(C+ compilers. +.PP +A server program generally defines an \s-1XPA\s0 access point by calling the +\&\fIXPANew()\fR routine and specifies \*(L"send\*(R" and/or \*(L"receive\*(R" callback +procedures to be executed by the program when an external process +either sends data or commands to this access point or requests data or +information from this access point. A program also can define several +sub-commands for a single access point by calling \fIXPACmdNew()\fR and +\&\fIXPACmdAdd()\fR instead. Having defined one or more public access points +in this way, an \s-1XPA\s0 server program enters its usual event loop (or +uses the standard \s-1XPA\s0 event loop). +.SH "SEE ALSO" +.IX Header "SEE ALSO" +See xpa(n) for a list of \s-1XPA\s0 help pages diff --git a/xpa/man/man3/xpaset.3 b/xpa/man/man3/xpaset.3 new file mode 100644 index 0000000..d9dd7c0 --- /dev/null +++ b/xpa/man/man3/xpaset.3 @@ -0,0 +1,236 @@ +.\" Automatically generated by Pod::Man 2.22 (Pod::Simple 3.13) +.\" +.\" Standard preamble: +.\" ======================================================================== +.de Sp \" Vertical space (when we can't use .PP) +.if t .sp .5v +.if n .sp +.. +.de Vb \" Begin verbatim text +.ft CW +.nf +.ne \\$1 +.. +.de Ve \" End verbatim text +.ft R +.fi +.. +.\" Set up some character translations and predefined strings. \*(-- will +.\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left +.\" double quote, and \*(R" will give a right double quote. \*(C+ will +.\" give a nicer C++. Capital omega is used to do unbreakable dashes and +.\" therefore won't be available. \*(C` and \*(C' expand to `' in nroff, +.\" nothing in troff, for use with C<>. +.tr \(*W- +.ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p' +.ie n \{\ +. ds -- \(*W- +. ds PI pi +. if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch +. if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch +. ds L" "" +. ds R" "" +. ds C` "" +. ds C' "" +'br\} +.el\{\ +. ds -- \|\(em\| +. ds PI \(*p +. ds L" `` +. ds R" '' +'br\} +.\" +.\" Escape single quotes in literal strings from groff's Unicode transform. +.ie \n(.g .ds Aq \(aq +.el .ds Aq ' +.\" +.\" If the F register is turned on, we'll generate index entries on stderr for +.\" titles (.TH), headers (.SH), subsections (.SS), items (.Ip), and index +.\" entries marked with X<> in POD. Of course, you'll have to process the +.\" output yourself in some meaningful fashion. +.ie \nF \{\ +. de IX +. tm Index:\\$1\t\\n%\t"\\$2" +.. +. nr % 0 +. rr F +.\} +.el \{\ +. de IX +.. +.\} +.\" +.\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2). +.\" Fear. Run. Save yourself. No user-serviceable parts. +. \" fudge factors for nroff and troff +.if n \{\ +. ds #H 0 +. ds #V .8m +. ds #F .3m +. ds #[ \f1 +. ds #] \fP +.\} +.if t \{\ +. ds #H ((1u-(\\\\n(.fu%2u))*.13m) +. ds #V .6m +. ds #F 0 +. ds #[ \& +. ds #] \& +.\} +. \" simple accents for nroff and troff +.if n \{\ +. ds ' \& +. ds ` \& +. ds ^ \& +. ds , \& +. ds ~ ~ +. ds / +.\} +.if t \{\ +. ds ' \\k:\h'-(\\n(.wu*8/10-\*(#H)'\'\h"|\\n:u" +. ds ` \\k:\h'-(\\n(.wu*8/10-\*(#H)'\`\h'|\\n:u' +. ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'^\h'|\\n:u' +. ds , \\k:\h'-(\\n(.wu*8/10)',\h'|\\n:u' +. ds ~ \\k:\h'-(\\n(.wu-\*(#H-.1m)'~\h'|\\n:u' +. ds / \\k:\h'-(\\n(.wu*8/10-\*(#H)'\z\(sl\h'|\\n:u' +.\} +. \" troff and (daisy-wheel) nroff accents +.ds : \\k:\h'-(\\n(.wu*8/10-\*(#H+.1m+\*(#F)'\v'-\*(#V'\z.\h'.2m+\*(#F'.\h'|\\n:u'\v'\*(#V' +.ds 8 \h'\*(#H'\(*b\h'-\*(#H' +.ds o \\k:\h'-(\\n(.wu+\w'\(de'u-\*(#H)/2u'\v'-.3n'\*(#[\z\(de\v'.3n'\h'|\\n:u'\*(#] +.ds d- \h'\*(#H'\(pd\h'-\w'~'u'\v'-.25m'\f2\(hy\fP\v'.25m'\h'-\*(#H' +.ds D- D\\k:\h'-\w'D'u'\v'-.11m'\z\(hy\v'.11m'\h'|\\n:u' +.ds th \*(#[\v'.3m'\s+1I\s-1\v'-.3m'\h'-(\w'I'u*2/3)'\s-1o\s+1\*(#] +.ds Th \*(#[\s+2I\s-2\h'-\w'I'u*3/5'\v'-.3m'o\v'.3m'\*(#] +.ds ae a\h'-(\w'a'u*4/10)'e +.ds Ae A\h'-(\w'A'u*4/10)'E +. \" corrections for vroff +.if v .ds ~ \\k:\h'-(\\n(.wu*9/10-\*(#H)'\s-2\u~\d\s+2\h'|\\n:u' +.if v .ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'\v'-.4m'^\v'.4m'\h'|\\n:u' +. \" for low resolution devices (crt and lpr) +.if \n(.H>23 .if \n(.V>19 \ +\{\ +. ds : e +. ds 8 ss +. ds o a +. ds d- d\h'-1'\(ga +. ds D- D\h'-1'\(hy +. ds th \o'bp' +. ds Th \o'LP' +. ds ae ae +. ds Ae AE +.\} +.rm #[ #] #H #V #F C +.\" ======================================================================== +.\" +.IX Title "xpaset 3" +.TH xpaset 3 "July 23, 2013" "version 2.1.15" "SAORD Documentation" +.\" For nroff, turn off justification. Always turn off hyphenation; it makes +.\" way too many mistakes in technical documents. +.if n .ad l +.nh +.SH "NAME" +\&\fBXPASet: send data to one or more \s-1XPA\s0 servers\fR +.SH "SYNOPSIS" +.IX Header "SYNOPSIS" +.Vb 1 +\& #include <xpa.h> +\& +\& int XPASet(XPA xpa, +\& char *template, char *paramlist, char *mode, +\& char *buf, size_t len, char **names, char **messages, +\& int n); +.Ve +.SH "DESCRIPTION" +.IX Header "DESCRIPTION" +Send data to one or more \s-1XPA\s0 servers whose class:name identifier +matches the specified template. +.PP +A +template +of the form \*(L"class1:name1\*(R" is sent to the +\&\s-1XPA\s0 name server, which returns a list of at most n matching \s-1XPA\s0 +servers. A connection is established with each of these servers and +the paramlist string is passed to the server as the data transfer +request is initiated. If an \s-1XPA\s0 struct is passed to the call, the +persistent connections are updated as described above. Otherwise, +temporary connections are made to the servers (which will be closed +when the call completes). +.PP +The \fIXPASet()\fR routine transfers data from buf to the \s-1XPA\s0 servers. +The length of buf (in bytes) should be placed in the len variable. +.PP +A string containing the class:name and ip:port of each of these server +is returned in the name array. If a given server returned an error or +the server callback sends a message back to the client, then the +message will be stored in the associated element of the messages +array. \s-1NB:\s0 if specified, the name and messages arrays must be of size +n or greater. +.PP +The returned message string will be of the form: +.PP +.Vb 1 +\& XPA$ERROR [error] (class:name ip:port) +.Ve +.PP +or +.PP +.Vb 1 +\& XPA$MESSAGE [message] (class:name ip:port) +.Ve +.PP +The return value will contain the actual number of servers that were +processed. This value thus will hold the number of valid entries in +the names and messages arrays, and can be used to loop through these +arrays. In names and/or messages is \s-1NULL\s0, no information is passed back +in that particular array. +.PP +The mode string is of the form: \*(L"key1=value1,key2=value2,...\*(R" +The following keywords are recognized: +.PP +.Vb 5 +\& key value default explanation +\& \-\-\-\-\-\- \-\-\-\-\-\-\-\- \-\-\-\-\-\-\-\- \-\-\-\-\-\-\-\-\-\-\- +\& ack true/false true if false, don\*(Aqt wait for ack from server (after callback completes) +\& verify true/false false send buf from XPASet[Fd] to stdout +\& doxpa true/false true client processes xpa requests +.Ve +.PP +The ack keyword is useful in cases where one does not want to wait for +the server to complete, e.g. if a lot of processing needs to be done +by the server on the passed data or when the success of the server +operation is not relevant to the client. +.PP +Normally, an \s-1XPA\s0 client will process incoming \s-1XPA\s0 server requests +while awaiting the completion of the client request. Setting this +variable to \*(L"false\*(R" will prevent \s-1XPA\s0 server requests from being +processed by the client. +.PP +\&\fBExample:\fR +.PP +.Vb 1 +\& #include <xpa.h> +\& +\& #define NXPA 10 +\& int i, got; +\& size_t len; +\& char *buf; +\& char *names[NXPA]; +\& char *messages[NXPA]; +\& ... +\& [fill buf with data and set len to the length, in bytes, of the data] +\& ... +\& /* send data to all access points */ +\& got = XPASet(NULL, "ds9", "fits", NULL, buf, len, names, messages, NXPA); +\& /* error processing */ +\& for(i=0; i<got; i++){ +\& if( messages[i] ){ +\& fprintf(stderr, "ERROR: %s (%s)\en", messages[i], names[i]); +\& } +\& if( names[i] ) free(names[i]); +\& if( messages[i] ) free(messages[i]); +\& } +.Ve +.SH "SEE ALSO" +.IX Header "SEE ALSO" +See xpa(n) for a list of \s-1XPA\s0 help pages diff --git a/xpa/man/man3/xpasetfd.3 b/xpa/man/man3/xpasetfd.3 new file mode 100644 index 0000000..5017a38 --- /dev/null +++ b/xpa/man/man3/xpasetfd.3 @@ -0,0 +1,214 @@ +.\" Automatically generated by Pod::Man 2.22 (Pod::Simple 3.13) +.\" +.\" Standard preamble: +.\" ======================================================================== +.de Sp \" Vertical space (when we can't use .PP) +.if t .sp .5v +.if n .sp +.. +.de Vb \" Begin verbatim text +.ft CW +.nf +.ne \\$1 +.. +.de Ve \" End verbatim text +.ft R +.fi +.. +.\" Set up some character translations and predefined strings. \*(-- will +.\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left +.\" double quote, and \*(R" will give a right double quote. \*(C+ will +.\" give a nicer C++. Capital omega is used to do unbreakable dashes and +.\" therefore won't be available. \*(C` and \*(C' expand to `' in nroff, +.\" nothing in troff, for use with C<>. +.tr \(*W- +.ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p' +.ie n \{\ +. ds -- \(*W- +. ds PI pi +. if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch +. if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch +. ds L" "" +. ds R" "" +. ds C` "" +. ds C' "" +'br\} +.el\{\ +. ds -- \|\(em\| +. ds PI \(*p +. ds L" `` +. ds R" '' +'br\} +.\" +.\" Escape single quotes in literal strings from groff's Unicode transform. +.ie \n(.g .ds Aq \(aq +.el .ds Aq ' +.\" +.\" If the F register is turned on, we'll generate index entries on stderr for +.\" titles (.TH), headers (.SH), subsections (.SS), items (.Ip), and index +.\" entries marked with X<> in POD. Of course, you'll have to process the +.\" output yourself in some meaningful fashion. +.ie \nF \{\ +. de IX +. tm Index:\\$1\t\\n%\t"\\$2" +.. +. nr % 0 +. rr F +.\} +.el \{\ +. de IX +.. +.\} +.\" +.\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2). +.\" Fear. Run. Save yourself. No user-serviceable parts. +. \" fudge factors for nroff and troff +.if n \{\ +. ds #H 0 +. ds #V .8m +. ds #F .3m +. ds #[ \f1 +. ds #] \fP +.\} +.if t \{\ +. ds #H ((1u-(\\\\n(.fu%2u))*.13m) +. ds #V .6m +. ds #F 0 +. ds #[ \& +. ds #] \& +.\} +. \" simple accents for nroff and troff +.if n \{\ +. ds ' \& +. ds ` \& +. ds ^ \& +. ds , \& +. ds ~ ~ +. ds / +.\} +.if t \{\ +. ds ' \\k:\h'-(\\n(.wu*8/10-\*(#H)'\'\h"|\\n:u" +. ds ` \\k:\h'-(\\n(.wu*8/10-\*(#H)'\`\h'|\\n:u' +. ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'^\h'|\\n:u' +. ds , \\k:\h'-(\\n(.wu*8/10)',\h'|\\n:u' +. ds ~ \\k:\h'-(\\n(.wu-\*(#H-.1m)'~\h'|\\n:u' +. ds / \\k:\h'-(\\n(.wu*8/10-\*(#H)'\z\(sl\h'|\\n:u' +.\} +. \" troff and (daisy-wheel) nroff accents +.ds : \\k:\h'-(\\n(.wu*8/10-\*(#H+.1m+\*(#F)'\v'-\*(#V'\z.\h'.2m+\*(#F'.\h'|\\n:u'\v'\*(#V' +.ds 8 \h'\*(#H'\(*b\h'-\*(#H' +.ds o \\k:\h'-(\\n(.wu+\w'\(de'u-\*(#H)/2u'\v'-.3n'\*(#[\z\(de\v'.3n'\h'|\\n:u'\*(#] +.ds d- \h'\*(#H'\(pd\h'-\w'~'u'\v'-.25m'\f2\(hy\fP\v'.25m'\h'-\*(#H' +.ds D- D\\k:\h'-\w'D'u'\v'-.11m'\z\(hy\v'.11m'\h'|\\n:u' +.ds th \*(#[\v'.3m'\s+1I\s-1\v'-.3m'\h'-(\w'I'u*2/3)'\s-1o\s+1\*(#] +.ds Th \*(#[\s+2I\s-2\h'-\w'I'u*3/5'\v'-.3m'o\v'.3m'\*(#] +.ds ae a\h'-(\w'a'u*4/10)'e +.ds Ae A\h'-(\w'A'u*4/10)'E +. \" corrections for vroff +.if v .ds ~ \\k:\h'-(\\n(.wu*9/10-\*(#H)'\s-2\u~\d\s+2\h'|\\n:u' +.if v .ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'\v'-.4m'^\v'.4m'\h'|\\n:u' +. \" for low resolution devices (crt and lpr) +.if \n(.H>23 .if \n(.V>19 \ +\{\ +. ds : e +. ds 8 ss +. ds o a +. ds d- d\h'-1'\(ga +. ds D- D\h'-1'\(hy +. ds th \o'bp' +. ds Th \o'LP' +. ds ae ae +. ds Ae AE +.\} +.rm #[ #] #H #V #F C +.\" ======================================================================== +.\" +.IX Title "xpasetfd 3" +.TH xpasetfd 3 "July 23, 2013" "version 2.1.15" "SAORD Documentation" +.\" For nroff, turn off justification. Always turn off hyphenation; it makes +.\" way too many mistakes in technical documents. +.if n .ad l +.nh +.SH "NAME" +\&\fBXPASetFd: send data from stdin to one or more \s-1XPA\s0 servers\fR +.SH "SYNOPSIS" +.IX Header "SYNOPSIS" +.Vb 1 +\& #include <xpa.h> +\& +\& int XPASetFd(XPA xpa, +\& char *template, char *paramlist, char *mode, +\& int fd, char **names, char **messages, int n) +.Ve +.SH "DESCRIPTION" +.IX Header "DESCRIPTION" +Read data from a standard I/O fd and send it to one or more \s-1XPA\s0 +servers whose class:name identifier matches the specified +template. +.PP +A +template +of the form \*(L"class1:name1\*(R" is sent to the +\&\s-1XPA\s0 name server, which returns a list of at most n matching \s-1XPA\s0 +servers. A connection is established with each of these servers and +the paramlist string is passed to the server as the data transfer +request is initiated. If an \s-1XPA\s0 struct is passed to the call, then the +persistent connections are updated as described above. Otherwise, +temporary connections are made to the servers (which will be closed +when the call completes). +.PP +The \fIXPASetFd()\fR routine then reads bytes from the specified fd +until \s-1EOF\s0 and sends these bytes to the \s-1XPA\s0 servers. +The final parameter n specifies the maximum number of servers to contact. +A string containing the class:name and ip:port of each server is returned in +the name array. If a given server returned an error, then the error +message will be stored in the associated element of the messages array. +\&\s-1NB:\s0 if specified, the name and messages arrays must be of size n or greater. +.PP +The return value will contain the actual number of servers that were +processed. This value thus will hold the number of valid entries in +the names and messages arrays, and can be used to loop through these +arrays. In names and/or messages is \s-1NULL\s0, no information is passed back +in that array. +.PP +The mode string is of the form: \*(L"key1=value1,key2=value2,...\*(R" +The following keywords are recognized: +.PP +.Vb 4 +\& key value default explanation +\& \-\-\-\-\-\- \-\-\-\-\-\-\-\- \-\-\-\-\-\-\-\- \-\-\-\-\-\-\-\-\-\-\- +\& ack true/false true if false, don\*(Aqt wait for ack from server (after callback completes) +\& verify true/false false send buf from XPASet[Fd] to stdout +.Ve +.PP +The ack keyword is useful in cases where one does not want to wait for +the server to complete, e.g. is a lot of processing needs to be done +on the passed data or when the success of the server operation is not +relevant to the client. +.PP +\&\fBExample:\fR +.PP +.Vb 1 +\& #include <xpa.h> +\& +\& #define NXPA 10 +\& int i, got; +\& int fd; +\& char *names[NXPA]; +\& char *messages[NXPA]; +\& fd = open(...); +\& got = XPASetFd(NULL, "ds9", "fits", NULL, fd, names, messages, NXPA); +\& for(i=0; i<got; i++){ +\& if( messages[i] != NULL ){ +\& /* error processing */ +\& fprintf(stderr, "ERROR: %s (%s)\en", messages[i], names[i]); +\& } +\& if( names[i] ) +\& free(names[i]); +\& if( messages[i] ) +\& free(messages[i]); +\& } +.Ve +.SH "SEE ALSO" +.IX Header "SEE ALSO" +See xpa(n) for a list of \s-1XPA\s0 help pages diff --git a/xpa/man/mann/xpa.n b/xpa/man/mann/xpa.n new file mode 100644 index 0000000..189a601 --- /dev/null +++ b/xpa/man/mann/xpa.n @@ -0,0 +1,318 @@ +.\" Automatically generated by Pod::Man 2.22 (Pod::Simple 3.13) +.\" +.\" Standard preamble: +.\" ======================================================================== +.de Sp \" Vertical space (when we can't use .PP) +.if t .sp .5v +.if n .sp +.. +.de Vb \" Begin verbatim text +.ft CW +.nf +.ne \\$1 +.. +.de Ve \" End verbatim text +.ft R +.fi +.. +.\" Set up some character translations and predefined strings. \*(-- will +.\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left +.\" double quote, and \*(R" will give a right double quote. \*(C+ will +.\" give a nicer C++. Capital omega is used to do unbreakable dashes and +.\" therefore won't be available. \*(C` and \*(C' expand to `' in nroff, +.\" nothing in troff, for use with C<>. +.tr \(*W- +.ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p' +.ie n \{\ +. ds -- \(*W- +. ds PI pi +. if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch +. if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch +. ds L" "" +. ds R" "" +. ds C` "" +. ds C' "" +'br\} +.el\{\ +. ds -- \|\(em\| +. ds PI \(*p +. ds L" `` +. ds R" '' +'br\} +.\" +.\" Escape single quotes in literal strings from groff's Unicode transform. +.ie \n(.g .ds Aq \(aq +.el .ds Aq ' +.\" +.\" If the F register is turned on, we'll generate index entries on stderr for +.\" titles (.TH), headers (.SH), subsections (.SS), items (.Ip), and index +.\" entries marked with X<> in POD. Of course, you'll have to process the +.\" output yourself in some meaningful fashion. +.ie \nF \{\ +. de IX +. tm Index:\\$1\t\\n%\t"\\$2" +.. +. nr % 0 +. rr F +.\} +.el \{\ +. de IX +.. +.\} +.\" +.\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2). +.\" Fear. Run. Save yourself. No user-serviceable parts. +. \" fudge factors for nroff and troff +.if n \{\ +. ds #H 0 +. ds #V .8m +. ds #F .3m +. ds #[ \f1 +. ds #] \fP +.\} +.if t \{\ +. ds #H ((1u-(\\\\n(.fu%2u))*.13m) +. ds #V .6m +. ds #F 0 +. ds #[ \& +. ds #] \& +.\} +. \" simple accents for nroff and troff +.if n \{\ +. ds ' \& +. ds ` \& +. ds ^ \& +. ds , \& +. ds ~ ~ +. ds / +.\} +.if t \{\ +. ds ' \\k:\h'-(\\n(.wu*8/10-\*(#H)'\'\h"|\\n:u" +. ds ` \\k:\h'-(\\n(.wu*8/10-\*(#H)'\`\h'|\\n:u' +. ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'^\h'|\\n:u' +. ds , \\k:\h'-(\\n(.wu*8/10)',\h'|\\n:u' +. ds ~ \\k:\h'-(\\n(.wu-\*(#H-.1m)'~\h'|\\n:u' +. ds / \\k:\h'-(\\n(.wu*8/10-\*(#H)'\z\(sl\h'|\\n:u' +.\} +. \" troff and (daisy-wheel) nroff accents +.ds : \\k:\h'-(\\n(.wu*8/10-\*(#H+.1m+\*(#F)'\v'-\*(#V'\z.\h'.2m+\*(#F'.\h'|\\n:u'\v'\*(#V' +.ds 8 \h'\*(#H'\(*b\h'-\*(#H' +.ds o \\k:\h'-(\\n(.wu+\w'\(de'u-\*(#H)/2u'\v'-.3n'\*(#[\z\(de\v'.3n'\h'|\\n:u'\*(#] +.ds d- \h'\*(#H'\(pd\h'-\w'~'u'\v'-.25m'\f2\(hy\fP\v'.25m'\h'-\*(#H' +.ds D- D\\k:\h'-\w'D'u'\v'-.11m'\z\(hy\v'.11m'\h'|\\n:u' +.ds th \*(#[\v'.3m'\s+1I\s-1\v'-.3m'\h'-(\w'I'u*2/3)'\s-1o\s+1\*(#] +.ds Th \*(#[\s+2I\s-2\h'-\w'I'u*3/5'\v'-.3m'o\v'.3m'\*(#] +.ds ae a\h'-(\w'a'u*4/10)'e +.ds Ae A\h'-(\w'A'u*4/10)'E +. \" corrections for vroff +.if v .ds ~ \\k:\h'-(\\n(.wu*9/10-\*(#H)'\s-2\u~\d\s+2\h'|\\n:u' +.if v .ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'\v'-.4m'^\v'.4m'\h'|\\n:u' +. \" for low resolution devices (crt and lpr) +.if \n(.H>23 .if \n(.V>19 \ +\{\ +. ds : e +. ds 8 ss +. ds o a +. ds d- d\h'-1'\(ga +. ds D- D\h'-1'\(hy +. ds th \o'bp' +. ds Th \o'LP' +. ds ae ae +. ds Ae AE +.\} +.rm #[ #] #H #V #F C +.\" ======================================================================== +.\" +.IX Title "xpa n" +.TH xpa n "July 23, 2013" "version 2.1.15" "SAORD Documentation" +.\" For nroff, turn off justification. Always turn off hyphenation; it makes +.\" way too many mistakes in technical documents. +.if n .ad l +.nh +.SH "NAME" +\&\fB\s-1XPA:\s0 Public Access to Data and Algorithms\fR +.SH "SYNOPSIS" +.IX Header "SYNOPSIS" +This document is the Table of Contents for \s-1XPA\s0. +.SH "DESCRIPTION" +.IX Header "DESCRIPTION" +The \s-1XPA\s0 messaging system provides seamless communication between many +kinds of Unix programs, including X programs and Tcl/Tk programs. It +also provides an easy way for users to communicate with XPA-enabled +programs by executing \s-1XPA\s0 client commands in the shell or by utilizing +such commands in scripts. Because \s-1XPA\s0 works both at the programming +level and the shell level, it is a powerful tool for unifying any +analysis environment: users and programmers have great flexibility in +choosing the best level or levels at which to access \s-1XPA\s0 services, and +client access can be extended or modified easily at any time. +.PP +A program becomes an XPA-enabled server by defining named points of +public access through which data and commands can be exchanged with +other client programs (and users). Using standard \s-1TCP\s0 sockets as a +transport mechanism, \s-1XPA\s0 supports both single-point and broadcast +messaging to and from these servers. It supports direct communication +between clients and servers, or indirect communication via an +intermediate message bus emulation program. Host-based access control +is implemented, as is as the ability to communicate with \s-1XPA\s0 servers +across a network. +.PP +\&\s-1XPA\s0 implements a layered interface that is designed to be useful both +to software developers and to users. The interface consists of a +library of \s-1XPA\s0 client and server routines for use in C/\*(C+ programs and +a suite of high-level user programs built on top of these libraries. +Using the \s-1XPA\s0 library, access points can be added to Tcl/Tk programs, +Xt programs, or to Unix programs that use the \s-1XPA\s0 event loop or any +event loop based on \fIselect()\fR. Client access subroutines can be added +to any Tcl/Tk, Xt, or Unix program. Client access also is supported at +the command line via a suite of high-level programs. +.PP +Choose from the following topics: +.IP "\(bu" 4 +Introduction to \s-1XPA\s0 +[xpaintro(n)] +.IP "\(bu" 4 +Access Point Names and Templates +[xpatemplate(n)] +.IP "\(bu" 4 +Getting Common Information About Access Points +[xpacommon(n)] +.IP "\(bu" 4 +Communication Methods +[xpamethod(n)] +.IP "\(bu" 4 +Communication Between Hosts +[xpainet(n)] +.IP "\(bu" 4 +Distinguishing Users +[xpausers(n)] +.IP "\(bu" 4 +\&\s-1XPA\s0 User Programs +.RS 4 +.IP "\(bu" 4 +xpaget: get data and info +[\fIxpaget\fR\|(1)] +.IP "\(bu" 4 +xpaset: send data and info +[\fIxpaset\fR\|(1)] +.IP "\(bu" 4 +xpainfo: send info alert +[\fIxpainfo\fR\|(1)] +.IP "\(bu" 4 +xpaaccess: get access point info +[\fIxpaaccess\fR\|(1)] +.IP "\(bu" 4 +xpamb: message bus emulation +[\fIxpamb\fR\|(1)] +.IP "\(bu" 4 +xpans: the \s-1XPA\s0 name server +[\fIxpans\fR\|(1)] +.RE +.RS 4 +.RE +.IP "\(bu" 4 +\&\s-1XPA\s0 Server Routines +.RS 4 +.IP "\(bu" 4 +XPANew: define a new access point +[\fIxpanew\fR\|(3)] +.IP "\(bu" 4 +XPACmdNew: define a new command access point +[\fIxpacmdnew\fR\|(3)] +.IP "\(bu" 4 +XPACmdAdd: add a command +[\fIxpacmdadd\fR\|(3)] +.IP "\(bu" 4 +XPACmdDel: delete a command +[\fIxpacmddel\fR\|(3)] +.IP "\(bu" 4 +XPAInfoNew: define an info access point +[\fIxpainfonew\fR\|(3)] +.IP "\(bu" 4 +XPAFree: free an access point +[\fIxpafree\fR\|(3)] +.IP "\(bu" 4 +XPAMainLoop: event loop for select server +[\fIxpamainloop\fR\|(3)] +.IP "\(bu" 4 +XPAPoll: poll for \s-1XPA\s0 events +[\fIxpapoll\fR\|(3)] +.IP "\(bu" 4 +XPACleanup: release reserved \s-1XPA\s0 memory +[\fIxpacleanup\fR\|(3)] +.IP "\(bu" 4 +\&\s-1XPA\s0 Server Macros: accessing structure internals +[\fIxpamacros\fR\|(3)] +.IP "\(bu" 4 +\&\s-1XPA\s0 Race Conditions: how to avoid them +[\fIxparace\fR\|(3)] +.IP "\(bu" 4 +\&\s-1XPA\s0 Out of Memory (\s-1OOM\s0) errors +[\fIxpaoom\fR\|(3)] +.RE +.RS 4 +.RE +.IP "\(bu" 4 +\&\s-1XPA\s0 Client Routines +.RS 4 +.IP "\(bu" 4 +XPAOpen: open a persistent client connection +[\fIxpaopen\fR\|(3)] +.IP "\(bu" 4 +XPAClose: close persistent client connection +[\fIxpaclose\fR\|(3)] +.IP "\(bu" 4 +XPAGet: get data +[\fIxpaget\fR\|(3)] +.IP "\(bu" 4 +XPASet: send data or commands +[\fIxpaset\fR\|(3)] +.IP "\(bu" 4 +XPAInfo: send an info alert +[\fIxpainfo\fR\|(3)] +.IP "\(bu" 4 +XPAGetFd: get data and write to an fd +[\fIxpagetfd\fR\|(3)] +.IP "\(bu" 4 +XPASetFd: read data from and fd and send +[\fIxpasetfd\fR\|(3)] +.IP "\(bu" 4 +XPANSLookup: look up an access point +[\fIxpanslookup\fR\|(3)] +.IP "\(bu" 4 +XPAAccess: get access info +[\fIxpaaccess\fR\|(3)] +.IP "\(bu" 4 +The XPA/Xt Interface: Xt interface to \s-1XPA\s0 +[xpaxt(n)] +.IP "\(bu" 4 +The XPA/Tcl Interface: Tcl interface to \s-1XPA\s0 +[xpatcl(n)] +.RE +.RS 4 +.RE +.IP "\(bu" 4 +Tailoring the \s-1XPA\s0 Environment +.RS 4 +.IP "\(bu" 4 +Environment Variables +[xpaenv(n)] +.IP "\(bu" 4 +Access Control +[xpaacl(n)] +.RE +.RS 4 +.RE +.IP "\(bu" 4 +Miscellaneous +.RS 4 +.IP "\(bu" 4 +Where to Find Example/Test Code +.IP "\(bu" 4 +User Changes Between \s-1XPA\s0 1.0 and 2.0 +.IP "\(bu" 4 +\&\s-1API\s0 Changes Between \s-1XPA\s0 1.0 and 2.0 +.IP "\(bu" 4 +What Does \s-1XPA\s0 Stand For, Anyway? +.RE +.RS 4 +.RE diff --git a/xpa/man/mann/xpaacl.n b/xpa/man/mann/xpaacl.n new file mode 100644 index 0000000..d339c5d --- /dev/null +++ b/xpa/man/mann/xpaacl.n @@ -0,0 +1,251 @@ +.\" Automatically generated by Pod::Man 2.22 (Pod::Simple 3.13) +.\" +.\" Standard preamble: +.\" ======================================================================== +.de Sp \" Vertical space (when we can't use .PP) +.if t .sp .5v +.if n .sp +.. +.de Vb \" Begin verbatim text +.ft CW +.nf +.ne \\$1 +.. +.de Ve \" End verbatim text +.ft R +.fi +.. +.\" Set up some character translations and predefined strings. \*(-- will +.\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left +.\" double quote, and \*(R" will give a right double quote. \*(C+ will +.\" give a nicer C++. Capital omega is used to do unbreakable dashes and +.\" therefore won't be available. \*(C` and \*(C' expand to `' in nroff, +.\" nothing in troff, for use with C<>. +.tr \(*W- +.ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p' +.ie n \{\ +. ds -- \(*W- +. ds PI pi +. if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch +. if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch +. ds L" "" +. ds R" "" +. ds C` "" +. ds C' "" +'br\} +.el\{\ +. ds -- \|\(em\| +. ds PI \(*p +. ds L" `` +. ds R" '' +'br\} +.\" +.\" Escape single quotes in literal strings from groff's Unicode transform. +.ie \n(.g .ds Aq \(aq +.el .ds Aq ' +.\" +.\" If the F register is turned on, we'll generate index entries on stderr for +.\" titles (.TH), headers (.SH), subsections (.SS), items (.Ip), and index +.\" entries marked with X<> in POD. Of course, you'll have to process the +.\" output yourself in some meaningful fashion. +.ie \nF \{\ +. de IX +. tm Index:\\$1\t\\n%\t"\\$2" +.. +. nr % 0 +. rr F +.\} +.el \{\ +. de IX +.. +.\} +.\" +.\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2). +.\" Fear. Run. Save yourself. No user-serviceable parts. +. \" fudge factors for nroff and troff +.if n \{\ +. ds #H 0 +. ds #V .8m +. ds #F .3m +. ds #[ \f1 +. ds #] \fP +.\} +.if t \{\ +. ds #H ((1u-(\\\\n(.fu%2u))*.13m) +. ds #V .6m +. ds #F 0 +. ds #[ \& +. ds #] \& +.\} +. \" simple accents for nroff and troff +.if n \{\ +. ds ' \& +. ds ` \& +. ds ^ \& +. ds , \& +. ds ~ ~ +. ds / +.\} +.if t \{\ +. ds ' \\k:\h'-(\\n(.wu*8/10-\*(#H)'\'\h"|\\n:u" +. ds ` \\k:\h'-(\\n(.wu*8/10-\*(#H)'\`\h'|\\n:u' +. ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'^\h'|\\n:u' +. ds , \\k:\h'-(\\n(.wu*8/10)',\h'|\\n:u' +. ds ~ \\k:\h'-(\\n(.wu-\*(#H-.1m)'~\h'|\\n:u' +. ds / \\k:\h'-(\\n(.wu*8/10-\*(#H)'\z\(sl\h'|\\n:u' +.\} +. \" troff and (daisy-wheel) nroff accents +.ds : \\k:\h'-(\\n(.wu*8/10-\*(#H+.1m+\*(#F)'\v'-\*(#V'\z.\h'.2m+\*(#F'.\h'|\\n:u'\v'\*(#V' +.ds 8 \h'\*(#H'\(*b\h'-\*(#H' +.ds o \\k:\h'-(\\n(.wu+\w'\(de'u-\*(#H)/2u'\v'-.3n'\*(#[\z\(de\v'.3n'\h'|\\n:u'\*(#] +.ds d- \h'\*(#H'\(pd\h'-\w'~'u'\v'-.25m'\f2\(hy\fP\v'.25m'\h'-\*(#H' +.ds D- D\\k:\h'-\w'D'u'\v'-.11m'\z\(hy\v'.11m'\h'|\\n:u' +.ds th \*(#[\v'.3m'\s+1I\s-1\v'-.3m'\h'-(\w'I'u*2/3)'\s-1o\s+1\*(#] +.ds Th \*(#[\s+2I\s-2\h'-\w'I'u*3/5'\v'-.3m'o\v'.3m'\*(#] +.ds ae a\h'-(\w'a'u*4/10)'e +.ds Ae A\h'-(\w'A'u*4/10)'E +. \" corrections for vroff +.if v .ds ~ \\k:\h'-(\\n(.wu*9/10-\*(#H)'\s-2\u~\d\s+2\h'|\\n:u' +.if v .ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'\v'-.4m'^\v'.4m'\h'|\\n:u' +. \" for low resolution devices (crt and lpr) +.if \n(.H>23 .if \n(.V>19 \ +\{\ +. ds : e +. ds 8 ss +. ds o a +. ds d- d\h'-1'\(ga +. ds D- D\h'-1'\(hy +. ds th \o'bp' +. ds Th \o'LP' +. ds ae ae +. ds Ae AE +.\} +.rm #[ #] #H #V #F C +.\" ======================================================================== +.\" +.IX Title "xpaacl n" +.TH xpaacl n "July 23, 2013" "version 2.1.15" "SAORD Documentation" +.\" For nroff, turn off justification. Always turn off hyphenation; it makes +.\" way too many mistakes in technical documents. +.if n .ad l +.nh +.SH "NAME" +\&\fBXPAAcl: Access Control for \s-1XPA\s0 Messaging\fR +.SH "SYNOPSIS" +.IX Header "SYNOPSIS" +\&\s-1XPA\s0 supports host-based access control for each \s-1XPA\s0 access point. You +can enable/disable access control using the \s-1XPA_ACL\s0 environment +variable. You can specify access to specific \s-1XPA\s0 access points for +specific machines using the \s-1XPA_DEFACL\s0 and \s-1XPA_ACLFILE\s0 environment +variables. By default, an \s-1XPA\s0 access point is accessible only to +processes running on the same machine (same as X Windows). +.SH "DESCRIPTION" +.IX Header "DESCRIPTION" +When \s-1INET\s0 sockets are in use (the default, as specified by the +\&\fI\s-1XPA_METHOD\s0\fR environment variable), \s-1XPA\s0 supports a host-based +access control mechanism for individual access points. This mean that +access can be specified for get, set, or info operations for each +access point on a machine by machine basis. For \s-1LOCAL\s0 sockets, access +is restricted (by definition) to the host machine. +.PP +\&\s-1XPA\s0 access control is enabled by default, but can be turned off by +setting the \fI\s-1XPA_ACL\s0\fR environment variable to \fIfalse\fR. +In this case, any process can access any \s-1XPA\s0 server. +.PP +Assuming that access control is turned on, the \s-1ACL\s0 for an individual +\&\s-1XPA\s0 access point is set up when that access point is registered +(although it can be changed later on; see below). This can be done in +one of two ways: +.PP +Firstly, the \fI\s-1XPA_ACLFILE\s0\fR environment variable can defined to +point to a file of access controls for individual access points. The format +of this file is: +.PP +.Vb 1 +\& class:name ip acl +.Ve +.PP +The first argument is a template that specifies the class:name of the +access point covered by this \s-1ACL\s0. See +\&\s-1XPA\s0 Access Points and Templates +for more information about xpa templates. +.PP +The second argument is the \s-1IP\s0 address (in human-readable format) of +the machine which is being given access. This argument can be +\&\fI*\fR to match all \s-1IP\s0 addresses. It also can be \fI\f(CI$host\fI\fR +to match the \s-1IP\s0 address of the current host. +.PP +The third argument is a string combination of \fIs\fR, \fIg\fR, +or \fIi\fR to allow \fIxpaset\fR, \fIxpaget\fR, or +\&\fIxpainfo\fR access respectively. The \s-1ACL\s0 argument can be +\&\fI+\fR to give \fIsgi\fR access or it can be \fI\-\fR to turn +off all access. +.PP +For example, +.PP +.Vb 3 +\& *:xpa1 somehost sg +\& *:xpa1 myhost + +\& * * g +.Ve +.PP +will allow processes on the machine somehost to make xpaget and xpaset calls, +allow processes on myhost to make any call, and allow all other hosts to +make xpaget (but not xpaset) calls. +.PP +Secondly, if the \fI\s-1XPA_ACLFILE\s0\fR does not exist, then a single +default value for all access points can be specified using the +\&\fI\s-1XPA_DEFACL\s0\fR environment variable. The default value for this +variable is: +.PP +.Vb 1 +\& #define XPA_DEFACL "*:* $host +" +.Ve +.PP +meaning that all access points are fully accessible to all processes +on the current host. Thus, in the absence of any \s-1ACL\s0 environment variables, +processes on the current host have full access to all access points +created on that host. This parallels the X11 xhost mechanism. +.PP +Access to an individual \s-1XPA\s0 access point can be changed using the \-acl +parameter for that access point. For example: +.PP +.Vb 1 +\& xpaset \-p xpa1 \-acl "somehost \-" +.Ve +.PP +will turn off all access control for somehost to the xpa1 access point, while: +.PP +.Vb 1 +\& xpaset \-p XPA:xpa1 \-acl "beberly gs" +.Ve +.PP +will give beberly xpaget and xpaset access to the access point whose +class is \s-1XPA\s0 and whose name is xpa1. +.PP +Similarly, the current \s-1ACL\s0 for a given access point can be retrieved using: +.PP +.Vb 1 +\& xpaget xpa1 \-acl +.Ve +.PP +Of course, you must have xpaget access to this \s-1XPA\s0 access point to +retrieve its \s-1ACL\s0. +.PP +Note that the \s-1XPA\s0 access points registered in the \fIxpans\fR +program also behave according to the \s-1ACL\s0 rules. That is, you cannot +use xpaget to view the access points registered with xpans unless +you have the proper \s-1ACL\s0. +.PP +Note also when a client request is made to an \s-1XPA\s0 server, the access +control is checked when the initial connection is established. This +access in effect at this time remains in effect so long as the client +connection is maintained, regardless of whether the access fro that +\&\s-1XPA\s0 is changed later on. +.PP +We recognize that host-based access control is only relatively secure +and will consider more stringent security (e.g., private key) in the +future if the community requires such support. +.SH "SEE ALSO" +.IX Header "SEE ALSO" +See xpa(n) for a list of \s-1XPA\s0 help pages diff --git a/xpa/man/mann/xpacode.n b/xpa/man/mann/xpacode.n new file mode 100644 index 0000000..b13c7ae --- /dev/null +++ b/xpa/man/mann/xpacode.n @@ -0,0 +1,181 @@ +.\" Automatically generated by Pod::Man 2.22 (Pod::Simple 3.13) +.\" +.\" Standard preamble: +.\" ======================================================================== +.de Sp \" Vertical space (when we can't use .PP) +.if t .sp .5v +.if n .sp +.. +.de Vb \" Begin verbatim text +.ft CW +.nf +.ne \\$1 +.. +.de Ve \" End verbatim text +.ft R +.fi +.. +.\" Set up some character translations and predefined strings. \*(-- will +.\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left +.\" double quote, and \*(R" will give a right double quote. \*(C+ will +.\" give a nicer C++. Capital omega is used to do unbreakable dashes and +.\" therefore won't be available. \*(C` and \*(C' expand to `' in nroff, +.\" nothing in troff, for use with C<>. +.tr \(*W- +.ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p' +.ie n \{\ +. ds -- \(*W- +. ds PI pi +. if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch +. if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch +. ds L" "" +. ds R" "" +. ds C` "" +. ds C' "" +'br\} +.el\{\ +. ds -- \|\(em\| +. ds PI \(*p +. ds L" `` +. ds R" '' +'br\} +.\" +.\" Escape single quotes in literal strings from groff's Unicode transform. +.ie \n(.g .ds Aq \(aq +.el .ds Aq ' +.\" +.\" If the F register is turned on, we'll generate index entries on stderr for +.\" titles (.TH), headers (.SH), subsections (.SS), items (.Ip), and index +.\" entries marked with X<> in POD. Of course, you'll have to process the +.\" output yourself in some meaningful fashion. +.ie \nF \{\ +. de IX +. tm Index:\\$1\t\\n%\t"\\$2" +.. +. nr % 0 +. rr F +.\} +.el \{\ +. de IX +.. +.\} +.\" +.\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2). +.\" Fear. Run. Save yourself. No user-serviceable parts. +. \" fudge factors for nroff and troff +.if n \{\ +. ds #H 0 +. ds #V .8m +. ds #F .3m +. ds #[ \f1 +. ds #] \fP +.\} +.if t \{\ +. ds #H ((1u-(\\\\n(.fu%2u))*.13m) +. ds #V .6m +. ds #F 0 +. ds #[ \& +. ds #] \& +.\} +. \" simple accents for nroff and troff +.if n \{\ +. ds ' \& +. ds ` \& +. ds ^ \& +. ds , \& +. ds ~ ~ +. ds / +.\} +.if t \{\ +. ds ' \\k:\h'-(\\n(.wu*8/10-\*(#H)'\'\h"|\\n:u" +. ds ` \\k:\h'-(\\n(.wu*8/10-\*(#H)'\`\h'|\\n:u' +. ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'^\h'|\\n:u' +. ds , \\k:\h'-(\\n(.wu*8/10)',\h'|\\n:u' +. ds ~ \\k:\h'-(\\n(.wu-\*(#H-.1m)'~\h'|\\n:u' +. ds / \\k:\h'-(\\n(.wu*8/10-\*(#H)'\z\(sl\h'|\\n:u' +.\} +. \" troff and (daisy-wheel) nroff accents +.ds : \\k:\h'-(\\n(.wu*8/10-\*(#H+.1m+\*(#F)'\v'-\*(#V'\z.\h'.2m+\*(#F'.\h'|\\n:u'\v'\*(#V' +.ds 8 \h'\*(#H'\(*b\h'-\*(#H' +.ds o \\k:\h'-(\\n(.wu+\w'\(de'u-\*(#H)/2u'\v'-.3n'\*(#[\z\(de\v'.3n'\h'|\\n:u'\*(#] +.ds d- \h'\*(#H'\(pd\h'-\w'~'u'\v'-.25m'\f2\(hy\fP\v'.25m'\h'-\*(#H' +.ds D- D\\k:\h'-\w'D'u'\v'-.11m'\z\(hy\v'.11m'\h'|\\n:u' +.ds th \*(#[\v'.3m'\s+1I\s-1\v'-.3m'\h'-(\w'I'u*2/3)'\s-1o\s+1\*(#] +.ds Th \*(#[\s+2I\s-2\h'-\w'I'u*3/5'\v'-.3m'o\v'.3m'\*(#] +.ds ae a\h'-(\w'a'u*4/10)'e +.ds Ae A\h'-(\w'A'u*4/10)'E +. \" corrections for vroff +.if v .ds ~ \\k:\h'-(\\n(.wu*9/10-\*(#H)'\s-2\u~\d\s+2\h'|\\n:u' +.if v .ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'\v'-.4m'^\v'.4m'\h'|\\n:u' +. \" for low resolution devices (crt and lpr) +.if \n(.H>23 .if \n(.V>19 \ +\{\ +. ds : e +. ds 8 ss +. ds o a +. ds d- d\h'-1'\(ga +. ds D- D\h'-1'\(hy +. ds th \o'bp' +. ds Th \o'LP' +. ds ae ae +. ds Ae AE +.\} +.rm #[ #] #H #V #F C +.\" ======================================================================== +.\" +.IX Title "xpacode n" +.TH xpacode n "July 23, 2013" "version 2.1.15" "SAORD Documentation" +.\" For nroff, turn off justification. Always turn off hyphenation; it makes +.\" way too many mistakes in technical documents. +.if n .ad l +.nh +.SH "NAME" +\&\fBXPACode: Where to Find Example/Test Code\fR +.SH "SYNOPSIS" +.IX Header "SYNOPSIS" +The \s-1XPA\s0 source code directory contains two test programs, +\&\fIstest.c\fR, and \fIctest.c\fR that can serve as +examples for writing \s-1XPA\s0 servers and clients, respectively. +They also can be used to test various features of \s-1XPA\s0. +.SH "DESCRIPTION" +.IX Header "DESCRIPTION" +To build the \s-1XPA\s0 test programs, execute: +.PP +.Vb 1 +\& make All +.Ve +.PP +in the \s-1XPA\s0 source directory to generate the \fIstest\fR and +\&\fIctest\fR programs. (\s-1NB:\s0 this should work on all platforms, +although we have had problems with unresolved externals on one +Sun/Solaris machine, for reasons still unknown.) +.PP +The stest program can be executed with no arguments to start +an \s-1XPA\s0 server that contains the access points: xpa, xpa1, +c_xpa (containing sub-commands cmd1 and cmd2), and i_xpa. +You then can use xpaset and xpaget to interact with these access points: +.PP +.Vb 4 +\& cat xpa.c | xpaset xpa # send to xpa +\& cat xpa.c | xpaset "xpa*" # send to xpa and xpa1 +\& xpaget xpa # receive from xpa +\& xpaget xpa* # receive from xpa and xpa1 +.Ve +.PP +etc. You also can use ctest to do the same thing, or to iterate: +.PP +.Vb 4 +\& ctest \-s \-l 100 xpa # send to xpa 100 times +\& ctest \-s \-l 100 "xpa*" # send to xpa and xpa1 100 times +\& ctest \-g \-l 100 xpa # receive from xpa 100 times +\& ctest \-g \-l 100 "xpa*" # receive from xpa and xpa1 100 times +.Ve +.PP +More options are available: see the stest.c and ctest.c code itself, which +were used extensively to debug \s-1XPA\s0. +.PP +The file test.tcl in the \s-1XPA\s0 source directory gives examples for using the +XPATclInterface. +.SH "SEE ALSO" +.IX Header "SEE ALSO" +See xpa(n) for a list of \s-1XPA\s0 help pages diff --git a/xpa/man/mann/xpacommon.n b/xpa/man/mann/xpacommon.n new file mode 100644 index 0000000..1a456ed --- /dev/null +++ b/xpa/man/mann/xpacommon.n @@ -0,0 +1,302 @@ +.\" Automatically generated by Pod::Man 2.22 (Pod::Simple 3.13) +.\" +.\" Standard preamble: +.\" ======================================================================== +.de Sp \" Vertical space (when we can't use .PP) +.if t .sp .5v +.if n .sp +.. +.de Vb \" Begin verbatim text +.ft CW +.nf +.ne \\$1 +.. +.de Ve \" End verbatim text +.ft R +.fi +.. +.\" Set up some character translations and predefined strings. \*(-- will +.\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left +.\" double quote, and \*(R" will give a right double quote. \*(C+ will +.\" give a nicer C++. Capital omega is used to do unbreakable dashes and +.\" therefore won't be available. \*(C` and \*(C' expand to `' in nroff, +.\" nothing in troff, for use with C<>. +.tr \(*W- +.ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p' +.ie n \{\ +. ds -- \(*W- +. ds PI pi +. if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch +. if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch +. ds L" "" +. ds R" "" +. ds C` "" +. ds C' "" +'br\} +.el\{\ +. ds -- \|\(em\| +. ds PI \(*p +. ds L" `` +. ds R" '' +'br\} +.\" +.\" Escape single quotes in literal strings from groff's Unicode transform. +.ie \n(.g .ds Aq \(aq +.el .ds Aq ' +.\" +.\" If the F register is turned on, we'll generate index entries on stderr for +.\" titles (.TH), headers (.SH), subsections (.SS), items (.Ip), and index +.\" entries marked with X<> in POD. Of course, you'll have to process the +.\" output yourself in some meaningful fashion. +.ie \nF \{\ +. de IX +. tm Index:\\$1\t\\n%\t"\\$2" +.. +. nr % 0 +. rr F +.\} +.el \{\ +. de IX +.. +.\} +.\" +.\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2). +.\" Fear. Run. Save yourself. No user-serviceable parts. +. \" fudge factors for nroff and troff +.if n \{\ +. ds #H 0 +. ds #V .8m +. ds #F .3m +. ds #[ \f1 +. ds #] \fP +.\} +.if t \{\ +. ds #H ((1u-(\\\\n(.fu%2u))*.13m) +. ds #V .6m +. ds #F 0 +. ds #[ \& +. ds #] \& +.\} +. \" simple accents for nroff and troff +.if n \{\ +. ds ' \& +. ds ` \& +. ds ^ \& +. ds , \& +. ds ~ ~ +. ds / +.\} +.if t \{\ +. ds ' \\k:\h'-(\\n(.wu*8/10-\*(#H)'\'\h"|\\n:u" +. ds ` \\k:\h'-(\\n(.wu*8/10-\*(#H)'\`\h'|\\n:u' +. ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'^\h'|\\n:u' +. ds , \\k:\h'-(\\n(.wu*8/10)',\h'|\\n:u' +. ds ~ \\k:\h'-(\\n(.wu-\*(#H-.1m)'~\h'|\\n:u' +. ds / \\k:\h'-(\\n(.wu*8/10-\*(#H)'\z\(sl\h'|\\n:u' +.\} +. \" troff and (daisy-wheel) nroff accents +.ds : \\k:\h'-(\\n(.wu*8/10-\*(#H+.1m+\*(#F)'\v'-\*(#V'\z.\h'.2m+\*(#F'.\h'|\\n:u'\v'\*(#V' +.ds 8 \h'\*(#H'\(*b\h'-\*(#H' +.ds o \\k:\h'-(\\n(.wu+\w'\(de'u-\*(#H)/2u'\v'-.3n'\*(#[\z\(de\v'.3n'\h'|\\n:u'\*(#] +.ds d- \h'\*(#H'\(pd\h'-\w'~'u'\v'-.25m'\f2\(hy\fP\v'.25m'\h'-\*(#H' +.ds D- D\\k:\h'-\w'D'u'\v'-.11m'\z\(hy\v'.11m'\h'|\\n:u' +.ds th \*(#[\v'.3m'\s+1I\s-1\v'-.3m'\h'-(\w'I'u*2/3)'\s-1o\s+1\*(#] +.ds Th \*(#[\s+2I\s-2\h'-\w'I'u*3/5'\v'-.3m'o\v'.3m'\*(#] +.ds ae a\h'-(\w'a'u*4/10)'e +.ds Ae A\h'-(\w'A'u*4/10)'E +. \" corrections for vroff +.if v .ds ~ \\k:\h'-(\\n(.wu*9/10-\*(#H)'\s-2\u~\d\s+2\h'|\\n:u' +.if v .ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'\v'-.4m'^\v'.4m'\h'|\\n:u' +. \" for low resolution devices (crt and lpr) +.if \n(.H>23 .if \n(.V>19 \ +\{\ +. ds : e +. ds 8 ss +. ds o a +. ds d- d\h'-1'\(ga +. ds D- D\h'-1'\(hy +. ds th \o'bp' +. ds Th \o'LP' +. ds ae ae +. ds Ae AE +.\} +.rm #[ #] #H #V #F C +.\" ======================================================================== +.\" +.IX Title "xpacommon n" +.TH xpacommon n "July 23, 2013" "version 2.1.15" "SAORD Documentation" +.\" For nroff, turn off justification. Always turn off hyphenation; it makes +.\" way too many mistakes in technical documents. +.if n .ad l +.nh +.SH "NAME" +\&\fBXPACommon: Getting Common Information About Access Points\fR +.SH "SYNOPSIS" +.IX Header "SYNOPSIS" +There are various kinds of generic information you can retrieve about +an \s-1XPA\s0 access point by using the xpaget command. +.SH "DESCRIPTION" +.IX Header "DESCRIPTION" +You can find out which \s-1XPA\s0 access points have been registered with +the currently running +\&\s-1XPA\s0 name server +by executing the +xpaget +command to retrieve info from the \s-1XPA\s0 name server: +.PP +.Vb 1 +\& xpaget xpans +.Ve +.PP +If, for example, the +stest test server program +is running, the following \s-1XPA\s0 access points will be returned (the specifics +of the returned info will vary for different machines and users): +.PP +.Vb 4 +\& XPA xpa gs 838e2f67:1262 eric +\& XPA xpa1 gs 838e2f67:1266 eric +\& XPA c_xpa gs 838e2f67:1267 eric +\& XPA i_xpa i 838e2f67:1268 eric +.Ve +.PP +Note that access to this information is subject to the usual +\&\s-1XPA\s0 Access Control restrictions. +.PP +Each \s-1XPA\s0 access point supports a number of reserved sub-commands that provide +access to different kinds of information, e.g. the access control for +that access point. These sub-commands can be executed by using +xpaset +or +xpaget +at the command line, or +\&\fIXPAGet()\fR +or +\&\fIXPASet()\fR +in programs, e.g: +.PP +.Vb 3 +\& xpaget ds9 \-acl +\& xpaget ds9 \-help +\& xpaget ds9 env FOO +\& +\& xpaset \-p ds9 env FOO foofoo +.Ve +.PP +With the exception of \fB\-help\fR and \fB\-version\fR, reserved +sub-commands are available only on the machine on which the \s-1XPA\s0 server +itself is running. +.PP +The following reserved sub-commands are defined for all access points: +.IP "\(bu" 4 +\&\fB\-acl\fR get (set) the access control list [options: host type acl, for set] +.Sp +The 'xpaset' option allows you to add a new acl for a given host, or change +the acl for an existing host. See +\&\s-1XPA\s0 Access Control +for more information. +This access point is available only on the server machine. +.IP "\(bu" 4 +\&\fB\-env\fR get (set) an environment variable [options: name (value, for set)] +.Sp +The 'xpaget' option will return the value of the named environment +variable. The 'xpaset' option will set the value of the names +variable to the specified value. +This access point is available only on the server machine. +(Please be advised that we have had problems setting environment +variables in static Tcl/Tk programs such as ds9 running under Linux.) +.IP "\(bu" 4 +\&\fB\-clipboard\fR set(get) information on a named clipboard +.Sp +Clients can store \s-1ASCII\s0 state information on any number of named +clipboards. Clipboards of the same name created by clients on +different machines are kept separate. The syntax for creating a +clipboard is: +.Sp +.Vb 2 +\& [data] | xpaset [server] \-clipboard add|append [clipboard_name] +\& xpaset \-p [server] \-clipboard delete [clipboard_name] +.Ve +.Sp +Use \*(L"add\*(R" to create a new clipboard or replace the contents of an existing +one. Use \*(L"append\*(R" to append to an existing clipboard. +.Sp +Information on a named clipboard is retrieved using: +.Sp +.Vb 1 +\& xpaget [server] \-clipboard [clipboard_name] +.Ve +.IP "\(bu" 4 +\&\fB\-exec\fR set: execute commands from buffer [options: none] +.Sp +If \-exec is specified in the paramlist of an 'xpaset' call, then further +sub-commands will be retrieved from the data buffer. +.IP "\(bu" 4 +\&\fB\-help\fR get: return help string for this \s-1XPA\s0 or sub-command [options: name (for sub\-commands)] +.Sp +Each \s-1XPA\s0 access point and each \s-1XPA\s0 sub-command can have a help string +associated with it that is specified when the access point is defined. +The \-help option will return this help string. For \s-1XPA\s0 access points +that contain user-defined sub-commands, you can get the help string +for a particular sub-command by specifying its name, or else get the +help strings for all sub-commands if not name is specified. +.IP "\(bu" 4 +\&\fB\-ltimeout\fR get (set) the long timeout value [options: seconds|reset] +.Sp +The 'xpaget' option will return the value of the long timeout (in seconds). +The 'xpaset' option will set the value of the long timeout. If \*(L"reset\*(R" is +specified, then the timeout value will be reset to the default value. +.IP "\(bu" 4 +\&\fB\-nsconnect\fR set: re-establish name server connection to all \s-1XPA\s0's [options: none] +.Sp +If the +\&\s-1XPA\s0 Name Server (xpans) +process has terminated unexpectedly and then re-started, this +sub-command can be used to re-establish the connection. You use it by +sending the command to the [name:port] or [file] of the access point +instead of to the \s-1XPA\s0 name (since the latter requires the xpans +connection!): +.Sp +.Vb 1 +\& xpaset \-p 838e2f67:1268 \-nsconnect +.Ve +.Sp +See xpans for more information. +.IP "\(bu" 4 +\&\fB\-nsdisconnect\fR set: break name server connection to all \s-1XPA\s0's [options: none] +.Sp +This sub-command will terminate the connection to the +\&\s-1XPA\s0 Name Server (xpans), thereby making +all access points inaccessible except through their underlying [name:port] +or [file] identifiers. I forget why we added it, it seems pretty useless. +.IP "\(bu" 4 +\&\fB\-stimeout\fR get (set) the short timeout value [options: seconds|reset] +.Sp +The 'xpaget' option will return the value of the short timeout (in seconds). +The 'xpaset' option will set the value of the short timeout. If \*(L"reset\*(R" is +specified, then the timeout value will be reset to the default value. +.IP "\(bu" 4 +\&\fB\-remote\fR set: register xpa with remote server [options: host[:port] [acl]] [\-proxy] +.Sp +This sub-command will register the \s-1XPA\s0 access point with the \s-1XPA\s0 name +server (xpans) on the specified host (which must already be running). +The specified host also is given access control to the access point, +using the specified acl or the default acl of \*(L"+\*(R" (meaning the remote +host can xpaset, xpaget, xpainfo or xpaaccess). If the acl is +specified as \*(L"\-\*(R", then the access point is unregistered. +See Communication Between Machines +for more information on how this sub-command is used. +.IP "\(bu" 4 +\&\fB\-version\fR get: return \s-1XPA\s0 version string [options: none] +.Sp +The version refers to the version of \s-1XPA\s0 used to define this access point +(currently something like 2.0). +.PP +You can add your own reserved commands to all \s-1XPA\s0 access points by using the +\&\fIXPACmdAdd()\fR +routine, passing the \s-1XPA\s0 handle returned by \fI\s-1XPA\s0 XPAGetReserved(void)\fR +as the first argument. Note again that these will only be available on the +machine where the \s-1XPA\s0 service is running. +.SH "SEE ALSO" +.IX Header "SEE ALSO" +See xpa(n) for a list of \s-1XPA\s0 help pages diff --git a/xpa/man/mann/xpaconvert.n b/xpa/man/mann/xpaconvert.n new file mode 100644 index 0000000..035ef0b --- /dev/null +++ b/xpa/man/mann/xpaconvert.n @@ -0,0 +1,267 @@ +.\" Automatically generated by Pod::Man 2.22 (Pod::Simple 3.13) +.\" +.\" Standard preamble: +.\" ======================================================================== +.de Sp \" Vertical space (when we can't use .PP) +.if t .sp .5v +.if n .sp +.. +.de Vb \" Begin verbatim text +.ft CW +.nf +.ne \\$1 +.. +.de Ve \" End verbatim text +.ft R +.fi +.. +.\" Set up some character translations and predefined strings. \*(-- will +.\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left +.\" double quote, and \*(R" will give a right double quote. \*(C+ will +.\" give a nicer C++. Capital omega is used to do unbreakable dashes and +.\" therefore won't be available. \*(C` and \*(C' expand to `' in nroff, +.\" nothing in troff, for use with C<>. +.tr \(*W- +.ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p' +.ie n \{\ +. ds -- \(*W- +. ds PI pi +. if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch +. if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch +. ds L" "" +. ds R" "" +. ds C` "" +. ds C' "" +'br\} +.el\{\ +. ds -- \|\(em\| +. ds PI \(*p +. ds L" `` +. ds R" '' +'br\} +.\" +.\" Escape single quotes in literal strings from groff's Unicode transform. +.ie \n(.g .ds Aq \(aq +.el .ds Aq ' +.\" +.\" If the F register is turned on, we'll generate index entries on stderr for +.\" titles (.TH), headers (.SH), subsections (.SS), items (.Ip), and index +.\" entries marked with X<> in POD. Of course, you'll have to process the +.\" output yourself in some meaningful fashion. +.ie \nF \{\ +. de IX +. tm Index:\\$1\t\\n%\t"\\$2" +.. +. nr % 0 +. rr F +.\} +.el \{\ +. de IX +.. +.\} +.\" +.\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2). +.\" Fear. Run. Save yourself. No user-serviceable parts. +. \" fudge factors for nroff and troff +.if n \{\ +. ds #H 0 +. ds #V .8m +. ds #F .3m +. ds #[ \f1 +. ds #] \fP +.\} +.if t \{\ +. ds #H ((1u-(\\\\n(.fu%2u))*.13m) +. ds #V .6m +. ds #F 0 +. ds #[ \& +. ds #] \& +.\} +. \" simple accents for nroff and troff +.if n \{\ +. ds ' \& +. ds ` \& +. ds ^ \& +. ds , \& +. ds ~ ~ +. ds / +.\} +.if t \{\ +. ds ' \\k:\h'-(\\n(.wu*8/10-\*(#H)'\'\h"|\\n:u" +. ds ` \\k:\h'-(\\n(.wu*8/10-\*(#H)'\`\h'|\\n:u' +. ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'^\h'|\\n:u' +. ds , \\k:\h'-(\\n(.wu*8/10)',\h'|\\n:u' +. ds ~ \\k:\h'-(\\n(.wu-\*(#H-.1m)'~\h'|\\n:u' +. ds / \\k:\h'-(\\n(.wu*8/10-\*(#H)'\z\(sl\h'|\\n:u' +.\} +. \" troff and (daisy-wheel) nroff accents +.ds : \\k:\h'-(\\n(.wu*8/10-\*(#H+.1m+\*(#F)'\v'-\*(#V'\z.\h'.2m+\*(#F'.\h'|\\n:u'\v'\*(#V' +.ds 8 \h'\*(#H'\(*b\h'-\*(#H' +.ds o \\k:\h'-(\\n(.wu+\w'\(de'u-\*(#H)/2u'\v'-.3n'\*(#[\z\(de\v'.3n'\h'|\\n:u'\*(#] +.ds d- \h'\*(#H'\(pd\h'-\w'~'u'\v'-.25m'\f2\(hy\fP\v'.25m'\h'-\*(#H' +.ds D- D\\k:\h'-\w'D'u'\v'-.11m'\z\(hy\v'.11m'\h'|\\n:u' +.ds th \*(#[\v'.3m'\s+1I\s-1\v'-.3m'\h'-(\w'I'u*2/3)'\s-1o\s+1\*(#] +.ds Th \*(#[\s+2I\s-2\h'-\w'I'u*3/5'\v'-.3m'o\v'.3m'\*(#] +.ds ae a\h'-(\w'a'u*4/10)'e +.ds Ae A\h'-(\w'A'u*4/10)'E +. \" corrections for vroff +.if v .ds ~ \\k:\h'-(\\n(.wu*9/10-\*(#H)'\s-2\u~\d\s+2\h'|\\n:u' +.if v .ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'\v'-.4m'^\v'.4m'\h'|\\n:u' +. \" for low resolution devices (crt and lpr) +.if \n(.H>23 .if \n(.V>19 \ +\{\ +. ds : e +. ds 8 ss +. ds o a +. ds d- d\h'-1'\(ga +. ds D- D\h'-1'\(hy +. ds th \o'bp' +. ds Th \o'LP' +. ds ae ae +. ds Ae AE +.\} +.rm #[ #] #H #V #F C +.\" ======================================================================== +.\" +.IX Title "xpaconvert n" +.TH xpaconvert n "July 23, 2013" "version 2.1.15" "SAORD Documentation" +.\" For nroff, turn off justification. Always turn off hyphenation; it makes +.\" way too many mistakes in technical documents. +.if n .ad l +.nh +.SH "NAME" +\&\fBXPAConvert: Converting the \s-1XPA\s0 \s-1API\s0 to 2.0\fR +.SH "SYNOPSIS" +.IX Header "SYNOPSIS" +This document describes tips for converting from xpa 1.0 (Xt-based +xpa) to xpa 2.0 (socket-based xpa). +.SH "DESCRIPTION" +.IX Header "DESCRIPTION" +The following are tips for converting from xpa 1.0 (Xt-based xpa) to +xpa 2.0 (socket-based xpa). The changes are straight-forward and +almost can be done automatically (we used editor macros for most of +the conversion). +.IP "\(bu" 4 +The existence of the cpp \s-1XPA_VERSION\s0 directive to distinguish between 1.0 +(where it is not defined) and 2.0 (where it is defined). +.IP "\(bu" 4 +Remove the first widget argument from all send and receive server +callbacks. Also change first 2 arguments from XtPointer to void +*. For example: +.Sp +#ifdef \s-1XPA_VERSION\s0 +static void XPAReceiveFile(client_data, call_data, paramlist, buf, len) + void *client_data; + void *call_data; + char *paramlist; + char *buf; + int len; +#else +static void XPAReceiveFile(w, client_data, call_data, paramlist, buf, len) + Widget w; + XtPointer client_data; + XtPointer call_data; + char *paramlist; + char *buf; + int len; +#endif +.IP "\(bu" 4 +Server callbacks should be declared as returning int instead +of void. They now should return 0 for no errors, \-1 for error. +.IP "\(bu" 4 +The mode flags have changed when defining \s-1XPA\s0 server callbacks. +The old \fIS\fR flag (save buffer) is replaced by \fIfreebuf=false\fR. +The old \fIE\fR flag (empty buffer is \s-1OK\s0) is no longer used (it +was an artifact of the X implementation). +.IP "\(bu" 4 +Change \fINewXPACommand()\fR to \fIXPAcmdNew()\fR, with the new calling sequence: +.Sp +.Vb 1 +\& xpa = NewXPACommand(toplevel, NULL, prefix, NULL); +.Ve +.Sp +is changed to: +.Sp +.Vb 1 +\& xpa = XPACmdNew(xclass, name); +.Ve +.IP "\(bu" 4 +Change the \fIAddXPACommand()\fR subroutine name to XPACmdAdd (with the same +calling sequence): +.Sp +.Vb 3 +\& AddXPACommand(xpa, "file", +\& "\etdisplay a new file\en\et\et requires: filename", +\& NULL, NULL, NULL, XPAReceiveFile, text, NULL); +.Ve +.Sp +is changed to: +.Sp +.Vb 3 +\& XPACmdAdd(xpa, "file", +\& "\etdisplay a new file\en\et\et requires: filename", +\& NULL, NULL, NULL, XPAReceiveFile, text, NULL); +.Ve +.IP "\(bu" 4 +The \fIXPAXtAppInput()\fR routine should be called just before \fIXtAppMainLoop()\fR +to add xpa fds to the Xt event loop: +.Sp +.Vb 2 +\& /* add the xpas to the Xt loop */ +\& XPAXtAddInput(app, NULL); +\& +\& /* process events */ +\& XtAppMainLoop(app); +.Ve +.IP "\(bu" 4 +Change \fINewXPA()\fR to \fIXPANew()\fR and call \fIXPAXtAddInput()\fR if the XtAppMainLoop +routine already has been entered: +.Sp +.Vb 4 +\& xpa = NewXPA(saotng\->xim\->toplevel, prefix, xparoot, +\& "FITS data or image filename\en\et\et options: file type", +\& XPASendData, new, NULL, +\& XPAReceiveData, new, "SE"); +.Ve +.Sp +is changed to: +.Sp +.Vb 6 +\& sprintf(tbuf, "%s.%s", prefix, xparoot); +\& xpa = XPANew("SAOTNG", tbuf, +\& "FITS data or image filename\en\et\et options: file type", +\& XPASendData, new, NULL, +\& XPAReceiveData, new, "SE"); +\& XPAXtAddInput(XtWidgetToApplicationContext(saotng\->xim\->toplevel), xpa); +.Ve +.IP "\(bu" 4 +Change \fIXPAInternalReceiveCommand()\fR to \fIXPACmdInternalReceive()\fR +remove first argument in the calling sequence): +.Sp +.Vb 3 +\& XPAInternalReceiveCommand(im\->saotng\->xim\->toplevel, +\& im\->saotng, im\->saotng\->commands, +\& "zoom reset", NULL, 0); +.Ve +.Sp +is changed to: +.Sp +.Vb 2 +\& XPACmdInternalReceive(im\->saotng, im\->saotng\->commands, +\& "zoom reset", NULL, 0); +.Ve +.IP "\(bu" 4 +Change DestroyXPA to XPAFree: +.Sp +.Vb 1 +\& DestroyXPA(im\->dataxpa); +.Ve +.Sp +is changed to: +.Sp +.Vb 1 +\& XPAFree(im\->dataxpa); +.Ve +.SH "SEE ALSO" +.IX Header "SEE ALSO" +See xpa(n) for a list of \s-1XPA\s0 help pages diff --git a/xpa/man/mann/xpaenv.n b/xpa/man/mann/xpaenv.n new file mode 100644 index 0000000..ead081c --- /dev/null +++ b/xpa/man/mann/xpaenv.n @@ -0,0 +1,482 @@ +.\" Automatically generated by Pod::Man 2.22 (Pod::Simple 3.13) +.\" +.\" Standard preamble: +.\" ======================================================================== +.de Sp \" Vertical space (when we can't use .PP) +.if t .sp .5v +.if n .sp +.. +.de Vb \" Begin verbatim text +.ft CW +.nf +.ne \\$1 +.. +.de Ve \" End verbatim text +.ft R +.fi +.. +.\" Set up some character translations and predefined strings. \*(-- will +.\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left +.\" double quote, and \*(R" will give a right double quote. \*(C+ will +.\" give a nicer C++. Capital omega is used to do unbreakable dashes and +.\" therefore won't be available. \*(C` and \*(C' expand to `' in nroff, +.\" nothing in troff, for use with C<>. +.tr \(*W- +.ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p' +.ie n \{\ +. ds -- \(*W- +. ds PI pi +. if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch +. if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch +. ds L" "" +. ds R" "" +. ds C` "" +. ds C' "" +'br\} +.el\{\ +. ds -- \|\(em\| +. ds PI \(*p +. ds L" `` +. ds R" '' +'br\} +.\" +.\" Escape single quotes in literal strings from groff's Unicode transform. +.ie \n(.g .ds Aq \(aq +.el .ds Aq ' +.\" +.\" If the F register is turned on, we'll generate index entries on stderr for +.\" titles (.TH), headers (.SH), subsections (.SS), items (.Ip), and index +.\" entries marked with X<> in POD. Of course, you'll have to process the +.\" output yourself in some meaningful fashion. +.ie \nF \{\ +. de IX +. tm Index:\\$1\t\\n%\t"\\$2" +.. +. nr % 0 +. rr F +.\} +.el \{\ +. de IX +.. +.\} +.\" +.\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2). +.\" Fear. Run. Save yourself. No user-serviceable parts. +. \" fudge factors for nroff and troff +.if n \{\ +. ds #H 0 +. ds #V .8m +. ds #F .3m +. ds #[ \f1 +. ds #] \fP +.\} +.if t \{\ +. ds #H ((1u-(\\\\n(.fu%2u))*.13m) +. ds #V .6m +. ds #F 0 +. ds #[ \& +. ds #] \& +.\} +. \" simple accents for nroff and troff +.if n \{\ +. ds ' \& +. ds ` \& +. ds ^ \& +. ds , \& +. ds ~ ~ +. ds / +.\} +.if t \{\ +. ds ' \\k:\h'-(\\n(.wu*8/10-\*(#H)'\'\h"|\\n:u" +. ds ` \\k:\h'-(\\n(.wu*8/10-\*(#H)'\`\h'|\\n:u' +. ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'^\h'|\\n:u' +. ds , \\k:\h'-(\\n(.wu*8/10)',\h'|\\n:u' +. ds ~ \\k:\h'-(\\n(.wu-\*(#H-.1m)'~\h'|\\n:u' +. ds / \\k:\h'-(\\n(.wu*8/10-\*(#H)'\z\(sl\h'|\\n:u' +.\} +. \" troff and (daisy-wheel) nroff accents +.ds : \\k:\h'-(\\n(.wu*8/10-\*(#H+.1m+\*(#F)'\v'-\*(#V'\z.\h'.2m+\*(#F'.\h'|\\n:u'\v'\*(#V' +.ds 8 \h'\*(#H'\(*b\h'-\*(#H' +.ds o \\k:\h'-(\\n(.wu+\w'\(de'u-\*(#H)/2u'\v'-.3n'\*(#[\z\(de\v'.3n'\h'|\\n:u'\*(#] +.ds d- \h'\*(#H'\(pd\h'-\w'~'u'\v'-.25m'\f2\(hy\fP\v'.25m'\h'-\*(#H' +.ds D- D\\k:\h'-\w'D'u'\v'-.11m'\z\(hy\v'.11m'\h'|\\n:u' +.ds th \*(#[\v'.3m'\s+1I\s-1\v'-.3m'\h'-(\w'I'u*2/3)'\s-1o\s+1\*(#] +.ds Th \*(#[\s+2I\s-2\h'-\w'I'u*3/5'\v'-.3m'o\v'.3m'\*(#] +.ds ae a\h'-(\w'a'u*4/10)'e +.ds Ae A\h'-(\w'A'u*4/10)'E +. \" corrections for vroff +.if v .ds ~ \\k:\h'-(\\n(.wu*9/10-\*(#H)'\s-2\u~\d\s+2\h'|\\n:u' +.if v .ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'\v'-.4m'^\v'.4m'\h'|\\n:u' +. \" for low resolution devices (crt and lpr) +.if \n(.H>23 .if \n(.V>19 \ +\{\ +. ds : e +. ds 8 ss +. ds o a +. ds d- d\h'-1'\(ga +. ds D- D\h'-1'\(hy +. ds th \o'bp' +. ds Th \o'LP' +. ds ae ae +. ds Ae AE +.\} +.rm #[ #] #H #V #F C +.\" ======================================================================== +.\" +.IX Title "xpaenv n" +.TH xpaenv n "July 23, 2013" "version 2.1.15" "SAORD Documentation" +.\" For nroff, turn off justification. Always turn off hyphenation; it makes +.\" way too many mistakes in technical documents. +.if n .ad l +.nh +.SH "NAME" +\&\fBXPAEnv: Environment Variables for \s-1XPA\s0 Messaging\fR +.SH "SYNOPSIS" +.IX Header "SYNOPSIS" +Describes the environment variables which can be used to tailor the overall +\&\s-1XPA\s0 environment. +.SH "DESCRIPTION" +.IX Header "DESCRIPTION" +The following environment variables are supported by \s-1XPA:\s0 +.IP "\(bu" 4 +\&\fB\s-1XPA_ACL\s0\fR +.Sp +If \fI\s-1XPA_ACL\s0\fR is \fItrue\fR, then +host-based \s-1XPA\s0 Access Control +is turned on and only specified machines can access specified access +points. If \fIfalse\fR, then access control is turned off and any +machine can access point. The default is turn turn access control on. +.IP "\(bu" 4 +\&\fB\s-1XPA_ACLFILE\s0\fR +.Sp +If +\&\s-1XPA\s0 Access Control +is turned on, this variable specifies the name of the file containing +access control information for all access points started by this user. +The default file name is: \fI\f(CI$HOME\fI/acls.xpa\fR. +.IP "\(bu" 4 +\&\fB\s-1XPA_CONNECT_TIMEOUT\s0\fR +.Sp +When an \s-1XPA\s0 server first starts up, it immediately tries to +connect to the \s-1XPA\s0 name server program (xpans) on the host specified by +the \fI\s-1XPA_NSINET\s0\fR variable. (If this connection fails on the +local host, and if xpans can be found in the path, then the name +server is started automatically.) Unfortunately, a mis-configured +network can cause this connect attempt to hang for many seconds while +the \fIconnect()\fR system call times out. Therefore, an alarm is started +to interrupt the \fIconnect()\fR call and prevent a long hang. The initial +value of the alarm timeout is 10 seconds, but can be changed by setting +this environment variable. If you want to disable the alarm and allow +the initial \fIconnect()\fR to time out, set the value of this variable to +0. Normally, users would not change this variable at all. +.IP "\(bu" 4 +\&\fB\s-1XPA_CLIENT_DOXPA\s0\fR +.Sp +Normally, an \s-1XPA\s0 client (xpaget, xpaset, etc.) will process incoming +\&\s-1XPA\s0 server requests while awaiting the completion of the client request. +Setting this variable to \*(L"false\*(R" will prevent \s-1XPA\s0 server requests from +being processed by the client. +.IP "\(bu" 4 +\&\fB\s-1XPA_DEFACL\s0\fR +.Sp +If +\&\s-1XPA\s0 Access Control +is turned on, this variable specifies the default access control +condition for all access points, if the \fI\s-1XPA_ACLFILE\s0\fR file does +not exist. The default acl is: \fI\f(CI$host:\fI* \f(CI$host\fI +\fR, meaning that +all processes on the host machine have full access to all access points. +.IP "\(bu" 4 +\&\fB\s-1XPA_HOST\s0\fR +.Sp +For the \s-1INET\s0 socket method, \s-1XPA\s0 utilizes the canonical hostname (as +returned by the \fIgethostname()\fR routine) to construct the \s-1IP\s0 part of the +method id. Under some circumstances, this might not be a correct choice +of name and \s-1IP\s0. For example, if an \s-1XPA\s0 server is started on a machine +running \s-1VPN\s0, you might want to use the \s-1VPN\s0 name and \s-1IP\s0 instead of the +canonical host name, so that other machines in the \s-1VPN\s0 network can +access the server. In this case, you can set the \s-1XPA_HOST\s0 to be +the \s-1VPN\s0 name (if resolvable) or, more easily, the \s-1VPN\s0 \s-1IP\s0. +.IP "\(bu" 4 +\&\fB\s-1XPA_IOCALLSXPA\s0\fR +.Sp +Setting this variable causes all \s-1XPA\s0 socket \s-1IO\s0 calls to process +outstanding \s-1XPA\s0 requests whenever the primary socket is not ready for +\&\s-1IO\s0. This means that a server making a client call will (recursively) +process incoming server requests while waiting for client completion. +This inter-IO \s-1XPA\s0 processing avoids a rare +\&\s-1XPA\s0 Race Condition: two or more +\&\s-1XPA\s0 servers sending messages to one another using an \s-1XPA\s0 client +routine such as \fIXPASet()\fR can deadlock while each waits for the other +server to respond. This can happen, for example, if the servers call +\&\fIXPAPoll()\fR with a time limit, and send messages in between the polling call. +.Sp +By default, this option is turned off, because we judge that the added +code complication and overhead involved will not be justified by the +amount of its use. Moreover, processing \s-1XPA\s0 requests within socket \s-1IO\s0 +can lead to non-intuitive results, since incoming server requests will +not necessarily be processed to completion in the order in which they +are received. +.IP "\(bu" 4 +\&\fB\s-1XPA_LOGNAME\s0\fR +.Sp +\&\s-1XPA\s0 preferentially uses the de facto standard environment variable +\&\s-1LOGNAME\s0 to determine the username when registering an access point in +the name server. If this environment variable has been used for +something other than the actual user name (such as a log file name), +unexpected results can ensue. In such cases, use the \s-1XPA_LOGNAME\s0 +variable to set the user name. (If neither exists, then getpwuid(\fIgeteuid()\fR) +is used as a last resort). +.IP "\(bu" 4 +\&\fB\s-1XPA_LONG_TIMEOUT\s0\fR +.Sp +\&\s-1XPA\s0 is designed to allow data to be sent from one process to +another over a long period of time (i.e., a program that generates +image data sends that data to an image display, but slowly) but it +also seeks to prevent hangs. This is done by supporting 2 timeout +periods: a \fIshort\fR timeout for protocol communication +and a \fIlong\fR for data communication. +.Sp +The \fI\s-1XPA_LONG_TIMEOUT\s0\fR variable controls the \fIlong\fR +timeout and is used to prevent hangs in cases where communication +between the client and server that is \fInot\fR controlled by the +\&\s-1XPA\s0 interface itself. Transfer of data between client and server, or a +client's wait for a status message after completion of the server +callback, are two examples of this sort of communication. By default, +the \fIlong\fR timeout is set to 180 seconds. +Setting the value to \-1 will disable \fIlong\fR timeouts and allow +an infinite amount of time. +.IP "\(bu" 4 +\&\fB\s-1XPA_MAXHOSTS\s0\fR +.Sp +The maximum number of access points that the programs +\&\fIxpaset\fR, \fIxpaget\fR, and \fIxpainfo\fR will +communicate with at one time. The default is 64, meaning, for +example, that the \fIxpaset\fR program will not send a message +to more than 100 access points at one time and \fIxpaget\fR will +not retrieve from more than 100 access points at one time. +.IP "\(bu" 4 +\&\fB\s-1XPA_METHOD\s0\fR +.Sp +Determines the socket connection method used by this session of \s-1XPA\s0. +The choices are: \fIinet\fR (to use \s-1INET\s0 or Internet-based +sockets), \fIlocalhost\fR (to use the machines localhost inet +socket), or \fIlocal (unix)\fR (to use \s-1UNIX\s0 sockets). The default +is \fI\s-1INET\s0\fR. Using the \fIinet\fR method will allow access +from other machines (subject to access controls) but using +\&\fIlocalhost\fR or \fIlocal\fR will not. Localhost is most useful +for private access and when the machine in question is not connected +to the Internet. The unix method also can be used for private access +and non-Internet connections (Unix platforms only). +.Sp +Once defined, the first registration of an \s-1XPA\s0 access point will +ensure that an instance of the +\&\s-1XPA\s0 Name Server (xpans) +is running that handles that connection method. All new access points +will use the new connection method but existing access points will use +the original method. +.IP "\(bu" 4 +\&\fB\s-1XPA_NSINET\s0\fR +.Sp +For the \fIinet\fR method of socket connection, this variable +specifies the host and port on which the +\&\s-1XPA\s0 Name Server (xpans) +is listens for new access points. The default is \fI\f(CI$host:\fI$port\fR, +meaning that the default \s-1XPA\s0 port (14285) on the current machine +(as returned by \fIgethostname()\fR) is used. If several machines were all +accessing the same \s-1XPA\s0 access points, you would use this variable to +specify that they all use the same name server to find out about these +access points. For example, a value of \fImyhost:$port\fR would +mean that the xpans name server is running on myhost and uses the +default port 12345. All machines would then get the \s-1XPA\s0 access points +registered with that name server, subject to access controls. +.Sp +The port used by xpans to register its \s-1XPA\s0 access point normally is +taken to be one greater than the port on which it receives new access +points from \s-1XPA\s0 servers. You can specify a specific access point port +using the syntax machine:port1,port2, i.e., the access point port is +specified after the comma. For example, \f(CW$host:12345\fR,23456 will listen +for new access ports on 12345 and will accept \s-1XPA\s0 commands on 23456. +.IP "\(bu" 4 +\&\fB\s-1XPA_NSREGISTER\s0\fR +.Sp +This boolean variable specifies whether a server registers its \s-1XPA\s0 +access point with the specified xpans name server. The default is +\&\fItrue\fR. If set to \fIfalse\fR, the access point still is +set up but it is not registered with xpans and therefore cannot be +accessed by name. (It can be accessed by method, if the latter is +known.) Note that an access point can be registered later on (using +\&\-remote or \-proxy, for example). This variable mainly is useful in +cases where the Internet configuration is broken (so that registration +causes a \s-1DNS\s0 hang) but you still wish to and can use the server with a +remote xpans (e.g., ds9's Virtual Observatory capability). +.IP "\(bu" 4 +\&\fB\s-1XPA_NSUNIX\s0\fR +.Sp +For the \fIlocal\fR method of socket connection, this variable +specifies the name of the Unix file that will be used to access the +\&\s-1XPA\s0 Name Server (xpans). The default is +\&\fIxpans_unix\fR. This variable is not usually needed. Note that +is the \fIlocal\fR socket method is used, then remote machines will +not be able to access the xpans name server or the registered \s-1XPA\s0 access +points. +.IP "\(bu" 4 +\&\fB\s-1XPA_NSUSERS\s0\fR +.Sp +This variable specifies whether other users' access points will be +returned by the +\&\s-1XPA\s0 Name Server (xpans) for use by +\&\fIxpaget\fR, \fIxpaset\fR, etc. +Generally speaking, it is sufficient to run one xpans name server per +machine and register the access points for all users with that xpans. +This means, for example, that if you request information from +ds9 by running: +.Sp +.Vb 1 +\& xpaget ds9 colormap +.Ve +.Sp +you might get information from your own ds9 as well as +from another user running ds9 on the same machine. The +\&\fI\s-1XPA_NSUSERS\s0\fR variable controls whether you want such access +to the access points of other users. +By default, only your own access points are returned, so +that, in the example above, you would only get the colormap information +from the ds9 you registered. If, however, you had set the value of the +\&\fI\s-1XPA_NSUSERS\s0\fR variable to \fIeric,fred\fR, then you would be +able to communicate with both eric and fred's access points. Note that +this variable can be overridden using the \fI\-u\fR switch on the +\&\fIxpaget\fR, \fIxpaset\fR, and \fIxpainfo\fR programs. +.IP "\(bu" 4 +\&\fB\s-1XPA_PORT\s0\fR +.Sp +A semi-colon delimited list of user specified ports to use for specific +\&\s-1XPA\s0 access points. The format is each specification is: +.Sp +class:template port1[ port2] +.Sp +where \fBport1\fR is the main (command) port for the access point and +\&\fBport2\fR is the (secondary) data port. If port2 is not specified, +it defaults to a value of 0 (meaning the system assigns the port). +.Sp +Specification of specific ports is useful, for example, when a machine +outside a firewall needs to communicate with a machine inside a +firewall. In such a case, the firewall should be configured to allow +socket connections to both the command and data port from the outside +machine, and the inside \s-1XPA\s0 program should be started up with the +outside machine in its \s-1ACL\s0 list. Then, when the inside program is +started with specified ports, outside \s-1XPA\s0 programs can use +\&\*(L"machine:port\*(R" to contact the inside access points, instead of the +access point names. That is, the machine outside the firewall does not +need access to the \s-1XPA\s0 name server: +.Sp +export XPA_PORT=\*(L"DS9:ds9 12345 12346\*(R" # on machine \*(L"inside\*(R" +cat foo.fits | xpaset inside:12345 fits # on machine \*(L"outside\*(R" +.Sp +Note that 2 ports are required for full \s-1XPA\s0 communication and +therefore 2 ports should be specified to go through a firewall. The +second port assignment is not important if you simply are assigning +the command port in order to communicate commands with a known +port (e.g., to bypass the xpans name server). If only one (command) +port is specified, the system will negotiate a random data port and +everything will work properly. +.Sp +This support is somewhat experimental. If you run into problems, please +let us know. +.IP "\(bu" 4 +\&\fB\s-1XPA_PORTFILE\s0\fR +.Sp +A list of user-specified port to use for specific xpa access points. +The format of the file is: +.Sp +class:template port1 [port2] +.Sp +where \fBport1\fR is the main port for the access point and +\&\fBport2\fR is the data port. If port2 is not specified, it defaults +to a value of 0 (meaning the system assigns the port). See +\&\fB\s-1XPA_PORT\s0\fR above for an explanation of user-specified ports. +.IP "\(bu" 4 +\&\fB\s-1XPA_SHORT_TIMEOUT\s0\fR +.Sp +\&\s-1XPA\s0 is designed to allow data to be sent from one process to +another over a long period of time (i.e., a program that generates +image data sends that data to an image display, but slowly) but it +also seeks to prevent hangs. This is done by supporting 2 timeout +periods: a \fIshort\fR timeout for protocol communication +and a \fIlong\fR for data communication. +.Sp +The \fI\s-1XPA_SHORT_TIMEOUT\s0\fR variable +controls the \fIshort\fR timeout and is used to prevent hangs +in cases where the \s-1XPA\s0 protocol requires internal communication between +the client and server that is controlled by the \s-1XPA\s0 interface +itself. Authentication is an example of this sort of communication, +as is the establishment of a data channel between the two processes. +The default value for the \fIshort\fR is 30 seconds (which is +a pretty long time, actually). Setting the value to \-1 will disable +\&\fIshort\fR timeouts and allow an infinite amount of time. +.IP "\(bu" 4 +\&\fB\s-1XPA_SIGUSR1\s0\fR +.Sp +If the value of this variable is \fItrue\fR, then \s-1XPA\s0 will +catch \s-1SIGUSR1\s0 signals when performing an I/O operation in order to +curtail that operation. This facility allows users to send a \s-1SIGUSR1\s0 +signal to an \s-1XPA\s0 server if a client is hanging up the server by +sending or receiving data too slowly (timeouts also can be used \*(-- see +above). When enabled in this way, the \s-1SIGUSR1\s0 signal is ignored at all other +times, so that its safe to send the signal at any time. If the +variable is set to \fIfalse\fR, then \s-1SIGUSR1\s0 is not used at +all. Turning off \s-1SIGUSR1\s0 would be desired in cases there the program +uses \s-1SIGUSR1\s0 for some other reason and does not want \s-1XPA\s0 interfering. +The default is to use the signal. +.IP "\(bu" 4 +\&\fB\s-1XPA_TIMESTAMP_ERRORS\s0\fR +.Sp +If \fI\s-1XPA_TIMESTAMP_ERRORS\s0\fR is \fItrue\fR, then error +messages will include a date/time string. This can be useful when +\&\s-1XPA\s0 errors are being saved in an error log (e.g. Web/CGI use). The +default is false. +.IP "\(bu" 4 +\&\fB\s-1XPA_TMPDIR\s0\fR +.Sp +This variable specifies the directory into which \s-1XPA\s0 logs, Unix +socket files (when \fI\s-1XPA_METHOD\s0\fR is \fIlocal\fR), etc. are +stored. The default is \fI/tmp/.xpa\fR. +.IP "\(bu" 4 +\&\fB\s-1XPA_VERBOSITY\s0\fR +.Sp +Specify the verbosity level of error messages. If the value is +set to \fI0\fR, \fIfalse\fR, or \fIoff\fR, then no error +messages are printed to stderr. If the value is \fI1\fR, then +important \s-1XPA\s0 error messages will be output. If the value is +set to \fI2\fR, \s-1XPA\s0 warnings about out-of-sync messages will also +be output. These latter almost always can be ignored. +.IP "\(bu" 4 +\&\fB\s-1XPA_VERSIONCHECK\s0\fR +.Sp +Specify whether a new access point should check its major and minor \s-1XPA\s0 +version number against the version used by the xpans name server at +registration time. The default is \fItrue\fR. When checking is +performed, a warning is issued if the server major version is found to +be greater than the xpans version. Note that the check is performed +both by the \s-1XPA\s0 server and by the xpans process and warnings will be +issued by each. Also, instead of the values of \fItrue\fR or +\&\fIfalse\fR, you can give this variable an integer value n. In this +case, each version checking process (i.e., the XPA-enabled server or +xpans) will print out a maximum of n warning messages (after which +version warnings are silently swallowed). +.Sp +In general, it is a bad idea to run an XPA-enabled server program +using a version of \s-1XPA\s0 newer than the basic xpaset, xpaget, xpaaccess, +xpans programs. This sort of mismatch usually will not work due to +protocol changes. +.SH "SEE ALSO" +.IX Header "SEE ALSO" +See xpa(n) for a list of \s-1XPA\s0 help pages +.SH "POD ERRORS" +.IX Header "POD ERRORS" +Hey! \fBThe above document had some coding errors, which are explained below:\fR +.IP "Around line 458:" 4 +.IX Item "Around line 458:" +\&'=item' outside of any '=over' +.IP "Around line 509:" 4 +.IX Item "Around line 509:" +You forgot a '=back' before '=head1' diff --git a/xpa/man/mann/xpainet.n b/xpa/man/mann/xpainet.n new file mode 100644 index 0000000..4847654 --- /dev/null +++ b/xpa/man/mann/xpainet.n @@ -0,0 +1,396 @@ +.\" Automatically generated by Pod::Man 2.22 (Pod::Simple 3.13) +.\" +.\" Standard preamble: +.\" ======================================================================== +.de Sp \" Vertical space (when we can't use .PP) +.if t .sp .5v +.if n .sp +.. +.de Vb \" Begin verbatim text +.ft CW +.nf +.ne \\$1 +.. +.de Ve \" End verbatim text +.ft R +.fi +.. +.\" Set up some character translations and predefined strings. \*(-- will +.\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left +.\" double quote, and \*(R" will give a right double quote. \*(C+ will +.\" give a nicer C++. Capital omega is used to do unbreakable dashes and +.\" therefore won't be available. \*(C` and \*(C' expand to `' in nroff, +.\" nothing in troff, for use with C<>. +.tr \(*W- +.ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p' +.ie n \{\ +. ds -- \(*W- +. ds PI pi +. if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch +. if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch +. ds L" "" +. ds R" "" +. ds C` "" +. ds C' "" +'br\} +.el\{\ +. ds -- \|\(em\| +. ds PI \(*p +. ds L" `` +. ds R" '' +'br\} +.\" +.\" Escape single quotes in literal strings from groff's Unicode transform. +.ie \n(.g .ds Aq \(aq +.el .ds Aq ' +.\" +.\" If the F register is turned on, we'll generate index entries on stderr for +.\" titles (.TH), headers (.SH), subsections (.SS), items (.Ip), and index +.\" entries marked with X<> in POD. Of course, you'll have to process the +.\" output yourself in some meaningful fashion. +.ie \nF \{\ +. de IX +. tm Index:\\$1\t\\n%\t"\\$2" +.. +. nr % 0 +. rr F +.\} +.el \{\ +. de IX +.. +.\} +.\" +.\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2). +.\" Fear. Run. Save yourself. No user-serviceable parts. +. \" fudge factors for nroff and troff +.if n \{\ +. ds #H 0 +. ds #V .8m +. ds #F .3m +. ds #[ \f1 +. ds #] \fP +.\} +.if t \{\ +. ds #H ((1u-(\\\\n(.fu%2u))*.13m) +. ds #V .6m +. ds #F 0 +. ds #[ \& +. ds #] \& +.\} +. \" simple accents for nroff and troff +.if n \{\ +. ds ' \& +. ds ` \& +. ds ^ \& +. ds , \& +. ds ~ ~ +. ds / +.\} +.if t \{\ +. ds ' \\k:\h'-(\\n(.wu*8/10-\*(#H)'\'\h"|\\n:u" +. ds ` \\k:\h'-(\\n(.wu*8/10-\*(#H)'\`\h'|\\n:u' +. ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'^\h'|\\n:u' +. ds , \\k:\h'-(\\n(.wu*8/10)',\h'|\\n:u' +. ds ~ \\k:\h'-(\\n(.wu-\*(#H-.1m)'~\h'|\\n:u' +. ds / \\k:\h'-(\\n(.wu*8/10-\*(#H)'\z\(sl\h'|\\n:u' +.\} +. \" troff and (daisy-wheel) nroff accents +.ds : \\k:\h'-(\\n(.wu*8/10-\*(#H+.1m+\*(#F)'\v'-\*(#V'\z.\h'.2m+\*(#F'.\h'|\\n:u'\v'\*(#V' +.ds 8 \h'\*(#H'\(*b\h'-\*(#H' +.ds o \\k:\h'-(\\n(.wu+\w'\(de'u-\*(#H)/2u'\v'-.3n'\*(#[\z\(de\v'.3n'\h'|\\n:u'\*(#] +.ds d- \h'\*(#H'\(pd\h'-\w'~'u'\v'-.25m'\f2\(hy\fP\v'.25m'\h'-\*(#H' +.ds D- D\\k:\h'-\w'D'u'\v'-.11m'\z\(hy\v'.11m'\h'|\\n:u' +.ds th \*(#[\v'.3m'\s+1I\s-1\v'-.3m'\h'-(\w'I'u*2/3)'\s-1o\s+1\*(#] +.ds Th \*(#[\s+2I\s-2\h'-\w'I'u*3/5'\v'-.3m'o\v'.3m'\*(#] +.ds ae a\h'-(\w'a'u*4/10)'e +.ds Ae A\h'-(\w'A'u*4/10)'E +. \" corrections for vroff +.if v .ds ~ \\k:\h'-(\\n(.wu*9/10-\*(#H)'\s-2\u~\d\s+2\h'|\\n:u' +.if v .ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'\v'-.4m'^\v'.4m'\h'|\\n:u' +. \" for low resolution devices (crt and lpr) +.if \n(.H>23 .if \n(.V>19 \ +\{\ +. ds : e +. ds 8 ss +. ds o a +. ds d- d\h'-1'\(ga +. ds D- D\h'-1'\(hy +. ds th \o'bp' +. ds Th \o'LP' +. ds ae ae +. ds Ae AE +.\} +.rm #[ #] #H #V #F C +.\" ======================================================================== +.\" +.IX Title "xpainet n" +.TH xpainet n "July 23, 2013" "version 2.1.15" "SAORD Documentation" +.\" For nroff, turn off justification. Always turn off hyphenation; it makes +.\" way too many mistakes in technical documents. +.if n .ad l +.nh +.SH "NAME" +\&\fBXPAInet: \s-1XPA\s0 Communication Between Hosts\fR +.SH "SYNOPSIS" +.IX Header "SYNOPSIS" +\&\s-1XPA\s0 uses standard inet sockets to support communication between two or +more host computers. +.SH "DESCRIPTION" +.IX Header "DESCRIPTION" +When the Communication Method is set to +\&\fBinet\fR (as it is by default), \s-1XPA\s0 can be used to communicate +between different computers on the Internet. \s-1INET\s0 sockets utilize the +\&\s-1IP\s0 address of the given machine and a (usually random) port number to +communicate between processes on the same machine or between different +machines on the Internet. These standard Internet sockets are also +used by programs such as Netscape, ftp. etc. +.PP +\&\s-1XPA\s0 supports a host-based Access Control mechanism +to prevent unauthorized access of \s-1XPA\s0 access points by other computers +on the Net. By default, only the machine on which the \s-1XPA\s0 server is +running can access \s-1XPA\s0 services. Therefore, setting up communication +between a local \s-1XPA\s0 server machine and a remote client machine +requires a two-part registration process: +.IP "\(bu" 4 +the \s-1XPA\s0 service on the local machine must be made known to the +remote machine +.IP "\(bu" 4 +the remote machine must be given permission to access the local +\&\s-1XPA\s0 service +.PP +Three methods by which this remote registration can be accomplished +are described below. +.PP +\&\fBManual Registration\fR +.PP +The first method is the most basic and does not require the remote +client to have xpans running. To use it, the local server simply +gives a remote client machine access to one or more \s-1XPA\s0 access points +using xpaset and the \fB\-acl\fR sub-command. For example, +consider the \s-1XPA\s0 test program \*(L"stest\*(R" running on a local machine. By +default the access control for the access point named \*(L"xpa\*(R" is +restricted to that machine: +.PP +.Vb 3 +\& [sh]$ xpaget xpa \-acl +\& *:* 123.456.78.910 gisa +\& *:* localhost gisa +.Ve +.PP +Using xpaset and the \fB\-acl\fR sub-command, a remote client +machine can be given permission to perform xpaget, xpaset, xpaaccess, +or xpainfo operations. For example, to allow the xpaget operation, the +following command can be issued on the local machine: +.PP +.Vb 1 +\& [sh]$ xpaset \-p xpa \-acl "remote_machine g" +.Ve +.PP +This results in the following access permissions on the local machine: +.PP +.Vb 4 +\& [sh]$ xpaget xpa \-acl +\& XPA:xpa 234.567.89.012 g +\& *:* 123.456.78.910 gisa +\& *:* localhost gisa +.Ve +.PP +The remote client can now use the local server's xpans name server to +establish communication with the local \s-1XPA\s0 service. This can be done +on a call-by-call basis using the \fB\-i\fR switch on xpaset, xpaget, etc: +.PP +.Vb 6 +\& [sh]$ xpaget \-i "local_machine:12345" xpa +\& class: XPA +\& name: xpa +\& method: 88877766:2778 +\& sendian: little +\& cendian: big +.Ve +.PP +Alternatively, the \s-1XPA_NSINET\s0 variable on the remote machine can be +set to point directly to xpans on the local machine, removing +the need to override this value each time an \s-1XPA\s0 program is run: +.PP +.Vb 7 +\& [csh]$ setenv XPA_NSINET \*(Aqkarapet:$port\*(Aq +\& [csh]$ xpaget xpa +\& class: XPA +\& name: xpa +\& method: 88877766:2778 +\& sendian: little +\& cendian: big +.Ve +.PP +Here, '$port' means to use the default \s-1XPA\s0 name service port (14285). +not a port environment variable. +.PP +Access permission for remote client machines can be stored in a file +on the local machine pointed to by the \fB\s-1XPA_ACLFILE\s0\fR environment +variable or using the \fB\s-1XPA_DEFACL\s0\fR environment variable. See <A +HREF=\*(L"./acl.html\*(R">\s-1XPA\s0 Access Control for more information. +.PP +\&\fBRemote Registration\fR +.PP +If xpans is running on the remote client machine, then a local xpaset +command can be used with the \fB\-remote\fR sub-command to +register the local \s-1XPA\s0 service in the remote name service, while at +the same time giving the remote machine permission to access the local +service. For example, assume again that \*(L"stest\*(R" is running on the +local machine and that xpans is also running on the remote machine. +To register access of this local xpa on the remote machine, use +the xpaset and the \fB\-remote\fR sub-command: +.PP +.Vb 1 +\& [sh]$ ./xpaset \-p xpa \-remote \*(Aqremote_machine:$port\*(Aq + +.Ve +.PP +To register the local xpa access point on the remote machine with xpaget +access only, execute: +.PP +.Vb 1 +\& [sh]$ ./xpaset \-p xpa \-remote \*(Aqremote_machine:$port\*(Aq g +.Ve +.PP +Once the remote registration command is executed, the remote client +machine will have an entry such as the following in its own xpans name +service: +.PP +.Vb 2 +\& [csh]$ xpaget xpans +\& XPA xpa gs 88877766:2839 eric +.Ve +.PP +The xpa access point can now be utilized on the remote machine without +further setup: +.PP +.Vb 6 +\& [csh]$ xpaget xpa +\& class: XPA +\& name: xpa +\& method: 838e2f68:2839 +\& sendian: little +\& cendian: big +.Ve +.PP +To unregister remote access from the local machine, use the same +command but with a '\-' argument: +.PP +.Vb 1 +\& [sh]$ xpaset \-p xpa \-remote \*(Aqremote_machine:$port\*(Aq \- +.Ve +.PP +The benefit of using remote registration is that communication with +remote access points can be mixed with that of other access points +on the remote machine. Using Access Point +Names and Templates, one \s-1XPA\s0 command can be used to send or +receive messages to the remote and local services. +.PP +\&\fB\s-1XPANS\s0 Proxy Registration\fR +.PP +The two methods described above are useful when the local and remote +machines are able to communicate freely to one another. This would be +the case on most Local Area Networks (LANs) where all machines are +behind the same firewall and there is no port blocking between +machines on the same \s-1LAN\s0. The situation is more complicated when the +\&\s-1XPA\s0 server is behind a firewall, where outgoing connections are +allowed, but incoming port blocking is implemented to prevent machines +outside the firewall from connecting to machines inside the +firewall. Such incoming port blocking will prevent xpaset and xpaget +from connecting to an \s-1XPA\s0 server inside a firewall. +.PP +To allow locally fire-walled \s-1XPA\s0 services to register with remote +machines, we have implemented a proxy service within the xpans name +server. To register remote proxy service, xpaset and the +\&\fB\-remote\fR sub-command is again used, but with an additional +\&\fB\-proxy\fR argument added to the end of the command: +.PP +.Vb 1 +\& [sh]$ ./xpaset \-p xpa \-remote \*(Aqremote_machine:$port\*(Aq g \-proxy +.Ve +.PP +Once a remote proxy registration command is executed, the remote +machine will have an entry such as the following in its own xpans name +service: +.PP +.Vb 2 +\& [csh]$ xpaget xpans +\& XPA xpa gs @88877766:2839 eric +.Ve +.PP +The '@' sign in the name service entry indicates that xpans proxy +processing is being used for this access point. Other than that, from +the user's point of view, there is no difference in how this \s-1XPA\s0 +access point is contacted using \s-1XPA\s0 programs (xpaset, xpaget, etc.) or +libraries: +.PP +.Vb 6 +\& [csh]$ xpaget xpa +\& class: XPA +\& name: xpa +\& method: 88877766:3053 +\& sendian: little +\& cendian: big +.Ve +.PP +Of course, the underlying processing of the \s-1XPA\s0 requests is very much +different when xpans proxy is involved. Instead of an \s-1XPA\s0 program such +contacting the \s-1XPA\s0 service directly, it contacts the local xpans. +Acting as a proxy server, xpans communicates with the \s-1XPA\s0 service +using the command channel established at registration time. Commands +(including establishing a new data channel) are sent between xpans and +the \s-1XPA\s0 service to set up a new message transfer, and then data is fed +to/from the xpa request, through xpans, from/to the \s-1XPA\s0 service. In +this way, it can be arranged so that connections between the +fire-walled \s-1XPA\s0 service and the remote client are always initiated by +the \s-1XPA\s0 service itself. Thus, incoming connections that would be +blocked by the firewall are avoided. Note that there is a performance +penalty for using the xpans/proxy service. Aside from extra overhead +to set up proxy communication, all data must be sent through the +intermediate proxy process. +.PP +The xpans proxy scheme requires that the remote client allow the local +\&\s-1XPA\s0 server machine to connect to the remote xpans/proxy server. If the +remote client machine also is behind a port-blocking firewall, such +connections will be disallowed. In this case, the only solution is to +open up some ports on the remote client machine to allow incoming +connections to xpans/proxy. Two ports must be opened (for command and +data channel connections). By default, these two ports are 14285 and +14287. The port numbers can be changed using the \fB\s-1XPA_NSINET\s0\fR +environment variable. This variable takes the form: +.PP +.Vb 1 +\& setenv XPA_NSINET machine:port1[,port2[,port3]] +.Ve +.PP +where port1 is the main connecting port, port2 is the \s-1XPA\s0 access port, +and port3 is the secondary data connecting port. The second and third +ports are optional and default to port1+1 and port1+2, respectively. +It is port1 and port3 that must be left open for incoming connections. +.PP +For example, to change the port assignments so that xpans listens +for registration commands on port 12345 and data commands on port 28573: +.PP +.Vb 1 +\& setenv XPA_NSINET myhost:12345 +.Ve +.PP +Alternatively, all three ports can be assigned explicitly: +.PP +.Vb 1 +\& setenv XPA_NSINET remote:12345,3000,12346 +.Ve +.PP +In this case 12345 and 12346 should be open for incoming connections. +The \s-1XPA\s0 access port (which need not be open to the outside +world) is set to 3000. +.PP +Finally, note that we currently have no mechanism to cope with +Internet proxy servers (such as \s-1SOCKS\s0 servers). If an \s-1XPA\s0 service is +running on a machine that cannot connect directly to outside machines, +but goes through a proxy server instead, there currently is no way to +register that \s-1XPA\s0 service with a remote machine. We hope to implement +support for \s-1SOCKS\s0 proxy in a future release. +.SH "SEE ALSO" +.IX Header "SEE ALSO" +See xpa(n) for a list of \s-1XPA\s0 help pages diff --git a/xpa/man/mann/xpaintro.n b/xpa/man/mann/xpaintro.n new file mode 100644 index 0000000..2978e6b --- /dev/null +++ b/xpa/man/mann/xpaintro.n @@ -0,0 +1,250 @@ +.\" Automatically generated by Pod::Man 2.22 (Pod::Simple 3.13) +.\" +.\" Standard preamble: +.\" ======================================================================== +.de Sp \" Vertical space (when we can't use .PP) +.if t .sp .5v +.if n .sp +.. +.de Vb \" Begin verbatim text +.ft CW +.nf +.ne \\$1 +.. +.de Ve \" End verbatim text +.ft R +.fi +.. +.\" Set up some character translations and predefined strings. \*(-- will +.\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left +.\" double quote, and \*(R" will give a right double quote. \*(C+ will +.\" give a nicer C++. Capital omega is used to do unbreakable dashes and +.\" therefore won't be available. \*(C` and \*(C' expand to `' in nroff, +.\" nothing in troff, for use with C<>. +.tr \(*W- +.ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p' +.ie n \{\ +. ds -- \(*W- +. ds PI pi +. if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch +. if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch +. ds L" "" +. ds R" "" +. ds C` "" +. ds C' "" +'br\} +.el\{\ +. ds -- \|\(em\| +. ds PI \(*p +. ds L" `` +. ds R" '' +'br\} +.\" +.\" Escape single quotes in literal strings from groff's Unicode transform. +.ie \n(.g .ds Aq \(aq +.el .ds Aq ' +.\" +.\" If the F register is turned on, we'll generate index entries on stderr for +.\" titles (.TH), headers (.SH), subsections (.SS), items (.Ip), and index +.\" entries marked with X<> in POD. Of course, you'll have to process the +.\" output yourself in some meaningful fashion. +.ie \nF \{\ +. de IX +. tm Index:\\$1\t\\n%\t"\\$2" +.. +. nr % 0 +. rr F +.\} +.el \{\ +. de IX +.. +.\} +.\" +.\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2). +.\" Fear. Run. Save yourself. No user-serviceable parts. +. \" fudge factors for nroff and troff +.if n \{\ +. ds #H 0 +. ds #V .8m +. ds #F .3m +. ds #[ \f1 +. ds #] \fP +.\} +.if t \{\ +. ds #H ((1u-(\\\\n(.fu%2u))*.13m) +. ds #V .6m +. ds #F 0 +. ds #[ \& +. ds #] \& +.\} +. \" simple accents for nroff and troff +.if n \{\ +. ds ' \& +. ds ` \& +. ds ^ \& +. ds , \& +. ds ~ ~ +. ds / +.\} +.if t \{\ +. ds ' \\k:\h'-(\\n(.wu*8/10-\*(#H)'\'\h"|\\n:u" +. ds ` \\k:\h'-(\\n(.wu*8/10-\*(#H)'\`\h'|\\n:u' +. ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'^\h'|\\n:u' +. ds , \\k:\h'-(\\n(.wu*8/10)',\h'|\\n:u' +. ds ~ \\k:\h'-(\\n(.wu-\*(#H-.1m)'~\h'|\\n:u' +. ds / \\k:\h'-(\\n(.wu*8/10-\*(#H)'\z\(sl\h'|\\n:u' +.\} +. \" troff and (daisy-wheel) nroff accents +.ds : \\k:\h'-(\\n(.wu*8/10-\*(#H+.1m+\*(#F)'\v'-\*(#V'\z.\h'.2m+\*(#F'.\h'|\\n:u'\v'\*(#V' +.ds 8 \h'\*(#H'\(*b\h'-\*(#H' +.ds o \\k:\h'-(\\n(.wu+\w'\(de'u-\*(#H)/2u'\v'-.3n'\*(#[\z\(de\v'.3n'\h'|\\n:u'\*(#] +.ds d- \h'\*(#H'\(pd\h'-\w'~'u'\v'-.25m'\f2\(hy\fP\v'.25m'\h'-\*(#H' +.ds D- D\\k:\h'-\w'D'u'\v'-.11m'\z\(hy\v'.11m'\h'|\\n:u' +.ds th \*(#[\v'.3m'\s+1I\s-1\v'-.3m'\h'-(\w'I'u*2/3)'\s-1o\s+1\*(#] +.ds Th \*(#[\s+2I\s-2\h'-\w'I'u*3/5'\v'-.3m'o\v'.3m'\*(#] +.ds ae a\h'-(\w'a'u*4/10)'e +.ds Ae A\h'-(\w'A'u*4/10)'E +. \" corrections for vroff +.if v .ds ~ \\k:\h'-(\\n(.wu*9/10-\*(#H)'\s-2\u~\d\s+2\h'|\\n:u' +.if v .ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'\v'-.4m'^\v'.4m'\h'|\\n:u' +. \" for low resolution devices (crt and lpr) +.if \n(.H>23 .if \n(.V>19 \ +\{\ +. ds : e +. ds 8 ss +. ds o a +. ds d- d\h'-1'\(ga +. ds D- D\h'-1'\(hy +. ds th \o'bp' +. ds Th \o'LP' +. ds ae ae +. ds Ae AE +.\} +.rm #[ #] #H #V #F C +.\" ======================================================================== +.\" +.IX Title "xpaintro n" +.TH xpaintro n "July 23, 2013" "version 2.1.15" "SAORD Documentation" +.\" For nroff, turn off justification. Always turn off hyphenation; it makes +.\" way too many mistakes in technical documents. +.if n .ad l +.nh +.SH "NAME" +\&\fBXPAIntro: Introduction to the \s-1XPA\s0 Messaging System\fR +.SH "SYNOPSIS" +.IX Header "SYNOPSIS" +A brief introduction to the \s-1XPA\s0 messaging system, which provides +seamless communication between all kinds of Unix event-driven +programs, including X programs, Tcl/Tk programs, and Perl programs. +.SH "DESCRIPTION" +.IX Header "DESCRIPTION" +The \s-1XPA\s0 messaging system provides seamless communication between all +kinds of Unix programs, including X programs, Tcl/Tk programs, and +Perl programs. It also provides an easy way for users to communicate +with these XPA-enabled programs by executing \s-1XPA\s0 client commands in +the shell or by utilizing such commands in scripts. Because \s-1XPA\s0 works +both at the programming level and the shell level, it is a powerful +tool for unifying any analysis environment: users and programmers have +great flexibility in choosing the best level or levels at which to +access \s-1XPA\s0 services, and client access can be extended or modified +easily at any time. +.PP +A program becomes an XPA-enabled server by defining named points of +public access through which data and commands can be exchanged with +other client programs (and users). Using standard \s-1TCP\s0 sockets as +a transport mechanism, \s-1XPA\s0 supports both single-point and broadcast +messaging to and from these servers. It supports direct communication +between clients and servers, or indirect communication via an +intermediate message bus emulation program. Host-based access control +is implemented, as is as the ability to communicate with \s-1XPA\s0 servers +across a network. +.PP +\&\s-1XPA\s0 implements a layered interface that is designed to be useful both +to software developers and to users. The interface consists of a +library of \s-1XPA\s0 client and server routines for use in programs and a +suite of high-level user programs built on top of these libraries. +Using the \s-1XPA\s0 library, access points can be added to +Tcl/Tk +programs, +Xt +programs, or to Unix programs that use the \s-1XPA\s0 event loop or any +event loop based on \fIselect()\fR. Client access subroutines can be added +to any Tcl/Tk or Unix program. Client access also is supported at the +command line via a suite of high-level programs. +.PP +The major components of the \s-1XPA\s0 layered interface are: +.IP "\(bu" 4 +A set of \s-1XPA\s0 server routines, centered on +\&\fIXPANew()\fR, +which are used by \s-1XPA\s0 server programs to tag public access points with +string identifiers and to register send and receive callbacks for +these access points. +.IP "\(bu" 4 +A set of \s-1XPA\s0 client routines, centered on the +\&\fIXPASet()\fR +and +\&\fIXPAGet()\fR, +which are used by external client applications to exchange data and +commands with an \s-1XPA\s0 server. +.IP "\(bu" 4 +High-level programs, centered on +xpaset +and +xpaget, +which allow data +and information to be exchanged with \s-1XPA\s0 server programs from the +command line and from scripts. These programs have the command syntax: +.Sp +.Vb 2 +\& [data] | xpaset [qualifiers ...] +\& xpaget [qualifiers ...] +.Ve +.IP "\(bu" 4 +An \s-1XPA\s0 name server program, +xpans, +through which \s-1XPA\s0 access point names are +registered by servers and distributed to clients. +.PP +Defining an \s-1XPA\s0 access point is easy: a server application calls +\&\fIXPANew()\fR, +\&\fIXPACmdNew()\fR, +or the experimental +\&\fIXPAInfoNew()\fR +routine to +create a named public access point. An \s-1XPA\s0 service can specify \*(L"send\*(R" +and \*(L"receive\*(R" callback procedures (or an \*(L"info\*(R" procedure in the case +of \fIXPAInfoNew()\fR) to be executed by the program when an external +process either sends data or commands to this access point or requests +data or information from this access point. Either of the callbacks +can be omitted, so that a particular access point can be specified as +read-only, read-write, or write-only. Application-specific client +data can be associated with these callbacks. Having defined one or +more public access points in this way, an \s-1XPA\s0 server program enters +its usual event loop (or uses the standard \s-1XPA\s0 event loop). +.PP +Clients communicate with these \s-1XPA\s0 public access points +using programs such as +xpaget, +xpaset, and +xpainfo +(at the command line), +or routines such as +\&\fIXPAGet()\fR, +\&\fIXPASet()\fR, +and +\&\fIXPAInfo()\fR +within a program. Both methods require specification of the name of +the access point. The xpaget program returns data or other +information from an \s-1XPA\s0 server to its standard output, while the +xpaset program sends data or commands from its standard input to an +\&\s-1XPA\s0 application. The corresponding \s-1API\s0 routines set/get data to/from +memory, returning error messages and other info as needed. If a +template +is used to specify the access point name (e.g., \*(L"ds9*\*(R"), then +communication will take place with all servers matching that template. +.PP +Please note that \s-1XPA\s0 currently is not thread-safe. All \s-1XPA\s0 calls must be +in the same thread. +.SH "SEE ALSO" +.IX Header "SEE ALSO" +See xpa(n) for a list of \s-1XPA\s0 help pages diff --git a/xpa/man/mann/xpamethod.n b/xpa/man/mann/xpamethod.n new file mode 100644 index 0000000..faecd86 --- /dev/null +++ b/xpa/man/mann/xpamethod.n @@ -0,0 +1,200 @@ +.\" Automatically generated by Pod::Man 2.22 (Pod::Simple 3.13) +.\" +.\" Standard preamble: +.\" ======================================================================== +.de Sp \" Vertical space (when we can't use .PP) +.if t .sp .5v +.if n .sp +.. +.de Vb \" Begin verbatim text +.ft CW +.nf +.ne \\$1 +.. +.de Ve \" End verbatim text +.ft R +.fi +.. +.\" Set up some character translations and predefined strings. \*(-- will +.\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left +.\" double quote, and \*(R" will give a right double quote. \*(C+ will +.\" give a nicer C++. Capital omega is used to do unbreakable dashes and +.\" therefore won't be available. \*(C` and \*(C' expand to `' in nroff, +.\" nothing in troff, for use with C<>. +.tr \(*W- +.ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p' +.ie n \{\ +. ds -- \(*W- +. ds PI pi +. if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch +. if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch +. ds L" "" +. ds R" "" +. ds C` "" +. ds C' "" +'br\} +.el\{\ +. ds -- \|\(em\| +. ds PI \(*p +. ds L" `` +. ds R" '' +'br\} +.\" +.\" Escape single quotes in literal strings from groff's Unicode transform. +.ie \n(.g .ds Aq \(aq +.el .ds Aq ' +.\" +.\" If the F register is turned on, we'll generate index entries on stderr for +.\" titles (.TH), headers (.SH), subsections (.SS), items (.Ip), and index +.\" entries marked with X<> in POD. Of course, you'll have to process the +.\" output yourself in some meaningful fashion. +.ie \nF \{\ +. de IX +. tm Index:\\$1\t\\n%\t"\\$2" +.. +. nr % 0 +. rr F +.\} +.el \{\ +. de IX +.. +.\} +.\" +.\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2). +.\" Fear. Run. Save yourself. No user-serviceable parts. +. \" fudge factors for nroff and troff +.if n \{\ +. ds #H 0 +. ds #V .8m +. ds #F .3m +. ds #[ \f1 +. ds #] \fP +.\} +.if t \{\ +. ds #H ((1u-(\\\\n(.fu%2u))*.13m) +. ds #V .6m +. ds #F 0 +. ds #[ \& +. ds #] \& +.\} +. \" simple accents for nroff and troff +.if n \{\ +. ds ' \& +. ds ` \& +. ds ^ \& +. ds , \& +. ds ~ ~ +. ds / +.\} +.if t \{\ +. ds ' \\k:\h'-(\\n(.wu*8/10-\*(#H)'\'\h"|\\n:u" +. ds ` \\k:\h'-(\\n(.wu*8/10-\*(#H)'\`\h'|\\n:u' +. ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'^\h'|\\n:u' +. ds , \\k:\h'-(\\n(.wu*8/10)',\h'|\\n:u' +. ds ~ \\k:\h'-(\\n(.wu-\*(#H-.1m)'~\h'|\\n:u' +. ds / \\k:\h'-(\\n(.wu*8/10-\*(#H)'\z\(sl\h'|\\n:u' +.\} +. \" troff and (daisy-wheel) nroff accents +.ds : \\k:\h'-(\\n(.wu*8/10-\*(#H+.1m+\*(#F)'\v'-\*(#V'\z.\h'.2m+\*(#F'.\h'|\\n:u'\v'\*(#V' +.ds 8 \h'\*(#H'\(*b\h'-\*(#H' +.ds o \\k:\h'-(\\n(.wu+\w'\(de'u-\*(#H)/2u'\v'-.3n'\*(#[\z\(de\v'.3n'\h'|\\n:u'\*(#] +.ds d- \h'\*(#H'\(pd\h'-\w'~'u'\v'-.25m'\f2\(hy\fP\v'.25m'\h'-\*(#H' +.ds D- D\\k:\h'-\w'D'u'\v'-.11m'\z\(hy\v'.11m'\h'|\\n:u' +.ds th \*(#[\v'.3m'\s+1I\s-1\v'-.3m'\h'-(\w'I'u*2/3)'\s-1o\s+1\*(#] +.ds Th \*(#[\s+2I\s-2\h'-\w'I'u*3/5'\v'-.3m'o\v'.3m'\*(#] +.ds ae a\h'-(\w'a'u*4/10)'e +.ds Ae A\h'-(\w'A'u*4/10)'E +. \" corrections for vroff +.if v .ds ~ \\k:\h'-(\\n(.wu*9/10-\*(#H)'\s-2\u~\d\s+2\h'|\\n:u' +.if v .ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'\v'-.4m'^\v'.4m'\h'|\\n:u' +. \" for low resolution devices (crt and lpr) +.if \n(.H>23 .if \n(.V>19 \ +\{\ +. ds : e +. ds 8 ss +. ds o a +. ds d- d\h'-1'\(ga +. ds D- D\h'-1'\(hy +. ds th \o'bp' +. ds Th \o'LP' +. ds ae ae +. ds Ae AE +.\} +.rm #[ #] #H #V #F C +.\" ======================================================================== +.\" +.IX Title "xpamethod n" +.TH xpamethod n "July 23, 2013" "version 2.1.15" "SAORD Documentation" +.\" For nroff, turn off justification. Always turn off hyphenation; it makes +.\" way too many mistakes in technical documents. +.if n .ad l +.nh +.SH "NAME" +\&\fBXPAMethod: \s-1XPA\s0 Communication Methods\fR +.SH "SYNOPSIS" +.IX Header "SYNOPSIS" +\&\s-1XPA\s0 supports both inet and unix (local) socket communication. +.SH "DESCRIPTION" +.IX Header "DESCRIPTION" +\&\s-1XPA\s0 uses sockets for communication between processes. It supports +three methods of socket communication: inet, localhost, and unix. In +general, the same method should be employed for all \s-1XPA\s0 processes in a +session and the global environment variable \s-1XPA_METHOD\s0 should be used +to set up the desired method. By default, the preferred method is +\&\*(L"inet\*(R", which is appropriate for most users. You can set up a +different method by typing something like: +.PP +.Vb 3 +\& setenv XPA_METHOD local # unix csh +\& XPA_METHOD=local; export XPA_METHOD # unix sh, bash, windows/cygwin +\& set XPA_METHOD=localhost # dos/windows +.Ve +.PP +The options for \s-1XPA_METHOD\s0 are: \fBinet\fR, \fBunix\fR (or +\&\fBlocal\fR), and \fBlocalhost\fR. On Unix machines, this +environment setup command can be placed in your shell init file +(.cshrc, .profile, .bashrc, etc.) On Windows platforms, it can be +placed in your \s-1AUTOEXEC\s0.BAT file (I think!). +.PP +By default, \fBinet\fR sockets are used by \s-1XPA\s0. These are the standard +Internet sockets that are used by programs such as Netscape, +ftp. etc. Inet sockets utilize the \s-1IP\s0 address of the given machine and +a (usually random) port number to communicate between processes on the +same machine or between different machines on the Internet. (Note that +\&\s-1XPA\s0 has an Access Control mechanism to +prevent unauthorized access of \s-1XPA\s0 access points by other computers on +the Net). For users connected to the Internet, this usually is the +appropriate communication method. For more information about setting +up \s-1XPA\s0 communication between machines, see +Communication Between Machines. +.PP +In you are using \s-1XPA\s0 on a machine without an Internet connection, then +inet sockets are not appropriate. In fact, an \s-1XPA\s0 process often will +hang for many seconds while waiting for a response from the Domain +Name Service (\s-1DNS\s0) when using inet sockets. Instead of inet sockets, +users on Unix platforms can also use \fBunix\fR sockets (also known +as local sockets). These sockets are based on the local file system +and do not make use of the \s-1DNS\s0. They generally are considered to be +faster than inet sockets, but they are not implemented under +Windows. Use local sockets as a first resort if you are on a Unix +machine that is not connected to the Internet. +.PP +Users not connected to the Internet also can use \fBlocalhost\fR +sockets. These are also inet-type sockets but the \s-1IP\s0 address used for +the local machine is the \fBlocalhost\fR address, 0x7F000001, instead +of the real \s-1IP\s0 of the machine. Depending on how sockets are set up for +a given platform, communication with the \s-1DNS\s0 usually is not required in +this case (though of course, \s-1XPA\s0 cannot interact with other machines). +The localhost method will generally work on both Unix and Windows +platforms, but whether the \s-1DNS\s0 is required or not is subject to +individual configurations. +.PP +A final warning/reminder: if your XPA-enabled server hangs at startup +time and your \s-1XPA_METHOD\s0 is \fBinet\fR, the problem probably is +related to an incorrect Internet configuration. This can be confirmed +by using the \fBunix\fR method or (usually) the \fBlocalhost\fR +method. You can use these alternate methods if other hosts do not need +access to the \s-1XPA\s0 server. +.SH "SEE ALSO" +.IX Header "SEE ALSO" +See xpa(n) for a list of \s-1XPA\s0 help pages diff --git a/xpa/man/mann/xpaname.n b/xpa/man/mann/xpaname.n new file mode 100644 index 0000000..cdb6839 --- /dev/null +++ b/xpa/man/mann/xpaname.n @@ -0,0 +1,158 @@ +.\" Automatically generated by Pod::Man 2.22 (Pod::Simple 3.13) +.\" +.\" Standard preamble: +.\" ======================================================================== +.de Sp \" Vertical space (when we can't use .PP) +.if t .sp .5v +.if n .sp +.. +.de Vb \" Begin verbatim text +.ft CW +.nf +.ne \\$1 +.. +.de Ve \" End verbatim text +.ft R +.fi +.. +.\" Set up some character translations and predefined strings. \*(-- will +.\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left +.\" double quote, and \*(R" will give a right double quote. \*(C+ will +.\" give a nicer C++. Capital omega is used to do unbreakable dashes and +.\" therefore won't be available. \*(C` and \*(C' expand to `' in nroff, +.\" nothing in troff, for use with C<>. +.tr \(*W- +.ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p' +.ie n \{\ +. ds -- \(*W- +. ds PI pi +. if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch +. if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch +. ds L" "" +. ds R" "" +. ds C` "" +. ds C' "" +'br\} +.el\{\ +. ds -- \|\(em\| +. ds PI \(*p +. ds L" `` +. ds R" '' +'br\} +.\" +.\" Escape single quotes in literal strings from groff's Unicode transform. +.ie \n(.g .ds Aq \(aq +.el .ds Aq ' +.\" +.\" If the F register is turned on, we'll generate index entries on stderr for +.\" titles (.TH), headers (.SH), subsections (.SS), items (.Ip), and index +.\" entries marked with X<> in POD. Of course, you'll have to process the +.\" output yourself in some meaningful fashion. +.ie \nF \{\ +. de IX +. tm Index:\\$1\t\\n%\t"\\$2" +.. +. nr % 0 +. rr F +.\} +.el \{\ +. de IX +.. +.\} +.\" +.\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2). +.\" Fear. Run. Save yourself. No user-serviceable parts. +. \" fudge factors for nroff and troff +.if n \{\ +. ds #H 0 +. ds #V .8m +. ds #F .3m +. ds #[ \f1 +. ds #] \fP +.\} +.if t \{\ +. ds #H ((1u-(\\\\n(.fu%2u))*.13m) +. ds #V .6m +. ds #F 0 +. ds #[ \& +. ds #] \& +.\} +. \" simple accents for nroff and troff +.if n \{\ +. ds ' \& +. ds ` \& +. ds ^ \& +. ds , \& +. ds ~ ~ +. ds / +.\} +.if t \{\ +. ds ' \\k:\h'-(\\n(.wu*8/10-\*(#H)'\'\h"|\\n:u" +. ds ` \\k:\h'-(\\n(.wu*8/10-\*(#H)'\`\h'|\\n:u' +. ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'^\h'|\\n:u' +. ds , \\k:\h'-(\\n(.wu*8/10)',\h'|\\n:u' +. ds ~ \\k:\h'-(\\n(.wu-\*(#H-.1m)'~\h'|\\n:u' +. ds / \\k:\h'-(\\n(.wu*8/10-\*(#H)'\z\(sl\h'|\\n:u' +.\} +. \" troff and (daisy-wheel) nroff accents +.ds : \\k:\h'-(\\n(.wu*8/10-\*(#H+.1m+\*(#F)'\v'-\*(#V'\z.\h'.2m+\*(#F'.\h'|\\n:u'\v'\*(#V' +.ds 8 \h'\*(#H'\(*b\h'-\*(#H' +.ds o \\k:\h'-(\\n(.wu+\w'\(de'u-\*(#H)/2u'\v'-.3n'\*(#[\z\(de\v'.3n'\h'|\\n:u'\*(#] +.ds d- \h'\*(#H'\(pd\h'-\w'~'u'\v'-.25m'\f2\(hy\fP\v'.25m'\h'-\*(#H' +.ds D- D\\k:\h'-\w'D'u'\v'-.11m'\z\(hy\v'.11m'\h'|\\n:u' +.ds th \*(#[\v'.3m'\s+1I\s-1\v'-.3m'\h'-(\w'I'u*2/3)'\s-1o\s+1\*(#] +.ds Th \*(#[\s+2I\s-2\h'-\w'I'u*3/5'\v'-.3m'o\v'.3m'\*(#] +.ds ae a\h'-(\w'a'u*4/10)'e +.ds Ae A\h'-(\w'A'u*4/10)'E +. \" corrections for vroff +.if v .ds ~ \\k:\h'-(\\n(.wu*9/10-\*(#H)'\s-2\u~\d\s+2\h'|\\n:u' +.if v .ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'\v'-.4m'^\v'.4m'\h'|\\n:u' +. \" for low resolution devices (crt and lpr) +.if \n(.H>23 .if \n(.V>19 \ +\{\ +. ds : e +. ds 8 ss +. ds o a +. ds d- d\h'-1'\(ga +. ds D- D\h'-1'\(hy +. ds th \o'bp' +. ds Th \o'LP' +. ds ae ae +. ds Ae AE +.\} +.rm #[ #] #H #V #F C +.\" ======================================================================== +.\" +.IX Title "xpaname n" +.TH xpaname n "July 23, 2013" "version 2.1.15" "SAORD Documentation" +.\" For nroff, turn off justification. Always turn off hyphenation; it makes +.\" way too many mistakes in technical documents. +.if n .ad l +.nh +.SH "NAME" +\&\fBXPAName: What does \s-1XPA\s0 stand for?\fR +.SH "SYNOPSIS" +.IX Header "SYNOPSIS" +What does \s-1XPA\s0 stand for? Who knows anymore! +.SH "DESCRIPTION" +.IX Header "DESCRIPTION" +What does \s-1XPA\s0 stand for? Dunno! The \s-1XPA\s0 messaging system originally +was built on top of the X Window System and \s-1XPA\s0 was the mnemonic for +\&\fIX Public Access\fR, to emphasize that we were providing public +access to previously private data and algorithms in Xt programs. Now +that \s-1XPA\s0 no longer is tied to X, it can be argued that we ought to +change the name (how about \s-1SPAM:\s0 simple public access mechanism +), but \s-1XPA\s0 is in wide-spread use in the astronomical community of +its birth, and the name has taken on a life of its own. If anyone can +think of what \s-1XPA\s0 now means, please let us know. +.PP +If you think this is bad, consider the \s-1MMT\s0 Telescope on Mount Hopkins, +Arizona. When first installed twenty years ago, it featured an array +of six 72\-inch diameter mirrors. from which came its name: the +\&\fIMultiple Mirror Telescope\fR. In spring of 1999, these mirrors +were replaced by a single 21 and 1/2 \-foot diameter primary mirror, +the largest single-piece glass reflector on the North American +continent. And now \s-1MMT\s0 stands for ... \s-1MMT\s0! +.SH "SEE ALSO" +.IX Header "SEE ALSO" +See xpa(n) for a list of \s-1XPA\s0 help pages diff --git a/xpa/man/mann/xpaoom.n b/xpa/man/mann/xpaoom.n new file mode 100644 index 0000000..9dfdc3f --- /dev/null +++ b/xpa/man/mann/xpaoom.n @@ -0,0 +1,166 @@ +.\" Automatically generated by Pod::Man 2.22 (Pod::Simple 3.13) +.\" +.\" Standard preamble: +.\" ======================================================================== +.de Sp \" Vertical space (when we can't use .PP) +.if t .sp .5v +.if n .sp +.. +.de Vb \" Begin verbatim text +.ft CW +.nf +.ne \\$1 +.. +.de Ve \" End verbatim text +.ft R +.fi +.. +.\" Set up some character translations and predefined strings. \*(-- will +.\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left +.\" double quote, and \*(R" will give a right double quote. \*(C+ will +.\" give a nicer C++. Capital omega is used to do unbreakable dashes and +.\" therefore won't be available. \*(C` and \*(C' expand to `' in nroff, +.\" nothing in troff, for use with C<>. +.tr \(*W- +.ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p' +.ie n \{\ +. ds -- \(*W- +. ds PI pi +. if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch +. if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch +. ds L" "" +. ds R" "" +. ds C` "" +. ds C' "" +'br\} +.el\{\ +. ds -- \|\(em\| +. ds PI \(*p +. ds L" `` +. ds R" '' +'br\} +.\" +.\" Escape single quotes in literal strings from groff's Unicode transform. +.ie \n(.g .ds Aq \(aq +.el .ds Aq ' +.\" +.\" If the F register is turned on, we'll generate index entries on stderr for +.\" titles (.TH), headers (.SH), subsections (.SS), items (.Ip), and index +.\" entries marked with X<> in POD. Of course, you'll have to process the +.\" output yourself in some meaningful fashion. +.ie \nF \{\ +. de IX +. tm Index:\\$1\t\\n%\t"\\$2" +.. +. nr % 0 +. rr F +.\} +.el \{\ +. de IX +.. +.\} +.\" +.\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2). +.\" Fear. Run. Save yourself. No user-serviceable parts. +. \" fudge factors for nroff and troff +.if n \{\ +. ds #H 0 +. ds #V .8m +. ds #F .3m +. ds #[ \f1 +. ds #] \fP +.\} +.if t \{\ +. ds #H ((1u-(\\\\n(.fu%2u))*.13m) +. ds #V .6m +. ds #F 0 +. ds #[ \& +. ds #] \& +.\} +. \" simple accents for nroff and troff +.if n \{\ +. ds ' \& +. ds ` \& +. ds ^ \& +. ds , \& +. ds ~ ~ +. ds / +.\} +.if t \{\ +. ds ' \\k:\h'-(\\n(.wu*8/10-\*(#H)'\'\h"|\\n:u" +. ds ` \\k:\h'-(\\n(.wu*8/10-\*(#H)'\`\h'|\\n:u' +. ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'^\h'|\\n:u' +. ds , \\k:\h'-(\\n(.wu*8/10)',\h'|\\n:u' +. ds ~ \\k:\h'-(\\n(.wu-\*(#H-.1m)'~\h'|\\n:u' +. ds / \\k:\h'-(\\n(.wu*8/10-\*(#H)'\z\(sl\h'|\\n:u' +.\} +. \" troff and (daisy-wheel) nroff accents +.ds : \\k:\h'-(\\n(.wu*8/10-\*(#H+.1m+\*(#F)'\v'-\*(#V'\z.\h'.2m+\*(#F'.\h'|\\n:u'\v'\*(#V' +.ds 8 \h'\*(#H'\(*b\h'-\*(#H' +.ds o \\k:\h'-(\\n(.wu+\w'\(de'u-\*(#H)/2u'\v'-.3n'\*(#[\z\(de\v'.3n'\h'|\\n:u'\*(#] +.ds d- \h'\*(#H'\(pd\h'-\w'~'u'\v'-.25m'\f2\(hy\fP\v'.25m'\h'-\*(#H' +.ds D- D\\k:\h'-\w'D'u'\v'-.11m'\z\(hy\v'.11m'\h'|\\n:u' +.ds th \*(#[\v'.3m'\s+1I\s-1\v'-.3m'\h'-(\w'I'u*2/3)'\s-1o\s+1\*(#] +.ds Th \*(#[\s+2I\s-2\h'-\w'I'u*3/5'\v'-.3m'o\v'.3m'\*(#] +.ds ae a\h'-(\w'a'u*4/10)'e +.ds Ae A\h'-(\w'A'u*4/10)'E +. \" corrections for vroff +.if v .ds ~ \\k:\h'-(\\n(.wu*9/10-\*(#H)'\s-2\u~\d\s+2\h'|\\n:u' +.if v .ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'\v'-.4m'^\v'.4m'\h'|\\n:u' +. \" for low resolution devices (crt and lpr) +.if \n(.H>23 .if \n(.V>19 \ +\{\ +. ds : e +. ds 8 ss +. ds o a +. ds d- d\h'-1'\(ga +. ds D- D\h'-1'\(hy +. ds th \o'bp' +. ds Th \o'LP' +. ds ae ae +. ds Ae AE +.\} +.rm #[ #] #H #V #F C +.\" ======================================================================== +.\" +.IX Title "xpaoom n" +.TH xpaoom n "July 23, 2013" "version 2.1.15" "SAORD Documentation" +.\" For nroff, turn off justification. Always turn off hyphenation; it makes +.\" way too many mistakes in technical documents. +.if n .ad l +.nh +.SH "NAME" +\&\fBXpaoom: What happens when \s-1XPA\s0 runs out of memory?\fR +.SH "SYNOPSIS" +.IX Header "SYNOPSIS" +When \s-1XPA\s0 can't allocate memory, it exits. You can arrange to have it call +\&\fIlongjmp()\fR instead. +.SH "DESCRIPTION" +.IX Header "DESCRIPTION" +When an \s-1XPA\s0 server or client cannot allocate memory, it will attempt to +output an error message and then exit. If this is not satisfactory (e.g., +perhaps your program is interactive and can recover from \s-1OOM\s0 errors), you +can tell \s-1XPA\s0 to call \fIlongjmp()\fR to go to a recovery branch. To pass the +requisite jmp_buf variable to \s-1XPA\s0, make the following call: +.PP +.Vb 1 +\& XPASaveJmp(void *env); +.Ve +.PP +The value of env is the address of a jmp_buf variable that was previously +passed to \fIsetjmp()\fR. For example: +.PP +.Vb 9 +\& jmp_buf env; +\& ... +\& if( setjmp(jmp_buf) != 0 ){ +\& /* out of memory \-\- take corrective action, if possible */ +\& } else { +\& /* save env for XPA */ +\& XPASaveJmp((void *)&jmp_buf); +\& } +\& // enter main loop ... +.Ve +.SH "SEE ALSO" +.IX Header "SEE ALSO" +See xpa(n) for a list of \s-1XPA\s0 help pages diff --git a/xpa/man/mann/xpatcl.n b/xpa/man/mann/xpatcl.n new file mode 100644 index 0000000..9156d5e --- /dev/null +++ b/xpa/man/mann/xpatcl.n @@ -0,0 +1,362 @@ +.\" Automatically generated by Pod::Man 2.22 (Pod::Simple 3.13) +.\" +.\" Standard preamble: +.\" ======================================================================== +.de Sp \" Vertical space (when we can't use .PP) +.if t .sp .5v +.if n .sp +.. +.de Vb \" Begin verbatim text +.ft CW +.nf +.ne \\$1 +.. +.de Ve \" End verbatim text +.ft R +.fi +.. +.\" Set up some character translations and predefined strings. \*(-- will +.\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left +.\" double quote, and \*(R" will give a right double quote. \*(C+ will +.\" give a nicer C++. Capital omega is used to do unbreakable dashes and +.\" therefore won't be available. \*(C` and \*(C' expand to `' in nroff, +.\" nothing in troff, for use with C<>. +.tr \(*W- +.ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p' +.ie n \{\ +. ds -- \(*W- +. ds PI pi +. if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch +. if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch +. ds L" "" +. ds R" "" +. ds C` "" +. ds C' "" +'br\} +.el\{\ +. ds -- \|\(em\| +. ds PI \(*p +. ds L" `` +. ds R" '' +'br\} +.\" +.\" Escape single quotes in literal strings from groff's Unicode transform. +.ie \n(.g .ds Aq \(aq +.el .ds Aq ' +.\" +.\" If the F register is turned on, we'll generate index entries on stderr for +.\" titles (.TH), headers (.SH), subsections (.SS), items (.Ip), and index +.\" entries marked with X<> in POD. Of course, you'll have to process the +.\" output yourself in some meaningful fashion. +.ie \nF \{\ +. de IX +. tm Index:\\$1\t\\n%\t"\\$2" +.. +. nr % 0 +. rr F +.\} +.el \{\ +. de IX +.. +.\} +.\" +.\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2). +.\" Fear. Run. Save yourself. No user-serviceable parts. +. \" fudge factors for nroff and troff +.if n \{\ +. ds #H 0 +. ds #V .8m +. ds #F .3m +. ds #[ \f1 +. ds #] \fP +.\} +.if t \{\ +. ds #H ((1u-(\\\\n(.fu%2u))*.13m) +. ds #V .6m +. ds #F 0 +. ds #[ \& +. ds #] \& +.\} +. \" simple accents for nroff and troff +.if n \{\ +. ds ' \& +. ds ` \& +. ds ^ \& +. ds , \& +. ds ~ ~ +. ds / +.\} +.if t \{\ +. ds ' \\k:\h'-(\\n(.wu*8/10-\*(#H)'\'\h"|\\n:u" +. ds ` \\k:\h'-(\\n(.wu*8/10-\*(#H)'\`\h'|\\n:u' +. ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'^\h'|\\n:u' +. ds , \\k:\h'-(\\n(.wu*8/10)',\h'|\\n:u' +. ds ~ \\k:\h'-(\\n(.wu-\*(#H-.1m)'~\h'|\\n:u' +. ds / \\k:\h'-(\\n(.wu*8/10-\*(#H)'\z\(sl\h'|\\n:u' +.\} +. \" troff and (daisy-wheel) nroff accents +.ds : \\k:\h'-(\\n(.wu*8/10-\*(#H+.1m+\*(#F)'\v'-\*(#V'\z.\h'.2m+\*(#F'.\h'|\\n:u'\v'\*(#V' +.ds 8 \h'\*(#H'\(*b\h'-\*(#H' +.ds o \\k:\h'-(\\n(.wu+\w'\(de'u-\*(#H)/2u'\v'-.3n'\*(#[\z\(de\v'.3n'\h'|\\n:u'\*(#] +.ds d- \h'\*(#H'\(pd\h'-\w'~'u'\v'-.25m'\f2\(hy\fP\v'.25m'\h'-\*(#H' +.ds D- D\\k:\h'-\w'D'u'\v'-.11m'\z\(hy\v'.11m'\h'|\\n:u' +.ds th \*(#[\v'.3m'\s+1I\s-1\v'-.3m'\h'-(\w'I'u*2/3)'\s-1o\s+1\*(#] +.ds Th \*(#[\s+2I\s-2\h'-\w'I'u*3/5'\v'-.3m'o\v'.3m'\*(#] +.ds ae a\h'-(\w'a'u*4/10)'e +.ds Ae A\h'-(\w'A'u*4/10)'E +. \" corrections for vroff +.if v .ds ~ \\k:\h'-(\\n(.wu*9/10-\*(#H)'\s-2\u~\d\s+2\h'|\\n:u' +.if v .ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'\v'-.4m'^\v'.4m'\h'|\\n:u' +. \" for low resolution devices (crt and lpr) +.if \n(.H>23 .if \n(.V>19 \ +\{\ +. ds : e +. ds 8 ss +. ds o a +. ds d- d\h'-1'\(ga +. ds D- D\h'-1'\(hy +. ds th \o'bp' +. ds Th \o'LP' +. ds ae ae +. ds Ae AE +.\} +.rm #[ #] #H #V #F C +.\" ======================================================================== +.\" +.IX Title "xpatcl n" +.TH xpatcl n "July 23, 2013" "version 2.1.15" "SAORD Documentation" +.\" For nroff, turn off justification. Always turn off hyphenation; it makes +.\" way too many mistakes in technical documents. +.if n .ad l +.nh +.SH "NAME" +\&\fBXPATcl: the \s-1XPA\s0 Interface to the Tcl/Tk Environment\fR +.SH "SYNOPSIS" +.IX Header "SYNOPSIS" +Tcl/Tk programs can act as \s-1XPA\s0 clients and/or servers using the Tcl +interface to \s-1XPA\s0 that is contained in the libtclxpa.so shared object. +.PP +\&\fBServer Routines\fR +.PP +.Vb 11 +\& set xpa [xpanew class name help sproc sdata smode rproc rdata rmode] +\& xpafree xpa +\& set xpa [xpanew class name help iproc idata imode] +\& set xpa [xpacmdnew class name] +\& xpacmdadd xpa name help sproc sdata smode rproc rdata rmode +\& xpacmddel xpa cmd +\& set val [xparec xpa option] +\& options: name, class, method, cmdfd, datafd, cmdchan, datachan +\& xpasetbuf xpa buf len +\& xpaerror xpa message +\& xpamessage xpa message +.Ve +.PP +\&\fBClient Routines\fR +.PP +.Vb 11 +\& set xpa [xpaopen mode] +\& xpaclose xpa +\& set got [xpaget xpa template paramlist mode bufs lens names errs n] +\& set got [xpaget xpa template paramlist mode chans names errs n] +\& set got [xpaset xpa template paramlist mode buf len names errs n] +\& set got [xpasetfd xpa template paramlist mode chan names errs n] +\& set got [xpainfo xpa template paramlist mode names errs n] +\& # NB: 2.1 calling sequence change +\& # set got [xpaaccess template type] (2.0.5) +\& set got [xpaaccess xpa template paramlist mode names errs n] +\& set got [xpanslookup template type classes names methods] +.Ve +.SH "DESCRIPTION" +.IX Header "DESCRIPTION" +You can call \fIXPANew()\fR, \fIXPACmdNew()\fR, or \fIXPAInfoNew()\fR within a C +routine to add C\-based \s-1XPA\s0 server callbacks to a TCL/Tk program that +uses a Tcl/Tk event loop (either \fIvwait()\fR or the Tk event loop); +Such a program does not need or want to use the \s-1XPA\s0 event loop. +Therefore, in order to add \s-1XPA\s0 access points to the Tcl/Tk loop, the +following routine should be called beforehand: +.PP +.Vb 1 +\& int XPATclAddInput(XPA xpa); +.Ve +.PP +Normally, the xpa argument is \s-1NULL\s0, meaning that all current \s-1XPA\s0 +access points are registered with the event loop. However, if a +single \s-1XPA\s0 access point is to be added (i.e., after the event loop is +started) then the handle of that \s-1XPA\s0 access point can be passed to +this routine. +.PP +The significance of the \s-1XPA/TCL\s0 interface goes beyond the support for +using \s-1XPA\s0 inside C code. The interface allows you to write \s-1XPA\s0 +servers and to make calls to the \s-1XPA\s0 client interface within the Tcl +environment using the Tcl language directly. The XPA/Tcl +interface can be loaded using the following package command: +.PP +.Vb 1 +\& package require tclxpa 2.0 +.Ve +.PP +Alternatively, you can load the shared object (called libtclxpa.so ) directly: +.PP +.Vb 1 +\& load .../libtclxpa.so tclxpa +.Ve +.PP +Once the tclxpa package is loaded, you can use Tcl versions of \s-1XPA\s0 +routines to define \s-1XPA\s0 servers or make client \s-1XPA\s0 calls. The +interface for these routines is designed to match the Unix \s-1XPA\s0 +interface as nearly as possible. Please refer to +\&\s-1XPA\s0 Servers +and +\&\s-1XPA\s0 Clients +for general information about these routines. +.PP +The file test.tcl in the \s-1XPA\s0 source directory gives examples for using the +XPA/Tcl interface. +.PP +The following notes describe the minor differences between the interfaces. +.PP +\&\fBXPANew\fR +.PP +.Vb 1 +\& set xpa [xpanew class name help sproc sdata smode rproc rdata rmode] +.Ve +.PP +rproc and sproc routines are routines. The calling sequence of the +rproc routine is identical to its C counterpart: +.PP +.Vb 1 +\& proc rec_cb { xpa client_data paramlist buf len } { ... } +.Ve +.PP +The sproc routine, however is slightly different from its C counterpart +because of the difficulty of passing data back from the callback to C: +.PP +.Vb 1 +\& proc sendcb { xpa client_data paramlist } { ... } +.Ve +.PP +Note that the C\-based server's char **buf and int *len arguments are +missing from the Tcl callback. This is because we did not know how to +fill buf with data and pass it back to the C routines for communication +with the client. Instead, the Tcl server callback uses the following +routine to set buf and len: +.PP +.Vb 1 +\& xpasetbuf xpa buf len +.Ve +.PP +where: +.PP +.Vb 5 +\& arg explanation +\& \-\-\-\-\-\- \-\-\-\-\-\-\-\-\-\-\- +\& xpa the first argument of the server callback +\& buf the data to be returned to the client +\& len data length in bytes, (if absent, use length of the buf object) +.Ve +.PP +When this routine is called, a copy of buf is saved for transmission to +the client. +.PP +The fact that buf is duplicated means that \s-1TCL\s0 server writers might wish to +perform the I/O directly within the callback, rather than have \s-1XPA\s0 do it +automatically at the end of the routine. To do this, set: +.PP +.Vb 1 +\& fillbuf=false +.Ve +.PP +in the xpanew smode and then perform I/O through the Tcl channel +obtained from: +.PP +.Vb 1 +\& set dchan [xparec $xpa datachan] +.Ve +.PP +where: +.PP +.Vb 5 +\& arg explanation +\& \-\-\-\-\-\- \-\-\-\-\-\-\-\-\-\-\- +\& xpa the first argument of the server callback +\& datachan literal string "datachan" that returns the data channel +\& len data length in bytes, (if absent, use length of the buf object) +.Ve +.PP +\&\s-1NB:\s0 datachan and cmdchan are not available under Windows. It is +necessary to use the \*(L"raw\*(R" equivalents: datafd and cmdfd. +.PP +The same considerations apply to the rproc for receive servers: a copy +of the incoming data is generated to pass to the receive callback. This +copy again can be avoided by using \*(L"fillbuf=false\*(R" in the rmode and then +reading the incoming data from datachan. +.PP +The send and receive callback routines can use the xpaerror and xpamessage +routines to send errors and messages back to the client. If you also +want tcl itself to field an error condition, use the standard return call: +.PP +.Vb 1 +\& return ?\-code c? ?\-errorinfo i? ?\-errorcode ec? string +.Ve +.PP +See the Tcl man page for more info. +.PP +\&\fBXPARec\fR +.PP +The Tcl xparec procedure supplies server routines with access to information +that is available via macros in the C interface: +.PP +.Vb 1 +\& set val [xparec xpa <option>] +.Ve +.PP +where option is: name, class, method, cmdfd, datafd, cmdchan, +datachan. Note that two additional identifiers, cmdchan and datachan, +have been added to to provide Tcl channels corresponding to datafd and +cmdfd. (These latter might still be retrieved in Tcl and passed back +to a C routines.) An additional option called \*(L"version\*(R" can be used to +determine the \s-1XPA\s0 version used to build the Tcl interface. Note that +the standard options require a valid \s-1XPA\s0 handle, but \*(L"version\*(R" does +not (since it simply reports the value of the \s-1XPA_VERSION\s0 definition +in the \s-1XPA\s0 source include file). +.PP +\&\s-1NB:\s0 datachan and cmdchan are not available under Windows. It is +necessary to use the \*(L"raw\*(R" equivalents: datafd and cmdfd. +.PP +.Vb 12 +\& macro explanation +\& \-\-\-\-\-\- \-\-\-\-\-\-\-\-\-\-\- +\& class class of this xpa +\& name name of this xpa +\& method method string (inet or local connect info) +\& cmdchan Tcl channel of command socket +\& datachan Tcl channel of data socket +\& cmdfd fd of command socket +\& datafd fd of data socket +\& sendian endian\-ness of server ("little" or "big") +\& cendian endian\-ness of client ("little" or "big" +\& version XPA version used to build this code +.Ve +.PP +Under Windows, the Tcl event handler cannot automatically sense when an +\&\s-1XPA\s0 socket is ready for \s-1IO\s0 (i.e. \fITcl_CreateFileHandler()\fR is not available +under Windows). The Windows Tcl event handler therefore must be awakened +occasionally for check for \s-1XPA\s0 events. This is done using the standard +\&\fITcl_SetMaxBlockTime()\fR call. The time parameter is defined in tclloop.c +and is currently set to 1000 microseconds (1/1000 of a second). +.PP +The version option can be used to differentiate between source code versions. +It was created to support legacy Tcl code that needs to maintain the 2.0.5 +calling sequence for xpaaccess. You can use a version test such as: +.PP +.Vb 5 +\& if [catch { xparec "" version } version] { +\& puts "pre\-2.1.0e" +\& } else { +\& puts [split $version .] +\& } +.Ve +.SH "SEE ALSO" +.IX Header "SEE ALSO" +See xpa(n) for a list of \s-1XPA\s0 help pages diff --git a/xpa/man/mann/xpatemplate.n b/xpa/man/mann/xpatemplate.n new file mode 100644 index 0000000..f8fc55a --- /dev/null +++ b/xpa/man/mann/xpatemplate.n @@ -0,0 +1,232 @@ +.\" Automatically generated by Pod::Man 2.22 (Pod::Simple 3.13) +.\" +.\" Standard preamble: +.\" ======================================================================== +.de Sp \" Vertical space (when we can't use .PP) +.if t .sp .5v +.if n .sp +.. +.de Vb \" Begin verbatim text +.ft CW +.nf +.ne \\$1 +.. +.de Ve \" End verbatim text +.ft R +.fi +.. +.\" Set up some character translations and predefined strings. \*(-- will +.\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left +.\" double quote, and \*(R" will give a right double quote. \*(C+ will +.\" give a nicer C++. Capital omega is used to do unbreakable dashes and +.\" therefore won't be available. \*(C` and \*(C' expand to `' in nroff, +.\" nothing in troff, for use with C<>. +.tr \(*W- +.ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p' +.ie n \{\ +. ds -- \(*W- +. ds PI pi +. if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch +. if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch +. ds L" "" +. ds R" "" +. ds C` "" +. ds C' "" +'br\} +.el\{\ +. ds -- \|\(em\| +. ds PI \(*p +. ds L" `` +. ds R" '' +'br\} +.\" +.\" Escape single quotes in literal strings from groff's Unicode transform. +.ie \n(.g .ds Aq \(aq +.el .ds Aq ' +.\" +.\" If the F register is turned on, we'll generate index entries on stderr for +.\" titles (.TH), headers (.SH), subsections (.SS), items (.Ip), and index +.\" entries marked with X<> in POD. Of course, you'll have to process the +.\" output yourself in some meaningful fashion. +.ie \nF \{\ +. de IX +. tm Index:\\$1\t\\n%\t"\\$2" +.. +. nr % 0 +. rr F +.\} +.el \{\ +. de IX +.. +.\} +.\" +.\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2). +.\" Fear. Run. Save yourself. No user-serviceable parts. +. \" fudge factors for nroff and troff +.if n \{\ +. ds #H 0 +. ds #V .8m +. ds #F .3m +. ds #[ \f1 +. ds #] \fP +.\} +.if t \{\ +. ds #H ((1u-(\\\\n(.fu%2u))*.13m) +. ds #V .6m +. ds #F 0 +. ds #[ \& +. ds #] \& +.\} +. \" simple accents for nroff and troff +.if n \{\ +. ds ' \& +. ds ` \& +. ds ^ \& +. ds , \& +. ds ~ ~ +. ds / +.\} +.if t \{\ +. ds ' \\k:\h'-(\\n(.wu*8/10-\*(#H)'\'\h"|\\n:u" +. ds ` \\k:\h'-(\\n(.wu*8/10-\*(#H)'\`\h'|\\n:u' +. ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'^\h'|\\n:u' +. ds , \\k:\h'-(\\n(.wu*8/10)',\h'|\\n:u' +. ds ~ \\k:\h'-(\\n(.wu-\*(#H-.1m)'~\h'|\\n:u' +. ds / \\k:\h'-(\\n(.wu*8/10-\*(#H)'\z\(sl\h'|\\n:u' +.\} +. \" troff and (daisy-wheel) nroff accents +.ds : \\k:\h'-(\\n(.wu*8/10-\*(#H+.1m+\*(#F)'\v'-\*(#V'\z.\h'.2m+\*(#F'.\h'|\\n:u'\v'\*(#V' +.ds 8 \h'\*(#H'\(*b\h'-\*(#H' +.ds o \\k:\h'-(\\n(.wu+\w'\(de'u-\*(#H)/2u'\v'-.3n'\*(#[\z\(de\v'.3n'\h'|\\n:u'\*(#] +.ds d- \h'\*(#H'\(pd\h'-\w'~'u'\v'-.25m'\f2\(hy\fP\v'.25m'\h'-\*(#H' +.ds D- D\\k:\h'-\w'D'u'\v'-.11m'\z\(hy\v'.11m'\h'|\\n:u' +.ds th \*(#[\v'.3m'\s+1I\s-1\v'-.3m'\h'-(\w'I'u*2/3)'\s-1o\s+1\*(#] +.ds Th \*(#[\s+2I\s-2\h'-\w'I'u*3/5'\v'-.3m'o\v'.3m'\*(#] +.ds ae a\h'-(\w'a'u*4/10)'e +.ds Ae A\h'-(\w'A'u*4/10)'E +. \" corrections for vroff +.if v .ds ~ \\k:\h'-(\\n(.wu*9/10-\*(#H)'\s-2\u~\d\s+2\h'|\\n:u' +.if v .ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'\v'-.4m'^\v'.4m'\h'|\\n:u' +. \" for low resolution devices (crt and lpr) +.if \n(.H>23 .if \n(.V>19 \ +\{\ +. ds : e +. ds 8 ss +. ds o a +. ds d- d\h'-1'\(ga +. ds D- D\h'-1'\(hy +. ds th \o'bp' +. ds Th \o'LP' +. ds ae ae +. ds Ae AE +.\} +.rm #[ #] #H #V #F C +.\" ======================================================================== +.\" +.IX Title "xpatemplate n" +.TH xpatemplate n "July 23, 2013" "version 2.1.15" "SAORD Documentation" +.\" For nroff, turn off justification. Always turn off hyphenation; it makes +.\" way too many mistakes in technical documents. +.if n .ad l +.nh +.SH "NAME" +\&\fBXPATemplate: Access Point Names and Templates\fR +.SH "SYNOPSIS" +.IX Header "SYNOPSIS" +\&\s-1XPA\s0 access points are composed of two parts: a general class and a +specific name. Both parts accept template characters so that you +can send/retrieve data to/from multiple servers at one time. +.SH "DESCRIPTION" +.IX Header "DESCRIPTION" +When \s-1XPA\s0 servers call +\&\fIXPANew()\fR, +or +\&\fIXPACmdNew()\fR +to define \s-1XPA\s0 access points, they specify a string identifier composed of a +class and a name. When clients communicate with \s-1XPA\s0 access points, +they specify which access points to communicate with using +an identifier of the form: +.PP +.Vb 1 +\& class:name +.Ve +.PP +All registered \s-1XPA\s0 access points that match the specified identifier +will be available for communication (subject to access control rules, +etc.) +.PP +As of \s-1XPA\s0 2.1.5, the length of both the class and name designations are +limited to 1024 characters. +.PP +The \s-1XPA\s0 class:name identifier actually is a template: it accepts wild +cards in its syntax, so a single specifier can match more than one \s-1XPA\s0 +access point. (Note that the class is optional and defaults to \*(L"*\*(R".) +The allowed syntax for clients to specify the class:name template is +of the form shown below. (Note that \*(L"*\*(R" is used to denote a generic +wild card, but other wild cards characters are supported, as described +below). +.PP +.Vb 7 +\& template explanation +\& \-\-\-\-\-\-\-\- \-\-\-\-\-\-\-\-\-\-\- +\& class:name exact match of class and name +\& name match any class with this name +\& *:name match any class with this name +\& class:* match any name of this class +\& *:* match any access point +.Ve +.PP +In general, the following wild-cards can be applied to class and name: +.PP +.Vb 5 +\& wildcard explanation +\& \-\-\-\-\-\-\-\- \-\-\-\-\-\-\-\-\-\-\- +\& ? match any character, but there must be one +\& * match anything, or nothing +\& [...] match an inclusive set +.Ve +.PP +Although the class:name template normally is used to refer to \s-1XPA\s0 +access points, these also can be specified using their individual +socket identifiers. For inet sockets, the socket identifier is +\&\fBip:port\fR, where ip can be the DNS-registered name, +the \s-1ASCII\s0 \s-1IP\s0 number (e.g. 123.45.67.890) or the hex \s-1IP\s0 number +(e.g. 838f3a60). For unix sockets, the identifier is the socket file +name. These socket identifiers are displayed as the fourth argument +in the xpans display of registered access points. For example, +consider the ds9 program started using inet sockets. The xpans name +server will register something like this: +.PP +.Vb 2 +\& csh> xpaget xpans +\& DS9 ds9 gs saord.harvard.edu:3236 eric +.Ve +.PP +You can access ds9 using ip:3236 in any of the three forms: +.PP +.Vb 2 +\& csh> xpaget saord:3236 file +\& /home/eric/data/snr.ev +\& +\& csh> xpaget 123.45.67.890:3236 file +\& /home/eric/data/snr.ev +\& +\& csh> xpaget 838f3a60:3236 file +\& /home/eric/data/snr.ev +.Ve +.PP +In the case of unix sockets, the socket identifier is a file: +.PP +.Vb 2 +\& csh> xpaget xpans +\& DS9 ds9 gs /tmp/.xpa/DS9_ds9.2631 eric +\& +\& csh> xpaget /tmp/.xpa/DS9_ds9.2631 file +\& /home/eric/data/snr.ev +.Ve +.PP +This feature can be useful in distinguishing between multiple +instances of a program that all have the same class:name designation. +.SH "SEE ALSO" +.IX Header "SEE ALSO" +See xpa(n) for a list of \s-1XPA\s0 help pages diff --git a/xpa/man/mann/xpausers.n b/xpa/man/mann/xpausers.n new file mode 100644 index 0000000..2823e3d --- /dev/null +++ b/xpa/man/mann/xpausers.n @@ -0,0 +1,186 @@ +.\" Automatically generated by Pod::Man 2.22 (Pod::Simple 3.13) +.\" +.\" Standard preamble: +.\" ======================================================================== +.de Sp \" Vertical space (when we can't use .PP) +.if t .sp .5v +.if n .sp +.. +.de Vb \" Begin verbatim text +.ft CW +.nf +.ne \\$1 +.. +.de Ve \" End verbatim text +.ft R +.fi +.. +.\" Set up some character translations and predefined strings. \*(-- will +.\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left +.\" double quote, and \*(R" will give a right double quote. \*(C+ will +.\" give a nicer C++. Capital omega is used to do unbreakable dashes and +.\" therefore won't be available. \*(C` and \*(C' expand to `' in nroff, +.\" nothing in troff, for use with C<>. +.tr \(*W- +.ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p' +.ie n \{\ +. ds -- \(*W- +. ds PI pi +. if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch +. if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch +. ds L" "" +. ds R" "" +. ds C` "" +. ds C' "" +'br\} +.el\{\ +. ds -- \|\(em\| +. ds PI \(*p +. ds L" `` +. ds R" '' +'br\} +.\" +.\" Escape single quotes in literal strings from groff's Unicode transform. +.ie \n(.g .ds Aq \(aq +.el .ds Aq ' +.\" +.\" If the F register is turned on, we'll generate index entries on stderr for +.\" titles (.TH), headers (.SH), subsections (.SS), items (.Ip), and index +.\" entries marked with X<> in POD. Of course, you'll have to process the +.\" output yourself in some meaningful fashion. +.ie \nF \{\ +. de IX +. tm Index:\\$1\t\\n%\t"\\$2" +.. +. nr % 0 +. rr F +.\} +.el \{\ +. de IX +.. +.\} +.\" +.\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2). +.\" Fear. Run. Save yourself. No user-serviceable parts. +. \" fudge factors for nroff and troff +.if n \{\ +. ds #H 0 +. ds #V .8m +. ds #F .3m +. ds #[ \f1 +. ds #] \fP +.\} +.if t \{\ +. ds #H ((1u-(\\\\n(.fu%2u))*.13m) +. ds #V .6m +. ds #F 0 +. ds #[ \& +. ds #] \& +.\} +. \" simple accents for nroff and troff +.if n \{\ +. ds ' \& +. ds ` \& +. ds ^ \& +. ds , \& +. ds ~ ~ +. ds / +.\} +.if t \{\ +. ds ' \\k:\h'-(\\n(.wu*8/10-\*(#H)'\'\h"|\\n:u" +. ds ` \\k:\h'-(\\n(.wu*8/10-\*(#H)'\`\h'|\\n:u' +. ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'^\h'|\\n:u' +. ds , \\k:\h'-(\\n(.wu*8/10)',\h'|\\n:u' +. ds ~ \\k:\h'-(\\n(.wu-\*(#H-.1m)'~\h'|\\n:u' +. ds / \\k:\h'-(\\n(.wu*8/10-\*(#H)'\z\(sl\h'|\\n:u' +.\} +. \" troff and (daisy-wheel) nroff accents +.ds : \\k:\h'-(\\n(.wu*8/10-\*(#H+.1m+\*(#F)'\v'-\*(#V'\z.\h'.2m+\*(#F'.\h'|\\n:u'\v'\*(#V' +.ds 8 \h'\*(#H'\(*b\h'-\*(#H' +.ds o \\k:\h'-(\\n(.wu+\w'\(de'u-\*(#H)/2u'\v'-.3n'\*(#[\z\(de\v'.3n'\h'|\\n:u'\*(#] +.ds d- \h'\*(#H'\(pd\h'-\w'~'u'\v'-.25m'\f2\(hy\fP\v'.25m'\h'-\*(#H' +.ds D- D\\k:\h'-\w'D'u'\v'-.11m'\z\(hy\v'.11m'\h'|\\n:u' +.ds th \*(#[\v'.3m'\s+1I\s-1\v'-.3m'\h'-(\w'I'u*2/3)'\s-1o\s+1\*(#] +.ds Th \*(#[\s+2I\s-2\h'-\w'I'u*3/5'\v'-.3m'o\v'.3m'\*(#] +.ds ae a\h'-(\w'a'u*4/10)'e +.ds Ae A\h'-(\w'A'u*4/10)'E +. \" corrections for vroff +.if v .ds ~ \\k:\h'-(\\n(.wu*9/10-\*(#H)'\s-2\u~\d\s+2\h'|\\n:u' +.if v .ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'\v'-.4m'^\v'.4m'\h'|\\n:u' +. \" for low resolution devices (crt and lpr) +.if \n(.H>23 .if \n(.V>19 \ +\{\ +. ds : e +. ds 8 ss +. ds o a +. ds d- d\h'-1'\(ga +. ds D- D\h'-1'\(hy +. ds th \o'bp' +. ds Th \o'LP' +. ds ae ae +. ds Ae AE +.\} +.rm #[ #] #H #V #F C +.\" ======================================================================== +.\" +.IX Title "xpausers n" +.TH xpausers n "July 23, 2013" "version 2.1.15" "SAORD Documentation" +.\" For nroff, turn off justification. Always turn off hyphenation; it makes +.\" way too many mistakes in technical documents. +.if n .ad l +.nh +.SH "NAME" +\&\fBXPAUsers: Distinguishing Users\fR +.SH "SYNOPSIS" +.IX Header "SYNOPSIS" +\&\s-1XPA\s0 normally distinguishes between users on a given host, but it is possible +to send data to access points belonging to other users. +.SH "DESCRIPTION" +.IX Header "DESCRIPTION" +A single \s-1XPA\s0 name service typically serves all users on a given +machine. Two users can register the same \s-1XPA\s0 access points on the +same machine without conflict, because the user's username is +registered with each access point and, by default, programs such as +xpaget and xpaset only process access points of the appropriate user. +For example: +.PP +.Vb 4 +\& XPA xpa1 gs 838e2f67:1262 eric +\& XPA xpa2 gs 838e2f67:1266 eric +\& XPA xpa1 gs 838e2f67:2523 john +\& XPA xpa2 gs 838e2f67:2527 john +.Ve +.PP +Here the users \*(L"eric\*(R" and \*(L"john\*(R" both have registered the access +points xpa1 and xpa2. When either \*(L"john\*(R" or \*(L"eric\*(R" retrieves +information from xpa1, they will process only the access point +registered in their user name. +.PP +If you want to access another user's \s-1XPA\s0 access points on a single +machine, use the \-u [user] option on xpaset, xpaget, etc. For example, +if eric executes: +.PP +.Vb 1 +\& xpaget \-u john xpa1 +.Ve +.PP +he will access John's xpa1 access point.Use \*(L"*\*(R" to access all users +on a given machine: +.PP +.Vb 1 +\& xpaget \-u "*" xpa1 +.Ve +.PP +Note that the \s-1XPA\s0 Environment Variable +\&\s-1XPA_NSUSERS\s0 can be used to specify the default list of users to +process: +.PP +.Vb 1 +\& setenv XPA_NSUSERS "eric,john" +.Ve +.PP +will cause access points from both \*(L"eric\*(R" and \*(L"john\*(R" to be processed +by default. +.SH "SEE ALSO" +.IX Header "SEE ALSO" +See xpa(n) for a list of \s-1XPA\s0 help pages diff --git a/xpa/man/mann/xpaxt.n b/xpa/man/mann/xpaxt.n new file mode 100644 index 0000000..8885dd4 --- /dev/null +++ b/xpa/man/mann/xpaxt.n @@ -0,0 +1,161 @@ +.\" Automatically generated by Pod::Man 2.22 (Pod::Simple 3.13) +.\" +.\" Standard preamble: +.\" ======================================================================== +.de Sp \" Vertical space (when we can't use .PP) +.if t .sp .5v +.if n .sp +.. +.de Vb \" Begin verbatim text +.ft CW +.nf +.ne \\$1 +.. +.de Ve \" End verbatim text +.ft R +.fi +.. +.\" Set up some character translations and predefined strings. \*(-- will +.\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left +.\" double quote, and \*(R" will give a right double quote. \*(C+ will +.\" give a nicer C++. Capital omega is used to do unbreakable dashes and +.\" therefore won't be available. \*(C` and \*(C' expand to `' in nroff, +.\" nothing in troff, for use with C<>. +.tr \(*W- +.ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p' +.ie n \{\ +. ds -- \(*W- +. ds PI pi +. if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch +. if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch +. ds L" "" +. ds R" "" +. ds C` "" +. ds C' "" +'br\} +.el\{\ +. ds -- \|\(em\| +. ds PI \(*p +. ds L" `` +. ds R" '' +'br\} +.\" +.\" Escape single quotes in literal strings from groff's Unicode transform. +.ie \n(.g .ds Aq \(aq +.el .ds Aq ' +.\" +.\" If the F register is turned on, we'll generate index entries on stderr for +.\" titles (.TH), headers (.SH), subsections (.SS), items (.Ip), and index +.\" entries marked with X<> in POD. Of course, you'll have to process the +.\" output yourself in some meaningful fashion. +.ie \nF \{\ +. de IX +. tm Index:\\$1\t\\n%\t"\\$2" +.. +. nr % 0 +. rr F +.\} +.el \{\ +. de IX +.. +.\} +.\" +.\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2). +.\" Fear. Run. Save yourself. No user-serviceable parts. +. \" fudge factors for nroff and troff +.if n \{\ +. ds #H 0 +. ds #V .8m +. ds #F .3m +. ds #[ \f1 +. ds #] \fP +.\} +.if t \{\ +. ds #H ((1u-(\\\\n(.fu%2u))*.13m) +. ds #V .6m +. ds #F 0 +. ds #[ \& +. ds #] \& +.\} +. \" simple accents for nroff and troff +.if n \{\ +. ds ' \& +. ds ` \& +. ds ^ \& +. ds , \& +. ds ~ ~ +. ds / +.\} +.if t \{\ +. ds ' \\k:\h'-(\\n(.wu*8/10-\*(#H)'\'\h"|\\n:u" +. ds ` \\k:\h'-(\\n(.wu*8/10-\*(#H)'\`\h'|\\n:u' +. ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'^\h'|\\n:u' +. ds , \\k:\h'-(\\n(.wu*8/10)',\h'|\\n:u' +. ds ~ \\k:\h'-(\\n(.wu-\*(#H-.1m)'~\h'|\\n:u' +. ds / \\k:\h'-(\\n(.wu*8/10-\*(#H)'\z\(sl\h'|\\n:u' +.\} +. \" troff and (daisy-wheel) nroff accents +.ds : \\k:\h'-(\\n(.wu*8/10-\*(#H+.1m+\*(#F)'\v'-\*(#V'\z.\h'.2m+\*(#F'.\h'|\\n:u'\v'\*(#V' +.ds 8 \h'\*(#H'\(*b\h'-\*(#H' +.ds o \\k:\h'-(\\n(.wu+\w'\(de'u-\*(#H)/2u'\v'-.3n'\*(#[\z\(de\v'.3n'\h'|\\n:u'\*(#] +.ds d- \h'\*(#H'\(pd\h'-\w'~'u'\v'-.25m'\f2\(hy\fP\v'.25m'\h'-\*(#H' +.ds D- D\\k:\h'-\w'D'u'\v'-.11m'\z\(hy\v'.11m'\h'|\\n:u' +.ds th \*(#[\v'.3m'\s+1I\s-1\v'-.3m'\h'-(\w'I'u*2/3)'\s-1o\s+1\*(#] +.ds Th \*(#[\s+2I\s-2\h'-\w'I'u*3/5'\v'-.3m'o\v'.3m'\*(#] +.ds ae a\h'-(\w'a'u*4/10)'e +.ds Ae A\h'-(\w'A'u*4/10)'E +. \" corrections for vroff +.if v .ds ~ \\k:\h'-(\\n(.wu*9/10-\*(#H)'\s-2\u~\d\s+2\h'|\\n:u' +.if v .ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'\v'-.4m'^\v'.4m'\h'|\\n:u' +. \" for low resolution devices (crt and lpr) +.if \n(.H>23 .if \n(.V>19 \ +\{\ +. ds : e +. ds 8 ss +. ds o a +. ds d- d\h'-1'\(ga +. ds D- D\h'-1'\(hy +. ds th \o'bp' +. ds Th \o'LP' +. ds ae ae +. ds Ae AE +.\} +.rm #[ #] #H #V #F C +.\" ======================================================================== +.\" +.IX Title "xpaxt n" +.TH xpaxt n "July 23, 2013" "version 2.1.15" "SAORD Documentation" +.\" For nroff, turn off justification. Always turn off hyphenation; it makes +.\" way too many mistakes in technical documents. +.if n .ad l +.nh +.SH "NAME" +\&\fBXPAXt: the \s-1XPA\s0 Interface to Xt (X Windows)\fR +.SH "SYNOPSIS" +.IX Header "SYNOPSIS" +Describes how \s-1XPA\s0 access points can be added to X Toolkit (Xt) programs. +.SH "DESCRIPTION" +.IX Header "DESCRIPTION" +\&\s-1XPA\s0 supports Xt programs: you can call \fIXPANew()\fR, \fIXPACmdNew()\fR, or +\&\fIXPAInfoNew()\fR within any C routine to add \s-1XPA\s0 server callbacks to an Xt +program. Since an Xt program has its own event loop call (i.e., +\&\fIXtAppMainLoop()\fR), it therefore does not need or want to use the \s-1XPA\s0 +even loop. Thus, in order to add \s-1XPA\s0 access points to the standard Xt +event loop, the following routine should be called before entering the +loop: +.PP +.Vb 1 +\& int XPAXtAddInput(XtAppContext app, XPA xpa) +.Ve +.PP +The \fIXPAAddAddInput()\fR routine will add \s-1XPA\s0 access points to the Xt event +loop by making calls to the standard \fIXtAppAddInput()\fR routine. (If the +XtAppContext argument is \s-1NULL\s0, then the alternate \fIXtAddInput()\fR routine +is used instead.) If the xpa argument is \s-1NULL\s0, then all active \s-1XPA\s0 +access points are added to the loop. If xpa is not \s-1NULL\s0, then only +the specified access point is added. The latter type of call is used +to add new access points from within a callback, after the program has +entered the \fIXtAppMainLoop()\fR even loop. +.SH "SEE ALSO" +.IX Header "SEE ALSO" +See xpa(n) for a list of \s-1XPA\s0 help pages diff --git a/xpa/mklib b/xpa/mklib new file mode 100755 index 0000000..c900b3e --- /dev/null +++ b/xpa/mklib @@ -0,0 +1,880 @@ +#!/bin/sh + +# Make a shared library. +# This script should be useful for projects other than Mesa. +# Improvements/fixes are welcome. + + +# Copyright (C) 1999-2006 Brian Paul All Rights Reserved. +# +# Permission is hereby granted, free of charge, to any person obtaining a +# copy of this software and associated documentation files (the "Software"), +# to deal in the Software without restriction, including without limitation +# the rights to use, copy, modify, merge, publish, distribute, sublicense, +# and/or sell copies of the Software, and to permit persons to whom the +# Software is furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +# OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +# BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +# AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +# +# Option defaults +# +LIBNAME="" +MAJOR=1 +MINOR=0 +PATCH="" +DEPS="" +LINK="" +LDFLAGS="" +CPLUSPLUS=0 +STATIC=0 +DLOPEN=0 +INSTALLDIR="." +ARCH="auto" +ARCHOPT="" +NOPREFIX=0 +EXPORTS="" + + +# +# Parse arguments +# +while true +do + case $1 in + '-h' | '--help') + echo 'Usage: mklib [options] objects' + echo 'Create a shared library from object files.' + echo ' -o LIBRARY specifies the name of the resulting library, without' + echo ' the leading "lib" or any suffix.' + echo ' (eg: "-o GL" might result in "libGL.so" being made)' + echo ' -major N specifies major version number (default is 1)' + echo ' -minor N specifies minor version number (default is 0)' + echo ' -patch N specifies patch version number (default is 0)' + echo ' -lLIBRARY specifies a dependency on LIBRARY' + echo ' -LDIR search in DIR for library dependencies' + echo ' -linker L explicity specify the linker program to use (eg: gcc, g++)' + echo ' Not observed on all systems at this time.' + echo ' -ldflags OPT specify any additional linker flags in OPT' + echo ' -cplusplus link with C++ runtime' + echo ' -static make a static library (default is dynamic/shared)' + echo ' -dlopen make a shared library suitable for dynamic loading' + echo ' -install DIR put resulting library file(s) in DIR' + echo ' -arch ARCH override using `uname` to determine host system' + echo ' -archopt OPT specify an extra achitecture-specific option OPT' + echo ' -altopts OPTS alternate options to override all others' + echo " -noprefix don't prefix library name with 'lib' nor add any suffix" + echo ' -exports FILE only export the symbols listed in FILE' + echo ' -h, --help display this information and exit' + exit 1 + ;; + '-o') + shift 1; + LIBNAME=$1 + ;; + '-major') + shift 1; + MAJOR=$1 + ;; + '-minor') + shift 1; + MINOR=$1 + ;; + '-patch') + shift 1; + PATCH=$1 + ;; + '-linker') + shift 1; + LINK=$1 + ;; + '-ldflags') + shift 1; + LDFLAGS=$1 + ;; + -l*) + DEPS="$DEPS $1" + ;; + -L*) + DEPS="$DEPS $1" + ;; + -pthread) + # this is a special case (see bugzilla 10876) + DEPS="$DEPS $1" + ;; + -Wl*) + # Another special case for DragonFly + DEPS="$DEPS $1" + ;; + -Wl*) + DEPS="$DEPS $1" + ;; + '-pthread') + DEPS="$DEPS -pthread" + ;; + '-cplusplus') + CPLUSPLUS=1 + ;; + '-static') + STATIC=1 + ;; + '-dlopen') + DLOPEN=1 + ;; + '-install') + shift 1; + INSTALLDIR=$1 + ;; + '-arch') + shift 1; + ARCH=$1 + ;; + '-archopt') + shift 1; + ARCHOPT=$1 + ;; + '-altopts') + shift 1; + ALTOPTS=$1 + ;; + '-noprefix') + NOPREFIX=1 + ;; + '-exports') + shift 1; + EXPORTS=$1 + ;; + -*) + echo "mklib: Unknown option: " $1 ; + exit 1 + ;; + *) + # This should be the first object file, stop parsing + break + esac + shift 1 +done +OBJECTS=$@ + + +if [ ${ARCH} = "auto" ] ; then + ARCH=`uname` +fi + + +# +# Error checking +# +if [ "x${LIBNAME}" = "x" ] ; then + echo "mklib: Error: no library name specified" + exit 1 +fi +if [ "x${OBJECTS}" = "x" ] ; then + echo "mklib: Error: no object files specified" + exit 1 +fi + + +# +# Debugging info +# +if [ ] ; then + echo "-----------------" + echo ARCH is $ARCH + echo LIBNAME is $LIBNAME + echo MAJOR is $MAJOR + echo MINOR is $MINOR + echo PATCH is $PATCH + echo DEPS are $DEPS + echo "EXPORTS in" $EXPORTS + echo "-----------------" +fi + + +# +# OK, make the library now +# +case $ARCH in + + 'Linux' | 'OpenBSD' | 'DragonFly' | 'GNU' | GNU/*) + # we assume gcc + + if [ "x$LINK" = "x" ] ; then + # -linker was not specified so set default link command now + if [ $CPLUSPLUS = 1 ] ; then + LINK=g++ + else + LINK=gcc + fi + fi + + if [ $NOPREFIX = 1 ] ; then + # No "lib" or ".so" part + echo "mklib: Making" $ARCH "shared library: " ${LIBNAME} + case $ARCH in 'Linux' | 'GNU' | GNU/*) + OPTS="-Xlinker -Bsymbolic -shared" + ;; + *) + OPTS="-shared" + ;; + esac + + # Check if objects are 32-bit and we're running in 64-bit + # environment. If so, pass -m32 flag to linker. + set ${OBJECTS} + ABI32=`file $1 | grep 32-bit` + if [ "${ABI32}" -a `uname -m` = "x86_64" ] ; then + OPTS="-m32 ${OPTS}" + fi + + if [ "${ALTOPTS}" ] ; then + OPTS=${ALTOPTS} + fi + + rm -f ${LIBNAME} + # make lib + ${LINK} ${OPTS} ${LDFLAGS} -o ${LIBNAME} ${OBJECTS} ${DEPS} + # finish up + FINAL_LIBS="${LIBNAME}" + elif [ $STATIC = 1 ] ; then + LIBNAME="lib${LIBNAME}.a" # prefix with "lib", suffix with ".a" + echo "mklib: Making" $ARCH "static library: " ${LIBNAME} + LINK="ar" + OPTS="-ru" + if [ "${ALTOPTS}" ] ; then + OPTS=${ALTOPTS} + fi + rm -f ${LIBNAME} + # make lib + ${LINK} ${OPTS} ${LIBNAME} ${OBJECTS} + ranlib ${LIBNAME} + # finish up + FINAL_LIBS=${LIBNAME} + else + LIBNAME="lib${LIBNAME}" # prefix with "lib" + case $ARCH in 'Linux' | 'GNU' | GNU/*) + OPTS="-Xlinker -Bsymbolic -shared -Wl,-soname,${LIBNAME}.so.${MAJOR}" + ;; + *) + OPTS="-shared -Wl,-soname,${LIBNAME}.so.${MAJOR}" + ;; + esac + if [ $EXPORTS ] ; then + #OPTS="${OPTS} -Xlinker --retain-symbols-file ${EXPORTS}" + # Make the 'exptmp' file for --version-script option + echo "{" > exptmp + echo "global:" >> exptmp + sed 's/$/;/' ${EXPORTS} >> exptmp + echo "local:" >> exptmp + echo "*;" >> exptmp + echo "};" >> exptmp + OPTS="${OPTS} -Xlinker --version-script=exptmp" + # exptmp is removed below + fi + + # Check if objects are 32-bit and we're running in 64-bit + # environment. If so, pass -m32 flag to linker. + set ${OBJECTS} + ABI32=`file $1 | grep 32-bit` + if [ "${ABI32}" -a `uname -m` = "x86_64" ] ; then + OPTS="-m32 ${OPTS}" + fi + if [ "${ALTOPTS}" ] ; then + OPTS=${ALTOPTS} + fi + + if [ x${PATCH} = "x" ] ; then + VERSION="${MAJOR}.${MINOR}" + else + VERSION="${MAJOR}.${MINOR}.${PATCH}" + fi + + echo "mklib: Making" $ARCH "shared library: " ${LIBNAME}.so.${VERSION} + + # rm any old libs + rm -f ${LIBNAME}.so.${VERSION} + rm -f ${LIBNAME}.so.${MAJOR} + rm -f ${LIBNAME}.so + + # make lib + ${LINK} ${OPTS} ${LDFLAGS} -o ${LIBNAME}.so.${VERSION} ${OBJECTS} ${DEPS} + # make usual symlinks + ln -s ${LIBNAME}.so.${VERSION} ${LIBNAME}.so.${MAJOR} + ln -s ${LIBNAME}.so.${MAJOR} ${LIBNAME}.so + # finish up + FINAL_LIBS="${LIBNAME}.so.${VERSION} ${LIBNAME}.so.${MAJOR} ${LIBNAME}.so" +# rm -f exptmp + fi + ;; + + 'SunOS') + if [ $STATIC = 1 ] ; then + LIBNAME="lib${LIBNAME}.a" + echo "mklib: Making SunOS static library: " ${LIBNAME} + rm -f ${LIBNAME} + ar -ruv ${LIBNAME} ${OBJECTS} + FINAL_LIBS=${LIBNAME} + else + if [ $NOPREFIX = 0 ] ; then + LIBNAME="lib${LIBNAME}.so" + fi + echo "mklib: Making SunOS shared library: " ${LIBNAME} + + if [ "x$LINK" = "x" ] ; then + # -linker was not specified, choose default linker now + if [ $CPLUSPLUS = 1 ] ; then + # determine linker and options for C++ code + if [ `which c++` ] ; then + # use Sun c++ + LINK="c++" + elif [ `type g++` ] ; then + # use g++ + LINK="g++" + else + echo "mklib: warning: can't find C++ comiler, trying CC." + LINK="CC" + fi + else + # use native Sun linker for C code + LINK="ld" + fi + fi + + # linker options + if [ ${LINK} = "ld" -o ${LINK} = "cc" -o ${LINK} = "CC" ] ; then + # SunOS tools, -G to make shared libs + OPTS="-G" + else + # gcc linker + # Check if objects are 32-bit and we're running in 64-bit + # environment. If so, pass -m32 flag to linker. + set ${OBJECTS} + ABI32=`file $1 | grep 32-bit` + if [ "${ABI32}" ] ; then + OPTS="-m32 -shared -Wl,-Bdynamic" + else + OPTS="-m64 -shared -Wl,-Bdynamic" + fi + fi + + # Check if objects are SPARC v9 + # file says: ELF 64-bit MSB relocatable SPARCV9 Version 1 + set ${OBJECTS} + SPARCV9=`file $1 | grep SPARCV9` + if [ "${SPARCV9}" ] ; then + OPTS="${OPTS} -xarch=v9" + fi + if [ "${ALTOPTS}" ] ; then + OPTS=${ALTOPTS} + fi + # for debug: + #echo "mklib: linker is" ${LINK} ${OPTS} + if [ $NOPREFIX = 1 ] ; then + rm -f ${LIBNAME} + ${LINK} ${OPTS} ${LDFLAGS} -o ${LIBNAME} ${OBJECTS} ${DEPS} + else + rm -f ${LIBNAME}.${MAJOR} ${LIBNAME} + ${LINK} ${OPTS} ${LDFLAGS} -o ${LIBNAME}.${MAJOR} ${OBJECTS} ${DEPS} + ln -s ${LIBNAME}.${MAJOR} ${LIBNAME} + fi + FINAL_LIBS="${LIBNAME}.${MAJOR} ${LIBNAME}" + fi + ;; + + 'FreeBSD') + # we assume gcc + + if [ "x$LINK" = "x" ] ; then + # -linker was not specified so set default link command now + if [ $CPLUSPLUS = 1 ] ; then + LINK=g++ + else + LINK=gcc + fi + fi + + if [ $NOPREFIX = 1 ] ; then + # No "lib" or ".so" part + echo "mklib: Making FreeBSD shared library: " ${LIBNAME} + OPTS="-shared" + if [ "${ALTOPTS}" ] ; then + OPTS=${ALTOPTS} + fi + rm -f ${LIBNAME} + ${LINK} ${OPTS} ${LDFLAGS} -o ${LIBNAME} ${OBJECTS} ${DEPS} + FINAL_LIBS=${LIBNAME} + elif [ $STATIC = 1 ] ; then + STLIB="lib${LIBNAME}.a" + echo "mklib: Making FreeBSD static library: " ${STLIB} + rm -f ${STLIB} + ar cq ${STLIB} ${OBJECTS} + ranlib ${STLIB} + FINAL_LIBS=${STLIB} + else + SHLIB="lib${LIBNAME}.so.${MAJOR}" + OPTS="-shared -Wl,-soname,${SHLIB}" + if [ "${ALTOPTS}" ] ; then + OPTS=${ALTOPTS} + fi + echo "mklib: Making FreeBSD shared library: " ${SHLIB} + rm -f ${SHLIB} + ${LINK} ${OPTS} ${LDFLAGS} -o ${SHLIB} ${OBJECTS} ${DEPS} + ln -sf ${SHLIB} "lib${LIBNAME}.so" + FINAL_LIBS="${SHLIB} lib${LIBNAME}.so" + fi + ;; + + 'NetBSD') + if [ $STATIC = 1 ] ; then + LIBNAME="lib${LIBNAME}_pic.a" + echo "mklib: Making NetBSD PIC static library: " ${LIBNAME} + rm -f ${LIBNAME} + ar cq ${LIBNAME} ${OBJECTS} + ranlib ${LIBNAME} + FINAL_LIBS=${LIBNAME} + else + LIBNAME="lib${LIBNAME}.so.${MAJOR}.${MINOR}" + echo "mklib: Making NetBSD PIC shared library: " ${LIBNAME} + rm -f ${LIBNAME} + ld -x -Bshareable -Bforcearchive -o ${LIBNAME} ${OBJECTS} + FINAL_LIBS=${LIBNAME} + fi + ;; + + 'IRIX' | 'IRIX64') + if [ $STATIC = 1 ] ; then + LIBNAME="lib${LIBNAME}.a" + rm -f ${LIBNAME} + ar rc ${LIBNAME} ${OBJECTS} + FINAL_LIBS=${LIBNAME} + else + LIBNAME="lib${LIBNAME}.so" # prefix with "lib", suffix with ".so" + + # examine first object to determine ABI + set ${OBJECTS} + ABI_O32=`file $1 | grep 'ELF 32-bit'` + ABI_N32=`file $1 | grep 'ELF N32'` + ABI_N64=`file $1 | grep 'ELF 64-bit'` + if [ "${ABI_O32}" ] ; then + OPTS="-32 -shared -all" + ABI="o32-bit" + elif [ "${ABI_N32}" ] ; then + OPTS="-n32 -shared -all" + ABI="n32-bit" + elif [ "${ABI_N64}" ] ; then + OPTS="-64 -shared -all" + ABI="64-bit" + else + echo "Error: Unexpected IRIX ABI!" + exit 1 + fi + + if [ "${ALTOPTS}" ] ; then + OPTS=${ALTOPTS} + fi + + if [ $CPLUSPLUS = 1 ] ; then + LINK="CC" + else + LINK="ld" + fi + + echo "mklib: Making IRIX " ${ABI} " shared library: " ${LIBNAME} + ${LINK} ${OPTS} ${LDFLAGS} -o ${LIBNAME} ${OBJECTS} ${DEPS} + FINAL_LIBS=${LIBNAME} + fi + ;; + + 'linux-cygwin') + LIBNAME="lib${LIBNAME}.a" + echo "mklib: Making linux-cygwin library: " ${LIBNAME} + rm -f ${LIBNAME} + gnuwin32ar ruv ${LIBNAME} ${OBJECTS} + FINAL_LIBS=${LIBNAME} + ;; + + 'HP-UX') + if [ $STATIC = 1 ] ; then + LIBNAME="lib${LIBNAME}.a" + echo "mklib: Making HP-UX static library: " ${LIBNAME} + rm -f ${LIBNAME} + ar -ruv ${LIBNAME} ${OBJECTS} + FINAL_LIBS=${LIBNAME} + else + # HP uses a .2 for their current GL/GLU libraries + if [ ${LIBNAME} = "GL" -o ${LIBNAME} = "GLU" ] ; then + MAJOR=2 + fi + RUNLIB="lib${LIBNAME}.${MAJOR}" + DEVLIB="lib${LIBNAME}.sl" + echo "mklib: Making HP-UX shared library: " ${RUNLIB} ${DEVLIB} + ld -b -o ${RUNLIB} +b ${RUNLIB} ${OBJECTS} ${DEPS} + ln -s ${RUNLIB} ${DEVLIB} + FINAL_LIBS="${RUNLIB} ${DEVLIB}" + fi + ;; + + 'AIX' ) + # examine first object to determine ABI + set ${OBJECTS} + ABI_64=`file $1 | grep '64-bit'` + if [ "${ABI_64}" ] ; then + X64="-X64" + Q64="-q64" + OFILE=shr_64.o + else + OFILE=shr.o #Want to be consistent with the IBM libGL.a + fi + + if [ $STATIC = 1 ] ; then + LIBNAME="lib${LIBNAME}.a" + echo "mklib: Making AIX static library: " ${LIBNAME} + ar -ruv ${X64} ${LIBNAME} ${OBJECTS} + FINAL_LIBS=${LIBNAME} + else + EXPFILE="lib${LIBNAME}.exp" + LIBNAME="lib${LIBNAME}.a" # shared objects are still stored in the .a libraries + OPTS="-bE:${EXPFILE} -bM:SRE -bnoentry ${Q64}" + rm -f ${EXPFILE} ${OFILE} + NM="/bin/nm -eC ${X64}" + echo "#! /usr/lib/${LIBNAME}" > ${EXPFILE} + ${NM} ${OBJECTS} | awk '{ + if ((($2 == "T") || ($2 == "D") || ($2 == "B")) \ + && ( substr($1,1,1) != ".")) { + if (substr ($1, 1, 7) != "__sinit" && + substr ($1, 1, 7) != "__sterm") { + if (substr ($1, 1, 5) == "__tf1") + print (substr ($1, 7)) + else if (substr ($1, 1, 5) == "__tf9") + print (substr ($1, 15)) + else + print $1 + } + } + }' | sort -u >> ${EXPFILE} + + if [ "${ALTOPTS}" ] ; then + OPTS=${ALTOPTS} + fi + + # On AIX a shared library is linked differently when + # you want to dlopen the file + if [ $DLOPEN = "1" ] ; then + cc -G ${OPTS} ${LDFLAGS} -o ${LIBNAME} ${OBJECTS} ${DEPS} + else + cc ${OPTS} ${LDFLAGS} -o ${OFILE} ${OBJECTS} ${DEPS} + ar ${X64} -r ${LIBNAME} ${OFILE} + fi + + FINAL_LIBS="${LIBNAME}" + fi + ;; + + 'OpenSTEP') + LIBNAME="lib${LIBNAME}.a" + echo "mklib: Making OpenSTEP static library: " ${LIBNAME} + libtool -static -o ${LIBNAME} - ${OBJECTS} + FINAL_LIBS=${LIBNAME} + ;; + + 'OSF1') + if [ $STATIC = 1 ] ; then + LIBNAME="lib${LIBNAME}.a" + echo "mklib: Making OSF/1 static library: " ${LIBNAME} + rm -f ${LIBNAME} + ar -ruv ${LIBNAME} ${OBJECTS} + FINAL_LIBS=${LIBNAME} + else + VERSION="${MAJOR}.${MINOR}" + LIBNAME="lib${LIBNAME}.so" + echo "mklib: Making OSF/1 shared library: " ${LIBNAME} + if [ "x$LINK" = "x" ] ; then + if [ $CPLUSPLUS = 1 ] ; then + LINK=cxx + else + LINK=cc + fi + fi + rm -f ${LIBNAME}.${VERSION} + ${LINK} -o ${LIBNAME}.${VERSION} -shared -set_version ${VERSION} -soname ${LIBNAME}.${VERSION} -expect_unresolved \* -all ${OBJECTS} ${DEPS} + ln -sf ${LIBNAME}.${VERSION} ${LIBNAME} + FINAL_LIBS="${LIBNAME} ${LIBNAME}.${VERSION}" + fi + ;; + + 'Darwin') + if [ $STATIC = 1 ] ; then + LIBNAME="lib${LIBNAME}.a" + echo "mklib: Making Darwin static library: " ${LIBNAME} + LINK="ar" + OPTS="-ruvs" + if [ "${ALTOPTS}" ] ; then + OPTS=${ALTOPTS} + fi + ${LINK} ${OPTS} ${LIBNAME} ${OBJECTS} + FINAL_LIBS=${LIBNAME} + else + # On Darwin a .bundle is used for a library that you want to dlopen + if [ $DLOPEN = "1" ] ; then + LIBSUFFIX="bundle" + OPTS="${ARCHOPT} -bundle -multiply_defined suppress" + else + LIBSUFFIX="dylib" + OPTS="${ARCHOPT} -dynamiclib -multiply_defined suppress -current_version ${MAJOR}.${MINOR}.0 -compatibility_version ${MAJOR}.${MINOR}.0 -install_name lib${LIBNAME}.${MAJOR}.${LIBSUFFIX}" + fi + + if [ ${EXPORTS} ] ; then + OPTS="${OPTS} -exported_symbols_list ${EXPORTS}" + fi + + LINKNAME="lib${LIBNAME}.${MAJOR}.${LIBSUFFIX}" + LINKNAME2="lib${LIBNAME}.${LIBSUFFIX}" + LIBNAME="lib${LIBNAME}.${MAJOR}.${MINOR}.${LIBSUFFIX}" + + # examine first object to determine ABI + set ${OBJECTS} + ABI_PPC=`file $1 | grep ' ppc'` + ABI_I386=`file $1 | grep ' i386'` + ABI_PPC64=`file $1 | grep ' ppc64'` + ABI_X86_64=`file $1 | grep ' x86_64'` + if [ "${ABI_PPC}" ] ; then + OPTS="${OPTS} -arch ppc" + fi + if [ "${ABI_I386}" ] ; then + OPTS="${OPTS} -arch i386" + fi + if [ "${ABI_PPC64}" ] ; then + OPTS="${OPTS} -arch ppc64" + fi + if [ "${ABI_X86_64}" ] ; then + OPTS="${OPTS} -arch x86_64" + fi + + if [ "${ALTOPTS}" ] ; then + OPTS=${ALTOPTS} + fi + + # XXX can we always add -isysroot /Developer/SDKs/MacOSX10.4u.sdk + # to OPTS here? + + # determine linker + if [ $CPLUSPLUS = 1 ] ; then + LINK="g++" + else + LINK="cc" + fi + + echo "mklib: Making Darwin shared library: " ${LIBNAME} + + ${LINK} ${OPTS} ${LDFLAGS} -o ${LIBNAME} ${OBJECTS} ${DEPS} + ln -s ${LIBNAME} ${LINKNAME} + ln -s ${LIBNAME} ${LINKNAME2} + FINAL_LIBS="${LIBNAME} ${LINKNAME} ${LINKNAME2}" + fi + ;; + + 'LynxOS') + LIBNAME="lib${LIBNAME}.a" + echo "mklib: Making LynxOS static library: " ${LIBNAME} + rm -f ${LIBNAME} + ar ru ${LIBNAME} ${OBJECTS} + FINAL_LIBS=${LIBNAME} + ;; + + 'BeOS') + if [ $STATIC = 1 ] ; then + LIBNAME="lib${LIBNAME}.a" + echo "mklib: Making BeOS static library: " ${LIBNAME} + ar -cru "${LIBNAME}" ${OBJECTS} + else + LIBNAME="lib${LIBNAME}.so" + echo "mklib: Making BeOS shared library: " ${LIBNAME} + gcc -nostart -Xlinker "-soname=${LIBNAME}" -L/Be/develop/lib/x86 -lbe ${DEPS} ${OBJECTS} -o "${LIBNAME}" + mimeset -f "${LIBNAME}" + # XXX remove the Mesa3D stuff here since mklib isn't mesa-specific. + setversion "${LIBNAME}" -app ${MAJOR} ${MINOR} ${PATCH} -short "Powered by Mesa3D!" -long "Powered by Mesa3D!" + fi + FINAL_LIBS=${LIBNAME} + ;; + + 'QNX') + LIBNAME="lib${LIBNAME}.a" + echo "mklib: Making QNX library: " ${LIBNAME} + wlib ${LIBNAME} ${OBJECTS} + FINAL_LIBS=${LIBNAME} + ;; + + 'MorphOS') + LIBNAME="lib${LIBNAME}.a" + echo "mklib: Making MorphOS library: " ${LIBNAME} + ppc-morphos-ar rc ${LIBNAME} ${OBJECTS} + FINAL_LIBS="${LIBNAME}" + ;; + + 'icc' | 'icc-istatic') + # Intel C compiler + # This should get merged into the Linux code, above, since this isn't + # really a different architecture. + LIBNAME="lib${LIBNAME}" # prefix with "lib" + + if [ $STATIC = 1 ] ; then + echo "mklib: Making Intel ICC static library: " ${LIBNAME}.a + LINK="ar" + OPTS="-ruv" + if [ "${ALTOPTS}" ] ; then + OPTS=${ALTOPTS} + fi + # make lib + ${LINK} ${OPTS} ${LIBNAME}.a ${OBJECTS} + # finish up + FINAL_LIBS="${LIBNAME}.a" + else + if [ $ARCH = icc-istatic ] ; then + OPTS="-shared -i-static -cxxlib-icc" + else + OPTS="-shared" + fi + if [ "${ALTOPTS}" ] ; then + OPTS=${ALTOPTS} + fi + VERSION="${MAJOR}.${MINOR}.${PATCH}" + echo "mklib: Making Intel ICC shared library: " ${LIBNAME}.so.${VERSION} + + if [ $CPLUSPLUS = 1 ] ; then + LINK="icpc" + else + LINK="icc" + fi + # rm any old libs + rm -f ${LIBNAME}.so.${VERSION} + rm -f ${LIBNAME}.so.${MAJOR} + rm -f ${LIBNAME}.so + # make lib + ${LINK} ${OPTS} ${LDFLAGS} -o ${LIBNAME}.so.${VERSION} ${OBJECTS} ${DEPS} + # make usual symlinks + ln -s ${LIBNAME}.so.${VERSION} ${LIBNAME}.so.${MAJOR} + ln -s ${LIBNAME}.so.${MAJOR} ${LIBNAME}.so + # finish up + FINAL_LIBS="${LIBNAME}.so.${VERSION} ${LIBNAME}.so.${MAJOR} ${LIBNAME}.so" + fi + ;; + + 'aix-gcc') + # AIX with gcc + if [ $STATIC = 1 ] ; then + LIBNAME="lib${LIBNAME}.a" + echo "mklib: Making AIX GCC static library: " ${LIBNAME} + rm -f ${LIBNAME} + ar ru ${LIBNAME} ${OBJECTS} + FINAL_LIBS=${LIBNAME} + else + LIBNAME="lib${LIBNAME}.so" # prefix with "lib", suffix with ".so" + echo "mklib: Making AIX GCC shared library: " ${LIBNAME} + # remove old lib + rm -f ${LIBNAME} + # make the lib + gcc -shared -Wl,-G ${OBJECTS} ${DEPS} -o ${LIBNAME} + # NOTE: the application linking with this library must specify + # the -Wl,-brtl flags to gcc + FINAL_LIBS=${LIBNAME} + fi + ;; + + 'ultrix') + # XXX untested + if [ $STATIC = 0 ] ; then + echo "mklib: Warning shared libs not supported on Ultrix" + fi + LIBNAME="lib${LIBNAME}.a" + echo "mklib: Making static library for Ultrix: " ${LIBNAME} + rm -f ${LIBNAME} + ar ru ${LIBNAME} ${OBJECTS} + FINAL_LIBS="${LIBNAME}" + ;; + + CYGWIN*) + # GCC-based environment + CYGNAME="cyg${LIBNAME}" # prefix with "cyg" + LIBNAME="lib${LIBNAME}" # prefix with "lib" + + if [ $STATIC = 1 ] ; then + echo "mklib: Making" $ARCH "static library: " ${LIBNAME}.a + LINK="ar" + OPTS="-ru" + if [ "${ALTOPTS}" ] ; then + OPTS=${ALTOPTS} + fi + # make lib + ${LINK} ${OPTS} ${LIBNAME}.a ${OBJECTS} + ranlib ${LIBNAME}.a + # finish up + FINAL_LIBS=${LIBNAME}.a + else + OPTS="-shared -Wl,-export-all -Wl,--out-implib=${LIBNAME}-${MAJOR}.dll.a" + if [ "${ALTOPTS}" ] ; then + OPTS=${ALTOPTS} + fi + echo "mklib: Making" $ARCH "shared library: " ${LIBNAME}-${MAJOR}.dll + + if [ $CPLUSPLUS = 1 ] ; then + LINK="g++" + else + LINK="gcc" + fi + + # rm any old libs + rm -f ${LIBNAME}-${MAJOR}.dll + rm -f ${LIBNAME}.dll.a + rm -f ${LIBNAME}.a + + # make lib + ${LINK} ${OPTS} ${LDFLAGS} -o ${CYGNAME}-${MAJOR}.dll ${OBJECTS} ${DEPS} + # make usual symlinks + ln -s ${LIBNAME}-${MAJOR}.dll.a ${LIBNAME}.dll.a + # finish up + FINAL_LIBS="${LIBNAME}-${MAJOR}.dll.a ${LIBNAME}.dll.a" + # special case for installing in bin + FINAL_BINS="${CYGNAME}-${MAJOR}.dll" + fi + ;; + + 'example') + # If you're adding support for a new architecture, you can + # start with this: + if [ $STATIC = 1 ] ; then + LIBNAME="lib${LIBNAME}.a" + echo "mklib: Making static library for example arch: " ${LIBNAME} + rm -f ${LIBNAME} + ar rv ${LIBNAME} ${OBJECTS} + FINAL_LIBS="${LIBNAME}" + else + LIBNAME="lib${LIBNAME}.so" # prefix with "lib", suffix with ".so" + echo "mklib: Making shared library for example arch: " ${LIBNAME} + ld -o ${LIBNAME} ${OBJECTS} ${DEPS} + FINAL_LIBS="${LIBNAME}" + fi + ;; + + *) + echo "mklib: ERROR: Don't know how to make a static/shared library for" ${ARCH} + echo "mklib: Please add necessary commands to mklib script." + ;; +esac + + +# +# Put library files into installation directory if specified. +# +if [ ${INSTALLDIR} != "." ] ; then + echo "mklib: Installing" ${FINAL_LIBS} "in" ${INSTALLDIR} + mv ${FINAL_LIBS} ${INSTALLDIR}/ +fi diff --git a/xpa/notes/osx.note b/xpa/notes/osx.note new file mode 100644 index 0000000..6ba68a7 --- /dev/null +++ b/xpa/notes/osx.note @@ -0,0 +1,38 @@ +Mac OS X Leopard v10.5 (MB427Z/A) + +The process has forked and you cannot use this CoreFoundation + +http://developer.apple.com/releasenotes/CoreFoundation/CoreFoundation.html + +CoreFoundation and fork() Due to the behavior of fork(), +CoreFoundation cannot be used on the child-side of fork(). If you +fork(), you must follow that with an exec*() call of some sort, and +you should not use CoreFoundation APIs within the child, before the +exec*(). The applies to all higher-level APIs which use +CoreFoundation, and since you cannot know what those higher-level APIs +are doing, and whether they are using CoreFoundation APIs, you should +not use any higher-level APIs either. This includes use of the +daemon() function. + +Additionally, per POSIX, only async-cancel-safe functions are safe to +use on the child side of fork(), so even use of lower-level +libSystem/BSD/UNIX APIs should be kept to a minimum, and ideally to +only async-cancel-safe functions. + +This has always been true, and there have been notes made of this on +various Cocoa developer mailling lists in the past. But CoreFoundation +is taking some stronger measures now to "enforce" this limitation, so +we thought it would be worthwhile to add a release note to call this +out as well. A message is written to stderr when something uses API +which is definitely known not to be safe in CoreFoundation after +fork(). If file descriptor 2 has been closed, however, you will get no +message or notice, which is too bad. We tried to make processes +terminate in a very recognizable way, and did for a while and that was +very handy, but backwards binary compatibility prevented us from doing +so. + +-------------- + +This is the function you set a debug breakpoint on if you try to fork() in Leopard then call a CoreFoundation method: + +void __THE_PROCESS_HAS_FORKED_AND_YOU_CANNOT_USE_THIS_COREFOUNDATION_FUNCTIONALITY___YOU_MUST_EXEC__(void); diff --git a/xpa/notes/winport.note b/xpa/notes/winport.note new file mode 100644 index 0000000..fb7b46d --- /dev/null +++ b/xpa/notes/winport.note @@ -0,0 +1,81 @@ +Documentation: + +The URL: + + http://msdn.microsoft.com/library + +has a good Unix Application Migration Guide as well as Win32 API. + + MINGW32 +Problems: + +client.c: + +The select() function does not work on stdio files, so xpaset cannot add +stdio to select(). This means that "cat foo.fits | xpaset ds9" is not +implemented. This is a client side problem and would not affect ds9 running +as an xpa server. + +xpaio.c and others: + +Win32 does not support most Unix signal handling, and in particular, the +SIGALRM signal. This means that XPA will hang indefinitely on a system +call, i.e., there is no timeout support corresponding to XPA_LONG_TIMEOUT +and XPA_SHORT_TIMEOUT. This affects both clients and servers. + +timedconn.c: + +Again, lack of support for SIGALRM means alrmconnect() is not implemented. +For some reason, noblkconect() also did not work properly, so I had to +use theregular connect() in client.c and hang until further notice. This +is a client side problem and would not affect ds9 as an xpa server. + +launch.c: + +Without fork(), its not obvious how to make the code wait for the +child to start. In the end, I used simply called win32 spawnvp(), put +a short sleep into the parent, and hoped for the best. + +find.c: + +Couldn't find the access mode bits (S_IRUSR, S_IWUSR, S_IXUSR) in win32, +so access checking in find() is not supported. + +Code Changes: + +xpa.c, client.c (sockets) + +Ironically, wsock64 has an FD_SETSIZE of 64 and I had to redefine this to +8192 to make XPA sockets work. + +For wsock32 sockets, we must initialize wsock32 using: + + WSADATA wsaData; + ... + if( WSAStartup(MAKEWORD(2,0), &wsaData) ) != 0 ) {handle error}; + +and clean up at the time of exit: + + WSACleanup(); + +The close(sock) call is replaced by closesocket(sock). + +The call: + + fcntl(sock, F_SETFD, FD_CLOEXEC); + +is not needed or implemented (since sockets do not survive across exec) and +must be commented out. + +Calls to: + + flags = fcntl(client->datafd, F_GETFL); + fcntl(client->datafd, F_SETFL, flags|NONBIO); + +get changed to: + + int flags=1; + ioctlsocket(socket, FIONBIO, (u_long FAR *)&flags); + + + diff --git a/xpa/pkgIndex.tcl b/xpa/pkgIndex.tcl new file mode 100644 index 0000000..75d2435 --- /dev/null +++ b/xpa/pkgIndex.tcl @@ -0,0 +1,11 @@ +# Tcl package index file, version 1.1 +# This file is generated by the "pkg_mkIndex -direct" command +# and sourced either when an application starts up or +# by a "package unknown" script. It invokes the +# "package ifneeded" command to set up package-related +# information so that packages will be loaded automatically +# in response to "package require" commands. When this +# script is sourced, the variable $dir must contain the +# full path name of this file's directory. + +package ifneeded tclxpa 2.1 [list load [file join $dir libtclxpa.so]] diff --git a/xpa/port.c b/xpa/port.c new file mode 100644 index 0000000..f3751ac --- /dev/null +++ b/xpa/port.c @@ -0,0 +1,345 @@ +/* + * Copyright (c) 1999-2003 Smithsonian Astrophysical Observatory + */ + +/* + * + * port.c -- xpa port management + * + */ + +#include <xpap.h> + +/* + *---------------------------------------------------------------------------- + * + * + * Private Routines + * + * + *---------------------------------------------------------------------------- + */ + +/* this is the head of the global list -- too lazy to do anything more */ +static PORT porthead=NULL; + +#ifdef ANSI_FUNC +static PORT +XPAPortLookup (char *xclass, char *name) +#else +static PORT XPAPortLookup(xclass, name) + char *xclass; + char *name; +#endif +{ + PORT cur; + /* look for exact match */ + for(cur=porthead; cur!=NULL; cur=cur->next){ + if( !strcmp(xclass, cur->xclass) && + !strcmp(name, cur->name) ){ + return(cur); + } + } + /* otherwise look for a template match */ + for(cur=porthead; cur!=NULL; cur=cur->next){ + if( tmatch(xclass, cur->xclass) && + tmatch(name, cur->name) ){ + return(cur); + } + } + return(NULL); +} + +/* + *---------------------------------------------------------------------------- + * + * Routine: XPAPortParse + * + * Purpose: parse port list into components + * + * Returns: 0 on success, -1 on failure + * + *---------------------------------------------------------------------------- + */ +#ifdef ANSI_FUNC +static int +XPAPortParse (char *lbuf, char *xclass, char *name, int *port, int len) +#else +static int XPAPortParse(lbuf, xclass, name, port, len) + char *lbuf; + char *xclass; + char *name; + int *port; + int len; +#endif +{ + char tbuf[SZ_LINE]; + int lp=0; + + /* init port values */ + *port = 0; + + /* class:name is required */ + if( word(lbuf, tbuf, &lp) ){ + XPAParseName(tbuf, xclass, name, len); + } + else{ + return(-1); + } + + /* port is required but can be "*" for default port */ + if( word(lbuf, tbuf, &lp) ){ + if( !strcmp(tbuf, "*") ) + *port = XPA_DEFPORT; + else + *port = atoi(tbuf); + } + else{ + return(-1); + } + + /* made it */ + return(0); +} + +/*---------------------------------------------------------------------------- + * + * + * Public Routines + * + * + *---------------------------------------------------------------------------- + */ + +/* + *---------------------------------------------------------------------------- + * + * Routine: XPAPortAdd + * + * Purpose: add one port entry to the xpa port list + * + * Returns: 0 on success, -1 on failure + * + *---------------------------------------------------------------------------- + */ +#ifdef ANSI_FUNC +int +XPAPortAdd (char *lbuf) +#else +int XPAPortAdd(lbuf) + char *lbuf; +#endif +{ + PORT xnew; + PORT cur; + char xclass[SZ_LINE]; + char name[SZ_LINE]; + int port; + + /* allocate port struct */ + if( (xnew = (PORT)xcalloc(1, sizeof(struct portrec))) == NULL ) + goto error; + + /* parse info from line buffer */ + if( XPAPortParse(lbuf, xclass, name, &port, SZ_LINE) < 0 ) + goto error; + + /* fill in the blanks */ + xnew->xclass = xstrdup(xclass); + xnew->name = xstrdup(name); + xnew->port = port; + + /* add this port to end of list of port's */ + if( porthead == NULL ){ + porthead = xnew; + } + else{ + for(cur=porthead; cur->next!=NULL; cur=cur->next) + ; + cur->next = xnew; + } + return(0); + +error: + if( xnew ) + xfree(xnew); + return(-1); +} + +/* + *--------------------------------------------------------------------------- + * + * Routine: XPAPortDel + * + * Purpose: free up alloc'ed memory in the port record structure + * + * Results: 0 on success, -1 for failure + * + *--------------------------------------------------------------------------- + */ +#ifdef ANSI_FUNC +int +XPAPortDel (PORT port) +#else +int XPAPortDel(port) + PORT port; +#endif +{ + PORT cur; + + if( port == NULL ) + return(-1); + + /* remove from list of port's */ + if( porthead ){ + if( porthead == port ){ + porthead = porthead->next; + } + else{ + for(cur=porthead; cur!=NULL; cur=cur->next){ + if( cur->next == port ){ + cur->next = (cur->next)->next; + break; + } + } + } + } + + /* free up string space */ + if( port->xclass ) xfree(port->xclass); + if( port->name ) xfree(port->name); + + /* free up record struct */ + xfree((char *)port); + return(0); +} + +/* + *---------------------------------------------------------------------------- + * + * Routine: XPAPortFree + * + * Purpose: + * + * Results: 1 on success, 0 for failure + * + *---------------------------------------------------------------------------- + */ +#ifdef ANSI_FUNC +void +XPAPortFree (void) +#else +void XPAPortFree() +#endif +{ + PORT cur; + PORT saveport; + + for(cur=porthead; cur!=NULL; ){ + saveport = cur->next; + XPAPortDel(cur); + cur = saveport; + } +} + +/* + *---------------------------------------------------------------------------- + * + * Routine: XPAPortNew + * + * Purpose: read or re-read the port list + * + * Results: number of lines in list (including default) + * + *---------------------------------------------------------------------------- + */ +#ifdef ANSI_FUNC +int +XPAPortNew (char *aname, int flag) +#else +int XPAPortNew(aname, flag) + char *aname; + int flag; +#endif +{ + int got=0; + char lbuf[SZ_LINE]; + char *s; + char *portname=NULL; + char *portpath=NULL; + char *portstr=NULL; + char *portcopy=NULL; + FILE *fp; + + /* if there is an old list, free it */ + if( flag == 0 ) + XPAPortFree(); + + /* get port file name */ + if( aname && *aname ) + portname = aname; + else if( (portname=(char *)getenv("XPA_PORTFILE")) == NULL ) + portname = XPA_PORTFILE; + + /* get the default port */ + portstr=(char *)getenv("XPA_PORT"); + + /* add the port assignments from environment first */ + if( portstr && *portstr ){ + portcopy=(char *)xstrdup(portstr); + for(s=(char *)strtok(portcopy,";"); s!=NULL; s=(char *)strtok(NULL,";")){ + if( XPAPortAdd(s) == 0 ) + got++; + } + if( portcopy) xfree(portcopy); + } + + /* add the port assignments from file next */ + if( (portpath=(char *)Access(portname, "r")) != NULL ){ + if( (fp=fopen(portpath, "r")) != NULL ){ + while( fgets(lbuf, SZ_LINE, fp) ){ + if( *lbuf == '#' ){ + continue; + } + if( XPAPortAdd(lbuf) == 0 ) + got++; + } + fclose(fp); + } + xfree(portpath); + } + + /* return the news */ + return(got); +} + +/* + *---------------------------------------------------------------------------- + * + * Routine: XPAPort + * + * Purpose: check for pre-defined port for a given class, name and + * 1 for com port, 2 for data port + * + * Results: assigned port or 0 + * + *---------------------------------------------------------------------------- + */ +#ifdef ANSI_FUNC +int +XPAPort (XPA xpa) +#else +int XPAPort(xpa) + XPA xpa; +#endif +{ + int p=0; + PORT cur; + + if( xpa == NULL ) + return 0; + if( (cur = XPAPortLookup(xpa->xclass, xpa->name)) ){ + p = cur->port; + } + return p; +} diff --git a/xpa/prsetup.h b/xpa/prsetup.h new file mode 100644 index 0000000..e629156 --- /dev/null +++ b/xpa/prsetup.h @@ -0,0 +1,58 @@ +/* + * Copyright (c) 1999-2003 Smithsonian Astrophysical Observatory + */ + +/* prsetup.h -- define variables for ANSI prototyping */ + +#ifndef _prsetup +#define _prsetup + +#ifdef NO_ANSI_FUNC +#define _PRbeg +#define _PRend +#define _PRx(s) () +#ifdef ANSI_FUNC +#undef ANSI_FUNC +#endif +#else +#if defined(__cplusplus) || defined(c_plusplus) +#define _PRbeg extern "C" { /* do not leave open across includes */ +#define _PRend } +#define _PRx(s) s +#define ANSI_FUNC 1 +#else +#if defined(__STDC__) +#define _PRbeg +#define _PRend +#define _PRx(s) s +#define ANSI_FUNC 1 +#else +#define _PRbeg +#define _PRend +#define _PRx(s) () +#ifdef ANSI_FUNC +#undef ANSI_FUNC +#endif +#endif +#endif +#endif + +/* the ever-present */ +#ifndef SZ_LINE +#define SZ_LINE 4096 +#endif + +#ifndef MIN +#define MIN(a,b) (((a)<(b))?(a):(b)) +#endif + +#ifndef MAX +#define MAX(a,b) (((a)>(b))?(a):(b)) +#endif + +#ifndef ABS +#define ABS(x) ((x)<0?(-(x)):(x)) +#endif + +#endif + diff --git a/xpa/python/PythonXPA/README b/xpa/python/PythonXPA/README new file mode 100644 index 0000000..9c803db --- /dev/null +++ b/xpa/python/PythonXPA/README @@ -0,0 +1,25 @@ +Hi Eric, + +it's me again. Hope everything is ok with you. + +I started working with python and because python 2.5 comes with ctypes +included I started to wrap some XPA functionality. In the web I only +found PyXPA 0.2 which is very alpha. And with ctypes, we don't need any +c-code linked in, python package is enough. + +Although I have wrapped only the functionality I need for now, I think +it is already usable. And, of course, when you or anyone is interested +in it, I can easily add more functionality. + +There is no installation needed. Just adjust the path to your libxpa.so +in XPAClient.py and XPAServer.py and optionally adjust NXPA in +XCPAClient.py. + +Then you can start stest and run test_XPAC.py or run test_XPAS.py and +issue some xpainfo/get/set commands. + + + +Regards, +Bernhard + diff --git a/xpa/python/PythonXPA/client/XPAClient.py b/xpa/python/PythonXPA/client/XPAClient.py new file mode 100644 index 0000000..29e39eb --- /dev/null +++ b/xpa/python/PythonXPA/client/XPAClient.py @@ -0,0 +1,98 @@ + +import sys +from ctypes import * + +libxpa=cdll.LoadLibrary("../../libxpa.so.1.0") +libc=cdll.LoadLibrary(None); + + +#xpa_t = c_void_p +#xpa = xpa_t(None) + +c_byte_p = POINTER(c_byte) + + + +############## + +NXPA = 10 + +############## + + +def free_bufs(p_arr, len): + for i in range(len): + if p_arr[i]: + print "freeing [", i, "] ", p_arr[i][0], p_arr[i][1] + libc.free(p_arr[i]) + + + + + +## XPA XPAOpen(char *mode); + +XPAOpen = libxpa.XPAOpen +libxpa.XPAOpen.restype = c_void_p +libxpa.XPAOpen.argtypes = [c_char_p] + +## void XPAClose(XPA xpa); +XPAClose = libxpa.XPAClose +libxpa.XPAClose.argtypes = [c_void_p] + + +## int XPAGet(XPA xpa, char *template, char *paramlist, char *mode, +## char **bufs, int *lens, char **names, char **messages, int n); + +XPAGet = libxpa.XPAGet +libxpa.XPAGet.restype = c_int +libxpa.XPAGet.argtypes = [c_void_p, c_char_p, c_char_p, c_char_p, \ + c_byte_p*NXPA, c_int*NXPA, c_byte_p*NXPA, c_byte_p*NXPA, \ + c_int] + + +## when you want to send something like "hello\0x00 you" use this + +## int XPASet(XPA xpa, +## char *template, char *paramlist, char *mode, +## char *buf, int len, char **names, char **messages, +## int n); + +#libxpa.XPASet.restype = c_int +#libxpa.XPASet.argtypes = [c_void_p, c_char_p, c_char_p, c_char_p, \ +# c_byte_p, c_int, c_char_p*NXPA, c_char_p*NXPA, \ +# c_int] + +## when you know, you will send strings only, use this one to avoid conversions + +XPASet = libxpa.XPASet +libxpa.XPASet.restype = c_int +libxpa.XPASet.argtypes = [c_void_p, c_char_p, c_char_p, c_char_p, \ + c_char_p, c_int, c_byte_p*NXPA, c_byte_p*NXPA, \ + c_int] + +## int XPAInfo(XPA xpa, +## char *template, char *paramlist, char *mode, +## char **names, char **messages, int n); + +XPAInfo = libxpa.XPAInfo +libxpa.XPAInfo.restype = c_int +libxpa.XPAInfo.argtypes = [c_void_p, c_char_p, c_char_p, c_char_p, \ + c_byte_p*NXPA, c_byte_p*NXPA, \ + c_int] + +## int XPAAccess(XPA xpa, +## char *template, char *paramlist, char *mode, +## char **names, char **messages, int n); + +XPAAccess = libxpa.XPAAccess +libxpa.XPAAccess.restype = c_int +libxpa.XPAAccess.argtypes = [c_void_p, c_char_p, c_char_p, c_char_p, \ + c_byte_p*NXPA, c_byte_p*NXPA, \ + c_int] + +#del libxpa + + + + diff --git a/xpa/python/PythonXPA/client/test_XPAC.py b/xpa/python/PythonXPA/client/test_XPAC.py new file mode 100755 index 0000000..7111a98 --- /dev/null +++ b/xpa/python/PythonXPA/client/test_XPAC.py @@ -0,0 +1,104 @@ +#!/usr/bin/python + +################################ +####### testing: # +####### please start "stest" # +################################ + +from XPAClient import * + +import time + +xpa = None +print xpa +xpa = XPAOpen("ack=false") +############################ +print xpa + +buff_t = c_byte_p*NXPA + +buffs = buff_t() +names = buff_t() +messages = buff_t() + + + +int_t = c_int*NXPA +lens = int_t() + +ok = True +while ok: + #ok = False + print "--- XPAGet Test 1" + n = XPAGet(xpa, "XPA:xpa*", "help", "ack=false", buffs, lens, names, \ + messages, NXPA) + ######################################################################### + print n + print buffs[0][0:lens[0]], "\n", buffs[1][0:lens[1]] + print string_at(names[0]), string_at(names[1]) + + for j in range(n): + ascii_text = string_at(buffs[j], lens[j]) + #ascii_text = ''.join(chr(buffs[j][i]) for i in range(0, lens[j])) + print "---", j, "---\n>>>\n" + ascii_text + "\n<<<" + + free_bufs(buffs, NXPA) + free_bufs(names, NXPA) + free_bufs(messages, NXPA) + + + print "--- XPASet Test 1" + txt = "Hey, you!" + n = XPASet(xpa, "XPA:xpa", "", "", txt, len(txt), names, messages, NXPA) + ######################################################################### + print string_at(names[0]) + free_bufs(names, NXPA) + free_bufs(messages, NXPA) + + #sys.exit(0) + + print "--- XPAGet Test 2" + n = XPAGet(xpa, "XPA:xpa[12]", "error", "", buffs, lens, names, \ + messages, NXPA) + ######################################################################### + print n + print ":::: " + if names[0]: + print "\t names[0]: ", string_at(names[0]) + if names[1]: + print "\t names[1]: ", string_at(names[1]) + + free_bufs(buffs, NXPA) + free_bufs(names, NXPA) + free_bufs(messages, NXPA) + + print "--- XPAInfo Test 1" + n = XPAInfo(xpa, "XPA:i_xpa", "hey there", "", names, messages, NXPA) + ######################################################################### + print n + if names: + free_bufs(names, NXPA) + if messages: + free_bufs(messages, NXPA) + + n = XPAAccess(xpa, "XPA:*", "", "", names, messages, NXPA) + ######################################################################### + print n + for j in range(n): + print "access ---", j, "--- >>>" + string_at(names[j]) + "<<<" + + if names: + free_bufs(names, NXPA) + if messages: + free_bufs(messages, NXPA) + + + + #time.sleep(0.010) + + + +XPAClose(xpa) +############### +xpa = None + diff --git a/xpa/python/PythonXPA/server/XPAServer.py b/xpa/python/PythonXPA/server/XPAServer.py new file mode 100644 index 0000000..4c46ed3 --- /dev/null +++ b/xpa/python/PythonXPA/server/XPAServer.py @@ -0,0 +1,125 @@ + +from ctypes import * + +x=cdll.LoadLibrary("../libxpa.so.1.0") + + +c_byte_p = POINTER(c_byte) + + +## int XPAPoll(int msec, int maxreq); + +XPAPoll = x.XPAPoll +x.XPAPoll.restype = c_int +x.XPAPoll.argtypes = [c_int, c_int] + + + + +## typedef struct xparec{ +## /* xpa version */ +## char *version; +## /* status of this xpa */ +## int status; +## /* "g", "s", "i" are server types; "c" for client */ +## char *type; +## /* +## * THE SERVER SIDE +## */ +## struct xparec *next; +## char *xclass; +## char *name; +## char *help; + +## +## /* and so on */ +## +## } *XPA; + +# ctypes wrapper +class xparec(Structure): + _fields_ = [ ("version", c_char_p), \ + ("status", c_int), \ + ("type", c_char_p), \ + ("next", c_void_p), \ + ("xclass", c_char_p), \ + ("name", c_char_p), \ + ("help", c_char_p) \ + ] + +XPA = POINTER(xparec) + + + + + +## int XPAFree(XPA xpa); + +XPAFree = x.XPAFree +x.XPAFree.restype = c_void_p +x.XPAFree.argtypes = [XPA] + + + +## info callback: +## int info_cb(void *info_data, void *call_data, char *paramlist) + + + +INFOCBFUNC = CFUNCTYPE(c_int, c_char_p, XPA, c_char_p) + +### implement like this: +#def py_infocb_func(a, b, c): +# print "py_cmp_func", a, b +# return 0 +# +#infocb_func = INFOCBFUNC(py_infocb_func) + + + +## XPA XPAInfoNew(char *class, char *name, +## int (*info_callback)(), +## void *info_data, char *info_mode); + +XPAInfoNew = x.XPAInfoNew +x.XPAInfoNew.restype = XPA +x.XPAInfoNew.argtypes = [c_char_p, c_char_p, INFOCBFUNC, c_char_p, c_char_p] + + + + + +## int send_callback(void *send_data, void *call_data, +## char *paramlist, char **buf, int *len) + +SENDCBFUNC = CFUNCTYPE(c_int, c_char_p, XPA, c_char_p, POINTER(c_byte_p), POINTER(c_int)) + +### implement like this: +#def py_sendcb_func(a, data, call_data, param, buf, len): +# print "inside send_callback" +# return 0 +# +#sendcb_func = SENDCBFUNC(py_sendcb_func) + + +## int receive_callback(void *receive_data, void *call_data, +## char *paramlist, char *buf, int len) + +RCVCBFUNC = CFUNCTYPE(c_int, c_char_p, XPA, c_char_p, c_byte_p, c_int) + + + +## XPA XPANew(char *class, char *name, char *help, +## int (*send_callback)(), +## void *send_data, char *send_mode, +## int (*rec_callback)(), +## void *rec_data, char *rec_mode); + +XPANew = x.XPANew +x.XPANew.restype = XPA +x.XPANew.argtypes = [c_char_p, c_char_p, c_char_p, \ + SENDCBFUNC, \ + c_char_p, c_char_p, \ + RCVCBFUNC, \ + c_char_p, c_char_p \ + ] diff --git a/xpa/python/PythonXPA/server/test_XPAS.py b/xpa/python/PythonXPA/server/test_XPAS.py new file mode 100755 index 0000000..fe4f1a2 --- /dev/null +++ b/xpa/python/PythonXPA/server/test_XPAS.py @@ -0,0 +1,91 @@ +#!/usr/bin/python + +################################ +####### testing: # +################################ + +from XPAServer import * + +import time + +print "Poll" +n = x.XPAPoll(10000, 0) +print "got %d" % n + +EXIT_FLAG = False + + +############################## +# setting up Info Point # +############################## + +def py_infocb_func(a, b, c): + global EXIT_FLAG + print ">>> INFO:" + print "params:", c + print "info:", a + print "XPA.name", b[0].name + print "<<<" + if (c[0:4] == "exit"): + print "setting EXIT_FLAG" + EXIT_FLAG = True + return 0 + +infocb_func = INFOCBFUNC(py_infocb_func) + +xpa = XPAInfoNew("XPA", "i_test", infocb_func, "my info", "") + +############################## + + + + +####################################### +# setting up AccessPoint Get/Set # +####################################### + +def py_sendcb_func(data, call_data, param, buf, len): + print "inside send_callback" + print "param:", param + print "buf:", string_at(buf) + buf[0] = cast("this is test only\n", c_byte_p) + len[0] = 19 + return 0 + +sendcb_func = SENDCBFUNC(py_sendcb_func) + + +def py_rcvcb_func(data, call_data, param, buf, len): + print "inside rcv_callback" + print "param:", param + print "got %d bytes" % len + print "buf:", string_at(buf) + return 0 + +rcvcb_func = RCVCBFUNC(py_rcvcb_func) + + +xpa2 = XPANew("XPA", "myxpa", "this is great help", + sendcb_func, + "SEND_DATA", "freebuf=false", + rcvcb_func, + "", "") + + + + + +############################## +print "Entering loop" + +while EXIT_FLAG == False: + n = XPAPoll(1000, 1) + print "got:", n + +print "loop finished" +############################## + + +print "calling XPAFree" +XPAFree(xpa) +XPAFree(xpa2) diff --git a/xpa/remote.c b/xpa/remote.c new file mode 100644 index 0000000..1b1689c --- /dev/null +++ b/xpa/remote.c @@ -0,0 +1,280 @@ +/* + * Copyright (c) 1999-2003 Smithsonian Astrophysical Observatory + */ + +/* + * + * remote.c -- xpa access control list management + * + */ + +#include <xpap.h> + +/* + *---------------------------------------------------------------------------- + * + * + * Private Routines + * + * + *---------------------------------------------------------------------------- + */ + +/* + *---------------------------------------------------------------------------- + * + * + * Semi-Public Routines (used by command.c) + * + * + *---------------------------------------------------------------------------- + */ + +/* + *---------------------------------------------------------------------------- + * + * Routine: XPAReceiveRemote + * + * Purpose: establish remote connection with specified acls + * + * Returns: xpa callback error codes + * + *---------------------------------------------------------------------------- + */ +#ifdef ANSI_FUNC +int +XPAReceiveRemote (void *client_data, void *call_data, char *paramlist, + char *buf, size_t len) +#else +int XPAReceiveRemote(client_data, call_data, paramlist, buf, len) + void *client_data; + void *call_data; + char *paramlist; + char *buf; + size_t len; +#endif +{ + XPA xpa = (XPA)call_data; + XPA cxpa; + char *mode=NULL; + char host[SZ_LINE]; + char acl[SZ_LINE]; + char which[SZ_LINE]; + char tbuf[SZ_LINE]; + int lp=0; + + /* make sure we are using inet sockets */ + if( XPAMtype() != XPA_INET ){ + snprintf(tbuf, SZ_LINE, "remote requires that XPA_METHOD be 'inet'\n"); + XPAError(xpa, tbuf); + return(-1); + } + + /* see if we are connecting to a particular host */ + if( paramlist && *paramlist ){ + cxpa = xpa; + /* arg1: host */ + if( !word(paramlist, host, &lp) ){ + goto error; + } + /* arg2: acl (optional) or -proxy */ + if( !word(paramlist, acl, &lp) ){ + strcpy(acl, "+"); + } + /* arg3: -proxy to set up proxy processing + or acl (if other word was -proxy) */ + else{ + if( !strcmp(acl, "-proxy") ){ + mode="proxy=true"; + if( !word(paramlist, acl, &lp) ){ + strcpy(acl, "+"); + } + } + else if( word(paramlist, which, &lp) ){ + if( !strcmp(which, "-proxy") ){ + mode="proxy=true"; + } + else{ + goto error; + } + } + } + /* make the call */ + if( XPARemote(cxpa, host, acl, mode) >= 0 ){ + return(0); + } + else{ + snprintf(tbuf, SZ_LINE, "remote xpans %s failed to process %s\n", + host, xpa->name); + XPAError(xpa, tbuf); + return(-1); + } + } + else{ + goto error; + } + +error: + XPAError(xpa, "syntax error: -remote hostname:port [acl] [-proxy]\n"); + return(-1); +} + +/* + *---------------------------------------------------------------------------- + * + * Routine: XPASendRemote + * + * Purpose: return the list of remotes for this access point + * + * Returns: 0 for success, -1 for failure + * + *---------------------------------------------------------------------------- + */ +#ifdef ANSI_FUNC +int +XPASendRemote (void *client_data, void *call_data, char *paramlist, + char **buf, size_t *len) +#else +int XPASendRemote(client_data, call_data, paramlist, buf, len) + void *client_data; + void *call_data; + char *paramlist; + char **buf; + size_t *len; +#endif +{ + XPA xpa = (XPA)call_data; + NS ns; + int got = 0; + char tbuf[SZ_LINE]; + + /* list out the remotes */ + for(ns=xpa->nshead; ns!=NULL; ns=ns->next){ + /* skip default ns */ + if( ns->host == NULL ) continue; + snprintf(tbuf, SZ_LINE, "%s %x:%d\n", ns->host, ns->ip, ns->port); + send(xpa_datafd(xpa), tbuf, strlen(tbuf), 0); + got++; + } + if( got == 0 ){ + send(xpa_datafd(xpa), "\n", 1, 0); + } + return(0); +} + +/* + *---------------------------------------------------------------------------- + * + * Routine: XPARemote + * + * Purpose: register the specified XPA (or all XPAs) with the named remote + * name server using the specified acl + * + * Returns: none + * + *---------------------------------------------------------------------------- + */ +#ifdef ANSI_FUNC +int +XPARemote (XPA xpa, char *host, char *acl, char *mode) +#else +int XPARemote(xpa, host, acl, mode) + XPA xpa; + char *host; + char *acl; + char *mode; +#endif +{ + int got=0; + char remote[SZ_LINE]; + char mach[SZ_LINE]; + char lbuf[SZ_LINE]; + char *ind; + XPA cur; + + /* might have to add the "port" to the host to get remote */ + strncpy(remote, host, SZ_LINE-1); + remote[SZ_LINE-1] = '\0'; + if( (ind=strchr(remote, ':')) == NULL ){ + strcat(remote, ":$port"); + } + + /* if no acl is specified, make it '+' */ + if( (acl == NULL) || (*acl == '\0') ){ + acl = "+"; + } + + /* get machine name by removing port suffix */ + strcpy(mach, remote); + if( (ind=strchr(mach, ':')) != NULL ){ + *ind = '\0'; + } + else{ + return(-1); + } + + /* either process the specified xpa, or do all of them */ + if( xpa ){ + cur = xpa; + /* acl="-" => delete, else add */ + if( strcmp(acl, "-") ){ + got=XPANSAdd(cur, remote, mode); + } + else{ + got=XPANSDel(cur, remote, mode); + } + switch(got){ + /* error condition */ + case -1: + return(-1); + /* OK */ + case 0: + snprintf(lbuf, SZ_LINE, "%s:%s %s %s", + cur->xclass, cur->name, mach, acl); + XPAAclEdit(lbuf); + break; + /* entry already exists (OK) */ + case 1: + break; + } + } + else{ + for(cur=XPAListHead(); cur!=NULL; cur=cur->next){ + /* acl="-" => delete, else add */ + if( strcmp(acl, "-") ){ + got=XPANSAdd(cur, remote, mode); + } + else{ + got=XPANSDel(cur, remote, mode); + } + switch(got){ + /* error condition */ + case -1: + return(-1); + /* OK */ + case 0: + snprintf(lbuf, SZ_LINE, "%s:%s %s %s", + cur->xclass, cur->name, mach, acl); + XPAAclEdit(lbuf); + break; + /* entry already exists (OK) */ + case 1: + break; + } + } + } + + /* return OK */ + return(0); +} + +/* + *---------------------------------------------------------------------------- + * + * + * Public Routines + * + * + *---------------------------------------------------------------------------- + */ + diff --git a/xpa/rtest.c b/xpa/rtest.c new file mode 100644 index 0000000..94387a7 --- /dev/null +++ b/xpa/rtest.c @@ -0,0 +1,222 @@ +/* + * Copyright (c) 2004 Smithsonian Astrophysical Observatory + */ + +/* + * + * rtest -- server test for xpa + * + */ +#include <xpap.h> + +#define MAX_XPAS 10 + +extern char *optarg; +extern int optind; + +#define BUFSIZE 1000000 + +char xbuf[BUFSIZE+1]; +size_t xlen; +int quiet=0; + +#ifdef ANSI_FUNC +int send_cb (void *client_data, void *call_data, char *paramlist, + char **buf, size_t *len) +#else +int send_cb(client_data, call_data, paramlist, buf, len) + void *client_data; + void *call_data; + char *paramlist; + char **buf; + size_t *len; +#endif +{ + XPA xpa = (XPA)call_data; + + if( !xpa ) return(-1); + *len = xlen; + *buf = (char *)xmalloc(*len); + memcpy(*buf, xbuf, *len); + if( !quiet ) fprintf(stderr, "sent (%s): %lu\n", + paramlist, (unsigned long)xlen); + return(0); +} + +#ifdef ANSI_FUNC +int receive_cb (void *client_data, void *call_data, char *paramlist, + char *buf, size_t len) +#else +int receive_cb(client_data, call_data, paramlist, buf, len) + void *client_data; + void *call_data; + char *paramlist; + char *buf; + size_t len; +#endif +{ + XPA xpa = (XPA)call_data; + + if( !xpa ) return(-1); + if( !quiet ) fprintf(stderr, "recd (%s): %s\n", paramlist, buf); + return(0); +} + +#ifdef ANSI_FUNC +int +main (int argc, char **argv) +#else +main(argc, argv) + int argc; + char **argv; +#endif +{ + int c; + int i, j; + int got; + int delay=-1; + int total=0; + int dobig=0; + int dofd=0; + int doexit=0; + int poll=1; + int msec=100; + size_t lens[MAX_XPAS]; + char *bufs[MAX_XPAS]; + char *names[MAX_XPAS]; + char *errs[MAX_XPAS]; + char *xmode=""; + char xname[SZ_LINE]; + char xclass[SZ_LINE]; + char paramlist[SZ_LINE]; + + int xfds[1]; + XPA xpa; + + /* we use the xpa timestamp routine */ + putenv("XPA_TIMESTAMP_ERRORS=true"); + + /* process switch arguments */ + while ((c = getopt(argc, argv, "bd:fm:pqv")) != -1){ + switch(c){ + case 'b': + dobig = 1; + break; + case 'd': + delay = atoi(optarg); + break; + case 'f': + dofd = 1; + break; + case 'm': + msec = atoi(optarg); + break; + case 'p': + poll = 0; + break; + case 'q': + quiet = 1; + break; + case 'v': + break; + default: + break; + } + } + /* make sure we have the xpa argument */ + if( optind >= argc ){ + fprintf(stderr, "usage: %s [xpa] [target1 target2 ...]\n", argv[0]); + exit(1); + } + strcpy(xname, argv[optind++]); + strcpy(xclass, xname); + cluc(xclass); + + if( (xpa = XPANew(xclass, xname, "help is on the way", + send_cb, (void *)xname, xmode, + receive_cb, (void *)xname, xmode)) ){ + fprintf(stdout, "%s using method: %s\n", xpa_name(xpa), xpa_method(xpa)); + } + else{ + fprintf(stderr, "ERROR: could not init xpa\n"); + exit(1); + } + + if( dobig ){ + for(i=0; i<BUFSIZE; i++){ + xbuf[i] = 'a' + (i%26); + } + } + else{ + snprintf(xbuf, SZ_LINE, + "%s:%s %s (%s);", + xpa_class(xpa), xpa_name(xpa), xpa_method(xpa), xpa_sendian(xpa)); + } + xlen = strlen(xbuf); + xfds[0] = fileno(stderr); + + fprintf(stdout, "\nEntering select loop ...\n"); + while( 1 ){ + if( poll ){ + fprintf(stderr, "*"); + XPAPoll(msec, 1); + } + else{ + fprintf(stderr, "."); + } + for(doexit=0, j=optind; j<argc; j++){ + snprintf(paramlist, SZ_LINE, "#%d", total++); + if( total && ((total % 1000) == 0) ) fprintf(stderr, "%d", total); + if( dofd ){ + got = XPAGetFd(NULL, argv[j], paramlist, NULL, xfds, names, errs, + -MAX_XPAS); + for(i=0; i<got; i++){ + if( errs[i] ){ + fprintf(stderr, "ERROR in %s:\n%s", names[i], errs[i]); + fprintf(stderr, "Exiting after error\n"); + doexit = 1; + } + } + } + else{ + got = XPAGet(NULL, argv[j], paramlist, NULL, bufs, lens, names, errs, + MAX_XPAS); + for(i=0; i<got; i++){ + if( errs[i] ){ + fprintf(stderr, "ERROR in %s:\n%s", names[i], errs[i]); + fprintf(stderr, "Exiting after error\n"); + doexit = 1; + } + else{ + if( !quiet ) fprintf(stderr, "%s", bufs[i]); + if( bufs[i] ) xfree(bufs[i]); + } + } + } + for(i=0; i<got; i++){ + if( names[i] ) xfree(names[i]); + if( errs[i] ) xfree(errs[i]); + } + if( doexit ) exit(1); + XPASet(NULL, argv[j], paramlist, NULL, xbuf, xlen, names, errs, + MAX_XPAS); + for(i=0; i<got; i++){ + if( errs[i] ){ + fprintf(stderr, "ERROR in %s:\n%s", names[i], errs[i]); + fprintf(stderr, "Exiting after error\n"); + doexit = 1; + } + } + for(i=0; i<got; i++){ + if( names[i] ) xfree(names[i]); + if( errs[i] ) xfree(errs[i]); + } + if( doexit ) goto done; + if( delay > 0 ) XPASleep(delay); + } + } + +done: + XPAFree(xpa); + exit(0); +} diff --git a/xpa/saoconfig b/xpa/saoconfig new file mode 100755 index 0000000..4046822 --- /dev/null +++ b/xpa/saoconfig @@ -0,0 +1,180 @@ +#!/bin/sh +set -x +rm -rf ./config.cache + +if [ x"$1" = x ]; then + name=`uname -n` +else + if [ x"$1" = x"--" ]; then + name=`uname -n` + else + name="$1" + fi + shift +fi + +if [ x"$CFLAGS" = x ]; then + CFLAGS="-g" + export CFLAGS +fi +if [ x"$LDFLAGS" = x ]; then + LDFLAGS="-g" + export LDFLAGS +fi + +GCCFLAGS="-Wall -Wno-implicit-int" +CF="--config-cache" +BIT64="-m64 -mcpu=v9" +LARGEFILE="-D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64" + +# handle saord builds specially +if [ x$name = xsaord ]; then + SAORDPREFIX=/soft/saord + platform=`uname` + case $platform in + SunOS) + SAORDPREFIX=/soft/saord + ;; + esac +fi + +echo "configure for: " $name + +case $name in + cc) + ./configure $CF \ + CC=cc CFLAGS="$CFLAGS" $* + ;; + + gcc) + ./configure $CF \ + CC=gcc CFLAGS="$CFLAGS $GCCFLAGS" $* + ;; + +# Solaris 64bit and largefile suport + large) + ./configure $CF \ + --x-includes=/usr/openwin/include \ + --x-libraries=/usr/openwin/lib/sparcv9 \ + --without-tcl \ + CC=gcc CFLAGS="$CFLAGS $GCCFLAGS $BIT64 $LARGEFILE" \ + LDFLAGS="-g $BIT64 -L/usr/lib/sparcv9" $* + ;; + + opt) + ./configure $CF \ + CC=gcc CFLAGS="$CFLAGS $GCCFLAGS -O2" $* + ;; + + g++) + ./configure $CF \ + CC=g++ CFLAGS="$CFLAGS $GCCFLAGS" $* + ;; + + noansi) + ./configure $CF \ + CC=gcc CFLAGS="$CFLAGS $GCCFLAGS -DNO_ANSI_FUNC" $* + ;; + + dl) + ./configure $CF \ + --enable-dl=yes CC=gcc CFLAGS="$CFLAGS $GCCFLAGS" $* + ;; + + shared) + ./configure $CF \ + --enable-shared=yes \ + CC=gcc CFLAGS="$CFLAGS $GCCFLAGS" \ + $* + ;; + + threads) + ./configure $CF \ + --enable-threaded-xpans \ + CC=cc CFLAGS="$CFLAGS" $* + ;; + + saord*) + ./configure $CF \ + --prefix=$SAORDPREFIX \ + CC=gcc CFLAGS="$CFLAGS -O2" \ + $* + ;; + + bokhara*) + ./configure $CF \ + --prefix=${HOME} \ + CC=gcc CFLAGS="$CFLAGS $GCCFLAGS" $* + ;; + + ds9*) + ./configure $CF \ + --prefix=${HOME} \ + --enable-shared=yes \ + --with-tcl=/proj/rd/eric/saods9/lib \ + CC=gcc CFLAGS="$CFLAGS $GCCFLAGS" $* + ;; + + cfa208*) + ./configure $CF \ + --prefix=${HOME} \ + CC=gcc CFLAGS="$CFLAGS" $* + ;; + + akela*|karapet*) + ./configure $CF \ + --prefix=${HOME} \ + --enable-shared=yes \ + CC=gcc CFLAGS="$CFLAGS $GCCFLAGS" $* + ;; + + ds9*) + ./configure $CF \ + --prefix=${HOME}/eric \ + --enable-shared=yes \ + CC=gcc CFLAGS="$CFLAGS $GCCFLAGS" $* + ;; + + baba*) + ./configure $CF \ + --prefix=${HOME} \ + CC=gcc CFLAGS="$CFLAGS" $* + ;; + + apple*|APPLE*) + ./configure $CF \ + --prefix=${HOME} \ + CC=icc CFLAGS="$CFLAGS" $* + ;; + + mred) + ./configure $CF \ + --prefix=${HOME}/pub/usr/local \ + --enable-threaded-xpans \ + --without-tcl \ + CC=cc CFLAGS="$CFLAGS" $* + ;; + + mocha*|Mocha*|luwak*|*Luwak*|decaf*|Decaf*|barista*|Barista*|knomad*|Knomad*) + ./configure $CF \ + --prefix=/usr/local \ + CC=gcc CFLAGS="$CFLAGS $GCCFLAGS $LARGEFILE -O2" \ + $* + ;; + + voyager*|VOYAGER*) + ./configure $CF \ + --enable-posix_spawn --prefix=${HOME} \ + CC=gcc CFLAGS="$CFLAGS $GCCFLAGS" $* + ;; + + + kitchensink) + ./configure --enable-shared=link --enable-threaded-xpans --with-threads $* + ;; + + *) + ./configure $CF $* + ;; + +esac diff --git a/xpa/stest.c b/xpa/stest.c new file mode 100644 index 0000000..afceb89 --- /dev/null +++ b/xpa/stest.c @@ -0,0 +1,729 @@ +/* + * Copyright (c) 1999-2003 Smithsonian Astrophysical Observatory + */ + +/* + * + * stest -- server test for xpa + * + */ +#include <xpap.h> + +#ifndef BUILD_WITH_XT +#if HAVE_XT +#undef HAVE_XT +#endif +#endif + +#if HAVE_XT +#include <X11/Intrinsic.h> +#include <X11/StringDefs.h> +#endif + +#define MAX_FPS 10 + +extern char *optarg; +extern int optind; + +XPA xpa1, xpa1a, xpa2, xpa3; +int quiet=0; +int dowait=0; +int dofill=0; +int dosave=1; +int doone=0; +int domyfree=0; +int doatexit=0; +int n=0; +int please_exit=0; +size_t save_bytes=-1; +char *save_buf=NULL; + +char *mode=""; +char name[SZ_LINE]; +char xclass[SZ_LINE]; + +#ifdef ANSI_FUNC +void myfree(void *buf) +#else +void myfree(buf) + void *buf; +#endif +{ + fprintf(stderr, "myfree calling xfree(%p)\n", buf); + xfree(buf); +} + +#ifdef ANSI_FUNC +int +send_cb (void *client_data, void *call_data, char *paramlist, + char **buf, size_t *len) +#else +int send_cb(client_data, call_data, paramlist, buf, len) + void *client_data; + void *call_data; + char *paramlist; + char **buf; + size_t *len; +#endif +{ + char *s = (char *)client_data; + XPA xpa = (XPA)call_data; + char tbuf[SZ_LINE]; + char xtemplate[SZ_LINE]; + char *names[MAX_FPS]; + char *bufs[MAX_FPS]; + char *errs[MAX_FPS]; + size_t lens[MAX_FPS]; + int sendbuf=0; + int got; + int i; + int ip; + + /* set the free routine */ + if( domyfree ) XPASetFree(xpa, myfree, NULL); + + /* introduce ourselves */ + if( !quiet ){ + fprintf(stdout, "SEND_CB #%d: %s:%s %s (%s)\n", + n++, xpa_class(xpa), xpa_name(xpa), xpa_method(xpa), s); + } + + /* process special paramlist tokens */ + if( paramlist && *paramlist ){ + ip = 0; + word(paramlist, xtemplate, &ip); + if( !quiet ) + fprintf(stdout, "\tparamlist: %s\n", paramlist); + if( !strncmp(paramlist, "buf", 3) ){ + sendbuf=1; + } + else if( !strcmp(paramlist, "free") ){ + if( !quiet ) + fprintf(stdout, "Freeing xpa struct\n"); + XPAFree(xpa); + return(0); + } + else if( !strcmp(paramlist, "exit") ){ + if( !quiet ) + fprintf(stdout, "Exiting\n"); + if( doatexit){ + please_exit = 1; + } else { + XPAFree(xpa1); + if( !doone ){ + XPAFree(xpa1a); + XPAFree(xpa2); + XPAFree(xpa3); + } + } + } + else if( !strcmp(paramlist, "Exit") ){ + if( !quiet ) + fprintf(stdout, "Exiting immediately\n"); + exit(0); + } + else if( !strncmp(paramlist, "error", 5) ){ + if( !quiet ) + fprintf(stdout, "\treturning error: %s\n", ¶mlist[6]); + *len = 0; + *buf = NULL; + if( strlen(paramlist) > 6 ) + XPAError(xpa, ¶mlist[6]); + else + XPAError(xpa, "intentional error from client"); + return(-1); + } + else if( !strcmp(paramlist, "wait") || !strcmp(paramlist, "version") ){ + fprintf(stdout, "Press <CR> to continue ..."); + fgets(tbuf, SZ_LINE, stdin); + } + else if( !strcmp(paramlist, "poll") ){ +repoll: + fprintf(stdout, "Press 'q' to quit ..."); + got = XPAPoll (10000, 1); + fprintf(stdout, " XPAPoll returns %d ...", got); + fgets(tbuf, SZ_LINE, stdin); + if( *tbuf != 'q' ) + goto repoll; + } + else if( !strncmp(paramlist, "fork ", 5) ){ +#if HAVE_MINGW32==0 + if( strlen(paramlist) > 5 ){ + fprintf(stdout, "fork command: %s\n", ¶mlist[5]); + /* child forks a command and exits */ + if(!(fork())){ + system(¶mlist[5]); + /* should call _exit but this tests avoidance of atexit routine */ + exit(0); + } + } +#else + fprintf(stderr, "ERROR: fork() not available in mingw\n"); + exit(1); +#endif + } + else if( !strcmp(xtemplate, "xpaget") ){ + word(paramlist, xtemplate, &ip); + got = XPAGet(xpa, xtemplate, &(paramlist[ip]), NULL, + bufs, lens, names, errs, MAX_FPS); + if( !quiet ) + fprintf(stdout, "XPAGet (%s) returned %d buffer(s)\n", xtemplate, got); + for(i=0; i<got; i++){ + if( !quiet ) + fprintf(stdout, "\t%d: %s\n", i, names[i]); + if( errs[i] == NULL ){ + if( !quiet && (lens[i] > 0) ){ + fprintf(stdout, "contents (%lu bytes):\n", (unsigned long)lens[i]); + fwrite(bufs[i], sizeof(char), lens[i], stdout); + } + if( !quiet ) + fprintf(stdout, "\n"); + } + else{ + write(fileno(stdout), errs[i], strlen(errs[i])); + } + if( bufs[i] ) + xfree(bufs[i]); + if( names[i] ) + xfree(names[i]); + if( errs[i] ) + xfree(errs[i]); + } + } + } + else if( dowait ){ + fprintf(stdout, "Press <CR> to continue ..."); + fgets(tbuf, SZ_LINE, stdin); + } + + /* return information about this xpa */ + if( !sendbuf ){ + snprintf(tbuf, SZ_LINE, + "class: %s\nname: %s\nmethod: %s\nsendian: %s\ncendian: %s\n", + xpa_class(xpa), xpa_name(xpa), xpa_method(xpa), + xpa_sendian(xpa), xpa_cendian(xpa)); + + if( (xpa->send_mode & XPA_MODE_FILLBUF) ){ + send(xpa_datafd(xpa), tbuf, strlen(tbuf), 0); + *len = 0; + *buf = NULL; + if( !quiet) + fprintf(stdout, "\tcallback writes %d bytes to client\n", + (int)strlen(tbuf)); + } + /* return the buffer and let xpa transmit it */ + else{ + *len = strlen(tbuf); + *buf = (char *)xmalloc(*len); + memcpy(*buf, tbuf, *len); + if( !quiet) + fprintf(stdout, "\tcallback returns %d bytes to xpa handler\n", + (int)strlen(tbuf)); + } + } + /* return the last buffer we were sent */ + else{ + if( (xpa->send_mode & XPA_MODE_FILLBUF) ){ + send(xpa_datafd(xpa), save_buf, save_bytes, 0); + *len = 0; + *buf = NULL; + if( !quiet) + fprintf(stdout, "\tcallback writes %lu bytes to client\n", + (unsigned long)save_bytes); + } + /* return the buffer and let xpa transmit it */ + else{ + *len = save_bytes; + *buf = (char *)xmalloc(*len); + memcpy(*buf, save_buf, *len); + if( !quiet) + fprintf(stdout, "\tcallback returns %lu bytes to xpa handler\n", + (unsigned long)save_bytes); + } + } + if( !quiet ){ + fprintf(stdout, "SEND_CB complete\n"); + } + else{ + fprintf(stdout, "."); + } + fflush(stdout); + fflush(stderr); + return(0); +} + +#ifdef ANSI_FUNC +int +receive_cb (void *client_data, void *call_data, char *paramlist, + char *buf, size_t len) +#else +int receive_cb(client_data, call_data, paramlist, buf, len) + void *client_data; + void *call_data; + char *paramlist; + char *buf; + size_t len; +#endif +{ + XPA xpa = (XPA)call_data; + char *s = (char *)client_data; + char tbuf[SZ_LINE]; + char cbuf[SZ_LINE]; + char *errs[1]; + int i; + int ip; + int got; + int xwait; + + /* set the free routine */ + if( domyfree ) XPASetFree(xpa, myfree, NULL); + + if( !quiet ){ + fprintf(stdout, "RECEIVE_CB #%d: %s:%s %s (%s)\n", + n++, xpa_class(xpa), xpa_name(xpa), xpa_method(xpa), s); + } + /* process param list */ + if( paramlist && *paramlist ){ + if( !quiet ) + fprintf(stdout, "\tparamlist: %s\n", paramlist); + if( !strcmp(paramlist, "free") ){ + if( !quiet ) + fprintf(stdout, "Freeing xpa struct\n"); + XPAFree(xpa); + return(0); + } + else if( !strcmp(paramlist, "exit") ){ + if( !quiet ) + fprintf(stdout, "Exiting\n"); + if( doatexit){ + please_exit = 1; + } else { + XPAFree(xpa1); + if( !doone ){ + XPAFree(xpa1a); + XPAFree(xpa2); + XPAFree(xpa3); + } + } + } + else if( !strcmp(paramlist, "Exit") ){ + if( !quiet ) + fprintf(stdout, "Exiting immediately\n"); + exit(0); + } + else if( !strncmp(paramlist, "error", 5) ){ + if( !quiet ) + fprintf(stdout, "Processing error: %s\n", ¶mlist[6]); + if( strlen(paramlist) > 6 ) + XPAError(xpa, ¶mlist[6]); + else + XPAError(xpa, "intentional error from client"); + return(-1); + } + else if( !strcmp(paramlist, "wait") ){ + fprintf(stdout, "Press <CR> to continue ..."); + fgets(tbuf, SZ_LINE, stdin); + } + else if( !strcmp(paramlist, "poll") ){ +repoll: + fprintf(stdout, "Press 'q' to quit ..."); + got = XPAPoll (10000, 1); + fprintf(stdout, " ... XPAPoll returns %d ...", got); + fgets(tbuf, SZ_LINE, stdin); + if( *tbuf != 'q' ) + goto repoll; + } + else if( !strncmp(paramlist, "fork ", 5) ){ +#if HAVE_MINGW32==0 + if( strlen(paramlist) > 5 ){ + fprintf(stdout, "fork command: %s\n", ¶mlist[5]); + /* child forks a command and exits */ + if(!(fork())){ + system(¶mlist[5]); + /* should call _exit but this tests avoidance of atexit routine */ + exit(0); + } + } +#else + fprintf(stderr, "ERROR: fork() not available in mingw\n"); + exit(1); +#endif + } + else if( !strncmp(paramlist, "xpaset", 6) ){ + ip = 0; + word(paramlist, tbuf, &ip); + if( word(paramlist, tbuf, &ip) ){ + if( !quiet ) + fprintf(stdout, "calling XPASet(%s, \"%s\")\n", + tbuf, &(paramlist[ip])); + got = XPASet(NULL, tbuf, &(paramlist[ip]), mode, + paramlist, strlen(paramlist), NULL, errs, 1); + if( got == 0 ){ + if( !quiet ) + fprintf(stdout, "no XPA access points matched template %s\n", + tbuf); + } + else if( errs[0] != NULL ){ + if( !quiet ) + fprintf(stdout, "Error on xpaset to %s: %s\n", tbuf, errs[0]); + xfree(errs[0]); + } + else{ + if( !quiet ) + fprintf(stdout, "XPASet to %s successful\n", tbuf); + } + } + return(0); + } + } + else if( dowait ){ + fprintf(stdout, "Press <CR> to continue ..."); + fgets(tbuf, SZ_LINE, stdin); + } + + /* reset save buffer */ + if( save_buf != NULL ){ + xfree(save_buf); + save_buf = NULL; + } + save_bytes = 0; + xwait = dowait; + if( !(xpa->receive_mode & XPA_MODE_FILLBUF) && dofill ){ + while( (got=recv(xpa_datafd(xpa), tbuf, SZ_LINE, 0)) >0 ){ + if( xwait >0 ){ + fprintf(stdout, "got %d bytes ... press <CR> to continue ...", got); + fgets(cbuf, SZ_LINE, stdin); + xwait--; + } + i = save_bytes; + save_bytes += got; + if( dosave ){ + if( save_buf == NULL ) + save_buf = (char *)xmalloc(save_bytes); + else + save_buf = (char *)xrealloc(save_buf, save_bytes); + memcpy(&save_buf[i], tbuf, got); + } + } + if( !quiet ) + fprintf(stdout, "\tcallback read %lu bytes\n", + (unsigned long)save_bytes); + } + else{ + if( !quiet ){ + fprintf(stdout, "\tenter callback with buf: %lu bytes\n", + (unsigned long)len); + } + save_bytes = len; + save_buf = (char *)xmalloc(len); + memcpy(save_buf, buf, len); + } + if( !quiet ){ + fprintf(stdout, "RECEIVE_CB complete\n"); + } + else{ + fprintf(stdout, "."); + } + fflush(stdout); + fflush(stderr); + return(0); +} + +#ifdef ANSI_FUNC +int +info_cb (void *client_data, void *call_data, char *paramlist) +#else +int info_cb(client_data, call_data, paramlist) + void *client_data; + void *call_data; + char *paramlist; +#endif +{ + XPA xpa = (XPA)call_data; + char *s = (char *)client_data; + char xtemplate[SZ_LINE]; + char *names[MAX_FPS]; + char *bufs[MAX_FPS]; + char *errs[MAX_FPS]; + size_t lens[MAX_FPS]; + int i; + int ip; + int got; + + if( !quiet ){ + fprintf(stdout, "INFO_CB #%d: %s:%s (%s)\n", + n++, xpa_class(xpa), xpa_name(xpa), s); + } + + if( paramlist && *paramlist ){ + if( !quiet ) + fprintf(stdout, "\tparamlist: %s\n", paramlist); + ip = 0; + word(paramlist, xtemplate, &ip); + if( !strcmp(xtemplate, "xpaget") ){ + word(paramlist, xtemplate, &ip); + got = XPAGet(xpa, xtemplate, &(paramlist[ip]), NULL, + bufs, lens, names, errs, MAX_FPS); + if( !quiet ) + fprintf(stdout, "XPAGet (%s) returned %d buffer(s)\n", xtemplate, got); + for(i=0; i<got; i++){ + if( !quiet ) + fprintf(stdout, "\t%d: %s\n", i, names[i]); + if( errs[i] == NULL ){ + if( !quiet && (lens[i] > 0) ){ + fprintf(stdout, "contents (%lu bytes):\n", + (unsigned long)lens[i]); + fwrite(bufs[i], sizeof(char), lens[i], stdout); + } + if( !quiet ) + fprintf(stdout, "\n"); + } + else{ + write(fileno(stdout), errs[i], strlen(errs[i])); + } + if( bufs[i] ) + xfree(bufs[i]); + if( names[i] ) + xfree(names[i]); + if( errs[i] ) + xfree(errs[i]); + } + } + } + if( !quiet ){ + fprintf(stdout, "INFO_CB complete\n"); + } + else{ + fprintf(stdout, "."); + } + fflush(stdout); + fflush(stderr); + return(0); +} + +#ifdef ANSI_FUNC +int +main (int argc, char **argv) +#else +main(argc, argv) + int argc; + char **argv; +#endif +{ +#if HAVE_XT + Widget top; + XtAppContext appcontext; +#endif + char *proxy=NULL; + char tbuf[SZ_LINE]; + char tbuf2[SZ_LINE]; + char cmd[SZ_LINE]; + int c; + int got=0; + int x=0; + int delay=0; + +#if HAVE_MINGW32==0 + setvbuf(stdout, NULL, _IONBF, 0); + setvbuf(stderr, NULL, _IONBF, 0); +#endif + + *cmd = '\0'; + /* process switch arguments */ + while ((c = getopt(argc, argv, "1ad:f:mqrRp:suwxX")) != -1){ + switch(c){ + case '1': + doone = 1; + break; + case 'a': + mode = "ack=false"; + break; + case 'd': + delay = atoi(optarg); + break; + case 'f': + snprintf(cmd, SZ_LINE, "%s %s &\n", argv[0], optarg); + break; + case 'm': + domyfree = 1; + break; + case 'q': + quiet = 1; + break; + case 'p': + proxy = optarg; + break; + case 'r': + mode = "fillbuf=false"; + break; + case 'R': + mode = "fillbuf=false"; + dofill = 1; + dosave = 0; + break; + case 's': + x = 0; + break; + case 'u': + mode = "buf=false"; + break; + case 'w': + dowait++; + break; + case 'x': + doatexit=1; + break; + case 'X': + x = 1; + break; + } + } + + if( optind >= argc ){ + strcpy(name, "xpa"); + } + else{ + strcpy(name, argv[optind]); + } + strcpy(xclass, name); + cluc(xclass); + + if( doatexit ){ +#if HAVE_ATEXIT + XPAAtExit(); +#else + fprintf(stderr, "ERROR: atexit not available\n"); + exit(1); +#endif + } + + if( x ){ +#if HAVE_XT + top = XtAppInitialize(&appcontext, "Server", NULL, 0, + &argc, argv, NULL, NULL, 0); + XtVaSetValues(top, XtNwidth, (XtArgVal)10, XtNheight, (XtArgVal)10, + XtNmappedWhenManaged, (XtArgVal)False, NULL); +#else + fprintf(stderr, "Xt is not available ...\n"); + got = 1; + goto done; +#endif + } + + strcpy(tbuf, name); + snprintf(tbuf2, SZ_LINE, "help for %s", tbuf); + xpa1 = XPANew(xclass, tbuf, tbuf2, + send_cb, (void *)"send1", mode, + receive_cb, (void *)"receive1", mode); + if( xpa1 == NULL ){ + fprintf(stderr, "ERROR: could not init xpa1\n"); + } + else{ + fprintf(stdout, "%s using method: %s\n", xpa_name(xpa1), xpa_method(xpa1)); + } + + if( !doone ){ + snprintf(tbuf, SZ_LINE, "%s1", name); + snprintf(tbuf2, SZ_LINE, "help for %s", tbuf); + xpa1a = XPANew(xclass, tbuf, tbuf2, + send_cb, (void *)"send1a", mode, + receive_cb, (void *)"receive1a", mode); + if( xpa1a == NULL ){ + fprintf(stderr, "ERROR: could not init xpa1a\n"); + } + else{ + fprintf(stdout, "%s using method: %s\n", + xpa_name(xpa1a), xpa_method(xpa1a)); + } + + snprintf(tbuf, SZ_LINE, "c_%s", name); + xpa2 = XPACmdNew(xclass, tbuf); + if( xpa2 == NULL ){ + fprintf(stderr, "ERROR: could not init xpa2\n"); + } + else{ + XPACmdAdd(xpa2, "cmd2", "and help for cmd2", + send_cb, (void *)"cmd2", mode, + receive_cb, (void *)"cmd2", mode); + XPACmdAdd(xpa2, "cmd1 xx yy", "help for cmd1 xx yy", + send_cb, (void *)"cmd1 xx yy", mode, + receive_cb, (void *)"cmd1 xx yy", mode); + XPACmdAdd(xpa2, "cmd1 xx", "help for cmd1 xx", + send_cb, (void *)"cmd1 xx", mode, + receive_cb, (void *)"cmd1 xx", mode); + XPACmdAdd(xpa2, "cmd1", NULL, + send_cb, (void *)"cmd1", mode, + receive_cb, (void *)"cmd1", mode); + fprintf(stdout, "%s using method: %s\n", + xpa_name(xpa2), xpa_method(xpa2)); + } + + snprintf(tbuf, SZ_LINE, "i_%s", name); + xpa3 = XPAInfoNew(xclass, tbuf, info_cb, (void *)"info1", mode); + if( xpa3 == NULL ){ + fprintf(stderr, "ERROR: could not init xpa3\n"); + } + else{ + fprintf(stdout, "%s using method: %s\n", xpa_name(xpa3), xpa_method(xpa3)); + } + } + + if( *cmd != '\0' ){ + fprintf(stdout, "starting bkgd process: %s", cmd); + system(cmd); + } + + /* delay if necessary */ + if( delay ){ + fprintf(stdout, "starting delay of %d seconds ...", delay); + XPASleep(delay*1000); + fprintf(stdout, " done\n"); + } + fflush(stdout); + fflush(stderr); + + /* connect to proxy, if necessary */ + if( proxy ){ + if( XPARemote(xpa1, proxy, "+", "proxy=true") < 0 ){ + fprintf(stderr, "ERROR: could not connect to proxy: %s\n", proxy); + } + } + + if( x ){ +#if HAVE_XT + fprintf(stdout, "\nEntering Xt loop ...\n"); + XPAXtAddInput(appcontext, NULL); + XtRealizeWidget(top); + XtAppMainLoop(appcontext); +#else + fprintf(stderr, "Xt is not available ...\n"); + got = 1; + goto done; +#endif + } + else{ + fprintf(stdout, "\nEntering select loop ...\n"); + if( !doatexit ){ + XPAMainLoop(); + } else { + while( !please_exit ) + if( !XPAPoll(-1, 100) ) please_exit=1; + } + goto done; + } + +done: + if( !doatexit ){ + XPAFree(xpa1); + if( !doone ){ + XPAFree(xpa1a); + XPAFree(xpa2); + XPAFree(xpa3); + } + } + + /* make valgrind happy */ + XPACleanup(); + if( save_buf ) xfree(save_buf); + exit(got); +} diff --git a/xpa/tcl.c b/xpa/tcl.c new file mode 100644 index 0000000..1dbdad4 --- /dev/null +++ b/xpa/tcl.c @@ -0,0 +1,2773 @@ +/* + * Copyright (c) 1999-2003 Smithsonian Astrophysical Observatory + */ + +#include <xpap.h> + +#if HAVE_TCL + +#include <tcl.h> + +/* + *---------------------------------------------------------------------------- + * + * + * Private Routines and Data + * + * + *---------------------------------------------------------------------------- + */ + +/* with Tcl 8.4, some function prototypes have added CONST qualifiers, + which we try to deal with in a backward-compatible way */ +#define XCONST84 +#if TCL_MAJOR_VERSION >= 8 +#if TCL_MINOR_VERSION >= 4 +#undef XCONST84 +#define XCONST84 CONST +#endif +#endif + +#ifdef NULLSTRING +#undef NULLSTRING +#endif +#define NULLSTRING "" + +#define TCL_NULLSTR(s) (!s || !*s || !strcmp(s, "{}")) + +#define TY_CLIENT 1 +#define TY_SERVER 2 + +#ifndef MAX_XPAS +#define MAX_XPAS 10000 +#endif + +/* + * + * record struct for client_data for XPATcl[Send,Receive,Info] routines + * + */ +typedef struct xpatclclientdatarec{ + Tcl_Interp *interp; + char *callback; + char *client_data; +} *XPATclClientData, XPATclClientDataRec; + + +/* + *---------------------------------------------------------------------------- + * + * Routine: Tcl_GetXPAFromObj + * + * Purpose: convert string to XPA handle + * + * Returns: Tcl error code + * + *---------------------------------------------------------------------------- + */ +#ifdef ANSI_FUNC +static int +Tcl_GetXPAFromObj(Tcl_Interp *interp, Tcl_Obj *obj, int flag, XPA *xpa) +#else +static int Tcl_GetXPAFromObj(interp, obj, flag, xpa) + Tcl_Interp *interp; + Tcl_Obj *obj; + int flag; + XPA *xpa; +#endif +{ + char *s; + void *lval; + Tcl_Obj *resultPtr; + + /* get result pointer */ + resultPtr = Tcl_GetObjResult(interp); + + if( (s = Tcl_GetStringFromObj(obj, NULL)) == NULL ){ + return(TCL_ERROR); + } + if( strncmp(s, "xpa_", 4) || (sscanf(&(s[4]), "%p", &lval) != 1) ){ + Tcl_SetStringObj(resultPtr, "XPA$ERROR: invalid xpa handle", -1); + return(TCL_ERROR); + } + *xpa = (XPA)lval; + /* make sure its a valid xpa */ + switch(flag){ + case TY_CLIENT: + if( !XPAClientValid(*xpa) ){ + Tcl_SetStringObj(resultPtr, "XPA$ERROR: invalid xpa client handle", -1); + return(TCL_ERROR); + } + break; + case TY_SERVER: + if( !XPAValid(*xpa) ){ + Tcl_SetStringObj(resultPtr, "XPA$ERROR: invalid xpa server handle", -1); + return(TCL_ERROR); + } + break; + } + return(TCL_OK); +} + + +/* + *---------------------------------------------------------------------------- + * + * Routine: XPATclHandler + * + * Purpose: common handler for access points written in tcl + * execute the tcl receive command with xpa arguments + * used instead of Tcl_Eval so we can avoid interpreting either + * paramlist or buf + * + * + * Returns: 0 on success, -1 on failure + * + *---------------------------------------------------------------------------- + */ +#ifdef ANSI_FUNC +static int +XPATclHandler (void *client_data, void *call_data, char *paramlist, + char *buf, int len, int nargs) +#else +static int XPATclHandler(client_data, call_data, paramlist, buf, len, nargs) + void *client_data; + void *call_data; + char *paramlist; + char *buf; + int len; + int nargs; +#endif +{ + XPA xpa = (XPA)call_data; + XPATclClientData xptr = (XPATclClientData)client_data; + Tcl_CmdInfo info; /* Info about command procedures */ + Tcl_Obj *objv[10]; /* Object vector for arguments */ + Tcl_Obj *resultPtr; /* The result object */ + int result; /* TCL_OK or TCL_ERROR */ + int object; + char tbuf[SZ_LINE]; + XCONST84 char *argv[10]; + char *s=NULL; + char *t=NULL; + char *cmd; + + /* make sure we have a callback */ + if( !xptr || !xptr->callback ){ + XPAError(xpa, "Invalid tcl command for xpa callback"); + return(-1); + } + /* set command name */ + cmd = xptr->callback; + + /* Map from the command name to a C procedure */ + if( !Tcl_GetCommandInfo(xptr->interp, cmd, &info) ){ + XPAError(xpa, "Unknown tcl command for xpa callback"); + return(-1); + } + + /* string-ize some values */ + snprintf(tbuf, SZ_LINE, "xpa_%p", xpa); + s = xstrdup(tbuf); + if( nargs > 4 ){ + snprintf(tbuf, SZ_LINE, "%d", len); + t = xstrdup(tbuf); + } + + /* package up argument values */ + object = info.isNativeObjectProc; + if (object) { + /* The object interface is preferred for this command */ + objv[0] = Tcl_NewStringObj(cmd, strlen(cmd)); + objv[1] = Tcl_NewStringObj(s, strlen(s)); + if( (xptr->client_data == NULL) || (*xptr->client_data == '\0') ) + objv[2] = Tcl_NewStringObj(NULLSTRING, strlen(NULLSTRING)); + else + objv[2] = Tcl_NewStringObj(xptr->client_data, strlen(xptr->client_data)); + if( (paramlist == NULL) || (*paramlist == '\0') ) + objv[3] = Tcl_NewStringObj(NULLSTRING, strlen(NULLSTRING)); + else + objv[3] = Tcl_NewStringObj(paramlist, strlen(paramlist)); + if( nargs > 4 ){ + if( (buf == NULL) || (*buf == '\0') || (len == 0) ) + objv[4] = Tcl_NewStringObj(NULLSTRING, strlen(NULLSTRING)); + else + objv[4] = Tcl_NewStringObj(buf, len); + objv[5] = Tcl_NewStringObj(t, strlen(t)); + } + } else { + argv[0] = cmd; + argv[1] = s; + argv[2] = xptr->client_data; + argv[3] = paramlist; + if( nargs > 4 ){ + argv[4] = buf; + argv[5] = t; + } + } + + /* reset before we make C call */ + Tcl_ResetResult(xptr->interp); + + /* + * Invoke the C procedure. + */ + if (object) { + result = (*info.objProc)(info.objClientData, xptr->interp, nargs, objv); + /* Get the string value from the result object */ + resultPtr = Tcl_GetObjResult(xptr->interp); + Tcl_SetResult(xptr->interp, Tcl_GetStringFromObj(resultPtr, NULL), + TCL_VOLATILE); + } else { + result = (*info.proc)(info.clientData, xptr->interp, nargs, argv); + } + + /* clean up */ + if( s ) xfree(s); + if( t ) xfree(t); + + /* translate Tcl status into XPA status */ + if( result == TCL_OK ){ + return(0); + } + else{ + s = (char *)Tcl_GetStringResult(xptr->interp); + if( !strncmp(s, "XPA$ERROR: ", 11) ) + s += 11; + XPAError(xpa, s); + return(-1); + } +} + +/* + *---------------------------------------------------------------------------- + * + * Routine: XPATclReceive + * + * Purpose: receive handler for access points written in tcl + * execute the tcl receive command with xpa arguments + * used instead of Tcl_Eval so we can avoid interpreting either + * paramlist or buf + * + * + * Returns: 0 on success, -1 on failure + * + *---------------------------------------------------------------------------- + */ +#ifdef ANSI_FUNC +static int +XPATclReceive (void *client_data, void *call_data, char *paramlist, + char *buf, size_t len) +#else +static int XPATclReceive(client_data, call_data, paramlist, buf, len) + void *client_data; + void *call_data; + char *paramlist; + char *buf; + size_t len; +#endif +{ + return(XPATclHandler(client_data, call_data, paramlist, buf, len, 6)); +} + +/* + *---------------------------------------------------------------------------- + * + * Routine: XPATclSend + * + * Purpose: send handler for access points written in tcl + * + * Returns: 0 on success, -1 on failure + * + *---------------------------------------------------------------------------- + */ +#ifdef ANSI_FUNC +static int +XPATclSend (void *client_data, void *call_data, char *paramlist, + char **buf, size_t *len) +#else +static int XPATclSend(client_data, call_data, paramlist, buf, len) + void *client_data; + void *call_data; + char *paramlist; + char **buf; + size_t *len; +#endif +{ + return(XPATclHandler(client_data, call_data, paramlist, NULL, 0, 4)); +} + +/* + *---------------------------------------------------------------------------- + * + * Routine: XPATclInfo + * + * Purpose: info handler for access points written in tcl + * + * Returns: 0 on success, -1 on failure + * + *---------------------------------------------------------------------------- + */ +#ifdef ANSI_FUNC +static int +XPATclInfo (void *client_data, void *call_data, char *paramlist) +#else +static int XPATclInfo(client_data, call_data, paramlist) + void *client_data; + void *call_data; + char *paramlist; +#endif +{ + return(XPATclHandler(client_data, call_data, paramlist, NULL, 0, 4)); +} + +/* + *---------------------------------------------------------------------------- + * + * Routine: XPANew_Tcl + * + * Purpose: Tcl binding to XPANew procedure + * + * Tcl call: + * + * xpanew class name help sproc sdata smode rproc rdata rmode + * + * use the empty string to specify NULL arguments + * + * Returns: Tcl error code + * + *---------------------------------------------------------------------------- + */ +#ifdef ANSI_FUNC +static int +XPANew_Tcl(ClientData clientData, Tcl_Interp *interp, + int objc, Tcl_Obj *CONST objv[]) +#else +static int XPANew_Tcl(clientData, interp, objc, objv) + ClientData clientData; + Tcl_Interp *interp; + int objc; + Tcl_Obj *CONST objv[]; +#endif +{ + char *xclass; + char *name; + char *help; + char *send_cb; + char *sdata; + char *smode; + char *rec_cb; + char *rdata; + char *rmode; + char tbuf[SZ_LINE]; + XPA xpa; + SendCb sproc; + ReceiveCb rproc; + XPATclClientData sptr; + XPATclClientData rptr; + Tcl_Obj *resultPtr; + + /* make sure argument count is correct */ + if( objc != 10 ){ + Tcl_WrongNumArgs(interp, 1, objv, + "class name help sproc sdata smode rproc rdata rmode"); + return(TCL_ERROR); + } + + /* get arguments as strings */ + xclass = Tcl_GetStringFromObj(objv[1], NULL); + name = Tcl_GetStringFromObj(objv[2], NULL); + help = Tcl_GetStringFromObj(objv[3], NULL); + send_cb = Tcl_GetStringFromObj(objv[4], NULL); + sdata = Tcl_GetStringFromObj(objv[5], NULL); + smode = Tcl_GetStringFromObj(objv[6], NULL); + rec_cb = Tcl_GetStringFromObj(objv[7], NULL); + rdata = Tcl_GetStringFromObj(objv[8], NULL); + rmode = Tcl_GetStringFromObj(objv[9], NULL); + + /* this will hold the result */ + resultPtr = Tcl_GetObjResult(interp); + + /* set up callback procedures */ + if( ((send_cb == NULL) || (*send_cb == '\0') ) ){ + sproc = NULL; + sptr = NULL; + } + else{ + sproc = XPATclSend; + sptr = (XPATclClientData)xcalloc(1, sizeof(XPATclClientDataRec)); + sptr->interp = interp; + sptr->callback = xstrdup(send_cb); + sptr->client_data = xstrdup(sdata); + } + if( ((rec_cb == NULL) || (*rec_cb == '\0') ) ){ + rproc = NULL; + rptr = NULL; + } + else{ + rproc = XPATclReceive; + rptr = (XPATclClientData)xcalloc(1, sizeof(XPATclClientDataRec)); + rptr->interp = interp; + rptr->callback = xstrdup(rec_cb); + rptr->client_data = xstrdup(rdata); + } + + /* make sure we have either a send or receive callback */ + if( !sproc && !rproc ){ + Tcl_SetStringObj(resultPtr, + "XPA$ERROR: xpanew requires send_cb or rec_cb (or both)", -1); + return(TCL_ERROR); + } + + /* set up the tcl handler for the xpa access point */ + xpa = XPANew(xclass, name, help, sproc, sptr, smode, rproc, rptr, rmode); + if( xpa == NULL ){ + Tcl_SetStringObj(resultPtr, + "XPA$ERROR: could not create XPA access point", -1); + return(TCL_ERROR); + } + else{ + /* add this xpa to the Tcl event loop */ + XPATclAddInput(xpa); + /* return xpa address to tcl in a string */ + snprintf(tbuf, SZ_LINE, "xpa_%p", xpa); + Tcl_SetStringObj(resultPtr, tbuf, -1); + return(TCL_OK); + } +} + +/* + *---------------------------------------------------------------------------- + * + * Routine: XPAFree_Tcl + * + * Purpose: Tcl binding to XPAFree procedure + * + * Tcl call: + * + * xpafree xpa + * + * Returns: Tcl error code + * + *---------------------------------------------------------------------------- + */ +#ifdef ANSI_FUNC +static int +XPAFree_Tcl(ClientData clientData, Tcl_Interp *interp, + int objc, Tcl_Obj *CONST objv[]) +#else +static int XPAFree_Tcl(clientData, interp, objc, objv) + ClientData clientData; + Tcl_Interp *interp; + int objc; + Tcl_Obj *CONST objv[]; +#endif +{ + XPA xpa; + XPATclClientData ptr; + + /* make sure argument count is correct */ + if( objc != 2 ){ + Tcl_WrongNumArgs(interp, 1, objv, "xpa"); + return(TCL_ERROR); + } + + /* get xpa, which is always arg 1 */ + if( Tcl_GetXPAFromObj(interp, objv[1], TY_SERVER, &xpa) != TCL_OK){ + return(TCL_ERROR); + } + + /* reset error/result condition */ + Tcl_ResetResult(interp); + + /* free the associated tcl record, stored in the client data */ + if( xpa->send_data ){ + ptr = (XPATclClientData)xpa->send_data; + if( ptr->callback ) xfree( ptr->callback); + if( ptr->client_data ) xfree( ptr->client_data); + xfree(xpa->send_data); + } + if( xpa->receive_data ){ + ptr = (XPATclClientData)xpa->receive_data; + if( ptr->callback ) xfree( ptr->callback); + if( ptr->client_data ) xfree( ptr->client_data); + xfree(xpa->receive_data); + } + if( xpa->info_data ){ + ptr = (XPATclClientData)xpa->info_data; + if( ptr->callback ) xfree( ptr->callback); + if( ptr->client_data ) xfree( ptr->client_data); + xfree(xpa->info_data); + } + + /* call the XPAFree routine */ + XPAFree(xpa); + return(TCL_OK); +} + +/* + *---------------------------------------------------------------------------- + * + * Routine: XPAInfoNew_Tcl + * + * Purpose: Tcl binding to XPAInfoNew procedure + * + * Tcl call: + * + * xpanew class name help iproc idata imode + * + * use the empty string to specify NULL arguments + * + * Returns: Tcl error code + * + *---------------------------------------------------------------------------- + */ +#ifdef ANSI_FUNC +static int +XPAInfoNew_Tcl(ClientData clientData, Tcl_Interp *interp, + int objc, Tcl_Obj *CONST objv[]) +#else +static int XPAInfoNew_Tcl(clientData, interp, objc, objv) + ClientData clientData; + Tcl_Interp *interp; + int objc; + Tcl_Obj *CONST objv[]; +#endif +{ + char *xclass; + char *name; + char *info_cb; + char *idata; + char *imode; + char tbuf[SZ_LINE]; + XPA xpa; + InfoCb iproc; + XPATclClientData iptr; + Tcl_Obj *resultPtr; + + /* make sure argument count is correct */ + if( objc != 6 ){ + Tcl_WrongNumArgs(interp, 1, objv, + "class name iproc idata imode"); + return(TCL_ERROR); + } + + /* get arguments as strings */ + xclass = Tcl_GetStringFromObj(objv[1], NULL); + name = Tcl_GetStringFromObj(objv[2], NULL); + info_cb = Tcl_GetStringFromObj(objv[3], NULL); + idata = Tcl_GetStringFromObj(objv[4], NULL); + imode = Tcl_GetStringFromObj(objv[5], NULL); + + /* this will hold the result */ + resultPtr = Tcl_GetObjResult(interp); + + /* set up callback procedures */ + if( info_cb == NULL ){ + Tcl_SetStringObj(resultPtr, + "XPA$ERROR: xpainfonew requires info_cb", -1); + return(TCL_ERROR); + } + else{ + iproc = XPATclInfo; + iptr = (XPATclClientData)xcalloc(1, sizeof(XPATclClientDataRec)); + iptr->interp = interp; + iptr->callback = xstrdup(info_cb); + iptr->client_data = xstrdup(idata); + } + + /* set up the tcl handler for the xpa access point */ + xpa = XPAInfoNew(xclass, name, iproc, iptr, imode); + if( xpa == NULL ){ + Tcl_SetStringObj(resultPtr, + "XPA$ERROR: could not create XPA info access point", -1); + return(TCL_ERROR); + } + else{ + /* add this xpa to the Tcl event loop */ + XPATclAddInput(xpa); + /* return xpa address to tcl in a string */ + snprintf(tbuf, SZ_LINE, "xpa_%p", xpa); + Tcl_SetStringObj(resultPtr, tbuf, -1); + return(TCL_OK); + } +} + +/* + *---------------------------------------------------------------------------- + * + * Routine: XPACmdNew_Tcl + * + * Purpose: Tcl binding to XPACmdNew procedure + * + * Tcl call: + * + * xpacmdnew class name + * + * Returns: Tcl error code + * + *---------------------------------------------------------------------------- + */ +#ifdef ANSI_FUNC +static int +XPACmdNew_Tcl(ClientData clientData, Tcl_Interp *interp, + int objc, Tcl_Obj *CONST objv[]) +#else +static int XPACmdNew_Tcl(clientData, interp, objc, objv) + ClientData clientData; + Tcl_Interp *interp; + int objc; + Tcl_Obj *CONST objv[]; +#endif +{ + char *xclass; + char *name; + char tbuf[SZ_LINE]; + XPA xpa; + Tcl_Obj *resultPtr; + + /* make sure argument count is correct */ + if( objc != 3 ){ + Tcl_WrongNumArgs(interp, 1, objv, "class name"); + return(TCL_ERROR); + } + + /* get arguments as strings */ + xclass = Tcl_GetStringFromObj(objv[1], NULL); + name = Tcl_GetStringFromObj(objv[2], NULL); + + /* this will hold the result */ + resultPtr = Tcl_GetObjResult(interp); + + /* set up the tcl handler for the xpa access point */ + if( (xpa = XPACmdNew(xclass, name)) == NULL ){ + Tcl_SetStringObj(resultPtr, + "XPA$ERROR: could not create XPA command access point", -1); + return(TCL_ERROR); + } + else{ + /* add this xpa to the Tcl event loop */ + XPATclAddInput(xpa); + /* return xpa address to tcl in a string */ + snprintf(tbuf, SZ_LINE, "xpa_%p", xpa); + Tcl_SetStringObj(resultPtr, tbuf, -1); + return(TCL_OK); + } +} + +/* + *---------------------------------------------------------------------------- + * + * Routine: XPACmdAdd_Tcl + * + * Purpose: Tcl binding to XPACmdAdd procedure + * + * Tcl call: + * + * xpacmdadd xpa name help sproc sdata smode rproc rdata rmode + * + * use the empty string to specify NULL arguments + * + * Returns: Tcl error code + * + *---------------------------------------------------------------------------- + */ +#ifdef ANSI_FUNC +static int +XPACmdAdd_Tcl(ClientData clientData, Tcl_Interp *interp, + int objc, Tcl_Obj *CONST objv[]) +#else +static int XPACmdAdd_Tcl(clientData, interp, objc, objv) + ClientData clientData; + Tcl_Interp *interp; + int objc; + Tcl_Obj *CONST objv[]; +#endif +{ + char *name; + char *help; + char *send_cb; + char *sdata; + char *smode; + char *rec_cb; + char *rdata; + char *rmode; + char tbuf[SZ_LINE]; + XPA xpa; + XPACmd xpacmd; + SendCb sproc; + ReceiveCb rproc; + XPATclClientData sptr; + XPATclClientData rptr; + Tcl_Obj *resultPtr; + + /* make sure argument count is correct */ + if( objc != 10 ){ + Tcl_WrongNumArgs(interp, 1, objv, + "class name help sproc sdata smode rproc rdata rmode"); + return(TCL_ERROR); + } + + /* get xpa, which is always arg 1 */ + if( Tcl_GetXPAFromObj(interp, objv[1], TY_SERVER, &xpa) != TCL_OK){ + return(TCL_ERROR); + } + + name = Tcl_GetStringFromObj(objv[2], NULL); + help = Tcl_GetStringFromObj(objv[3], NULL); + send_cb = Tcl_GetStringFromObj(objv[4], NULL); + sdata = Tcl_GetStringFromObj(objv[5], NULL); + smode = Tcl_GetStringFromObj(objv[6], NULL); + rec_cb = Tcl_GetStringFromObj(objv[7], NULL); + rdata = Tcl_GetStringFromObj(objv[8], NULL); + rmode = Tcl_GetStringFromObj(objv[9], NULL); + + /* this will hold the result */ + resultPtr = Tcl_GetObjResult(interp); + + /* set up callback procedures */ + if( ((send_cb == NULL) || (*send_cb == '\0') ) ){ + sproc = NULL; + sptr = NULL; + } + else{ + sproc = XPATclSend; + sptr = (XPATclClientData)xcalloc(1, sizeof(XPATclClientDataRec)); + sptr->interp = interp; + sptr->callback = xstrdup(send_cb); + sptr->client_data = xstrdup(sdata); + } + if( ((rec_cb == NULL) || (*rec_cb == '\0') ) ){ + rproc = NULL; + rptr = NULL; + } + else{ + rproc = XPATclReceive; + rptr = (XPATclClientData)xcalloc(1, sizeof(XPATclClientDataRec)); + rptr->interp = interp; + rptr->callback = xstrdup(rec_cb); + rptr->client_data = xstrdup(rdata); + } + + /* make sure we have either a send or receive callback */ + if( !sproc && !rproc ){ + Tcl_SetStringObj(resultPtr, + "XPA$ERROR: xpacmdadd requires send_cb or rec_cb (or both)", -1); + return(TCL_ERROR); + } + + /* set up the tcl handler for the xpa access point */ + xpacmd = XPACmdAdd(xpa, name, help, sproc, sptr, smode, rproc, rptr, rmode); + if( xpacmd == NULL ){ + Tcl_SetStringObj(resultPtr, "XPA$ERROR: could not create XPA command", -1); + return(TCL_ERROR); + } + else{ + /* return xpa address to tcl in a string */ + snprintf(tbuf, SZ_LINE, "xpacmd_%p", xpacmd); + Tcl_SetStringObj(resultPtr, tbuf, -1); + return(TCL_OK); + } +} + +/* + *---------------------------------------------------------------------------- + * + * Routine: XPACmdDel_Tcl + * + * Purpose: Tcl binding to XPACmdDel procedure + * + * Tcl call: + * + * xpacmddel xpa cmd + * + * Returns: Tcl error code + * + *---------------------------------------------------------------------------- + */ +#ifdef ANSI_FUNC +static int +XPACmdDel_Tcl(ClientData clientData, Tcl_Interp *interp, + int objc, Tcl_Obj *CONST objv[]) +#else +static int XPACmdDel_Tcl(clientData, interp, objc, objv) + ClientData clientData; + Tcl_Interp *interp; + int objc; + Tcl_Obj *CONST objv[]; +#endif +{ + void *lval; + char *s; + XPA xpa; + XPACmd cmd; + Tcl_Obj *resultPtr; + + /* make sure argument count is correct */ + if( objc != 3 ){ + Tcl_WrongNumArgs(interp, 1, objv, "xpa cmd"); + return(TCL_ERROR); + } + + /* get result pointer */ + resultPtr = Tcl_GetObjResult(interp); + + /* get xpa, which is always arg 1 */ + if( Tcl_GetXPAFromObj(interp, objv[1], TY_SERVER, &xpa) != TCL_OK){ + return(TCL_ERROR); + } + + /* get xpacmd, which is always arg 2 */ + if( (s = Tcl_GetStringFromObj(objv[2], NULL)) == NULL ){ + return(TCL_ERROR); + } + if( strncmp(s, "xpacmd_", 7) || (sscanf(&(s[7]), "%p", &lval) != 1) ){ + Tcl_SetStringObj(resultPtr, "XPA$ERROR: invalid xpacmd handle", -1); + return(TCL_ERROR); + } + cmd = (XPACmd)lval; + + /* reset error/result condition */ + Tcl_ResetResult(interp); + + /* call the XPACmdDel routine */ + if( XPACmdDel(xpa, cmd) == 0 ){ + /* free the associated tcl record, stored in the client data */ + if( cmd->send_data ) xfree(cmd->send_data); + if( cmd->receive_data ) xfree(cmd->receive_data); + return(TCL_OK); + } + else{ + resultPtr = Tcl_GetObjResult(interp); + Tcl_SetStringObj(resultPtr, "XPA$ERROR: could not delete xpa cmd", -1); + return(TCL_ERROR); + } +} + +/* + *---------------------------------------------------------------------------- + * + * Routine: XPARec_Tcl + * + * Purpose: Tcl binding to retrieve info from the xpa struct + * + * Tcl call: + * + * set val [xparec xpa <option>] + * + * where option can be one of the following: + * + * name + * class + * method + * cmdfd + * datafd +#ifndef HAVE_CYGWIN + * cmdchan + * datachan +#endif + * sendian + * cendian + * version + * + * + * Returns: Tcl error code + * + *---------------------------------------------------------------------------- + */ +#ifdef ANSI_FUNC +static int +XPARec_Tcl(ClientData clientData, Tcl_Interp *interp, + int objc, Tcl_Obj *CONST objv[]) +#else +static int XPARec_Tcl(clientData, interp, objc, objv) + ClientData clientData; + Tcl_Interp *interp; + int objc; + Tcl_Obj *CONST objv[]; +#endif +{ +#ifndef HAVE_CYGWIN + Tcl_Channel chan; +#endif + static XCONST84 char *subCmds[] = { + "cendian", + "class", +#ifndef HAVE_CYGWIN + "cmdchan", +#endif + "cmdfd", +#ifndef HAVE_CYGWIN + "datachan", +#endif + "datafd", + "method", + "name", + "sendian", + "version", + (char *) NULL}; + enum ISubCmdIdx { + ICendianIdx, + IClassIdx, +#ifndef HAVE_CYGWIN + ICmdChanIdx, +#endif + ICmdFdIdx, +#ifndef HAVE_CYGWIN + IDataChanIdx, +#endif + IDataFdIdx, + IMethodIdx, + INameIdx, + ISendianIdx, + IVersionIdx + } index; + XPA xpa; + int result; + char tbuf[SZ_LINE]; + + /* we always have 3 args: xparec $xpa [option] */ + if (objc != 3) { + Tcl_WrongNumArgs(interp, 1, objv, "xpa option"); + return TCL_ERROR; + } + + /* get sub-command index */ + if( (result = Tcl_GetIndexFromObj(interp, objv[2], subCmds, "option", 0, + (int *)&index)) != TCL_OK ){ + return result; + } + + /* get xpa, which is always arg 1 */ + if( (result=Tcl_GetXPAFromObj(interp, objv[1], TY_SERVER, &xpa)) != TCL_OK){ + /* valid xpa is required, except for version */ + if( index != IVersionIdx ) + return(TCL_ERROR); + } + + /* process sub-command */ + switch (index) { + case ICendianIdx: + Tcl_SetResult(interp, (char *)xpa_cendian(xpa), TCL_VOLATILE); + result = TCL_OK; + break; + case IClassIdx: + Tcl_SetResult(interp, xpa_class(xpa), TCL_VOLATILE); + result = TCL_OK; + break; +#ifndef HAVE_CYGWIN + case ICmdChanIdx: + snprintf(tbuf, SZ_LINE, "sock%d", xpa_cmdfd(xpa)); + /* make sure we have a valid OS socket fd */ + if( xpa_cmdfd(xpa) < 0 ){ + Tcl_SetResult(interp, "none", TCL_STATIC); + result = TCL_OK; + } + /* see if this socket already is defined as a tcl variable */ + else if( Tcl_GetChannel(interp, tbuf, NULL) != NULL ){ + Tcl_SetResult(interp, tbuf, TCL_VOLATILE); + result = TCL_OK; + } + /* create new tcl variable for this socket */ + else{ + /* create a tcl channel corresponding to the xpa socket */ + if( !(chan = Tcl_MakeTcpClientChannel((ClientData)(uintptr_t)xpa_cmdfd(xpa))) ){ + Tcl_SetResult(interp, "XPA$ERROR: could not map XPA cmdfd to tcl", + TCL_STATIC); + result = TCL_ERROR; + } + else{ + /* hold a reference to this channel outside tcl */ + Tcl_RegisterChannel(NULL, chan); + /* register this channel with tcl */ + Tcl_RegisterChannel(interp, chan); + /* make this Tcl channel unbuffered, so user does not have to flush */ + Tcl_SetChannelOption(interp, chan, "-buffering", "none"); + /* return name so that it can be used by tcl */ + Tcl_SetResult(interp, (char *)Tcl_GetChannelName(chan), TCL_VOLATILE); + result = TCL_OK; + } + } + break; +#endif + case ICmdFdIdx: + if( xpa_cmdfd(xpa) < 0 ) + strcpy(tbuf, "none"); + else + snprintf(tbuf, SZ_LINE, "%d", xpa_cmdfd(xpa)); + Tcl_SetResult(interp, tbuf, TCL_VOLATILE); + result = TCL_OK; + break; +#ifndef HAVE_CYGWIN + case IDataChanIdx: + snprintf(tbuf, SZ_LINE, "sock%d", xpa_datafd(xpa)); + /* make sure we have a valid OS socket fd */ + if( xpa_datafd(xpa) < 0 ){ + Tcl_SetResult(interp, "none", TCL_STATIC); + result = TCL_OK; + } + /* see if this socket already is defined as a tcl variable */ + else if( Tcl_GetChannel(interp, tbuf, NULL) != NULL ){ + Tcl_SetResult(interp, tbuf, TCL_VOLATILE); + result = TCL_OK; + } + /* create new tcl variable for this socket */ + else{ + if( !(chan = Tcl_MakeTcpClientChannel((ClientData)(uintptr_t)xpa_datafd(xpa))) ){ + Tcl_SetResult(interp, "XPA$ERROR: could not map XPA datafd to tcl", + TCL_STATIC); + result = TCL_ERROR; + } + else{ + /* hold a reference to this channel outside tcl */ + Tcl_RegisterChannel(NULL, chan); + /* register this channel with tcl */ + Tcl_RegisterChannel(interp, chan); + /* make this Tcl channel unbuffered, so user does not have to flush */ + Tcl_SetChannelOption(interp, chan, "-buffering", "none"); + /* return name so that it can be used by tcl */ + Tcl_SetResult(interp, (char *)Tcl_GetChannelName(chan), TCL_VOLATILE); + result = TCL_OK; + } + } + break; +#endif + case IDataFdIdx: + if( xpa_datafd(xpa) < 0 ) + strcpy(tbuf, "none"); + else + snprintf(tbuf, SZ_LINE, "%d", xpa_datafd(xpa)); + Tcl_SetResult(interp, tbuf, TCL_VOLATILE); + result = TCL_OK; + break; + case IMethodIdx: + Tcl_SetResult(interp, xpa_method(xpa), TCL_VOLATILE); + result = TCL_OK; + break; + case INameIdx: + Tcl_SetResult(interp, xpa_name(xpa), TCL_VOLATILE); + result = TCL_OK; + break; + case ISendianIdx: + Tcl_SetResult(interp, xpa_sendian(xpa), TCL_VOLATILE); + result = TCL_OK; + break; + case IVersionIdx: + snprintf(tbuf, SZ_LINE, "%s", XPA_VERSION); + Tcl_SetResult(interp, tbuf, TCL_VOLATILE); + result = TCL_OK; + break; + } + return result; +} + +/* + *---------------------------------------------------------------------------- + * + * Routine: XPASetBuf_Tcl + * + * Purpose: Tcl binding to XPASetBuf procedure + * + * Tcl call: + * + * xpasetbuf xpa buf len + * + * Returns: Tcl error code + * + *---------------------------------------------------------------------------- + */ +#ifdef ANSI_FUNC +static int +XPASetBuf_Tcl(ClientData clientData, Tcl_Interp *interp, + int objc, Tcl_Obj *CONST objv[]) +#else +static int XPASetBuf_Tcl(clientData, interp, objc, objv) + ClientData clientData; + Tcl_Interp *interp; + int objc; + Tcl_Obj *CONST objv[]; +#endif +{ + int error; + int len; + char *buf; + XPA xpa; + + /* make sure argument count is correct */ + if( objc < 3 ){ + Tcl_WrongNumArgs(interp, 1, objv, "xpa buf len"); + return(TCL_ERROR); + } + + /* get xpa, which is always arg 1 */ + if( Tcl_GetXPAFromObj(interp, objv[1], TY_SERVER, &xpa) != TCL_OK){ + return(TCL_ERROR); + } + + /* get buf */ + buf = Tcl_GetStringFromObj(objv[2], &len); + /* get len if specified */ + if( objc >= 4 ){ + if( (error = Tcl_GetIntFromObj(interp, objv[3], &len)) != TCL_OK ) + return(error); + } + /* copy buffer to the xpa struct */ + XPASetBuf(xpa, buf, len, 1); + /* return status */ + return(TCL_OK); +} + +/* + *---------------------------------------------------------------------------- + * + * Routine: XPAOpen_Tcl + * + * Purpose: Tcl binding to XPAOpen procedure + * + * Tcl call: + * + * xpaopen mode + * + * mode currently is NULL + * + * Returns: Tcl error code + * + *---------------------------------------------------------------------------- + */ +#ifdef ANSI_FUNC +static int +XPAOpen_Tcl(ClientData clientData, Tcl_Interp *interp, + int objc, Tcl_Obj *CONST objv[]) +#else +static int XPAOpen_Tcl(clientData, interp, objc, objv) + ClientData clientData; + Tcl_Interp *interp; + int objc; + Tcl_Obj *CONST objv[]; +#endif +{ + char *mode; + char tbuf[SZ_LINE]; + XPA xpa; + Tcl_Obj *resultPtr; + + /* make sure argument count is correct */ + if( objc != 2 ){ + Tcl_WrongNumArgs(interp, 1, objv, "mode"); + return(TCL_ERROR); + } + + /* get arguments as strings */ + mode = Tcl_GetStringFromObj(objv[1], NULL); + + /* this will hold the result */ + resultPtr = Tcl_GetObjResult(interp); + + /* set up the tcl handler for the xpa access point */ + xpa = XPAOpen(mode); + if( xpa == NULL ){ + Tcl_SetStringObj(resultPtr, + "XPA$ERROR: could not open XPA", -1); + return(TCL_ERROR); + } + else{ + /* return xpa address to tcl in a string */ + snprintf(tbuf, SZ_LINE, "xpa_%p", xpa); + Tcl_SetStringObj(resultPtr, tbuf, -1); + return(TCL_OK); + } +} + +/* + *---------------------------------------------------------------------------- + * + * Routine: XPAClose_Tcl + * + * Purpose: Tcl binding to XPAClose procedure + * + * Tcl call: + * + * xpaclose xpa + * + * Returns: Tcl error code + * + *---------------------------------------------------------------------------- + */ +#ifdef ANSI_FUNC +static int +XPAClose_Tcl(ClientData clientData, Tcl_Interp *interp, + int objc, Tcl_Obj *CONST objv[]) +#else +static int XPAClose_Tcl(clientData, interp, objc, objv) + ClientData clientData; + Tcl_Interp *interp; + int objc; + Tcl_Obj *CONST objv[]; +#endif +{ + XPA xpa; + + /* make sure argument count is correct */ + if( objc != 2 ){ + Tcl_WrongNumArgs(interp, 1, objv, "xpa"); + return(TCL_ERROR); + } + + /* get xpa, which is always arg 1 */ + if( Tcl_GetXPAFromObj(interp, objv[1], TY_CLIENT, &xpa) != TCL_OK){ + return(TCL_ERROR); + } + + /* reset error/result condition */ + Tcl_ResetResult(interp); + + /* call the XPAClose routine */ + XPAClose(xpa); + return(TCL_OK); +} + +/* + *---------------------------------------------------------------------------- + * + * Routine: XPAGet_Tcl + * + * Purpose: Tcl binding to XPAGet procedure + * + * Tcl call: + * + * set got [xpaget xpa template paramlist mode bufs lens names errs n] + * + * Returns: Tcl error code + * + *---------------------------------------------------------------------------- + */ +#ifdef ANSI_FUNC +static int +XPAGet_Tcl(ClientData clientData, Tcl_Interp *interp, + int objc, Tcl_Obj *CONST objv[]) +#else +static int XPAGet_Tcl(clientData, interp, objc, objv) + ClientData clientData; + Tcl_Interp *interp; + int objc; + Tcl_Obj *CONST objv[]; +#endif +{ + XPA xpa; + int got; + int n; + int i; + size_t *clens=NULL; + char *xpastr; + char *tmpl; + char *paramlist; + char *mode; + /* char *bufs; */ + /* char *lens; */ + char *names; + char *errs; + char **cbufs=NULL; + char **cnames=NULL; + char **cerrs=NULL; + Tcl_Obj *resultPtr; + Tcl_Obj *nullPtr; + Tcl_Obj *bufsPtr; + Tcl_Obj *lensPtr; + Tcl_Obj *namesPtr; + Tcl_Obj *errsPtr; + Tcl_Obj **bufsObjv; + Tcl_Obj **lensObjv; + Tcl_Obj **namesObjv=NULL; + Tcl_Obj **errsObjv=NULL; + + /* make sure argument count is correct */ + if( objc != 10 ){ + Tcl_WrongNumArgs(interp, 1, objv, + "xpa template paramlist mode bufs lens names errs n"); + return(TCL_ERROR); + } + + /* get result pointer */ + resultPtr = Tcl_GetObjResult(interp); + + /* get xpa struct pointer, which might be NULL */ + xpastr = Tcl_GetStringFromObj(objv[1], NULL); + if( TCL_NULLSTR(xpastr) ) + xpa = NULL; + else{ + /* get xpa, which is always arg 1 */ + if( Tcl_GetXPAFromObj(interp, objv[1], TY_CLIENT, &xpa) != TCL_OK){ + Tcl_SetStringObj(resultPtr, "XPA$ERROR: invalid xpa client handle", -1); + return(TCL_ERROR); + } + } + + /* get other args */ + tmpl = Tcl_GetStringFromObj(objv[2], NULL); + paramlist = Tcl_GetStringFromObj(objv[3], NULL); + mode = Tcl_GetStringFromObj(objv[4], NULL); + /* bufs = Tcl_GetStringFromObj(objv[5], NULL); */ + /* lens = Tcl_GetStringFromObj(objv[6], NULL); */ + names = Tcl_GetStringFromObj(objv[7], NULL); + errs = Tcl_GetStringFromObj(objv[8], NULL); + if( (Tcl_GetIntFromObj(interp, objv[9], &n) != TCL_OK) || (n < 1) ){ + n = 1; + } + + /* allocate return buffers */ + cbufs = (char **)xcalloc(n, sizeof(char *)); + bufsObjv = (Tcl_Obj **)xcalloc(n, sizeof(Tcl_Obj *)); + clens = (size_t *)xcalloc(n, sizeof(size_t)); + lensObjv = (Tcl_Obj **)xcalloc(n, sizeof(Tcl_Obj *)); + if( !TCL_NULLSTR(names) ){ + cnames = (char **)xcalloc(n, sizeof(char *)); + namesObjv = (Tcl_Obj **)xcalloc(n, sizeof(Tcl_Obj *)); + } + if( !TCL_NULLSTR(errs) ){ + cerrs = (char **)xcalloc(n, sizeof(char *)); + errsObjv = (Tcl_Obj **)xcalloc(n, sizeof(Tcl_Obj *)); + } + + /* reset before we make C call */ + Tcl_ResetResult(interp); + + /* make the XPA C call */ + got = XPAGet(xpa, tmpl, paramlist, mode, cbufs, clens, cnames, cerrs, n); + + /* if we got anything, fill in the blanks */ + if( got > 0 ){ + /* generate a Tcl object for each return argument */ + for(i=0; i<got; i++){ + bufsObjv[i] = Tcl_NewObj(); + Tcl_SetStringObj(bufsObjv[i], cbufs[i], clens[i]); + + lensObjv[i] = Tcl_NewObj(); + Tcl_SetIntObj(lensObjv[i], clens[i]); + + if( cnames ){ + namesObjv[i] = Tcl_NewObj(); + Tcl_SetStringObj(namesObjv[i], cnames[i], + cnames[i] ? strlen(cnames[i]) : 0); + } + + if( cerrs ){ + errsObjv[i] = Tcl_NewObj(); + Tcl_SetStringObj(errsObjv[i], cerrs[i], + cerrs[i] ? strlen(cerrs[i]) : 0); + } + } + /* make lists from the return arguments and set the return variables */ + bufsPtr = Tcl_NewObj(); + Tcl_SetListObj(bufsPtr, got, bufsObjv); + Tcl_ObjSetVar2(interp, objv[5], NULL, bufsPtr, TCL_PARSE_PART1); + + lensPtr = Tcl_NewObj(); + Tcl_SetListObj(lensPtr, got, lensObjv); + Tcl_ObjSetVar2(interp, objv[6], NULL, lensPtr, TCL_PARSE_PART1); + + if( cnames ){ + namesPtr = Tcl_NewObj(); + Tcl_SetListObj(namesPtr, got, namesObjv); + Tcl_ObjSetVar2(interp, objv[7], NULL, namesPtr, TCL_PARSE_PART1); + } + + if( cerrs ){ + errsPtr = Tcl_NewObj(); + Tcl_SetListObj(errsPtr, got, errsObjv); + Tcl_ObjSetVar2(interp, objv[8], NULL, errsPtr, TCL_PARSE_PART1); + } + } + else{ + nullPtr = Tcl_NewObj(); + Tcl_SetStringObj(nullPtr, "", -1); + Tcl_ObjSetVar2(interp, objv[5], NULL, nullPtr, TCL_PARSE_PART1); + Tcl_ObjSetVar2(interp, objv[6], NULL, nullPtr, TCL_PARSE_PART1); + if( cnames ) + Tcl_ObjSetVar2(interp, objv[7], NULL, nullPtr, TCL_PARSE_PART1); + if( cerrs ) + Tcl_ObjSetVar2(interp, objv[8], NULL, nullPtr, TCL_PARSE_PART1); + } + + /* free up space */ + for(i=0; i<got; i++){ + if( cbufs[i] ) xfree((char *)cbufs[i]); + if( cnames[i] ) xfree((char *)cnames[i]); + if( cerrs[i] ) xfree((char *)cerrs[i]); + } + if( cbufs ) xfree((char *)cbufs); + if( clens ) xfree((char *)clens); + if( cnames ) xfree((char *)cnames); + if( cerrs ) xfree((char *)cerrs); + if( bufsObjv ) xfree((char *)bufsObjv); + if( lensObjv ) xfree((char *)lensObjv); + if( namesObjv ) xfree((char *)namesObjv); + if( errsObjv ) xfree((char *)errsObjv); + + /* return the number of accesses as the tcl function result */ + resultPtr = Tcl_GetObjResult(interp); + Tcl_SetIntObj(resultPtr, got); + + /* return status */ + return(TCL_OK); +} + +/* + *---------------------------------------------------------------------------- + * + * Routine: XPAGetFd_Tcl + * + * Purpose: Tcl binding to XPAGetFd procedure + * + * Tcl call: + * + * set got [xpaget xpa template paramlist mode chans names errs n] + * + * Returns: Tcl error code + * + *---------------------------------------------------------------------------- + */ +#ifdef ANSI_FUNC +static int +XPAGetFd_Tcl(ClientData clientData, Tcl_Interp *interp, + int objc, Tcl_Obj *CONST objv[]) +#else +static int XPAGetFd_Tcl(clientData, interp, objc, objv) + ClientData clientData; + Tcl_Interp *interp; + int objc; + Tcl_Obj *CONST objv[]; +#endif +{ + XPA xpa; + int got; + int n; + int i; + int flag; + int *cfds; + char *xpastr; + char *tmpl; + char *paramlist; + char *mode; + char *names; + char *errs; + char **cnames=NULL; + char **cerrs=NULL; + Tcl_Obj *resultPtr; + Tcl_Obj *nullPtr; + Tcl_Obj *fdPtr; + Tcl_Obj *namesPtr; + Tcl_Obj *errsPtr; + Tcl_Obj **namesObjv=NULL; + Tcl_Obj **errsObjv=NULL; + Tcl_Channel chan; + + /* make sure argument count is correct */ + if( objc != 9 ){ + Tcl_WrongNumArgs(interp, 1, objv, + "xpa template paramlist mode chans names errs n"); + return(TCL_ERROR); + } + + /* get result pointer */ + resultPtr = Tcl_GetObjResult(interp); + + /* get xpa struct pointer, which might be NULL */ + xpastr = Tcl_GetStringFromObj(objv[1], NULL); + if( TCL_NULLSTR(xpastr) ) + xpa = NULL; + else{ + /* get xpa, which is always arg 1 */ + if( Tcl_GetXPAFromObj(interp, objv[1], TY_CLIENT, &xpa) != TCL_OK ){ + Tcl_SetStringObj(resultPtr, "XPA$ERROR: invalid xpa client handle", -1); + return(TCL_ERROR); + } + } + + /* get other args */ + tmpl = Tcl_GetStringFromObj(objv[2], NULL); + paramlist = Tcl_GetStringFromObj(objv[3], NULL); + mode = Tcl_GetStringFromObj(objv[4], NULL); + names = Tcl_GetStringFromObj(objv[6], NULL); + errs = Tcl_GetStringFromObj(objv[7], NULL); + if( (Tcl_GetIntFromObj(interp, objv[8], &n) != TCL_OK) || (n < 1) ){ + n = 1; + } + + /* get file descriptors */ + if( n < 0 ){ + cfds = (int *)xcalloc(1, sizeof(int)); + if( Tcl_ListObjIndex(interp, objv[5], 0, &fdPtr) != TCL_OK ){ + Tcl_SetStringObj(resultPtr, + "XPA$ERROR: invalid channel list passed to xpagetfd", -1); + return(TCL_ERROR); + } + else{ + chan = Tcl_GetChannel(interp, Tcl_GetStringFromObj(fdPtr, NULL), + &flag); + if( chan == NULL ){ + Tcl_SetStringObj(resultPtr, + "XPA$ERROR: invalid channel passed to xpagetfd", -1); + return(TCL_ERROR); + } + if( !(flag&TCL_WRITABLE) ){ + Tcl_SetStringObj(resultPtr, + "XPA$ERROR: non-writable channel passed to xpagetfd", -1); + return(TCL_ERROR); + } + Tcl_GetChannelHandle(chan, TCL_WRITABLE, (ClientData *)&(cfds[0])); + } + } + else{ + cfds = (int *)xcalloc(n, sizeof(int)); + for(i=0; i<n; i++){ + if( Tcl_ListObjIndex(interp, objv[5], i, &fdPtr) != TCL_OK ){ + Tcl_SetStringObj(resultPtr, + "XPA$ERROR: invalid channel list passed to xpagetfd", -1); + return(TCL_ERROR); + } + else{ + chan = Tcl_GetChannel(interp, Tcl_GetStringFromObj(fdPtr, NULL), + &flag); + if( chan == NULL ){ + Tcl_SetStringObj(resultPtr, + "XPA$ERROR: invalid channel passed to xpagetfd", -1); + return(TCL_ERROR); + } + if( !(flag&TCL_WRITABLE) ){ + Tcl_SetStringObj(resultPtr, + "XPA$ERROR: non-writable channel passed to xpagetfd", -1); + return(TCL_ERROR); + } + Tcl_GetChannelHandle(chan, TCL_WRITABLE, (ClientData *)&(cfds[i])); + } + } + } + + /* allocate return buffers */ + if( !TCL_NULLSTR(names) ){ + cnames = (char **)xcalloc(n, sizeof(char *)); + namesObjv = (Tcl_Obj **)xcalloc(n, sizeof(Tcl_Obj *)); + } + if( !TCL_NULLSTR(errs) ){ + cerrs = (char **)xcalloc(n, sizeof(char *)); + errsObjv = (Tcl_Obj **)xcalloc(n, sizeof(Tcl_Obj *)); + } + + /* reset before we make C call */ + Tcl_ResetResult(interp); + + /* make the XPA C call */ + got = XPAGetFd(xpa, tmpl, paramlist, mode, cfds, cnames, cerrs, n); + + /* if we got anything, fill in the blanks */ + if( got > 0 ){ + /* generate a Tcl object for each return argument */ + for(i=0; i<got; i++){ + if( cnames ){ + namesObjv[i] = Tcl_NewObj(); + Tcl_SetStringObj(namesObjv[i], cnames[i], + cnames[i] ? strlen(cnames[i]) : 0); + } + + if( cerrs ){ + errsObjv[i] = Tcl_NewObj(); + Tcl_SetStringObj(errsObjv[i], cerrs[i], + cerrs[i] ? strlen(cerrs[i]) : 0); + } + } + /* make lists from the return arguments and set the return variables */ + if( cnames ){ + namesPtr = Tcl_NewObj(); + Tcl_SetListObj(namesPtr, got, namesObjv); + Tcl_ObjSetVar2(interp, objv[6], NULL, namesPtr, TCL_PARSE_PART1); + } + if( cerrs ){ + errsPtr = Tcl_NewObj(); + Tcl_SetListObj(errsPtr, got, errsObjv); + Tcl_ObjSetVar2(interp, objv[7], NULL, errsPtr, TCL_PARSE_PART1); + } + } + else{ + nullPtr = Tcl_NewObj(); + Tcl_SetStringObj(nullPtr, "", -1); + if( cnames ) + Tcl_ObjSetVar2(interp, objv[6], NULL, nullPtr, TCL_PARSE_PART1); + if( cerrs ) + Tcl_ObjSetVar2(interp, objv[7], NULL, nullPtr, TCL_PARSE_PART1); + } + + /* free up space */ + for(i=0; i<got; i++){ + if( cnames[i] ) xfree((char *)cnames[i]); + if( cerrs[i] ) xfree((char *)cerrs[i]); + } + if( cfds ) xfree((char *)cfds); + if( cnames ) xfree((char *)cnames); + if( cerrs ) xfree((char *)cerrs); + if( namesObjv ) xfree((char *)namesObjv); + if( errsObjv ) xfree((char *)errsObjv); + + /* return the number of accesses as the tcl function result */ + Tcl_SetIntObj(resultPtr, got); + + /* return status */ + return(TCL_OK); +} + +/* + *---------------------------------------------------------------------------- + * + * Routine: XPASet_Tcl + * + * Purpose: Tcl binding to XPASet procedure + * + * Tcl call: + * + * set got [xpaset xpa template paramlist mode buf len names errs n] + * + * Returns: Tcl error code + * + *---------------------------------------------------------------------------- + */ +#ifdef ANSI_FUNC +static int +XPASet_Tcl(ClientData clientData, Tcl_Interp *interp, + int objc, Tcl_Obj *CONST objv[]) +#else +static int XPASet_Tcl(clientData, interp, objc, objv) + ClientData clientData; + Tcl_Interp *interp; + int objc; + Tcl_Obj *CONST objv[]; +#endif +{ + XPA xpa; + int got; + int n; + int i; + int blen; + int len; + char *xpastr; + char *tmpl; + char *paramlist; + char *mode; + char *buf; + char *names; + char *errs; + char **cnames=NULL; + char **cerrs=NULL; + Tcl_Obj *resultPtr; + Tcl_Obj *nullPtr; + Tcl_Obj *namesPtr; + Tcl_Obj *errsPtr; + Tcl_Obj **namesObjv=NULL; + Tcl_Obj **errsObjv=NULL; + + /* make sure argument count is correct */ + if( objc != 10 ){ + Tcl_WrongNumArgs(interp, 1, objv, + "xpa template paramlist mode buf len names errs n"); + return(TCL_ERROR); + } + + /* get result pointer */ + resultPtr = Tcl_GetObjResult(interp); + + /* get xpa struct pointer, which might be NULL */ + xpastr = Tcl_GetStringFromObj(objv[1], NULL); + if( TCL_NULLSTR(xpastr) ) + xpa = NULL; + else{ + /* get xpa, which is always arg 1 */ + if( Tcl_GetXPAFromObj(interp, objv[1], TY_CLIENT, &xpa) != TCL_OK ){ + Tcl_SetStringObj(resultPtr, "XPA$ERROR: invalid xpa client handle", -1); + return(TCL_ERROR); + } + } + + /* get other args */ + tmpl = Tcl_GetStringFromObj(objv[2], NULL); + paramlist = Tcl_GetStringFromObj(objv[3], NULL); + mode = Tcl_GetStringFromObj(objv[4], NULL); + buf = Tcl_GetStringFromObj(objv[5], &blen); + if( (Tcl_GetIntFromObj(interp, objv[6], &len) != TCL_OK) || (len < 0) ){ + len = blen; + } + names = Tcl_GetStringFromObj(objv[7], NULL); + errs = Tcl_GetStringFromObj(objv[8], NULL); + if( (Tcl_GetIntFromObj(interp, objv[9], &n) != TCL_OK) || (n < 1) ){ + n = 1; + } + + /* allocate return buffers */ + if( !TCL_NULLSTR(names) ){ + cnames = (char **)xcalloc(n, sizeof(char *)); + namesObjv = (Tcl_Obj **)xcalloc(n, sizeof(Tcl_Obj *)); + } + if( !TCL_NULLSTR(errs) ){ + cerrs = (char **)xcalloc(n, sizeof(char *)); + errsObjv = (Tcl_Obj **)xcalloc(n, sizeof(Tcl_Obj *)); + } + + /* reset before we make C call */ + Tcl_ResetResult(interp); + + /* make the XPA C call */ + got = XPASet(xpa, tmpl, paramlist, mode, buf, len, cnames, cerrs, n); + + /* if we got anything, fill in the blanks */ + if( got > 0 ){ + /* generate a Tcl object for each return argument */ + for(i=0; i<got; i++){ + if( cnames ){ + namesObjv[i] = Tcl_NewObj(); + Tcl_SetStringObj(namesObjv[i], cnames[i], + cnames[i] ? strlen(cnames[i]) : 0); + } + if( cerrs ){ + errsObjv[i] = Tcl_NewObj(); + Tcl_SetStringObj(errsObjv[i], cerrs[i], + cerrs[i] ? strlen(cerrs[i]) : 0); + } + } + /* make lists from the return arguments and set the return variables */ + if( cnames ){ + namesPtr = Tcl_NewObj(); + Tcl_SetListObj(namesPtr, got, namesObjv); + Tcl_ObjSetVar2(interp, objv[7], NULL, namesPtr, TCL_PARSE_PART1); + } + if( cerrs ){ + errsPtr = Tcl_NewObj(); + Tcl_SetListObj(errsPtr, got, errsObjv); + Tcl_ObjSetVar2(interp, objv[8], NULL, errsPtr, TCL_PARSE_PART1); + } + } + else{ + nullPtr = Tcl_NewObj(); + Tcl_SetStringObj(nullPtr, "", -1); + if( cnames ) + Tcl_ObjSetVar2(interp, objv[7], NULL, nullPtr, TCL_PARSE_PART1); + if( cerrs ) + Tcl_ObjSetVar2(interp, objv[8], NULL, nullPtr, TCL_PARSE_PART1); + } + + /* free up space */ + for(i=0; i<got; i++){ + if( cnames[i] ) xfree((char *)cnames[i]); + if( cerrs[i] ) xfree((char *)cerrs[i]); + } + if( cnames ) xfree((char *)cnames); + if( cerrs ) xfree((char *)cerrs); + if( namesObjv ) xfree((char *)namesObjv); + if( errsObjv ) xfree((char *)errsObjv); + + /* return the number of accesses as the tcl function result */ + Tcl_SetIntObj(resultPtr, got); + + /* return status */ + return(TCL_OK); +} + +/* + *---------------------------------------------------------------------------- + * + * Routine: XPASetFd_Tcl + * + * Purpose: Tcl binding to XPASetFd procedure + * + * Tcl call: + * + * set got [xpasetfd xpa template paramlist mode chan names errs n] + * + * Returns: Tcl error code + * + *---------------------------------------------------------------------------- + */ +#ifdef ANSI_FUNC +static int +XPASetFd_Tcl(ClientData clientData, Tcl_Interp *interp, + int objc, Tcl_Obj *CONST objv[]) +#else +static int XPASetFd_Tcl(clientData, interp, objc, objv) + ClientData clientData; + Tcl_Interp *interp; + int objc; + Tcl_Obj *CONST objv[]; +#endif +{ + XPA xpa; + int got; + int n; + int i; + int flag; + int fd; + char *xpastr; + char *tmpl; + char *paramlist; + char *mode; + char *names; + char *errs; + char **cnames=NULL; + char **cerrs=NULL; + Tcl_Obj *resultPtr; + Tcl_Obj *nullPtr; + Tcl_Obj *namesPtr; + Tcl_Obj *errsPtr; + Tcl_Obj **namesObjv=NULL; + Tcl_Obj **errsObjv=NULL; + Tcl_Channel chan; + + /* make sure argument count is correct */ + if( objc != 9 ){ + Tcl_WrongNumArgs(interp, 1, objv, + "xpa template paramlist mode chan names errs n"); + return(TCL_ERROR); + } + + /* get result pointer */ + resultPtr = Tcl_GetObjResult(interp); + + /* get xpa struct pointer, which might be NULL */ + xpastr = Tcl_GetStringFromObj(objv[1], NULL); + if( TCL_NULLSTR(xpastr) ) + xpa = NULL; + else{ + /* get xpa, which is always arg 1 */ + if( Tcl_GetXPAFromObj(interp, objv[1], TY_CLIENT, &xpa) != TCL_OK){ + Tcl_SetStringObj(resultPtr, "XPA$ERROR: invalid xpa client handle", -1); + return(TCL_ERROR); + } + } + + /* get other args */ + tmpl = Tcl_GetStringFromObj(objv[2], NULL); + paramlist = Tcl_GetStringFromObj(objv[3], NULL); + mode = Tcl_GetStringFromObj(objv[4], NULL); + names = Tcl_GetStringFromObj(objv[6], NULL); + errs = Tcl_GetStringFromObj(objv[7], NULL); + if( (Tcl_GetIntFromObj(interp, objv[8], &n) != TCL_OK) || (n < 1) ){ + n = 1; + } + + /* allocate return buffers */ + if( !TCL_NULLSTR(names) ){ + cnames = (char **)xcalloc(n, sizeof(char *)); + namesObjv = (Tcl_Obj **)xcalloc(n, sizeof(Tcl_Obj *)); + } + if( !TCL_NULLSTR(errs) ){ + cerrs = (char **)xcalloc(n, sizeof(char *)); + errsObjv = (Tcl_Obj **)xcalloc(n, sizeof(Tcl_Obj *)); + } + + /* get file descriptor */ + chan = Tcl_GetChannel(interp, Tcl_GetStringFromObj(objv[5], NULL), &flag); + if( chan == NULL ){ + Tcl_SetStringObj(resultPtr, + "XPA$ERROR: invalid channel passed to xpasetfd", -1); + return(TCL_ERROR); + } + if( !(flag&TCL_READABLE) ){ + Tcl_SetStringObj(resultPtr, + "XPA$ERROR: non-readable channel passed to xpasetfd", -1); + return(TCL_ERROR); + } + Tcl_GetChannelHandle(chan, TCL_READABLE, (ClientData *)&fd); + + /* reset before we make C call */ + Tcl_ResetResult(interp); + + /* make the XPA C call */ + got = XPASetFd(xpa, tmpl, paramlist, mode, fd, cnames, cerrs, n); + + /* if we got anything, fill in the blanks */ + if( got > 0 ){ + /* generate a Tcl object for each return argument */ + for(i=0; i<got; i++){ + if( cnames ){ + namesObjv[i] = Tcl_NewObj(); + Tcl_SetStringObj(namesObjv[i], cnames[i], + cnames[i] ? strlen(cnames[i]) : 0); + } + if( cerrs ){ + errsObjv[i] = Tcl_NewObj(); + Tcl_SetStringObj(errsObjv[i], cerrs[i], + cerrs[i] ? strlen(cerrs[i]) : 0); + } + } + /* make lists from the return arguments and set the return variables */ + if( cnames ){ + namesPtr = Tcl_NewObj(); + Tcl_SetListObj(namesPtr, got, namesObjv); + Tcl_ObjSetVar2(interp, objv[6], NULL, namesPtr, TCL_PARSE_PART1); + } + if( cerrs ){ + errsPtr = Tcl_NewObj(); + Tcl_SetListObj(errsPtr, got, errsObjv); + Tcl_ObjSetVar2(interp, objv[7], NULL, errsPtr, TCL_PARSE_PART1); + } + } + else{ + nullPtr = Tcl_NewObj(); + Tcl_SetStringObj(nullPtr, "", -1); + if( cnames ) + Tcl_ObjSetVar2(interp, objv[6], NULL, nullPtr, TCL_PARSE_PART1); + if( cerrs ) + Tcl_ObjSetVar2(interp, objv[7], NULL, nullPtr, TCL_PARSE_PART1); + } + + /* free up space */ + for(i=0; i<got; i++){ + if( cnames[i] ) xfree((char *)cnames[i]); + if( cerrs[i] ) xfree((char *)cerrs[i]); + } + if( cnames ) xfree((char *)cnames); + if( cerrs ) xfree((char *)cerrs); + if( namesObjv ) xfree((char *)namesObjv); + if( errsObjv ) xfree((char *)errsObjv); + + /* return the number of accesses as the tcl function result */ + Tcl_SetIntObj(resultPtr, got); + + /* return status */ + return(TCL_OK); +} + +/* + *---------------------------------------------------------------------------- + * + * Routine: XPAInfo_Tcl + * + * Purpose: Tcl binding to XPAInfo procedure + * + * Tcl call: + * + * set got [xpainfo xpa template paramlist mode names errs n] + * + * Returns: Tcl error code + * + *---------------------------------------------------------------------------- + */ +#ifdef ANSI_FUNC +static int +XPAInfo_Tcl(ClientData clientData, Tcl_Interp *interp, + int objc, Tcl_Obj *CONST objv[]) +#else +static int XPAInfo_Tcl(clientData, interp, objc, objv) + ClientData clientData; + Tcl_Interp *interp; + int objc; + Tcl_Obj *CONST objv[]; +#endif +{ + XPA xpa; + int got; + int n; + int i; + char *xpastr; + char *tmpl; + char *paramlist; + char *mode; + char *names; + char *errs; + char **cnames=NULL; + char **cerrs=NULL; + Tcl_Obj *resultPtr; + Tcl_Obj *nullPtr; + Tcl_Obj *namesPtr; + Tcl_Obj *errsPtr; + Tcl_Obj **namesObjv=NULL; + Tcl_Obj **errsObjv=NULL; + + /* make sure argument count is correct */ + if( objc != 8 ){ + Tcl_WrongNumArgs(interp, 1, objv, + "xpa template paramlist mode names errs n"); + return(TCL_ERROR); + } + + /* get result pointer */ + resultPtr = Tcl_GetObjResult(interp); + + /* get xpa struct pointer, which might be NULL */ + xpastr = Tcl_GetStringFromObj(objv[1], NULL); + if( TCL_NULLSTR(xpastr) ) + xpa = NULL; + else{ + /* get xpa, which is always arg 1 */ + if( Tcl_GetXPAFromObj(interp, objv[1], TY_CLIENT, &xpa) != TCL_OK){ + Tcl_SetStringObj(resultPtr, "XPA$ERROR: invalid xpa client handle", -1); + return(TCL_ERROR); + } + } + + /* get other args */ + tmpl = Tcl_GetStringFromObj(objv[2], NULL); + paramlist = Tcl_GetStringFromObj(objv[3], NULL); + mode = Tcl_GetStringFromObj(objv[4], NULL); + names = Tcl_GetStringFromObj(objv[5], NULL); + errs = Tcl_GetStringFromObj(objv[6], NULL); + if( (Tcl_GetIntFromObj(interp, objv[7], &n) != TCL_OK) || (n < 1) ){ + n = 1; + } + + /* allocate return buffers */ + if( !TCL_NULLSTR(names) ){ + cnames = (char **)xcalloc(n, sizeof(char *)); + namesObjv = (Tcl_Obj **)xcalloc(n, sizeof(Tcl_Obj *)); + } + if( !TCL_NULLSTR(errs) ){ + cerrs = (char **)xcalloc(n, sizeof(char *)); + errsObjv = (Tcl_Obj **)xcalloc(n, sizeof(Tcl_Obj *)); + } + + /* reset before we make C call */ + Tcl_ResetResult(interp); + + /* make the XPA C call */ + got = XPAInfo(xpa, tmpl, paramlist, mode, cnames, cerrs, n); + + /* if we got anything, fill in the blanks */ + if( got > 0 ){ + /* generate a Tcl object for each return argument */ + for(i=0; i<got; i++){ + if( cnames ){ + namesObjv[i] = Tcl_NewObj(); + Tcl_SetStringObj(namesObjv[i], cnames[i], + cnames[i] ? strlen(cnames[i]) : 0); + } + if( cerrs ){ + errsObjv[i] = Tcl_NewObj(); + Tcl_SetStringObj(errsObjv[i], cerrs[i], + cerrs[i] ? strlen(cerrs[i]) : 0); + } + } + /* make lists from the return arguments and set the return variables */ + if( cnames ){ + namesPtr = Tcl_NewObj(); + Tcl_SetListObj(namesPtr, got, namesObjv); + Tcl_ObjSetVar2(interp, objv[5], NULL, namesPtr, TCL_PARSE_PART1); + } + + if( cerrs ){ + errsPtr = Tcl_NewObj(); + Tcl_SetListObj(errsPtr, got, errsObjv); + Tcl_ObjSetVar2(interp, objv[6], NULL, errsPtr, TCL_PARSE_PART1); + } + } + else{ + nullPtr = Tcl_NewObj(); + Tcl_SetStringObj(nullPtr, "", -1); + if( cnames ) + Tcl_ObjSetVar2(interp, objv[5], NULL, nullPtr, TCL_PARSE_PART1); + if( cerrs ) + Tcl_ObjSetVar2(interp, objv[6], NULL, nullPtr, TCL_PARSE_PART1); + } + + /* free up space */ + for(i=0; i<got; i++){ + if( cnames[i] ) xfree((char *)cnames[i]); + if( cerrs[i] ) xfree((char *)cerrs[i]); + } + if( cnames ) xfree((char *)cnames); + if( cerrs ) xfree((char *)cerrs); + if( namesObjv ) xfree((char *)namesObjv); + if( errsObjv ) xfree((char *)errsObjv); + + /* return the number of accesses as the tcl function result */ + Tcl_SetIntObj(resultPtr, got); + + /* return status */ + return(TCL_OK); +} + +/* + *---------------------------------------------------------------------------- + * + * Routine: XPAAccess_Tcl + * + * Purpose: Tcl binding to XPAAccess procedure + * + * Tcl call: + * + * set got [xpaaccess xpa template paramlist mode names errs n] + * + * Returns: Tcl error code + * + *---------------------------------------------------------------------------- + */ +#ifdef ANSI_FUNC +static int +XPAAccess_Tcl(ClientData clientData, Tcl_Interp *interp, + int objc, Tcl_Obj *CONST objv[]) +#else +static int XPAAccess_Tcl(clientData, interp, objc, objv) + ClientData clientData; + Tcl_Interp *interp; + int objc; + Tcl_Obj *CONST objv[]; +#endif +{ + XPA xpa; + int got; + int n; + int i; + char *xpastr; + char *tmpl; + char *paramlist; + char *mode; + char *names; + char *errs; + char **cnames=NULL; + char **cerrs=NULL; + Tcl_Obj *resultPtr; + Tcl_Obj *nullPtr; + Tcl_Obj *namesPtr; + Tcl_Obj *errsPtr; + Tcl_Obj **namesObjv=NULL; + Tcl_Obj **errsObjv=NULL; + + /* make sure argument count is correct */ + if( objc != 8 ){ + Tcl_WrongNumArgs(interp, 1, objv, + "xpa template paramlist mode names errs n"); + return(TCL_ERROR); + } + + /* get result pointer */ + resultPtr = Tcl_GetObjResult(interp); + + /* get xpa struct pointer, which might be NULL */ + xpastr = Tcl_GetStringFromObj(objv[1], NULL); + if( TCL_NULLSTR(xpastr) ) + xpa = NULL; + else{ + /* get xpa, which is always arg 1 */ + if( Tcl_GetXPAFromObj(interp, objv[1], TY_CLIENT, &xpa) != TCL_OK){ + Tcl_SetStringObj(resultPtr, "XPA$ERROR: invalid xpa client handle", -1); + return(TCL_ERROR); + } + } + + /* get other args */ + tmpl = Tcl_GetStringFromObj(objv[2], NULL); + paramlist = Tcl_GetStringFromObj(objv[3], NULL); + mode = Tcl_GetStringFromObj(objv[4], NULL); + names = Tcl_GetStringFromObj(objv[5], NULL); + errs = Tcl_GetStringFromObj(objv[6], NULL); + if( (Tcl_GetIntFromObj(interp, objv[7], &n) != TCL_OK) || (n < 1) ){ + n = 1; + } + + if( !TCL_NULLSTR(names) ){ + cnames = (char **)xcalloc(n, sizeof(char *)); + namesObjv = (Tcl_Obj **)xcalloc(n, sizeof(Tcl_Obj *)); + } + if( !TCL_NULLSTR(errs) ){ + cerrs = (char **)xcalloc(n, sizeof(char *)); + errsObjv = (Tcl_Obj **)xcalloc(n, sizeof(Tcl_Obj *)); + } + + /* reset before we make C call */ + Tcl_ResetResult(interp); + + /* make the XPA C call */ + got = XPAAccess(xpa, tmpl, paramlist, mode, cnames, cerrs, n); + + /* if we got anything, fill in the blanks */ + if( got > 0 ){ + /* generate a Tcl object for each return argument */ + for(i=0; i<got; i++){ + if( cnames ){ + namesObjv[i] = Tcl_NewObj(); + Tcl_SetStringObj(namesObjv[i], cnames[i], + cnames[i] ? strlen(cnames[i]) : 0); + } + if( cerrs ){ + errsObjv[i] = Tcl_NewObj(); + Tcl_SetStringObj(errsObjv[i], cerrs[i], + cerrs[i] ? strlen(cerrs[i]) : 0); + } + } + /* make lists from the return arguments and set the return variables */ + if( cnames ){ + namesPtr = Tcl_NewObj(); + Tcl_SetListObj(namesPtr, got, namesObjv); + Tcl_ObjSetVar2(interp, objv[5], NULL, namesPtr, TCL_PARSE_PART1); + } + if( cerrs ){ + errsPtr = Tcl_NewObj(); + Tcl_SetListObj(errsPtr, got, errsObjv); + Tcl_ObjSetVar2(interp, objv[6], NULL, errsPtr, TCL_PARSE_PART1); + } + } + else{ + nullPtr = Tcl_NewObj(); + Tcl_SetStringObj(nullPtr, "", -1); + if( cnames ) + Tcl_ObjSetVar2(interp, objv[5], NULL, nullPtr, TCL_PARSE_PART1); + if( cerrs ) + Tcl_ObjSetVar2(interp, objv[6], NULL, nullPtr, TCL_PARSE_PART1); + } + + /* free up space */ + for(i=0; i<got; i++){ + if( cnames[i] ) xfree((char *)cnames[i]); + if( cerrs[i] ) xfree((char *)cerrs[i]); + } + if( cnames ) xfree((char *)cnames); + if( cerrs ) xfree((char *)cerrs); + if( namesObjv ) xfree((char *)namesObjv); + if( errsObjv ) xfree((char *)errsObjv); + + /* return the number of accesses as the tcl function result */ + Tcl_SetIntObj(resultPtr, got); + + /* return status */ + return(TCL_OK); +} + +/* + *---------------------------------------------------------------------------- + * + * Routine: XPANSLookup_Tcl + * + * Purpose: Tcl binding to XPANSLookup procedure + * + * Tcl call: + * + * set got [xpanslookup template type] + * + * Returns: Tcl error code + * + *---------------------------------------------------------------------------- + */ +#ifdef ANSI_FUNC +static int +XPANSLookup_Tcl(ClientData clientData, Tcl_Interp *interp, + int objc, Tcl_Obj *CONST objv[]) +#else +static int XPANSLookup_Tcl(clientData, interp, objc, objv) + ClientData clientData; + Tcl_Interp *interp; + int objc; + Tcl_Obj *CONST objv[]; +#endif +{ + XPA xpa; + int i; + int got; + char *xpastr; + char *tmpl; + char *ttype; + char **xclasses; + char **names; + char **methods; + char **infos; + Tcl_Obj *resultPtr; + Tcl_Obj *nullPtr; + Tcl_Obj *classesPtr; + Tcl_Obj *namesPtr; + Tcl_Obj *methodsPtr; + Tcl_Obj *infosPtr; + Tcl_Obj **classesObjv; + Tcl_Obj **namesObjv; + Tcl_Obj **methodsObjv; + Tcl_Obj **infosObjv; + + /* make sure argument count is correct */ + if( objc != 7 ){ + Tcl_WrongNumArgs(interp, 1, objv, + "template type classes names methods infos"); + return(TCL_ERROR); + } + + /* get result pointer */ + resultPtr = Tcl_GetObjResult(interp); + + /* get other args */ + tmpl = Tcl_GetStringFromObj(objv[1], NULL); + ttype = Tcl_GetStringFromObj(objv[2], NULL); + + /* reset before we make C call */ + Tcl_ResetResult(interp); + + /* get xpa struct pointer, which might be NULL */ + xpastr = Tcl_GetStringFromObj(objv[1], NULL); + if( TCL_NULLSTR(xpastr) ) + xpa = NULL; + else{ + /* get xpa, which is always arg 1 */ + if( Tcl_GetXPAFromObj(interp, objv[1], TY_CLIENT, &xpa) != TCL_OK){ + Tcl_SetStringObj(resultPtr, "XPA$ERROR: invalid xpa client handle", -1); + return(TCL_ERROR); + } + } + + /* make the XPA C call */ + got = XPANSLookup(xpa, tmpl, ttype, &xclasses, &names, &methods, &infos); + + /* if we got anything, fill in the blanks */ + if( got > 0 ){ + /* allocate just enough pointers */ + classesObjv = (Tcl_Obj **)xcalloc(got, sizeof(Tcl_Obj *)); + namesObjv = (Tcl_Obj **)xcalloc(got, sizeof(Tcl_Obj *)); + methodsObjv = (Tcl_Obj **)xcalloc(got, sizeof(Tcl_Obj *)); + infosObjv = (Tcl_Obj **)xcalloc(got, sizeof(Tcl_Obj *)); + + /* generate a Tcl object for each return argument */ + for(i=0; i<got; i++){ + classesObjv[i] = Tcl_NewObj(); + Tcl_SetStringObj(classesObjv[i], xclasses[i], strlen(xclasses[i])); + namesObjv[i] = Tcl_NewObj(); + Tcl_SetStringObj(namesObjv[i], names[i], strlen(names[i])); + methodsObjv[i] = Tcl_NewObj(); + Tcl_SetStringObj(methodsObjv[i], methods[i], strlen(methods[i])); + infosObjv[i] = Tcl_NewObj(); + Tcl_SetStringObj(infosObjv[i], infos[i], strlen(infos[i])); + } + /* make lists from the return arguments and set the return variables */ + classesPtr = Tcl_NewObj(); + Tcl_SetListObj(classesPtr, got, classesObjv); + Tcl_ObjSetVar2(interp, objv[3], NULL, classesPtr, TCL_PARSE_PART1); + + namesPtr = Tcl_NewObj(); + Tcl_SetListObj(namesPtr, got, namesObjv); + Tcl_ObjSetVar2(interp, objv[4], NULL, namesPtr, TCL_PARSE_PART1); + + methodsPtr = Tcl_NewObj(); + Tcl_SetListObj(methodsPtr, got, methodsObjv); + Tcl_ObjSetVar2(interp, objv[5], NULL, methodsPtr, TCL_PARSE_PART1); + + infosPtr = Tcl_NewObj(); + Tcl_SetListObj(infosPtr, got, infosObjv); + Tcl_ObjSetVar2(interp, objv[5], NULL, infosPtr, TCL_PARSE_PART1); + + /* free up the space */ + for(i=0; i<got; i++){ + /* done with these strings */ + xfree(xclasses[i]); + xfree(names[i]); + xfree(methods[i]); + xfree(infos[i]); + } + /* free up arrays alloc'ed by name server */ + if( got > 0 ){ + xfree(xclasses); + xfree(names); + xfree(methods); + xfree(infos); + xfree(classesObjv); + xfree(namesObjv); + xfree(methodsObjv); + xfree(infosObjv); + } + } + else{ + nullPtr = Tcl_NewObj(); + Tcl_SetStringObj(nullPtr, "", -1); + Tcl_ObjSetVar2(interp, objv[3], NULL, nullPtr, TCL_PARSE_PART1); + Tcl_ObjSetVar2(interp, objv[4], NULL, nullPtr, TCL_PARSE_PART1); + Tcl_ObjSetVar2(interp, objv[5], NULL, nullPtr, TCL_PARSE_PART1); + Tcl_ObjSetVar2(interp, objv[6], NULL, nullPtr, TCL_PARSE_PART1); + } + + /* return the number of accesses as the tcl function result */ + Tcl_SetIntObj(resultPtr, got); + + /* return status */ + return(TCL_OK); +} + +/* + *---------------------------------------------------------------------------- + * + * Routine: XPANSKeepAlive_Tcl + * + * Purpose: Tcl binding to XPANSKeepAlive procedure + * + * Tcl call: + * + * xpafree xpa + * + * Returns: Tcl error code + * + *---------------------------------------------------------------------------- + */ +#ifdef ANSI_FUNC +static int +XPANSKeepAlive_Tcl(ClientData clientData, Tcl_Interp *interp, + int objc, Tcl_Obj *CONST objv[]) +#else +static int XPANSKeepAlive_Tcl(clientData, interp, objc, objv) + ClientData clientData; + Tcl_Interp *interp; + int objc; + Tcl_Obj *CONST objv[]; +#endif +{ + XPA xpa; + int type=0; + char *s=NULL; + + /* make sure argument count is correct */ + if( objc < 2 ){ + Tcl_WrongNumArgs(interp, 1, objv, "xpa [type]"); + return(TCL_ERROR); + } + + /* get xpa, which is always arg 1 */ + if( Tcl_GetXPAFromObj(interp, objv[1], TY_SERVER, &xpa) != TCL_OK){ + return(TCL_ERROR); + } + + /* optional type, usually not specified for default */ + if( (objc >= 3) && (s = Tcl_GetStringFromObj(objv[2], NULL)) != NULL ) + type = atoi(s); + + /* reset error/result condition */ + Tcl_ResetResult(interp); + + /* call the XPANSKeepAlive routine */ + XPANSKeepAlive(xpa, type); + + return(TCL_OK); +} + +/* + *---------------------------------------------------------------------------- + * + * Routine: XPARemote_Tcl + * + * Purpose: Tcl binding to XPARemote procedure + * + * Tcl call: + * + * xpaRemote xpa host acl + * + * use the empty string to specify NULL arguments + * + * Returns: Tcl error code + * + *---------------------------------------------------------------------------- + */ +#ifdef ANSI_FUNC +static int +XPARemote_Tcl(ClientData clientData, Tcl_Interp *interp, + int objc, Tcl_Obj *CONST objv[]) +#else +static int XPARemote_Tcl(clientData, interp, objc, objv) + ClientData clientData; + Tcl_Interp *interp; + int objc; + Tcl_Obj *CONST objv[]; +#endif +{ + int got; + char *host; + char *acl="+"; + char *s; + char *mode=NULL; + char tbuf[SZ_LINE]; + XPA xpa; + Tcl_Obj *resultPtr; + + /* make sure argument count is correct */ + if( (objc < 3) || (objc > 5) ){ + Tcl_WrongNumArgs(interp, 1, objv, "xpa host [acl] [-proxy]"); + return(TCL_ERROR); + } + + /* get result pointer */ + resultPtr = Tcl_GetObjResult(interp); + + /* get xpa, which is always arg 1 */ + if( Tcl_GetXPAFromObj(interp, objv[1], TY_SERVER, &xpa) != TCL_OK){ + return(TCL_ERROR); + } + + /* make sure we are using inet sockets */ + if( XPAMtype() != XPA_INET ){ + snprintf(tbuf, SZ_LINE, "remote requires that XPA_METHOD be 'inet'\n"); + Tcl_SetStringObj(resultPtr, tbuf, -1); + return(TCL_ERROR); + } + + /* get required host */ + host = Tcl_GetStringFromObj(objv[2], NULL); + + /* get optional acl */ + if( objc >= 4 ){ + s = Tcl_GetStringFromObj(objv[3], NULL); + if( !strcmp(s, "-proxy") ){ + mode="proxy=true"; + } + else{ + acl = s; + } + } + + /* get optional -proxy switch */ + if( objc == 5 ){ + s = Tcl_GetStringFromObj(objv[4], NULL); + if( !strcmp(s, "-proxy") ){ + mode="proxy=true"; + } + else if( mode ){ + acl = s; + } + else{ + snprintf(tbuf, SZ_LINE, + "XPA$ERROR: invalid arg (%s): xpa -remote host [acl] [-proxy]\n", + s); + Tcl_SetStringObj(resultPtr, tbuf, -1); + return(TCL_ERROR); + } + } + + /* reset error/result condition */ + Tcl_ResetResult(interp); + + /* set up the tcl handler for the xpa access point */ + got = XPARemote(xpa, host, acl, mode); + if( got >= 0 ){ + return(TCL_OK); + } + else{ + snprintf(tbuf, SZ_LINE, + "XPA$ERROR: remote xpans %s failed to process %s\n", + host, xpa->name); + Tcl_SetStringObj(resultPtr, tbuf, -1); + return(TCL_ERROR); + } +} + +/* + *---------------------------------------------------------------------------- + * + * Routine: XPAError_Tcl + * + * Purpose: Tcl binding to XPAError procedure + * + * Tcl call: + * + * xpaerror xpa errmess + * + * Returns: Tcl error code + * + *---------------------------------------------------------------------------- + */ +#ifdef ANSI_FUNC +static int +XPAError_Tcl(ClientData clientData, Tcl_Interp *interp, + int objc, Tcl_Obj *CONST objv[]) +#else +static int XPAError_Tcl(clientData, interp, objc, objv) + ClientData clientData; + Tcl_Interp *interp; + int objc; + Tcl_Obj *CONST objv[]; +#endif +{ + char *message; + XPA xpa; + + /* make sure argument count is correct */ + if( objc != 3 ){ + Tcl_WrongNumArgs(interp, 1, objv, "xpa message"); + return(TCL_ERROR); + } + + /* get xpa, which is always arg 1 */ + if( Tcl_GetXPAFromObj(interp, objv[1], TY_SERVER, &xpa) != TCL_OK){ + return(TCL_ERROR); + } + + /* get message string */ + message = Tcl_GetStringFromObj(objv[2], NULL); + + /* reset error/result condition */ + Tcl_ResetResult(interp); + + /* call the XPAError routine */ + XPAError(xpa, message); + + /* no error message (too lazy) */ + return(TCL_OK); +} + +/* + *---------------------------------------------------------------------------- + * + * Routine: XPAMessage_Tcl + * + * Purpose: Tcl binding to XPAMessage procedure + * + * Tcl call: + * + * xpamessage xpa errmess + * + * Returns: Tcl error code + * + *---------------------------------------------------------------------------- + */ +#ifdef ANSI_FUNC +static int +XPAMessage_Tcl(ClientData clientData, Tcl_Interp *interp, + int objc, Tcl_Obj *CONST objv[]) +#else +static int XPAMessage_Tcl(clientData, interp, objc, objv) + ClientData clientData; + Tcl_Interp *interp; + int objc; + Tcl_Obj *CONST objv[]; +#endif +{ + char *message; + XPA xpa; + + /* make sure argument count is correct */ + if( objc != 3 ){ + Tcl_WrongNumArgs(interp, 1, objv, "xpa message"); + return(TCL_ERROR); + } + + /* get xpa, which is always arg 1 */ + if( Tcl_GetXPAFromObj(interp, objv[1], TY_SERVER, &xpa) != TCL_OK){ + return(TCL_ERROR); + } + + /* get message string */ + message = Tcl_GetStringFromObj(objv[2], NULL); + + /* reset error/result condition */ + Tcl_ResetResult(interp); + + /* call the XPAMessage routine */ + XPAMessage(xpa, message); + + /* no error message (too lazy) */ + return(TCL_OK); +} + +/* + *---------------------------------------------------------------------------- + * + * + * Public Routines and Data + * + * + *---------------------------------------------------------------------------- + */ + +/* + *---------------------------------------------------------------------------- + * + * Routine: Xpa_Init + * + * Purpose: initialize Tcl xpa package + * + * Returns: tcl return code + * + *---------------------------------------------------------------------------- + */ +#ifdef ANSI_FUNC +int +Tclxpa_Init (void *vinterp) +#else +int Tclxpa_Init (vinterp) + void *vinterp; +#endif +{ + Tcl_Interp *interp = (Tcl_Interp *)vinterp; + + if( +#ifdef USE_TCL_STUBS + Tcl_InitStubs(interp, "8.4", 0) +#else + Tcl_PkgRequire(interp, "Tcl", "8.4", 0) +#endif + == NULL) { + return TCL_ERROR; + } + + /* add xpa commands to this interpreter */ + Tcl_CreateObjCommand(interp, "xpanew", XPANew_Tcl, + (ClientData)NULL, (Tcl_CmdDeleteProc *)NULL); + + Tcl_CreateObjCommand(interp, "xpafree", XPAFree_Tcl, + (ClientData)NULL, (Tcl_CmdDeleteProc *)NULL); + + Tcl_CreateObjCommand(interp, "xpainfonew", XPAInfoNew_Tcl, + (ClientData)NULL, (Tcl_CmdDeleteProc *)NULL); + + Tcl_CreateObjCommand(interp, "xpacmdnew", XPACmdNew_Tcl, + (ClientData)NULL, (Tcl_CmdDeleteProc *)NULL); + + Tcl_CreateObjCommand(interp, "xpacmddel", XPACmdDel_Tcl, + (ClientData)NULL, (Tcl_CmdDeleteProc *)NULL); + + Tcl_CreateObjCommand(interp, "xpacmdadd", XPACmdAdd_Tcl, + (ClientData)NULL, (Tcl_CmdDeleteProc *)NULL); + + Tcl_CreateObjCommand(interp, "xparec", XPARec_Tcl, + (ClientData)NULL, (Tcl_CmdDeleteProc *)NULL); + + Tcl_CreateObjCommand(interp, "xpasetbuf", XPASetBuf_Tcl, + (ClientData)NULL, (Tcl_CmdDeleteProc *)NULL); + + Tcl_CreateObjCommand(interp, "xpaopen", XPAOpen_Tcl, + (ClientData)NULL, (Tcl_CmdDeleteProc *)NULL); + + Tcl_CreateObjCommand(interp, "xpaclose", XPAClose_Tcl, + (ClientData)NULL, (Tcl_CmdDeleteProc *)NULL); + + Tcl_CreateObjCommand(interp, "xpaget", XPAGet_Tcl, + (ClientData)NULL, (Tcl_CmdDeleteProc *)NULL); + + Tcl_CreateObjCommand(interp, "xpagetfd", XPAGetFd_Tcl, + (ClientData)NULL, (Tcl_CmdDeleteProc *)NULL); + + Tcl_CreateObjCommand(interp, "xpaset", XPASet_Tcl, + (ClientData)NULL, (Tcl_CmdDeleteProc *)NULL); + + Tcl_CreateObjCommand(interp, "xpasetfd", XPASetFd_Tcl, + (ClientData)NULL, (Tcl_CmdDeleteProc *)NULL); + + Tcl_CreateObjCommand(interp, "xpainfo", XPAInfo_Tcl, + (ClientData)NULL, (Tcl_CmdDeleteProc *)NULL); + + Tcl_CreateObjCommand(interp, "xpaaccess", XPAAccess_Tcl, + (ClientData)NULL, (Tcl_CmdDeleteProc *)NULL); + + Tcl_CreateObjCommand(interp, "xpanslookup", XPANSLookup_Tcl, + (ClientData)NULL, (Tcl_CmdDeleteProc *)NULL); + + Tcl_CreateObjCommand(interp, "xpanskeepalive", XPANSKeepAlive_Tcl, + (ClientData)NULL, (Tcl_CmdDeleteProc *)NULL); + + Tcl_CreateObjCommand(interp, "xparemote", XPARemote_Tcl, + (ClientData)NULL, (Tcl_CmdDeleteProc *)NULL); + + Tcl_CreateObjCommand(interp, "xpaerror", XPAError_Tcl, + (ClientData)NULL, (Tcl_CmdDeleteProc *)NULL); + + Tcl_CreateObjCommand(interp, "xpamessage", XPAMessage_Tcl, + (ClientData)NULL, (Tcl_CmdDeleteProc *)NULL); + + Tcl_PkgProvide(interp, "tclxpa", "2.1"); + return(TCL_OK); +} + +/* required for tclkit 8.6 */ +int Tclxpa_Unload() { return TCL_ERROR; } +int Tclxpa_SafeUnload() { return TCL_ERROR; } +int Tclxpa_SafeInit() { return TCL_ERROR; } + + +int xpa_tclbinding = 1; + +#else + +int xpa_tclbinding = 0; + +#endif diff --git a/xpa/tcl.m4 b/xpa/tcl.m4 new file mode 100644 index 0000000..8125361 --- /dev/null +++ b/xpa/tcl.m4 @@ -0,0 +1,2464 @@ +#------------------------------------------------------------------------ +# SC_PATH_TCLCONFIG -- +# +# Locate the tclConfig.sh file and perform a sanity check on +# the Tcl compile flags +# +# Arguments: +# none +# +# Results: +# +# Adds the following arguments to configure: +# --with-tcl=... +# +# Defines the following vars: +# TCL_BIN_DIR Full path to the directory containing +# the tclConfig.sh file +#------------------------------------------------------------------------ + +AC_DEFUN(SC_PATH_TCLCONFIG, [ + # + # Ok, lets find the tcl configuration + # First, look for one uninstalled. + # the alternative search directory is invoked by --with-tcl + # + + if test x"${no_tcl}" = x ; then + # we reset no_tcl in case something fails here + no_tcl=true + AC_ARG_WITH(tcl, [ --with-tcl directory containing tcl configuration (tclConfig.sh)], with_tclconfig=${withval}) + AC_MSG_CHECKING([for Tcl configuration]) + if test x"${withval}" != xno ; then + AC_CACHE_VAL(ac_cv_c_tclconfig,[ + + # First check to see if --with-tcl was specified. + if test x"${with_tclconfig}" != x ; then + if test -f "${with_tclconfig}/tclConfig.sh" ; then + ac_cv_c_tclconfig=`(cd ${with_tclconfig}; pwd)` + else + AC_MSG_RESULT([${with_tclconfig} directory doesn't contain tclConfig.sh]) + fi + fi + + # then check for a private Tcl installation + if test x"${ac_cv_c_tclconfig}" = x ; then + for i in \ + ../tcl \ + `ls -dr ../tcl[[8-9]].[[0-9]]* 2>/dev/null` \ + ../../tcl \ + `ls -dr ../../tcl[[8-9]].[[0-9]]* 2>/dev/null` \ + ../../../tcl \ + `ls -dr ../../../tcl[[8-9]].[[0-9]]* 2>/dev/null` ; do + if test -f "$i/unix/tclConfig.sh" ; then + ac_cv_c_tclconfig=`(cd $i/unix; pwd)` + break + fi + done + fi + + # check in a few common install locations + if test x"${ac_cv_c_tclconfig}" = x ; then + for i in `ls -d ${libdir} 2>/dev/null` \ + `ls -d /usr/local/lib 2>/dev/null` \ + `ls -d /usr/contrib/lib 2>/dev/null` \ + `ls -d /usr/lib 2>/dev/null` \ + ; do + if test -f "$i/tclConfig.sh" ; then + ac_cv_c_tclconfig=`(cd $i; pwd)` + break + fi + done + fi + + # check in a few other private locations + if test x"${ac_cv_c_tclconfig}" = x ; then + for i in \ + ${srcdir}/../tcl \ + `ls -dr ${srcdir}/../tcl[[8-9]].[[0-9]]* 2>/dev/null` ; do + if test -f "$i/unix/tclConfig.sh" ; then + ac_cv_c_tclconfig=`(cd $i/unix; pwd)` + break + fi + done + fi + ]) + else + AC_MSG_RESULT(skipping Tcl configuration) + ac_cv_c_tclconfig="none" + fi + + if test x"${ac_cv_c_tclconfig}" = x ; then + TCL_BIN_DIR="# no Tcl configs found" + AC_MSG_RESULT(can't find Tcl configuration definitions) +# no Tcl is OK egm 03/25/03 +# AC_MSG_WARN(Can't find Tcl configuration definitions) +# exit 0 + elif test x"${ac_cv_c_tclconfig}" = xnone ; then + TCL_BIN_DIR="" + else + no_tcl= + TCL_BIN_DIR=${ac_cv_c_tclconfig} + AC_MSG_RESULT(found $TCL_BIN_DIR/tclConfig.sh) + fi + fi +]) + +#------------------------------------------------------------------------ +# SC_PATH_TKCONFIG -- +# +# Locate the tkConfig.sh file +# +# Arguments: +# none +# +# Results: +# +# Adds the following arguments to configure: +# --with-tk=... +# +# Defines the following vars: +# TK_BIN_DIR Full path to the directory containing +# the tkConfig.sh file +#------------------------------------------------------------------------ + +AC_DEFUN(SC_PATH_TKCONFIG, [ + # + # Ok, lets find the tk configuration + # First, look for one uninstalled. + # the alternative search directory is invoked by --with-tk + # + + if test x"${no_tk}" = x ; then + # we reset no_tk in case something fails here + no_tk=true + AC_ARG_WITH(tk, [ --with-tk directory containing tk configuration (tkConfig.sh)], with_tkconfig=${withval}) + AC_MSG_CHECKING([for Tk configuration]) + AC_CACHE_VAL(ac_cv_c_tkconfig,[ + + # First check to see if --with-tkconfig was specified. + if test x"${with_tkconfig}" != x ; then + if test -f "${with_tkconfig}/tkConfig.sh" ; then + ac_cv_c_tkconfig=`(cd ${with_tkconfig}; pwd)` + else + AC_MSG_RESULT([${with_tkconfig} directory doesn't contain tkConfig.sh]) + fi + fi + + # then check for a private Tk library + if test x"${ac_cv_c_tkconfig}" = x ; then + for i in \ + ../tk \ + `ls -dr ../tk[[8-9]].[[0-9]]* 2>/dev/null` \ + ../../tk \ + `ls -dr ../../tk[[8-9]].[[0-9]]* 2>/dev/null` \ + ../../../tk \ + `ls -dr ../../../tk[[8-9]].[[0-9]]* 2>/dev/null` ; do + if test -f "$i/unix/tkConfig.sh" ; then + ac_cv_c_tkconfig=`(cd $i/unix; pwd)` + break + fi + done + fi + # check in a few common install locations + if test x"${ac_cv_c_tkconfig}" = x ; then + for i in `ls -d ${libdir} 2>/dev/null` \ + `ls -d /usr/local/lib 2>/dev/null` \ + `ls -d /usr/contrib/lib 2>/dev/null` \ + `ls -d /usr/lib 2>/dev/null` \ + ; do + if test -f "$i/tkConfig.sh" ; then + ac_cv_c_tkconfig=`(cd $i; pwd)` + break + fi + done + fi + # check in a few other private locations + if test x"${ac_cv_c_tkconfig}" = x ; then + for i in \ + ${srcdir}/../tk \ + `ls -dr ${srcdir}/../tk[[8-9]].[[0-9]]* 2>/dev/null` ; do + if test -f "$i/unix/tkConfig.sh" ; then + ac_cv_c_tkconfig=`(cd $i/unix; pwd)` + break + fi + done + fi + ]) + if test x"${ac_cv_c_tkconfig}" = x ; then + TK_BIN_DIR="# no Tk configs found" + AC_MSG_RESULT(can't find Tk configuration definitions) +# no Tk is OK egm 03/25/03 +# AC_MSG_WARN(Can't find Tk configuration definitions) +# exit 0 + else + no_tk= + TK_BIN_DIR=${ac_cv_c_tkconfig} + AC_MSG_RESULT(found $TK_BIN_DIR/tkConfig.sh) + fi + fi + +]) + +#------------------------------------------------------------------------ +# SC_LOAD_TCLCONFIG -- +# +# Load the tclConfig.sh file +# +# Arguments: +# +# Requires the following vars to be set: +# TCL_BIN_DIR +# +# Results: +# +# Subst the following vars: +# TCL_BIN_DIR +# TCL_SRC_DIR +# TCL_LIB_FILE +# +#------------------------------------------------------------------------ + +AC_DEFUN(SC_LOAD_TCLCONFIG, [ + AC_MSG_CHECKING([for existence of $TCL_BIN_DIR/tclConfig.sh]) + + if test -f "$TCL_BIN_DIR/tclConfig.sh" ; then + AC_MSG_RESULT([loading]) + . $TCL_BIN_DIR/tclConfig.sh + else + AC_MSG_RESULT([file not found]) + fi + + # + # If the TCL_BIN_DIR is the build directory (not the install directory), + # then set the common variable name to the value of the build variables. + # For example, the variable TCL_LIB_SPEC will be set to the value + # of TCL_BUILD_LIB_SPEC. An extension should make use of TCL_LIB_SPEC + # instead of TCL_BUILD_LIB_SPEC since it will work with both an + # installed and uninstalled version of Tcl. + # + + if test -f $TCL_BIN_DIR/Makefile ; then + TCL_LIB_SPEC=${TCL_BUILD_LIB_SPEC} + TCL_STUB_LIB_SPEC=${TCL_BUILD_STUB_LIB_SPEC} + TCL_STUB_LIB_PATH=${TCL_BUILD_STUB_LIB_PATH} + fi + + # + # eval is required to do the TCL_DBGX substitution + # + + eval "TCL_LIB_FILE=\"${TCL_LIB_FILE}\"" + eval "TCL_LIB_FLAG=\"${TCL_LIB_FLAG}\"" + eval "TCL_LIB_SPEC=\"${TCL_LIB_SPEC}\"" + + eval "TCL_STUB_LIB_FILE=\"${TCL_STUB_LIB_FILE}\"" + eval "TCL_STUB_LIB_FLAG=\"${TCL_STUB_LIB_FLAG}\"" + eval "TCL_STUB_LIB_SPEC=\"${TCL_STUB_LIB_SPEC}\"" + + AC_SUBST(TCL_VERSION) + AC_SUBST(TCL_BIN_DIR) + AC_SUBST(TCL_SRC_DIR) + + AC_SUBST(TCL_LIB_FILE) + AC_SUBST(TCL_LIB_FLAG) + AC_SUBST(TCL_LIB_SPEC) + + AC_SUBST(TCL_STUB_LIB_FILE) + AC_SUBST(TCL_STUB_LIB_FLAG) + AC_SUBST(TCL_STUB_LIB_SPEC) +]) + +#------------------------------------------------------------------------ +# SC_LOAD_TKCONFIG -- +# +# Load the tkConfig.sh file +# +# Arguments: +# +# Requires the following vars to be set: +# TK_BIN_DIR +# +# Results: +# +# Sets the following vars that should be in tkConfig.sh: +# TK_BIN_DIR +#------------------------------------------------------------------------ + +AC_DEFUN(SC_LOAD_TKCONFIG, [ + AC_MSG_CHECKING([for existence of $TK_BIN_DIR/tkConfig.sh]) + + if test -f "$TK_BIN_DIR/tkConfig.sh" ; then + AC_MSG_RESULT([loading]) + . $TK_BIN_DIR/tkConfig.sh + else + AC_MSG_RESULT([could not find $TK_BIN_DIR/tkConfig.sh]) + fi + + AC_SUBST(TK_VERSION) + AC_SUBST(TK_BIN_DIR) + AC_SUBST(TK_SRC_DIR) + AC_SUBST(TK_LIB_FILE) +]) + +#------------------------------------------------------------------------ +# SC_ENABLE_SHARED -- +# +# Allows the building of shared libraries +# +# Arguments: +# none +# +# Results: +# +# Adds the following arguments to configure: +# --enable-shared=yes|no +# +# Defines the following vars: +# STATIC_BUILD Used for building import/export libraries +# on Windows. +# +# Sets the following vars: +# SHARED_BUILD Value of 1 or 0 +#------------------------------------------------------------------------ + +AC_DEFUN(SC_ENABLE_SHARED, [ + AC_MSG_CHECKING([how to build libraries]) + AC_ARG_ENABLE(shared, + [ --enable-shared build and link with shared libraries [--enable-shared]], + [tcl_ok=$enableval], [tcl_ok=yes]) + + if test "${enable_shared+set}" = set; then + enableval="$enable_shared" + tcl_ok=$enableval + else + tcl_ok=yes + fi + + if test "$tcl_ok" = "yes" ; then + AC_MSG_RESULT([shared]) + SHARED_BUILD=1 + else + AC_MSG_RESULT([static]) + SHARED_BUILD=0 + AC_DEFINE(STATIC_BUILD) + fi +]) + +#------------------------------------------------------------------------ +# SC_ENABLE_FRAMEWORK -- +# +# Allows the building of shared libraries into frameworks +# +# Arguments: +# none +# +# Results: +# +# Adds the following arguments to configure: +# --enable-framework=yes|no +# +# Sets the following vars: +# FRAMEWORK_BUILD Value of 1 or 0 +#------------------------------------------------------------------------ + +AC_DEFUN(SC_ENABLE_FRAMEWORK, [ + AC_MSG_CHECKING([how to package libraries]) + AC_ARG_ENABLE(framework, + [ --enable-framework package shared libraries in frameworks [--disable-framework]], + [tcl_ok=$enableval], [tcl_ok=no]) + + if test "${enable_framework+set}" = set; then + enableval="$enable_framework" + tcl_ok=$enableval + else + tcl_ok=no + fi + + if test "$tcl_ok" = "yes" ; then + AC_MSG_RESULT([framework]) + FRAMEWORK_BUILD=1 + if test "${SHARED_BUILD}" = "0" ; then + AC_MSG_WARN("Frameworks can only be built if --enable-shared is yes") + FRAMEWORK_BUILD=0 + fi + else + AC_MSG_RESULT([standard shared library]) + FRAMEWORK_BUILD=0 + fi +]) + +#------------------------------------------------------------------------ +# SC_ENABLE_THREADS -- +# +# Specify if thread support should be enabled +# +# Arguments: +# none +# +# Results: +# +# Adds the following arguments to configure: +# --enable-threads +# +# Sets the following vars: +# THREADS_LIBS Thread library(s) +# +# Defines the following vars: +# TCL_THREADS +# _REENTRANT +# _THREAD_SAFE +# +#------------------------------------------------------------------------ + +AC_DEFUN(SC_ENABLE_THREADS, [ + AC_MSG_CHECKING(for building with threads) + AC_ARG_ENABLE(threads, [ --enable-threads build with threads], + [tcl_ok=$enableval], [tcl_ok=no]) + + if test "$tcl_ok" = "yes"; then + AC_MSG_RESULT(yes) + TCL_THREADS=1 + AC_DEFINE(TCL_THREADS) + # USE_THREAD_ALLOC tells us to try the special thread-based + # allocator that significantly reduces lock contention + AC_DEFINE(USE_THREAD_ALLOC) + AC_DEFINE(_REENTRANT) + AC_DEFINE(_THREAD_SAFE) + AC_CHECK_LIB(pthread,pthread_mutex_init,tcl_ok=yes,tcl_ok=no) + if test "$tcl_ok" = "no"; then + # Check a little harder for __pthread_mutex_init in the same + # library, as some systems hide it there until pthread.h is + # defined. We could alternatively do an AC_TRY_COMPILE with + # pthread.h, but that will work with libpthread really doesn't + # exist, like AIX 4.2. [Bug: 4359] + AC_CHECK_LIB(pthread,__pthread_mutex_init,tcl_ok=yes,tcl_ok=no) + fi + + if test "$tcl_ok" = "yes"; then + # The space is needed + THREADS_LIBS=" -lpthread" + else + AC_CHECK_LIB(pthreads,pthread_mutex_init,tcl_ok=yes,tcl_ok=no) + if test "$tcl_ok" = "yes"; then + # The space is needed + THREADS_LIBS=" -lpthreads" + else + AC_CHECK_LIB(c,pthread_mutex_init,tcl_ok=yes,tcl_ok=no) + if test "$tcl_ok" = "no"; then + AC_CHECK_LIB(c_r,pthread_mutex_init,tcl_ok=yes,tcl_ok=no) + if test "$tcl_ok" = "yes"; then + # The space is needed + THREADS_LIBS=" -pthread" + else + TCL_THREADS=0 + AC_MSG_WARN("Don t know how to find pthread lib on your system - you must disable thread support or edit the LIBS in the Makefile...") + fi + fi + fi + fi + + # Does the pthread-implementation provide + # 'pthread_attr_setstacksize' ? + + ac_saved_libs=$LIBS + LIBS="$LIBS $THREADS_LIBS" + AC_CHECK_FUNCS(pthread_attr_setstacksize) + LIBS=$ac_saved_libs + AC_CHECK_FUNCS(readdir_r) + else + TCL_THREADS=0 + AC_MSG_RESULT([no (default)]) + fi + AC_SUBST(TCL_THREADS) +]) + +#------------------------------------------------------------------------ +# SC_ENABLE_SYMBOLS -- +# +# Specify if debugging symbols should be used. +# Memory (TCL_MEM_DEBUG) and compile (TCL_COMPILE_DEBUG) debugging +# can also be enabled. +# +# Arguments: +# none +# +# Requires the following vars to be set in the Makefile: +# CFLAGS_DEBUG +# CFLAGS_OPTIMIZE +# LDFLAGS_DEBUG +# LDFLAGS_OPTIMIZE +# +# Results: +# +# Adds the following arguments to configure: +# --enable-symbols +# +# Defines the following vars: +# CFLAGS_DEFAULT Sets to $(CFLAGS_DEBUG) if true +# Sets to $(CFLAGS_OPTIMIZE) if false +# LDFLAGS_DEFAULT Sets to $(LDFLAGS_DEBUG) if true +# Sets to $(LDFLAGS_OPTIMIZE) if false +# DBGX Debug library extension +# +#------------------------------------------------------------------------ + +AC_DEFUN(SC_ENABLE_SYMBOLS, [ + AC_MSG_CHECKING([for build with symbols]) + AC_ARG_ENABLE(symbols, [ --enable-symbols build with debugging symbols [--disable-symbols]], [tcl_ok=$enableval], [tcl_ok=no]) +# FIXME: Currently, LDFLAGS_DEFAULT is not used, it should work like CFLAGS_DEFAULT. + if test "$tcl_ok" = "no"; then + CFLAGS_DEFAULT='$(CFLAGS_OPTIMIZE)' + LDFLAGS_DEFAULT='$(LDFLAGS_OPTIMIZE)' + DBGX="" + AC_MSG_RESULT([no]) + else + CFLAGS_DEFAULT='$(CFLAGS_DEBUG)' + LDFLAGS_DEFAULT='$(LDFLAGS_DEBUG)' + DBGX=g + if test "$tcl_ok" = "yes"; then + AC_MSG_RESULT([yes (standard debugging)]) + fi + fi + AC_SUBST(CFLAGS_DEFAULT) + AC_SUBST(LDFLAGS_DEFAULT) + + if test "$tcl_ok" = "mem" -o "$tcl_ok" = "all"; then + AC_DEFINE(TCL_MEM_DEBUG) + fi + + if test "$tcl_ok" = "compile" -o "$tcl_ok" = "all"; then + AC_DEFINE(TCL_COMPILE_DEBUG) + AC_DEFINE(TCL_COMPILE_STATS) + fi + + if test "$tcl_ok" != "yes" -a "$tcl_ok" != "no"; then + if test "$tcl_ok" = "all"; then + AC_MSG_RESULT([enabled symbols mem compile debugging]) + else + AC_MSG_RESULT([enabled $tcl_ok debugging]) + fi + fi +]) + +#------------------------------------------------------------------------ +# SC_ENABLE_LANGINFO -- +# +# Allows use of modern nl_langinfo check for better l10n. +# This is only relevant for Unix. +# +# Arguments: +# none +# +# Results: +# +# Adds the following arguments to configure: +# --enable-langinfo=yes|no (default is yes) +# +# Defines the following vars: +# HAVE_LANGINFO Triggers use of nl_langinfo if defined. +# +#------------------------------------------------------------------------ + +AC_DEFUN(SC_ENABLE_LANGINFO, [ + AC_ARG_ENABLE(langinfo, + [ --enable-langinfo use nl_langinfo if possible to determine + encoding at startup, otherwise use old heuristic], + [langinfo_ok=$enableval], [langinfo_ok=yes]) + + HAVE_LANGINFO=0 + if test "$langinfo_ok" = "yes"; then + if test "$langinfo_ok" = "yes"; then + AC_CHECK_HEADER(langinfo.h,[langinfo_ok=yes],[langinfo_ok=no]) + fi + fi + AC_MSG_CHECKING([whether to use nl_langinfo]) + if test "$langinfo_ok" = "yes"; then + AC_TRY_COMPILE([#include <langinfo.h>], + [nl_langinfo(CODESET);],[langinfo_ok=yes],[langinfo_ok=no]) + if test "$langinfo_ok" = "no"; then + langinfo_ok="no (could not compile with nl_langinfo)"; + fi + if test "$langinfo_ok" = "yes"; then + AC_DEFINE(HAVE_LANGINFO) + fi + fi + AC_MSG_RESULT([$langinfo_ok]) +]) + +#-------------------------------------------------------------------- +# SC_CONFIG_MANPAGES +# +# Decide whether to use symlinks for linking the manpages and +# whether to compress the manpages after installation. +# +# Arguments: +# none +# +# Results: +# +# Adds the following arguments to configure: +# --enable-man-symlinks +# --enable-man-compression=PROG +# +# Defines the following variable: +# +# MKLINKS_FLAGS - The apropriate flags for mkLinks +# according to the user's selection. +# +#-------------------------------------------------------------------- +AC_DEFUN(SC_CONFIG_MANPAGES, [ + + AC_MSG_CHECKING([whether to use symlinks for manpages]) + AC_ARG_ENABLE(man-symlinks, + [ --enable-man-symlinks use symlinks for the manpages], + test "$enableval" != "no" && MKLINKS_FLAGS="$MKLINKS_FLAGS --symlinks", + enableval="no") + AC_MSG_RESULT([$enableval]) + + AC_MSG_CHECKING([compression for manpages]) + AC_ARG_ENABLE(man-compression, + [ --enable-man-compression=PROG + compress the manpages with PROG], + test "$enableval" = "yes" && echo && AC_MSG_ERROR([missing argument to --enable-man-compression]) + test "$enableval" != "no" && MKLINKS_FLAGS="$MKLINKS_FLAGS --compress $enableval", + enableval="no") + AC_MSG_RESULT([$enableval]) + + AC_SUBST(MKLINKS_FLAGS) +]) + +#-------------------------------------------------------------------- +# SC_CONFIG_CFLAGS +# +# Try to determine the proper flags to pass to the compiler +# for building shared libraries and other such nonsense. +# +# Arguments: +# none +# +# Results: +# +# Defines and substitutes the following vars: +# +# DL_OBJS - Name of the object file that implements dynamic +# loading for Tcl on this system. +# DL_LIBS - Library file(s) to include in tclsh and other base +# applications in order for the "load" command to work. +# LDFLAGS - Flags to pass to the compiler when linking object +# files into an executable application binary such +# as tclsh. +# LD_SEARCH_FLAGS-Flags to pass to ld, such as "-R /usr/local/tcl/lib", +# that tell the run-time dynamic linker where to look +# for shared libraries such as libtcl.so. Depends on +# the variable LIB_RUNTIME_DIR in the Makefile. Could +# be the same as CC_SEARCH_FLAGS if ${CC} is used to link. +# CC_SEARCH_FLAGS-Flags to pass to ${CC}, such as "-Wl,-rpath,/usr/local/tcl/lib", +# that tell the run-time dynamic linker where to look +# for shared libraries such as libtcl.so. Depends on +# the variable LIB_RUNTIME_DIR in the Makefile. +# MAKE_LIB - Command to execute to build the a library; +# differs when building shared or static. +# MAKE_STUB_LIB - +# Command to execute to build a stub library. +# INSTALL_LIB - Command to execute to install a library; +# differs when building shared or static. +# INSTALL_STUB_LIB - +# Command to execute to install a stub library. +# STLIB_LD - Base command to use for combining object files +# into a static library. +# SHLIB_CFLAGS - Flags to pass to cc when compiling the components +# of a shared library (may request position-independent +# code, among other things). +# SHLIB_LD - Base command to use for combining object files +# into a shared library. +# SHLIB_LD_FLAGS -Flags to pass when building a shared library. This +# differes from the SHLIB_CFLAGS as it is not used +# when building object files or executables. +# SHLIB_LD_LIBS - Dependent libraries for the linker to scan when +# creating shared libraries. This symbol typically +# goes at the end of the "ld" commands that build +# shared libraries. The value of the symbol is +# "${LIBS}" if all of the dependent libraries should +# be specified when creating a shared library. If +# dependent libraries should not be specified (as on +# SunOS 4.x, where they cause the link to fail, or in +# general if Tcl and Tk aren't themselves shared +# libraries), then this symbol has an empty string +# as its value. +# SHLIB_SUFFIX - Suffix to use for the names of dynamically loadable +# extensions. An empty string means we don't know how +# to use shared libraries on this platform. +# TCL_SHLIB_LD_EXTRAS - Additional element which are added to SHLIB_LD_LIBS +# TK_SHLIB_LD_EXTRAS for the build of Tcl and Tk, but not recorded in the +# tclConfig.sh, since they are only used for the build +# of Tcl and Tk. +# Examples: MacOS X records the library version and +# compatibility version in the shared library. But +# of course the Tcl version of this is only used for Tcl. +# LIB_SUFFIX - Specifies everything that comes after the "libfoo" +# in a static or shared library name, using the $VERSION variable +# to put the version in the right place. This is used +# by platforms that need non-standard library names. +# Examples: ${VERSION}.so.1.1 on NetBSD, since it needs +# to have a version after the .so, and ${VERSION}.a +# on AIX, since a shared library needs to have +# a .a extension whereas shared objects for loadable +# extensions have a .so extension. Defaults to +# ${VERSION}${SHLIB_SUFFIX}. +# TCL_NEEDS_EXP_FILE - +# 1 means that an export file is needed to link to a +# shared library. +# TCL_EXP_FILE - The name of the installed export / import file which +# should be used to link to the Tcl shared library. +# Empty if Tcl is unshared. +# TCL_BUILD_EXP_FILE - +# The name of the built export / import file which +# should be used to link to the Tcl shared library. +# Empty if Tcl is unshared. +# CFLAGS_DEBUG - +# Flags used when running the compiler in debug mode +# CFLAGS_OPTIMIZE - +# Flags used when running the compiler in optimize mode +# EXTRA_CFLAGS +# +#-------------------------------------------------------------------- + +AC_DEFUN(SC_CONFIG_CFLAGS, [ + + # Step 0.a: Enable 64 bit support? + + AC_MSG_CHECKING([if 64bit support is requested]) + AC_ARG_ENABLE(64bit,[ --enable-64bit enable 64bit support (where applicable)],,enableval="no") + + if test "$enableval" = "yes"; then + do64bit=yes + else + do64bit=no + fi + AC_MSG_RESULT($do64bit) + + # Step 0.b: Enable Solaris 64 bit VIS support? + + AC_MSG_CHECKING([if 64bit Sparc VIS support is requested]) + AC_ARG_ENABLE(64bit-vis,[ --enable-64bit-vis enable 64bit Sparc VIS support],,enableval="no") + + if test "$enableval" = "yes"; then + # Force 64bit on with VIS + do64bit=yes + do64bitVIS=yes + else + do64bitVIS=no + fi + AC_MSG_RESULT($do64bitVIS) + + # Step 1: set the variable "system" to hold the name and version number + # for the system. This can usually be done via the "uname" command, but + # there are a few systems, like Next, where this doesn't work. + + AC_MSG_CHECKING([system version (for dynamic loading)]) + if test -f /usr/lib/NextStep/software_version; then + system=NEXTSTEP-`awk '/3/,/3/' /usr/lib/NextStep/software_version` + else + system=`uname -s`-`uname -r` + if test "$?" -ne 0 ; then + AC_MSG_RESULT([unknown (can't find uname command)]) + system=unknown + else + # Special check for weird MP-RAS system (uname returns weird + # results, and the version is kept in special file). + + if test -r /etc/.relid -a "X`uname -n`" = "X`uname -s`" ; then + system=MP-RAS-`awk '{print $3}' /etc/.relid'` + fi + if test "`uname -s`" = "AIX" ; then + system=AIX-`uname -v`.`uname -r` + fi + AC_MSG_RESULT($system) + fi + fi + + # Step 2: check for existence of -ldl library. This is needed because + # Linux can use either -ldl or -ldld for dynamic loading. + + AC_CHECK_LIB(dl, dlopen, have_dl=yes, have_dl=no) + + # Require ranlib early so we can override it in special cases below. + + AC_REQUIRE([AC_PROG_RANLIB]) + + # Step 3: set configuration options based on system name and version. + + do64bit_ok=no + EXTRA_CFLAGS="" + TCL_EXPORT_FILE_SUFFIX="" + UNSHARED_LIB_SUFFIX="" + TCL_TRIM_DOTS='`echo ${VERSION} | tr -d .`' + ECHO_VERSION='`echo ${VERSION}`' + TCL_LIB_VERSIONS_OK=ok + CFLAGS_DEBUG=-g + CFLAGS_OPTIMIZE=-O + if test "$GCC" = "yes" ; then + CFLAGS_WARNING="-Wall -Wconversion -Wno-implicit-int" + else + CFLAGS_WARNING="" + fi + TCL_NEEDS_EXP_FILE=0 + TCL_BUILD_EXP_FILE="" + TCL_EXP_FILE="" +dnl FIXME: Replace AC_CHECK_PROG with AC_CHECK_TOOL once cross compiling is fixed. +dnl AC_CHECK_TOOL(AR, ar) + AC_CHECK_PROG(AR, ar, ar) + if test "${AR}" = "" ; then + AC_MSG_ERROR([Required archive tool 'ar' not found on PATH.]) + fi + STLIB_LD='${AR} cr' + LD_LIBRARY_PATH_VAR="LD_LIBRARY_PATH" + PLAT_OBJS="" + case $system in + AIX-5.*) + if test "${TCL_THREADS}" = "1" -a "$GCC" != "yes" ; then + # AIX requires the _r compiler when gcc isn't being used + if test "${CC}" != "cc_r" ; then + CC=${CC}_r + fi + AC_MSG_RESULT(Using $CC for compiling with threads) + fi + LIBS="$LIBS -lc" + # AIX-5 uses ELF style dynamic libraries + SHLIB_CFLAGS="" + SHLIB_LD_LIBS='${LIBS}' + SHLIB_SUFFIX=".so" + if test "`uname -m`" = "ia64" ; then + # AIX-5 uses ELF style dynamic libraries on IA-64, but not PPC + SHLIB_LD="/usr/ccs/bin/ld -G -z text" + # AIX-5 has dl* in libc.so + DL_LIBS="" + if test "$GCC" = "yes" ; then + CC_SEARCH_FLAGS='-Wl,-R,${LIB_RUNTIME_DIR}' + else + CC_SEARCH_FLAGS='-R${LIB_RUNTIME_DIR}' + fi + LD_SEARCH_FLAGS='-R ${LIB_RUNTIME_DIR}' + else + SHLIB_LD="${TCL_SRC_DIR}/unix/ldAix /bin/ld -bhalt:4 -bM:SRE -bE:lib.exp -H512 -T512 -bnoentry" + DL_LIBS="-ldl" + CC_SEARCH_FLAGS='-L${LIB_RUNTIME_DIR}' + LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS} + TCL_NEEDS_EXP_FILE=1 + TCL_EXPORT_FILE_SUFFIX='${VERSION}\$\{DBGX\}.exp' + fi + + # Note: need the LIBS below, otherwise Tk won't find Tcl's + # symbols when dynamically loaded into tclsh. + + DL_OBJS="tclLoadDl.o" + LDFLAGS="" + + LD_LIBRARY_PATH_VAR="LIBPATH" + + # Check to enable 64-bit flags for compiler/linker + if test "$do64bit" = "yes" ; then + if test "$GCC" = "yes" ; then + AC_MSG_WARN("64bit mode not supported with GCC on $system") + else + do64bit_ok=yes + EXTRA_CFLAGS="-q64" + LDFLAGS="-q64" + RANLIB="${RANLIB} -X64" + AR="${AR} -X64" + SHLIB_LD_FLAGS="-b64" + fi + fi + ;; + AIX-*) + if test "${TCL_THREADS}" = "1" -a "$GCC" != "yes" ; then + # AIX requires the _r compiler when gcc isn't being used + if test "${CC}" != "cc_r" ; then + CC=${CC}_r + fi + AC_MSG_RESULT(Using $CC for compiling with threads) + fi + LIBS="$LIBS -lc" + SHLIB_CFLAGS="" + SHLIB_LD="${TCL_SRC_DIR}/unix/ldAix /bin/ld -bhalt:4 -bM:SRE -bE:lib.exp -H512 -T512 -bnoentry" + SHLIB_LD_LIBS='${LIBS}' + SHLIB_SUFFIX=".so" + DL_OBJS="tclLoadDl.o" + DL_LIBS="-ldl" + LDFLAGS="" + CC_SEARCH_FLAGS='-L${LIB_RUNTIME_DIR}' + LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS} + LD_LIBRARY_PATH_VAR="LIBPATH" + TCL_NEEDS_EXP_FILE=1 + TCL_EXPORT_FILE_SUFFIX='${VERSION}\$\{DBGX\}.exp' + + # AIX v<=4.1 has some different flags than 4.2+ + if test "$system" = "AIX-4.1" -o "`uname -v`" -lt "4" ; then + # upgrade to 2.5x egm 3/25/03 + AC_LIBOBJ(tclLoadAix.o) + HAVE_COMPAT=true + DL_LIBS="-lld" + fi + + # On AIX <=v4 systems, libbsd.a has to be linked in to support + # non-blocking file IO. This library has to be linked in after + # the MATH_LIBS or it breaks the pow() function. The way to + # insure proper sequencing, is to add it to the tail of MATH_LIBS. + # This library also supplies gettimeofday. + # + # AIX does not have a timezone field in struct tm. When the AIX + # bsd library is used, the timezone global and the gettimeofday + # methods are to be avoided for timezone deduction instead, we + # deduce the timezone by comparing the localtime result on a + # known GMT value. + + AC_CHECK_LIB(bsd, gettimeofday, libbsd=yes, libbsd=no) + if test $libbsd = yes; then + MATH_LIBS="$MATH_LIBS -lbsd" + AC_DEFINE(USE_DELTA_FOR_TZ) + fi + + # Check to enable 64-bit flags for compiler/linker + if test "$do64bit" = "yes" ; then + if test "$GCC" = "yes" ; then + AC_MSG_WARN("64bit mode not supported with GCC on $system") + else + do64bit_ok=yes + EXTRA_CFLAGS="-q64" + LDFLAGS="-q64" + RANLIB="${RANLIB} -X64" + AR="${AR} -X64" + SHLIB_LD_FLAGS="-b64" + fi + fi + ;; + BSD/OS-2.1*|BSD/OS-3*) + SHLIB_CFLAGS="" + SHLIB_LD="shlicc -r" + SHLIB_LD_LIBS='${LIBS}' + SHLIB_SUFFIX=".so" + DL_OBJS="tclLoadDl.o" + DL_LIBS="-ldl" + LDFLAGS="" + CC_SEARCH_FLAGS="" + LD_SEARCH_FLAGS="" + ;; + BSD/OS-4.*) + SHLIB_CFLAGS="-export-dynamic -fPIC" + SHLIB_LD="cc -shared" + SHLIB_LD_LIBS='${LIBS}' + SHLIB_SUFFIX=".so" + DL_OBJS="tclLoadDl.o" + DL_LIBS="-ldl" + LDFLAGS="-export-dynamic" + CC_SEARCH_FLAGS="" + LD_SEARCH_FLAGS="" + ;; + dgux*) + SHLIB_CFLAGS="-K PIC" + SHLIB_LD="cc -G" + SHLIB_LD_LIBS="" + SHLIB_SUFFIX=".so" + DL_OBJS="tclLoadDl.o" + DL_LIBS="-ldl" + LDFLAGS="" + CC_SEARCH_FLAGS="" + LD_SEARCH_FLAGS="" + ;; + HP-UX-*.11.*) + # Use updated header definitions where possible + AC_DEFINE(_XOPEN_SOURCE) # Use the XOPEN network library + AC_DEFINE(_XOPEN_SOURCE_EXTENDED) # Use the XOPEN network library + LIBS="$LIBS -lxnet" # Use the XOPEN network library + + SHLIB_SUFFIX=".sl" + AC_CHECK_LIB(dld, shl_load, tcl_ok=yes, tcl_ok=no) + if test "$tcl_ok" = yes; then + SHLIB_CFLAGS="+z" + SHLIB_LD="ld -b" + SHLIB_LD_LIBS='${LIBS}' + DL_OBJS="tclLoadShl.o" + DL_LIBS="-ldld" + LDFLAGS="-Wl,-E" + CC_SEARCH_FLAGS='-Wl,+s,+b,${LIB_RUNTIME_DIR}:.' + LD_SEARCH_FLAGS='+s +b ${LIB_RUNTIME_DIR}:.' + LD_LIBRARY_PATH_VAR="SHLIB_PATH" + fi + + # Users may want PA-RISC 1.1/2.0 portable code - needs HP cc + #EXTRA_CFLAGS="+DAportable" + + # Check to enable 64-bit flags for compiler/linker + if test "$do64bit" = "yes" ; then + if test "$GCC" = "yes" ; then + hpux_arch=`gcc -dumpmachine` + case $hpux_arch in + hppa64*) + # 64-bit gcc in use. Fix flags for GNU ld. + do64bit_ok=yes + SHLIB_LD="gcc -shared" + SHLIB_LD_LIBS="" + LD_SEARCH_FLAGS='' + CC_SEARCH_FLAGS='' + ;; + *) + AC_MSG_WARN("64bit mode not supported with GCC on $system") + ;; + esac + else + do64bit_ok=yes + if test "`uname -m`" = "ia64" ; then + EXTRA_CFLAGS="+DD64" + LDFLAGS="+DD64 $LDFLAGS" + else + EXTRA_CFLAGS="+DA2.0W" + LDFLAGS="+DA2.0W $LDFLAGS" + fi + fi + fi + ;; + HP-UX-*.08.*|HP-UX-*.09.*|HP-UX-*.10.*) + SHLIB_SUFFIX=".sl" + AC_CHECK_LIB(dld, shl_load, tcl_ok=yes, tcl_ok=no) + if test "$tcl_ok" = yes; then + SHLIB_CFLAGS="+z" + SHLIB_LD="ld -b" + SHLIB_LD_LIBS="" + DL_OBJS="tclLoadShl.o" + DL_LIBS="-ldld" + LDFLAGS="-Wl,-E" + CC_SEARCH_FLAGS='-Wl,+s,+b,${LIB_RUNTIME_DIR}:.' + LD_SEARCH_FLAGS='+s +b ${LIB_RUNTIME_DIR}:.' + LD_LIBRARY_PATH_VAR="SHLIB_PATH" + fi + ;; + IRIX-4.*) + SHLIB_CFLAGS="-G 0" + SHLIB_SUFFIX=".a" + SHLIB_LD="echo tclLdAout $CC \{$SHLIB_CFLAGS\} | `pwd`/tclsh -r -G 0" + SHLIB_LD_LIBS='${LIBS}' + DL_OBJS="tclLoadAout.o" + DL_LIBS="" + LDFLAGS="-Wl,-D,08000000" + CC_SEARCH_FLAGS='-L${LIB_RUNTIME_DIR}' + LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS} + SHARED_LIB_SUFFIX='${VERSION}\$\{DBGX\}.a' + ;; + IRIX-5.*) + SHLIB_CFLAGS="" + SHLIB_LD="ld -shared -rdata_shared" + SHLIB_LD_LIBS='${LIBS}' + SHLIB_SUFFIX=".so" + DL_OBJS="tclLoadDl.o" + DL_LIBS="" + CC_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}' + LD_SEARCH_FLAGS='-rpath ${LIB_RUNTIME_DIR}' + EXTRA_CFLAGS="" + LDFLAGS="" + ;; + IRIX-6.*|IRIX64-6.5*) + SHLIB_CFLAGS="" + SHLIB_LD="ld -n32 -shared -rdata_shared" + SHLIB_LD_LIBS='${LIBS}' + SHLIB_SUFFIX=".so" + DL_OBJS="tclLoadDl.o" + DL_LIBS="" + CC_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}' + LD_SEARCH_FLAGS='-rpath ${LIB_RUNTIME_DIR}' + if test "$GCC" = "yes" ; then + EXTRA_CFLAGS="-mabi=n32" + LDFLAGS="-mabi=n32" + else + case $system in + IRIX-6.3) + # Use to build 6.2 compatible binaries on 6.3. + EXTRA_CFLAGS="-n32 -D_OLD_TERMIOS" + ;; + *) + EXTRA_CFLAGS="-n32" + ;; + esac + LDFLAGS="-n32" + fi + ;; + IRIX64-6.*) + SHLIB_CFLAGS="" + SHLIB_LD="ld -n32 -shared -rdata_shared" + SHLIB_LD_LIBS='${LIBS}' + SHLIB_SUFFIX=".so" + DL_OBJS="tclLoadDl.o" + DL_LIBS="" + LDFLAGS="" + CC_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}' + LD_SEARCH_FLAGS='-rpath ${LIB_RUNTIME_DIR}' + + # Check to enable 64-bit flags for compiler/linker + + if test "$do64bit" = "yes" ; then + if test "$GCC" = "yes" ; then + AC_MSG_WARN([64bit mode not supported by gcc]) + else + do64bit_ok=yes + SHLIB_LD="ld -64 -shared -rdata_shared" + EXTRA_CFLAGS="-64" + LDFLAGS="-64" + fi + fi + ;; + Linux*) + SHLIB_CFLAGS="-fPIC" + SHLIB_LD_LIBS='${LIBS}' + SHLIB_SUFFIX=".so" + + # egcs-2.91.66 on Redhat Linux 6.0 generates lots of warnings + # when you inline the string and math operations. Turn this off to + # get rid of the warnings. + + CFLAGS_OPTIMIZE="${CFLAGS_OPTIMIZE} -D__NO_STRING_INLINES -D__NO_MATH_INLINES" + + if test "$have_dl" = yes; then + SHLIB_LD="${CC} -shared" + DL_OBJS="tclLoadDl.o" + DL_LIBS="-ldl" + LDFLAGS="-rdynamic" + CC_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}' + LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS} + else + AC_CHECK_HEADER(dld.h, [ + SHLIB_LD="ld -shared" + DL_OBJS="tclLoadDld.o" + DL_LIBS="-ldld" + LDFLAGS="" + CC_SEARCH_FLAGS="" + LD_SEARCH_FLAGS=""]) + fi + if test "`uname -m`" = "alpha" ; then + EXTRA_CFLAGS="-mieee" + fi + + # The combo of gcc + glibc has a bug related + # to inlining of functions like strtod(). The + # -fno-builtin flag should address this problem + # but it does not work. The -fno-inline flag + # is kind of overkill but it works. + # Disable inlining only when one of the + # files in compat/*.c is being linked in. + if test x"${HAVE_COMPAT}" = "xtrue" ; then + EXTRA_CFLAGS="${EXTRA_CFLAGS} -fno-inline" + fi + + # XIM peeking works under XFree86. + AC_DEFINE(PEEK_XCLOSEIM) + + ;; + GNU*) + SHLIB_CFLAGS="-fPIC" + SHLIB_LD_LIBS='${LIBS}' + SHLIB_SUFFIX=".so" + + if test "$have_dl" = yes; then + SHLIB_LD="${CC} -shared" + DL_OBJS="" + DL_LIBS="-ldl" + LDFLAGS="-rdynamic" + CC_SEARCH_FLAGS="" + LD_SEARCH_FLAGS="" + else + AC_CHECK_HEADER(dld.h, [ + SHLIB_LD="ld -shared" + DL_OBJS="" + DL_LIBS="-ldld" + LDFLAGS="" + CC_SEARCH_FLAGS="" + LD_SEARCH_FLAGS=""]) + fi + if test "`uname -m`" = "alpha" ; then + EXTRA_CFLAGS="-mieee" + fi + ;; + MP-RAS-02*) + SHLIB_CFLAGS="-K PIC" + SHLIB_LD="cc -G" + SHLIB_LD_LIBS="" + SHLIB_SUFFIX=".so" + DL_OBJS="tclLoadDl.o" + DL_LIBS="-ldl" + LDFLAGS="" + CC_SEARCH_FLAGS="" + LD_SEARCH_FLAGS="" + ;; + MP-RAS-*) + SHLIB_CFLAGS="-K PIC" + SHLIB_LD="cc -G" + SHLIB_LD_LIBS="" + SHLIB_SUFFIX=".so" + DL_OBJS="tclLoadDl.o" + DL_LIBS="-ldl" + LDFLAGS="-Wl,-Bexport" + CC_SEARCH_FLAGS="" + LD_SEARCH_FLAGS="" + ;; + NetBSD-*|FreeBSD-[[1-2]].*|OpenBSD-*) + # Not available on all versions: check for include file. + AC_CHECK_HEADER(dlfcn.h, [ + # NetBSD/SPARC needs -fPIC, -fpic will not do. + SHLIB_CFLAGS="-fPIC" + SHLIB_LD="ld -Bshareable -x" + SHLIB_LD_LIBS="" + SHLIB_SUFFIX=".so" + DL_OBJS="tclLoadDl.o" + DL_LIBS="" + LDFLAGS="" + CC_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}' + LD_SEARCH_FLAGS='-rpath ${LIB_RUNTIME_DIR}' + AC_MSG_CHECKING(for ELF) + AC_EGREP_CPP(yes, [ +#ifdef __ELF__ + yes +#endif + ], + AC_MSG_RESULT(yes) + SHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}\$\{DBGX\}.so', + AC_MSG_RESULT(no) + SHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}\$\{DBGX\}.so.1.0' + ) + ], [ + SHLIB_CFLAGS="" + SHLIB_LD="echo tclLdAout $CC \{$SHLIB_CFLAGS\} | `pwd`/tclsh -r" + SHLIB_LD_LIBS='${LIBS}' + SHLIB_SUFFIX=".a" + DL_OBJS="tclLoadAout.o" + DL_LIBS="" + LDFLAGS="" + CC_SEARCH_FLAGS='-L${LIB_RUNTIME_DIR}' + LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS} + SHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}\$\{DBGX\}.a' + ]) + + # FreeBSD doesn't handle version numbers with dots. + + UNSHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}\$\{DBGX\}.a' + TCL_LIB_VERSIONS_OK=nodots + ;; + FreeBSD-*) + # FreeBSD 3.* and greater have ELF. + SHLIB_CFLAGS="-fPIC" + SHLIB_LD="ld -Bshareable -x" + SHLIB_LD_LIBS='${LIBS}' + SHLIB_SUFFIX=".so" + DL_OBJS="tclLoadDl.o" + DL_LIBS="" + LDFLAGS="-export-dynamic" + CC_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}' + LD_SEARCH_FLAGS='-rpath ${LIB_RUNTIME_DIR}' + if test "${TCL_THREADS}" = "1" ; then + # The -pthread needs to go in the CFLAGS, not LIBS + LIBS=`echo $LIBS | sed s/-pthread//` + EXTRA_CFLAGS="-pthread" + LDFLAGS="$LDFLAGS -pthread" + fi + case $system in + FreeBSD-3.*) + # FreeBSD-3 doesn't handle version numbers with dots. + UNSHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}\$\{DBGX\}.a' + SHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}\$\{DBGX\}.so' + TCL_LIB_VERSIONS_OK=nodots + ;; + esac + ;; + Rhapsody-*|Darwin-*) + SHLIB_CFLAGS="-fno-common" + SHLIB_LD="cc -dynamiclib \${LDFLAGS}" + TCL_SHLIB_LD_EXTRAS="-compatibility_version ${TCL_VERSION} -current_version \${VERSION} -install_name \${DYLIB_INSTALL_DIR}/\${TCL_LIB_FILE} -prebind -seg1addr 0xa000000" + TK_SHLIB_LD_EXTRAS="-compatibility_version ${TK_VERSION} -current_version \${VERSION} -install_name \${DYLIB_INSTALL_DIR}/\${TK_LIB_FILE} -prebind -seg1addr 0xb000000" + SHLIB_LD_LIBS='${LIBS}' + SHLIB_SUFFIX=".dylib" + DL_OBJS="tclLoadDyld.o" + PLAT_OBJS="tclMacOSXBundle.o" + DL_LIBS="" + LDFLAGS="-prebind" + CC_SEARCH_FLAGS="" + LD_SEARCH_FLAGS="" + CFLAGS_OPTIMIZE="-Os" + LD_LIBRARY_PATH_VAR="DYLD_LIBRARY_PATH" + # for compatibility with autoconf vers 2.13 : + HACK="" + EXTRA_CFLAGS="-DMA${HACK}C_OSX_TCL -DHAVE_CFBUNDLE -DUSE_VFORK -DTCL_DEFAULT_ENCODING=\\\"utf-8\\\"" + LIBS="$LIBS -framework CoreFoundation" + ;; + NEXTSTEP-*) + SHLIB_CFLAGS="" + SHLIB_LD="cc -nostdlib -r" + SHLIB_LD_LIBS="" + SHLIB_SUFFIX=".so" + DL_OBJS="tclLoadNext.o" + DL_LIBS="" + LDFLAGS="" + CC_SEARCH_FLAGS="" + LD_SEARCH_FLAGS="" + ;; + OS/390-*) + CFLAGS_OPTIMIZE="" # Optimizer is buggy + AC_DEFINE(_OE_SOCKETS) # needed in sys/socket.h + ;; + OSF1-1.0|OSF1-1.1|OSF1-1.2) + # OSF/1 1.[012] from OSF, and derivatives, including Paragon OSF/1 + SHLIB_CFLAGS="" + # Hack: make package name same as library name + SHLIB_LD='ld -R -export $@:' + SHLIB_LD_LIBS="" + SHLIB_SUFFIX=".so" + DL_OBJS="tclLoadOSF.o" + DL_LIBS="" + LDFLAGS="" + CC_SEARCH_FLAGS="" + LD_SEARCH_FLAGS="" + ;; + OSF1-1.*) + # OSF/1 1.3 from OSF using ELF, and derivatives, including AD2 + SHLIB_CFLAGS="-fPIC" + if test "$SHARED_BUILD" = "1" ; then + SHLIB_LD="ld -shared" + else + SHLIB_LD="ld -non_shared" + fi + SHLIB_LD_LIBS="" + SHLIB_SUFFIX=".so" + DL_OBJS="tclLoadDl.o" + DL_LIBS="" + LDFLAGS="" + CC_SEARCH_FLAGS="" + LD_SEARCH_FLAGS="" + ;; + OSF1-V*) + # Digital OSF/1 + SHLIB_CFLAGS="" + if test "$SHARED_BUILD" = "1" ; then + SHLIB_LD='ld -shared -expect_unresolved "*"' + else + SHLIB_LD='ld -non_shared -expect_unresolved "*"' + fi + SHLIB_LD_LIBS="" + SHLIB_SUFFIX=".so" + DL_OBJS="tclLoadDl.o" + DL_LIBS="" + LDFLAGS="" + CC_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}' + LD_SEARCH_FLAGS='-rpath ${LIB_RUNTIME_DIR}' + if test "$GCC" != "yes" ; then + EXTRA_CFLAGS="-DHAVE_TZSET -std1" + fi + # see pthread_intro(3) for pthread support on osf1, k.furukawa + if test "${TCL_THREADS}" = "1" ; then + EXTRA_CFLAGS="${EXTRA_CFLAGS} -DHAVE_PTHREAD_ATTR_SETSTACKSIZE" + EXTRA_CFLAGS="${EXTRA_CFLAGS} -DTCL_THREAD_STACK_MIN=PTHREAD_STACK_MIN*64" + LIBS=`echo $LIBS | sed s/-lpthreads//` + if test "$GCC" = "yes" ; then + LIBS="$LIBS -lpthread -lmach -lexc" + else + EXTRA_CFLAGS="${EXTRA_CFLAGS} -pthread" + LDFLAGS="-pthread" + fi + fi + + ;; + QNX-6*) + # QNX RTP + # This may work for all QNX, but it was only reported for v6. + SHLIB_CFLAGS="-fPIC" + SHLIB_LD="ld -Bshareable -x" + SHLIB_LD_LIBS="" + SHLIB_SUFFIX=".so" + DL_OBJS="tclLoadDl.o" + # dlopen is in -lc on QNX + DL_LIBS="" + LDFLAGS="" + CC_SEARCH_FLAGS="" + LD_SEARCH_FLAGS="" + ;; + RISCos-*) + SHLIB_CFLAGS="-G 0" + SHLIB_LD="echo tclLdAout $CC \{$SHLIB_CFLAGS\} | `pwd`/tclsh -r -G 0" + SHLIB_LD_LIBS='${LIBS}' + SHLIB_SUFFIX=".a" + DL_OBJS="tclLoadAout.o" + DL_LIBS="" + LDFLAGS="-Wl,-D,08000000" + CC_SEARCH_FLAGS='-L${LIB_RUNTIME_DIR}' + LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS} + ;; + SCO_SV-3.2*) + # Note, dlopen is available only on SCO 3.2.5 and greater. However, + # this test works, since "uname -s" was non-standard in 3.2.4 and + # below. + if test "$GCC" = "yes" ; then + SHLIB_CFLAGS="-fPIC -melf" + LDFLAGS="-melf -Wl,-Bexport" + else + SHLIB_CFLAGS="-Kpic -belf" + LDFLAGS="-belf -Wl,-Bexport" + fi + SHLIB_LD="ld -G" + SHLIB_LD_LIBS="" + SHLIB_SUFFIX=".so" + DL_OBJS="tclLoadDl.o" + DL_LIBS="" + CC_SEARCH_FLAGS="" + LD_SEARCH_FLAGS="" + ;; + SINIX*5.4*) + SHLIB_CFLAGS="-K PIC" + SHLIB_LD="cc -G" + SHLIB_LD_LIBS="" + SHLIB_SUFFIX=".so" + DL_OBJS="tclLoadDl.o" + DL_LIBS="-ldl" + LDFLAGS="" + CC_SEARCH_FLAGS="" + LD_SEARCH_FLAGS="" + ;; + SunOS-4*) + SHLIB_CFLAGS="-PIC" + SHLIB_LD="ld" + SHLIB_LD_LIBS="" + SHLIB_SUFFIX=".so" + DL_OBJS="tclLoadDl.o" + DL_LIBS="-ldl" + LDFLAGS="" + CC_SEARCH_FLAGS='-L${LIB_RUNTIME_DIR}' + LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS} + + # SunOS can't handle version numbers with dots in them in library + # specs, like -ltcl7.5, so use -ltcl75 instead. Also, it + # requires an extra version number at the end of .so file names. + # So, the library has to have a name like libtcl75.so.1.0 + + SHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}\$\{DBGX\}.so.1.0' + UNSHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}\$\{DBGX\}.a' + TCL_LIB_VERSIONS_OK=nodots + ;; + SunOS-5.[[0-6]]*) + + # Note: If _REENTRANT isn't defined, then Solaris + # won't define thread-safe library routines. + + AC_DEFINE(_REENTRANT) + AC_DEFINE(_POSIX_PTHREAD_SEMANTICS) + + SHLIB_CFLAGS="-KPIC" + + # Note: need the LIBS below, otherwise Tk won't find Tcl's + # symbols when dynamically loaded into tclsh. + + SHLIB_LD_LIBS='${LIBS}' + SHLIB_SUFFIX=".so" + DL_OBJS="tclLoadDl.o" + DL_LIBS="-ldl" + LDFLAGS="" + if test "$GCC" = "yes" ; then + SHLIB_LD="$CC -shared" + CC_SEARCH_FLAGS='-Wl,-R,${LIB_RUNTIME_DIR}' + LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS} + else + SHLIB_LD="/usr/ccs/bin/ld -G -z text" + CC_SEARCH_FLAGS='-R ${LIB_RUNTIME_DIR}' + LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS} + fi + ;; + SunOS-5*) + + # Note: If _REENTRANT isn't defined, then Solaris + # won't define thread-safe library routines. + + AC_DEFINE(_REENTRANT) + AC_DEFINE(_POSIX_PTHREAD_SEMANTICS) + + SHLIB_CFLAGS="-KPIC" + LDFLAGS="" + + # Check to enable 64-bit flags for compiler/linker + if test "$do64bit" = "yes" ; then + arch=`isainfo` + if test "$arch" = "sparcv9 sparc" ; then + if test "$GCC" = "yes" ; then + AC_MSG_WARN("64bit mode not supported with GCC on $system") + else + do64bit_ok=yes + if test "$do64bitVIS" = "yes" ; then + EXTRA_CFLAGS="-xarch=v9a" + LDFLAGS="-xarch=v9a" + else + EXTRA_CFLAGS="-xarch=v9" + LDFLAGS="-xarch=v9" + fi + fi + else + AC_MSG_WARN("64bit mode only supported sparcv9 system") + fi + fi + + # Note: need the LIBS below, otherwise Tk won't find Tcl's + # symbols when dynamically loaded into tclsh. + + SHLIB_LD_LIBS='${LIBS}' + SHLIB_SUFFIX=".so" + DL_OBJS="tclLoadDl.o" + DL_LIBS="-ldl" + if test "$GCC" = "yes" ; then + SHLIB_LD="$CC -shared" + CC_SEARCH_FLAGS='-Wl,-R,${LIB_RUNTIME_DIR}' + LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS} + else + SHLIB_LD="/usr/ccs/bin/ld -G -z text" + CC_SEARCH_FLAGS='-Wl,-R,${LIB_RUNTIME_DIR}' + LD_SEARCH_FLAGS='-R ${LIB_RUNTIME_DIR}' + fi + ;; + ULTRIX-4.*) + SHLIB_CFLAGS="-G 0" + SHLIB_SUFFIX=".a" + SHLIB_LD="echo tclLdAout $CC \{$SHLIB_CFLAGS\} | `pwd`/tclsh -r -G 0" + SHLIB_LD_LIBS='${LIBS}' + DL_OBJS="tclLoadAout.o" + DL_LIBS="" + LDFLAGS="-Wl,-D,08000000" + CC_SEARCH_FLAGS='-L${LIB_RUNTIME_DIR}' + LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS} + if test "$GCC" != "yes" ; then + EXTRA_CFLAGS="-DHAVE_TZSET -std1" + fi + ;; + UNIX_SV* | UnixWare-5*) + SHLIB_CFLAGS="-KPIC" + SHLIB_LD="cc -G" + SHLIB_LD_LIBS="" + SHLIB_SUFFIX=".so" + DL_OBJS="tclLoadDl.o" + DL_LIBS="-ldl" + # Some UNIX_SV* systems (unixware 1.1.2 for example) have linkers + # that don't grok the -Bexport option. Test that it does. + hold_ldflags=$LDFLAGS + AC_MSG_CHECKING(for ld accepts -Bexport flag) + LDFLAGS="${LDFLAGS} -Wl,-Bexport" + AC_TRY_LINK(, [int i;], found=yes, found=no) + LDFLAGS=$hold_ldflags + AC_MSG_RESULT($found) + if test $found = yes; then + LDFLAGS="-Wl,-Bexport" + else + LDFLAGS="" + fi + CC_SEARCH_FLAGS="" + LD_SEARCH_FLAGS="" + ;; + esac + + if test "$do64bit" = "yes" -a "$do64bit_ok" = "no" ; then + AC_MSG_WARN("64bit support being disabled -- don\'t know magic for this platform") + fi + + # Step 4: If pseudo-static linking is in use (see K. B. Kenny, "Dynamic + # Loading for Tcl -- What Became of It?". Proc. 2nd Tcl/Tk Workshop, + # New Orleans, LA, Computerized Processes Unlimited, 1994), then we need + # to determine which of several header files defines the a.out file + # format (a.out.h, sys/exec.h, or sys/exec_aout.h). At present, we + # support only a file format that is more or less version-7-compatible. + # In particular, + # - a.out files must begin with `struct exec'. + # - the N_TXTOFF on the `struct exec' must compute the seek address + # of the text segment + # - The `struct exec' must contain a_magic, a_text, a_data, a_bss + # and a_entry fields. + # The following compilation should succeed if and only if either sys/exec.h + # or a.out.h is usable for the purpose. + # + # Note that the modified COFF format used on MIPS Ultrix 4.x is usable; the + # `struct exec' includes a second header that contains information that + # duplicates the v7 fields that are needed. + + if test "x$DL_OBJS" = "xtclLoadAout.o" ; then + AC_MSG_CHECKING(sys/exec.h) + AC_TRY_COMPILE([#include <sys/exec.h>],[ + struct exec foo; + unsigned long seek; + int flag; +#if defined(__mips) || defined(mips) + seek = N_TXTOFF (foo.ex_f, foo.ex_o); +#else + seek = N_TXTOFF (foo); +#endif + flag = (foo.a_magic == OMAGIC); + return foo.a_text + foo.a_data + foo.a_bss + foo.a_entry; + ], tcl_ok=usable, tcl_ok=unusable) + AC_MSG_RESULT($tcl_ok) + if test $tcl_ok = usable; then + AC_DEFINE(USE_SYS_EXEC_H) + else + AC_MSG_CHECKING(a.out.h) + AC_TRY_COMPILE([#include <a.out.h>],[ + struct exec foo; + unsigned long seek; + int flag; +#if defined(__mips) || defined(mips) + seek = N_TXTOFF (foo.ex_f, foo.ex_o); +#else + seek = N_TXTOFF (foo); +#endif + flag = (foo.a_magic == OMAGIC); + return foo.a_text + foo.a_data + foo.a_bss + foo.a_entry; + ], tcl_ok=usable, tcl_ok=unusable) + AC_MSG_RESULT($tcl_ok) + if test $tcl_ok = usable; then + AC_DEFINE(USE_A_OUT_H) + else + AC_MSG_CHECKING(sys/exec_aout.h) + AC_TRY_COMPILE([#include <sys/exec_aout.h>],[ + struct exec foo; + unsigned long seek; + int flag; +#if defined(__mips) || defined(mips) + seek = N_TXTOFF (foo.ex_f, foo.ex_o); +#else + seek = N_TXTOFF (foo); +#endif + flag = (foo.a_midmag == OMAGIC); + return foo.a_text + foo.a_data + foo.a_bss + foo.a_entry; + ], tcl_ok=usable, tcl_ok=unusable) + AC_MSG_RESULT($tcl_ok) + if test $tcl_ok = usable; then + AC_DEFINE(USE_SYS_EXEC_AOUT_H) + else + DL_OBJS="" + fi + fi + fi + fi + + # Step 5: disable dynamic loading if requested via a command-line switch. + + AC_ARG_ENABLE(load, [ --disable-load disallow dynamic loading and "load" command], + [tcl_ok=$enableval], [tcl_ok=yes]) + if test "$tcl_ok" = "no"; then + DL_OBJS="" + fi + + if test "x$DL_OBJS" != "x" ; then + BUILD_DLTEST="\$(DLTEST_TARGETS)" + else + echo "Can't figure out how to do dynamic loading or shared libraries" + echo "on this system." + SHLIB_CFLAGS="" + SHLIB_LD="" + SHLIB_SUFFIX="" + DL_OBJS="tclLoadNone.o" + DL_LIBS="" + LDFLAGS="" + CC_SEARCH_FLAGS="" + LD_SEARCH_FLAGS="" + BUILD_DLTEST="" + fi + + # If we're running gcc, then change the C flags for compiling shared + # libraries to the right flags for gcc, instead of those for the + # standard manufacturer compiler. + + if test "$DL_OBJS" != "tclLoadNone.o" ; then + if test "$GCC" = "yes" ; then + case $system in + AIX-*) + ;; + BSD/OS*) + ;; + IRIX*) + ;; + NetBSD-*|FreeBSD-*|OpenBSD-*) + ;; + Rhapsody-*|Darwin-*) + ;; + RISCos-*) + ;; + SCO_SV-3.2*) + ;; + ULTRIX-4.*) + ;; + *) + SHLIB_CFLAGS="-fPIC" + ;; + esac + fi + fi + + if test "$SHARED_LIB_SUFFIX" = "" ; then + SHARED_LIB_SUFFIX='${VERSION}\$\{DBGX\}${SHLIB_SUFFIX}' + fi + if test "$UNSHARED_LIB_SUFFIX" = "" ; then + UNSHARED_LIB_SUFFIX='${VERSION}\$\{DBGX\}.a' + fi + + if test "${SHARED_BUILD}" = "1" && test "${SHLIB_SUFFIX}" != "" ; then + LIB_SUFFIX=${SHARED_LIB_SUFFIX} + MAKE_LIB='${SHLIB_LD} -o [$]@ ${SHLIB_LD_FLAGS} ${OBJS} ${SHLIB_LD_LIBS} ${TCL_SHLIB_LD_EXTRAS} ${TK_SHLIB_LD_EXTRAS} ${LD_SEARCH_FLAGS}' + INSTALL_LIB='$(INSTALL_LIBRARY) $(LIB_FILE) $(LIB_INSTALL_DIR)/$(LIB_FILE)' + else + LIB_SUFFIX=${UNSHARED_LIB_SUFFIX} + + if test "$RANLIB" = "" ; then + MAKE_LIB='$(STLIB_LD) [$]@ ${OBJS}' + INSTALL_LIB='$(INSTALL_LIBRARY) $(LIB_FILE) $(LIB_INSTALL_DIR)/$(LIB_FILE)' + else + MAKE_LIB='${STLIB_LD} [$]@ ${OBJS} ; ${RANLIB} [$]@' + INSTALL_LIB='$(INSTALL_LIBRARY) $(LIB_FILE) $(LIB_INSTALL_DIR)/$(LIB_FILE) ; (cd $(LIB_INSTALL_DIR) ; $(RANLIB) $(LIB_FILE))' + fi + +dnl Not at all clear what this was doing in Tcl's configure.in +dnl or why it was needed was needed. In any event, this sort of +dnl things needs to be done in the big loop above. +dnl REMOVE THIS BLOCK LATER! (mdejong) +dnl case $system in +dnl BSD/OS*) +dnl ;; +dnl AIX-[[1-4]].*) +dnl ;; +dnl *) +dnl SHLIB_LD_LIBS="" +dnl ;; +dnl esac + fi + + + # Stub lib does not depend on shared/static configuration + if test "$RANLIB" = "" ; then + MAKE_STUB_LIB='${STLIB_LD} [$]@ ${STUB_LIB_OBJS}' + INSTALL_STUB_LIB='$(INSTALL_LIBRARY) $(STUB_LIB_FILE) $(LIB_INSTALL_DIR)/$(STUB_LIB_FILE)' + else + MAKE_STUB_LIB='${STLIB_LD} [$]@ ${STUB_LIB_OBJS} ; ${RANLIB} [$]@' + INSTALL_STUB_LIB='$(INSTALL_LIBRARY) $(STUB_LIB_FILE) $(LIB_INSTALL_DIR)/$(STUB_LIB_FILE) ; (cd $(LIB_INSTALL_DIR) ; $(RANLIB) $(STUB_LIB_FILE))' + fi + + + AC_SUBST(DL_LIBS) + + AC_SUBST(DL_OBJS) + AC_SUBST(PLAT_OBJS) + AC_SUBST(CFLAGS) + AC_SUBST(CFLAGS_DEBUG) + AC_SUBST(CFLAGS_OPTIMIZE) + AC_SUBST(CFLAGS_WARNING) + AC_SUBST(EXTRA_CFLAGS) + + AC_SUBST(LDFLAGS) + AC_SUBST(LDFLAGS_DEBUG) + AC_SUBST(LDFLAGS_OPTIMIZE) + AC_SUBST(CC_SEARCH_FLAGS) + AC_SUBST(LD_SEARCH_FLAGS) + + AC_SUBST(STLIB_LD) + AC_SUBST(SHLIB_LD) + AC_SUBST(TCL_SHLIB_LD_EXTRAS) + AC_SUBST(TK_SHLIB_LD_EXTRAS) + AC_SUBST(SHLIB_LD_FLAGS) + AC_SUBST(SHLIB_LD_LIBS) + AC_SUBST(SHLIB_CFLAGS) + AC_SUBST(SHLIB_SUFFIX) + + AC_SUBST(MAKE_LIB) + AC_SUBST(MAKE_STUB_LIB) + AC_SUBST(INSTALL_LIB) + AC_SUBST(INSTALL_STUB_LIB) + AC_SUBST(RANLIB) +]) + +#-------------------------------------------------------------------- +# SC_SERIAL_PORT +# +# Determine which interface to use to talk to the serial port. +# Note that #include lines must begin in leftmost column for +# some compilers to recognize them as preprocessor directives, +# and some build environments have stdin not pointing at a +# pseudo-terminal (usually /dev/null instead.) +# +# Arguments: +# none +# +# Results: +# +# Defines only one of the following vars: +# HAVE_SYS_MODEM_H +# USE_TERMIOS +# USE_TERMIO +# USE_SGTTY +# +#-------------------------------------------------------------------- + +AC_DEFUN(SC_SERIAL_PORT, [ + AC_CHECK_HEADERS(sys/modem.h) + AC_MSG_CHECKING([termios vs. termio vs. sgtty]) + AC_CACHE_VAL(tcl_cv_api_serial, [ + AC_TRY_RUN([ +#include <termios.h> + +int main() { + struct termios t; + if (tcgetattr(0, &t) == 0) { + cfsetospeed(&t, 0); + t.c_cflag |= PARENB | PARODD | CSIZE | CSTOPB; + return 0; + } + return 1; +}], tcl_cv_api_serial=termios, tcl_cv_api_serial=no, tcl_cv_api_serial=no) + if test $tcl_cv_api_serial = no ; then + AC_TRY_RUN([ +#include <termio.h> + +int main() { + struct termio t; + if (ioctl(0, TCGETA, &t) == 0) { + t.c_cflag |= CBAUD | PARENB | PARODD | CSIZE | CSTOPB; + return 0; + } + return 1; +}], tcl_cv_api_serial=termio, tcl_cv_api_serial=no, tcl_cv_api_serial=no) + fi + if test $tcl_cv_api_serial = no ; then + AC_TRY_RUN([ +#include <sgtty.h> + +int main() { + struct sgttyb t; + if (ioctl(0, TIOCGETP, &t) == 0) { + t.sg_ospeed = 0; + t.sg_flags |= ODDP | EVENP | RAW; + return 0; + } + return 1; +}], tcl_cv_api_serial=sgtty, tcl_cv_api_serial=no, tcl_cv_api_serial=no) + fi + if test $tcl_cv_api_serial = no ; then + AC_TRY_RUN([ +#include <termios.h> +#include <errno.h> + +int main() { + struct termios t; + if (tcgetattr(0, &t) == 0 + || errno == ENOTTY || errno == ENXIO || errno == EINVAL) { + cfsetospeed(&t, 0); + t.c_cflag |= PARENB | PARODD | CSIZE | CSTOPB; + return 0; + } + return 1; +}], tcl_cv_api_serial=termios, tcl_cv_api_serial=no, tcl_cv_api_serial=no) + fi + if test $tcl_cv_api_serial = no; then + AC_TRY_RUN([ +#include <termio.h> +#include <errno.h> + +int main() { + struct termio t; + if (ioctl(0, TCGETA, &t) == 0 + || errno == ENOTTY || errno == ENXIO || errno == EINVAL) { + t.c_cflag |= CBAUD | PARENB | PARODD | CSIZE | CSTOPB; + return 0; + } + return 1; + }], tcl_cv_api_serial=termio, tcl_cv_api_serial=no, tcl_cv_api_serial=no) + fi + if test $tcl_cv_api_serial = no; then + AC_TRY_RUN([ +#include <sgtty.h> +#include <errno.h> + +int main() { + struct sgttyb t; + if (ioctl(0, TIOCGETP, &t) == 0 + || errno == ENOTTY || errno == ENXIO || errno == EINVAL) { + t.sg_ospeed = 0; + t.sg_flags |= ODDP | EVENP | RAW; + return 0; + } + return 1; +}], tcl_cv_api_serial=sgtty, tcl_cv_api_serial=none, tcl_cv_api_serial=none) + fi]) + case $tcl_cv_api_serial in + termios) AC_DEFINE(USE_TERMIOS);; + termio) AC_DEFINE(USE_TERMIO);; + sgtty) AC_DEFINE(USE_SGTTY);; + esac + AC_MSG_RESULT($tcl_cv_api_serial) +]) + +#-------------------------------------------------------------------- +# SC_MISSING_POSIX_HEADERS +# +# Supply substitutes for missing POSIX header files. Special +# notes: +# - stdlib.h doesn't define strtol, strtoul, or +# strtod insome versions of SunOS +# - some versions of string.h don't declare procedures such +# as strstr +# +# Arguments: +# none +# +# Results: +# +# Defines some of the following vars: +# NO_DIRENT_H +# NO_ERRNO_H +# NO_VALUES_H +# NO_LIMITS_H +# NO_STDLIB_H +# NO_STRING_H +# NO_SYS_WAIT_H +# NO_DLFCN_H +# HAVE_UNISTD_H +# HAVE_SYS_PARAM_H +# +# HAVE_STRING_H ? +# +#-------------------------------------------------------------------- + +AC_DEFUN(SC_MISSING_POSIX_HEADERS, [ + AC_MSG_CHECKING(dirent.h) + AC_TRY_LINK([#include <sys/types.h> +#include <dirent.h>], [ +#ifndef _POSIX_SOURCE +# ifdef __Lynx__ + /* + * Generate compilation error to make the test fail: Lynx headers + * are only valid if really in the POSIX environment. + */ + + missing_procedure(); +# endif +#endif +DIR *d; +struct dirent *entryPtr; +char *p; +d = opendir("foobar"); +entryPtr = readdir(d); +p = entryPtr->d_name; +closedir(d); +], tcl_ok=yes, tcl_ok=no) + + if test $tcl_ok = no; then + AC_DEFINE(NO_DIRENT_H) + fi + + AC_MSG_RESULT($tcl_ok) + AC_CHECK_HEADER(errno.h, , [AC_DEFINE(NO_ERRNO_H)]) + AC_CHECK_HEADER(float.h, , [AC_DEFINE(NO_FLOAT_H)]) + AC_CHECK_HEADER(values.h, , [AC_DEFINE(NO_VALUES_H)]) + AC_CHECK_HEADER(limits.h, , [AC_DEFINE(NO_LIMITS_H)]) + AC_CHECK_HEADER(stdlib.h, tcl_ok=1, tcl_ok=0) + AC_EGREP_HEADER(strtol, stdlib.h, , tcl_ok=0) + AC_EGREP_HEADER(strtoul, stdlib.h, , tcl_ok=0) + AC_EGREP_HEADER(strtod, stdlib.h, , tcl_ok=0) + if test $tcl_ok = 0; then + AC_DEFINE(NO_STDLIB_H) + fi + AC_CHECK_HEADER(string.h, tcl_ok=1, tcl_ok=0) + AC_EGREP_HEADER(strstr, string.h, , tcl_ok=0) + AC_EGREP_HEADER(strerror, string.h, , tcl_ok=0) + + # See also memmove check below for a place where NO_STRING_H can be + # set and why. + + if test $tcl_ok = 0; then + AC_DEFINE(NO_STRING_H) + fi + + AC_CHECK_HEADER(sys/wait.h, , [AC_DEFINE(NO_SYS_WAIT_H)]) + AC_CHECK_HEADER(dlfcn.h, , [AC_DEFINE(NO_DLFCN_H)]) + + # OS/390 lacks sys/param.h (and doesn't need it, by chance). + + AC_HAVE_HEADERS(unistd.h sys/param.h) + +]) + +#-------------------------------------------------------------------- +# SC_PATH_X +# +# Locate the X11 header files and the X11 library archive. Try +# the ac_path_x macro first, but if it doesn't find the X stuff +# (e.g. because there's no xmkmf program) then check through +# a list of possible directories. Under some conditions the +# autoconf macro will return an include directory that contains +# no include files, so double-check its result just to be safe. +# +# Arguments: +# none +# +# Results: +# +# Sets the the following vars: +# XINCLUDES +# XLIBSW +# +#-------------------------------------------------------------------- + +AC_DEFUN(SC_PATH_X, [ + AC_PATH_X + not_really_there="" + if test "$no_x" = ""; then + if test "$x_includes" = ""; then + AC_TRY_CPP([#include <X11/XIntrinsic.h>], , not_really_there="yes") + else + if test ! -r $x_includes/X11/Intrinsic.h; then + not_really_there="yes" + fi + fi + fi + if test "$no_x" = "yes" -o "$not_really_there" = "yes"; then + AC_MSG_CHECKING(for X11 header files) + found_xincludes="no" + AC_TRY_CPP([#include <X11/Intrinsic.h>], found_xincludes="yes", found_xincludes="no") + if test "$found_xincludes" = "no"; then + dirs="/usr/unsupported/include /usr/local/include /usr/X386/include /usr/X11R6/include /usr/X11R5/include /usr/include/X11R5 /usr/include/X11R4 /usr/openwin/include /usr/X11/include /usr/sww/include" + for i in $dirs ; do + if test -r $i/X11/Intrinsic.h; then + AC_MSG_RESULT($i) + XINCLUDES=" -I$i" + found_xincludes="yes" + break + fi + done + fi + else + if test "$x_includes" != ""; then + XINCLUDES="-I$x_includes" + found_xincludes="yes" + fi + fi + if test found_xincludes = "no"; then + AC_MSG_RESULT(couldn't find any!) + fi + + if test "$no_x" = yes; then + AC_MSG_CHECKING(for X11 libraries) + XLIBSW=nope + dirs="/usr/unsupported/lib /usr/local/lib /usr/X386/lib /usr/X11R6/lib /usr/X11R5/lib /usr/lib/X11R5 /usr/lib/X11R4 /usr/openwin/lib /usr/X11/lib /usr/sww/X11/lib" + for i in $dirs ; do + if test -r $i/libX11.a -o -r $i/libX11.so -o -r $i/libX11.sl; then + AC_MSG_RESULT($i) + XLIBSW="-L$i -lX11" + x_libraries="$i" + break + fi + done + else + if test "$x_libraries" = ""; then + XLIBSW=-lX11 + else + XLIBSW="-L$x_libraries -lX11" + fi + fi + if test "$XLIBSW" = nope ; then + AC_CHECK_LIB(Xwindow, XCreateWindow, XLIBSW=-lXwindow) + fi + if test "$XLIBSW" = nope ; then + AC_MSG_RESULT(couldn't find any! Using -lX11.) + XLIBSW=-lX11 + fi +]) +#-------------------------------------------------------------------- +# SC_BLOCKING_STYLE +# +# The statements below check for systems where POSIX-style +# non-blocking I/O (O_NONBLOCK) doesn't work or is unimplemented. +# On these systems (mostly older ones), use the old BSD-style +# FIONBIO approach instead. +# +# Arguments: +# none +# +# Results: +# +# Defines some of the following vars: +# HAVE_SYS_IOCTL_H +# HAVE_SYS_FILIO_H +# USE_FIONBIO +# O_NONBLOCK +# +#-------------------------------------------------------------------- + +AC_DEFUN(SC_BLOCKING_STYLE, [ + AC_CHECK_HEADERS(sys/ioctl.h) + AC_CHECK_HEADERS(sys/filio.h) + AC_MSG_CHECKING([FIONBIO vs. O_NONBLOCK for nonblocking I/O]) + if test -f /usr/lib/NextStep/software_version; then + system=NEXTSTEP-`awk '/3/,/3/' /usr/lib/NextStep/software_version` + else + system=`uname -s`-`uname -r` + if test "$?" -ne 0 ; then + system=unknown + else + # Special check for weird MP-RAS system (uname returns weird + # results, and the version is kept in special file). + + if test -r /etc/.relid -a "X`uname -n`" = "X`uname -s`" ; then + system=MP-RAS-`awk '{print $3}' /etc/.relid'` + fi + if test "`uname -s`" = "AIX" ; then + system=AIX-`uname -v`.`uname -r` + fi + fi + fi + case $system in + # There used to be code here to use FIONBIO under AIX. However, it + # was reported that FIONBIO doesn't work under AIX 3.2.5. Since + # using O_NONBLOCK seems fine under AIX 4.*, I removed the FIONBIO + # code (JO, 5/31/97). + + OSF*) + AC_DEFINE(USE_FIONBIO) + AC_MSG_RESULT(FIONBIO) + ;; + SunOS-4*) + AC_DEFINE(USE_FIONBIO) + AC_MSG_RESULT(FIONBIO) + ;; + ULTRIX-4.*) + AC_DEFINE(USE_FIONBIO) + AC_MSG_RESULT(FIONBIO) + ;; + *) + AC_MSG_RESULT(O_NONBLOCK) + ;; + esac +]) + +#-------------------------------------------------------------------- +# SC_TIME_HANLDER +# +# Checks how the system deals with time.h, what time structures +# are used on the system, and what fields the structures have. +# +# Arguments: +# none +# +# Results: +# +# Defines some of the following vars: +# USE_DELTA_FOR_TZ +# HAVE_TM_GMTOFF +# HAVE_TM_TZADJ +# HAVE_TIMEZONE_VAR +# +#-------------------------------------------------------------------- + +AC_DEFUN(SC_TIME_HANDLER, [ + AC_CHECK_HEADERS(sys/time.h) + AC_HEADER_TIME + AC_STRUCT_TIMEZONE + + AC_CHECK_FUNCS(gmtime_r localtime_r) + + AC_MSG_CHECKING([tm_tzadj in struct tm]) + AC_CACHE_VAL(tcl_cv_member_tm_tzadj, + AC_TRY_COMPILE([#include <time.h>], [struct tm tm; tm.tm_tzadj;], + tcl_cv_member_tm_tzadj=yes, tcl_cv_member_tm_tzadj=no)) + AC_MSG_RESULT($tcl_cv_member_tm_tzadj) + if test $tcl_cv_member_tm_tzadj = yes ; then + AC_DEFINE(HAVE_TM_TZADJ) + fi + + AC_MSG_CHECKING([tm_gmtoff in struct tm]) + AC_CACHE_VAL(tcl_cv_member_tm_gmtoff, + AC_TRY_COMPILE([#include <time.h>], [struct tm tm; tm.tm_gmtoff;], + tcl_cv_member_tm_gmtoff=yes, tcl_cv_member_tm_gmtoff=no)) + AC_MSG_RESULT($tcl_cv_member_tm_gmtoff) + if test $tcl_cv_member_tm_gmtoff = yes ; then + AC_DEFINE(HAVE_TM_GMTOFF) + fi + + # + # Its important to include time.h in this check, as some systems + # (like convex) have timezone functions, etc. + # + AC_MSG_CHECKING([long timezone variable]) + AC_CACHE_VAL(tcl_cv_var_timezone, + AC_TRY_COMPILE([#include <time.h>], + [extern long timezone; + timezone += 1; + exit (0);], + tcl_cv_timezone_long=yes, tcl_cv_timezone_long=no)) + AC_MSG_RESULT($tcl_cv_timezone_long) + if test $tcl_cv_timezone_long = yes ; then + AC_DEFINE(HAVE_TIMEZONE_VAR) + else + # + # On some systems (eg IRIX 6.2), timezone is a time_t and not a long. + # + AC_MSG_CHECKING([time_t timezone variable]) + AC_CACHE_VAL(tcl_cv_timezone_time, + AC_TRY_COMPILE([#include <time.h>], + [extern time_t timezone; + timezone += 1; + exit (0);], + tcl_cv_timezone_time=yes, tcl_cv_timezone_time=no)) + AC_MSG_RESULT($tcl_cv_timezone_time) + if test $tcl_cv_timezone_time = yes ; then + AC_DEFINE(HAVE_TIMEZONE_VAR) + fi + fi +]) + +#-------------------------------------------------------------------- +# SC_BUGGY_STRTOD +# +# Under Solaris 2.4, strtod returns the wrong value for the +# terminating character under some conditions. Check for this +# and if the problem exists use a substitute procedure +# "fixstrtod" (provided by Tcl) that corrects the error. +# Also, on Compaq's Tru64 Unix 5.0, +# strtod(" ") returns 0.0 instead of a failure to convert. +# +# Arguments: +# none +# +# Results: +# +# Might defines some of the following vars: +# strtod (=fixstrtod) +# +#-------------------------------------------------------------------- + +AC_DEFUN(SC_BUGGY_STRTOD, [ + AC_CHECK_FUNC(strtod, tcl_strtod=1, tcl_strtod=0) + if test "$tcl_strtod" = 1; then + AC_MSG_CHECKING([for Solaris2.4/Tru64 strtod bugs]) + AC_CACHE_VAL(tcl_cv_strtod_buggy,[ + AC_TRY_RUN([ + extern double strtod(); + int main() { + char *infString="Inf", *nanString="NaN", *spaceString=" "; + char *term; + double value; + value = strtod(infString, &term); + if ((term != infString) && (term[-1] == 0)) { + exit(1); + } + value = strtod(nanString, &term); + if ((term != nanString) && (term[-1] == 0)) { + exit(1); + } + value = strtod(spaceString, &term); + if (term == (spaceString+1)) { + exit(1); + } + exit(0); + }], tcl_cv_strtod_buggy=1, tcl_cv_strtod_buggy=0, tcl_cv_strtod_buggy=0)]) + if test "$tcl_cv_strtod_buggy" = 1; then + AC_MSG_RESULT(ok) + else + AC_MSG_RESULT(buggy) + # upgrade to 2.5x egm 3/25/03 + AC_LIBOBJ(fixstrtod.o) + HAVE_COMPAT=true + AC_DEFINE(strtod, fixstrtod) + fi + fi +]) + +#-------------------------------------------------------------------- +# SC_TCL_LINK_LIBS +# +# Search for the libraries needed to link the Tcl shell. +# Things like the math library (-lm) and socket stuff (-lsocket vs. +# -lnsl) are dealt with here. +# +# Arguments: +# Requires the following vars to be set in the Makefile: +# DL_LIBS +# LIBS +# MATH_LIBS +# +# Results: +# +# Subst's the following var: +# TCL_LIBS +# MATH_LIBS +# +# Might append to the following vars: +# LIBS +# +# Might define the following vars: +# HAVE_NET_ERRNO_H +# +#-------------------------------------------------------------------- + +AC_DEFUN(SC_TCL_LINK_LIBS, [ + #-------------------------------------------------------------------- + # On a few very rare systems, all of the libm.a stuff is + # already in libc.a. Set compiler flags accordingly. + # Also, Linux requires the "ieee" library for math to work + # right (and it must appear before "-lm"). + #-------------------------------------------------------------------- + + AC_CHECK_FUNC(sin, MATH_LIBS="", MATH_LIBS="-lm") + AC_CHECK_LIB(ieee, main, [MATH_LIBS="-lieee $MATH_LIBS"]) + + #-------------------------------------------------------------------- + # Interactive UNIX requires -linet instead of -lsocket, plus it + # needs net/errno.h to define the socket-related error codes. + #-------------------------------------------------------------------- + + AC_CHECK_LIB(inet, main, [LIBS="$LIBS -linet"]) + AC_CHECK_HEADER(net/errno.h, [AC_DEFINE(HAVE_NET_ERRNO_H)]) + + #-------------------------------------------------------------------- + # Check for the existence of the -lsocket and -lnsl libraries. + # The order here is important, so that they end up in the right + # order in the command line generated by make. Here are some + # special considerations: + # 1. Use "connect" and "accept" to check for -lsocket, and + # "gethostbyname" to check for -lnsl. + # 2. Use each function name only once: can't redo a check because + # autoconf caches the results of the last check and won't redo it. + # 3. Use -lnsl and -lsocket only if they supply procedures that + # aren't already present in the normal libraries. This is because + # IRIX 5.2 has libraries, but they aren't needed and they're + # bogus: they goof up name resolution if used. + # 4. On some SVR4 systems, can't use -lsocket without -lnsl too. + # To get around this problem, check for both libraries together + # if -lsocket doesn't work by itself. + #-------------------------------------------------------------------- + + tcl_checkBoth=0 + AC_CHECK_FUNC(connect, tcl_checkSocket=0, tcl_checkSocket=1) + if test "$tcl_checkSocket" = 1; then + AC_CHECK_FUNC(setsockopt, , [AC_CHECK_LIB(socket, setsockopt, + LIBS="$LIBS -lsocket", tcl_checkBoth=1)]) + fi + if test "$tcl_checkBoth" = 1; then + tk_oldLibs=$LIBS + LIBS="$LIBS -lsocket -lnsl" + AC_CHECK_FUNC(accept, tcl_checkNsl=0, [LIBS=$tk_oldLibs]) + fi + AC_CHECK_FUNC(gethostbyname, , [AC_CHECK_LIB(nsl, gethostbyname, + [LIBS="$LIBS -lnsl"])]) + + # Don't perform the eval of the libraries here because DL_LIBS + # won't be set until we call SC_CONFIG_CFLAGS + + TCL_LIBS='${DL_LIBS} ${LIBS} ${MATH_LIBS}' + AC_SUBST(TCL_LIBS) + AC_SUBST(MATH_LIBS) +]) + +#-------------------------------------------------------------------- +# SC_TCL_EARLY_FLAGS +# +# Check for what flags are needed to be passed so the correct OS +# features are available. +# +# Arguments: +# None +# +# Results: +# +# Might define the following vars: +# _ISOC99_SOURCE +# _LARGEFILE64_SOURCE +# +#-------------------------------------------------------------------- + +AC_DEFUN(SC_TCL_EARLY_FLAG,[ + AC_CACHE_VAL([tcl_cv_flag_]translit($1,[A-Z],[a-z]), + AC_TRY_COMPILE([$2], $3, [tcl_cv_flag_]translit($1,[A-Z],[a-z])=no, + AC_TRY_COMPILE([[#define ]$1[ 1 +]$2], $3, + [tcl_cv_flag_]translit($1,[A-Z],[a-z])=yes, + [tcl_cv_flag_]translit($1,[A-Z],[a-z])=no))) + if test ["x${tcl_cv_flag_]translit($1,[A-Z],[a-z])[}" = "xyes"] ; then + AC_DEFINE($1) + tcl_flags="$tcl_flags $1" + fi]) + +AC_DEFUN(SC_TCL_EARLY_FLAGS,[ + AC_MSG_CHECKING([for required early compiler flags]) + tcl_flags="" + SC_TCL_EARLY_FLAG(_ISOC99_SOURCE,[#include <stdlib.h>], + [char *p = (char *)strtoll; char *q = (char *)strtoull;]) + SC_TCL_EARLY_FLAG(_LARGEFILE64_SOURCE,[#include <sys/stat.h>], + [struct stat64 buf; int i = stat64("/", &buf);]) + if test "x${tcl_flags}" = "x" ; then + AC_MSG_RESULT(none) + else + AC_MSG_RESULT(${tcl_flags}) + fi]) + +#-------------------------------------------------------------------- +# SC_TCL_64BIT_FLAGS +# +# Check for what is defined in the way of 64-bit features. +# +# Arguments: +# None +# +# Results: +# +# Might define the following vars: +# TCL_WIDE_INT_IS_LONG +# TCL_WIDE_INT_TYPE +# HAVE_STRUCT_DIRENT64 +# HAVE_STRUCT_STAT64 +# HAVE_TYPE_OFF64_T +# +#-------------------------------------------------------------------- + +AC_DEFUN(SC_TCL_64BIT_FLAGS, [ + AC_MSG_CHECKING([for 64-bit integer type]) + AC_CACHE_VAL(tcl_cv_type_64bit,[ + tcl_cv_type_64bit=none + # See if the compiler knows natively about __int64 + AC_TRY_COMPILE(,[__int64 value = (__int64) 0;], + tcl_type_64bit=__int64, tcl_type_64bit="long long") + # See if we should use long anyway Note that we substitute in the + # type that is our current guess for a 64-bit type inside this check + # program, so it should be modified only carefully... + AC_TRY_RUN([#include <unistd.h> + int main() {exit(!(sizeof(]${tcl_type_64bit}[) > sizeof(long)));} + ], tcl_cv_type_64bit=${tcl_type_64bit},:,:)]) + if test "${tcl_cv_type_64bit}" = none ; then + AC_DEFINE(TCL_WIDE_INT_IS_LONG) + AC_MSG_RESULT(using long) + else + AC_DEFINE_UNQUOTED(TCL_WIDE_INT_TYPE,${tcl_cv_type_64bit}) + AC_MSG_RESULT(${tcl_cv_type_64bit}) + + # Now check for auxiliary declarations + AC_MSG_CHECKING([for struct dirent64]) + AC_CACHE_VAL(tcl_cv_struct_dirent64,[ + AC_TRY_COMPILE([#include <sys/types.h> +#include <sys/dirent.h>],[struct dirent64 p;], + tcl_cv_struct_dirent64=yes,tcl_cv_struct_dirent64=no)]) + if test "x${tcl_cv_struct_dirent64}" = "xyes" ; then + AC_DEFINE(HAVE_STRUCT_DIRENT64) + fi + AC_MSG_RESULT(${tcl_cv_struct_dirent64}) + + AC_MSG_CHECKING([for struct stat64]) + AC_CACHE_VAL(tcl_cv_struct_stat64,[ + AC_TRY_COMPILE([#include <sys/stat.h>],[struct stat64 p; +], + tcl_cv_struct_stat64=yes,tcl_cv_struct_stat64=no)]) + if test "x${tcl_cv_struct_stat64}" = "xyes" ; then + AC_DEFINE(HAVE_STRUCT_STAT64) + fi + AC_MSG_RESULT(${tcl_cv_struct_stat64}) + + AC_MSG_CHECKING([for off64_t]) + AC_CACHE_VAL(tcl_cv_type_off64_t,[ + AC_TRY_COMPILE([#include <sys/types.h>],[off64_t offset; +], + tcl_cv_type_off64_t=yes,tcl_cv_type_off64_t=no)]) + if test "x${tcl_cv_type_off64_t}" = "xyes" ; then + AC_DEFINE(HAVE_TYPE_OFF64_T) + fi + AC_MSG_RESULT(${tcl_cv_type_off64_t}) + fi]) diff --git a/xpa/tclloop.c b/xpa/tclloop.c new file mode 100644 index 0000000..a8b4ac5 --- /dev/null +++ b/xpa/tclloop.c @@ -0,0 +1,391 @@ +/* + * Copyright (c) 1999-2003 Smithsonian Astrophysical Observatory + */ + +#include <xpap.h> + +#if HAVE_TCL + +#include <tcl.h> + +/* We build XPA on Windows using Cygwin and, for convenience, we sense the + presence of Windows by the presence of Cygwin. This is important for Tcl + because Windows does not support Tcl_CreateFileHandler */ +#ifndef HAVE_TCLFILEHANDLER +#if HAVE_CYGWIN|HAVE_MINGW32 +#define HAVE_TCLFILEHANDLER 0 +#else +#define HAVE_TCLFILEHANDLER 1 +#endif +#endif + +/* + *---------------------------------------------------------------------------- + * + * + * Private Routines and Data + * + * + *---------------------------------------------------------------------------- + */ + +#define TCL_SOCKET TCL_UNIX_FD + +/* + * + * record struct for maintining Tcl info in Tcl select loop + * + */ +typedef struct xpatclrec{ + Tcl_Event header; + int fd; + void *client_data; +} *XPATcl, XPATclRec; + + +#if HAVE_TCLFILEHANDLER +/* + *---------------------------------------------------------------------------- + * + * Routine: XPATclHandler + * + * Purpose: handle one request for an xpaset or xpaget + * + * Return: none + * + *---------------------------------------------------------------------------- + */ +#ifdef ANSI_FUNC +static void +XPATclHandler (ClientData client_data, int mask) +#else +static void XPATclHandler(client_data, mask) + ClientData client_data; + int mask; +#endif +{ + XPATcl xptr = (XPATcl)client_data; + if( (xptr == NULL) || (xptr->client_data == NULL) ) + return; + XPAHandler((XPA)xptr->client_data, xptr->fd); +} + +#else + +#define TCL_BLOCKTIME_SEC 0 +#define TCL_BLOCKTIME_USEC 1000 + +/* + *---------------------------------------------------------------------- + * + * XPAEventProc -- + * + * This procedure is called by Tcl_ServiceEvent when an XPA event + * reaches the front of the event queue. This procedure is + * responsible for notifying the generic channel code. + * + * Results: + * Returns 1 if the event was handled, meaning it should be removed + * from the queue. Returns 0 if the event was not handled, meaning + * it should stay on the queue. The only time the event isn't + * handled is if the TCL_FILE_EVENTS flag bit isn't set. + * + * Side effects: + * Whatever the channel callback procedures do. + * + *---------------------------------------------------------------------- + */ +#ifdef ANSI_FUNC +static int +XPAEventProc(Tcl_Event *evPtr, int flags) +#else +static int +XPAEventProc(evPtr, flags) + Tcl_Event *evPtr; /* Event to service. */ + int flags; /* Flags that indicate what events to + * handle, such as TCL_FILE_EVENTS. */ +#endif +{ + XPATcl xptr = (XPATcl)evPtr; + if( xptr && xptr->client_data ) + XPAHandler((XPA)xptr->client_data, xptr->fd); + return 1; +} + +/* + *---------------------------------------------------------------------- + * + * XPASetupProc -- + * + * This procedure is invoked before Tcl_DoOneEvent blocks waiting + * for an event. + * + * Results: + * None. + * + * Side effects: + * Adjusts the block time if needed. + * + *---------------------------------------------------------------------- + */ +#ifdef ANSI_FUNC +static void +XPASetupProc(ClientData data, int flags) +#else +static void +XPASetupProc(data, flags) + ClientData data; + int flags; +#endif +{ + Tcl_Time blockTime = { TCL_BLOCKTIME_SEC, TCL_BLOCKTIME_USEC }; + + Tcl_SetMaxBlockTime(&blockTime); + return; +} + +/* + *---------------------------------------------------------------------- + * + * XPACheckProc -- + * + * This procedure is called by Tcl_DoOneEvent to check the XPA + * event source for events. + * + * Results: + * None. + * + * Side effects: + * May queue an event. + * + *---------------------------------------------------------------------- + */ +#ifdef ANSI_FUNC +static void +XPACheckProc(ClientData data, int flags) +#else +static void +XPACheckProc(data, flags) + ClientData data; + int flags; +#endif +{ + XPATcl xptr = (XPATcl)data; + XPATcl evPtr; + fd_set readfds; + struct timeval tv; + int got; + +again: + FD_ZERO(&readfds); + if( XPAActiveFd(xptr->fd) ){ + FD_SET(xptr->fd, &readfds); + tv.tv_sec = 0; + tv.tv_usec = 0; + got = xselect(xptr->fd+1, &readfds, NULL, NULL, &tv); + if( got < 0 ){ + if( errno == EINTR ) + goto again; + perror("xpa select event"); + Tcl_DeleteEventSource(XPASetupProc, XPACheckProc, xptr); + } + else if( got ){ + evPtr = (XPATcl)Tcl_Alloc(sizeof(XPATclRec)); + memcpy(evPtr, xptr, sizeof(XPATclRec)); + evPtr->header.proc = XPAEventProc; + Tcl_QueueEvent((Tcl_Event *) evPtr, TCL_QUEUE_TAIL); + } + } +} +#endif + +/* + *---------------------------------------------------------------------------- + * + * Routine: XPATclEnableOneInput + * + * Purpose: Enable 1 XPA entry from the Tcl event loop + * + * Results: none + * + *---------------------------------------------------------------------------- + */ +#ifdef ANSI_FUNC +static void +XPATclEnableOneInput (void *client_data) +#else +static void XPATclEnableOneInput(client_data) + void *client_data; +#endif +{ + XPATcl xptr = (XPATcl)client_data; + if( xptr == NULL ) + return; +#if HAVE_TCLFILEHANDLER + Tcl_CreateFileHandler(xptr->fd, TCL_READABLE, XPATclHandler, xptr); +#else + Tcl_CreateEventSource(XPASetupProc, XPACheckProc, xptr); +#endif +} + +/* + *---------------------------------------------------------------------------- + * + * Routine: XPATclDisableOneInput + * + * Purpose: Disable 1 XPA entry from the Tcl event loop + * + * Results: none + * + *---------------------------------------------------------------------------- + */ +#ifdef ANSI_FUNC +static void +XPATclDisableOneInput (void *client_data) +#else +static void XPATclDisableOneInput(client_data) + void *client_data; +#endif +{ + XPATcl xptr = (XPATcl)client_data; + if( xptr == NULL ) + return; +#if HAVE_TCLFILEHANDLER + Tcl_CreateFileHandler(xptr->fd, 0, XPATclHandler, xptr->client_data); +#else + Tcl_DeleteEventSource(XPASetupProc, XPACheckProc, xptr); +#endif +} + +/* + *---------------------------------------------------------------------------- + * + * Routine: XPATclAddOneInput + * + * Purpose: Add 1 XPA entry to the Tcl event loop + * + * Results: none + * + *---------------------------------------------------------------------------- + */ +#ifdef ANSI_FUNC +static void * +XPATclAddOneInput (void *client_data, int fd) +#else +static void *XPATclAddOneInput(client_data, fd) + void *client_data; + int fd; +#endif +{ + XPATcl xptr; + if( fd < 0 ) + return(NULL); + xptr = (XPATcl)xcalloc(1, sizeof(XPATclRec)); + xptr->fd = fd; + xptr->client_data = (XPA)client_data; + XPATclEnableOneInput(xptr); + return(xptr); +} + +/* + *---------------------------------------------------------------------------- + * + * Routine: XPATclDelOneInput + * + * Purpose: Delete 1 XPA entry from the Tcl event loop (called by XPAFree) + * + * Results: none + * + *---------------------------------------------------------------------------- + */ +#ifdef ANSI_FUNC +static void +XPATclDelOneInput (void *client_data) +#else +static void XPATclDelOneInput(client_data) + void *client_data; +#endif +{ + XPATcl xptr = (XPATcl)client_data; + if( xptr == NULL ) + return; + XPATclDisableOneInput(xptr); + xfree(xptr); +} + +/* + *---------------------------------------------------------------------------- + * + * + * Public Routines and Data + * + * + *---------------------------------------------------------------------------- + */ + +/* + *---------------------------------------------------------------------------- + * + * Routine: XPATclAddInput + * + * Purpose: Add XPA entries to the Tcl event loop + * + * Results: number of xpa entried added + * + *---------------------------------------------------------------------------- + */ +#ifdef ANSI_FUNC +int +XPATclAddInput (XPA xpa) +#else +int XPATclAddInput(xpa) + XPA xpa; +#endif +{ + XPA cur; + int got=0; + + /* if a specific xpa was specified, just add it */ + if( xpa != NULL ){ + /* remove old one */ + if( xpa->seldel && xpa->selptr ){ + (xpa->seldel)(xpa->selptr); + } + /* add new one */ + xpa->seladd = XPATclAddOneInput; + xpa->seldel = XPATclDelOneInput; +#if HAVE_TCLFILEHANDLER + xpa->selon = XPATclEnableOneInput; + xpa->seloff = XPATclDisableOneInput; +#endif + xpa->selptr = XPATclAddOneInput((void *)xpa, xpa->fd); + got = 1; + } + /* otherwise set up all xpa's */ + else{ + for(cur=(XPA)XPAListHead(); cur!=NULL; cur=cur->next){ + /* remove old one */ + if( cur->seldel && cur->selptr ){ + (cur->seldel)(cur->selptr); + } + /* add new one */ + cur->seladd = XPATclAddOneInput; + cur->seldel = XPATclDelOneInput; +#if HAVE_TCLFILEHANDLER + cur->selon = XPATclEnableOneInput; + cur->seloff = XPATclDisableOneInput; +#endif + cur->selptr = XPATclAddOneInput((void *)cur, cur->fd); + got++; + } + } + return(got); +} + +int xpa_tcl = 1; + +#else + +int xpa_tcl = 0; + +#endif diff --git a/xpa/tcp.c b/xpa/tcp.c new file mode 100644 index 0000000..ddd4366 --- /dev/null +++ b/xpa/tcp.c @@ -0,0 +1,223 @@ +/* + * Copyright (c) 1999-2003 Smithsonian Astrophysical Observatory + */ + +/* + * + * tcp.c -- unix tcp connection routines + * + */ +#if HAVE_CONFIG_H +#include <conf.h> +#endif + +#if HAVE_UNISTD_H +#include <unistd.h> +#endif +#if HAVE_STDLIB_H +#include <stdlib.h> +#endif +#include <stdio.h> +#include <errno.h> +#include <string.h> +#include <xport.h> +#include <tcp.h> + +/* the ever-present */ +#ifndef SZ_LINE +#define SZ_LINE 1024 +#endif + +/* name of user environment variable specifying this host */ +#ifndef MYHOST +#define MYHOST "XPA_HOST" +#endif + +/* other modules can set this variable and the default for various routines + will be "localhost" instead of the DNS-dependent hostname */ +int use_localhost=0; + +static char myhost[SZ_LINE]; /* hostname to registering access points */ + +/* + *---------------------------------------------------------------------------- + * + * + * Private Routines and Data + * + * + *---------------------------------------------------------------------------- + */ + +static char ipstr[SZ_LINE]; + +/* + *---------------------------------------------------------------------------- + * + * + * Public Routines + * + * + *---------------------------------------------------------------------------- + */ + +/* + *-------------------------------------------------------------- + * + * Routines: gethost + * + * Purpose: Find the current hostname + * + * Results: 1 on success, 0 for failure + * + *-------------------------------------------------------------- + */ +#ifdef ANSI_FUNC +int +gethost ( + char *xhost, /* (out) corresponding hostname */ + int len /* (in) length of host buffer */ +) +#else +int gethost(xhost, len) + char *xhost; /* (out) corresponding hostname */ + int len; /* (in) length of host buffer */ +#endif +{ + char *s=NULL; + struct hostent *hent; + static int init=0; + + if( use_localhost == 0 ){ + if( init == 0 ){ + if( (s=(char *)getenv(MYHOST)) != NULL ){ + strncpy(myhost, s, SZ_LINE-1); + } else { + gethostname(myhost, SZ_LINE-1); + } + init++; + } + strncpy(xhost, myhost, len-1); + if( (hent = gethostbyname(xhost)) == NULL ){ + return(-1); + } + strncpy(xhost, hent->h_name, len-1); + } + else{ + strncpy(xhost, "localhost", len-1); + } + xhost[len-1] = '\0'; + return(0); +} + +/* + *---------------------------------------------------------------------------- + * + * Routine: gethostip + * + * Purpose: Find the IP address corresponding to a hostname + * + * Results: ip (host byte order) on success, 0 if host is unknown + * + *--------------------------------------------------------------------------- + */ +#ifdef ANSI_FUNC +unsigned int +gethostip ( + char *xhost /* (in) Hostname (human readable) */ +) +#else +unsigned int gethostip(xhost) + char *xhost; /* (in) Hostname (human readable) */ +#endif +{ + struct hostent *hostent; + unsigned int ip; + char temp[SZ_LINE]; + int saveip=0; + static unsigned int myip=0; + + + /* null input means current host */ + if( (xhost == NULL) || (*xhost == '\0') || !strcmp(xhost, "$host") ){ + if( myip != 0 ) + return(myip); + saveip = 1; + gethost(temp, SZ_LINE); + } + else if( !strcmp(xhost, "$localhost") ){ + strcpy(temp, "localhost"); + } else { + strncpy(temp, xhost, SZ_LINE-1); + temp[SZ_LINE-1] = '\0'; + } + + /* special check */ + if( !strcmp(temp, "localhost") || !strcmp(temp, "localhost.localdomain") ){ + ip = htonl(0x7F000001); + goto done; + } + + /* + * Try looking by address (i.e., host is something like "128.84.253.1"). + * Do this first because it's much faster (no trip to the DNS) + */ + if( (int)(ip = inet_addr(temp)) != -1 ){ + goto done; + } + + /* + * Try looking it up by name. If successful, the IP address is in + * hostent->h_addr_list[0] + */ + if( (hostent = gethostbyname(temp)) != NULL ){ + memcpy(&ip, hostent->h_addr_list[0], (size_t)hostent->h_length); + goto done; + } + + /* could not convert */ + ip = 0; + saveip = 0; + +done: + ip = ntohl(ip); + if( saveip ) myip = ip; + return(ip); +} + +/* + *---------------------------------------------------------------------------- + * + * Routine: getiphost + * + * Purpose: Find the IP address in dot format corresponding to an ip + * + * Results: ip string (in static buffer) or NULL + * + *--------------------------------------------------------------------------- + */ +#ifdef ANSI_FUNC +char * +getiphost (unsigned int ip) +#else +char *getiphost(ip) + unsigned int ip; +#endif +{ + char *s; + struct sockaddr_in sockbuf; + + if( ip == 0x7F000001 ){ + strcpy(ipstr, "localhost"); + return(ipstr); + } + + sockbuf.sin_addr.s_addr = htonl(ip); + s = (char *)inet_ntoa(sockbuf.sin_addr); + if( s != NULL ){ + strcpy(ipstr, s); + return(ipstr); + } + else + return(NULL); +} diff --git a/xpa/tcp.h b/xpa/tcp.h new file mode 100644 index 0000000..c22b874 --- /dev/null +++ b/xpa/tcp.h @@ -0,0 +1,24 @@ +/* + * Copyright (c) 1999-2003 Smithsonian Astrophysical Observatory + */ + +/* + * + * tcp.h - include file for tcp support in xpa + * + */ + +#ifndef __tcp_h +#define __tcp_h + +#include <prsetup.h> + +_PRbeg + +int gethost _PRx((char *host, int len)); +unsigned int gethostip _PRx((char *host)); +char *getiphost _PRx((unsigned int ip)); + +_PRend + +#endif diff --git a/xpa/test.tcl b/xpa/test.tcl new file mode 100644 index 0000000..bfc413c --- /dev/null +++ b/xpa/test.tcl @@ -0,0 +1,261 @@ +lappend auto_path . + +package require tclxpa 2.1 + +# set rmode "fillbuf=false" +set rmode "" +set imode "" + +set smode "" +set sbuf "initial message\n" +set slen [string length $sbuf] +set schan "" + +set n 0 + +proc DoIt {xpa cdata param buf len} { + puts [format "entering %s" $cdata] + tk_messageBox -parent . -type ok -message "$cdata" + puts [format "exiting %s" $cdata] +} + +proc reccb { xpa client_data paramlist buf len }\ +{ + global sbuf slen rmode n + global sfile sfilebuf schan + puts " " + puts [format "Entering receive callback routine %s" $n] + puts [format "xpa class: %s" [xparec $xpa class]] + puts [format "xpa name: %s" [xparec $xpa name]] + puts [format "xpa method: %s" [xparec $xpa method]] + puts [format "xpa cmdfd: %s" [xparec $xpa cmdfd]] + puts [format "xpa cmdchan: %s" [xparec $xpa cmdchan]] + puts [format "xpa datafd: %s" [xparec $xpa datafd]] + puts [format "xpa datachan: %s" [xparec $xpa datachan]] + puts [format "xpa sendian: %s" [xparec $xpa sendian]] + puts [format "xpa cendian: %s" [xparec $xpa cendian]] + puts [format "client_data: %s" $client_data] + puts [format "paramlist: %s" $paramlist] + incr n + + if { $rmode == "fillbuf=false" } { + set dchan [xparec $xpa datachan] + fconfigure $dchan -translation binary + set mybuf [read $dchan] + set mylen [string length $mybuf] + puts [format "read %s bytes" $mylen] + set sbuf $mybuf + set slen $mylen + if { $mylen < 512 } { + puts $mybuf + } else { + xpaerror $xpa [format "Jeez! %s is too many bytes" $mylen] + return -code error + } + } else { + puts [format "entering with %s bytes" $len] + if { $len < 512 } { + puts $buf + } + set sbuf $buf + set slen $len + } + if { $paramlist == "open" } { + if { $schan != "" } { + close $schan + } + set sfile [string trimright $sbuf] + set schan [open $sfile r] + set sfilebuf [read $schan] + puts [format "read %d bytes from '%s'" [string length $sfilebuf] $sfile] + } +} + +proc sendcb { xpa client_data paramlist }\ +{ + global sbuf slen n + puts " " + puts [format "Entering send callback routine %s for %s" $n $xpa] + puts [format "xpa class: %s" [xparec $xpa class]] + puts [format "xpa name: %s" [xparec $xpa name]] + puts [format "xpa method: %s" [xparec $xpa method]] + puts [format "xpa cmdfd: %s" [xparec $xpa cmdfd]] + puts [format "xpa cmdchan: %s" [xparec $xpa cmdchan]] + puts [format "xpa datafd: %s" [xparec $xpa datafd]] + puts [format "xpa datachan: %s" [xparec $xpa datachan]] + puts [format "xpa sendian: %s" [xparec $xpa sendian]] + puts [format "xpa cendian: %s" [xparec $xpa cendian]] + puts [format "client_data: %s" $client_data] + puts [format "paramlist: %s" $paramlist] + incr n + + if { $slen > 0 } { + puts [format "sending %s bytes of data" $slen] + xpasetbuf $xpa $sbuf $slen + } else { + xpaerror $xpa [format "no data to send from %s\n" $client_data] + return -code error + } +} + +proc infocb { xpa client_data paramlist }\ +{ + puts " " + puts "Entering info callback routine" + puts [format "xpa class: %s" [xparec $xpa class]] + puts [format "xpa name: %s" [xparec $xpa name]] + puts [format "xpa method: %s" [xparec $xpa method]] + puts [format "xpa sendian: %s" [xparec $xpa sendian]] + puts [format "xpa cendian: %s" [xparec $xpa cendian]] + puts [format "client_data: %s" $client_data] + puts [format "paramlist: %s" $paramlist] +} + +if { [info exists class] == 0 } { + set class "XPA" +} +puts [format "class: %s" $class] + +if { [info exists name] == 0 } { + set name "xpa" +} +puts [format "name: %s" $name] + +if { [info exists initxpa] } { + +puts "initializing xpa access points ..." + +set xpa [xpanew [format "%s" $class] [format "%s" $name] "xpa1 help" \ + sendcb "xpa1" $smode reccb "xpa1" $rmode] +puts [format "xpa=%s" $xpa] + +set xpa1 [xpanew [format "%s" $class] [format "%s1" $name] "xpa1a help" \ + sendcb "xpa1a" $smode reccb "xpa1a" $rmode] +puts [format "xpa1=%s" $xpa1] + +set xpac [xpacmdnew [format "%s" $class] [format "%sc" $name]] +puts [format "xpac=%s" $xpac] + +set cmd1 [xpacmdadd $xpac "cmd1" "cmd1 help" \ + sendcb "xpac/cmd1" $smode reccb "xpac/cmd1" $rmode] +puts [format "cmd1=%s" $cmd1] + +set cmd2 [xpacmdadd $xpac "cmd2" "cmd2 help" \ + sendcb "xpac/cmd2" $smode reccb "xpac/cmd2" $rmode] +puts [format "cmd2=%s" $cmd2] + +set cmd3 [xpacmdadd $xpac cmd3 "help cmd 3" "" "" "" DoIt "cmd 3" ""] +puts [format "cmd3=%s" $cmd3] + +set cmd4 [xpacmdadd $xpac cmd4 "help cmd 4" "" "" "" DoIt "cmd 4" ""] +puts [format "cmd4=%s" $cmd4] + +set xpai [xpainfonew XPA [format "%si" $name] infocb "xpai" $imode] +puts [format "xpai=%s" $xpai] + +} + +proc getloop { xpa loops } { + for {set i 0} {$i < $loops} {incr i} { + set got [xpaget "" $xpa [format "testing xpaget %s" $i] \ + "" bufs lens names errs 10] + for {set j 0} {$j < $got} {incr j} { + set err [lindex $errs $j] + if { $err != "" } { + puts $err + } else { + set buf [lindex $bufs $j] + puts [format "return buf %s: %s" $j $buf] + } + } + } +} + +proc setloop { loops } { + for {set i 0} {$i < $loops} {incr i} { + set got [xpaset "" "xpa*" [format "testing xpaset %s" $i] \ + "" "dummy buffer" "" names errs 10] + puts $names + } +} + +proc infoloop { loops } { + for {set i 0} {$i < $loops} {incr i} { + set got [xpainfo "" "i_xpa" [format "testing xpainfo %s" $i] \ + "" names errs 10] + puts $names + } +} + +if { 0 } { + set got [xpaget "" "xpa1" "this is a test" "" bufs lens names errs 10] + puts $got + puts $lens + puts $bufs + + set got [xpaset "" "xpa1" "test" "" "this is a test" "" names errs 10] + puts $got + puts $errs + + set got [xpainfo "" "i_xpa" "info test" "" names errs 10] + puts $got + puts $errs + + set got [xpaaccess "" "xpa*" "" "" names errs 10] + puts $got + puts $names + puts $errs + + set xpa [xpaopen ""] + set got [xpaset $xpa "xpa1" "test" "" "this is a test" "" names errs 10] + set got [xpainfo $xpa xpai "info test" "" names errs 10] + xpaclose $xpa + + set wchan1 [open foo1.log w+] + set wchan2 [open foo2.log w+] + set wchans [list $wchan1 $wchan2] + set got [xpagetfd "" "xpa1" "this is a test" "" $wchans names errs 10] + set got [xpasetfd "" "xpa1" "this is a test" "" $rchan names errs 10] + set got [xpanslookup "xpa1" "" classes names methods] +} + +proc wsbuf { fname } { + global sbuf + set fid [open $fname w 0600] + puts -nonewline $fid $sbuf + close $fid +} + +set _xpakeepalive 1 +proc xpakeepalive { xpa sec {type 0} } { + global _xpakeepalive + if { $_xpakeepalive > 0 } { + puts "sending keepalive ..." + xpanskeepalive $xpa $type + after [expr $sec * 1000] xpakeepalive $xpa $sec $type + } +} + +proc katest { host sec {type 0} } { + global xpa + xparemote $xpa $host + -proxy + after [expr $sec * 1000] xpakeepalive $xpa $sec $type +} + +if { 0 } { + puts "You can now execute:" + puts " " + puts " katest bynars.harvard.edu:28571 60" + puts " (if this is tclsh, you need to run vwait)" + # katest bynars.harvard.edu:28571 60 + puts " " + puts "or:" + puts " " + puts " xparemote $xpa bynars.harvard.edu:28571 + -proxy" + puts " " + # xparemote $xpa bynars.harvard.edu:28571 + -proxy +} + +# vwait forever + + diff --git a/xpa/timedconn.c b/xpa/timedconn.c new file mode 100644 index 0000000..ff8202f --- /dev/null +++ b/xpa/timedconn.c @@ -0,0 +1,258 @@ +/* + * Copyright (c) 1999-2003 Smithsonian Astrophysical Observatory + */ + +#include <xpap.h> + +/* + *---------------------------------------------------------------------------- + * + * + * Private Routines and Data + * + * + *---------------------------------------------------------------------------- + */ + +#if HAVE_MINGW32==0 + +static int alarm_flag=0; + +#ifdef ANSI_FUNC +static void AlarmFunc (int signo) +#else +static void AlarmFunc (signo) + int signo; +#endif +{ + alarm_flag = 1; +} + +/* + *---------------------------------------------------------------------------- + * + * + * Public Routines and Data + * + * + *---------------------------------------------------------------------------- + */ + +/* + *---------------------------------------------------------------------------- + * + * Routine: alrmconnect + * + * Purpose: connect with alarm-based timeout + * + * Returns: status + * + * adapted from the connect_alarm() code in: + * W. Richard Stevens + * "Advanced Programming in the Unix Environment" + * Addison-Wesley Publishing Co, 1992 + * p. 350 + * + *---------------------------------------------------------------------------- + */ +#ifdef ANSI_FUNC +int alrmconnect(int sockfd, void *saptr, int salen, int nsec) +#else +int alrmconnect(sockfd, saptr, salen, nsec) + int sockfd; + void *saptr; + int salen; + int nsec; +#endif +{ + int status=0; + struct sigaction act1, oact1; + + /* no error yet */ + alarm_flag = 0; + errno = 0; + + /* set up alarm */ + if( nsec ){ + act1.sa_handler = AlarmFunc; + sigemptyset(&act1.sa_mask); + act1.sa_flags = 0; +#ifdef SA_INTERRUPT + act1.sa_flags |= SA_INTERRUPT; +#endif + if( sigaction(SIGALRM, &act1, &oact1) < 0 ){ + goto done; + } + /* start alarm */ + alarm(nsec); + } + + /* try to connect */ + status=connect(sockfd, (struct sockaddr *)saptr, salen); + + /* turn off alarm if it did not go off */ + if( nsec ) + alarm(0); + +done: + /* check for alarm => we timed out */ + if( alarm_flag ){ + xclose(sockfd); + errno = ETIMEDOUT; + status = -1; + } + + return(status); +} + +#endif + +/* + *---------------------------------------------------------------------------- + * + * Routine: noblkconnect + * + * Purpose: non-blocking connect with select-based timeout + * + * Returns: status + * + * adapted from the connect_nonb() code in: + * W. Richard Stevens + * "Advanced Programming in the Unix Environment" + * Addison-Wesley Publishing Co, 1992 + * p. 411 + * + *---------------------------------------------------------------------------- + */ +#ifdef ANSI_FUNC +int noblkconnect(int sockfd, void *saptr, int salen, int nsec) +#else +int noblkconnect(sockfd, saptr, salen, nsec) + int sockfd; + void *saptr; + int salen; + int nsec; +#endif +{ + int flags, n, error; + socklen_t len; + fd_set rset, wset; + struct timeval tval; + + /* save state and set in non-blocking mode */ + xfcntl_nonblock(sockfd, flags); + + error = 0; + if( (n = connect(sockfd, (struct sockaddr *) saptr, salen)) < 0){ + if((xerrno != EINPROGRESS) && (xerrno != EWOULDBLOCK)) + return(-1); + } + + /* Do whatever we want while the connect is taking place. */ + if(n == 0) + goto done; /* connect completed immediately */ + + FD_ZERO(&rset); + FD_SET(sockfd, &rset); + wset = rset; + tval.tv_sec = nsec; + tval.tv_usec = 0; + + if( (n = xselect(sockfd+1, &rset, &wset, NULL, + nsec ? &tval : NULL)) == 0) { + xclose(sockfd); /* timeout */ + errno = ETIMEDOUT; + return(-1); + } + + if(FD_ISSET(sockfd, &rset) || FD_ISSET(sockfd, &wset)) { + len = sizeof(error); + if(getsockopt(sockfd, SOL_SOCKET, SO_ERROR, (void *)&error, &len) <0) + return(-1); /* Solaris pending error */ + } else{ + errno = ETIMEDOUT; + } + +done: + xfcntl_restore(sockfd, flags); /* restore file status flags */ + + if(error) { + xclose(sockfd); /* just in case */ + errno = error; + return(-1); + } + return(0); +} + +#ifdef DO_MAIN +/* + * solaris: gcc -o atest atest.c -lsocket -lnsl + * linux: gcc -o atest atest.c + * os x: gcc -o atest atest.c + */ +#include <stdio.h> + +extern char *optarg; +extern int optind; + +int main(int argc, char **argv) +{ + int c; + int args; + int status; + int fd; + int doalarm=0; + int nsec=2; + unsigned int ip; + char *sip; + struct sockaddr_in sock_in; + + /* process switch arguments */ + while ((c = getopt(argc, argv, "ab")) != -1){ + switch(c){ + case 'a': + doalarm = 1; + break; + case 'b': + doalarm = 0; + break; + } + } + + args = argc - optind; + if( args > 0 ) + sip = argv[optind]; + /* this ip is bogus and normally will cause connect to hang */ + else + sip ="209.1.1.1"; + + /* set up socket to a bogus ip and port */ + if( (int)(ip = inet_addr(sip)) == -1 ){ + perror("inet_addr"); + exit(1); + } + if( (fd = xsocket(AF_INET, SOCK_STREAM, 0)) < 0 ){ + perror("socket"); + exit(1); + } + memset((char *)&sock_in, 0, sizeof(sock_in)); + sock_in.sin_family = AF_INET; + sock_in.sin_addr.s_addr = ip; + sock_in.sin_port = htons(80); + + if( doalarm ){ + fprintf(stderr, "alarm-based connect() ...\n"); + status=alrmconnect(fd, (void *)&sock_in, sizeof(sock_in), nsec); + } + else{ + fprintf(stderr, "non-blocking connect() ...\n"); + status=noblkconnect(fd, (void *)&sock_in, sizeof(sock_in), nsec); + } + + /* if alarm_flag is 1, alarm went off and interrupted connect */ + fprintf(stderr, "alarm_flag=%d status=%d\n", alarm_flag, status); + if( status != 0 ) + perror("connect"); +} + +#endif diff --git a/xpa/timedconn.h b/xpa/timedconn.h new file mode 100644 index 0000000..e46e69d --- /dev/null +++ b/xpa/timedconn.h @@ -0,0 +1,24 @@ +/* + * Copyright (c) 1999-2003 Smithsonian Astrophysical Observatory + */ + +/* + * + * timedconn.h -- declarations for connect w/ timeout + * + */ + +#ifndef __timedconn_h +#define __timedconn_h + +#include <prsetup.h> + +_PRbeg + +int alrmconnect _PRx((int sockfd, void *saptr, int salen, int nsec)); + +int noblkconnect _PRx((int sockfd, void *saptr, int salen, int nsec)); + +_PRend + +#endif diff --git a/xpa/word.c b/xpa/word.c new file mode 100644 index 0000000..2d60eb0 --- /dev/null +++ b/xpa/word.c @@ -0,0 +1,1097 @@ +/* + * Copyright (c) 1999-2003 Smithsonian Astrophysical Observatory + */ + +/* + * word.c -- token parser, pattern matcher, macro expander, + * and other word-related routines + * + */ + +#include <stdio.h> +#include <string.h> +#include <ctype.h> +#include <word.h> + +/* SAOMOD_CTYPE -- work around Slackware/RedHat incompatibility */ +#ifdef linux +#ifdef isalnum +#undef isalnum +#define isalnum(c) (isalpha(c)||isdigit(c)) +#endif +#endif + +/* ************************************************************************** + * + * + * PRIVATE ROUTINES AND DATA + * + * + * **************************************************************************/ + +/* word */ +#define MAXDELIM 256 +#define MAXDTABLES 1024 +#define BUFINC 5000 + +static char lastd; +static char dtable[MAXDELIM]; +static char *dtables[MAXDTABLES]; +static int ndtable=0; + +/* tmatch */ +#define ALL '*' +#define ANY '?' +#define RANGE '[' +#define ENDRANGE ']' +#define RANGEDELIM '-' +#define NOTRANGE '~' + +/* + *---------------------------------------------------------------------------- + * + * Routine: checkrange (from tmatch) + * + * Purpose: see if character is in specified range + * + * Returns: 1 if in range, otherwise 0 + * + *---------------------------------------------------------------------------- + */ +#ifdef ANSI_FUNC +static int +checkrange (char *xtemplate, int *ptr, int c) +#else +static int checkrange(xtemplate, ptr, c) + char *xtemplate; + int *ptr; + int c; +#endif +{ + int inrange, notrange; + char lorange, hirange; + int tptr; + + tptr = *ptr; + /* make sure we have a close bracket */ + if( strchr(&xtemplate[tptr], ENDRANGE) == NULL ) + return(0); + /* check for negation - match if not in range */ + if( xtemplate [tptr+1] == NOTRANGE ){ + notrange = 1; tptr++; + } + else + notrange = 0; + /* start pessimistically */ + inrange = 0; + /* point past RANGE character */ + tptr++; + while( xtemplate[tptr] != ENDRANGE ){ + /* get lo range */ + lorange = xtemplate[tptr]; + /* and hi range */ + tptr++; + if( xtemplate[tptr] != RANGEDELIM ) + hirange = lorange; + else{ + tptr++;hirange = xtemplate[tptr];tptr++; + } + if( (c>=lorange) && (c<=hirange) ){ + inrange = 1; break; + } + } + /* only exclusive OR of inrange and notrange is ok */ + if( (inrange ^ notrange) ==0 ) + return(0); + else{ + *ptr = strchr(&xtemplate[tptr],']') - xtemplate + 1; + return(1); + } +} + +/* + *---------------------------------------------------------------------------- + * + * Routine: addstring (from macro) + * + * Purpose: add a string to a buffer + * + * Returns: none + * + *---------------------------------------------------------------------------- + */ +#ifdef ANSI_FUNC +static void +addstring (char **buf, int *blen, int *maxlen, char *str) +#else +static void addstring(buf, blen, maxlen, str) + char **buf; + int *blen; + int *maxlen; + char *str; +#endif +{ + int slen; + + slen = strlen(str) + 1; + while( (*blen + slen) >= *maxlen ){ + *maxlen += BUFINC; + *buf = (char *)xrealloc(*buf, *maxlen); + } + strcat(*buf, str); + *blen += slen; +} + +/* + *---------------------------------------------------------------------------- + * + * Routine: addchar (from macro) + * + * Purpose: add a single char to a buffer + * + * Returns: none + * + *---------------------------------------------------------------------------- + */ +#ifdef ANSI_FUNC +static void +addchar (char **buf, int *blen, int *maxlen, int c) +#else +static void addchar(buf, blen, maxlen, c) + char **buf; + int *blen; + int *maxlen; + int c; +#endif +{ + char tbuf[2]; + + tbuf[0] = c; + tbuf[1] = '\0'; + addstring(buf, blen, maxlen, tbuf); +} + +/* + *---------------------------------------------------------------------------- + * + * Routine: lookupkeywords (from macro) + * + * Purpose: lookup a name in a list of keywords + * + * Returns: return the associated value or NULL + * + *---------------------------------------------------------------------------- + */ +#ifdef ANSI_FUNC +static char * +lookupkeywords (char *name, char **keyword, char **value, int nkey) +#else +static char *lookupkeywords(name, keyword, value, nkey) + char *name; + char **keyword; + char **value; + int nkey; +#endif +{ + int i; + for(i=0; i<nkey; i++){ + if( !strcmp(name, keyword[i]) ) + return(value[i]); + } + return(NULL); +} + +/* + *---------------------------------------------------------------------------- + * + * Routine: hexval (from strtoul16) + * + * Purpose: return the int value corresponding to a hex character + * + * Returns: hex value or -1 if the character is not legal hex + * + *---------------------------------------------------------------------------- + */ +#ifdef ANSI_FUNC +static int +hexval (int c) +#else +static int hexval(c) + int c; +#endif +{ + switch(c){ + case '0': return 0; + case '1': return 1; + case '2': return 2; + case '3': return 3; + case '4': return 4; + case '5': return 5; + case '6': return 6; + case '7': return 7; + case '8': return 8; + case '9': return 9; + case 'A': return 10; + case 'a': return 10; + case 'B': return 11; + case 'b': return 11; + case 'C': return 12; + case 'c': return 12; + case 'D': return 13; + case 'd': return 13; + case 'E': return 14; + case 'e': return 14; + case 'F': return 15; + case 'f': return 15; + default: return -1; + } +} + +/* ************************************************************************** + * + * + * PUBLIC ROUTINES + * + * + * **************************************************************************/ + +/* + *---------------------------------------------------------------------------- + * + * Routine: word + * + * Purpose: a simple spaced parser + * + * Returns: 1 if word was found, else 0 + * + *---------------------------------------------------------------------------- + */ +#ifdef ANSI_FUNC +int +word (char *lbuf, char *tbuf, int *lptr) +#else +int word(lbuf, tbuf, lptr) + char *lbuf; + char *tbuf; + int *lptr; +#endif +{ + int ip; + int i; + char quotes; + + /* reset last delimiter */ + lastd='\0'; + + /* null out the output string */ + *tbuf = '\0'; + + /* if no string was specified, just return */ + if( lbuf == NULL ) + return(0); + + /* just a more convenient pointer ... */ + ip = *lptr; + + /* if we are at the end of string, just return */ + if( lbuf[ip] == '\0' ) + return(0); + + /* skip over white space */ + while( isspace((int)lbuf[ip]) || (dtable[(int)lbuf[ip]]>0) ){ + if( lbuf[ip] == '\0' ){ + *lptr = ip; + return(0); + } + else + ip++; + } + + /* check for an explicit quote */ + quotes = '\0'; + if( lbuf[ip] == '"' ){ + quotes = '"'; + lastd = '"'; + } + if( lbuf[ip] == '\'' ){ + quotes = '\''; + lastd = '\''; + } + + /* grab next token */ + if( quotes != '\0' ){ + /* bump past quotes */ + ip++; + /* grab up to next quotes -- but skip escaped quotes */ + for(i=0; lbuf[ip] != '\0'; i++, ip++){ + if( (lbuf[ip] == quotes) && (lbuf[ip-1] != '\\') ) + break; + else + tbuf[i] = lbuf[ip]; + } + } + else{ + /* grab up to next whitespace */ + for(i=0; + lbuf[ip] && !isspace((int)lbuf[ip]) && (dtable[(int)lbuf[ip]]==0); + i++, ip++) + tbuf[i] = lbuf[ip]; + /* save this delimiter */ + lastd = lbuf[ip]; + } + /* bump past delimiter (but not null terminator) */ + if( lbuf[ip] ) + ip++; + + /* null terminate */ + tbuf[i] = '\0'; + + /* got something */ + *lptr = ip; + return(1); +} + +/* + *---------------------------------------------------------------------------- + * + * Routine: newdtable + * + * Purpose: save the current delim table and init a new one + * + * Returns: 1 if another delim table can be allocated, 0 otherwise + * + *---------------------------------------------------------------------------- + */ +#ifdef ANSI_FUNC +int +newdtable (char *s) +#else +int newdtable(s) + char *s; +#endif +{ + int i; + char *cur; + + if( ndtable >= MAXDTABLES ){ + fprintf(stderr, "ERROR: no more delimiter tables available\n"); + return(0); + } + /* save another dtable */ + ndtable++; + /* allocate new space for this table */ + dtables[ndtable-1] = (char *)xmalloc(MAXDELIM); + cur = dtables[ndtable-1]; + /* copy and zero the old table */ + for(i=0; i<MAXDELIM; i++){ + cur[i] = dtable[i]; + dtable[i] = 0; + } + /* add delims to the new table */ + if( s != NULL ){ + for(; *s; s++) + dtable[(int)*s] = 1; + } + return(1); +} + +/* + *---------------------------------------------------------------------------- + * + * Routine: freedtable + * + * Purpose: restore last delim table as the current + * + * Returns: 1 if there is a table to restore, else 0 + * + *---------------------------------------------------------------------------- + */ +#ifdef ANSI_FUNC +int +freedtable (void) +#else +int freedtable() +#endif +{ + int i; + char *cur; + + if( ndtable <= 0 ){ + fprintf(stderr, "ERROR: no delimiter tables to restore\n"); + return(0); + } + cur = dtables[ndtable-1]; + /* copy the restored table into 'current' */ + for(i=0; i<MAXDELIM; i++){ + dtable[i] = cur[i]; + } + /* free up this dtable */ + xfree((void *)cur); + /* one less dtable to worry about */ + ndtable--; + return(1); +} + +/* + *---------------------------------------------------------------------------- + * + * Routine: newdelim + * + * Purpose: add a string delimiters to the parse table + * + * Returns: none + * + *---------------------------------------------------------------------------- + */ +#ifdef ANSI_FUNC +void +newdelim (char *s) +#else +void newdelim(s) + char *s; +#endif +{ + if( s != NULL ){ + for(; *s; s++) + dtable[(int)*s] = 1; + } +} + +/* + *---------------------------------------------------------------------------- + * + * Routine: freedelim + * + * Purpose: remove delims from current delim table + * + * Returns: none + * + *---------------------------------------------------------------------------- + */ +#ifdef ANSI_FUNC +void +freedelim (char *s) +#else +void freedelim(s) + char *s; +#endif +{ + int i; + + if( s ){ + for(; *s; s++) + if( dtable[(int)*s] > 0 ) + dtable[(int)*s] -= 1; + } + else{ + for(i=0; i<MAXDELIM; i++) + if( dtable[i] > 0 ) + dtable[i] -= 1; + } +} + +/* + *---------------------------------------------------------------------------- + * + * Routine: lastdelim + * + * Purpose: return the last delimiter + * + * Returns: delim character + * + *---------------------------------------------------------------------------- + */ +#ifdef ANSI_FUNC +int +lastdelim (void) +#else +int lastdelim() +#endif +{ + return((int)lastd); +} + +/* + *---------------------------------------------------------------------------- + * + * Routine: tmatch + * + * Purpose: match string to a template + * + * the legal meta characters in a template are just like the + * C-shell meta characters, i.e: + * ? match any character, but there must be one + * * match anything, or nothing + * [<c>...] match an inclusive set + * + * + * Returns: non-zero if match, zero otherwise + + * + *---------------------------------------------------------------------------- + */ +#ifdef ANSI_FUNC +int +tmatch (char *string, char *xtemplate) +#else +int tmatch(string, xtemplate) + char *string; + char *xtemplate; +#endif +{ + char *lastmeta=0; + char *nonabsorbed=0; + int sptr=0; + int tptr=0; + + /* loop through string and template */ + while( (xtemplate[tptr] != '\0') || (string[sptr] != '\0') ){ + /* if exact match, just bump both pointers */ + if( string[sptr] == xtemplate[tptr] ){ + sptr++; tptr++; continue; + } + /* if range character, check ranges */ + if( xtemplate[tptr] == RANGE ){ + if( checkrange(xtemplate, &tptr, string[sptr]) == 0 ){ + /* no match - was there a meta character before */ + if( lastmeta == 0 ) return(0); + /* if so, back up to it and try again */ + xtemplate = lastmeta; tptr=0; + /* begin checking at the non-absorbed point */ + string = nonabsorbed; sptr=0; + continue; + } + /* got a match, so bump past */ + else{ + sptr++; continue; + } + } + /* if ANY, any character if fine, but there must be one */ + if( xtemplate[tptr] == ANY ){ + if( string[sptr] == '\0' ) + return(0); + else{ + sptr++; tptr++; continue; + } + } + /* if ALL, we can match anything */ + if( xtemplate[tptr] == ALL ){ + /* remember where the * is */ + lastmeta = &xtemplate[tptr]; + tptr++; + /* no more template after this means a win */ + if( xtemplate[tptr] == '\0' ) return(1); + /* if the next template char is not a meta, + we skip up to its match in the string */ + if( xtemplate[tptr] == RANGE){ + while( checkrange(xtemplate, &tptr, string[sptr]) == 0 ){ + /* missing the next template char */ + if( string[sptr] == '\0' ) return(0); + sptr++; + } + /* remember the first non-absorbed character */ + nonabsorbed = &string[sptr];nonabsorbed++; + sptr++; + continue; + } + /* skip past characters, if next template char is not a meta */ + else if( xtemplate[tptr] != ANY && xtemplate[tptr] != ALL ){ + while(string[sptr] != xtemplate[tptr]){ + /* not finding the next template char + is bad */ + if( string[sptr] == '\0' ) return(0); + sptr++; + } + /* remember the first non-absorbed character */ + nonabsorbed = &string[sptr];nonabsorbed++; + continue; + } + else{ + /* remember the first non-absorbed character */ + nonabsorbed = &string[sptr];nonabsorbed++; + continue; + } + } + /* no match, no meta char - see if we once had a meta */ + else{ + if( lastmeta == 0 ) return(0); + /* if so, back up to it and try again */ + xtemplate = lastmeta; tptr=0; + /* begin checking at the non-absorbed point */ + string = nonabsorbed; sptr=0; + continue; + } + } + /* matched to the nulls - we win */ + return(1); +} + +/* + *---------------------------------------------------------------------------- + * + * Routine: keyword + * + * Purpose: look for a keyword=<value> string inside another string, + * remove and return the <value> in another buffer + * + * Returns: len if keyword was found, 0 otherwise + * + * NB: ibuf cannot be static, as it is modified in place + * + *---------------------------------------------------------------------------- + */ +#ifdef ANSI_FUNC +int +keyword (char *ibuf, char *key, char *obuf, int maxlen) +#else +int keyword(ibuf, key, obuf, maxlen) + char *ibuf; + char *key; + char *obuf; + int maxlen; +#endif +{ + int len; + int qlev; + char *s; + char *t; + char *u; + char *v; + char *iptr; + char quote; + + /* if we have no input string, we are done */ + if( (ibuf == NULL) || (*ibuf == '\0') ){ + return(0); + } + + /* start out pessimistically */ + *obuf = '\0'; + iptr = ibuf; + + /* maxlen generally is 1 more than we can handle */ + maxlen--; + + /* keep trying */ + while( *iptr ){ + /* look for key from current position */ + if( (s = (char *)strstr(iptr, key)) == NULL ) + return(0); + /* if we found a key, we need to make sure ... */ + /* it must be preceeded by beginning of string, beginning of bracket, + or by a "," from previous keyword */ + if( (s == ibuf) || (*(s-1) == ',') || (*(s-1) == '[') ){ + /* it can be followed by spaces ... */ + t = s + strlen(key); + while( isspace((int)*t) ) + t++; + /* but must be followed by an "=" */ + if( *t == '=' ){ + t++; + /* skip spaces again */ + while( isspace((int)*t) ) + t++; + /* this is where the actual value part of the string begins */ + u = t; + /* this will be where it ends */ + v = t; + /* gather up everything to the next "," or end of filter */ + if( (*t == '"') || (*t == '\'') || (*t == '(') || (*t == '[') ){ + switch(*t){ + case '"': + case '\'': + quote = *t; + break; + case '(': + quote = ')'; + break; + case '[': + quote = ']'; + break; + } + /* bump past opening quote char */ + t++; u++; v++; + while( *t && (*t != quote) ){ + t++; v++; + } + if( *t == quote ){ + t++; + } + } + else{ + qlev = 0; + while( *t && + ((qlev != 0) || (*t != ',')) && + ((qlev != 0) || (*t != ']')) ){ + if( *t == '[' ) + qlev++; + else if( *t == ']' ) + qlev--; + t++; v++; + } + } + len = MIN(maxlen, v - u); + strncpy(obuf, u, len); + obuf[len] = '\0'; + /* remove keyword=value string from the original buffer */ + /* first remove preceding comma, if necessary */ + if( (s > ibuf) && (*(s-1) == ',') ) + s--; + /* but leave 1 comma in place */ + else if( *t == ',' ) + t++; + /* now overwrite original from where the keyword started */ + memmove(s, t, strlen(t)+1); + return(len); + } + } + /* start next search just past this one */ + iptr = s+1; + } + return(0); +} + +/* + *---------------------------------------------------------------------------- + * + * Routine: macro + * + * Purpose: expand a macro using a client's callback + * + * Returns: expanded macro as an allocated string + * + *---------------------------------------------------------------------------- + */ +#ifdef ANSI_FUNC +char * +macro (char *icmd, char **keyword, char **value, int nkey, + MacroCB client_callback, void *client_data) +#else +char *macro(icmd, keyword, value, nkey, client_callback, client_data) + char *icmd; + char **keyword; + char **value; + int nkey; + MacroCB client_callback; + void *client_data; +#endif +{ + int i, j; + int maxlen; + char brace; + char *result; + char tbuf[1000]; + char tbuf1[1000]; + char *s; + char *ip; + char *mip; + + /* make a new string using the command as a base, but substituting + for "$" values as needed */ + result = (char *)xmalloc(BUFINC+1); + maxlen = BUFINC; + *result = '\0'; + for(i=0, ip=icmd; *ip; ip++){ + if( *ip != '$' ){ + addchar(&result, &i, &maxlen, *ip); + } + else{ + /* save beginning of macro */ + mip = ip; + /* skip past '$' */ + ip++; + /* check for brace mode */ + if( *ip == '{' ){ + brace = '{'; + ip++; + } + else if( *ip == '(' ){ + brace = '('; + ip++; + } + else + brace = '\0'; + /* get variable up to next non-alpha character or close brace */ + for(*tbuf='\0', j=0; *ip; ip++ ){ + /* if we are in brace mode, look for trailing brace */ + if( brace && *ip == (brace == '(' ? ')' : '}') ){ + ip++; + break; + } + /* else look for a non-alpha character */ + else if( !isalnum((int)*ip) && *ip != '_'){ + break; + } + else{ + tbuf[j++] = *ip; + tbuf[j] = '\0'; + } + } + /* back up so the outer loop adds this delimiting char to the output */ + ip--; + /* search for keyword from the list */ + if( (nkey > 0) && + (s=lookupkeywords(tbuf, keyword, value, nkey)) != NULL ){ + addstring(&result, &i, &maxlen, s); + } + /* execute the client routine to expand macros */ + else if( (client_callback != NULL) && + ((s=(*client_callback)(tbuf, client_data)) != NULL) ){ + addstring(&result, &i, &maxlen, s); + } + /* look for an environment variable */ + else if( (s = (char *)getenv(tbuf)) != NULL ){ + addstring(&result, &i, &maxlen, s); + } + /* if we don't recognize this macro, put it back onto the string */ + else{ + int len; + len = ip - mip + 1; + strncpy(tbuf1, mip, len); + tbuf1[len] = '\0'; + addstring(&result, &i, &maxlen, tbuf1); + } + } + } + /* null terminate and save the string */ + result[i] = '\0'; + result = (char *)xrealloc(result, i+1); + return(result); +} + +/* ************************************************************************** + * + * misc word routines + * + * **************************************************************************/ + +/* + *---------------------------------------------------------------------------- + * + * Routine: cluc + * + * Purpose: convert lower to upper case string in place + * + * Returns: none + * + *---------------------------------------------------------------------------- + */ +#ifdef ANSI_FUNC +void +cluc (char *s) +#else +void cluc(s) + char *s; +#endif +{ + while(*s){ + if( islower((int)*s) ) + *s = toupper(*s); + s++; + } +} + +/* + *---------------------------------------------------------------------------- + * + * Routine: culc + * + * Purpose: convert upper to lower case string in place + * + * Returns: + * + *---------------------------------------------------------------------------- + */ +#ifdef ANSI_FUNC +void +culc (char *s) +#else +void culc(s) + char *s; +#endif +{ + while(*s){ + if( isupper((int)*s) ) + *s = tolower(*s); + s++; + } +} + +/* + *---------------------------------------------------------------------------- + * + * Routine: nowhite + * + * Purpose: removes all beginning and ending white space from string + * + * Returns: returns the number of characters + * + *---------------------------------------------------------------------------- + */ +#ifdef ANSI_FUNC +int +nowhite ( + char *c, /* buffer to be cleaned */ + char *cr /* buffer for returned string */ +) +#else +int nowhite(c,cr) +char *c; /* buffer to be cleaned */ +char *cr; /* buffer for returned string */ +#endif +{ + char *cr0; /* initial value of cr */ + int n; /* the number of characters */ + + /* skip leading white space */ + while(*c && isspace((int)*c)) + c++; + /* copy up to the null */ + cr0 = cr; + while(*c) + *cr++ = *c++; + n = cr - cr0; /* the number of characters */ + *cr-- = '\0'; /* Null and point to the last character */ + /* remove trailing white space */ + while( n && isspace((int)*cr) ){ + *cr-- = '\0'; + n--; + } + return(n); +} + +/* + *---------------------------------------------------------------------------- + * + * Routine: nocr + * + * Purpose: remove trailing <CR> from a string (in place) + * + * Returns: none + * + *---------------------------------------------------------------------------- + */ +#ifdef ANSI_FUNC +void +nocr (char *s) +#else +void nocr(s) + char *s; +#endif +{ + int len; + + if( (s==NULL) || (*s=='\0') ) + return; + len = strlen(s); + if( s[len-1] == '\n' ) + s[len-1] = '\0'; +} + +/* + *---------------------------------------------------------------------------- + * + * Routine: istrue + * + * Purpose: check if a string is "true" or "yes" or "on" + * + * Returns: 1 if true string, 0 otherwise + * + *---------------------------------------------------------------------------- + */ +#ifdef ANSI_FUNC +int +istrue (char *s) +#else +int istrue(s) + char *s; +#endif +{ + char *t; + int result; + + if( (s==NULL) || (*s=='\0') ) + return(0); + t = (char *)xmalloc(strlen(s)+1); + nowhite(s, t); + culc(t); + result = (!strcmp(t, "true") || !strcmp(t, "yes") || + !strcmp(t, "on") || !strcmp(t, "1") ); + xfree(t); + return(result); +} + + +/* + *---------------------------------------------------------------------------- + * + * Routine: isfalse + * + * Purpose: check if a string is "false" or "no" or "off" + * + * Returns: 1 if false string, 0 otherwise + * + *---------------------------------------------------------------------------- + */ +#ifdef ANSI_FUNC +int +isfalse (char *s) +#else +int isfalse(s) + char *s; +#endif +{ + char *t; + int result; + + if( (s==NULL) || (*s=='\0') ) + return(0); + t = (char *)xmalloc(strlen(s)+1); + nowhite(s, t); + culc(t); + result = (!strcmp(t, "false") || !strcmp(t, "no") || + !strcmp(t, "off") || !strcmp(t, "0") ); + xfree(t); + return(result); +} + + +/* + *---------------------------------------------------------------------------- + * + * Routine: strtoul16 + * + * Purpose: convert a string to an unsigned long hex value + * + * Returns: converted hex value (end of converted string is in t) + * + *---------------------------------------------------------------------------- + */ +#ifdef ANSI_FUNC +unsigned long strtoul16 (char *s, char **t) +#else +unsigned long strtoul16(s, t) + char *s; + char **t; +#endif +{ + unsigned long v=0; + int h; + + while ( *s != ' ' && + *s != '\n' && + *s != '\r' && + *s != '\0' ){ + v *= 16; + if( (h = hexval(*s)) >= 0 ){ + v += h; + s++; + } + else{ + break; + } + } + if( t != NULL ) + *t = s; + return(v); +} diff --git a/xpa/word.h b/xpa/word.h new file mode 100644 index 0000000..5778574 --- /dev/null +++ b/xpa/word.h @@ -0,0 +1,59 @@ +/* + * Copyright (c) 1999-2003 Smithsonian Astrophysical Observatory + */ + +/* + * + * word.h -- declarations for word parsing + * + */ + +#ifndef __word_h +#define __word_h + +#if HAVE_CONFIG_H +#include <conf.h> +#endif +#ifdef HAVE_STRING_H +#include <string.h> +#endif +#if HAVE_MALLOC_H +#include <malloc.h> +#endif +#if HAVE_STDLIB_H +#include <stdlib.h> +#endif +#include <prsetup.h> +#include <xalloc.h> + +/* defines the types of callback procedure we use */ +typedef char *(*MacroCB)( +#ifdef ANSI_FUNC + char *buf, + void *client_data +#endif +); + +_PRbeg + +int word _PRx((char *lbuf, char *tbuf, int *lptr)); +int newdtable _PRx((char *s)); +int freedtable _PRx((void)); +void newdelim _PRx((char *s)); +void freedelim _PRx((char *s)); +int lastdelim _PRx((void)); +int tmatch _PRx((char *string, char *xtemplate)); +int keyword _PRx((char *ibuf, char *key, char *obuf, int maxlen)); +char *macro _PRx((char *icmd, char **keyword, char **value, int nkey, + MacroCB client_callback, void *client_data)); +void cluc _PRx((char *s)); +void culc _PRx((char *s)); +int nowhite _PRx((char *c, char *cr)); +void nocr _PRx((char *s)); +int istrue _PRx((char *s)); +int isfalse _PRx((char *s)); +unsigned long strtoul16 _PRx((char *s, char **t)); + +_PRend + +#endif diff --git a/xpa/xalloc.c b/xpa/xalloc.c new file mode 100644 index 0000000..18234db --- /dev/null +++ b/xpa/xalloc.c @@ -0,0 +1,117 @@ +/* + * Copyright (c) 2004-2009 Smithsonian Astrophysical Observatory + */ + +/* + * + * xalloc -- safe memory allocation with error checking + * + */ + +/* this module is compiled within a funtools filter and must not require + the header files */ +#ifdef FILTER_PTYPE +#define ANSI_FUNC 1 +#else +#include <xalloc.h> +#endif + +#define XALLOC_ERROR "ERROR: can't allocate memory (xalloc)\n" + +#if XALLOC_SETJMP + +static jmp_buf *xalloc_envptr=NULL; + +#ifdef ANSI_FUNC +void xalloc_savejmp(jmp_buf *env) +#else +void xalloc_savejmp(env) + jmp_buf *env; +#endif +{ + xalloc_envptr = env; +} +#endif + + +#ifdef ANSI_FUNC +static void _xalloc_error(void) +#else +static void _xalloc_error() +#endif +{ + write(1, XALLOC_ERROR, strlen(XALLOC_ERROR)); +#if XALLOC_SETJMP + if( xalloc_envptr ) + longjmp(*xalloc_envptr, XALLOC_SETJMP); + else +#endif + exit(1); +} + +#ifdef ANSI_FUNC +void *xmalloc(size_t n) +#else +void *xmalloc(n) + size_t n; +#endif +{ + void *p; + + if( !(p = (void *)malloc(n)) ) + _xalloc_error(); + return p; +} + +#ifdef ANSI_FUNC +void *xcalloc (size_t n, size_t s) +#else +void *xcalloc (n, s) + size_t n, s; +#endif +{ + void *p; + + if( !(p = (void *)calloc(n, s)) ) + _xalloc_error(); + return p; +} + +#ifdef ANSI_FUNC +void *xrealloc (void *p, size_t n) +#else +void *xrealloc (p, n) + void *p; + size_t n; +#endif +{ + if( !p ) + return xmalloc(n); + if( !(p = (void *)realloc(p, n)) ) + _xalloc_error(); + return p; +} + +#ifdef ANSI_FUNC +void xfree (void *p) +#else +void xfree (p) + void *p; +#endif +{ + if( p ) + free(p); +} + +#ifdef ANSI_FUNC +char *xstrdup (char *s) +#else +char *xstrdup (s) + char *s; +#endif +{ + if( s ) + return((char *)strcpy((char *)xmalloc((size_t)strlen(s)+1), s)); + else + return NULL; +} diff --git a/xpa/xalloc.h b/xpa/xalloc.h new file mode 100644 index 0000000..c25fb32 --- /dev/null +++ b/xpa/xalloc.h @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2004 Smithsonian Astrophysical Observatory + */ + +/* + * + * xalloc.h -- declarations for safe (error-checked) memory allocation + * + */ + +#ifndef __xalloc_h +#define __xalloc_h + +#if HAVE_CONFIG_H +#include <conf.h> +#endif + +#include <sys/types.h> +#if HAVE_STRING_H +#include <string.h> +#endif +#if HAVE_MALLOC_H +#include <malloc.h> +#endif +#if HAVE_STDLIB_H +#include <stdlib.h> +#endif +#if HAVE_UNISTD_H +#include <unistd.h> +#endif +#ifdef HAVE_SETJMP_H +#define XALLOC_SETJMP 142857 +#include <setjmp.h> +#endif + +#include <prsetup.h> + +_PRbeg + +void *xmalloc _PRx((size_t n)); +void *xcalloc _PRx((size_t n, size_t s)); +void *xrealloc _PRx((void *p, size_t n)); +void xfree _PRx((void *p)); +char *xstrdup _PRx((char *s)); +#if HAVE_SETJMP_H +void xalloc_savejmp _PRx((jmp_buf *env)); +#endif + +_PRend + +#endif diff --git a/xpa/xlaunch.c b/xpa/xlaunch.c new file mode 100644 index 0000000..9f064d1 --- /dev/null +++ b/xpa/xlaunch.c @@ -0,0 +1,657 @@ +/* + * Copyright (c) 1999-2007 Smithsonian Astrophysical Observatory + */ + +#include <xlaunch.h> + +/* + *---------------------------------------------------------------------------- + * + * + * Private Routines and Data + * + * + *---------------------------------------------------------------------------- + */ + +static pid_t pid=0; + +#if HAVE_MINGW32==0 + +/* wait for child process to start, using waitpid() */ +#ifdef ANSI_FUNC +static int launch_pipes(int *pipes, int flag) +#else +static int launch_pipes(pipes, flag) + int *pipes; + int flag; +#endif +{ + int i; + char tbuf[SZ_LINE]; + if( pipes ){ + for(i=0; i<4; i++){ + pipes[i] = -1; + } + if( (pipe(&pipes[0]) < 0) || (pipe(&pipes[2]) < 0) ) return -1; + if( flag ){ +#if HAVE_SETENV + snprintf(tbuf, SZ_LINE-1, "%d,%d,%d,%d", + pipes[0], pipes[1], pipes[2], pipes[3]); + setenv("LAUNCH_PIPES", tbuf, 1); +#else + snprintf(tbuf, SZ_LINE-1, "LAUNCH_PIPES=%d,%d,%d,%d", + pipes[0], pipes[1], pipes[2], pipes[3]); + putenv(xstrdup(tbuf)); +#endif + } + } + return 0; +} + +#ifdef ANSI_FUNC +static int cleanup_pipes(int *pipes) +#else +static int cleanup_pipes(pipes) + int *pipes; +#endif +{ + if( pipes ){ + /* close child pipes */ + close(pipes[1]); + close(pipes[2]); + /* move parent write into slot 1 */ + pipes[1] = pipes[3]; + /* set unused pipes to impossible value */ + pipes[2] = -1; + pipes[3] = -1; + } + return 0; +} + +#if LAUNCH_USE_WAITPID +/* wait for child process to start, using waitpid() */ +#ifdef ANSI_FUNC +static int launch_waitstart(pid_t pid) +#else +static int launch_waitstart(pid) + pid_t pid; +#endif +{ + int i, got; + int status=0; + struct timeval tv; + /* wait up to LAUNCH_WAIT_TRIES millisec to make sure the child started, + but if we get an error, we can exit immediately */ + for(i=0; i<LAUNCH_WAIT_TRIES; i++){ + errno = 0; + got=waitpid(pid, &status, WNOHANG); + /* look for error termination */ + if( (got < 0) || ((got == 0) && xerrno) ){ + got = -1; + /* make sure status shows error */ + if( status == 0 ) + status = -1; + break; + } + /* look for normal termination */ + else if( got > 0 ){ + break; + } + /* no termination, sleep and wait some more */ + else{ + tv.tv_sec = 0; + tv.tv_usec = LAUNCH_WAIT_MSEC; + xselect(1, NULL, NULL, NULL, &tv); + } + } + /* no termination means the child is still running */ + if( got == 0 ) status = 0; + /* return the news */ + return status; +} +#endif + +/* + * standard unix version of launch: + * adapted from the system() code in: + * W. Richard Stevens + * "Advanced Programming in the Unix Environment" + * Addison-Wesley Publishing Co, 1992 + * p. 314 + */ +#ifdef ANSI_FUNC +static int launch_fork_exec(char *cmdstring, int attach, + char **stdfiles, int *pipes) +#else + static int launch_fork_exec(cmdstring, attach, stdfiles, pipes) + char *cmdstring; + int attach; + char **stdfiles; + int *pipes; +#endif +{ + int status; + int tpipes[4]; + struct sigaction ignore, saveintr, savequit; + sigset_t chldmask, savemask; +#if LAUNCH_USE_PIPE + int fd[2]; +#endif + + /* return false if no command is specified */ + if( !cmdstring || !*cmdstring ) return -1; + + ignore.sa_handler = SIG_IGN; /* ignore SIGINT and SIGQUIT */ + sigemptyset(&ignore.sa_mask); + ignore.sa_flags = 0; + if (sigaction(SIGINT, &ignore, &saveintr) < 0) + return -1; + if (sigaction(SIGQUIT, &ignore, &savequit) < 0) + return -1; + + sigemptyset(&chldmask); /* now block SIGCHLD */ + sigaddset(&chldmask, SIGCHLD); + if (sigprocmask(SIG_BLOCK, &chldmask, &savemask) < 0) + return -1; + +#if LAUNCH_USE_PIPE + /* open a pipe so parent can hear if the child fails to exec */ + if( !attach ){ + if( pipe(fd) < 0 ) + return -1; + xfcntl(fd[0], F_SETFD, FD_CLOEXEC); + xfcntl(fd[1], F_SETFD, FD_CLOEXEC); + } +#endif + + /* create temp ipc pipes if necessary */ + if( pipes ){ + if( launch_pipes(tpipes, 0) < 0 ) return -1; + } + + /* start new process */ + if( (pid = fork()) < 0 ){ +#if LAUNCH_USE_PIPE + if( !attach ){ + close(fd[0]); + close(fd[1]); + } +#endif + if( pipes ){ + close(tpipes[0]); + close(tpipes[1]); + close(tpipes[2]); + close(tpipes[3]); + } + status = -1; /* ERROR: probably out of processes */ + } else if( pid == 0 ){ /* child */ + int i, j, len; + char *argv[LAUNCH_ARGS+1]; + char *path=NULL; + char *s=NULL, *t=NULL; + + /* reset pipes, if necessary */ + if( pipes ){ + /* close parent's read/write pipes */ + close(tpipes[0]); + close(tpipes[3]); + /* change child's stdin/stdout to use the passed pipes to parent */ + dup2(tpipes[2], 0); close(tpipes[2]); + dup2(tpipes[1], 1); close(tpipes[1]); + } + + /* close and reopen stdio files, if necessary */ + if( stdfiles ){ + for(i=0; i<3; i++){ + if( stdfiles[i] ){ + close(i); + switch(i){ + case 0: + if( open(stdfiles[i], O_RDONLY) < 0){ + _exit(-1); + } + break; + case 1: + if( open(stdfiles[i], O_CREAT|O_WRONLY|O_TRUNC, 0600) < 0){ + _exit(-1); + } + break; + case 2: + /* if stderr is the same as stdout, just dup */ + if( stdfiles[1] && !strcmp(stdfiles[1], stdfiles[i]) ){ + dup(1); + } + else{ + if( open(stdfiles[i], O_CREAT|O_WRONLY|O_TRUNC, 0600) < 0){ + _exit(-1); + } + } + break; + } + } + } + } + + /* restore previous signal actions & reset signal mask, but only if + parent is waiting for completion (i.e., we are "attached") */ + if( attach ){ + sigaction(SIGINT, &saveintr, NULL); + sigaction(SIGQUIT, &savequit, NULL); + sigprocmask(SIG_SETMASK, &savemask, NULL); + } +#if LAUNCH_USE_PIPE + /* child closes reader -- only writes status */ + else{ + close(fd[0]); + } +#endif + + /* package up the arguments for new process */ + t = (char *)xstrdup(cmdstring); + for(i=0, s=(char *)strtok(t, " \t"); s; + i++, s=(char *)strtok(NULL," \t")){ + if( i < LAUNCH_ARGS ){ + /* save argument */ + argv[i] = xstrdup(s); + /* change back special char to spaces, if necessary */ + len = strlen(argv[i]); + for(j=0; j<len; j++){ + if( argv[i][j] == LAUNCH_SPACE){ + argv[i][j] = ' '; + } + } + argv[i+1] = NULL; + /* save program name */ + if( i == 0 ) path = argv[i]; + } + } + if( t ) xfree(t); +#ifndef HAVE_CYGWIN + /* this call is broken in cygwin */ + /* for unattached processes, start a new session (with new process id), + so that we do not inherit signals from parent (particularly SIGTERM) */ + if( !attach ) + setsid(); +#endif + /* start up the new program */ + if( execvp(path, argv) ){ + status = 127; +#if LAUNCH_USE_PIPE + if( !attach ){ + write(fd[1], &status, 4); + close(fd[1]); + } +#endif + _exit(status); /* exec error */ + } + } else { /* parent */ + /* wait for program termination from attached process */ + if( attach ){ + while( waitpid(pid, &status, 0) < 0 ){ + if( xerrno != EINTR ){ + status = -1; /* error other than EINTR from waitpid() */ + break; + } + } + } + else{ +#if LAUNCH_USE_WAITPID + status = launch_waitstart(pid); +#endif +#if LAUNCH_USE_PIPE + close(fd[1]); + if( read(fd[0], &status, 4) == 0 ){ + status = 0; + } + close(fd[0]); +#endif + } + } + + /* cleanup temp ipc pipes and move into user space */ + if( pipes ){ + cleanup_pipes(tpipes); + pipes[0] = tpipes[0]; + pipes[1] = tpipes[1]; + } + + /* restore previous signal actions & reset signal mask */ + if( sigaction(SIGINT, &saveintr, NULL) < 0 ) return -1; + if( sigaction(SIGQUIT, &savequit, NULL) < 0 ) return -1; + if( sigprocmask(SIG_SETMASK, &savemask, NULL) < 0 ) return -1; + + /* return the news */ + return status; +} + +#endif + +#if HAVE_POSIX_SPAWN + +#if defined(HAVE__NSGETENVIRON) && defined(HAVE_CRT_EXTERNS_H) +#include <crt_externs.h> +#define environ (*_NSGetEnviron()) +#else +extern char **environ; +#endif + +/* spawn calls POSIX posix_spawn */ +#ifdef ANSI_FUNC +static int launch_posix_spawn(char *cmdstring, int attach, + char **stdfiles, int *pipes) +#else + static int launch_posix_spawn(cmdstring, attach, stdfiles, pipes) + char *cmdstring; + int attach; + char **stdfiles; + int *pipes; +#endif +{ + int i, j, len; + int status=0; + int got=0; + int tpipes[4]; + char *argv[LAUNCH_ARGS+1]; + char *path=NULL; + char *s=NULL, *t=NULL; + posix_spawn_file_actions_t act; + posix_spawn_file_actions_t *pact=NULL; + + /* return false if no command is specified */ + if( !cmdstring || !*cmdstring ) + return -1; + + /* create temp ipc pipes if necessary */ + if( pipes ){ + if( launch_pipes(tpipes, 1) < 0 ) return -1; + } + + /* package up the arguments for new process */ + t = (char *)xstrdup(cmdstring); + for(i=0, s=(char *)strtok(t, " \t"); s; + i++, s=(char *)strtok(NULL," \t")){ + if( i < LAUNCH_ARGS ){ + /* save argument */ + argv[i] = xstrdup(s); + /* change back special char to spaces, if necessary */ + len = strlen(argv[i]); + for(j=0; j<len; j++){ + if( argv[i][j] == LAUNCH_SPACE){ + argv[i][j] = ' '; + } + } + /* last arg is always a NULL */ + argv[i+1] = NULL; + /* save program name */ + if( i == 0 ) path = argv[i]; + /* inc arg count */ + got++; + } + } + if( t ) xfree(t); + /* arrange stdfiles files, if necessary */ + if( stdfiles ){ + if( posix_spawn_file_actions_init(&act) != 0) + return -1; + /* stdin */ + if(stdfiles[0] && + posix_spawn_file_actions_addopen(&act, 0, stdfiles[0], O_RDONLY, 0)) + return -1; + /* stdout */ + if(stdfiles[1] && + posix_spawn_file_actions_addopen(&act, 1, stdfiles[1], O_CREAT|O_WRONLY|O_TRUNC, 0600)) + return -1; + /* stderr */ + if(stdfiles[2] && + posix_spawn_file_actions_addopen(&act, 2, stdfiles[2], O_CREAT|O_WRONLY|O_TRUNC, 0600)) + return -1; + pact = &act; + } + /* start the new process */ + if( (status = posix_spawnp(&pid, path, pact, NULL, argv, environ)) ) + return status; + /* wait for program termination from attached process */ + if( attach ){ + while( waitpid(pid, &status, 0) < 0 ){ + if( xerrno != EINTR ){ + status = -1; /* error other than EINTR from waitpid() */ + break; + } + } + } +#if BIG_DELAY_WHEN_USING_THIS + /* wait for child process to start */ + else{ + status = launch_waitstart(pid); + } +#endif + /* clean up */ + if( stdfiles ) posix_spawn_file_actions_destroy(&act); + /* cleanup temp ipc pipes and move into user space */ + if( pipes ){ + cleanup_pipes(tpipes); + pipes[0] = tpipes[0]; + pipes[1] = tpipes[1]; + } + for(i=0; i<got; i++){ + if( argv[i] ) xfree((char *)argv[i]); + } + /* return status */ + return status; +} + +#endif + +#if HAVE_SPAWNVP + +#ifdef ANSI_FUNC +static int launch_spawnvp(char *cmdstring, int attach, + char **stdfiles, int *pipes) +#else + static int launch_spawnvp(cmdstring, attach, stdfiles, pipes) + char *cmdstring; + int attach; + char **stdfiles; + int *pipes; +#endif +{ + int i, j; + int len; + int got; + int status; + int tpipes[4]; + char *argv[LAUNCH_ARGS+1]; + char *path=NULL; + char *s=NULL, *t=NULL; + struct timeval tv; + + /* return false if no command is specified */ + if( !cmdstring || !*cmdstring ) return -1; + + /* for now, we can't support stdfiles */ + if( stdfiles ) return -1; + + /* create temp ipc pipes if necessary */ + if( pipes ){ +#if HAVE_MINGW32==0 + if( launch_pipes(tpipes, 1) < 0 ) return -1; +#else + fprintf(stderr, "ERROR: launch_pipes() not available in mingw\n"); + exit(1); +#endif + } + + + /* package up the arguments for new process */ + t = (char *)xstrdup(cmdstring); + for(i=0, got=0, s=(char *)strtok(t, " \t"); s; + i++, s=(char *)strtok(NULL," \t")){ + if( i < LAUNCH_ARGS ){ + /* save argument */ + argv[i] = xstrdup(s); + /* change back special char to spaces, if necessary */ + len = strlen(argv[i]); + for(j=0; j<len; j++){ + if( argv[i][j] == LAUNCH_SPACE){ + argv[i][j] = ' '; + } + } + /* last arg is always a NULL */ + argv[i+1] = NULL; + /* save program name */ + if( i == 0 ) path = (char *)argv[i]; + /* inc arg count */ + got++; + } + } + if( t ) xfree(t); + if( attach ) + i = _P_WAIT; + else + i = _P_NOWAIT; + if((status = spawnvp(i, path, (void *)argv)) != -1){ + status = 0; + /* wait for child to start */ + tv.tv_sec = 0; + tv.tv_usec = LAUNCH_WAIT_MSEC; + xselect(1, NULL, NULL, NULL, &tv); + } + /* clean up */ + for(i=0; i<got; i++){ + if( argv[i] ) xfree((char *)argv[i]); + } + /* cleanup temp ipc pipes and move into user space */ + if( pipes ){ +#if HAVE_MINGW32==0 + cleanup_pipes(tpipes); + pipes[0] = tpipes[0]; + pipes[1] = tpipes[1]; +#else + fprintf(stderr, "ERROR: launch_pipes() not available in mingw\n"); + exit(1); +#endif + } + return status; +} + +#endif + +/* + *---------------------------------------------------------------------------- + * + * + * Public Routines and Data + * + * + *---------------------------------------------------------------------------- + */ + +/* + * + * LaunchPid() -- return pid of last launched process + * + */ +#ifdef ANSI_FUNC +pid_t LaunchPid(void) +#else +pid_t LaunchPid() +#endif +{ + return pid; +} + +#ifdef ANSI_FUNC +int Launch(char *cmdstring, int attach, char **stdfiles, int *pipes) +#else +int Launch(cmdstring, attach, stdfiles, piles) + char *cmdstring; + int attach; + char **stdfiles; + int *pipes; +#endif +{ + static int which_launch=0; + static int which_debug=0; + char *s=NULL; + + /* return false if no command is specified */ + if( !cmdstring || !*cmdstring ) return -1; + + /* sanity check: don't specify stdfiles and pipes simultaneously */ + if( stdfiles && pipes ){ + fprintf(stderr, + "ERROR: stdfiles and pipes are mutually exclusive in Launch()\n"); + return -1; + } + + /* if pipes are specified, we don't attach */ + if( pipes ) attach = 0; + + /* determine launch method */ + if( !which_launch ){ + which_launch = LAUNCH_DEFAULT_WHICH; + if( (s=getenv("LAUNCH_ROUTINE")) ){ + /* fork_exec */ + if( !strncasecmp(s, "f", 1) ){ + which_launch = 1; + if( *s == 'F' ) which_debug = 1; + } + /* posix_spawn */ + else if( !strncasecmp(s, "p", 1) ){ + which_launch = 2; + if( *s == 'P' ) which_debug = 1; + } + /* spawnvp */ + else if( !strncasecmp(s, "s", 1) ){ + which_launch = 3; + if( *s == 'S' ) which_debug = 1; + } + else if( *s == 'V' ) { + which_debug = 1; + } + } + } + /* call the correct launch method */ + switch(which_launch){ + case 1: +#if HAVE_MINGW32==0 + if( which_debug ) fprintf(stderr, "launch_fork_exec: %s\n", cmdstring); + return launch_fork_exec(cmdstring, attach, stdfiles, pipes); +#else + fprintf(stderr, "ERROR: fork_exec() not available on this host\n"); + exit(1); +#endif + break; + case 2: +#if HAVE_POSIX_SPAWN + if( which_debug ) fprintf(stderr, "launch_posix_spawn: %s\n", cmdstring); + return launch_posix_spawn(cmdstring, attach, stdfiles, pipes); +#else + fprintf(stderr, "ERROR: posix_spawn() not available on this host\n"); + exit(1); +#endif + break; + case 3: +#if HAVE_SPAWNVP + if( which_debug ) fprintf(stderr, "launch_spawnvp: %s\n", cmdstring); + return launch_spawnvp(cmdstring, attach, stdfiles, pipes); +#else + fprintf(stderr, "ERROR: spawnvp() not available on this host\n"); + exit(1); +#endif + break; + default: +#if HAVE_MINGW32==0 + if( which_debug ) fprintf(stderr, "launch_fork_exec: %s\n", cmdstring); + return launch_fork_exec(cmdstring, attach, stdfiles, pipes); +#else + fprintf(stderr, "ERROR: no launch techniques available on this host\n"); + exit(1); +#endif + break; + } + /* can't happen */ + return -1; +} + diff --git a/xpa/xlaunch.h b/xpa/xlaunch.h new file mode 100644 index 0000000..2c20cb8 --- /dev/null +++ b/xpa/xlaunch.h @@ -0,0 +1,87 @@ +/* + * Copyright (c) 1999-2003 Smithsonian Astrophysical Observatory + */ + +/* + * + * xlaunch.h -- declarations for launching a program + * + */ + +#ifndef __xlaunch_h +#define __xlaunch_h + +#if HAVE_CONFIG_H +#include <conf.h> +#endif + +#include <stdio.h> +#include <errno.h> +#include <signal.h> +#include <fcntl.h> +#include <sys/time.h> +#include <sys/stat.h> +#if HAVE_STRING_H +#include <string.h> +#endif +#if HAVE_STRINGS_H +#include <strings.h> +#endif +#if HAVE_MALLOC_H +#include <malloc.h> +#endif +#if HAVE_UNISTD_H +#include <unistd.h> +#endif +#if HAVE_POSIX_SPAWN +#include <spawn.h> +#endif +#include <xport.h> +#include <word.h> +#include <xalloc.h> +#include <prsetup.h> + +#define LAUNCH_ARGS 1024 + +#define LAUNCH_SPACE '\001' + +/* for fork/exec, one of these is required to specify the technique to be used + by the parent when determining if the child started successfully */ +#if !defined(LAUNCH_USE_PIPE) && !defined(LAUNCH_USE_WAITPID) +#define LAUNCH_USE_PIPE 1 +#endif +/* ... but not both */ +#if defined(LAUNCH_USE_PIPE) && defined(LAUNCH_USE_WAITPID) +#error "LAUNCH_USE_PIPE and LAUNCH_USE_WAITPID are mutually exclusive" +#endif + +#ifndef LAUNCH_WAIT_TRIES +#define LAUNCH_WAIT_TRIES 100 +#endif +#ifndef LAUNCH_WAIT_MSEC +#define LAUNCH_WAIT_MSEC 5000 +#endif + +#if HAVE_MINGW32|HAVE_CYGWIN +#define HAVE_SPAWNVP 1 +#endif + +#if HAVE_MINGW32 +/* for now, ensure that MinGW utilizes spawnvp() */ +#define LAUNCH_DEFAULT_WHICH 3 +#elif HAVE_POSIX_SPAWN +/* use posix_spawn if possible (required for OS X 10.5) */ +#define LAUNCH_DEFAULT_WHICH 2 +#else +/* use our home-grown version */ +#define LAUNCH_DEFAULT_WHICH 1 +#endif + +_PRbeg + +int Launch _PRx((char *cmdstring, int wait, char **stdfiles, int *pipes)); +pid_t LaunchPid _PRx((void)); + +_PRend + +#endif diff --git a/xpa/xpa.c b/xpa/xpa.c new file mode 100644 index 0000000..2454d64 --- /dev/null +++ b/xpa/xpa.c @@ -0,0 +1,4712 @@ +/* + * Copyright (c) 1999-2003 Smithsonian Astrophysical Observatory + */ + +#include <xpap.h> + +/* + *---------------------------------------------------------------------------- + * + * + * Private Routines and Data + * + * + *---------------------------------------------------------------------------- + */ + +/* this is the head of the global list -- too lazy to do anything more */ +static XPA xpahead=NULL; + +/* globals for the xpa environment, controlled by environment variables */ +static int stimeout=XPA_SHORT_TIMEOUT; /* select, gets timeout in secs */ +static int ltimeout=XPA_LONG_TIMEOUT; /* fillbuf timeout in secs */ +static int ctimeout=XPA_CONNECT_TIMEOUT;/* local xpans connect */ +static int verbosity=XPA_VERBOSITY; /* 0=quiet, 1=normal, 2=full */ +static int guseacl=1; /* 0=don't use acls, 1=enable acls */ +static int etimestamp=0; /* 0=don't timestamp errors, 1=do timestamp */ +static int nsregister=1; /* 0=don't register with xpans, 1=register */ +static int sigusr1=1; /* 0=don't use sigusr1, 1=enable sigusr1 */ +static int vercheck=1; /* 0=don't check version, 1=check version */ +static char *tmpdir=NULL; /* temporary dir for logs. etc. */ +#if HAVE_ATEXIT +static int atexitinit=0; /* whether atexit has been registered */ +#endif + +/* variables used by all XPAs in this process */ +static char activefds[FD_SETSIZE]; +static char nsmethod[SZ_LINE]; +static char nsusers[SZ_LINE]; + +/* global method type: unix or inet */ +static int mtype=0; + +/* width of select channel flag */ +static int swidth=FD_SETSIZE; + +/* defined in tcp.c */ +extern int use_localhost; + +/* erro code strings -- must match the error codes in xpap.h */ +char *xpaMessbuf[] = { + "oh, what a mess we've made!", + "authentication failed", + "xpa connection refused", + "can't resolve host name for xpa", + "can't read initialization info for xpa", + "invalid xpa command in initialization string", + "no receive function defined for this xpa", + "no send function defined for this xpa", + "no info function defined for this xpa", + "undefined command for this xpa", + "missing command for this xpa", + "name does not match target template", + "can't create data channel socket", + "could not read data buf (possible timeout)", + "illegal command or command switch" +}; + +/* temp static time buffer */ +static char ctimebuf[SZ_LINE]; + +/* + *---------------------------------------------------------------------------- + * + * Routine: XPAProxyConnect + * + * Purpose: connect to a client (in proxy mode) + * + * Returns: 0 if successfull, otherwise -1 + * + *---------------------------------------------------------------------------- + */ + +#ifdef ANSI_FUNC +static int +XPAProxyConnect(XPA xpa, char *method, + unsigned int *rip, unsigned short *rport, char *rname) +#else +static int XPAProxyConnect(xpa, method, rip, rport, rname) + XPA xpa; + char *method; + unsigned int *rip; + unsigned short *rport; + char *rname; +#endif +{ + int ofd; + int tries=0; + int keep_alive=1; + unsigned int ip; + unsigned short port; + struct sockaddr_in sock_in; +#if HAVE_SYS_UN_H + struct sockaddr_un sock_un; +#endif + + FPRINTF((stderr, "%sXPAProxyConnect to %s\n", _sp, method)); + /* initialize results */ + if( rip ) *rip = 0; + if( rport ) *rport = 0; + if( rname ) *rname = '\0'; + + switch(XPAMethod(method)){ + case XPA_INET: +again1: + if( !XPAParseIpPort(method, &ip, &port) ){ + goto error; + } + /* use $localhost over $host (we don't trust host to be correct) */ + if( (ip == gethostip("$host")) && (tries == 0) ){ + ip = gethostip("$localhost"); + } + /* connect to the server before we go further */ + if( (ofd = xsocket(AF_INET, SOCK_STREAM, 0)) < 0 ){ + PERROR(("XPAProxyConnect: socket()")); + goto error; + } + setsockopt(ofd, SOL_SOCKET, SO_KEEPALIVE, + (char *)&keep_alive, sizeof(keep_alive)); + memset((char *)&sock_in, 0, sizeof(sock_in)); + sock_in.sin_family = AF_INET; + sock_in.sin_addr.s_addr = htonl(ip); + sock_in.sin_port = htons(port); + /* make the connection with the server */ + if(connect(ofd, (struct sockaddr *)&sock_in, sizeof(sock_in))<0){ + xclose(ofd); + /* if localhost doesn't work, make one try with the host ip */ + /* we also try again just in case there was an odd error such + as "permission denied", which we have seen once or twice */ + if( tries < 2 ){ + tries++; + goto again1; + } + /* give up */ + else{ + PERROR(("XPAProxyConnect: connect()")); + goto error; + } + } + break; +#if HAVE_SYS_UN_H + case XPA_UNIX: +again2: + ip = 0; + port = 0; + /* open a socket and fill in socket information */ + if( (ofd = xsocket(AF_UNIX, SOCK_STREAM, 0)) < 0 ){ + goto error; + } + setsockopt(ofd, SOL_SOCKET, SO_KEEPALIVE, + (char *)&keep_alive, sizeof(keep_alive)); + memset((char *)&sock_un, 0, sizeof(sock_un)); + sock_un.sun_family = AF_UNIX; + strcpy(sock_un.sun_path, method); + /* make the connection with the server */ + if(connect(ofd, (struct sockaddr *)&sock_un, sizeof(sock_un))<0){ + xclose(ofd); + /* Unix sockets get ECONNREFUSED when the listen queue is full, + so we try a few times to give the server a chance to recover */ + if( (xerrno == ECONNREFUSED) && (tries < XPA_RETRIES) ){ + tries++; + XPASleep(10); + goto again2; + } + /* give up */ + else{ + goto error; + } + } + break; +#endif + default: + goto error; + } + + /* fill in blansk */ + if( rip ) *rip = ip; + if( rport ) *rport = port; + if( rname ){ + strncpy(rname, method, SZ_LINE-1); + rname[SZ_LINE-1] = '\0'; + } + return(ofd); + +error: + return -1; +} + +/* + *---------------------------------------------------------------------------- + * + * Routine: CommNew + * + * Purpose: allocate a new comm record and add to end of list + * + * Returns: allocated comm record + * + *---------------------------------------------------------------------------- + */ + +#ifdef ANSI_FUNC +static XPAComm +CommNew (XPA xpa, int fd, unsigned int ip, int port, char *name, NS ns) +#else +static XPAComm CommNew(xpa, fd, ip, port, name, ns) + XPA xpa; + int fd; + unsigned int ip; + int port; + char *name; + NS ns; +#endif +{ + XPAComm comm, cur; + int i; + socklen_t slen; + struct sockaddr_in sock_in; +#if HAVE_SYS_UN_H + struct sockaddr_un sock_un; +#endif + + /* create the comm struct */ + if( (comm = (XPAComm)xcalloc(1, sizeof(XPACommRec))) == NULL ) + return(NULL); + + /* if fd < 0, we accept a connection to get the fd */ + if( fd < 0 ){ + /* accept the connection */ + switch(mtype){ + case XPA_INET: + while( 1 ){ + slen = sizeof(struct sockaddr_in); + if((comm->cmdfd=xaccept(xpa->fd,(struct sockaddr *)&sock_in,&slen))>=0){ + comm->cmdip = ntohl(sock_in.sin_addr.s_addr); + comm->cmdport = ntohs(sock_in.sin_port); + break; + } + else{ + if( xerrno == EINTR ) + continue; + else{ + xfree(comm); + return(NULL); + } + } + } + break; +#if HAVE_SYS_UN_H + case XPA_UNIX: + while( 1 ){ + slen = sizeof(struct sockaddr_un); + if((comm->cmdfd=xaccept(xpa->fd,(struct sockaddr *)&sock_un,&slen))>=0){ + comm->cmdname = xstrdup(sock_un.sun_path); + break; + } + else{ + if( xerrno == EINTR ) + continue; + else{ + xfree(comm); + return(NULL); + } + } + } + break; +#endif + default: + xfree(comm); + return(NULL); + } + } + /* all info is supplied */ + else{ + switch(mtype){ + case XPA_INET: + comm->cmdip = ip; + comm->cmdport = port; + break; + case XPA_UNIX: + comm->cmdname = xstrdup(name); + break; + } + comm->cmdfd = fd; + /* store name server record */ + comm->ns = ns; + } + + /* set back pointer */ + /* make sure we close on exec */ + xfcntl(comm->cmdfd, F_SETFD, FD_CLOEXEC); + /* mark data socket with impossible value */ + comm->datafd = -1; + /* default is to ack */ + comm->ack = 1; + /* set default cendian flag */ + comm->cendian = "?"; + /* clear the acl flags */ + for(i=0; i<XPA_CMDS+1; i++){ + comm->acl[i] = -1; + } + + /* add this comm to end of list of comms */ + if( xpa->commhead == NULL ){ + xpa->commhead = comm; + } + else{ + for(cur=xpa->commhead; cur->next!=NULL; cur=cur->next){ + ; + } + cur->next = comm; + } + + /* we might have to add this fd specially to a non-select event loop */ + if( xpa->seladd ) + comm->selcptr = (xpa->seladd)(xpa, comm->cmdfd); + + /* make this fd active */ + XPAActive(xpa, comm, 1); + + FPRINTF((stderr, "%sCommNew: ip=%x port=%d fd=%d\n", _sp, + comm->cmdip, comm->cmdport, comm->cmdfd)); + + /* return the good news */ + return(comm); +} + +/* + *---------------------------------------------------------------------------- + * + * Routine: CommFree + * + * Purpose: free a comm record and remove from list + * + * Returns: none + * + *---------------------------------------------------------------------------- + */ +#ifdef ANSI_FUNC +static void +CommFree (XPA xpa, XPAComm comm, int flag) +#else +static void CommFree(xpa, comm, flag) + XPA xpa; + XPAComm comm; + int flag; +#endif +{ + XPAComm cur; + + if( !comm ) + return; + + FPRINTF((stderr, "%sCommFree: ip=%x port=%d fd=%d dfd=%d\n", _sp, + comm->cmdip, comm->cmdport, comm->cmdfd, comm->datafd)); + /* remove from list of this xpa's comms */ + if( xpa ){ + if( xpa->commhead ){ + if( xpa->commhead == comm ){ + xpa->commhead = comm->next; + } + else{ + for(cur=xpa->commhead; cur!=NULL; cur=cur->next){ + if( cur->next == comm ){ + cur->next = comm->next; + break; + } + } + } + } + } + /* must check all xpas */ + else{ + for(xpa=xpahead; xpa!=NULL; xpa=xpa->next){ + if( xpa->commhead ){ + if( xpa->commhead == comm ){ + xpa->commhead = comm->next; + } + else{ + for(cur=xpa->commhead; cur!=NULL; cur=cur->next){ + if( cur->next == comm ){ + cur->next = comm->next; + break; + } + } + } + } + } + } + + /* close socket connections */ + if( flag && (comm->cmdfd >= 0) ){ + FPRINTF((stderr, "%sCommFree closing cmd fd: %d\n", _sp, comm->cmdfd)); + /* remove from active */ + if( comm->cmdfd < FD_SETSIZE ) + activefds[comm->cmdfd] = 0; + /* delete the comm cmd fd specially from a non-select event loop */ + if( xpa && xpa->seldel && comm->selcptr ){ + (xpa->seldel)(comm->selcptr); + comm->selcptr = NULL; + } + /* close file */ + xclose(comm->cmdfd); + } + /* close data channel */ + XPACloseData(xpa, comm); + /* if we have a file name (unix sockets), free it */ + if( comm->cmdname != NULL ){ + unlink(comm->cmdname); + xfree(comm->cmdname); + } + if( comm->dataname != NULL ){ + unlink(comm->dataname); + xfree(comm->dataname); + } + + /* free up the space */ + if( comm->id != NULL ) xfree(comm->id); + if( comm->info != NULL ) xfree(comm->info); + if( comm->target != NULL ) xfree(comm->target); + if( comm->paramlist != NULL ) xfree(comm->paramlist); + + /* this comm is no longer associated with an ns */ + if( comm->ns ){ + comm->ns->nproxy -= 1; + } + + /* disassociate from parent xpa */ + if( xpa ){ + xpa->comm = NULL; + } + + /* free up structure */ + xfree(comm); +} + +/* + *---------------------------------------------------------------------------- + * + * Routine: XPANSOpen + * + * Purpose: open a connection to the name service + * + * Returns: connection fd on success, -1 on failure + * + *---------------------------------------------------------------------------- + */ +#ifdef ANSI_FUNC +static NS +XPANSOpen (XPA xpa, char *host, int force) +#else +static NS XPANSOpen(xpa, host, force) + XPA xpa; + char *host; + int force; +#endif +{ + int i; + int status; + int xnsfd=0; + int keep_alive=1; + int tries=0; + int ip=0; + int dowarn=0; + int contmode=XPA_CONNECT_TIMEOUT_MODE; + unsigned short xnsport=0; + unsigned int xnsip=0; + static int errinit=0; + char *s; + char *path; + char *method; + char nscmd[SZ_LINE]; + char tbuf[SZ_LINE]; + char tbuf2[SZ_LINE]; + struct sockaddr_in sock_in; + struct passwd *pw; +#if HAVE_SYS_UN_H + struct sockaddr_un sock_un; +#endif + char *findname=NULL; + NS ns, cur; + + /* get name server method */ + method = XPANSMethod(host, 0); + + /* if the name service already is open, just return fd */ + if( xpa ){ + for(ns=xpa->nshead; ns!=NULL; ns=ns->next){ + if( !strcmp(ns->method, method) ){ + /* if forcing, see if the connection is valid */ + if( force >= 0 ){ + if( (XPAPuts(xpa, ns->fd, "status\n", stimeout) >0) && + (XPAGets(xpa, ns->fd, tbuf, SZ_LINE, stimeout) >0) && + !strncmp(tbuf, "XPA$OK", 6) ){ + FPRINTF((stderr, "%sXPANSOpen: found existing ns: %s\n", + _sp, ns->method)); + return ns; + } + /* found the ns, but its not open */ + else{ + FPRINTF((stderr, "%sXPANSOpen: existing ns is dead: %s\n", + _sp, ns->method)); + XPANSClose(xpa, ns); + break; + } + } + /* just return whatever we have if we are not forcing */ + else{ + return ns; + } + } + } + } + + /* if no existing ns and flag is negative, we are done */ + if( force == -1 ) + return(NULL); + + /* we always make up the command afresh */ + *nscmd = '\0'; + + /* get users for this user */ + if( (s=(char *)getenv("XPA_NSUSERS")) != NULL ) + strncpy(nsusers, s, SZ_LINE-1); + /* default is just this use's userrname, from the environment */ + else if( (s=(char *)getenv("LOGNAME")) != NULL ) + strncpy(nsusers, s, SZ_LINE-1); +#if HAVE_MINGW32==0 + /* this is a last resort */ + else if( (pw=getpwuid(geteuid())) ) + strncpy(nsusers, pw->pw_name, SZ_LINE-1); +#endif + /* if nothing good has happened, make it "all" */ + if( *nsusers == '\0' ) + strcpy(nsusers, "*"); + /* null-terminate string */ + nsusers[SZ_LINE-1] = '\0'; + + /* set up communications socket for this method */ + switch(mtype){ + case XPA_INET: +again1: + XPAParseIpPort(method, &xnsip, &xnsport); + /* use $localhost over $host (we do not trust host to be correct) */ + if( (xnsip == gethostip("$host")) && (tries == 0) ){ + xnsip = gethostip("$localhost"); + } + if( xnsip == 0 ){ + fprintf(stderr, + "XPA$ERROR: invalid host name specified: %s.\n", method); + return(NULL); + } + if( (xnsfd = xsocket(AF_INET, SOCK_STREAM, 0)) < 0 ) + goto nons; + memset((char *)&sock_in, 0, sizeof(sock_in)); + sock_in.sin_family = AF_INET; + sock_in.sin_addr.s_addr = htonl(xnsip); + sock_in.sin_port = htons(xnsport); + /* try connecting to the name server */ + if( ctimeout <= 0 ) contmode = 0; + switch(contmode){ + case 1: +#if HAVE_MINGW32==0 + status=alrmconnect(xnsfd, (void *)&sock_in, sizeof(sock_in), ctimeout); +#else + status=noblkconnect(xnsfd, (void *)&sock_in, sizeof(sock_in), ctimeout); +#endif + break; + case 2: + status=noblkconnect(xnsfd, (void *)&sock_in, sizeof(sock_in), ctimeout); + break; + default: + status=connect(xnsfd, (struct sockaddr *)&sock_in, sizeof(sock_in)); + break; + } + if( status == 0 ){ + FPRINTF((stderr, "%sXPANSOpen: connect to xpans\n", _sp)); + goto okns; + } + else{ + xclose(xnsfd); + /* if localhost doesn't work, make one try with the host ip */ + if( (xerrno == ECONNREFUSED) && (tries < 1) ){ + tries++; + goto again1; + } + } + break; +#if HAVE_SYS_UN_H + case XPA_UNIX: +again2: + /* open a socket and fill in socket information */ + if( (xnsfd = xsocket(AF_UNIX, SOCK_STREAM, 0)) < 0 ) + goto nons; + memset((char *)&sock_un, 0, sizeof(sock_un)); + sock_un.sun_family = AF_UNIX; + strcpy(sock_un.sun_path, method); + xnsip = 0; + /* try connecting to the name server */ + status=connect(xnsfd, (struct sockaddr *)&sock_un, sizeof(sock_un)); + if( status == 0 ){ + FPRINTF((stderr, "%sXPANSOpen: connect to xpans\n", _sp)); + goto okns; + } + else{ + xclose(xnsfd); + /* Unix sockets get ECONNREFUSED when the listen queue is full, + so we try a few times to give the server a chance to recover */ + if( (xerrno == ECONNREFUSED) && (tries < XPA_RETRIES) ){ + tries++; + XPASleep(10); + goto again2; + } + } + break; +#endif + } + + /* if force is set, we try to start up the name server */ + if( force == 0 ) + goto noforce; + + /* make up the xpans command we will use */ + if( *nscmd == '\0' ){ + if( (mtype == XPA_UNIX) || LOCALIP(xnsip) ){ + path = (char *)getenv("PATH"); + findname = (char *)Find(XPANSNAME, "x", NULL, path); +#if HAVE_CYGWIN + /* this will help start up xpans under Windows */ + if( !findname ) findname = (char *)Find(XPANSNAME, "x", NULL, "."); +#endif + } + if( findname != NULL ){ + switch(mtype){ + case XPA_INET: +#if USE_LAUNCH + /* change spaces to special launch space */ + for(i=0; i<strlen(findname); i++){ + if( findname[i] == ' '){ + findname[i] = LAUNCH_SPACE; + } + } + snprintf(nscmd, SZ_LINE, "%s -e -p %d -l %s/xpans_%d.log", + findname, xnsport, tmpdir, xnsport); +#else + snprintf(nscmd, SZ_LINE, "\"%s\" -e -p %d -l %s/xpans_%d.log &\n", + findname, xnsport, tmpdir, xnsport); +#endif + break; +#if HAVE_SYS_UN_H + case XPA_UNIX: +#if USE_LAUNCH + /* change spaces to special launch space */ + for(i=0; i<strlen(findname); i++){ + if( findname[i] == ' '){ + findname[i] = LAUNCH_SPACE; + } + } + snprintf(nscmd, SZ_LINE, "%s -e -f %s -l %s.log", + findname, method, method); +#else + snprintf(nscmd, SZ_LINE, "\"%s\" -e -f %s -l %s.log &\n", + findname, method, method); +#endif + break; +#endif + } + } + else{ + *nscmd = '\0'; + } + } + + /* did not find the name server -- start it up if we can, i.e., + if its on the same machine as we are on and we found it in the path */ + if((*nscmd != '\0') && ((mtype == XPA_UNIX) || LOCALIP(xnsip)) ){ + FPRINTF((stderr, "%sLaunching: %s\n", _sp, nscmd)); +#if USE_LAUNCH + if( Launch(nscmd, 0, NULL, NULL) != 0 ) + goto nons; +#else + if( system(nscmd) != 0 ) + goto nons; +#endif + /* enter loop looking to connect */ + for(tries=0; tries<XPA_RETRIES; tries++){ + switch(mtype){ + case XPA_INET: + /* use $localhost alternately with $host */ + if( (xnsip == gethostip("$host")) && (tries % 2 == 0) ){ + xnsip = gethostip("$localhost"); + } + if( xnsip == 0 ){ + fprintf(stderr, + "XPA$ERROR: invalid host name specified: %s.\n", method); + return(NULL); + } + if( (xnsfd = xsocket(AF_INET, SOCK_STREAM, 0)) < 0 ) + goto nons; + memset((char *)&sock_in, 0, sizeof(sock_in)); + sock_in.sin_family = AF_INET; + sock_in.sin_addr.s_addr = htonl(xnsip); + sock_in.sin_port = htons(xnsport); + FPRINTF((stderr, "%sXPANSOPEN: attempting connect to %x\n", + _sp, xnsip)); + if(connect(xnsfd, (struct sockaddr *)&sock_in, sizeof(sock_in)) ==0) + goto okns; + break; +#if HAVE_SYS_UN_H + case XPA_UNIX: + if( (xnsfd = xsocket(AF_UNIX, SOCK_STREAM, 0)) < 0 ) + goto nons; + if(connect(xnsfd, (struct sockaddr *)&sock_un, sizeof(sock_un)) ==0) + goto okns; + break; +#endif + } + xclose(xnsfd); + XPASleep(XPA_NSDELAY); + } + /* if we got here, we did not connect */ + goto nons; + } + /* name server is on a remote machine, so there is no hope */ + else{ + goto nons; + } + +okns: + /* make sure we close on exec */ + xfcntl(xnsfd, F_SETFD, FD_CLOEXEC); + setsockopt(xnsfd, SOL_SOCKET, SO_KEEPALIVE, + (char *)&keep_alive, sizeof(keep_alive)); + /* fill in new record */ + if( (ns = (NS)xcalloc(1, sizeof(NSRec))) == NULL ){ + xclose(xnsfd); + return NULL; + } + ns->method = xstrdup(method); + ns->host = xstrdup(host); + ns->fd = xnsfd; + FPRINTF((stderr, "%sXPANSOpen: host %s opened on fd %d\n", _sp, + host?host:"<unknown>", xnsfd)); + switch(mtype){ + case XPA_INET: + ns->ip = xnsip; + ns->port = xnsport; + break; +#if HAVE_SYS_UN_H + case XPA_UNIX: + ns->name = xstrdup(method); + break; +#endif + } + if( xpa ){ + /* add to list of name servers */ + if( xpa->nshead == NULL ){ + xpa->nshead = ns; + } + else{ + for(cur=xpa->nshead; cur->next!=NULL; cur=cur->next) + ; + cur->next = ns; + } + } + /* check version with xpans */ + snprintf(tbuf, SZ_LINE, "version %s\n", XPA_VERSION); + if( (XPAPuts(xpa, ns->fd, tbuf, stimeout) >0) && + (XPAGets(xpa, ns->fd, tbuf, SZ_LINE, stimeout) >0) ){ + if( word(tbuf, tbuf2, &ip) ){ + if( !strcmp(tbuf2, "XPA$VERSION") ){ + if( word(tbuf, tbuf2, &ip) ){ + /* version check: our server version should be <= xpans version */ + dowarn = (XPAVersionCheck(XPA_VERSION, tbuf2)>0); + } + else{ + strcpy(tbuf2, "unknown/pre-2.1 (noversion)"); + dowarn = 1; + } + } + else{ + strcpy(tbuf2, "unknown/pre-2.1 (badformat)"); + dowarn = 1; + } + } + FPRINTF((stderr, "%sXPANSOpen: version info: %s\n", _sp, tbuf)); + if( dowarn ){ + XPAVersionWarn(XPA_VERSION, tbuf2); + } + } + + /* clean up */ + if( findname != NULL ) xfree(findname); + return(ns); + +nons: + /* if we specified an explicit port, we don't need the name server, + so don't bother with any warning or error messages */ + if( XPAPort(xpa) >0 ) + return NULL; + switch(mtype){ + case XPA_INET: + if( !errinit && verbosity ){ + if( LOCALIP(xnsip) ){ + fprintf(stderr, + "XPA$WARNING: xpans needs to be running on this machine.\n"); + } + else{ + fprintf(stderr, + "XPA$WARNING: xpans needs to be running on machine: "); + fprintf(stderr, "%s\n", getiphost(xnsip)); + } + } + break; +#if HAVE_SYS_UN_H + case XPA_UNIX: + if( !errinit && verbosity ){ + fprintf(stderr, + "XPA$WARNING: xpans needs to be running on this machine.\n"); + } + break; +#endif + default: + break; + } + if( xpa && verbosity ){ + if( !errinit ){ + /* make up the command users will need to start xpans */ + if( *nscmd == '\0' ){ + switch(mtype){ + case XPA_INET: + snprintf(nscmd, SZ_LINE, "xpans -e -p %d -l %s/xpans_%d.log", + xnsport, tmpdir, xnsport); + break; +#if HAVE_SYS_UN_H + case XPA_UNIX: + snprintf(nscmd, SZ_LINE, "xpans -e -f %s -l %s.log", method, method); + break; +#endif + } + } + fprintf(stderr, "Please start xpans using the command:\n\t%s\n", nscmd); + fprintf(stderr, "Once xpans is running, register all xpas in this process using:\n"); + fprintf(stderr, "\txpaset -p %s -nsconnect\n", xpa->method); + } + fprintf(stderr, "For now, contact %s using:", xpa->name); + fprintf(stderr, " xpaset %s .. or xpaget %s ..\n", + xpa->method, xpa->method); + } + errinit++; + +noforce: + if( findname != NULL ) xfree(findname); + return(NULL); +} + +/* + *--------------------------------------------------------------------------- + * + * Routine: _XPAFree + * + * Purpose: free up memory in the XPA record structure + * (internal version) + * + * Results: 0 on success, -1 for failure + * + *--------------------------------------------------------------------------- + */ +#ifdef ANSI_FUNC +static int +_XPAFree (XPA xpa) +#else +static int _XPAFree(xpa) + XPA xpa; +#endif +{ + char tbuf[SZ_LINE]; + XPACmd cmd, tcmd; + XPAComm comm, tcomm; + XPAClip clip, tclip; + NS ns, tns; + + /* make sure we have something to do */ + if( xpa == NULL ) + return(-1); + + FPRINTF((stderr, "%s_XPAFree: freeing xpa struct\n", _sp)); + /* remove this xpa from public availability */ + if( xpa->type != NULL ) + XPANSDel(xpa, NULL, NULL); + + /* free all sub-commands */ + for(cmd=xpa->commands; cmd!=NULL; ){ + tcmd = cmd->next; + XPACmdDel(xpa, cmd); + cmd = tcmd; + } + + /* remove from list of xpas */ + XPAListDel(&xpahead, xpa); + + /* close down listening socket */ + if( xpa->fd >= 0 ) + xclose(xpa->fd); + + /* perform method-specific cleanup */ + switch(mtype){ +#if HAVE_SYS_UN_H + case XPA_UNIX: + /* delete the unix socket files */ + unlink(xpa->method); + snprintf(tbuf, SZ_LINE, "%s_data", xpa->method); + unlink(tbuf); + break; +#endif + default: + break; + } + + /* free up space */ + if( xpa->version ) xfree(xpa->version); + if( xpa->type ) xfree(xpa->type); + if( xpa->method ) xfree(xpa->method); + if( xpa->xclass ) xfree(xpa->xclass); + if( xpa->name ) xfree(xpa->name); + if( xpa->help ) xfree(xpa->help); + if( xpa->sendian ) xfree(xpa->sendian); + + /* call the select free routine for the listening socket and loop type. + we use an indirect routine to avoid having to link Xt, Tcl, etc. */ + if( xpa->seldel && xpa->selptr ){ + (xpa->seldel)(xpa->selptr); + xpa->selptr = NULL; + } + + /* close communication channels */ + for(comm=xpa->commhead; comm!=NULL; ){ + tcomm = comm->next; + CommFree(xpa, comm, 1); + comm = tcomm; + } + + /* free up clipboards */ + for(clip=xpa->cliphead; clip!=NULL; ){ + tclip = clip->next; + ClipBoardFree(xpa, clip); + clip = tclip; + } + + /* close down the name server and all of the remotes for this xpa */ + for(ns=xpa->nshead; ns!=NULL; ){ + tns = ns->next; + XPANSClose(xpa, ns); + ns = tns; + } + + /* free up record struct */ + xfree((char *)xpa); + + return(0); +} + +#if HAVE_ATEXIT +/* + *--------------------------------------------------------------------------- + * + * Routine: _XPAAtExit + * + * Purpose: XPA cleanup on exit + * The main purpose of this routine is to try to delete the + * unix socket files when an XPA server exits. + * + * Results: none + * + *--------------------------------------------------------------------------- + */ +#ifdef ANSI_FUNC +static void +_XPAAtExit (void) +#else +static void _XPAAtExit() +#endif +{ + XPA xpa, txpa; + static int done=0; + + if( !done ){ + /* return if we were not initialized */ + if( !atexitinit ) return; + /* return if I am not the process who initialized (I'm a child) */ + if( atexitinit != getpid() ) return; + FPRINTF((stderr, "calling XPAAtExit\n")); + for(xpa=xpahead; xpa!=NULL; ){ + /* use temp in case we destroy structure in the cleanup */ + txpa = xpa->next; + _XPAFree(xpa); + xpa = txpa; + } + /* platform-dependent cleanup */ + xsocketcleanup(); + /* done with cleanup */ + done++; + } +} + +/* + *--------------------------------------------------------------------------- + * + * Routine: XPAAtExit + * + * Purpose: set up XPA cleanup on exit + * + * Results: none + * + *--------------------------------------------------------------------------- + */ +#ifdef ANSI_FUNC +void +XPAAtExit (void) +#else +void XPAAtExit() +#endif +{ + if( !atexitinit ){ + atexit(_XPAAtExit); + atexitinit = getpid(); + } +} + +#endif + +/* + *---------------------------------------------------------------------------- + * + * + * Semi-Public Routines + * (mainly used by xpaset and xpaget) + * + * + *---------------------------------------------------------------------------- + */ + +/* + *--------------------------------------------------------------------------- + * + * Routine: _XPAValid + * + * Purpose: see if the xpa struct is valid + * + * Results: 1 on success, 0 for failure + * + *--------------------------------------------------------------------------- + */ +#ifdef ANSI_FUNC +int +_XPAValid (XPA head, XPA xpa, char *type) +#else +int _XPAValid(head, xpa, type) + XPA head; + XPA xpa; + char *type; +#endif +{ + XPA cur; + + if( xpa == NULL ) + return(0); + for(cur=head; cur!=NULL; cur=cur->next){ + if( (cur == xpa) && !strcspn(cur->type, type) ){ + return(1); + } + } + return(0); +} + +/* + *--------------------------------------------------------------------------- + * + * Routine: XPAValid + * + * Purpose: see if the xpa struct is valid + * + * Results: 1 on success, 0 for failure + * + *--------------------------------------------------------------------------- + */ +#ifdef ANSI_FUNC +int +XPAValid (XPA xpa) +#else +int XPAValid(xpa) + XPA xpa; +#endif +{ + if( _XPAValid(xpahead, xpa, XPA_ACLS) ) + return(1); + else + return(0); +} + +/* + *---------------------------------------------------------------------------- + * + * Routine: XPAEndian + * + * Purpose: semi-public routine to return the endian-ness of this + * machine + * + * Results: 0 if little endian, 1 if bigendian + * + *---------------------------------------------------------------------------- + */ +#ifdef ANSI_FUNC +int +XPAEndian(void) +#else +int XPAEndian() +#endif +{ + union + { + long l; + char c[sizeof (long)]; + } u; + u.l = 1; + return(u.c[sizeof (long) - 1] == 1); +} + +/* + *---------------------------------------------------------------------------- + * + * Routine: XPAListHead + * + * Purpose: semi-public routine to return the head of the xpa list + * + * Results: XPA list pointer on success + * + *---------------------------------------------------------------------------- + */ +#ifdef ANSI_FUNC +XPA +XPAListHead (void) +#else +XPA XPAListHead() +#endif +{ + return(xpahead); +} + +/* + *--------------------------------------------------------------------------- + * + * Routine: XPAListAdd + * + * Purpose: add a member of an xpa list + * + * Results: 1 on success, 0 for failure + * + *--------------------------------------------------------------------------- + */ +#ifdef ANSI_FUNC +void +XPAListAdd (XPA *head, XPA xpa) +#else +void XPAListAdd(head, xpa) + XPA *head; + XPA xpa; +#endif +{ + XPA cur; + + if( *head == NULL ){ + *head = xpa; + } + else{ + for(cur=*head; cur->next!=NULL; cur=cur->next) + ; + cur->next = xpa; + } +} + +/* + *--------------------------------------------------------------------------- + * + * Routine: XPAListDel + * + * Purpose: remove a member of an xpa list + * + * Results: 1 on success, 0 for failure + * + *--------------------------------------------------------------------------- + */ +#ifdef ANSI_FUNC +void +XPAListDel (XPA *head, XPA xpa) +#else +void XPAListDel(head, xpa) + XPA *head; + XPA xpa; +#endif +{ + XPA cur; + + /* remove from list of xpas */ + if( *head ){ + if( *head == xpa ){ + *head = xpa->next; + } + else{ + for(cur=*head; cur!=NULL; cur=cur->next){ + if( cur->next == xpa ){ + cur->next = xpa->next; + break; + } + } + } + } +} + +/* + *---------------------------------------------------------------------------- + * + * Routine: XPAActive + * + * Purpose: make the xpa, cmd and data fds active or inactive for select + * + * Returns: none + * + *---------------------------------------------------------------------------- + */ +#ifdef ANSI_FUNC +int +XPAActive (XPA xpa, XPAComm comm, int flag) +#else +int XPAActive(xpa, comm, flag) + XPA xpa; + XPAComm comm; + int flag; +#endif +{ + int prev=0; + + /* sanity check */ + if( !xpa ) return(0); + + switch(flag){ + /* remove this xpa from the active list */ + case 0: + if( (xpa->fd >= 0) && (xpa->fd < FD_SETSIZE) ){ + FPRINTF((stderr, "%sXPAActive: clearing fd %d\n", _sp, xpa->fd)); + prev = activefds[xpa->fd]; + activefds[xpa->fd] = 0; + if( xpa->seloff && xpa->selptr ) + (xpa->seloff)(xpa->selptr); + } + if( comm ){ + if( (comm->cmdfd >= 0) && (comm->cmdfd < FD_SETSIZE) ){ + activefds[comm->cmdfd] = 0; + if( xpa->seloff && comm->selcptr ) + (xpa->seloff)(comm->selcptr); + } + if( (comm->datafd >= 0) && (comm->datafd < FD_SETSIZE) ){ + activefds[comm->datafd] = 0; + if( xpa->seloff && comm->seldptr ) + (xpa->seloff)(comm->seldptr); + } + } + break; + /* add this xpa/comm to the active list */ + case 1: + if( (xpa->fd >= 0) && (xpa->fd < FD_SETSIZE) ){ + FPRINTF((stderr, "%sXPAActive: activating fd %d\n", _sp, xpa->fd)); + prev = activefds[xpa->fd]; + activefds[xpa->fd] = 1; + if( xpa->selon && xpa->selptr ) + (xpa->selon)(xpa->selptr); + } + if( comm ){ + if( (comm->cmdfd >= 0) && (comm->cmdfd < FD_SETSIZE) ){ + activefds[comm->cmdfd] = 1; + if( xpa->selon && comm->selcptr ) + (xpa->selon)(comm->selcptr); + } + if( (comm->datafd >= 0) && (comm->datafd < FD_SETSIZE) ){ + activefds[comm->datafd] = 1; + if( xpa->selon && comm->seldptr ) + (xpa->selon)(comm->seldptr); + } + } + break; + default: + break; + } + return(prev); +} + +/* + *---------------------------------------------------------------------------- + * + * Routine: XPAActiveFd + * + * Purpose: semi-public routine to return flag if fd is active + * + * Results: 1 is active, 0 is inactive + * + *---------------------------------------------------------------------------- + */ +#ifdef ANSI_FUNC +int +XPAActiveFd (int fd) +#else +int XPAActiveFd(fd) + int fd; +#endif +{ + if( (fd >= 0) && (fd < FD_SETSIZE) && (activefds[fd] > 0) ) + return(1); + else + return(0); +} + +/* + *---------------------------------------------------------------------------- + * + * Routine: XPAAddSelect + * + * Purpose: add one or more xpa sockets to the select flags + * + * Return: number of xpas that were added to the select flags + * + *---------------------------------------------------------------------------- + */ +#ifdef ANSI_FUNC +int +XPAAddSelect (XPA xpa, fd_set *readfdsptr) +#else +int XPAAddSelect(xpa, readfdsptr) + XPA xpa; + fd_set *readfdsptr; +#endif +{ + XPA cur; + XPAComm comm; + int got=0; + + /* better have some place to set the flags */ + if( readfdsptr == NULL ) + return(0); + + /* if a specific xpa was specified, just set its select flags */ + if( xpa != NULL ){ + if( XPAActiveFd(xpa->fd) ){ + FD_SET(xpa->fd, readfdsptr); + got++; + /* note that we only select on coms if the main fd is active */ + for(comm=xpa->commhead; comm!=NULL; comm=comm->next){ + if( XPAActiveFd(comm->cmdfd) ){ + FD_SET(comm->cmdfd, readfdsptr); + got++; + } + if( XPAActiveFd(comm->datafd) && (comm->datafd != comm->cmdfd) ){ + FD_SET(comm->datafd, readfdsptr); + got++; + } + } + } + } + /* otherwise set select flags for all xpas */ + else{ + for(cur=xpahead; cur!=NULL; cur=cur->next){ + if( XPAActiveFd(cur->fd) ){ + FPRINTF((stderr, "%sXPAAddSelect: adding fd %d\n", _sp, cur->fd)); + FD_SET(cur->fd, readfdsptr); + got++; + /* note that we only select on coms if the main fd is active */ + for(comm=cur->commhead; comm!=NULL; comm=comm->next){ + if( XPAActiveFd(comm->cmdfd) ){ + FPRINTF((stderr, "%sXPAAddSelect: adding cmdfd %d\n", + _sp, comm->cmdfd)); + FD_SET(comm->cmdfd, readfdsptr); + got++; + } + if( XPAActiveFd(comm->datafd) && (comm->datafd != comm->cmdfd) ){ + FPRINTF((stderr, "%sXPAAddSelect: adding datafd %d\n", + _sp, comm->datafd)); + FD_SET(comm->datafd, readfdsptr); + got++; + } + } + } + } + } + return(got); +} + +/* + *---------------------------------------------------------------------------- + * + * Routine: XPAProcessSelect + * + * Purpose: process xpas that have pending reads or writes + * + * Return: number of xpas processed + * + *---------------------------------------------------------------------------- + */ +#ifdef ANSI_FUNC +int +XPAProcessSelect (fd_set *readfdsptr, int maxreq) +#else +int XPAProcessSelect(readfdsptr, maxreq) + fd_set *readfdsptr; + int maxreq; +#endif +{ + int got=0; + XPA xpa; + XPAComm comm; +#ifdef OLD + XPA txpa; + XPAComm tcomm; +#endif + + /* <= 0 means do all of them */ + if( maxreq < 0 ){ + maxreq = 0; + } + +again: + for(xpa=xpahead; xpa!=NULL; xpa=xpa->next){ + /* handle command requests */ + for(comm=xpa->commhead; comm!=NULL; comm=comm->next){ + if( (comm->cmdfd >=0) && FD_ISSET(comm->cmdfd, readfdsptr) ){ + FD_CLR(comm->cmdfd, readfdsptr); + XPAHandler(xpa, comm->cmdfd); + got++; + if( maxreq && (got >= maxreq) ) return(got); + goto again; + } + } + /* handle data requests */ + for(comm=xpa->commhead; comm!=NULL; comm=comm->next){ + if( (comm->datafd >=0) && FD_ISSET(comm->datafd, readfdsptr) ){ + FD_CLR(comm->datafd, readfdsptr); + XPAHandler(xpa, comm->datafd); + got++; + if( maxreq && (got >= maxreq) ) return(got); + goto again; + } + } + /* handle new requests */ + if( (xpa->fd >= 0) && FD_ISSET(xpa->fd, readfdsptr) ){ + FD_CLR(xpa->fd, readfdsptr); + XPAHandler(xpa, xpa->fd); + got++; + if( maxreq && (got >= maxreq) ) return(got); + goto again; + } + } + +#ifdef OLD + for(xpa=xpahead; xpa!=NULL; ){ + txpa = xpa->next; + /* handle command requests */ + for(comm=xpa->commhead; comm!=NULL; ){ + tcomm = comm->next; + if( (comm->cmdfd >=0) && FD_ISSET(comm->cmdfd, readfdsptr) ){ + FD_CLR(comm->cmdfd, readfdsptr); + FPRINTF((stderr, "%sXPAProcessSelect: cmd %d\n", _sp, comm->cmdfd)); + /* if we got an error on this xpa, skip processing rest of it */ + if( XPAHandler(xpa, comm->cmdfd) != XPA_RTN_OK ){ + goto nextxpa; + } + got++; + /* if we freed this xpa, skip processing rest of it */ + if( !_XPAValid(xpahead, xpa, XPA_ACLS) ){ + goto nextxpa; + } + /* if we are have processed the max reqests, we are done */ + if( maxreq && (got >= maxreq) ){ + return(got); + } + } + comm = tcomm; + } + /* handle data requests */ + for(comm=xpa->commhead; comm!=NULL; ){ + tcomm = comm->next; + if( (comm->datafd >=0) && FD_ISSET(comm->datafd, readfdsptr) ){ + FD_CLR(comm->datafd, readfdsptr); + FPRINTF((stderr, "%sXPAProcessSelect: data %d\n", _sp, comm->datafd)); + /* if we got an error on this xpa, skip processing rest of it */ + if( XPAHandler(xpa, comm->datafd) != XPA_RTN_OK ){ + goto nextxpa; + } + got++; + /* if we freed this xpa, skip processing rest of it */ + if( !_XPAValid(xpahead, xpa, XPA_ACLS) ){ + goto nextxpa; + } + /* if we are have processed the max reqests, we are done */ + if( maxreq && (got >= maxreq) ){ + return(got); + } + } + comm = tcomm; + } + /* handle new requests */ + if( (xpa->fd >= 0) && FD_ISSET(xpa->fd, readfdsptr) ){ + FD_CLR(xpa->fd, readfdsptr); + FPRINTF((stderr, "%sXPAProcessSelect: xpa %d\n", _sp, xpa->fd)); + /* if we got an error on this xpa, skip processing rest of it */ + if( XPAHandler(xpa, xpa->fd) != XPA_RTN_OK ){ + goto nextxpa; + } + got++; + /* if we freed this xpa, skip processing rest of it */ + if( !_XPAValid(xpahead, xpa, XPA_ACLS) ){ + goto nextxpa; + } + /* if we are have processed the max reqests, we are done */ + if( maxreq && (got >= maxreq) ){ + return(got); + } + } + +nextxpa: + /* must check to see if last xpa freed the next xpa */ + if( _XPAValid(xpahead, txpa, XPA_ACLS) ) + xpa = txpa; + else + break; + } +#endif + FPRINTF((stderr, "%sXPAProcessSelect: returns %d\n", _sp, got)); + return(got); +} + +/* + *---------------------------------------------------------------------------- + * + * Routine: XPACloseData + * + * Purpose: close data fd if its not the cmd fd + * + * Returns: none + * + *---------------------------------------------------------------------------- + */ +#ifdef ANSI_FUNC +void +XPACloseData (XPA xpa, XPAComm comm) +#else +void XPACloseData(xpa, comm) + XPA xpa; + XPAComm comm; +#endif +{ + /* we close the data channel if its not the command channel */ + if( comm && (comm->datafd >=0) ){ + if( comm->cmdfd != comm->datafd ){ + FPRINTF((stderr, "%sXPACloseData: close fd %d for cmd fd %d\n", _sp, + comm->datafd, comm->cmdfd)); + /* remove from active */ + if( comm->datafd < FD_SETSIZE ) + activefds[comm->datafd] = 0; + /* delete the comm data fd specially from a non-select event loop */ + if( xpa && xpa->seldel && comm->seldptr ){ + (xpa->seldel)(comm->seldptr); + comm->seldptr = NULL; + } + /* close file */ + xclose(comm->datafd); + } + /* reset data channel to impossible value */ + comm->datafd = -1; + } +} + +/* + *---------------------------------------------------------------------------- + * + * Routine: XPAHandler + * + * Purpose: handle one request for an xpaset or xpaget + * + * Return: 0 on success, xpa error code on failure + * + *---------------------------------------------------------------------------- + */ +#ifdef ANSI_FUNC +int +XPAHandler (XPA xpa, int fd) +#else +int XPAHandler(xpa, fd) + XPA xpa; + int fd; +#endif +{ + char tbuf[SZ_LINE]; + char tbuf2[SZ_LINE]; + char lbuf[SZ_LINE]; + char cmd[SZ_LINE]; + char target[SZ_LINE]; + char method[SZ_LINE]; + char ctmpl[SZ_LINE]; + char ntmpl[SZ_LINE]; + char *paramlist=NULL; + char *acl; + int save_ack; + int tcmd; + int got=0; + int lp=0; + int cmdfd=-1; + unsigned short port=0; + unsigned int ip=0; + struct timeval tv; + XPAComm comm=NULL, tcomm=NULL, xcomm=NULL, ocomm=NULL; + XPA txpa=NULL; + NS ns=NULL; + fd_set readfds; + FPRINTF((stderr, "%sXPAHandler: entering with fd %d\n", _sp, fd)); + + /* this is a defensive measure: we have to guard against an external + loop calling the XPA handler with a bogus XPA record. This has been + seen with the Tcl event loop. + */ + for(txpa=xpahead; txpa!=NULL; txpa=txpa->next){ + if( txpa == xpa ) break; + } + if( txpa == NULL ){ + FPRINTF((stderr, "%sXPAHandler: xpa record %p is not in list\n", + _sp, xpa)); + return(XPA_RTN_NOCMD); + } + + /* this is a defensive measure: we have to ensure that there really + * is a request read. It is possible that a user-defined select loop + * might call us to handle a request that we had already handled + * (i.e. we handle a request but can't reset someone else's select flags) + */ + FD_ZERO(&readfds); + FD_SET(fd, &readfds); + tv.tv_sec = 0; + tv.tv_usec = 0; + while( xselect(fd+1, &readfds, NULL, NULL, &tv) <=0 ){ + if( xerrno == EINTR ) + continue; + FPRINTF((stderr, "%sXPAHandler: xpa fd %d is not ready\n", _sp, fd)); + return(XPA_RTN_NOCMD); + } + + /* if this is a first connection, we create a new comm channel and exit */ + if( fd == xpa->fd ){ + if( (comm = CommNew(xpa, -1, 0, 0, NULL, NULL)) == NULL ) + return(XPA_RTN_NOCONN); + /* Return to prevent xpa from finishing before other xpa's are started. + Otherwise, each xpa's associated with a target template will be + processed serially, which will defeat all the hard work done on + the client side to send data to servers when they ask for it. + */ + else{ + FPRINTF((stderr, "%sXPAHandler: returning after CommNew on fd %d\n", + _sp, fd)); + got = XPA_RTN_OK; + goto end; + } + } + + /* look for a currently active comm channel: cmd or data */ + for(comm=xpa->commhead; comm!= NULL; comm=comm->next){ + if( (fd == comm->cmdfd) || (fd == comm->datafd) ){ + break; + } + } + /* make sure we have something */ + if( comm == NULL ){ + /* read extraenous message */ + if( XPAGets(xpa, fd, tbuf, SZ_LINE, 1) >0 ){ + got = XPA_RTN_UNCMD; + FPRINTF((stderr, "%sXPAHandler: fd %d received extra message:\n%s\n", + _sp, fd, tbuf)); + } + else{ + FPRINTF((stderr, "%sXPAHandler: no active comm record for fd %d\n", + _sp, fd)); + got = XPA_RTN_NOCMD2; + } + goto error; + } + /* but don't recurse */ + if( comm->status & XPA_STATUS_ACTIVE ){ + FPRINTF((stderr, "%sXPAHandler: fd %d returning to avoid recursion\n", + _sp, fd)); + got = 0; + goto end; + } + /* set current comm for this xpa */ + ocomm = xpa->comm; + xpa->comm = comm; + /* no message sent yet */ + comm->message = 0; + + /* data ready on data channel: go right to data handling section */ + if( fd == comm->datafd ){ + FPRINTF((stderr, "%sXPAHandler: jumping to cb for %d\n", _sp, fd)); + goto cb; + } + + /* cmd channel: we are processing a new command */ +retry: + /* reset line buffer pointer for parsing */ + lp = 0; + /* read next command */ + if( XPAGets(xpa, comm->cmdfd, lbuf, SZ_LINE, stimeout) <=0 ){ + FPRINTF((stderr, "%sXPAHandler: fd %d read EOF\n", _sp, comm->cmdfd)); + got = XPA_RTN_OK; + goto eof; + } + /* new-lines imply we entered telnet mode on local host */ + else if( (*lbuf == '\n') || (*lbuf == '\r') || !strcmp(lbuf, "telnet") ){ + if( (mtype == XPA_UNIX) || LOCALIP(comm->cmdip) ){ + if( comm->telnet == 0 ) + XPAPuts(xpa, comm->cmdfd, "Entering telnet mode ...\n", stimeout); + comm->telnet = 1; + comm->ack = 0; + comm->datafd = comm->cmdfd; + stimeout = -1; + goto retry; + } + else{ + XPAError(xpa, xpaMessbuf[XPA_RTN_NOCMD]); + got = XPA_RTN_NOCMD; + goto error; + } + } + + FPRINTF((stderr, "%sXPAHandler: fd %d read command: %s", + _sp, comm->cmdfd, lbuf)); + + /* validate the command */ + if( !word(lbuf, cmd, &lp) ){ + FPRINTF((stderr, "%sXPAHandler: missing target for fd %d\n", + _sp, comm->cmd)); + XPAError(xpa, xpaMessbuf[XPA_RTN_NOCMD]); + got = XPA_RTN_NOCMD; + goto error; + } + + /* send help message (local support only) */ + if( !strcmp(cmd, "help") ){ + if( (mtype == XPA_UNIX) || LOCALIP(comm->cmdip) ){ + XPAPuts(xpa, comm->cmdfd, + "xpaset|xpaget|xpainfo|xpaaccess [switches] class:name [params]\n", + stimeout); + XPAPuts(xpa, comm->cmdfd, + "switches:\n", + stimeout); + XPAPuts(xpa, comm->cmdfd, + "\t-a\t\tclient wants to accept() data connection\n", + stimeout); + XPAPuts(xpa, comm->cmdfd, + "\t-e <b|l>\tclient endian-ness: big(b) or little(l)\n", + stimeout); + XPAPuts(xpa, comm->cmdfd, + "\t-i id\t\tclient id string\n", + stimeout); + XPAPuts(xpa, comm->cmdfd, + "\t-p <proxyinfo>\t\tfrom xpans (e.g., for proxy processing)\n", + stimeout); + XPAPuts(xpa, comm->cmdfd, + "\t-n\t\tdon't ack back to client\n", + stimeout); + XPAPuts(xpa, comm->cmdfd, + "\t-t\t\tenter telnet mode (local only)\n", + stimeout); + /* we must be in telnet mode */ + comm->telnet = 1; + comm->ack = 0; + goto retry; + } + else{ + XPAError(xpa, xpaMessbuf[XPA_RTN_NOCMD]); + got = XPA_RTN_NOCMD; + goto error; + } + } + + /* determine which command was specified */ + if( !strcmp(cmd, "xpaset") ) + tcmd = XPA_SET; + else if( !strcmp(cmd, "xpaget") ) + tcmd = XPA_GET; + else if( !strcmp(cmd, "xpainfo") ) + tcmd = XPA_INFO; + else if( !strcmp(cmd, "xpaaccess") ) + tcmd = XPA_ACCESS; + else if( !strcmp(cmd, "xpadata") ) + tcmd = XPA_DATA; + else if( !strcmp(cmd, "xpaaccept") ) + tcmd = XPA_ACCEPT; + else if( !strcmp(cmd, "xpanagle") || !strcmp(cmd, "XPA$OK") ) + tcmd = XPA_NAGLE; + else{ + FPRINTF((stderr, "%sXPAHandler: unknown command '%s' for fd %d\n", + _sp, cmd, comm->cmdfd)); + XPAError(xpa, xpaMessbuf[XPA_RTN_NOCMD]); + got = XPA_RTN_NOCMD; + goto error; + } + + /* process switches */ + while( word(lbuf, tbuf, &lp) ){ + if( *tbuf != '-' ) + break; + if( !strcmp(tbuf, "-a") ){ + comm->mode |= COMM_CONNECT; + } + else if( !strcmp(tbuf, "-e") ){ + if( word(lbuf, tbuf, &lp) ){ + if( *tbuf == 'b' ) + comm->cendian = "big"; + else if( *tbuf == 'l' ) + comm->cendian = "little"; + } + else{ + got = XPA_RTN_ILLCMD; + goto error; + } + } + else if( !strcmp(tbuf, "-f") ){ + /* B.Schoenhammer@bit-field.de 2009-09-21 */ +#if HAVE_MINGW32==0 + if( !word(lbuf, tbuf, &lp) || (sscanf(tbuf, "%p", &xcomm) != 1) ){ +#else + if( !word(lbuf, tbuf, &lp) || (sscanf(tbuf, "%x", &xcomm) != 1) ){ +#endif + got = XPA_RTN_ILLCMD; + goto done; + } + if( !word(lbuf, tbuf, &lp) || ((cmdfd = atoi(tbuf)) < 0) ){ + got = XPA_RTN_ILLCMD; + goto done; + } + } + else if( !strcmp(tbuf, "-i") ){ + if( word(lbuf, tbuf, &lp) ){ + if( comm->id != NULL ) xfree(comm->id); + comm->id = xstrdup(tbuf); + } + else{ + XPAError(xpa, xpaMessbuf[XPA_RTN_ILLCMD]); + got = XPA_RTN_ILLCMD; + goto error; + } + } + else if( !strcmp(tbuf, "-n") ){ + comm->ack = 0; + } + else if( !strcmp(tbuf, "-p") ){ + if( word(lbuf, tbuf, &lp) ){ + if( comm->info != NULL ) xfree(comm->info); + comm->info = xstrdup(tbuf); + } + else{ + XPAError(xpa, xpaMessbuf[XPA_RTN_ILLCMD]); + got = XPA_RTN_ILLCMD; + goto error; + } + } + else if( !strcmp(tbuf, "-t") ){ + comm->telnet = 1; + } + else{ + break; + } + } + + /* make sure we have some sort of id */ + if( comm->id == NULL ){ + comm->id = xstrdup("?"); + } + + /* process nagle ack */ + if( tcmd == XPA_NAGLE ){ + /* if data is forthcoming, exit and wait for data */ + if( comm->usebuf ){ + got = XPA_RTN_OK; + goto end; + } + /* go process callback */ + else{ + goto cb; + } + } + + /* connect (proxy) request: connect back to client */ + if( tcmd == XPA_ACCEPT ){ + FPRINTF((stderr, "%scmd is xpaaccept from client %d: %s", _sp, fd, lbuf)); + /* syntax: xpaaccept <method> ... */ + lp = 0; + if( !word(lbuf, tbuf, &lp) || + strcmp(tbuf, "xpaaccept") || + !word(lbuf, method, &lp) ){ + got = -1; + goto error; + } + if( (cmdfd=XPAProxyConnect(xpa, method, &ip, &port, tbuf)) <0 ){ + FPRINTF((stderr, "%sXPAProxyConnect failed for: %d\n", _sp, fd)); + got = -1; + goto error; + } + if( (tcomm = CommNew(xpa, cmdfd, ip, port, method, NULL)) == NULL ){ + got = XPA_RTN_NOCONN; + goto error; + } + else{ + /* now exit and wait for client to send command */ + FPRINTF((stderr, + "%sXPAHandler: fd %d exiting after proxy connect\n", _sp, + tcomm->cmdfd)); + got = XPA_RTN_OK; + goto end; + } + } + + /* data request: find associated command request, and process the command */ + if( tcmd == XPA_DATA ){ + FPRINTF((stderr, "%sXPAHandler: processing data fd %d\n", + _sp, comm->cmdfd)); + /* find the cmd record with which this data is associated */ + for(tcomm=xpa->commhead; tcomm!= NULL; tcomm=tcomm->next){ + if( (tcomm == xcomm) && (tcomm->cmdfd == cmdfd) ){ + break; + } + } + /* if we found an associated command, copy in data info and process */ + if( tcomm ){ + /* fill in command comm */ + tcomm->datafd = comm->cmdfd; + tcomm->seldptr = comm->selcptr; + if( tcomm->dataname ) xfree(tcomm->dataname); + tcomm->dataname = xstrdup(comm->cmdname); + /* done with data comm */ + CommFree(xpa, comm, 0); + /* reset comm pointers */ + comm = tcomm; + xpa->comm = comm; + FPRINTF((stderr, "%sXPAHandler: found cmd fd %d for this data fd %d\n", + _sp, comm->cmdfd, comm->datafd)); + if( comm->cmd == XPA_SET ){ + FPRINTF((stderr, "%sXPAHandler: data %d returning await xpaset\n", + _sp, comm->datafd)); + got = XPA_RTN_OK; + goto end; + } + else{ + FPRINTF((stderr, "%sXPAHandler: data %d going on to process data\n", + _sp, comm->datafd)); + goto cb; + } + } + else{ + FPRINTF((stderr, "%sXPAHandler: data fd has no corresponding cmd %d\n", + _sp, comm->cmdfd)); + XPAError(xpa, xpaMessbuf[XPA_RTN_ILLCMD]); + got = XPA_RTN_ILLCMD; + goto error; + } + } + + /* for a command, the first non-switch word we found was the target */ + if( *tbuf == '\0' ){ + FPRINTF((stderr, "%sXPAHandler: missing target for fd %d\n", + _sp, comm->cmdfd)); + XPAError(xpa, xpaMessbuf[XPA_RTN_NOCMD]); + got = XPA_RTN_NOCMD; + goto error; + } + else{ + strcpy(target, tbuf); + } + + /* validate the target (except for xpans for use as proxy) */ + if( strcmp(xpa->xclass, XPANS_CLASS) || strcmp(xpa->name, XPANS_NAME) ){ + XPAParseName(target, ctmpl, ntmpl, SZ_LINE); + if( (strcmp(ctmpl,"?") && !tmatch(xpa->xclass, ctmpl)) || + (strcmp(ntmpl,"?") && !tmatch(xpa->name, ntmpl)) ){ + got = XPA_RTN_NOTARG; + goto error; + } + } + if( comm->target != NULL ) xfree(comm->target); + comm->target = xstrdup(target); + + /* the rest of the input string is paramlist */ + paramlist = &(lbuf[lp]); + nowhite(paramlist, paramlist); + if( comm->paramlist != NULL ) xfree(comm->paramlist); + comm->paramlist = xstrdup(paramlist); + /* save command */ + comm->cmd = tcmd; + + FPRINTF((stderr, + "%sXPAHandler: processing command fd %d for target %s (%d)\n", + _sp, comm->cmdfd, target, comm->cmd)); + + /* a reserved command can only be called from the same host as the server, + or from local (unix) sockets */ + lp = 0; + if( XPACmdLookupReserved(xpa, comm->paramlist, &lp) ){ + comm->mode |= COMM_RESERVED; + } + + /* set up command-specific info */ + switch(comm->cmd){ + case XPA_SET: + if( comm->mode & COMM_RESERVED ){ + comm->usebuf = 1; + comm->useacl = guseacl && (mtype != XPA_UNIX); + acl = "s"; + } + else if( xpa->receive_callback ){ + comm->usebuf = (xpa->receive_mode & XPA_MODE_BUF); + comm->useacl = guseacl && + (xpa->receive_mode & XPA_MODE_ACL) && (mtype != XPA_UNIX); + acl = "s"; + } + else{ + XPAError(xpa, xpaMessbuf[XPA_RTN_NOREC]); + got = XPA_RTN_NOREC; + goto error; + } + break; + case XPA_GET: + if( comm->mode & COMM_RESERVED ){ + comm->usebuf = 1; + comm->useacl = guseacl && (mtype != XPA_UNIX); + acl = "g"; + } + else if( xpa->send_callback ){ + comm->usebuf = (xpa->send_mode & XPA_MODE_BUF); + comm->useacl = guseacl && + (xpa->send_mode & XPA_MODE_ACL) && (mtype != XPA_UNIX); + acl = "g"; + } + else{ + XPAError(xpa, xpaMessbuf[XPA_RTN_NOSEND]); + got = XPA_RTN_NOSEND; + goto error; + } + break; + case XPA_INFO: + if( xpa->info_callback ){ + comm->usebuf = 0; + comm->useacl = guseacl && + (xpa->info_mode & XPA_MODE_ACL) && (mtype != XPA_UNIX); + acl = "i"; + } + else{ + XPAError(xpa, xpaMessbuf[XPA_RTN_NOINFO]); + got = XPA_RTN_NOINFO; + goto error; + } + break; + case XPA_ACCESS: + comm->usebuf = 0; + comm->useacl = guseacl && (mtype != XPA_UNIX); + /* may as well check access mode as well */ + snprintf(tbuf2, SZ_LINE, "%sa%s", _sp, comm->paramlist?comm->paramlist:""); + acl = tbuf2; + break; + default: + FPRINTF((stderr, "%sXPAHandler: invalid access control check for fd %d\n", + _sp, comm->cmdfd)); + XPAError(xpa, xpaMessbuf[XPA_RTN_NOCMD]); + got = XPA_RTN_NOCMD; + goto error; + } + + /* perform access authentication */ + if( comm->useacl ){ + /* determine acl for this ip, if necessary */ + if( comm->acl[comm->cmd] < 0 ){ + comm->acl[comm->cmd] = XPAAclCheck(xpa, comm->cmdip, acl); + } + /* check acl */ + if( comm->acl[comm->cmd] <= 0 ){ + FPRINTF((stderr, "%sXPAHandler: fd %d FAILED acl check\n", + _sp, comm->cmdfd)); + XPAError(xpa, xpaMessbuf[XPA_RTN_NOAUTH]); + got = XPA_RTN_NOAUTH; + goto error; + } + FPRINTF((stderr, "%sXPAHandler: fd %d passed acl check\n", + _sp, comm->cmdfd)); + } + + /* for telnet mode, just use cmdfd for data */ + if( comm->telnet ){ + comm->datafd = comm->cmdfd; + } + /* for xpainfo and no ack, just go to the vallback */ + else if( (comm->cmd == XPA_INFO) && !comm->ack ){ + goto cb; + } + /* in general, we must tell the client how we will handle data */ + else{ + if( comm->usebuf ){ + if( comm->mode & COMM_CONNECT ){ + snprintf(lbuf, SZ_LINE, "%s XPA$DATA accept %p %d (%s:%s %s)\n", + comm->id, comm, comm->cmdfd, + xpa->xclass, xpa->name, xpa->method); + } + else{ + snprintf(lbuf, SZ_LINE, "%s XPA$DATA connect %p %d (%s:%s %s)\n", + comm->id, comm, comm->cmdfd, + xpa->xclass, xpa->name, xpa->method); + } + } + /* no data channel being set up */ + else{ + snprintf(lbuf, SZ_LINE, "%s XPA$NODATA (%s:%s %s)\n", + comm->id, xpa->xclass, xpa->name, xpa->method); + } + FPRINTF((stderr, "%sXPAHandler: fd %d sends string: %s", + _sp, comm->cmdfd, lbuf)); + if( XPAPuts(xpa, comm->cmdfd, lbuf, stimeout) <= 0 ){ + FPRINTF((stderr, "%sXPAHandler: fd %d couldn't send string: %s", + _sp, comm->cmdfd, lbuf)); + got = -1; + goto error; + } + /* now exit and wait for nagle ack and for client to send data */ + FPRINTF((stderr, + "%sXPAHandler: fd %d exiting to wait for nagle or connect req\n", + _sp, comm->cmdfd)); + got = XPA_RTN_OK; + goto end; + } + + /* data channel complete (or no data): ready to execute the user callback */ +cb: + /* we are now active */ + comm->status |= XPA_STATUS_ACTIVE; + + /* remove the current comm from the list of active fds, + in case the server callback re-enters the event loop */ + XPAActive(xpa, comm, 0); + + /* zero out buf and len, just to make sure (don't free buf, in case + application is using previous) */ + comm->buf = NULL; + comm->len = 0; + + /* if we are not ack'ing after callback, do it now so client can exit */ + /* but don't do this for xpainfo/noack */ + if( !comm->ack && (comm->cmd != XPA_INFO) ){ + FPRINTF((stderr, "%sXPAHandler: sending OK to non-acking client %d %d\n", + _sp, comm->cmdfd, comm->datafd)); + comm->ack = 1; + XPAOK(xpa); + comm->ack = 0; + } + + /* process command */ + switch(comm->cmd){ + case XPA_GET: + FPRINTF((stderr, + "%sXPAHandler: processing xpaget for %d %d\n", _sp, + comm->cmdfd, comm->datafd)); + /* check for a reserved command */ + if( comm->mode & COMM_RESERVED ){ + got = XPASendCommands(xpa->send_data, xpa, comm->paramlist, + &(comm->buf), &(comm->len)); + } + else{ + got = (xpa->send_callback)(xpa->send_data, xpa, comm->paramlist, + &(comm->buf), &(comm->len)); + } + if( (got == 0) && (comm->buf != NULL) && (comm->len > 0) ){ + if( XPAPutBuf(xpa, comm->datafd, comm->buf, comm->len, ltimeout) < 0 ){ + PERROR(("XPAHandler write buf")); + XPAError(xpa, "XPA could not write data to client"); + goto done; + } + } + if( (xpa->send_mode & XPA_MODE_FREEBUF) && (comm->buf != NULL) ){ + if( xpa->comm->myfree != NULL ){ + if( xpa->comm->myfree_ptr != NULL ){ + xpa->comm->myfree(xpa->comm->myfree_ptr); + } + else{ + xpa->comm->myfree(comm->buf); + } + } + else{ + xfree(comm->buf); + } + } + /* send client a message, unless its already been done */ + if( !comm->message ){ + if( got ) + XPAError(xpa, "error detected in send callback routine"); + else + XPAOK(xpa); + } + FPRINTF((stderr, + "%sXPAHandler: finished xpaget for %d %d\n", _sp, + comm->cmdfd, comm->datafd)); + break; + case XPA_SET: + FPRINTF((stderr, + "%sXPAHandler: processing xpaset for %d %d\n", _sp, + comm->cmdfd, comm->datafd)); + /* check for a reserved command */ + if( comm->mode & COMM_RESERVED ){ + got=XPAReceiveCommands(xpa->receive_data, xpa, + comm->paramlist, NULL, 0); + } + else{ + /* fill buf if necessary */ + if( (comm->datafd >= 0) && + comm->usebuf && (xpa->receive_mode & XPA_MODE_FILLBUF) ){ + if(XPAGetBuf(xpa, comm->datafd, &(comm->buf), &(comm->len), -1) <0){ + XPAError(xpa, xpaMessbuf[XPA_RTN_NODATA]); + FPRINTF((stderr, "%sXPAHandler: no data for XPAGetBuf on %d\n", _sp, + comm->datafd)); + got = -1; + goto done; + } + else{ + /* close the data fd now that we are done with it */ + XPACloseData(xpa, comm); + } + } + /* execute the receive callback */ + got = (xpa->receive_callback)(xpa->receive_data, xpa, + comm->paramlist, comm->buf, comm->len); + } + if( (xpa->receive_mode & XPA_MODE_FREEBUF) && (comm->buf != NULL) ){ + if( xpa->comm->myfree != NULL ){ + if( xpa->comm->myfree_ptr != NULL ){ + xpa->comm->myfree(xpa->comm->myfree_ptr); + } + else{ + xpa->comm->myfree(comm->buf); + } + } + else{ + xfree(comm->buf); + } + } + /* send client an error message, unless its already been done */ + if( !comm->message ){ + if( got ){ + XPAError(xpa, "error detected in receive callback routine"); + } + else{ + XPAOK(xpa); + } + } + FPRINTF((stderr, + "%sXPAHandler: finished xpaset for %d %d\n", _sp, + comm->cmdfd, comm->datafd)); + break; + case XPA_INFO: + /* send OK before callback because we do not want the client waiting */ + if( comm->ack ) + XPAOK(xpa); + save_ack = comm->ack; + /* don't ever ack in callback */ + comm->ack = 0; + /* execute the info callback -- don't bother checking for errors */ + (xpa->info_callback)(xpa->info_data, xpa, comm->paramlist); + comm->ack = save_ack; + break; + case XPA_ACCESS: + /* return errors -- that how we know if we have access */ + comm->ack = 1; + /* type is in paramlist */ + if( comm->paramlist && *comm->paramlist ){ + char *s; + for(s=comm->paramlist; *s; s++){ + switch(*s){ + case 'g': + if( !xpa->send_callback ){ + XPAError(xpa, "no send callback (i.e., can't xpaget)"); + goto done; + } + break; + case 'i': + if( !xpa->info_callback ){ + XPAError(xpa, "no info callback (i.e., can't xpainfo)"); + goto done; + } + break; + case 's': + if( !xpa->receive_callback ){ + XPAError(xpa, "no receive callback (i.e., can't xpaset)"); + goto done; + } + break; + case 'a': + break; + default: + XPAError(xpa, "unknown xpa access type"); + goto done; + } + } + /* if we got here, its OK */ + XPAOK(xpa); + } + /* no type, anything is OK */ + else + XPAOK(xpa); + break; + default: + /* something is really wrong if we have no command */ + FPRINTF((stderr, "%sXPAHandler: invalid command #%d for fd %d\n", + _sp, comm->cmd, comm->cmdfd)); + got = XPA_RTN_NOCMD; + goto error; + break; + } + +done: + FPRINTF((stderr, + "%sXPAHandler: finished processing %d with status %d\n", _sp, + fd, got)); + /* add xpa back to list of active ones */ + XPAActive(xpa, comm, 1); + + /* finalize comm record */ + if( comm ){ + /* close data channel */ + XPACloseData(xpa, comm); + /* xpa is no longer active */ + comm->status &= ~XPA_STATUS_ACTIVE; + } + + /* join common code */ + goto end; + +eof: + /* on eof, free up comm */ + if( comm ){ + ns = comm->ns; + CommFree(xpa, comm, 1); + comm = NULL; + if( ns && !ns->nproxy && !ns->nxpa ){ + FPRINTF((stderr, "%sXPAHandler: closing ns %s\n", _sp, ns->name)); + XPANSClose(xpa, ns); + } + } + /* join common code */ + goto end; + + +error: + FPRINTF((stderr, "%sXPAHandler ERROR: return code %d on %d\n", + _sp, got, fd)); + /* add xpa back to list of active ones (but not comm) */ + XPAActive(xpa, comm, 1); + /* xpa is no longer using this comm */ + xpa->comm = NULL; + /* don't accidentally close ns on error */ + if( comm ){ + if( comm->ns ) + CommFree(xpa, comm, 0); + else + CommFree(xpa, comm, 1); + comm = NULL; + } + /* join common code */ + goto end; + +end: + /* if a free was requested by the callback, do it now when its safe */ + if( xpa->status & XPA_STATUS_FREE ){ + XPAFree(xpa); + } + /* restore old value of comm */ + else{ + xpa->comm = ocomm; + } + + /* return the status */ + return(got); +} + +/* + *---------------------------------------------------------------------------- + * + * Routine: XPAMode + * + * Purpose: parse the mode string and set flags + * + * Returns: none + * + *---------------------------------------------------------------------------- + */ +#ifdef ANSI_FUNC +void +XPAMode (char *mode, int *flag, char *name, int mask, int def) +#else +void XPAMode(mode, flag, name, mask, def) + char *mode; + int *flag; + char *name; + int mask; + int def; +#endif +{ + char tbuf[SZ_LINE]; + char s[SZ_LINE]; + + /* keyword routine requires an input buffer that can be modified */ + if( mode && *mode ){ + strncpy(s, mode, SZ_LINE-1); + s[SZ_LINE-1] = '\0'; + } + else + goto error; + /* look for the keyword=<value> string */ + if( keyword(s, name, tbuf, SZ_LINE) ){ + if( istrue(tbuf) ) + *flag |= mask; + else + *flag &= ~mask; + return; + } + else + goto error; + +error: + if( def ) + *flag |= mask; + else + *flag &= ~mask; +} + +/* + *---------------------------------------------------------------------------- + * + * Routine: XPAShortTimeout + * + * Purpose: return short (select, gets) timeout value + * + * Return: timeout in seconds + * + *---------------------------------------------------------------------------- + */ +#ifdef ANSI_FUNC +int +XPAShortTimeout (void) +#else +int XPAShortTimeout() +#endif +{ + return(stimeout); +} + +/* + *---------------------------------------------------------------------------- + * + * Routine: XPALongTimeout + * + * Purpose: return long (fillbuf) timeout value + * + * Return: timeout in seconds + * + *---------------------------------------------------------------------------- + */ +#ifdef ANSI_FUNC +int +XPALongTimeout (void) +#else +int XPALongTimeout() +#endif +{ + return(ltimeout); +} + +/* + *---------------------------------------------------------------------------- + * + * Routine: XPAReceiveLTimeout + * + * Purpose: modify long timeout value for this process + * + * Returns: 0 for success, -1 for failure + * + *---------------------------------------------------------------------------- + */ +#ifdef ANSI_FUNC +int +XPAReceiveLTimeout (void *client_data, void *call_data, char *paramlist, + char *buf, size_t len) +#else +int XPAReceiveLTimeout(client_data, call_data, paramlist, buf, len) + void *client_data; + void *call_data; + char *paramlist; + char *buf; + size_t len; +#endif +{ + XPA xpa = (XPA)call_data; + char tbuf[SZ_LINE]; + char *s; + + if( paramlist && *paramlist ){ + strncpy(tbuf, paramlist, SZ_LINE-1); + tbuf[SZ_LINE-1] = '\0'; + nocr(tbuf); + culc(tbuf); + if( !strcmp(tbuf, "reset") ){ + ltimeout = XPA_LONG_TIMEOUT; + if( (s=(char *)getenv("XPA_LONG_TIMEOUT")) != NULL ) + ltimeout = atoi(s); + } + else{ + ltimeout = atoi(tbuf); + } + return(0); + } + else{ + XPAError(xpa, "missing long timeout value"); + return(-1); + } +} + +/* + *---------------------------------------------------------------------------- + * + * Routine: XPASendLTimeout + * + * Purpose: return the long timeout for this process + * + * Returns: 0 for success, -1 for failure + * + *---------------------------------------------------------------------------- + */ +#ifdef ANSI_FUNC +int +XPASendLTimeout (void *client_data, void *call_data, char *paramlist, + char **buf, size_t *len) +#else +int XPASendLTimeout(client_data, call_data, paramlist, buf, len) + void *client_data; + void *call_data; + char *paramlist; + char **buf; + size_t *len; +#endif +{ + XPA xpa = (XPA)call_data; + char tbuf[SZ_LINE]; + + snprintf(tbuf, SZ_LINE, "%d\n", ltimeout); + send(xpa_datafd(xpa), tbuf, strlen(tbuf), 0); + return(0); +} + +/* + *---------------------------------------------------------------------------- + * + * Routine: XPAReceiveSTimeout + * + * Purpose: modify short timeout value for this process + * + * Returns: 0 for success, -1 for failure + * + *---------------------------------------------------------------------------- + */ +#ifdef ANSI_FUNC +int +XPAReceiveSTimeout (void *client_data, void *call_data, char *paramlist, + char *buf, size_t len) +#else +int XPAReceiveSTimeout(client_data, call_data, paramlist, buf, len) + void *client_data; + void *call_data; + char *paramlist; + char *buf; + size_t len; +#endif +{ + XPA xpa = (XPA)call_data; + char tbuf[SZ_LINE]; + char *s; + + if( paramlist && *paramlist ){ + strncpy(tbuf, paramlist, SZ_LINE-1); + tbuf[SZ_LINE-1] = '\0'; + nocr(tbuf); + culc(tbuf); + if( !strcmp(tbuf, "reset") ){ + stimeout = XPA_SHORT_TIMEOUT; + if( (s=(char *)getenv("XPA_SHORT_TIMEOUT")) != NULL ) + stimeout = atoi(s); + } + else{ + stimeout = atoi(tbuf); + } + return(0); + } + else{ + XPAError(xpa, "missing short timeout value"); + return(-1); + } +} + +/* + *---------------------------------------------------------------------------- + * + * Routine: XPASendSTimeout + * + * Purpose: return the short timeout for this process + * + * Returns: 0 for success, -1 for failure + * + *---------------------------------------------------------------------------- + */ +#ifdef ANSI_FUNC +int +XPASendSTimeout (void *client_data, void *call_data, char *paramlist, + char **buf, size_t *len) +#else +int XPASendSTimeout(client_data, call_data, paramlist, buf, len) + void *client_data; + void *call_data; + char *paramlist; + char **buf; + size_t *len; +#endif +{ + XPA xpa = (XPA)call_data; + char tbuf[SZ_LINE]; + + snprintf(tbuf, SZ_LINE, "%d\n", stimeout); + send(xpa_datafd(xpa), tbuf, strlen(tbuf), 0); + return(0); +} + +/* + *---------------------------------------------------------------------------- + * + * Routine: XPAVerbosity + * + * Purpose: return verbosity value + * + * Return: verbosity value (0, 1, 2) + * + *---------------------------------------------------------------------------- + */ +#ifdef ANSI_FUNC +int +XPAVerbosity (void) +#else +int XPAVerbosity() +#endif +{ + return(verbosity); +} + +/* + *---------------------------------------------------------------------------- + * + * Routine: XPASigusr1 + * + * Purpose: return flag for using sigusr1 + * + * Return: 0 or 1 + * + *---------------------------------------------------------------------------- + */ +#ifdef ANSI_FUNC +int +XPASigusr1 (void) +#else +int XPASigusr1() +#endif +{ + return(sigusr1); +} + +/* + *---------------------------------------------------------------------------- + * + * Routine: XPAInitEnv + * + * Purpose: initialize the xpa environment + * + * Return: none + * + *---------------------------------------------------------------------------- + */ +#ifdef ANSI_FUNC +void +XPAInitEnv (void) +#else +void XPAInitEnv() +#endif +{ + char *s; + + if( !tmpdir ){ + /* determine the communication method */ + mtype=XPAMethod(NULL); + /* enable access controls and port management */ + if( mtype != XPA_UNIX ){ + XPAAclNew(NULL, 0); + XPAPortNew(NULL, 0); + } + /* set short (select,gets) timeout, if necessary */ + if( (s=(char *)getenv("XPA_SHORT_TIMEOUT")) != NULL ) + stimeout = atoi(s); + /* set long (fillbuf) timeout, if necessary */ + if( (s=(char *)getenv("XPA_LONG_TIMEOUT")) != NULL ) + ltimeout = atoi(s); + /* set xpans connect timeout, if necessary */ + if( (s=(char *)getenv("XPA_CONNECT_TIMEOUT")) != NULL ) + ctimeout = atoi(s); + /* set verbosity level, if necessary */ + if( (s=(char *)getenv("XPA_VERBOSITY")) != NULL ){ + if( istrue(s) ) + verbosity = XPA_VERBOSITY; + else if( isfalse(s) ) + verbosity = 0; + else + verbosity = atoi(s); + if( verbosity < 0 ) + verbosity = 0; + } + /* check for acl enable/disable */ + if( (s=(char *)getenv("XPA_ACL")) != NULL ) + guseacl = istrue(s); + /* check for timestamp on errors */ + if( (s=(char *)getenv("XPA_TIMESTAMP_ERRORS")) != NULL ) + etimestamp = istrue(s); + /* check for xpans register flag */ + if( (s=(char *)getenv("XPA_NSREGISTER")) != NULL ) + nsregister = istrue(s); + /* check for use of siguser1 */ + if( (s=(char *)getenv("XPA_SIGUSR1")) != NULL ) + sigusr1 = istrue(s); + /* check for version checking */ + if( (s=(char *)getenv("XPA_VERSIONCHECK")) != NULL ){ + if( istrue(s) ) + vercheck = 1; + else if( isfalse(s) ) + vercheck = 0; + else + vercheck = atoi(s); + } + /* check for io loop calling xpa */ + if( (s=(char *)getenv("XPA_IOCALLSXPA")) != NULL ){ + if( istrue(s) ){ + XPAIOCallsXPA(1); + } + else if( isfalse(s) ){ + XPAIOCallsXPA(0); + } + } + /* make sure we have a temp dir */ + if( tmpdir == NULL ){ + if( (s=(char *)getenv("XPA_TMPDIR")) != NULL ) + tmpdir = xstrdup(s); + else if( (s=(char *)getenv("TMPDIR")) != NULL ) + tmpdir = xstrdup(s); + else if( (s=(char *)getenv("TMP")) != NULL ) + tmpdir = xstrdup(s); + else + tmpdir = xstrdup(XPA_TMPDIR); + } + /* create directory, if necessary */ + xmkdir(tmpdir, 0777); + xchmod(tmpdir, 0777); +#if HAVE_MINGW32==0 + /* Disable SIGPIPE so we do not die if the client dies. + * Rather, we will get an EOF on reading or writing. + */ + xsignal_sigpipe(); +#endif + /* platform-dependent startup */ + xsocketstartup(); + } +} + +/* + *---------------------------------------------------------------------------- + * + * Routine: XPANSAdd + * + * Purpose: add this XPA to the name service + * + * Returns: 0 on success, -1 on failure + * + *---------------------------------------------------------------------------- + */ +#ifdef ANSI_FUNC +int +XPANSAdd (XPA xpa, char *host, char *mode) +#else +int XPANSAdd(xpa, host, mode) + XPA xpa; + char *host; + char *mode; +#endif +{ + char username[SZ_LINE]; + char tbuf[SZ_LINE]; + char xmode[SZ_LINE]; + char *cmd="add"; + char *s; + NS ns; + struct passwd *pw; + + /* sanity check */ + if( !xpa ) + return(0); + + /* handle special case of the name server itself -- its a known entry */ + if( !strcmp(xpa->name, XPANS_NAME) ){ + return(0); + } + + /* look for the proxy=<true|false> string */ + if( mode ){ + strncpy(xmode, mode, SZ_LINE-1); + xmode[SZ_LINE-1] = '\0'; + if( keyword(xmode, "proxy", tbuf, SZ_LINE) && istrue(tbuf) ){ + cmd="addproxy"; + } + } + + /* open a connection to the name service */ + if( (ns=XPANSOpen(xpa, host, 1)) != NULL ){ + /* get the user name, from the environment */ + if( (s=(char *)getenv("XPA_LOGNAME")) != NULL ) + strncpy(username, s, SZ_LINE-1); + else if( (s=(char *)getenv("LOGNAME")) != NULL ) + strncpy(username, s, SZ_LINE-1); +#if HAVE_MINGW32==0 + /* this is a last resort */ + else if( (pw=getpwuid(geteuid())) ) + strncpy(username, pw->pw_name, SZ_LINE-1); +#endif + /* if nothing good has happened, make it "unknown" */ + if( *username == '\0' ) + strcpy(username, "unknown"); + /* null-terminate string */ + username[SZ_LINE-1] = '\0'; + + /* write the command to add this xpa */ + snprintf(tbuf, SZ_LINE, "%s %s %s:%s %s %s\n", + cmd, xpa->method, xpa->xclass, xpa->name, xpa->type, username); + if( XPAPuts(xpa, ns->fd, tbuf, stimeout) < 0 ){ + return(-1); + } + /* get result */ + if( XPAGets(xpa, ns->fd, tbuf, SZ_LINE, stimeout) >0 ){ + if( !strncmp(tbuf, "XPA$OK", 6) ){ + /* for proxy, we now must listen for xpa requests on this ns */ + if( !strcmp(cmd, "addproxy") && xpa ){ + if( CommNew(xpa, ns->fd, ns->ip, ns->port, ns->name, ns) ){ + /* one more proxy is using this name server */ + ns->nproxy += 1; + } + } + else{ + /* one more access point is using this name server */ + ns->nxpa += 1; + } + return(0); + } + else if( !strncmp(tbuf, "XPA$EXISTS", 10) ) + return(0); + else + return(-1); + } + else{ + return(-1); + } + } + else{ + return(-1); + } +} + +/* + *---------------------------------------------------------------------------- + * + * Routine: XPANSDel + * + * Purpose: remove public knowledge of this XPA from the name service + * + * Returns: none + * + *---------------------------------------------------------------------------- + */ +#ifdef ANSI_FUNC +int +XPANSDel (XPA xpa, char *host, char *mode) +#else +int XPANSDel(xpa, host, mode) + XPA xpa; + char *host; + char *mode; +#endif +{ + int got=0; + char tbuf[SZ_LINE]; + char xmode[SZ_LINE]; + char *cmd="del"; + NS ns; + + /* sanity check */ + if( !xpa ) + return(0); + + /* handle special case of the name server itself -- its a known entry */ + if( xpa->name && !strcmp(xpa->name, XPANS_NAME) ){ + return(0); + } + + /* if there is no method, just return */ + if( (xpa->method == NULL) || (*xpa->method == '\0') ){ + return(0); + } + + /* look for the proxy=<true|false> string */ + if( mode ){ + strncpy(xmode, mode, SZ_LINE-1); + xmode[SZ_LINE-1] = '\0'; + if( keyword(xmode, "proxy", tbuf, SZ_LINE) && istrue(tbuf) ){ + cmd="delproxy"; + } + } + + /* open a connection to the name service */ + if( (ns=XPANSOpen(xpa, host, -1)) != NULL ){ + /* write the command to delete this xpa */ + snprintf(tbuf, SZ_LINE, "%s %s\n", cmd, xpa->method); + XPAPuts(xpa, ns->fd, tbuf, stimeout); + /* get result */ + if( XPAGets(xpa, ns->fd, tbuf, SZ_LINE, stimeout) >0 ){ + if( !strncmp(tbuf, "XPA$OK", 6) ){ + /* one less access point is using this name server */ + ns->nxpa -= 1; + /* if there are no more access points using this xpans, close it */ + if( !ns->nxpa && !ns->nproxy ){ + XPANSClose(xpa, ns); + } + } + else{ + got = -1; + } + } + else{ + got = -1; + } + } + else + got = -1; + return(got); +} + +/* + *---------------------------------------------------------------------------- + * + * Routine: XPAVersionCheck + * + * Purpose: check our version vs. xpans version + * + * Returns: -1,0,1 for our<=>xpans + * + *---------------------------------------------------------------------------- + */ +#ifdef ANSI_FUNC +int +XPAVersionCheck (char *serv, char *nsv) +#else +int XPAVersionCheck(serv, nsv) + char *serv; + char *nsv; +#endif +{ + int i; + int ip1=0; + int ip2=0; + int v1=0; + int v2=0; + int got=0; + int vsize=2; + char s1[SZ_LINE]; + char s2[SZ_LINE]; + + /* return if not checking version */ + if( vercheck <=0 ) + return(0); + /* if either does not exist, its a mismatch */ + if( !word(serv, s1, &ip1) || !word(nsv, s2, &ip2) ) + return(1); + /* if strings are equal, versions are equal */ + if( !strcasecmp(s1, s2) ) + return(0); + + /* format for version is maj.min.patch[be]beta */ + newdtable(".be"); + /* we check only the major and minor version for incompatibilities */ + for(i=0; i<vsize; i++){ + if( !word(serv, s1, &ip1) || !word(nsv, s2, &ip2) ){ + break; + } + v1 = atoi(s1); + v2 = atoi(s2); + if( v1 > v2 ){ + got = 1; + break; + } + if( v1 < v2 ){ + got = -1; + break; + } + } + + freedtable(); + return(got); +} + +/* + *---------------------------------------------------------------------------- + * + * Routine: XPAVersionWarn + * + * Purpose: warn about mismatched versions + * + * Returns: NONE + * + *---------------------------------------------------------------------------- + */ +#ifdef ANSI_FUNC +void +XPAVersionWarn (char *serv, char *nsv) +#else +void XPAVersionWarn(serv, nsv) + char *serv; + char *nsv; +#endif +{ + /* return if not checking version */ + if( vercheck <=0 ) + return; + + /* output warning */ + fprintf(stderr, + "XPA$WARNING: version mismatch detected between XPA-enabled server (%s)\n", serv?serv:"unknown"); + fprintf(stderr, "and xpans (%s).", nsv?nsv:"unknown"); + fprintf(stderr, " You probably will get bad results.\n"); + fprintf(stderr, "Please consider updating XPA to match the XPA-enabled server you are running.\n"); + + /* we did it */ + vercheck--; +} + +/* + *---------------------------------------------------------------------------- + * + * + * Public Routines + * + * + *---------------------------------------------------------------------------- + */ + +/* + *---------------------------------------------------------------------------- + * + * Routine: XPAMethod + * + * Purpose: return communication method type + * + * Returns: XPA__INET, XPA_UNIX + * + *---------------------------------------------------------------------------- + */ +#ifdef ANSI_FUNC +int +XPAMethod (char *method) +#else +int XPAMethod(method) + char *method; +#endif +{ + char *s1; + + /* if no method is passed, we return the default method type */ + if( method == NULL ){ + if( mtype == 0 ){ + s1 = (char *)getenv("XPA_METHOD"); + if( s1 == NULL ) + mtype = XPA_INET; + else if( !strcasecmp(s1, "inet") ) + mtype = XPA_INET; + else if( !strcasecmp(s1, "localhost") ){ + mtype = XPA_INET; + use_localhost = 1; + } + else if( !strcasecmp(s1, "unix") ){ +#if HAVE_SYS_UN_H + mtype = XPA_UNIX; +#else + mtype = XPA_INET; + use_localhost = 1; +#endif + } + else if( !strcasecmp(s1, "local") ){ +#if HAVE_SYS_UN_H + mtype = XPA_UNIX; +#else + mtype = XPA_INET; + use_localhost = 1; + +#endif + } + else + mtype = XPA_INET; + } + return(mtype); + } + /* otherwise, we analyze the input method to get the type */ + else{ + /* inet is ip:port, else unix filename */ + if( strchr(method, ':') != NULL ) + return(XPA_INET); + else +#if HAVE_SYS_UN_H + return(XPA_UNIX); +#else + return(XPA_INET); +#endif + } +} + +/* + *---------------------------------------------------------------------------- + * + * Routine: XPANSMethod + * + * Purpose: return string containing name server method + * + * Returns: name server method string + * + *---------------------------------------------------------------------------- + */ + +#ifdef ANSI_FUNC +char * +XPANSMethod (char *host, int flag) +#else +char *XPANSMethod(host, flag) + char *host; + int flag; +#endif +{ + char *s, *t; + char tbuf[SZ_LINE]; + int i; + int ip; + int port; + unsigned int bip; + unsigned short bport; + + switch( XPAMethod(host) ){ + case XPA_INET: + if( (host != NULL) && (*host != '\0') ) + strncpy(nsmethod, host, SZ_LINE-1); + else if( (s=(char *)getenv("XPA_NSINET")) != NULL ) + strncpy(nsmethod, s, SZ_LINE-1); + else + strncpy(nsmethod, XPA_NSINET, SZ_LINE-1); + /* always null-terminate */ + nsmethod[SZ_LINE-1] = '\0'; + /* if flag, we want the XPA access ip and port, not the communication + channel between xpa servers and the name service */ + if( flag ){ + if( (s=strrchr(nsmethod, ':')) != NULL ){ + /* this is where we will overwrite the port */ + t = s+1; + /* get base port for default */ + XPAParseIpPort(nsmethod, &bip, &bport); + newdtable(","); + for(ip=0, i=0; i<=flag; i++){ + if( !word(t, tbuf, &ip) ){ + *tbuf = '\0'; + break; + } + } + freedtable(); + if( *tbuf ) + port = atoi(tbuf); + else + port = bport + flag; + snprintf(t, SZ_LINE, "%d", port); + } + } + break; +#if HAVE_SYS_UN_H + case XPA_UNIX: + if( host != NULL ) + strncpy(nsmethod, host, SZ_LINE-1); + else if( (s=(char *)getenv("XPA_NSUNIX")) != NULL ) + strncpy(nsmethod, s, SZ_LINE-1); + else + snprintf(nsmethod, SZ_LINE, "%s/%s", tmpdir, XPA_NSUNIX); + /* always null-terminate */ + nsmethod[SZ_LINE-1] = '\0'; + /* if flag is set, we are getting the XPA access file, not the + socket file and we have to change the name slightly */ + if( flag ){ + /* replace the ending, if possible */ + s = strrchr(nsmethod, '.'); + t = strrchr(nsmethod, '/'); + if( (s != NULL) && (s > t) ) + *s = '\0'; + snprintf(tbuf, SZ_LINE, ".xpa-%d", flag); + strcat(nsmethod, tbuf); + } + break; +#endif + default: + if( (s=(char *)getenv("XPA_NSINET")) != NULL ) + strncpy(nsmethod, s, SZ_LINE-1); + else + strncpy(nsmethod, XPA_NSINET, SZ_LINE-1); + /* always null-terminate */ + nsmethod[SZ_LINE-1] = '\0'; + break; + } + + /* return the static method string */ + return(nsmethod); +} + +/* + *---------------------------------------------------------------------------- + * + * Routine: XPAParseName + * + * Purpose: split the xpaname into a class and name string + * + * Results: none + * + *---------------------------------------------------------------------------- + */ +#ifdef ANSI_FUNC +void +XPAParseName (char *xpaname, char *xclass, char *name, int len) +#else +void XPAParseName(xpaname, xclass, name, len) + char *xpaname; + char *xclass; + char *name; + int len; +#endif +{ + char *s; + char *t; + char *cptr=NULL; + char *nptr=NULL; + + /* if nothing is passed to us, allow everything */ + if( (xpaname == NULL) || (*xpaname == '\0') ){ + strncpy(xclass, "*", len-1); + strncpy(name, "*", len-1); + return; + } + + /* split the xpaname into class and name */ + s = xstrdup(xpaname); + if( (t=(char *)strchr(s, ':')) != NULL ){ + cptr = s; + *t = '\0'; + nptr = t+1; + } + else{ + nptr = s; + cptr = "*"; + } + if( *cptr == '\0' ) + cptr = "*"; + if( *nptr == '\0' ) + nptr = "*"; + + strncpy(xclass, cptr, len-1); + strncpy(name, nptr, len-1); + xfree(s); +} + +/* + *---------------------------------------------------------------------------- + * + * Routine: XPAParseIpPort + * + * Purpose: split the host into ip and port + * + * Results: none + * + *---------------------------------------------------------------------------- + */ +#ifdef ANSI_FUNC +int +XPAParseIpPort (char *host, unsigned int *ip, unsigned short *port) +#else +int XPAParseIpPort(host, ip, port) + char *host; + unsigned int *ip; + unsigned short *port; +#endif +{ + char *s1, *s2, *s3, *p1, *p2; + int got; + + /* make sure we have something to work with */ + if( (host == NULL) || (*host == '\0') ) + return(0); + + /* parse up the string and look for a port number (which is essential) */ + s1 = xstrdup(host); + /* if we have a ",", null it out since what comes after is aux info */ + if( (p1 = (char *)strchr(s1, ',')) != NULL ){ + *p1 = '\0'; + } + /* if we have a ":", we will null it out (so that what comes before is + the host name) and bump past it to point to the port */ + if( (p1 = (char *)strchr(s1, ':')) == NULL ){ + /* there is no ":", so the whole string is the port */ + p1 = s1; + s2 = NULL; + } else { + /* null out ':' and bump port pointer */ + *p1 = '\0'; + p1++; + s2 = s1; + } + + /* get port */ + p2 = NULL; + if( p1 && !strcmp(p1, "$port") ) + *port = XPA_NSPORT; + /* NB: port number might be followed by other stuff */ + else + *port = (unsigned short)strtol(p1, &p2, 0); + /* check for bad port number -- we lose */ + if( *port <=0 || (p1 == p2) || (p2 && (*p2 != '\0')) ){ + *ip = 0; + *port = 0; + got = 0; + goto done; + } + + /* get ip */ + if( s2 && *s2 ){ + /* see if this already is a hex address in network byte order */ + *ip = strtoul16(s2, &s3); + if( *s3 == '\0' ){ + got = 1; + goto done; + } + } + /* not hex or proxy -- convert ip string to an ip address */ + if( (*ip = gethostip(s2)) == 0 ){ + *port = 0; + got = 0; + } + else{ + got = 1; + } + +done: + xfree(s1); + return(got); +} + +/* + *---------------------------------------------------------------------------- + * + * Routine: XPAParseUnixSocket + * + * Purpose: see if host is actually a unix socket file + * + * Results: 1 if its a socket, 0 otherwise + * + *---------------------------------------------------------------------------- + */ +#ifdef ANSI_FUNC +int +XPAParseUnixSocket (char *host) +#else +int XPAParseUnixSocket(host) + char *host; +#endif +{ + struct stat buf; + + /* see if its a file in the right directory */ + if( !strncmp(host, tmpdir, strlen(tmpdir)) && + !stat(host, &buf) ){ + return(1); + } + else{ + return(0); + } +} + +/* + *---------------------------------------------------------------------------- + * + * Routine: XPAOK + * + * Purpose: send an XPA OK message to the client + * + * Returns: 0 on success, -1 on error + * + *---------------------------------------------------------------------------- + */ +#ifdef ANSI_FUNC +int +XPAOK (XPA xpa) +#else +int XPAOK(xpa) + XPA xpa; +#endif +{ + int len; + int status=0; + char tbuf[SZ_LINE]; + + /* make sure we have a valid struct */ + if( (xpa == NULL) || (xpa_cmdfd(xpa) <0) ) + return(-1); + + /* send message, if necessary */ + if( !(xpa_status(xpa) & XPA_STATUS_ACTIVE) || (xpa_ack(xpa) == 1) ){ + snprintf(tbuf, SZ_LINE, "%s XPA$OK (%s:%s %s)\n", + xpa_id(xpa), xpa_class(xpa), xpa_name(xpa), xpa_method(xpa)); + len = strlen(tbuf); + if( XPAPuts(xpa, xpa_cmdfd(xpa), tbuf, stimeout) != len ){ + status = -1; + } + } + + /* flag that there was a message sent for this xpa */ + xpa->comm->message = 1; + + /* return status */ + return(status); +} + +/* + *---------------------------------------------------------------------------- + * + * Routine: XPATimestamp + * + * Purpose: generate string with current date/time + * + * Returns: time string (in static buffer) + * + *---------------------------------------------------------------------------- + */ +#ifdef ANSI_FUNC +char * +XPATimestamp(void) +#else +char *XPATimestamp() +#endif +{ + time_t t; + struct tm *lt; + + *ctimebuf = '\0'; + if( etimestamp ){ + if( (t = time(NULL)) != (time_t)-1 ){ + if( (lt = localtime(&t)) != NULL ){ + snprintf(ctimebuf, SZ_LINE, " %02d/%02d/%d:%d:%d:%d", + lt->tm_mday, lt->tm_mon+1, lt->tm_year+1900, + lt->tm_hour, lt->tm_min, lt->tm_sec); + } + } + } + return ctimebuf; +} + +/* + *---------------------------------------------------------------------------- + * + * Routine: XPAError + * + * Purpose: send an XPA error message to the client + * + * Returns: none + * + *---------------------------------------------------------------------------- + */ +#ifdef ANSI_FUNC +int +XPAError (XPA xpa, char *s) +#else +int XPAError(xpa, s) + XPA xpa; + char *s; +#endif +{ + int status=0; + int ip=0; + char tbuf[SZ_LINE]; + char *t; + char *u; + + /* make sure we have a valid struct */ + if( (xpa == NULL) || (xpa_cmdfd(xpa) <0) ) + return(-1); + + /* send message, if necessary */ + if( !(xpa_status(xpa) & XPA_STATUS_ACTIVE) || (xpa_ack(xpa) == 1) ){ + t = xstrdup(s); + /* get rid of CR in message -- we add one at the end */ + nowhite(t, t); + if( !strncmp(t, "XPA$", 4) ) + word(t, tbuf, &ip); + u = (char *)xcalloc(strlen(t)+SZ_LINE, sizeof(char)); + /* package up and write the message */ + snprintf(u, SZ_LINE, "%s XPA$ERROR %s (%s:%s %s%s)\n", + xpa_id(xpa), + &t[ip], xpa_class(xpa), xpa_name(xpa), xpa_method(xpa), + XPATimestamp()); + if( XPAPuts(xpa, xpa_cmdfd(xpa), u, stimeout) != (int)strlen(u) ){ + status = -1; + } + if( t ) + xfree(t); + if( u ) + xfree(u); + } + + /* flag that there was a message sent for this xpa */ + xpa->comm->message = 1; + + /* return status */ + return(status); +} + +/* + *---------------------------------------------------------------------------- + * + * Routine: XPAMessage + * + * Purpose: send an XPA message to the client + * + * Returns: 0 on success, -1 on error + * + *---------------------------------------------------------------------------- + */ +#ifdef ANSI_FUNC +int +XPAMessage (XPA xpa, char *s) +#else +int XPAMessage(xpa, s) + XPA xpa; + char *s; +#endif +{ + int status=0; + int ip=0; + char tbuf[SZ_LINE]; + char *t; + char *u; + + /* make sure we have a valid struct */ + if( (xpa == NULL) || (xpa_cmdfd(xpa) <0) ) + return(-1); + + /* send message, if necessary */ + if( !(xpa_status(xpa) & XPA_STATUS_ACTIVE) || (xpa_ack(xpa) == 1) ){ + t = xstrdup(s); + /* get rid of CR in message -- we add one at the end */ + nowhite(t, t); + if( !strncmp(t, "XPA$", 4) ) + word(t, tbuf, &ip); + u = (char *)xcalloc(strlen(t)+SZ_LINE, sizeof(char)); + /* package up and write the message */ + snprintf(u, SZ_LINE, "%s XPA$MESSAGE %s (%s:%s %s%s)\n", + xpa_id(xpa), + &t[ip], xpa_class(xpa), xpa_name(xpa), xpa_method(xpa), + XPATimestamp()); + if( XPAPuts(xpa, xpa_cmdfd(xpa), u, stimeout) != (int)strlen(u) ){ + status = -1; + } + if( t ) + xfree(t); + if( u ) + xfree(u); + } + + /* flag that there was a message sent for this xpa */ + xpa->comm->message = 1; + + /* return status */ + return(status); +} + +/* + *---------------------------------------------------------------------------- + * + * Routine: XPAArgvParamlist + * + * Purpose: generate a paramlist string from an argv + * + * Results: allocated paramlist string + * + *---------------------------------------------------------------------------- + */ +#ifdef ANSI_FUNC +char * +XPAArgvParamlist (int argc, char **argv, int start) +#else +char *XPAArgvParamlist(argc, argv, start) + int argc; + char **argv; + int start; +#endif +{ + int plen; + int i; + char *paramlist; + + /* get length of paramlist */ + for(plen=0, i=start; i<argc; i++){ + plen += (strlen(argv[i])+1); + } + + /* allocate enough space for it */ + if( (paramlist = (char *)xcalloc(plen+1, sizeof(char))) == NULL ){ + return(NULL); + } + + /* gather up the paramlist */ + for(i=start; i<argc; i++){ + strcat(paramlist, argv[i]); + strcat(paramlist, " "); + } + + /* remove whitespace from beginning and end */ + nowhite(paramlist, paramlist); + + /* return paramlist */ + return(paramlist); +} + +/* + *---------------------------------------------------------------------------- + * + * Routine: XPANSLookup + * + * Purpose: get name server matches + * + * Returns: number of matches + * + *---------------------------------------------------------------------------- + */ +#ifdef ANSI_FUNC +int +XPANSLookup (XPA xpa, char *tname, char *ttype, + char ***xclasses, char ***names, char ***methods, char ***infos) +#else +int XPANSLookup(xpa, tname, ttype, xclasses, names, methods, infos) + XPA xpa; + char *tname; + char *ttype; + char ***xclasses; + char ***names; + char ***methods; + char ***infos; +#endif +{ + unsigned short port; + unsigned int ip; + int own; + int lp=0; + int got=0; + int nentry=100; + char *xtype; + char xclass[SZ_LINE]; + char name[SZ_LINE]; + char method[SZ_LINE]; + char info[SZ_LINE]; + char user[SZ_LINE]; + char type[SZ_LINE]; + char tbuf[SZ_LINE]; + char lbuf[SZ_LINE]; + NS ns; + XPA txpa; + + /* do some initialization */ + XPAInitEnv(); + + /* use "*" as default if no type was specified */ + if( (ttype == NULL) || (*ttype == '\0') ) + xtype = "*"; + /* type 'a' means we are only trying to access */ + else if( *ttype == 'a' ) + xtype = "*"; + else + xtype = ttype; + + /* special case of name server */ + if( !strcmp(tname, XPANS_NAME) ){ + *xclasses = (char **)xmalloc(sizeof(char *)); + *names = (char **)xmalloc(sizeof(char *)); + *methods = (char **)xmalloc(sizeof(char *)); + *infos = (char **)xmalloc(sizeof(char *)); + (*xclasses)[0] = xstrdup(XPANS_CLASS); + (*names)[0] = xstrdup(XPANS_NAME); + (*methods)[0] = xstrdup(XPANSMethod(NULL, 1)); + (*infos)[0] = xstrdup(XPA_DEF_CLIENT_INFO); + return(1); + } + + /* special case of a string containing ip:port -- avoid trip to ns */ + if( XPAParseIpPort(tname, &ip, &port) ){ + *xclasses = (char **)xmalloc(sizeof(char *)); + *names = (char **)xmalloc(sizeof(char *)); + *methods = (char **)xmalloc(sizeof(char *)); + *infos = (char **)xmalloc(sizeof(char *)); + (*xclasses)[0] = xstrdup("?"); + (*names)[0] = xstrdup("?"); + (*methods)[0] = xstrdup(tname); + (*infos)[0] = xstrdup(XPA_DEF_CLIENT_INFO); + return(1); + } + + /* special case of a string containing unix socket -- avoid trip to ns */ + if( XPAParseUnixSocket(tname) ){ + *xclasses = (char **)xmalloc(sizeof(char *)); + *names = (char **)xmalloc(sizeof(char *)); + *methods = (char **)xmalloc(sizeof(char *)); + *infos = (char **)xmalloc(sizeof(char *)); + (*xclasses)[0] = xstrdup("?"); + (*names)[0] = xstrdup("?"); + (*methods)[0] = xstrdup(tname); + (*infos)[0] = xstrdup(XPA_DEF_CLIENT_INFO); + return(1); + } + + /* pre-allocate the various arrays to an absurd number */ + *xclasses = (char **)xmalloc(nentry * sizeof(char *)); + *names = (char **)xmalloc(nentry * sizeof(char *)); + *methods = (char **)xmalloc(nentry * sizeof(char *)); + *infos = (char **)xmalloc(nentry * sizeof(char *)); + + /* open a connection to the name service */ + if( (ns=XPANSOpen(xpa, NULL, 0)) != NULL ){ + while( word(tname, lbuf, &lp) ){ + XPAParseName(lbuf, xclass, name, SZ_LINE); + /* write the command to add this xpa */ + snprintf(tbuf, SZ_LINE, "lookup %s:%s %s %s\n", + xclass, name, xtype, nsusers); + FPRINTF((stderr, "%sXPANSLookup: sending command %s", _sp, tbuf)); + XPAPuts(xpa, ns->fd, tbuf, stimeout); + /* read matches from the name server */ + while( 1 ){ + if( XPAGets(xpa, ns->fd, tbuf, SZ_LINE, stimeout) <=0 ){ + FPRINTF((stderr, "%sXPANSLookup: unexpected EOF from xpans\n", _sp)); + break; + } + FPRINTF((stderr, "%sXPANSLookup: receiving %s", _sp, tbuf)); + /* XPA$<result> signals end of input */ + if( !strncmp(tbuf, "XPA$", 4) ) + break; + /* otherwise scan next line */ + if( sscanf(tbuf, "%s %s %s %s %s %s\n", + xclass, name, type, method, user, info) != EOF ){ + /* make sure this entry is not in the current process + (i.e., we can't ever xpa ourselves!) */ + for(own=0, txpa=xpahead; txpa!=NULL; txpa=txpa->next){ + if( !strcmp(txpa->xclass, xclass) && !strcmp(txpa->name, name) && + !strcmp(txpa->method, method) ){ + own = 1; + break; + } + } + /* if this xpa is in the current process, skip it */ + if( own ) + continue; + /* make sure we have enough space */ + if( got >= nentry ){ + nentry *= 2; + *xclasses = (char **)xrealloc(*xclasses, nentry * sizeof(char *)); + *names = (char **)xrealloc(*names, nentry * sizeof(char *)); + *methods = (char **)xrealloc(*methods, nentry * sizeof(char *)); + *infos = (char **)xrealloc(*infos, nentry * sizeof(char *)); + } + /* add this entry to the list */ + (*xclasses)[got] = xstrdup(xclass); + (*names)[got] = xstrdup(name); + (*methods)[got] = xstrdup(method); + (*infos)[got] = xstrdup(info); + got++; + } + } + } + /* if we did not add to an xpa record, close up here */ + if( xpa == NULL ){ + XPANSClose(NULL, ns); + } + } + /* reallocate the exact number of buffers we have */ + if( got > 0 ){ + *xclasses = (char **)xrealloc(*xclasses, got * sizeof(char *)); + *names = (char **)xrealloc(*names, got * sizeof(char *)); + *methods = (char **)xrealloc(*methods, got * sizeof(char *)); + *infos = (char **)xrealloc(*infos, got * sizeof(char *)); + } + else{ + xfree(*xclasses); + xfree(*names); + xfree(*methods); + xfree(*infos); + } + FPRINTF((stderr, "%sXPANSLookup: found %d entries\n", _sp, got)); + return(got); +} + +/* + *---------------------------------------------------------------------------- + * + * Routine: XPANSClose + * + * Purpose: close connection to the name service + * + * Returns: none + * + *---------------------------------------------------------------------------- + */ +#ifdef ANSI_FUNC +int +XPANSClose (XPA xpa, NS ns) +#else +int XPANSClose(xpa, ns) + XPA xpa; + NS ns; +#endif +{ + NS cur; + XPAComm comm, tcomm; + + if( !ns ) + return(-1); + + /* remove from xpa list */ + if( xpa ){ + if( xpa->nshead ){ + if( xpa->nshead == ns ){ + xpa->nshead = ns->next; + } + else{ + for(cur=xpa->nshead; cur!=NULL; cur=cur->next){ + if( cur->next == ns ){ + cur->next = ns->next; + break; + } + } + } + } + /* close comms associated with this ns */ + for(comm=xpa->commhead; comm!=NULL; ){ + tcomm = comm->next; + if( comm->ns == ns ){ + CommFree(xpa, comm, 0); + } + comm = tcomm; + } + } + + /* close socket */ + if( ns->fd >=0 ){ + xclose(ns->fd); + } + /* free up space */ + if( ns->method) xfree(ns->method); + if( ns->host ) xfree(ns->host); + if( ns->name ) xfree(ns->name); + if( ns ) xfree(ns); + return(0); +} + +/* + *---------------------------------------------------------------------------- + * + * Routine: XPANSKeepAlive + * + * Purpose: send a 1-byte keep-alive packet to each name server + * + * Returns: -1 on error, else 1 + * + *---------------------------------------------------------------------------- + */ +#ifdef ANSI_FUNC +int +XPANSKeepAlive (XPA xpa, int type) +#else + int XPANSKeepAlive(xpa, type) + XPA xpa; + int type; +#endif +{ + NS ns; + int got=0; + + /* sanity check */ + if( !xpa ) + return(-1); + + /* use default type, if none specified */ + if( !type ) + type=DEF_KA_TYPE; + + /* send keep-alive to deserving xpans instances */ + for(ns=xpa->nshead; ns!=NULL; ns=ns->next){ + if( ((type&1) && (ns->nxpa>0)) || ((type&2) && (ns->nproxy>0)) ){ + FPRINTF((stderr, "%sXPANSKeepAlive: sending ka to %d\n", _sp, ns->fd)); +#if USE_KA_OOB + /* send as out of band data to avoid mixing with normal data stream */ + got = send(ns->fd, "\n", 1, MSG_OOB); +#else + /* cisco routers can clear the URG flag by default, so use in-band */ + got = send(ns->fd, "\n", 1, 0); +#endif + } + } + return(got); +} + +/* + *---------------------------------------------------------------------------- + * + * Routine: XPANew + * + * Purpose: add a new xpa name to a process to allow external + * process to read/write data associated with this name. + * + * If the send callback is defined, it can send to an external process. + * If the receive callback is defined, it can receive from an external process. + * + * Returns: xpa handle associated with this class.name or NULL + * + *---------------------------------------------------------------------------- + */ +#ifdef ANSI_FUNC +XPA +XPANew (char *xclass, char *name, char *help, + SendCb send_callback, void *send_data, char *send_mode, + ReceiveCb rec_callback, void *rec_data, char *rec_mode) +#else +XPA XPANew(xclass, name, help, + send_callback, send_data, send_mode, + rec_callback, rec_data, rec_mode) + char *xclass; + char *name; + char *help; + SendCb send_callback; + void *send_data; + char *send_mode; + ReceiveCb rec_callback; + void *rec_data; + char *rec_mode; +#endif +{ + unsigned short port; + unsigned int ip; + int got; + int oum; + int keep_alive=1; + int reuse_addr=1; + char tbuf[SZ_LINE]; + char tbuf2[SZ_LINE]; + char tfile[SZ_LINE]; + char *tfptr; + XPA xpa; + socklen_t slen = sizeof(struct sockaddr_in); + struct sockaddr_in sock_in; +#if HAVE_SYS_UN_H + struct sockaddr_un sock_un; +#endif + + /* do some initialization */ + XPAInitEnv(); + /* init the list of reserved commands */ + XPAInitReserved(); + + /* we need a name, but no ":" allowed in the name */ + if( (name == NULL) || (*name == '\0') || strchr(name, ':') ) + return(NULL); + + /* limit the size of the xclass and name designation */ + if( xclass && *xclass && (strlen(xclass) > XPA_NAMELEN) ){ + if( verbosity ) + fprintf(stderr, "XPA$ERROR: class designator too long\n"); + return(NULL); + } + if( strlen(name) > XPA_NAMELEN ){ + if( verbosity ) + fprintf(stderr, "XPA$ERROR: name designator too long\n"); + return(NULL); + } + + /* we need either a send or a receive or both */ + if( (send_callback == NULL) && (rec_callback == NULL ) ){ + if( verbosity ) + fprintf(stderr, "XPA$ERROR: requires send and/or receive callback\n"); + return(NULL); + } + + /* allocate xpa struct */ + if( (xpa = (XPA)xcalloc(1, sizeof(XPARec))) == NULL ) + return(NULL); + + /* fill in the blanks */ + xpa->version = xstrdup(XPA_VERSION); + xpa->type = (char *)xcalloc(10, sizeof(char)); + if( xclass && *xclass ) + xpa->xclass = xstrdup(xclass); + else + xpa->xclass = xstrdup("*"); + xpa->name = xstrdup(name); + xpa->help = xstrdup(help); + /* set the value of the server big-endian-ness */ + xpa->sendian = XPAEndian() ? xstrdup("big") : xstrdup("little"); + + /* fill in send information */ + if( send_callback != NULL ){ + xpa->send_callback = send_callback; + xpa->send_data = send_data; + strcat(xpa->type, "g"); + /* process the mode string */ + xpa->send_mode = XPA_DEF_MODE_SEND; + XPAMode(send_mode, &(xpa->send_mode), "freebuf", XPA_MODE_FREEBUF,1); + XPAMode(send_mode, &(xpa->send_mode), "acl", XPA_MODE_ACL, 1); + } + + /* fill in receive information */ + if( rec_callback != NULL ){ + xpa->receive_callback = rec_callback; + xpa->receive_data = rec_data; + strcat(xpa->type, "s"); + /* process the mode string */ + xpa->receive_mode = XPA_DEF_MODE_REC; + XPAMode(rec_mode, &(xpa->receive_mode), "buf", XPA_MODE_BUF, 1); + XPAMode(rec_mode, &(xpa->receive_mode), "fillbuf", XPA_MODE_FILLBUF, 1); + XPAMode(rec_mode, &(xpa->receive_mode), "freebuf", XPA_MODE_FREEBUF, 1); + XPAMode(rec_mode, &(xpa->receive_mode), "acl", XPA_MODE_ACL, 1); + } + + /* set up communication method */ + switch(mtype){ + case XPA_INET: + /* open a socket and fill in socket information */ + if( (xpa->fd = xsocket(AF_INET, SOCK_STREAM, 0)) < 0 ) + goto error; + setsockopt(xpa->fd, SOL_SOCKET, SO_KEEPALIVE, + (char *)&keep_alive, sizeof(keep_alive)); + setsockopt(xpa->fd, SOL_SOCKET, SO_REUSEADDR, + (char *)&reuse_addr, sizeof(reuse_addr)); + memset((char *)&sock_in, 0, sizeof(sock_in)); + sock_in.sin_family = AF_INET; + /* localhost only */ + if( use_localhost ) + sock_in.sin_addr.s_addr = htonl(gethostip("$localhost")); + /* any address will do */ + else + sock_in.sin_addr.s_addr = htonl(INADDR_ANY); + /* handle special case of xpans port */ + if( !strcmp(xpa->name, XPANS_NAME) ){ + XPAParseIpPort(XPANSMethod(NULL, 1), &ip, &port); + sock_in.sin_port = htons(port); + } + else{ + sock_in.sin_port = htons(XPAPort(xpa)); + } + /* bind to the ip:port */ + if( xbind(xpa->fd, (struct sockaddr *)&sock_in, sizeof(sock_in)) < 0 ) + goto error; + /* we now can determine which port the system assigned */ + if( getsockname(xpa->fd, (struct sockaddr *)&sock_in, &slen) < 0 ) + goto error; + else{ + /* ip:port is the method */ + gethost(tbuf2, SZ_LINE); + snprintf(tbuf, SZ_LINE, "%x:%d", + gethostip(tbuf2), ntohs(sock_in.sin_port)); + xpa->method = xstrdup(tbuf); + } + break; +#if HAVE_SYS_UN_H + case XPA_UNIX: + /* open a socket and fill in socket information */ + if( (xpa->fd = xsocket(AF_UNIX, SOCK_STREAM, 0)) < 0 ) + goto error; + setsockopt(xpa->fd, SOL_SOCKET, SO_KEEPALIVE, + (char *)&keep_alive, sizeof(keep_alive)); + setsockopt(xpa->fd, SOL_SOCKET, SO_REUSEADDR, + (char *)&reuse_addr, sizeof(reuse_addr)); + memset((char *)&sock_in, 0, sizeof(sock_in)); + sock_un.sun_family = AF_UNIX; + /* handle special case of xpans */ + if( !strcmp(xpa->name, XPANS_NAME) ){ + strcpy(tbuf, XPANSMethod(NULL, 1)); + } + else{ + /* get filename part, composed of class and name and unique id */ + snprintf(tfile, SZ_LINE, "%s_%s.%d", + xpa->xclass, xpa->name, (int)getpid()); + /* change "/" to "_" for filename */ + for(tfptr = tfile; *tfptr != '\0'; tfptr++){ + if( *tfptr == '/' ) + *tfptr = '_'; + } + /* create full pathname */ + snprintf(tbuf, SZ_LINE, "%s/%s", tmpdir, tfile); + } + /* delete old copy */ + unlink (tbuf); + strcpy(sock_un.sun_path, tbuf); + /* unset umask so that everyone can read and write */ + oum = umask(0); + /* bind to the file */ + got = xbind(xpa->fd, (struct sockaddr *)&sock_un, sizeof(sock_un)); + /* reset umask */ + umask(oum); + /* now check for bind error */ + if( got < 0 ) + goto error; + /* path is the method */ + xpa->method = xstrdup(tbuf); + break; +#endif + default: + goto error; + } + + /* listen for connections */ + if( listen(xpa->fd, XPA_MAXLISTEN) < 0 ) + goto error; + + /* make sure we close on exec */ + xfcntl(xpa->fd, F_SETFD, FD_CLOEXEC); + + /* add this xpa to end of list of xpas */ + XPAListAdd(&xpahead, xpa); + + /* publish this entry to the world */ + if( nsregister ) + XPANSAdd(xpa, NULL, NULL); + + /* make it active */ + XPAActive(xpa, NULL, 1); + +#if NO_AUTOMATIC_HAVE_ATEXIT + /* register XPA atexit funtion */ + if( !atexitinit ){ + atexit(_XPAAtExit); + atexitinit = getpid(); + } +#endif + + /* return good news */ + return(xpa); + +error: + if( verbosity ){ + perror("XPANew"); + } + _XPAFree(xpa); + return(NULL); +} + +/* + *--------------------------------------------------------------------------- + * + * Routine: XPAFree + * + * Purpose: free up alloc'ed memory in the XPA record structure + * + * Results: 0 on success, -1 for failure + * + *--------------------------------------------------------------------------- + */ +#ifdef ANSI_FUNC +int +XPAFree (XPA xpa) +#else +int XPAFree(xpa) + XPA xpa; +#endif +{ + /* if status is active, just flag eventual need to free and exit */ + if( _XPAValid(xpahead, xpa, XPA_ACLS) ){ + if( xpa_status(xpa) & XPA_STATUS_ACTIVE ){ + xpa->status |= XPA_STATUS_FREE; + FPRINTF((stderr, "%sXPAFree: marking xpa struct for later free'ing\n", + _sp)); + return(0); + } + else{ + /* call the primitive routine */ + FPRINTF((stderr, "%sXPAFree: freeing xpa struct\n", _sp)); + return(_XPAFree(xpa)); + } + } + else{ + return(-1); + } +} + +/* + *---------------------------------------------------------------------------- + * + * Routine: XPAInfoNew + * + * Purpose: add a new xpa name to a process to allow external + * process to send info messages + * + + * Returns: xpa handle associated with this class.name or NULL + * + *---------------------------------------------------------------------------- + */ +#ifdef ANSI_FUNC +XPA +XPAInfoNew (char *xclass, char *name, + InfoCb info_callback, void *info_data, char *info_mode) +#else +XPA XPAInfoNew(xclass, name, info_callback, info_data, info_mode) + char *xclass; + char *name; + InfoCb info_callback; + void *info_data; + char *info_mode; +#endif +{ + int got; + int oum; + int keep_alive=1; + int reuse_addr=1; + char tbuf[SZ_LINE]; + char tbuf2[SZ_LINE]; + char tfile[SZ_LINE]; + char *tfptr; + XPA xpa; + socklen_t slen = sizeof(struct sockaddr_in); + struct sockaddr_in sock_in; +#if HAVE_SYS_UN_H + struct sockaddr_un sock_un; +#endif + + /* do some initialization */ + XPAInitEnv(); + /* init the list of reserved commands */ + XPAInitReserved(); + + /* we need a name, but no ":" allowed in the name */ + if( (name == NULL) || (*name == '\0') || strchr(name, ':') ) + return(NULL); + + /* we need an info callback */ + if( info_callback == NULL ){ + if( verbosity ){ + fprintf(stderr, "XPA$ERROR: requires info callback\n"); + } + return(NULL); + } + + /* allocate xpa struct */ + if( (xpa = (XPA)xcalloc(1, sizeof(XPARec))) == NULL ) + return(NULL); + + xpa->version = xstrdup(XPA_VERSION); + xpa->type = (char *)xcalloc(10, sizeof(char)); + /* fill in the blanks */ + if( xclass != NULL ) + xpa->xclass = xstrdup(xclass); + else + xpa->xclass = xstrdup("*"); + xpa->name = xstrdup(name); + + /* fill in send information */ + xpa->info_callback = info_callback; + xpa->info_data = info_data; + strcat(xpa->type, "i"); + /* process the mode string */ + xpa->info_mode = XPA_DEF_MODE_INFO; + XPAMode(info_mode, &(xpa->info_mode), "acl", XPA_MODE_ACL, 1); + + /* set up communication method */ + switch(mtype){ + case XPA_INET: + /* open a socket and fill in socket information */ + if( (xpa->fd = xsocket(AF_INET, SOCK_STREAM, 0)) < 0 ) + goto error; + setsockopt(xpa->fd, SOL_SOCKET, SO_KEEPALIVE, + (char *)&keep_alive, sizeof(keep_alive)); + setsockopt(xpa->fd, SOL_SOCKET, SO_REUSEADDR, + (char *)&reuse_addr, sizeof(reuse_addr)); + memset((char *)&sock_in, 0, sizeof(sock_in)); + sock_in.sin_family = AF_INET; + /* localhost only */ + if( use_localhost ) + sock_in.sin_addr.s_addr = htonl(gethostip("$localhost")); + /* any address will do */ + else + sock_in.sin_addr.s_addr = htonl(INADDR_ANY); + sock_in.sin_port = htons(XPAPort(xpa)); + /* bind to the ip:port */ + if( xbind(xpa->fd, (struct sockaddr *)&sock_in, sizeof(sock_in)) < 0 ) + goto error; + /* we now can determine which port the system assigned */ + if( getsockname(xpa->fd, (struct sockaddr *)&sock_in, &slen) < 0 ) + goto error; + else{ + /* ip:port is the method */ + gethost(tbuf2, SZ_LINE); + snprintf(tbuf, SZ_LINE, "%x:%d", + gethostip(tbuf2), ntohs(sock_in.sin_port)); + xpa->method = xstrdup(tbuf); + } + break; +#if HAVE_SYS_UN_H + case XPA_UNIX: + /* get filename part, composed of class and name and unique id */ + snprintf(tfile, SZ_LINE, "%s_%s.%d", + xpa->xclass, xpa->name, (int)getpid()); + /* change "/" to "_" for filename */ + for(tfptr = tfile; *tfptr != '\0'; tfptr++){ + if( *tfptr == '/' ) + *tfptr = '_'; + } + /* create full pathname */ + snprintf(tbuf, SZ_LINE, "%s/%s", tmpdir, tfile); + /* delete old copy */ + unlink (tbuf); + /* open a socket and fill in socket information */ + if( (xpa->fd = xsocket(AF_UNIX, SOCK_STREAM, 0)) < 0 ) + goto error; + setsockopt(xpa->fd, SOL_SOCKET, SO_KEEPALIVE, + (char *)&keep_alive, sizeof(keep_alive)); + memset((char *)&sock_in, 0, sizeof(sock_in)); + sock_un.sun_family = AF_UNIX; + strcpy(sock_un.sun_path, tbuf); + /* unset umask so that everyone can read and write */ + oum = umask(0); + /* bind to the file */ + got = xbind(xpa->fd, (struct sockaddr *)&sock_un, sizeof(sock_un)); + /* reset umask */ + umask(oum); + /* now check for bind error */ + if( got < 0 ) + goto error; + /* path is the method */ + xpa->method = xstrdup(tbuf); + break; +#endif + default: + goto error; + } + + /* listen for connections */ + if( listen(xpa->fd, XPA_MAXLISTEN) < 0 ) + goto error; + + /* make sure we close on exec */ + xfcntl(xpa->fd, F_SETFD, FD_CLOEXEC); + + /* add this xpa to end of list of xpas */ + XPAListAdd(&xpahead, xpa); + + /* publish this entry to the world */ + if( nsregister ) + XPANSAdd(xpa, NULL, NULL); + + /* make it active */ + XPAActive(xpa, NULL, 1); + +#if NO_AUTOMATIC_HAVE_ATEXIT + /* register XPA atexit funtion */ + if( !atexitinit ){ + atexit(_XPAAtExit); + atexitinit = getpid(); + } +#endif + + /* return good news */ + return(xpa); + +error: + XPAFree(xpa); + return(NULL); +} + +/* + *---------------------------------------------------------------------------- + * + * Routine: XPAPoll + * + * Purpose: non-blocking handling of XPA access points + * timeout in millisecs, but if negative, no timeout is used + * + * Returns: number of requests processed (if maxreq >=0) + * number of requests pending (if maxreq <0) + * + *---------------------------------------------------------------------------- + */ +#ifdef ANSI_FUNC +int +XPAPoll (int msec, int maxreq) +#else +int XPAPoll(msec, maxreq) + int msec; + int maxreq; +#endif +{ + int sgot; + int got=0; + fd_set readfds; + struct timeval tv; + struct timeval *tvp; + +again: + if( msec >= 0 ){ + tv.tv_sec = msec / 1000; + tv.tv_usec = (msec % 1000) * 1000; + tvp = &tv; + } + /* negative value means just block and wait */ + else{ + tvp = NULL; + } + FD_ZERO(&readfds); + if( XPAAddSelect(NULL, &readfds) ){ + sgot = xselect(swidth, &readfds, NULL, NULL, tvp); + /* error -- what should we do? */ + if( sgot < 0 ){ + if( xerrno == EINTR ) + goto again; + if( verbosity ){ + perror("XPAPoll() select"); + } + exit(1); + } + /* timeout -- just return */ + else if( sgot == 0 ) + ; + /* finally ... something to do */ + else{ + /* if maxreq < 0, just return how many are ready */ + if( maxreq < 0 ) + return(sgot); + else + got = XPAProcessSelect(&readfds, maxreq); + } + } + return(got); +} + +/* + *---------------------------------------------------------------------------- + * + * Routine: XPAMainLoop + * + * Purpose: non-X programs event loop for handling XPA + * + * Returns: none + * + *---------------------------------------------------------------------------- + */ +#ifdef ANSI_FUNC +int +XPAMainLoop (void) +#else +int XPAMainLoop() +#endif +{ + int sgot; + int got=0; + fd_set readfds; + + + FD_ZERO(&readfds); + while( XPAAddSelect(NULL, &readfds) ){ + FPRINTF((stderr, "%sXPAMainLoop: waiting for select() ...\n", _sp)); + sgot = xselect(swidth, &readfds, NULL, NULL, NULL); + FPRINTF((stderr, "%sXPAMainLoop: select() returned: %d\n", _sp, sgot)); + /* error -- what should we do? */ + if( sgot < 0 ){ + if( xerrno == EINTR ){ + FD_ZERO(&readfds); + continue; + } + if( verbosity ){ + perror("XPAMainLoop() select"); + } + exit(1); + } + /* can't happen, since we have no timeout */ + else if( sgot == 0 ) + ; + /* finally ... something to do */ + else + got += XPAProcessSelect(&readfds, 0); + FD_ZERO(&readfds); + } + return(got); +} + +/* + *---------------------------------------------------------------------------- + * + * Routine: XPASleep + * + * Purpose: sleep for specified milliseconds + * + * Returns: none + * + *---------------------------------------------------------------------------- + */ +#ifdef ANSI_FUNC +void +XPASleep (int msec) +#else +void XPASleep(msec) + int msec; +#endif +{ + struct timeval tv; + + if( msec > 0 ){ + tv.tv_sec = msec / 1000; + tv.tv_usec = (msec % 1000) * 1000; + xselect(1, NULL, NULL, NULL, &tv); + } +} + +/* + *---------------------------------------------------------------------------- + * + * Routine: XPAListHead + * + * Purpose: semi-public routine to return the head of the xpa list + * + * Results: XPA list pointer on success + * + *---------------------------------------------------------------------------- + */ +#ifdef ANSI_FUNC +int +XPAMtype (void) +#else +int XPAMtype() +#endif +{ + return(mtype); +} + +/* + *---------------------------------------------------------------------------- + * + * Routine: XPATmpdir + * + * Purpose: semi-public routine to return the tmpdir value + * + * Results: tmpdir + * + *---------------------------------------------------------------------------- + */ +#ifdef ANSI_FUNC +char * +XPATmpdir (void) +#else +char * XPATmpdir() +#endif +{ + return(tmpdir); +} + +/* + *---------------------------------------------------------------------------- + * + * Routine: XPASetBuf + * + * Purpose: set the return buffer in a server send callback + * (use mainly by tcl to transfer tcl buffers to C) + * + * Returns: 0 on success, -1 on failure + * + *---------------------------------------------------------------------------- + */ +#ifdef ANSI_FUNC +int +XPASetBuf (XPA xpa, char *buf, size_t len, int xcopy) +#else +int XPASetBuf(xpa, buf, len, xcopy) + XPA xpa; + char *buf; + size_t len; + int xcopy; +#endif +{ + /* sanity check */ + if( !xpa || !xpa->comm ) + return(-1); + /* xcopy >0 => make a copy of the data, else just assign */ + if( xcopy ){ + xpa->comm->len = len; + if( (xpa->comm->buf = (char *)xmalloc(len)) == NULL ) + return(-1); + memcpy(xpa->comm->buf, buf, len); + } + else{ + xpa->comm->len = len; + xpa->comm->buf = buf; + } + return(0); +} + +/* + *---------------------------------------------------------------------------- + * + * Routine: XPASetBuf + * + * Purpose: set the return buffer in a server send callback + * (use mainly by tcl to transfer tcl buffers to C) + * + * Returns: 0 on success, -1 on failure + * + *---------------------------------------------------------------------------- + */ +#ifdef ANSI_FUNC +int +XPASetFree (XPA xpa, MyFree myfree, void *myfree_ptr) +#else + int XPASetFree(xpa, myfree, myfree_ptr) + XPA xpa; + MyFree myfree; + void *myfree_ptr; +#endif +{ + /* sanity check */ + if( !xpa || !xpa->comm ) return(-1); + /* set the free routine and data pointer */ + xpa->comm->myfree = myfree; + xpa->comm->myfree_ptr = myfree_ptr; + return(0); +} + +/* + *---------------------------------------------------------------------------- + * + * Routine: XPACleanup + * + * Purpose: make valgrind happy by freeing memory + * + * Results: none + * + *---------------------------------------------------------------------------- + */ +#ifdef ANSI_FUNC +void XPACleanup (void) +#else +void XPACleanup () +#endif +{ + XPAFreeReserved(); + XPAAclFree(); + if( tmpdir ){ + xfree(tmpdir); + tmpdir = NULL; + } +} + +#ifdef ANSI_FUNC +void XPASaveJmp(void *env) +#else +void XPASaveJmp(env) + void *env; +#endif +{ +#if HAVE_SETJMP_H + xalloc_savejmp((jmp_buf *)env); +#else + return; +#endif +} diff --git a/xpa/xpa.h b/xpa/xpa.h new file mode 100644 index 0000000..d5e27ab --- /dev/null +++ b/xpa/xpa.h @@ -0,0 +1,556 @@ +/* + * Copyright (c) 1999-2003 Smithsonian Astrophysical Observatory + */ + +/* + * + * xpa.h - include file for the X Public Access mechanism + * + */ + +#ifndef __xpa_h +#define __xpa_h + +#include <stdio.h> +#include <sys/types.h> +#include <prsetup.h> +#if HAVE_MINGW32 +#include <winsock2.h> +#endif + +#define XPA_MAJOR_VERSION 2 +#define XPA_MINOR_VERSION 1 +#define XPA_PATCH_LEVEL 18 +#define XPA_VERSION "2.1.18" + +/* #define XPA_DEBUG 1 */ +#ifdef XPA_DEBUG +#define FPRINTF(x) fprintf x +#define PERROR(x) perror x +#else +#define FPRINTF(x) +#define PERROR(x) +#endif + +/* types of xpa request */ +#define XPA_SET 1 +#define XPA_GET 2 +#define XPA_INFO 3 +#define XPA_ACCESS 4 +/* not actually commands but ... */ +#define XPA_DATA 5 +#define XPA_ACCEPT 6 +#define XPA_NAGLE 7 + +/* this is the number of actual commands we have above */ +#define XPA_CMDS 4 + +/* comm modes */ +#define COMM_RESERVED 1 +#define COMM_CONNECT 2 + +/* the ever-present */ +#ifndef SZ_LINE +#define SZ_LINE 4096 +#endif + +/* limit the length of the name and xclass strings */ +/* at least 2 of these should fit into SZ_LINE with lots of room to spare */ +#define XPA_NAMELEN 1024 + +/* defines the types of callback procedure we use */ +typedef int (*SendCb)( +#ifdef ANSI_FUNC + void *client_data, + void *call_data, + char *paramlist, + char **buf, + size_t *len +#endif +); + +typedef int (*ReceiveCb)( +#ifdef ANSI_FUNC + void *client_data, + void *call_data, + char *paramlist, + char *buf, + size_t len +#endif +); + +typedef int (*InfoCb)( +#ifdef ANSI_FUNC + void *client_data, + void *call_data, + char *paramlist +#endif +); + +typedef void *(*SelAdd)( +#ifdef ANSI_FUNC + void *client_data, + int fd +#endif +); + +typedef void (*SelDel)( +#ifdef ANSI_FUNC + void *client_data +#endif +); + +typedef void (*SelOn)( +#ifdef ANSI_FUNC + void *client_data +#endif +); + +typedef void (*SelOff)( +#ifdef ANSI_FUNC + void *client_data +#endif +); + +typedef void (*MyFree)( +#ifdef ANSI_FUNC + void *buf +#endif +); + +typedef void Sigfunc( +#ifdef ANSI_FUNC + int +#endif +); + +/* + * + * + * xpa access control record structure + * + */ +typedef struct aclrec{ + struct aclrec *next; + char *xclass; + char *name; + unsigned int ip; + char *acl; + int flag; +} *XACL, XACLRec; + +/* + * + * + * port management record structure + * + */ +typedef struct portrec{ + struct portrec *next; + char *xclass; + char *name; + int port; +} *PORT, PORTRec; + +/* + * + * + * xpa name server management + * + */ +typedef struct nsrec{ + struct nsrec *next; + char *method; + int nxpa; + int nproxy; + char *host; + int fd; + FILE *in; + FILE *out; + /* for AF_INET */ + unsigned int ip; + int port; + /* for AF_UNIX */ + char *name; +} *NS, NSRec; + +/* + * + * + * xpa communication structure for each connection + * + */ +typedef struct xpacommrec{ + struct xpacommrec *next; + int status; + int message; + int n; + int cmd; + int mode; + int telnet; + int usebuf; + int useacl; + char *id; + char *info; + char *target; + char *paramlist; + int cmdfd; + int datafd; + char *cendian; + int ack; + /* buf and len passed to callbacks */ + char *buf; + size_t len; + /* for AF_INET */ + unsigned int cmdip; + int cmdport; + int dataport; + /* for AF_UNIX */ + char *cmdname; + char *dataname; + int acl[XPA_CMDS+1]; + /* for handling fd's in non-select event loops */ + void *selcptr; /* cmdfd struct for seldel */ + void *seldptr; /* datafd struct for seldel */ + /* pointer to associated name server */ + struct nsrec *ns; + /* myfree routine */ + MyFree myfree; + void *myfree_ptr; +} *XPAComm, XPACommRec; + +/* + * + * + * clipboard record structure + * + */ +typedef struct cliprec{ + struct cliprec *next; + unsigned int ip; + char *name; + char *value; +} *XPAClip, XPAClipRec; + +/* + * + * record struct for receiving data from stdin + * + */ +typedef struct xpainputrec{ + struct xpainputrec *next; + size_t start; + size_t end; + size_t bytes; + char *buf; +} *XPAInput, XPAInputRec; + +/* + * + * + * xpa command record structure + * + */ +typedef struct xpacmdrec{ + struct xpacmdrec *next; + struct xparec *xpa; + char *name; + char *help; + int ntokens; + /* send callback info */ + SendCb send_callback; + void *send_data; + int send_mode; + /* receive callback info */ + ReceiveCb receive_callback; + void *receive_data; + int receive_mode; +} *XPACmd, XPACmdRec; + +/* + * + * + * xpa client record structure + * + */ +typedef struct xpaclientrec{ + struct xpaclientrec *next; + int status; + char *id; + char *xtemplate; + int type; + char *xclass; + char *name; + char *method; + char *info; + char *dataname; + unsigned int ip; + int cmdfd; + int datafd; + int mode; + int nsproxy; + /* xpaget parameters */ + char **bufptr; + size_t *lenptr; + size_t bufsize; + int fd; + /* xpaset parameters */ + char *buf; + size_t len; + size_t bytes; + /* fork parameters */ + pid_t pid; + /* common parameters */ + char **nameptr; + char **errptr; +} *XPAClient, XPAClientRec; + +/* + * + * + * main xpa record structure + * + * explanation of send_mode and receive_mode flags: + * + * receive-specific callback modes: + * + * r (raw) -- don't read data into buf (callback will read) + * + * general callback modes: + * + * r (raw) -- write raw data without protocol info to client + * s (save) -- 's' save passed buf (don't free it) + * + */ +typedef struct xparec{ + /* xpa version */ + char *version; + /* status of this xpa */ + int status; + /* "g", "s", "i" are server types; "c" for client */ + char *type; + /* + * THE SERVER SIDE + */ + struct xparec *next; + char *xclass; + char *name; + char *help; + /* send callback info */ + SendCb send_callback; + void *send_data; + int send_mode; + /* receive callback info */ + ReceiveCb receive_callback; + void *receive_data; + int receive_mode; + /* info callback info */ + InfoCb info_callback; + void *info_data; + int info_mode; + /* list of sub-commands for this access point */ + XPACmd commands; + /* communication info */ + int fd; /* listening socket file descriptor */ + char *method; /* method string: host:ip or unix_filename */ + NS nshead; /* name servers associated with this access point */ + XPAComm commhead; /* linked list of communcation records */ + XPAClip cliphead; /* linked list of cliboard records */ + char *filename; /* file name (unix sockets) for listening */ + char *sendian; /* endian-ness of server */ + /* request-specific info */ + XPAComm comm; /* current comm if we are processing a request */ + /* select loop info */ + SelDel seldel; /* routine to remove xpa socket from select loop */ + SelAdd seladd; /* routine to add xpa command sockets to select loop */ + SelOn selon; /* routine to enable xpa command sockets */ + SelOff seloff; /* routine to disable xpa command sockets */ + void *selptr; /* additional info for seldelete() */ + /* + * THE CLIENT SIDE + */ + int persist; /* flag whether this is a persistent client */ + int nclient; /* number of clients -- used in processing headers */ + int client_mode; /* global client mode */ + XPAClient clienthead; /* linked list of active clients */ + int ifd; /* input fd for XPASetFd() */ + size_t inpbytes; /* total number of bytes in input lists */ + XPAInput inphead; /* linked list of input structs */ +} *XPA, XPARec; + +/* macros to access the xpa struct */ +#define xpa_name(xpa) ((xpa)->name) +#define xpa_class(xpa) ((xpa)->xclass) +#define xpa_method(xpa) ((xpa)->method) +#define xpa_sendian(xpa) ((xpa)->sendian) +#define xpa_comm(xpa) (xpa&&(xpa)->comm?(xpa)->comm:NULL) +#define xpa_cendian(xpa) (((xpa)->comm&&(xpa)->comm->cendian)?(xpa)->comm->cendian:"?") +#define xpa_cmdfd(xpa) ((xpa)->comm?(xpa)->comm->cmdfd:-1) +#define xpa_datafd(xpa) ((xpa)->comm?(xpa)->comm->datafd:-1) +#define xpa_ack(xpa) ((xpa)->comm?(xpa)->comm->ack:1) +#define xpa_status(xpa) ((xpa)->comm?(xpa)->comm->status:0) +#define xpa_id(xpa) (((xpa)->comm&&(xpa)->comm->id)?(xpa)->comm->id:"?") + +extern char *xpaMessbuf[]; + +_PRbeg + +XPA XPAListHead _PRx((void)); +void XPAListAdd _PRx((XPA *head, XPA xpa)); +void XPAListDel _PRx((XPA *head, XPA xpa)); +int XPAActive _PRx((XPA xpa, XPAComm comm, int flag)); +int XPAActiveFd _PRx((int fd)); +int XPAAddSelect _PRx((XPA xpa, fd_set *readfdsptr)); +int XPAProcessSelect _PRx((fd_set *readfdsptr, int maxreq)); +void XPACloseData _PRx((XPA xpa, XPAComm comm)); +int XPAHandler _PRx((XPA xpa, int fd)); +void XPAMode _PRx((char *mode, int *flag, char *name, int mask, int def)); +int XPAEndian _PRx((void)); +char *XPATmpdir _PRx((void)); +void XPACleanup _PRx((void)); +int XPASetBuf _PRx((XPA xpa, char *buf, size_t len, int xcopy)); +int XPASetFree _PRx((XPA xpa, MyFree myfree, void *myfree_ptr)); +int XPAShortTimeout _PRx((void)); +int XPALongTimeout _PRx((void)); +int XPASendLTimeout _PRx((void *client_data, void *call_data, + char *paramlist, char **buf, size_t *len)); +int XPAReceiveLTimeout _PRx((void *client_data, void *call_data, + char *paramlist, char *buf, size_t len)); +int XPASendSTimeout _PRx((void *client_data, void *call_data, + char *paramlist, char **buf, size_t *len)); +int XPAReceiveSTimeout _PRx((void *client_data, void *call_data, + char *paramlist, char *buf, size_t len)); +int XPADebug _PRx((void)); +int XPASigusr1 _PRx((void)); +int XPAVerbosity _PRx((void)); +void XPAInitEnv _PRx((void)); +void XPAParseName _PRx((char *xpaname, char *xclass, char *name, int len)); +int XPAParseIpPort _PRx((char *host, unsigned int *ip, unsigned short *port)); +int XPAParseUnixSocket _PRx((char *host)); +int _XPAValid _PRx((XPA head, XPA xpa, char *type)); +int XPAValid _PRx((XPA xpa)); +char *XPATimestamp _PRx((void)); +int XPAError _PRx((XPA xpa, char *s)); +int XPAOK _PRx((XPA xpa)); +int XPAMessage _PRx((XPA xpa, char *s)); +char *XPAArgvParamlist _PRx((int argc, char **argv, int start)); +int XPAMethod _PRx((char *method)); +int XPAAccess _PRx((XPA xpa, char *xtemplate, char *paramlist, char *mode, + char **names, char **messages, int n)); +int XPANSLookup _PRx((XPA xpa, char *tname, char *ttype, + char ***xclasses, char ***names, + char ***methods, char ***infs)); +int XPANSClose _PRx((XPA xpa, NS ns)); +int XPANSKeepAlive _PRx((XPA xpa, int type)); +int XPANSAdd _PRx((XPA xpa, char *host, char *mode)); +int XPANSDel _PRx((XPA xpa, char *host, char *mode)); +int XPAVersionCheck _PRx((char *serv, char *nsv)); +void XPAVersionWarn _PRx((char *myv, char *nsv)); +char *XPANSMethod _PRx((char *host, int flag)); +XPA XPANew _PRx((char *xclass, char *name, char *help, + SendCb send_callback, void *send_data, char *send_mode, + ReceiveCb rec_callback, void *rec_data, char *rec_mode)); +int XPAFree _PRx((XPA xpa)); +XPA XPAInfoNew _PRx((char *xclass, char *name, + InfoCb info_callback, void *info_data, char *info_mode)); +int XPAPoll _PRx((int msec, int maxreq)); +int XPAMainLoop _PRx((void)); +void XPASleep _PRx((int msec)); +void XPAAtExit _PRx((void)); +/* command.c */ +void XPAInitReserved _PRx((void)); +void XPAFreeReserved _PRx((void)); +XPACmd XPACmdLookupReserved _PRx((XPA xpa, char *lbuf, int *lp)); +XPACmd XPACmdLookup _PRx((XPA xpa, char *lbuf, int *lp)); +int XPAReceiveCommands _PRx((void *client_data, void *call_data, + char *paramlist, char *buf, size_t len)); +int XPASendCommands _PRx((void *client_data, void *call_data, + char *paramlist, char **buf, size_t *len)); +XPA XPACmdNew _PRx((char *xclass, char *name)); +XPACmd XPACmdAdd _PRx((XPA xpa, char *name, char *help, + SendCb send_callback, void *send_data, char *send_mode, + ReceiveCb rec_callback, void *rec_data, char *rec_mode)); +int XPACmdDel _PRx((XPA xpa, XPACmd cmd)); +int XPACmdInternalReceive _PRx((void *client_data, void *call_data, + char *paramlist, char *buf, size_t len)); +int XPACmdInternalSend _PRx((void *client_data, void *call_data, + char *paramlist, char **buf, size_t *len)); +XPA XPAGetReserved _PRx((void)); +int XPAMtype _PRx((void)); +/* client.c */ +int XPAClientAddSelect _PRx((XPA xpa, + fd_set *readfdsptr, fd_set *writefdsptr)); +int XPAClientProcessSelect _PRx((XPA xpa, + fd_set *readfdsptr, fd_set *writefdsptr, + int maxreq)); +XPA XPAOpen _PRx((char *mode)); +void XPAClose _PRx((XPA xpa)); +int XPAGet _PRx((XPA xpa, char *xtemplate, + char *paramlist, char *mode, + char **bufs, size_t *lens, char **names, char **errs, int n)); +int XPAGetFd _PRx((XPA xpa, char *xtemplate, + char *paramlist, char *mode, + int *fds, char **names, char **errs, int n)); +int XPASet _PRx((XPA xpa, char *xtemplate, + char *paramlist, char *mode, + char *buf, size_t len, char **names, char **errs, int n)); +int XPASetFd _PRx((XPA xpa, char *xtemplate, + char *paramlist, char *mode, + int fd, char **names, char **errs, int n)); +int XPAInfo _PRx((XPA xpa, char *xtemplate, + char *paramlist, char *mode, + char **names, char **errs, int n)); +int XPAClientValid _PRx((XPA xpa)); +void XPASaveJmp _PRx((void *env)); + + +/* acl.c */ +int XPAReceiveAcl _PRx((void *client_data, void *call_data, + char *paramlist, char *buf, size_t len)); +int XPASendAcl _PRx((void *client_data, void *call_data, + char *paramlist, char **buf, size_t *len)); +int XPAAclEdit _PRx((char *lbuf)); +int XPAAclAdd _PRx((char *lbuf)); +int XPAAclDel _PRx((XACL acl)); +void XPAAclFree _PRx((void)); +int XPAAclNew _PRx((char *aname, int flag)); +int XPAAclCheck _PRx((XPA xpa, unsigned int ip, char *acl)); +/* port.c */ +int XPAPortEdit _PRx((char *lbuf)); +int XPAPortAdd _PRx((char *lbuf)); +int XPAPortDel _PRx((PORT port)); +void XPAPortFree _PRx((void)); +int XPAPortNew _PRx((char *aname, int flag)); +int XPAPort _PRx((XPA xpa)); +/* remote.c */ +int XPAReceiveRemote _PRx((void *client_data, void *call_data, + char *paramlist, char *buf, size_t len)); +int XPASendRemote _PRx((void *client_data, void *call_data, + char *paramlist, char **buf, size_t *len)); +int XPARemote _PRx((XPA xpa, char *host, char *acl, char *mode)); +/* clipboard.c */ +int XPAReceiveClipboard _PRx((void *client_data, void *call_data, + char *paramlist, char *buf, size_t len)); +int XPASendClipboard _PRx((void *client_data, void *call_data, + char *paramlist, char **buf, size_t *len)); +int ClipBoardFree _PRx((XPA xpa, XPAClip clip)); +/* xt.c */ +int XPAXtAddInput _PRx((void *app, XPA xpa)); +/* tcl.c */ +int XPATclAddInput _PRx((XPA xpa)); +int Tclxpa_Init _PRx((void *vinterp)); +/* gtkloop.c */ +int XPAGtkAddInput _PRx((XPA xpa)); +/* xpaio.c */ +int XPAGets _PRx((XPA xpa, int fd, char *buf, int len, int timeout)); +int XPAPuts _PRx((XPA xpa, int fd, char *buf, int timeout)); +int XPAGetBuf _PRx((XPA xpa, int fd, char **buf, size_t *len, int timeout)); +int XPAPutBuf _PRx((XPA xpa, int fd, char *buf, size_t len, int timeout)); +int XPAIOCallsXPA _PRx((int flag)); +char *XPALevelSpaces _PRx((void)); +void XPALevelSet _PRx((int lev)); +int XPALevelGet _PRx((void)); + +_PRend + +#endif /* __xpa.h */ diff --git a/xpa/xpa.pc.in b/xpa/xpa.pc.in new file mode 100644 index 0000000..e2d8baf --- /dev/null +++ b/xpa/xpa.pc.in @@ -0,0 +1,10 @@ +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +includedir=@includedir@ + +Name: @PACKAGE_NAME@ +Description: XPA messaging system for DS9 and other astro tools +Version: @PACKAGE_VERSION@ +Libs: -L${libdir} -lxpa @EXTRA_LIBS@ -lm +Cflags: -I${includedir} diff --git a/xpa/xpaaccess.c b/xpa/xpaaccess.c new file mode 100644 index 0000000..81643ac --- /dev/null +++ b/xpa/xpaaccess.c @@ -0,0 +1,212 @@ +/* + * Copyright (c) 1999-2003 Smithsonian Astrophysical Observatory + */ + +#include <xpap.h> + +#define MAX_XPAS 10000 + +extern char *optarg; +extern int optind; + +#ifdef ANSI_FUNC +void +usage (char *s) +#else +void usage(s) + char *s; +#endif +{ + fprintf(stderr, "\n"); + fprintf(stderr, "usage:\n"); + fprintf(stderr, " %s [-c] [-h] [-i nsinet] [-m method] [-n] [-t sval,lval] [-u users] [-v|-V] <template> [type]\n", s); + fprintf(stderr, "\n"); + fprintf(stderr, "switches:\n"); + fprintf(stderr, "\t-c\tcontact each access point individually to see if it is available\n"); + fprintf(stderr, "\t-h\tprint this message\n"); + fprintf(stderr, "\t-i\toverride XPA_NSINET environment variable\n"); + fprintf(stderr, "\t-m\toverride XPA_METHOD environment variable\n"); + fprintf(stderr, "\t-n\treturn number of matches instead of \"yes\" or \"no\"\n"); + fprintf(stderr, "\t-t \toverride XPA_[SHORT,LONG]_TIMEOUT environment variables\n"); + fprintf(stderr, "\t-u \toverride XPA_NSUSERS environment variable\n"); + fprintf(stderr, "\t-v\tprint info about successful access points\n"); + fprintf(stderr, "\t-V\tprint info and errors about all access points\n"); + fprintf(stderr, "\t--version display version and exit\n"); + fprintf(stderr, "\n"); + fprintf(stderr, "xpaaccess returns \"yes\" if there are existing XPA access points that match\n"); + fprintf(stderr, "the template (and optional access type: g,i,s), and returns \"no\" otherwise.\n"); + fprintf(stderr, "If -n is specified, the number of matches is returned.\n"); + fprintf(stderr, "Templates are of the form [class:]name. Wildcards *,?,[] are accepted.\n"); + fprintf(stderr, "\n"); + fprintf(stderr, "examples:\n"); + fprintf(stderr, "\tcsh> if( `xpaaccess ds9` == \"yes\") then ...\n" ); + fprintf(stderr, "\tcsh> set got=`xpaaccess -n ds9 g`\n"); + fprintf(stderr, "\n(version: %s)\n", XPA_VERSION); + exit(0); +} + +/* catch error from pre 2.1 server -- if we find this error, we know the + access point is available */ +#define OLD_SERVER(s) strstr(s, "XPA$ERROR invalid xpa command in initialization string") + +#ifdef ANSI_FUNC +int +main (int argc, char **argv) +#else +int +main(argc, argv) + int argc; + char **argv; +#endif +{ + int i; + int c; + int got; + int n=0; + int donum=0; + int verbosity=0; + int contact=0; + char cmd[SZ_LINE]; + char mode[SZ_LINE]; + char *type=NULL; + char *xtmpl=NULL; + char **rclasses; + char **rnames; + char **rmethods; + char **rinfos; + char *names[MAX_XPAS]; + char *errs[MAX_XPAS]; + XPA xpa=NULL; + + /* display version and exit, if necessary */ + if( (argc == 2) && !strcmp(argv[1], "--version") ){ + fprintf(stderr, "%s\n", XPA_VERSION); + exit(0); + } + + /* start with no mode flag */ + *mode = '\0'; + + /* we want the args in the same order in which they arrived, and + gnu getopt sometimes changes things without this */ + putenv("POSIXLY_CORRECT=true"); + + /* process switch arguments */ + while ((c = getopt(argc, argv, "chi:m:nt:u:vVwW")) != -1){ + switch(c){ + case 'c': + contact=1; + break; + case 'h': + usage(argv[0]); + case 'i': + snprintf(cmd, SZ_LINE, "XPA_NSINET=%s", optarg); + putenv(xstrdup(cmd)); + break; + case 'm': + snprintf(cmd, SZ_LINE, "XPA_METHOD=%s", optarg); + putenv(xstrdup(cmd)); + break; + case 'n': + donum=1; + break; + case 't': + { + int xip=0; + char xbuf[SZ_LINE]; + newdtable(",;"); + if( word(optarg, xbuf, &xip) && *xbuf && (*xbuf != '*') ){ + snprintf(cmd, SZ_LINE, "XPA_SHORT_TIMEOUT=%s", xbuf); + putenv(xstrdup(cmd)); + } + if( word(optarg, xbuf, &xip) && *xbuf && (*xbuf != '*') ){ + snprintf(cmd, SZ_LINE, "XPA_LONG_TIMEOUT=%s", xbuf); + putenv(xstrdup(cmd)); + } + freedtable(); + } + break; + case 'u': + snprintf(cmd, SZ_LINE, "XPA_NSUSERS=%s", optarg); + putenv(xstrdup(cmd)); + break; + case 'v': + verbosity=1; + break; + case 'V': + verbosity=2; + break; + /* for backward compatibility with 1.0 */ + case 'w': + case 'W': + break; + } + } + + /* we must have a template */ + if( optind >= argc ){ + usage(argv[0]); + } + else{ + xtmpl = argv[optind]; + optind++; + if( optind < argc ){ + type = argv[optind]; + } + } + + /* if we need to contact each server ... */ + if( contact ){ + got = XPAAccess(xpa, xtmpl, type, mode, names, errs, MAX_XPAS); + for(i=0; i<got; i++){ + if( !errs[i] || OLD_SERVER(errs[i]) ){ + if( verbosity ) fprintf(stdout, "%s\n", names[i]); + n++; + } + else{ + if( verbosity >= 2 ) fprintf(stdout, "%s", errs[i]); + } + if( errs[i] ) xfree(errs[i]); + if( names[i] ) xfree(names[i]); + } + } + /* only contact name server */ + else{ + n = XPANSLookup(xpa, xtmpl, type, &rclasses, &rnames, &rmethods, &rinfos); + /* free up the space */ + for(i=0; i<n; i++){ + if( verbosity ){ + fprintf(stdout, "%s", rmethods[i]); + if( strcmp(rinfos[i], XPA_DEF_CLIENT_INFO) ) + fprintf(stdout, " %s", rinfos[i]); + fprintf(stdout, "\n"); + } + /* done with these strings */ + xfree(rclasses[i]); + xfree(rnames[i]); + xfree(rmethods[i]); + xfree(rinfos[i]); + } + /* free up arrays returned by name server */ + if( n > 0 ){ + xfree(rclasses); + xfree(rnames); + xfree(rmethods); + xfree(rinfos); + } + } + + /* print out number */ + if( !verbosity && donum ){ + fprintf(stdout, "%d\n", n); + } + /* print out yes/no */ + else if( !verbosity && !donum ){ + if( n > 0 ) + fprintf(stdout, "yes\n"); + else + fprintf(stdout, "no\n"); + } + fflush(stdout); + return(n); +} diff --git a/xpa/xpaget.c b/xpa/xpaget.c new file mode 100644 index 0000000..ea70121 --- /dev/null +++ b/xpa/xpaget.c @@ -0,0 +1,225 @@ +/* + * Copyright (c) 1999-2003 Smithsonian Astrophysical Observatory + */ + +#include <xpap.h> + +extern char *optarg; +extern int optind; + +#ifdef ANSI_FUNC +void +usage (char *s) +#else +void usage(s) + char *s; +#endif +{ + fprintf(stderr, "\n"); + fprintf(stderr, "usage:\n"); + fprintf(stderr, " %s [-h] [-i nsinet] [-m method] [-n] [-s] [-t sval,lval] [-u users] <tmpl|host:port> [paramlist]\n", s); + fprintf(stderr, "\n"); + fprintf(stderr, "switches:\n"); + fprintf(stderr, "\t-h\tprint this message\n"); + fprintf(stderr, "\t-i\toverride XPA_NSINET environment variable\n"); + fprintf(stderr, "\t-m\toverride XPA_METHOD environment variable\n"); + fprintf(stderr, "\t-n\tdon't wait for message after server completes (kind of useless!)\n"); + fprintf(stderr, "\t-s\tserver mode\n"); + fprintf(stderr, "\t-t \toverride XPA_[SHORT,LONG]_TIMEOUT environment variables\n"); + fprintf(stderr, "\t-u\toverride XPA_NSUSERS environment variable\n"); + fprintf(stderr, "\t--version display version and exit\n"); + fprintf(stderr, "\n"); + fprintf(stderr, "Data will be retrieved from access points matching the template or host:port.\n"); + fprintf(stderr, "Templates are of the form [class:]name. Wildcards *,?,[] are accepted.\n"); + fprintf(stderr, "A set of qualifying parameters can be appended.\n"); + fprintf(stderr, "\n"); + fprintf(stderr, "examples:\n"); + fprintf(stderr, "\tcsh> xpaget ds9 file\n"); + fprintf(stderr, "\tcsh> xpaget bynars.harvard.edu:1147\n"); + fprintf(stderr, "\n(version: %s)\n", XPA_VERSION); + exit(1); +} + +#ifdef ANSI_FUNC +int +main (int argc, char **argv) +#else +int +main(argc, argv) + int argc; + char **argv; +#endif +{ + int i; + int c; + int got; + int lp; + int errcode=0; + int server=0; + int maxhosts=XPA_MAXHOSTS; + char *paramlist=NULL; + char *xtemplate=NULL; + char lbuf[SZ_LINE]; + char tbuf[SZ_LINE]; + char mode[SZ_LINE]; + char cmd[SZ_LINE]; + char *s; + char **errs=NULL; + char **names=NULL; + int fds[1]; + XPA xpa=NULL; + + /* display version and exit, if necessary */ + if( (argc == 2) && !strcmp(argv[1], "--version") ){ + fprintf(stderr, "%s\n", XPA_VERSION); + exit(0); + } + + /* make sure we have enough arguments */ + if( argc < 2 ) + usage(argv[0]); + + /* start with no mode flag */ + *mode = '\0'; + + /* we want the args in the same order in which they arrived, and + gnu getopt sometimes changes things without this */ + putenv("POSIXLY_CORRECT=true"); + + /* process switch arguments */ + while ((c = getopt(argc, argv, "hi:m:nst:u:wW")) != -1){ + switch(c){ + case 'h': + usage(argv[0]); + case 'i': + snprintf(cmd, SZ_LINE, "XPA_NSINET=%s", optarg); + putenv(xstrdup(cmd)); + break; + case 'm': + snprintf(cmd, SZ_LINE, "XPA_METHOD=%s", optarg); + putenv(xstrdup(cmd)); + break; + case 'n': + if( *mode != '\0' ) + strcat(mode, ","); + strcat(mode, "ack=false"); + break; + case 's': + server = 1; + xpa = XPAOpen(NULL); + break; + case 't': + { + int xip=0; + char xbuf[SZ_LINE]; + newdtable(",;"); + if( word(optarg, xbuf, &xip) && *xbuf && (*xbuf != '*') ){ + snprintf(cmd, SZ_LINE, "XPA_SHORT_TIMEOUT=%s", xbuf); + putenv(xstrdup(cmd)); + } + if( word(optarg, xbuf, &xip) && *xbuf && (*xbuf != '*') ){ + snprintf(cmd, SZ_LINE, "XPA_LONG_TIMEOUT=%s", xbuf); + putenv(xstrdup(cmd)); + } + freedtable(); + } + break; + case 'u': + snprintf(cmd, SZ_LINE, "XPA_NSUSERS=%s", optarg); + putenv(xstrdup(cmd)); + break; + /* for backward compatibility with 1.0 */ + case 'w': + case 'W': + break; + } + } + + /* no explicit host:port specified, so we should have a name */ + if( optind >= argc ){ + /* in server mode, we can skip the host on the command line */ + if( !server ) + usage(argv[0]); + } + else{ + xtemplate = xstrdup(argv[optind]); + optind++; + } + + /* make the paramlist */ + paramlist = XPAArgvParamlist(argc, argv, optind); + + /* init variables for names and ports */ + if( (s=(char *)getenv("XPA_MAXHOSTS")) != NULL ) + maxhosts = atoi(s); + names = (char **)xcalloc(maxhosts, sizeof(char *)); + errs = (char **)xcalloc(maxhosts, sizeof(char *)); + + /* we only send to stdout */ + fds[0] = fileno(stdout); + +again: + /* if we are in server mode, we might have to read a line from stdin + to grab the template and paramlist */ + if( server && (xtemplate==NULL) ){ + /* read description of template and paramlist */ + if( fgets(lbuf, SZ_LINE, stdin) == NULL ) + exit(errcode); + if( (*lbuf == '#') || (*lbuf == '\n') ) + goto again; + lp = 0; + if( word(lbuf, tbuf, &lp) && !strcmp(tbuf, "xpaget") && + word(lbuf, tbuf, &lp) ){ + xtemplate = xstrdup(tbuf); + paramlist = xstrdup(&(lbuf[lp])); + nowhite(paramlist, paramlist); + } + else{ + fprintf(stderr, "XPA$ERROR invalid command: %s", lbuf); + exit(++errcode); + } + } + + /* process xpa requests */ + got = XPAGetFd(xpa, xtemplate, paramlist, mode, fds, names, errs, -maxhosts); + if( got == 0 ){ + fprintf(stderr, "XPA$ERROR no 'xpaget' access points match template: %s\n", + xtemplate); + errcode++; + } + else{ + /* display errors and free up strings */ + for(i=0; i<got; i++){ + if( errs[i] != NULL ){ + fprintf(stderr, "%s", errs[i]); + xfree(errs[i]); + errcode++; + } + if( names[i] != NULL ) + xfree(names[i]); + } + } + + /* free the paramlist */ + if( paramlist!= NULL ){ + xfree(paramlist); + paramlist = NULL; + } + /* and the template */ + if( xtemplate != NULL ){ + xfree(xtemplate); + xtemplate = NULL; + } + + /* if we are in server mode, go back for more */ + if( server ) + goto again; + else{ + /* clean up */ + if( errs ) xfree(errs); + if( names ) xfree(names); + XPACleanup(); + exit(errcode); + } + return(0); +} diff --git a/xpa/xpainfo.c b/xpa/xpainfo.c new file mode 100644 index 0000000..6436703 --- /dev/null +++ b/xpa/xpainfo.c @@ -0,0 +1,219 @@ +/* + * Copyright (c) 1999-2003 Smithsonian Astrophysical Observatory + */ + +#include <xpap.h> + +extern char *optarg; +extern int optind; + +#ifdef ANSI_FUNC +void +usage (char *s) +#else +void usage(s) + char *s; +#endif +{ + fprintf(stderr, "\n"); + fprintf(stderr, "usage:\n"); + fprintf(stderr, " %s [-h] [-i nsinet] [-m method] [-n] [-s] [-t sval,lval] [-u users] <tmpl|host:port> [paramlist]\n", s); + fprintf(stderr, "\n"); + fprintf(stderr, "switches:\n"); + fprintf(stderr, "\t-h\tprint this message\n"); + fprintf(stderr, "\t-i \toverride XPA_NSINET environment variable\n"); + fprintf(stderr, "\t-m\toverride XPA_METHOD environment variable\n"); + fprintf(stderr, "\t-n\tdon't wait for ack from server\n"); + fprintf(stderr, "\t-s\tserver mode\n"); + fprintf(stderr, "\t-t \toverride XPA_[SHORT,LONG]_TIMEOUT environment variables\n"); + fprintf(stderr, "\t-u \toverride XPA_NSUSERS environment variable\n"); + fprintf(stderr, "\t--version display version and exit\n"); + fprintf(stderr, "\n"); + fprintf(stderr, "Info will be sent to access points matching the template or host:port.\n"); + fprintf(stderr, "Templates are of the form [class:]name. Wildcards *,?,[] are accepted.\n"); + fprintf(stderr, "A set of qualifying parameters can be appended.\n"); + fprintf(stderr, "\n"); + fprintf(stderr, "examples:\n"); + fprintf(stderr, "\tcsh> xpainfo IMAGE ds9 image\n"); + fprintf(stderr, "\n(version: %s)\n", XPA_VERSION); + exit(1); +} + +#ifdef ANSI_FUNC +int +main (int argc, char **argv) +#else +int +main(argc, argv) + int argc; + char **argv; +#endif +{ + int i; + int c; + int got; + int lp; + int errcode=0; + int server=0; + int maxhosts=XPA_MAXHOSTS; + char *paramlist=NULL; + char *xtemplate=NULL; + char lbuf[SZ_LINE]; + char tbuf[SZ_LINE]; + char mode[SZ_LINE]; + char cmd[SZ_LINE]; + char *s; + char **errs=NULL; + char **names=NULL; + XPA xpa=NULL; + + /* display version and exit, if necessary */ + if( (argc == 2) && !strcmp(argv[1], "--version") ){ + fprintf(stderr, "%s\n", XPA_VERSION); + exit(0); + } + + /* make sure we have enough arguments */ + if( argc < 2 ) + usage(argv[0]); + + /* start with no mode flag */ + *mode = '\0'; + + /* we want the args in the same order in which they arrived, and + gnu getopt sometimes changes things without this */ + putenv("POSIXLY_CORRECT=true"); + + /* process switch arguments */ + while ((c = getopt(argc, argv, "hi:m:nst:u:wW")) != -1){ + switch(c){ + case 'h': + usage(argv[0]); + case 'i': + snprintf(cmd, SZ_LINE, "XPA_NSINET=%s", optarg); + putenv(xstrdup(cmd)); + break; + case 'm': + snprintf(cmd, SZ_LINE, "XPA_METHOD=%s", optarg); + putenv(xstrdup(cmd)); + break; + case 'n': + if( *mode != '\0' ) + strcat(mode, ","); + strcat(mode, "ack=false"); + break; + case 's': + server = 1; + xpa = XPAOpen(NULL); + break; + case 't': + { + int xip=0; + char xbuf[SZ_LINE]; + newdtable(",;"); + if( word(optarg, xbuf, &xip) && *xbuf && (*xbuf != '*') ){ + snprintf(cmd, SZ_LINE, "XPA_SHORT_TIMEOUT=%s", xbuf); + putenv(xstrdup(cmd)); + } + if( word(optarg, xbuf, &xip) && *xbuf && (*xbuf != '*') ){ + snprintf(cmd, SZ_LINE, "XPA_LONG_TIMEOUT=%s", xbuf); + putenv(xstrdup(cmd)); + } + freedtable(); + } + break; + case 'u': + snprintf(cmd, SZ_LINE, "XPA_NSUSERS=%s", optarg); + putenv(xstrdup(cmd)); + break; + /* for backward compatibility with 1.0 */ + case 'w': + case 'W': + break; + } + } + + /* no explicit host:port specified, so we should have a name */ + if( optind >= argc ){ + /* in server mode, we can skip the host on the command line */ + if( !server ) + usage(argv[0]); + } + else{ + xtemplate = xstrdup(argv[optind]); + optind++; + } + + /* make the paramlist */ + paramlist = XPAArgvParamlist(argc, argv, optind); + + /* init variables for names and ports */ + if( (s=(char *)getenv("XPA_MAXHOSTS")) != NULL ) + maxhosts = atoi(s); + names = (char **)xcalloc(maxhosts, sizeof(char *)); + errs = (char **)xcalloc(maxhosts, sizeof(char *)); + +again: + /* if we are in server mode, we might have to read a line from stdin + to grab the template and paramlist */ + if( server && (xtemplate==NULL) ){ + /* read description of template and paramlist */ + if( fgets(lbuf, SZ_LINE, stdin) == NULL ) + exit(errcode); + if( (*lbuf == '#') || (*lbuf == '\n') ) + goto again; + lp = 0; + if( word(lbuf, tbuf, &lp) && !strcmp(tbuf, "xpaget") && + word(lbuf, tbuf, &lp) ){ + xtemplate = xstrdup(tbuf); + paramlist = xstrdup(&(lbuf[lp])); + nowhite(paramlist, paramlist); + } + else{ + fprintf(stderr, "XPA$ERROR invalid command: %s", lbuf); + exit(++errcode); + } + } + + /* process xpa requests */ + got = XPAInfo(xpa, xtemplate, paramlist, mode, names, errs, -maxhosts); + if( got == 0 ){ + fprintf(stderr, "XPA$ERROR no 'xpainfo' access points match template: %s\n", + xtemplate); + errcode++; + } + else{ + /* display errors and free up strings */ + for(i=0; i<got; i++){ + if( errs[i] != NULL ){ + fprintf(stderr, "%s", errs[i]); + xfree(errs[i]); + errcode++; + } + if( names[i] != NULL ) + xfree(names[i]); + } + } + + /* free the paramlist */ + if( paramlist!= NULL ){ + xfree(paramlist); + paramlist = NULL; + } + /* and the template */ + if( xtemplate != NULL ){ + xfree(xtemplate); + xtemplate = NULL; + } + + /* if we are in server mode, go back for more */ + if( server ) + goto again; + else{ + /* clean up */ + if( errs ) xfree(errs); + if( names ) xfree(names); + exit(errcode); + } + return(0); +} diff --git a/xpa/xpaio.c b/xpa/xpaio.c new file mode 100644 index 0000000..a5e7473 --- /dev/null +++ b/xpa/xpaio.c @@ -0,0 +1,989 @@ +/* + * Copyright (c) 1999-2003 Smithsonian Astrophysical Observatory + */ + +#include <xpap.h> + +/* + *---------------------------------------------------------------------------- + * + * + * Private Routines and Data + * + * + *---------------------------------------------------------------------------- + */ + +static int ioerr=0; +static int doxpa=XPA_IOCALLSXPA; +static int _doxpa=1; +static int level=0; +static char _xpalevelspaces[SZ_LINE]; + +#if HAVE_MINGW32==0 + +static struct sigaction act1, oact1; + +/* + *---------------------------------------------------------------------------- + * + * Routine: XPAInterruptFunc + * + * Purpose: function to call when interrupted + * + * Returns: none + * + *---------------------------------------------------------------------------- + */ +#ifdef ANSI_FUNC +static void +XPAInterruptFunc (int signo) +#else +static void XPAInterruptFunc(signo) + int signo; +#endif +{ + ioerr = 1; +} + +/* + *---------------------------------------------------------------------------- + * + * Routine: XPAInterruptSetup + * + * Purpose: set up the InterruptSetup handler + * + * Returns: 0 for success, -1 for failure + * + *---------------------------------------------------------------------------- + */ +#ifdef ANSI_FUNC +static int +XPAInterruptSetup (Sigfunc *func1) +#else +static int XPAInterruptSetup(func1) + Sigfunc *func1; +#endif +{ + ioerr = 0; + + if( XPASigusr1() ){ + act1.sa_handler = func1; + sigemptyset(&act1.sa_mask); + act1.sa_flags = 0; +#ifdef SA_INTERRUPT + act1.sa_flags |= SA_INTERRUPT; +#endif + if( sigaction(SIGUSR1, &act1, &oact1) < 0 ) + return(-1); + } + return(0); +} + +/* + *---------------------------------------------------------------------------- + * + * Routine: XPAInterruptStart + * + * Purpose: set up sigaction for interrupt + * + * Returns: 0 for success, -1 for failure + * + *---------------------------------------------------------------------------- + */ +#ifdef ANSI_FUNC +static void +XPAInterruptStart (void) +#else +static void XPAInterruptStart() +#endif +{ + /* Disable SIGPIPE so we do not die if the client dies. + Rather, we will get an EOF on reading or writing. */ + xsignal_sigpipe(); + + /* set up the signal callbacks */ + XPAInterruptSetup(XPAInterruptFunc); +} + +/* + *---------------------------------------------------------------------------- + * + * Routine: XPAInterruptEnd + * + * Purpose: stop the interrupt handling + * + * Returns: none + * + *---------------------------------------------------------------------------- + */ +#ifdef ANSI_FUNC +static void +XPAInterruptEnd (void) +#else +static void XPAInterruptEnd() +#endif +{ + /* restore old sigaction, if necessary */ + if( XPASigusr1() ) + XPAInterruptSetup(oact1.sa_handler); +} + +#else + +/* Windows does not support SIGUSR1 */ +#define XPAInterruptStart() ioerr=0 +#define XPAInterruptEnd() + +#endif + +/* + *---------------------------------------------------------------------------- + * + * Routine: XPAIOErrorCheck + * + * Purpose: check to see if there was an error + * + * Returns: none + * + *---------------------------------------------------------------------------- + */ +#ifdef ANSI_FUNC +static int +XPAIOErrorCheck (void) +#else +static int XPAIOErrorCheck() +#endif +{ + return(ioerr); +} + +/* + *---------------------------------------------------------------------------- + * + * + * Public Routines and Data + * + * + *---------------------------------------------------------------------------- + */ + +/* + *---------------------------------------------------------------------------- + * + * Routine: XPAGets + * + * Purpose: read characters up a new-line -- sockets only + * + * Returns: number of characters read + * + *---------------------------------------------------------------------------- + */ +#ifdef ANSI_FUNC +int +XPAGets (XPA xpa, int fd, char *buf, int len, int timeout) +#else +int XPAGets(xpa, fd, buf, len, timeout) + XPA xpa; + int fd; + char *buf; + int len; + int timeout; +#endif +{ + int cur; + int got; + int flags; + int active; + int firsttime; + int done1, done2; + int swidth = FD_SETSIZE; + struct timeval tv; + struct timeval *tvp; + fd_set readfds; + fd_set writefds; + + /* do we allow xpa processing within this routine? */ + _doxpa = 1; + + /* start out pessimistically */ + *buf = '\0'; + + /* make sure we have a valid channel */ + if( fd < 0 ) return(-1); + + /* make sure we have a valid len */ + if( len <= 0 ) return(-1); + + FPRINTF((stderr, "%sXPAGets: %d entering to read %d bytes\n", _sp, fd, len)); + + /* start the interrupt handler */ + XPAInterruptStart(); + + /* turn this xpa off */ + active = XPAActive(xpa, xpa_comm(xpa), 0); + + /* put socket into non-blocking mode */ + xfcntl_nonblock(fd,flags); + + /* grab characters up to a new-line or max len */ + cur = 0; + done1 = (cur >= (len-1)); + firsttime = 1; + while( !done1 ){ + /* first time through we try the primary IO before selecting */ + if( !firsttime ){ + /* set up timer, if necessary */ + if( timeout >= 0 ){ + tv.tv_sec = timeout; + tv.tv_usec = 0; + tvp = &tv; + } + else{ + tvp = NULL; + } + /* select this socket and all XPA server sockets */ + FD_ZERO(&readfds); + FD_SET(fd, &readfds); + FD_ZERO(&writefds); + if( doxpa && _doxpa ){ + XPAClientAddSelect(NULL, &readfds, &writefds); + XPAAddSelect(NULL, &readfds); + } + /* wait for the IO ready */ + FPRINTF((stderr, "%sXPAGets: select on fd %d ...", _sp, fd)); + got = xselect(swidth, &readfds, &writefds, NULL, tvp); + FPRINTF((stderr, " returned %d\n", got)); + /* check for user interrupt or error or timeout */ + if( XPAIOErrorCheck() || (got <=0) ){ + cur = -1; + done1 = 1; + continue; + } + /* if socket is not ready, process XPA's and try again */ + if( !FD_ISSET(fd, &readfds) ){ + if( doxpa && _doxpa ){ + XPALevelSet(1); + XPAClientProcessSelect(NULL, &readfds, &writefds, 0); + XPAProcessSelect(&readfds, 0); + XPALevelSet(-1); + } + continue; + } + } + else{ + firsttime = 0; + } + done2 = 0; + while( !done1 && !done2 ){ + /* get data */ + got = recv(fd, &(buf[cur]), 1, 0); + /* check for user interrupt */ + if( XPAIOErrorCheck() ){ + cur = -1; + done1 = 1; + continue; + } + /* process result code */ + switch(got){ + case -1: + /* socket would block */ + if((xerrno == EINPROGRESS) || + (xerrno == EWOULDBLOCK) || + (xerrno == EAGAIN) ){ + FPRINTF((stderr, "%sXPAGets: recoverable recv fd=%d errno=%d\n", + _sp, fd, xerrno)); + done2 = 1; + } + /* error of some sort */ + else{ + FPRINTF((stderr, "%sXPAGets: error recv fd=%d errno=%d\n", + _sp, fd, xerrno)); + PERROR(("XPAGets recv")); + cur = -1; + done1 = 1; + } + break; + case 0: + /* EOF */ + done1 = 1; + break; + default: + /* got a valid byte -- check for EOL */ + if( buf[cur++] == '\n' ){ + /* change \r\n to \n */ + if( (cur >= 2) && (buf[cur-2] == '\r') ){ + cur--; + buf[cur-1] = '\n'; + } + done1 = 1; + } + else{ + done1 = cur >= (len-1); + } + break; + } + } + } + + /* restore socket mode */ + xfcntl_restore(fd,flags); + + /* restore active flag */ + XPAActive(xpa, xpa_comm(xpa), active); + + /* stop the interrupt handler */ + XPAInterruptEnd(); + + if( cur >= 0 ){ + buf[cur] = '\0'; + } + else{ + buf[0] = '\0'; + } + FPRINTF((stderr, "%sXPAGets: %d read %d bytes:\n%.80s", _sp, fd, cur, buf)); + + /* return error code or length */ + return(cur); +} + +/* + *---------------------------------------------------------------------------- + * + * Routine: XPAPuts + * + * Purpose: write a line of characters up to a newline -- sockets only + * + * Returns: number of characters written + * + *---------------------------------------------------------------------------- + */ +#ifdef ANSI_FUNC +int +XPAPuts (XPA xpa, int fd, char *buf, int timeout) +#else +int XPAPuts(xpa, fd, buf, timeout) + XPA xpa; + int fd; + char *buf; + int timeout; +#endif +{ + int n; + int total; + int cur; + int got; + int flags; + int active; + int firsttime; + int done1, done2; + int swidth = FD_SETSIZE; + struct timeval tv; + struct timeval *tvp; + fd_set readfds, writefds; + + /* do we allow xpa processing within this routine? */ + _doxpa = 1; + + /* make sure we have a valid channel */ + if( fd < 0 ) return(-1); + + /* determine how many characters to send */ + got = strlen(buf); + for(total=0; total<got; total++){ + if( buf[total] == '\n' ){ + total++; + break; + } + } + FPRINTF((stderr, "%sXPAPuts: %d entering to write %d bytes\n", + _sp, fd, total)); + + /* start the interrupt handler */ + XPAInterruptStart(); + + /* turn this xpa off */ + active = XPAActive(xpa, xpa_comm(xpa), 0); + + /* put socket into non-blocking mode */ + xfcntl_nonblock(fd,flags); + + /* send characters up to a new-line */ + cur = 0; + done1 = (cur >= total); + firsttime = 1; + while( !done1 ){ + /* first time through we try the primary IO before selecting */ + if( !firsttime ){ + /* set up timer, if necessary */ + if( timeout >= 0 ){ + tv.tv_sec = timeout; + tv.tv_usec = 0; + tvp = &tv; + } + else{ + tvp = NULL; + } + /* select this socket and all XPA server sockets */ + FD_ZERO(&readfds); + FD_ZERO(&writefds); + FD_SET(fd, &writefds); + if( doxpa && _doxpa ){ + XPAClientAddSelect(NULL, &readfds, &writefds); + XPAAddSelect(NULL, &readfds); + } + /* wait for the IO ready */ + FPRINTF((stderr, "%sXPAPuts: select on fd %d ...", _sp, fd)); + got = xselect(swidth, &readfds, &writefds, NULL, tvp); + FPRINTF((stderr, " returned %d\n", got)); + /* check for user interrupt or error or timeout */ + if( XPAIOErrorCheck() || (got <=0) ){ + cur = -1; + done1 = 1; + continue; + } + /* if socket is not ready, process XPA's and try again */ + if( !FD_ISSET(fd, &writefds) ){ + FD_CLR(fd, &readfds); + if( doxpa && _doxpa ){ + XPALevelSet(1); + XPAClientProcessSelect(NULL, &readfds, &writefds, 0); + XPAProcessSelect(&readfds, 0); + XPALevelSet(-1); + } + continue; + } + } + else{ + firsttime = 0; + } + done2 = 0; + while( !done1 && !done2 ){ + /* calculate size of next chunk */ + if( (n = MIN(total-cur, XPA_IOSIZE)) <=0 ){ + done1 = 1; + continue; + } + /* write the data */ + FPRINTF((stderr, "%sXPAPuts: send %d on fd %d ...", _sp, n, fd)); + got=send(fd, &buf[cur], n, 0); + FPRINTF((stderr, " returned %d\n", got)); + /* check for user interrupt */ + if( XPAIOErrorCheck() ){ + cur = -1; + done1 = 1; + continue; + } + /* process return code */ + switch(got){ + case -1: + /* socket would block */ + if((xerrno == EINPROGRESS) || + (xerrno == EWOULDBLOCK) || + (xerrno == EAGAIN) ){ + done2 = 1; + } + /* error of some sort */ + else{ + cur = -1; + done1 = 1; + } + break; + case 0: + /* shouldn't happen */ + done1 = (cur >= total); + break; + default: + /* sent some data */ + cur += got; + done1 = (cur >= total); + break; + } + } + } + + /* restore socket mode */ + xfcntl_restore(fd,flags); + + /* restore active flag */ + XPAActive(xpa, xpa_comm(xpa), active); + + /* stop the interrupt handler */ + XPAInterruptEnd(); + FPRINTF((stderr, "%sXPAPuts: %d wrote %d bytes: %.50s", + _sp, fd, total, buf)); + /* return error code or length */ + return(cur); +} + +/* + *---------------------------------------------------------------------------- + * + * Routine: XPAGetBuf + * + * Purpose: read data from the xpa data socket until EOF -- sockets only + * + * Results: 0 on success, -1 on failure + * also allocates memory for buf and returns len + * + *---------------------------------------------------------------------------- + */ +#ifdef ANSI_FUNC +int +XPAGetBuf (XPA xpa, int fd, char **buf, size_t *len, int timeout) +#else +int XPAGetBuf(xpa, fd, buf, len, timeout) + XPA xpa; + int fd; + char **buf; + size_t *len; + int timeout; +#endif +{ + int n; + int cur; + int flags; + int active; + int firsttime; + int done1, done2; + int swidth = FD_SETSIZE; + int got; + size_t total; + size_t slen; + char *s=NULL; + struct timeval tv; + struct timeval *tvp; + fd_set readfds; + fd_set writefds; + + /* do we allow xpa processing within this routine? */ + _doxpa = 1; + + /* make sure we have a valid data channel */ + if( fd < 0 ) return(-1); + + /* make sure we have a valid buf ptr and len ptr */ + if( (len == NULL) || (buf == NULL) ) return(-1); + + FPRINTF((stderr, "%sXPAGetBuf: entering fd %d\n", _sp, fd)); + + /* allocate the first buffer, if necessary */ + if( (*len != 0) && (*buf != NULL) ){ + slen = *len; + total = *len; + s = *buf; + } + else{ + slen = XPA_IOSIZE; + total = 0; + if( (s=(char *)xmalloc(slen)) == NULL ) + return(-1); + } + n = XPA_IOSIZE; + + /* start the interrupt handler */ + XPAInterruptStart(); + + /* turn this xpa off */ + active = XPAActive(xpa, xpa_comm(xpa), 0); + + /* put socket into non-blocking mode */ + xfcntl_nonblock(fd,flags); + + /* grab bytes to EOF */ + done1 = 0; + firsttime = 1; + while( !done1 ){ + /* first time through we try the primary IO before selecting */ + if( !firsttime ){ + /* set up timer, if necessary */ + if( timeout >= 0 ){ + tv.tv_sec = timeout; + tv.tv_usec = 0; + tvp = &tv; + } + else{ + tvp = NULL; + } + /* select this socket and all XPA server sockets */ + FD_ZERO(&readfds); + FD_SET(fd, &readfds); + FD_ZERO(&writefds); + if( doxpa && _doxpa ){ + XPAClientAddSelect(NULL, &readfds, &writefds); + XPAAddSelect(NULL, &readfds); + } + /* wait for the IO ready */ + FPRINTF((stderr, "%sXPAGetBuf: select on fd %d ...", _sp, fd)); + got = xselect(swidth, &readfds, &writefds, NULL, tvp); + FPRINTF((stderr, " returned %lu\n", (unsigned long)got)); + /* check for user interrupt or error or timeout */ + if( XPAIOErrorCheck() || (got <=0) ){ + cur = -1; + done1 = 1; + continue; + } + /* if socket is not ready, process XPA's and try again */ + if( !FD_ISSET(fd, &readfds) ){ + if( doxpa && _doxpa ){ + XPALevelSet(1); + XPAClientProcessSelect(NULL, &readfds, &writefds, 0); + XPAProcessSelect(&readfds, 0); + XPALevelSet(-1); + } + continue; + } + } + else{ + firsttime = 0; + } + done2 = 0; + while( !done1 && !done2 ){ + /* make sure we have enough room */ + while( (total + n) > slen ){ + slen += (n*10); + if( (s = (char *)xrealloc(s, slen)) == NULL ){ + return(-1); + } + } + /* get data */ + got = recv(fd, &(s[total]), n, 0); + FPRINTF((stderr, "%sXPAGetBuf: %d got %d bytes (tried %d at %lu)\n", + _sp, fd, got, n, (unsigned long)total)); + /* check for user interrupt */ + if( XPAIOErrorCheck() ){ + cur = -1; + done1 = 1; + continue; + } + /* process return code */ + switch(got){ + case -1: + /* socket would block */ + if((xerrno == EINPROGRESS) || + (xerrno == EWOULDBLOCK) || + (xerrno == EAGAIN) ){ + done2 = 1; + } + /* error of some sort */ + else{ + cur = -1; + done1 = 1; + } + break; + case 0: + /* EOF */ + cur = 0; + done1 = 1; + break; + default: + /* got data */ + total += got; + break; + } + } + } + + /* restore socket mode */ + xfcntl_restore(fd,flags); + + /* restore active flag */ + XPAActive(xpa, xpa_comm(xpa), active); + + /* stop the interrupt handler */ + XPAInterruptEnd(); + + /* null terminate after last byte as a courtesy */ + if( cur == 0 ){ + s = (char *)xrealloc(s, total+1); + s[total] = '\0'; + *buf = s; + *len = total; + } + else{ + if( s ) xfree(s); + *buf = NULL; + *len = 0; + } + + FPRINTF((stderr, "%sXPAGetBuf: leaving fd %d with %lu bytes\n", + _sp, fd, (unsigned long)*len)); + + /* return error code or length */ + return(cur); +} + +/* + *---------------------------------------------------------------------------- + * + * Routine: XPAPutBuf + * + * Purpose: write data to the xpa data socket -- sockets only + * + * Results: 0 on success, -1 for failure + * + *---------------------------------------------------------------------------- + */ +#ifdef ANSI_FUNC +int +XPAPutBuf (XPA xpa, int fd, char *buf, size_t len, int timeout) +#else +int XPAPutBuf(xpa, fd, buf, len, timeout) + XPA xpa; + int fd; + char *buf; + size_t len; + int timeout; +#endif +{ + int n; + int cur; + int got; + int flags; + int active; + int firsttime; + int done1, done2; + int swidth = FD_SETSIZE; + size_t total; + struct timeval tv; + struct timeval *tvp; + fd_set readfds, writefds; + + /* do we allow xpa processing within this routine? */ + _doxpa = 1; + + /* make sure we have a valid data channel */ + if( fd < 0 ) return(-1); + + /* make sure we have a valid buf ptr and len ptr */ + if( (len == 0) || (buf == NULL) ) return(-1); + + FPRINTF((stderr, "%sXPAPutBuf: writing %lu bytes to %d\n", + _sp, (unsigned long)len, fd)); + + /* start the interrupt handler */ + XPAInterruptStart(); + + /* turn this xpa off */ + active = XPAActive(xpa, xpa_comm(xpa), 0); + + /* put socket into non-blocking mode */ + xfcntl_nonblock(fd,flags); + + cur = 0; + total = len; + /* write in batches until done */ + done1 = (cur >= total); + firsttime = 1; + while( !done1 ){ + /* first time through we try the primary IO before selecting */ + if( !firsttime ){ + /* set up timer, if necessary */ + if( timeout >= 0 ){ + tv.tv_sec = timeout; + tv.tv_usec = 0; + tvp = &tv; + } + else{ + tvp = NULL; + } + /* select this socket and all XPA server sockets */ + FD_ZERO(&readfds); + FD_ZERO(&writefds); + FD_SET(fd, &writefds); + if( doxpa && _doxpa ){ + XPAClientAddSelect(NULL, &readfds, &writefds); + XPAAddSelect(NULL, &readfds); + } + /* wait for the IO ready */ + FPRINTF((stderr, "%sXPAPutBuf: select on fd %d ...", _sp, fd)); + got = xselect(swidth, &readfds, &writefds, NULL, tvp); + FPRINTF((stderr, " returned %d\n", got)); + /* check for user interrupt or error or timeout */ + if( XPAIOErrorCheck() || (got <=0) ){ + cur = -1; + done1 = 1; + continue; + } + /* if socket is not ready, process XPA's and try again */ + if( !FD_ISSET(fd, &writefds) ){ + if( doxpa && _doxpa ){ + XPALevelSet(1); + XPAClientProcessSelect(NULL, &readfds, &writefds, 0); + XPAProcessSelect(&readfds, 0); + XPALevelSet(-1); + } + continue; + } + } + else{ + firsttime = 0; + } + done2 = 0; + while( !done1 && !done2 ){ + /* calculate size of next chunk */ + if( (n = MIN(total-cur, XPA_IOSIZE)) <=0 ){ + done1 = 1; + continue; + } + /* write the data */ + got=send(fd, &buf[cur], n, 0); + FPRINTF((stderr, "%sXPAPutBuf: %d sent %lu bytes (tried %d at %d)\n", + _sp, fd, (unsigned long)got, n, cur)); + /* check for user interrupt */ + if( XPAIOErrorCheck() ){ + cur = -1; + done1 = 1; + continue; + } + /* process result code */ + switch(got){ + case -1: + PERROR(("XPAPutBuf send")); + /* socket would block */ + if((xerrno == EINPROGRESS) || + (xerrno == EWOULDBLOCK) || + (xerrno == EAGAIN) ){ + done2 = 1; + } + /* error of some sort */ + else{ + cur = -1; + done1 = 1; + } + break; + case 0: + /* EOF */ + done1 = 1; + break; + default: + /* got some data */ + cur += got; + done1 = (cur >= total); + break; + } + } + } + + /* restore socket mode */ + xfcntl_restore(fd,flags); + + /* restore active flag */ + XPAActive(xpa, xpa_comm(xpa), active); + + /* stop the interrupt handler */ + XPAInterruptEnd(); + + /* return error code or length */ + return(cur); +} + +/* + *---------------------------------------------------------------------------- + * + * Routine: XPAIOCallsXPA + * + * Purpose: function to flag whether IO calls also call XPA + * + * Returns: old value + * + *---------------------------------------------------------------------------- + */ +#ifdef ANSI_FUNC +int +XPAIOCallsXPA (int flag) +#else +int XPAIOCallsXPA(flag) + int flag; +#endif +{ + int old_doxpa; + + old_doxpa=doxpa; + doxpa = flag; + return old_doxpa; +} + +/* + *---------------------------------------------------------------------------- + * + * Routine: XPALevelSpaces + * + * Purpose: return string containing spaces for debugging process level + * + * Returns: string + * + *---------------------------------------------------------------------------- + */ +#ifdef ANSI_FUNC +char *XPALevelSpaces (void) +#else +char *XPALevelSpaces() +#endif +{ + return(_xpalevelspaces); +} + +/* + *---------------------------------------------------------------------------- + * + * Routine: XPALevelSet + * + * Purpose: set processing level and update level string for debugging + * + * Returns: none + * + *---------------------------------------------------------------------------- + */ +#ifdef ANSI_FUNC +void +XPALevelSet (int lev) +#else +void XPALevelSet(lev) +#endif +{ +#ifdef XPA_DEBUG + int i; + int spaces; + int maxspaces; + char tbuf[SZ_LINE]; +#endif + + level += lev; + _xpalevelspaces[0] = '\0'; +#ifdef XPA_DEBUG + sprintf(tbuf, "#%d:", level); + maxspaces = SZ_LINE - strlen(tbuf); + if( level < maxspaces ) + spaces = level; + else + spaces = maxspaces-1; + for(i=0; i<spaces; i++){ + _xpalevelspaces[i] = ' '; + _xpalevelspaces[i+1] = '\0'; + } + strncat(_xpalevelspaces, tbuf, SZ_LINE); +#endif +} + +/* + *---------------------------------------------------------------------------- + * + * Routine: XPALevelGet + * + * Purpose: get processing level + * + * Returns: none + * + *---------------------------------------------------------------------------- + */ +#ifdef ANSI_FUNC +int +XPALevelGet (void) +#else +int XPALevelGet() +#endif +{ + return level; +} + diff --git a/xpa/xpamb.c b/xpa/xpamb.c new file mode 100644 index 0000000..4e58fb5 --- /dev/null +++ b/xpa/xpamb.c @@ -0,0 +1,615 @@ +/* + * Copyright (c) 1999-2003 Smithsonian Astrophysical Observatory + */ + +#include <time.h> +#include <xpap.h> + +#define XPAMB_CLASS "XPAMB" +#define XPAMB_NAME "xpamb" +#define XPAMB_MODE NULL +#define XPAMB_HELP "xpa message bus:\n" + +/* message bus structure */ +typedef struct mbrec{ + struct mbrec *next; + char *name; + char *info; + char *buf; + size_t len; + time_t t; +} *MB, MBRec; + +/* this is the head of the message bus list -- too lazy to do anything more */ +static MB mbhead=NULL; + +/* global error message buffer */ +static char errbuf[SZ_LINE]; +static int maxhosts=XPA_MAXHOSTS; +static XPA xpa=NULL; + +/* + *---------------------------------------------------------------------------- + * + * Routine: XPAReceiveExit + * + * Purpose: exit program + * + * Returns: NONE + * + *---------------------------------------------------------------------------- + */ +#ifdef ANSI_FUNC +static int +XPAReceiveExit (void *client_data, void *call_data, char *paramlist, + char *buf, size_t len) +#else +static int XPAReceiveExit(client_data, call_data, paramlist, buf, len) + void *client_data; + void *call_data; + char *paramlist; + char *buf; + size_t len; +#endif +{ + /* freeing the xpa handle will cause the xpa loop to terminate */ + XPAFree(xpa); + return(0); +} + +/* + *---------------------------------------------------------------------------- + * + * Routine: XPASendExit + * + * Purpose: exit program + * + * Returns: NONE + * + *---------------------------------------------------------------------------- + */ +#ifdef ANSI_FUNC +static int +XPASendExit (void *client_data, void *call_data, char *paramlist, + char **buf, size_t *len) +#else +static int XPASendExit(client_data, call_data, paramlist, buf, len) + void *client_data; + void *call_data; + char *paramlist; + char **buf; + size_t *len; +#endif +{ + /* freeing the xpa handle will cause the xpa loop to terminate */ + XPAFree(xpa); + return(0); +} + +/* + *---------------------------------------------------------------------------- + * + * Routine: MBLookup + * + * Purpose: lookup anentry by name + * + * Returns: mb struct on success, NULL on failure + * + *---------------------------------------------------------------------------- + */ +#ifdef ANSI_FUNC +static MB +MBLookup (char *name) +#else +static MB MBLookup(name) + char *name; +#endif +{ + MB cur; + + /*make sure we have something to work with */ + if( (name == NULL) || (*name == '\0') ) + return(NULL); + + /* look for exact match */ + for(cur=mbhead; cur!=NULL; cur=cur->next){ + if( !strcmp(name, cur->name) ){ + return(cur); + } + } + return(NULL); +} + +/* + *--------------------------------------------------------------------------- + * + * Routine: MBDel + * + * Purpose: free up and remove an MB + * + * Results: 0 on success, -1 for failure + * + *--------------------------------------------------------------------------- + */ +#ifdef ANSI_FUNC +static int +MBDel (MB mb) +#else +static int MBDel(mb) + MB mb; +#endif +{ + MB cur; + + if( mb == NULL ){ + snprintf(errbuf, SZ_LINE, "can't delete invalid xpamb entry"); + return(-1); + } + + /* remove from list of MB's */ + if( mbhead ){ + if( mbhead == mb ){ + mbhead = mbhead->next; + } + else{ + for(cur=mbhead; cur!=NULL; cur=cur->next){ + if( cur->next == mb ){ + cur->next = (cur->next)->next; + break; + } + } + } + } + + /* free up alloc'ed space */ + if( mb->name ) xfree(mb->name); + if( mb->info ) xfree(mb->info); + if( mb->buf ) xfree(mb->buf); + + /* free up record struct */ + xfree((char *)mb); + return(0); +} + +/* + *--------------------------------------------------------------------------- + * + * Routine: MBRemove + * + * Purpose: free up and remove an MB by name + * + * Results: 0 on success, -1 for failure + * + *--------------------------------------------------------------------------- + */ +#ifdef ANSI_FUNC +static int +MBRemove (char *name) +#else +static int MBRemove(name) + char *name; +#endif +{ + MB mb; + + if( (mb=MBLookup(name)) != NULL ) + return(MBDel(mb)); + else{ + snprintf(errbuf, SZ_LINE, "can't delete unknown xpamb entry: %s", name); + return(-1); + } +} + +/* + *---------------------------------------------------------------------------- + * + * Routine: MBAdd + * + * Purpose: add one MB to the xpa MB list + * + * Returns: 0 on success, -1 on failure + * + *---------------------------------------------------------------------------- + */ +#ifdef ANSI_FUNC +static int +MBAdd (char *name, char *info, char *buf, size_t len, int replace) +#else +static int MBAdd(name, info, buf, len, replace) + char *name; + char *info; + char *buf; + size_t len; + int replace; +#endif +{ + MB xnew=NULL; + MB cur; + + /* see if this entry already exists */ + if( (cur = MBLookup(name)) != NULL ){ + if( !replace ){ + snprintf(errbuf, SZ_LINE, "xpamb entry already exists: %s", name); + goto error; + } + else + MBDel(cur); + } + + /* allocate MB struct */ + if( (xnew = (MB)xcalloc(1, sizeof(MBRec))) == NULL ){ + snprintf(errbuf, SZ_LINE, "can't allocate memory for xpamb entry: %s", + name); + goto error; + } + + /* fill in the blanks */ + xnew->name = xstrdup(name); + xnew->info = xstrdup(info); + if( !(xnew->buf = (char *)xmalloc(len)) ){ + snprintf(errbuf, SZ_LINE, "can't allocate memory for xpamb buffer: %s", + name); + goto error; + } + memcpy(xnew->buf, buf, len); + xnew->len = len; + xnew->t = time(NULL); + + /* add this MB to end of list of MB's */ + if( mbhead == NULL ){ + mbhead = xnew; + } + else{ + for(cur=mbhead; cur->next!=NULL; cur=cur->next) + ; + cur->next = xnew; + } + return(0); + +error: + if( xnew ) + xfree(xnew); + return(-1); +} + +/* + *--------------------------------------------------------------------------- + * + * Routine: MBInfo + * + * Purpose: send info string to specified fd + * + * Results: 0 on success, -1 for failure + * + *--------------------------------------------------------------------------- + */ +#ifdef ANSI_FUNC +static int +MBInfo (int fd, MB mb) +#else +static int MBInfo(fd, mb) + int fd; + MB mb; +#endif +{ + MB cur; + char *tbuf; + + if( mb != NULL ){ + tbuf = (char *)xmalloc(strlen(mb->name) + SZ_LINE); + snprintf(tbuf, SZ_LINE, "%s\tsize:\t\t%d\n\tcreated:\t%s", + mb->name, (int)mb->len, ctime(&(mb->t))); + send(fd, tbuf, strlen(tbuf), 0); + xfree(tbuf); + if( mb->info && *(mb->info) ){ + tbuf = (char *)xmalloc(strlen(mb->info) + SZ_LINE); + snprintf(tbuf, SZ_LINE, "\tinfo:\t\t%s\n", mb->info); + send(fd, tbuf, strlen(tbuf), 0); + xfree(tbuf); + } + } + else{ + /* send info for all entries */ + for(cur=mbhead; cur!=NULL; cur=cur->next){ + MBInfo(fd, cur); + } + } + return(0); +} + +/* + *--------------------------------------------------------------------------- + * + * Routine: MBData + * + * Purpose: send data to specified fd + * + * Results: 0 on success, -1 for failure + * + *--------------------------------------------------------------------------- + */ +#ifdef ANSI_FUNC +static int +MBData (int fd, MB mb) +#else +static int MBData(fd, mb) + int fd; + MB mb; +#endif +{ + if( mb != NULL ){ + if( mb->buf && mb->len ){ + if( send(fd, mb->buf, mb->len, 0) == mb->len ){ + return(0); + } + else{ + snprintf(errbuf, SZ_LINE, "writing data for xpamb entry: %s", + mb->name); + return(-1); + } + } + else{ + return(0); + } + } + return(0); +} + +/* + *--------------------------------------------------------------------------- + * + * Routine: MBSendCB + * + * Purpose: callback when we need to send data to a client + * + * Results: 0 on success, -1 for failure + * + *--------------------------------------------------------------------------- + */ +#ifdef ANSI_FUNC +static int +MBSendCB (void *client_data, void *call_data, char *paramlist, + char **buf, size_t *len) +#else +static int MBSendCB(client_data, call_data, paramlist, buf, len) + void *client_data; + void *call_data; + char *paramlist; + char **buf; + size_t *len; +#endif +{ + XPA xpa = (XPA)call_data; + MB mb; + int i; + int got=0; + int tp=0; + int doinfo=0; + int dodata=0; + int status=0; + int fds[1]; + char tbuf[SZ_LINE]; + char *errs[XPA_MAXHOSTS]; + char *names[XPA_MAXHOSTS]; + + /* reset error buffer */ + *errbuf = '\0'; + + /* no paramlist means return info on all stored entries */ + if( !paramlist || !*paramlist ){ + return(MBInfo(xpa_datafd(xpa), NULL)); + } + + /* process switches */ + while( word(paramlist, tbuf, &tp) ){ + if( *tbuf != '-' ) + break; + else if( !strcmp(tbuf, "-data") ){ + dodata++; + } + else if( !strcmp(tbuf, "-info") ){ + doinfo++; + } + else{ + break; + } + } + + if( doinfo || dodata ){ + if( !*tbuf ){ + snprintf(errbuf, SZ_LINE, "missing xpamb entry name"); + status = -1; + } + if( (mb=MBLookup(tbuf)) != NULL ){ + if( doinfo ){ + status = MBInfo(xpa_datafd(xpa), mb); + } + if( dodata ){ + status = MBData(xpa_datafd(xpa), mb); + } + } + else{ + snprintf(errbuf, SZ_LINE, "unknown xpamb entry: %s", tbuf); + status = -1; + } + } + else{ + fds[0] = xpa_datafd(xpa); + got = XPAGetFd(NULL, tbuf, ¶mlist[tp], NULL, fds, names, errs, + -maxhosts); + for(i=0; i<got; i++){ + if( errs[i] ){ + if( !*errbuf ) + strcpy(errbuf, errs[i]); + status = -1; + xfree(errs[i]); + } + if( names[i] ) xfree(names[i]); + } + } + + /* send error message and return status */ + if( *errbuf ) + XPAError(xpa, errbuf); + return(status); +} + +/* + *--------------------------------------------------------------------------- + * + * Routine: MBRecCB + * + * Purpose: callback when we receive data/command from a client + * + * Results: 0 on success, -1 for failure + * + *--------------------------------------------------------------------------- + */ +#ifdef ANSI_FUNC +static int +MBRecCB (void *client_data, void *call_data, char *paramlist, + char *buf, size_t len) +#else +static int MBRecCB(client_data, call_data, paramlist, buf, len) + void *client_data; + void *call_data; + char *paramlist; + char *buf; + size_t len; +#endif +{ + XPA xpa = (XPA)call_data; + MB mb; + int i; + int got=0; + int tp=0; + int rflag=0; + int status=0; + char tbuf[SZ_LINE]; + char xsend[SZ_LINE]; + char xadd[SZ_LINE]; + char xinfo[SZ_LINE]; + char xremove[SZ_LINE]; + char xtemplate[SZ_LINE]; + char *errs[XPA_MAXHOSTS]; + char *names[XPA_MAXHOSTS]; + + /* init flags */ + *xsend = '\0'; + *xadd = '\0'; + *xinfo = '\0'; + *xremove = '\0'; + /* reset error buffer */ + *errbuf = '\0'; + + /* process switches */ + while( word(paramlist, tbuf, &tp) ){ + if( *tbuf != '-' ) + break; + else if( !strcmp(tbuf, "-data") ){ + word(paramlist, xadd, &tp); + } + else if( !strcmp(tbuf, "-add") ){ + word(paramlist, xadd, &tp); + } + else if( !strcmp(tbuf, "-replace") ){ + word(paramlist, xadd, &tp); + rflag = 1; + } + else if( !strcmp(tbuf, "-info") ){ + word(paramlist, xinfo, &tp); + } + else if( !strncmp(tbuf, "-del", 4) ){ + word(paramlist, xremove, &tp); + } + else if( !strcmp(tbuf, "-send") ){ + word(paramlist, xsend, &tp); + } + else + break; + } + + /* broadcast data, if we have a target + the first non-switch word we found previously is the target */ + if( *tbuf ){ + strcpy(xtemplate, tbuf); + /* the rest of the input string is the paramlist */ + paramlist = &(paramlist[tp]); + /* send named data, if necessary */ + if( *xsend != '\0' ){ + if( (mb=MBLookup(xsend)) != NULL ){ + got = XPASet(NULL, xtemplate, paramlist, NULL, mb->buf, mb->len, + names, errs, maxhosts); + } + if( (buf != NULL) && (len>0) ){ + got = XPASet(NULL, xtemplate, paramlist, NULL, buf, len, + names, errs, maxhosts); + } + } + else{ + got = XPASet(NULL, xtemplate, paramlist, NULL, buf, len, + names, errs, maxhosts); + } + for(i=0; i<got; i++){ + if( errs[i] ){ + if( !*errbuf ) + strcpy(errbuf, errs[i]); + status = -1; + xfree(errs[i]); + } + if( names[i] ) xfree(names[i]); + } + } + + /* save named data, if necessary */ + if( *xadd !='\0' ){ + status = MBAdd(xadd, xinfo, buf, len, rflag); + } + + /* remove named data, if necessary */ + if( *xremove !='\0' ){ + status = MBRemove(xremove); + } + + /* send error message and return status */ + if( *errbuf ) + XPAError(xpa, errbuf); + return(status); +} + +#ifdef ANSI_FUNC +int +main (int argc, char **argv) +#else +int main(argc, argv) + int argc; + char **argv; +#endif +{ + char *s; + + /* display version and exit, if necessary */ + if( (argc == 2) && !strcmp(argv[1], "--version") ){ + fprintf(stderr, "%s\n", XPA_VERSION); + exit(0); + } + + /* set global value for max hosts */ + maxhosts=XPA_MAXHOSTS; + if( (s=(char *)getenv("XPA_MAXHOSTS")) != NULL ) + maxhosts = atoi(s); + + /* start up the xpa access point */ + if( !(xpa=XPANew(XPAMB_CLASS, XPAMB_NAME, XPAMB_HELP, + MBSendCB, NULL, XPAMB_MODE, MBRecCB, NULL, XPAMB_MODE)) ){ + fprintf(stderr, "XPA$ERROR: could not create xpamb access point\n"); + exit(1); + } + /* allow for a graceful exit */ + XPACmdAdd(XPAGetReserved (), "-exit", "\texit program", + XPASendExit, NULL, NULL, XPAReceiveExit, NULL, "fillbuf=false"); + + /* process events */ + XPAMainLoop(); + return(0); +} diff --git a/xpa/xpans.c b/xpa/xpans.c new file mode 100644 index 0000000..af727aa --- /dev/null +++ b/xpa/xpans.c @@ -0,0 +1,1935 @@ +/* + * Copyright (c) 1999-2003 Smithsonian Astrophysical Observatory + */ + +#include <xpap.h> + +#if HAVE_LIBPTHREAD +#include <pthread.h> +static pthread_mutex_t xpans_mutex = PTHREAD_MUTEX_INITIALIZER; +#endif + +#define MAX_ERRORS 5 + +static int doproxy=0; +static unsigned int localhost_ip=0; + +extern char *optarg; +extern int optind; + +typedef struct entrec{ + struct entrec *next; + char *method; + char *xclass; + char *name; + char *type; + char *user; + char *info; +} *Entry, EntryRec; + +typedef struct reqrec{ + struct reqrec *next; + int sock; + unsigned int ip; + int port; + Entry entry; +} *Req, ReqRec; + +static char *helpbuf = "xpans commands:\nhelp\t\t\t\t# print this help message\nlist\t\t\t\t# list all entries\nlookup class:name type user\t# lookup entries of this type and user\n"; + +static int keepalive=0; +static int ksec=0; +static int mtype = 0; +static int nentry = 0; +static int exconn=0; +static int sock=-1; +static char *logfile=NULL; +static time_t lastt=(time_t)0; +static time_t curt=(time_t)0; +static FILE *securefp=NULL; +static Req reqhead=NULL; + +static int LookupReq _PRx((Req xreq, char *lbuf, int flag)); +static int ListReq _PRx((Req xreq, int flag)); +static void HelpReq _PRx((Req xreq, int flag)); +#ifdef __STDC__ +static void SecureLog(char *format, ...); +#else +static void SecureLog(); +#endif + +#if HAVE_LIBPTHREAD +/* + *---------------------------------------------------------------------------- + * + * Routine: doxpaloop + * + * Purpose: start up XPAMainLoop in another thread + * + * Returns: NONE + * + *---------------------------------------------------------------------------- + */ +#ifdef ANSI_FUNC +void *doxpaloop(void *arg) +#else +void *doxpaloop(arg) + void *arg; +#endif +{ + XPAMainLoop(); + return (void *)NULL; +} +#endif + +/* + *---------------------------------------------------------------------------- + * + * Routine: receive_proxy + * + * Purpose: receive callback for a proxy request + * + * Returns: 0 for success, -1 for failure + * + *---------------------------------------------------------------------------- + */ +#ifdef ANSI_FUNC +static int +receive_proxy (void *client_data, void *call_data, char *paramlist, + char *buf, int len) +#else +int receive_proxy(client_data, call_data, paramlist, buf, len) + void *client_data; + void *call_data; + char *paramlist; + char *buf; + int len; +#endif +{ + XPA xpa = (XPA)call_data; + char *xtemplate; + char *mode; + char *err; + char *s; + char xmode[SZ_LINE]; + char tbuf[SZ_LINE]; + int fd=0; + int pfd=-1; + int got=0; + Req req=NULL; + + xtemplate = xpa->comm->target; + mode = xpa->comm->info; + fd = xpa->comm->datafd; + + /* get proxy fd and associated xpans request struct */ + if( mode ){ + strcpy(xmode, mode); + if( keyword(xmode, "nsproxy", tbuf, SZ_LINE) ){ + pfd = strtol(tbuf, &s, 0); + if( s != tbuf ){ + for(req=reqhead; req!=NULL; req=req->next){ + if( req->sock == pfd ){ + break; + } + } + } + } + } + if( pfd < 0 ){ + snprintf(tbuf, SZ_LINE, "invalid or missing proxy fd"); + XPAError(xpa, tbuf); + return(-1); + } + else if( req == NULL ){ + snprintf(tbuf, SZ_LINE, "could not find xpans fd for proxy fd %d", pfd); + XPAError(xpa, tbuf); + return(-1); + } + + FPRINTF((stderr, "%sreceive_proxy: fd=%d xtmpl=%s mode=%s paramlist=%s\n", + _sp, xpa->comm->cmdfd, xtemplate, mode, + paramlist?paramlist:"NONE")); + + if( XPASetFd(xpa, xtemplate, paramlist, mode, fd, NULL, &err, 1) ){ + /* display errors and free up strings */ + if( err != NULL ){ + XPAError(xpa, err); + xfree(err); + got = -1; + } + } + else{ + got = -1; + } + + FPRINTF((stderr, "%sreceive_proxy done\n", _sp)); + return(got); +} + +/* + *---------------------------------------------------------------------------- + * + * Routine: send_proxy + * + * Purpose: send callback for a proxy request + * + * Returns: 0 for success, -1 for failure + * + *---------------------------------------------------------------------------- + */ +#ifdef ANSI_FUNC +static int +send_proxy (void *client_data, void *call_data, char *paramlist, + char **buf, size_t *len) +#else +static int send_proxy(client_data, call_data, paramlist, buf, len) + void *client_data; + void *call_data; + char *paramlist; + char **buf; + size_t *len; +#endif +{ + XPA xpa = (XPA)call_data; + char *xtemplate; + char *mode; + char *err; + char *s; + char xmode[SZ_LINE]; + char tbuf[SZ_LINE]; + int fd=0; + int pfd=-1; + int got=0; + Req req=NULL; + + xtemplate = xpa->comm->target; + mode = xpa->comm->info; + fd = xpa->comm->datafd; + + /* get proxy fd and associated xpans request struct */ + if( mode ){ + strcpy(xmode, mode); + if( keyword(xmode, "nsproxy", tbuf, SZ_LINE) ){ + pfd = strtol(tbuf, &s, 0); + if( s != tbuf ){ + for(req=reqhead; req!=NULL; req=req->next){ + if( req->sock == pfd ){ + break; + } + } + } + } + } + if( pfd < 0 ){ + snprintf(tbuf, SZ_LINE, "invalid or missing proxy fd"); + XPAError(xpa, tbuf); + return(-1); + } + else if( req == NULL ){ + snprintf(tbuf, SZ_LINE, "could not find xpans fd for proxy fd %d", pfd); + XPAError(xpa, tbuf); + return(-1); + } + + FPRINTF((stderr, "%ssend_proxy: fd=%d xtemplate=%s mode=%s paramlist=%s\n", + _sp, xpa->comm->cmdfd, xtemplate, mode, paramlist?paramlist:"NONE")); + + if( XPAGetFd(xpa, xtemplate, paramlist, mode, &fd, NULL, &err, 1) ){ + /* display errors and free up strings */ + if( err != NULL ){ + XPAError(xpa, err); + xfree(err); + got = -1; + } + } + else{ + got = -1; + } + + FPRINTF((stderr, "%ssend_proxy done\n", _sp)); + return(got); +} + +/* + *---------------------------------------------------------------------------- + * + * Routine: receive_cb + * + * Purpose: receive callback for XPA access point + * + * Returns: 0 for success, -1 for failure + * + *---------------------------------------------------------------------------- + */ +#ifdef ANSI_FUNC +static int +receive_cb (void *client_data, void *call_data, char *paramlist, + char *buf, size_t len) +#else +int receive_cb(client_data, call_data, paramlist, buf, len) + void *client_data; + void *call_data; + char *paramlist; + char *buf; + size_t len; +#endif +{ + XPA xpa = (XPA)call_data; + char tbuf[SZ_LINE]; + + /* if target is not xpans, we have a proxy request */ + snprintf(tbuf, SZ_LINE, "%s:%s", XPANS_CLASS, XPANS_NAME); + if( strcmp(xpa->comm->target, tbuf) ){ + if( doproxy ) + return(receive_proxy(client_data, call_data, paramlist, buf, len)); + else{ + XPAError(xpa, "proxy requests not enabled in this xpans"); + return(-1); + } + } + + /* nothing to do for normal receive callback */ + XPAError(xpa, "no receive function defined for xpans"); + return(-1); +} + +/* + *---------------------------------------------------------------------------- + * + * Routine: send_cb + * + * Purpose: send callback for XPA access point + * + * Returns: 0 for success, -1 for failure + * + *---------------------------------------------------------------------------- + */ +#ifdef ANSI_FUNC +static int +send_cb (void *client_data, void *call_data, char *paramlist, + char **buf, size_t *len) +#else +static int send_cb(client_data, call_data, paramlist, buf, len) + void *client_data; + void *call_data; + char *paramlist; + char **buf; + size_t *len; +#endif +{ + XPA xpa = (XPA)call_data; + Req req; + char tbuf[SZ_LINE]; + char ebuf[SZ_LINE]; + char tmpl[SZ_LINE]; + char type[SZ_LINE]; + char users[SZ_LINE]; + int got=0; + int wp=0; + + /* if target is not xpans, we have a proxy request */ + snprintf(tbuf, SZ_LINE, "%s:%s", XPANS_CLASS, XPANS_NAME); + if( strcmp(xpa->comm->target, tbuf) ){ + if( doproxy ) + return(send_proxy(client_data, call_data, paramlist, buf, len)); + else{ + XPAError(xpa, "proxy requests not enabled in this xpans"); + return(-1); + } + } + + if( paramlist && *paramlist ) + SecureLog("xpaget from host %x:%d (%s): %s", + xpa->comm->cmdip, xpa->comm->cmdport, + getiphost(xpa->comm->cmdip), + (paramlist && *paramlist)?paramlist:"<no params>"); + else + SecureLog("xpaget from host %x:%d (%s)", + xpa->comm->cmdip, xpa->comm->cmdport, + getiphost(xpa->comm->cmdip)); + if( (req = (Req)xcalloc(1, sizeof(ReqRec))) == NULL ) + return(-1); + if( xpa_datafd(xpa) >= 0 ){ + req->sock = xpa_datafd(xpa); + } + +#if HAVE_LIBPTHREAD + /* lock the mutex before processing a request */ + if( doproxy >= 2 ) pthread_mutex_lock(&xpans_mutex); +#endif + + /* execute the appropriate routine */ + if( paramlist && *paramlist && word(paramlist, tbuf, &wp) ){ + if( !strcmp(tbuf, "list") ){ + ListReq(req, 0); + } + else if( !strcmp(tbuf, "help") ){ + HelpReq(req, 0); + } + else if( !strcmp(tbuf, "lookup") ){ + if( word(paramlist, tmpl, &wp ) ){ + /* look for type */ + if( !word(paramlist, type, &wp ) ) + strcpy(type, XPA_ACLS); + /* look for users */ + if( !word(paramlist, users, &wp ) ) + strcpy(users, "*"); + snprintf(tbuf, SZ_LINE, "%s %s %s", tmpl, type, users); + LookupReq(req, tbuf, 0); + } + else{ + strcpy(ebuf, + "XPA$ERROR 'lookup' requires class:name [type] [user]\n"); + XPAPuts(NULL, req->sock, ebuf, XPALongTimeout()); + got = -1; + } + } + else{ + snprintf(ebuf, SZ_LINE, "XPA$ERROR unknown command '%s'\n", tbuf); + XPAPuts(NULL, req->sock, ebuf, XPALongTimeout()); + got = -1; + } + } + else { + ListReq(req, 0); + } + +#if HAVE_LIBPTHREAD + /* unlock the mutex */ + if( doproxy >= 2 ) pthread_mutex_unlock(&xpans_mutex); +#endif + + /* clean up */ + if( req ) xfree(req); + return(got); +} + +/* + *---------------------------------------------------------------------------- + * + * Routine: Log + * + * Purpose: write all names to a backup log + * + * Returns: none + * + *---------------------------------------------------------------------------- + */ +#ifdef ANSI_FUNC +static void +Log (void) +#else +static void Log() +#endif +{ + FILE *fp; + Req req; + Entry entry; + + if( !logfile ) + return; + if( !strcasecmp(logfile, "stdout") ) + fp = stdout; + else if( (fp=fopen(logfile, "w")) == NULL ) + return; + for(req=reqhead; req!=NULL; req=req->next){ + for(entry=req->entry; entry!=NULL; entry=entry->next){ + fprintf(fp, "# add %s %s %s %s %s\n", + entry->method, entry->xclass, + entry->name, entry->type, entry->user); + /* last one */ + if( entry->next == NULL ) + fprintf(fp, "xpaset -p %s -nsconnect\n", entry->method); + } + } + if( fp != stdout ) + fclose(fp); +} + +/* + *---------------------------------------------------------------------------- + * + * Routine: SecureLog + * + * Purpose: write security info to a backup log + * + * Returns: none + * + *---------------------------------------------------------------------------- + */ +#ifdef __STDC__ +void SecureLog(char *format, ...) +{ + char sbuf[SZ_LINE]; + time_t t; + va_list args; + va_start(args, format); +#else +void SecureLog(va_alist) va_dcl +{ + char *format; + char sbuf[SZ_LINE]; + time_t t; + va_list args; + + va_start(args); + format = va_arg(args, char *); +#endif + if( securefp == NULL ) + return; + t = time(NULL); + vsnprintf(sbuf, SZ_LINE, format, args); + fprintf(securefp, "%s", sbuf); + fprintf(securefp, "\t%s", ctime(&t)); + fflush(securefp); +} + +/* + *---------------------------------------------------------------------------- + * + * Routine: SplitArg + * + * Purpose: split the specified argument by changing a ":" to a space + * splitting is done in place + * + * Returns: none + * + *---------------------------------------------------------------------------- + */ +#ifdef ANSI_FUNC +static void +SplitArg (char *buf, int arg) +#else +static void SplitArg(buf, arg) + char *buf; + int arg; +#endif +{ + int i; + char *s; + + /* point to beginning of buffer */ + s = buf; + /* skip over previous args */ + for(i=0; i<arg; i++){ + /* skip up to white space */ + while( *s && !isspace((int)*s) ) + s++; + /* skip over white space to next arg */ + while( *s && isspace((int)*s) ) + s++; + } + /* we now are pointing at the arg in question. + look for a ':' (up to next white space) and change to space */ + while( *s && !isspace((int)*s) ){ + if( *s == ':' ){ + *s = ' '; + break; + } + else + s++; + } +} + +/* + *---------------------------------------------------------------------------- + * + * Routine: NewEntry + * + * Purpose: allocate a new XPA entry + * + * Returns: entry struct + * + *---------------------------------------------------------------------------- + */ +#ifdef ANSI_FUNC +static int +NewEntry (Req req, + char *method, char *xclass, char *name, + char *type, char *user, char *info) +#else +static int NewEntry(req, method, xclass, name, type, user, info) + Req req; + char *method; + char *xclass; + char *name; + char *type; + char *user; + char *info; +#endif +{ + Entry entry, cur; + Req xreq; + + /* don't duplicate with any other entry */ + for(xreq=reqhead; xreq!=NULL; xreq=xreq->next){ + for(entry=xreq->entry; entry!=NULL; entry=entry->next){ + if( !strcmp(entry->method, method) && + !strcmp(entry->xclass, xclass) && + !strcmp(entry->name, name) && + !strcmp(entry->type, type) && + !strcmp(entry->user, user) && + !strcmp(entry->info, info) ) + return(1); + } + } + + /* allocate new entry */ + if( (entry = (Entry)xcalloc(1, sizeof(EntryRec))) == NULL ) + return(-1); + + /* fill in the blanks */ + entry->xclass = xstrdup(xclass); + entry->name = xstrdup(name); + entry->method = xstrdup(method); + entry->type = xstrdup(type); + entry->user = xstrdup(user); + entry->info = xstrdup(info); + + FPRINTF((stderr, "%sNewEntry: %s %s %s %s %s %s\n", _sp, + xclass, name, method, type, user, info)); + + /* add this to end of the list */ + if( req->entry == NULL ){ + req->entry = entry; + } + else{ + for(cur=req->entry; cur->next!=NULL; cur=cur->next) + ; + cur->next = entry; + } + + /* inc the total number of entries */ + nentry++; + + /* return the news */ + return(0); +} + +/* + *---------------------------------------------------------------------------- + * + * Routine: FreeEntry + * + * Purpose: free up an XPA entry + * + * Returns: none + * + *---------------------------------------------------------------------------- + */ +#ifdef ANSI_FUNC +static void +FreeEntry (Req req, Entry entry) +#else +static void FreeEntry(req, entry) + Req req; + Entry entry; +#endif +{ + Entry cur; + + /* remove this entry from the list so it can't be found */ + if( entry == req->entry ){ + req->entry = req->entry->next; + } + else{ + for(cur=req->entry; cur!=NULL; cur=cur->next){ + if( entry == cur->next ){ + cur->next = entry->next; + break; + } + } + } + + FPRINTF((stderr, "%sFreeEntry: %s %s\n", _sp, entry->xclass, entry->name)); + + /* now free this struct */ + if( entry->method ) + xfree(entry->method); + if( entry->xclass ) + xfree(entry->xclass); + if( entry->name ) + xfree(entry->name); + if( entry->type ) + xfree(entry->type); + if( entry->user ) + xfree(entry->user); + if( entry->info ) + xfree(entry->info); + xfree(entry); +} + +/* + *---------------------------------------------------------------------------- + * + * Routine: DelEntry + * + * Purpose: Delete an XPA entry + * + * Returns: none + * + *---------------------------------------------------------------------------- + */ +#ifdef ANSI_FUNC +static int +DelEntry (Req req, char *method) +#else +static int DelEntry(req, method) + Req req; + char *method; +#endif +{ + Entry cur, tcur; + int got=-1; + + for(cur=req->entry; cur!=NULL; ){ + tcur = cur->next; + if( ((method == NULL) || (*method == '\0')) || + (!strcmp(method, "@") && (*cur->method == '@')) || + !strcmp(cur->method, method) ){ + FreeEntry(req, cur); + got = 0; + } + cur = tcur; + } + return(got); +} + +/* + *---------------------------------------------------------------------------- + * + * Routine: FirewallEntry + * + * Purpose: Correct the method to take a firewall into account + * we do this by taking the ip from the socket packet instead + * of the specified ip, if they differ + * + * Returns: none + * + *---------------------------------------------------------------------------- + */ +#ifdef ANSI_FUNC +static void +FirewallEntry (Req req, char *method) +#else +static void FirewallEntry(req, method) + Req req; + char *method; +#endif +{ + unsigned int ip; + unsigned short port; + + if( mtype != XPA_INET ) + return; + if( XPAParseIpPort(method, &ip, &port) ){ + if( (ip != req->ip) && (req->ip != localhost_ip) ){ + SecureLog("firewall %d: changing ip from %x to %x", + req->sock, ip, req->ip); + snprintf(method, SZ_LINE, "%x:%d", req->ip, port); + } + } +} + +/* + *---------------------------------------------------------------------------- + * + * Routine: NewReq + * + * Purpose: allocate a new XPA request struct + * + * Returns: Req struct + * + *---------------------------------------------------------------------------- + */ +#ifdef ANSI_FUNC +static Req +NewReq (int sock, unsigned int ip, int port) +#else +static Req NewReq(sock, ip, port) + int sock; + unsigned int ip; + int port; +#endif +{ + Req req; + Req cur; + + if( (req = (Req)xcalloc(1, sizeof(ReqRec))) == NULL ) + return(NULL); + + /* fill in the blanks */ + req->sock = sock; + req->ip = ip; + req->port = port; + + /* add this to end of the list */ + if( reqhead == NULL ){ + reqhead = req; + } + else{ + for(cur=reqhead; cur->next!=NULL; cur=cur->next) + ; + cur->next = req; + } + /* return the news */ + return(req); +} + +/* + *---------------------------------------------------------------------------- + * + * Routine: FreeReq + * + * Purpose: free up an XPA request entry + * + * Returns: none + * + *---------------------------------------------------------------------------- + */ +#ifdef ANSI_FUNC +static void +FreeReq (Req req) +#else +static void FreeReq(req) + Req req; +#endif +{ + Req cur; + /* remove this entry from the list so it can't be found */ + if( req == reqhead ){ + reqhead = req->next; + } + else{ + for(cur=reqhead; cur!=NULL; cur=cur->next){ + if( req == cur->next ){ + cur->next = req->next; + break; + } + } + } + /* close the communication channel */ + close(req->sock); + /* now free this struct */ + xfree(req); +} + +/* + *---------------------------------------------------------------------------- + * + * Routine: AddReq + * + * Purpose: add an XPA entry to the list + * + * Returns: none + * + *---------------------------------------------------------------------------- + */ +#ifdef ANSI_FUNC +static void +AddReq (Req req, char *lbuf, int flag) +#else +static void AddReq(req, lbuf, flag) + Req req; + char *lbuf; + int flag; +#endif +{ + int got; + char xclass[SZ_LINE]; + char name[SZ_LINE]; + char method[SZ_LINE]; + char omethod[SZ_LINE]; + char type[SZ_LINE]; + char user[SZ_LINE]; + char tbuf[SZ_LINE]; + + SplitArg(lbuf, 1); + got = sscanf(lbuf, "%s %s %s %s %s", method, xclass, name, type, user); + if( got == 5 ){ + /* fix method if we can determine its been through a firewall */ + strcpy(omethod, method); + FirewallEntry(req, method); + if( !strcmp(omethod, method) ) + strcpy(tbuf, method); + else + snprintf(tbuf, SZ_LINE, "%s,%s", method, omethod); + /* add the new entry */ + got = NewEntry(req, tbuf, xclass, name, type, user, XPA_DEF_CLIENT_INFO); + Log(); + if( flag ){ + switch(got){ + case -1: + XPAPuts(NULL, req->sock, "XPA$ERROR could not add entry\n", + XPALongTimeout()); + break; + case 0: + XPAPuts(NULL, req->sock, "XPA$OK\n", XPALongTimeout()); + break; + case 1: + XPAPuts(NULL, req->sock, "XPA$EXISTS entry already exists\n", + XPALongTimeout()); + break; + default: + XPAPuts(NULL, req->sock, "XPA$ERROR could not add entry\n", + XPALongTimeout()); + break; + } + } + } + else{ + strcpy(tbuf, + "XPA$ERROR 'add' requires 4 args: ip:port class:name type user\n"); + XPAPuts(NULL, req->sock, tbuf, XPALongTimeout()); + } +} + +/* + *---------------------------------------------------------------------------- + * + * Routine: AddProxyReq + * + * Purpose: add an XPA proxy entry to the list + * + * Returns: none + * + *---------------------------------------------------------------------------- + */ +#ifdef ANSI_FUNC +static void +AddProxyReq (Req req, char *lbuf, int flag) +#else +static void AddProxyReq(req, lbuf, flag) + Req req; + char *lbuf; + int flag; +#endif +{ + int got=0; + char xclass[SZ_LINE]; + char name[SZ_LINE]; + char method[SZ_LINE]; + char omethod[SZ_LINE]; + char type[SZ_LINE]; + char user[SZ_LINE]; + char info[SZ_LINE]; + char tbuf[SZ_LINE]; + + /* make sure we are accepting proxy requests */ + if( !doproxy ){ + strcpy(tbuf, + "XPA$ERROR: proxy requests not enabled in this xpans\n"); + XPAPuts(NULL, req->sock, tbuf, XPALongTimeout()); + return; + } + + SplitArg(lbuf, 1); + got = sscanf(lbuf, "%s %s %s %s %s", method, xclass, name, type, user); + if( got == 5 ){ + if( XPAMethod(method) == XPA_INET ){ + /* fix method if we can determine its been through a firewall */ + strcpy(omethod, method); + FirewallEntry(req, method); + if( !strcmp(omethod, method) ) + snprintf(tbuf, SZ_LINE, "@%s", method); + else + snprintf(tbuf, SZ_LINE, "@%s,%s", method, omethod); + } + else{ + strcpy(tbuf, + "XPA$ERROR 'proxy' requires INET method\n"); + XPAPuts(NULL, req->sock, tbuf, XPALongTimeout()); + return; + } + /* save info */ + snprintf(info, SZ_LINE, "nsproxy=%d,ns=(%s,%s,%s,%s),dofork=true", + req->sock, xclass, name, method, omethod); + /* add the new entry */ + got = NewEntry(req, tbuf, xclass, name, type, user, info); + Log(); + if( flag ){ + switch(got){ + case -1: + XPAPuts(NULL, req->sock, "XPA$ERROR could not add entry\n", + XPALongTimeout()); + break; + case 0: + XPAPuts(NULL, req->sock, "XPA$OK\n", XPALongTimeout()); + break; + case 1: + XPAPuts(NULL, req->sock, "XPA$EXISTS entry already exists\n", + XPALongTimeout()); + break; + default: + XPAPuts(NULL, req->sock, "XPA$ERROR could not add entry\n", + XPALongTimeout()); + break; + } + } + } + else{ + strcpy(tbuf, + "XPA$ERROR 'proxy' requires 4 args: ip:port class:name type user\n"); + XPAPuts(NULL, req->sock, tbuf, XPALongTimeout()); + } +} + +/* + *---------------------------------------------------------------------------- + * + * Routine: DelReq + * + * Purpose: delete an XPA entry from the list + * + * Returns: none + * + *---------------------------------------------------------------------------- + */ +#ifdef ANSI_FUNC +static void +DelReq (Req req, char *lbuf, int flag) +#else +static void DelReq(req, lbuf, flag) + Req req; + char *lbuf; + int flag; +#endif +{ + int got=0; + char method[SZ_LINE]; + char omethod[SZ_LINE]; + char tbuf[SZ_LINE]; + + if( lbuf != NULL ){ + if( sscanf(lbuf, "%s", method) == 1 ){ + /* fix method if we can determine its been through a firewall */ + strcpy(omethod, method); + FirewallEntry(req, method); + if( !strcmp(omethod, method) ) + strcpy(tbuf, method); + else + snprintf(tbuf, SZ_LINE, "%s,%s", method, omethod); + got = DelEntry(req, tbuf); + Log(); + if( flag ){ + if( got == 0 ) + XPAPuts(NULL, req->sock, "XPA$OK\n", XPALongTimeout()); + else + XPAPuts(NULL, req->sock, "XPA$ERROR entry does not exist\n", + XPALongTimeout()); + } + } + else{ + strcpy(tbuf, "XPA$ERROR 'del' requires 1 arg: ip:port\n"); + XPAPuts(NULL, req->sock, tbuf, XPALongTimeout()); + } + } + else{ + /* connection is closed -- free all entries for req, and delete req */ + FPRINTF((stderr, "%sxpans request really died: %d\n", _sp, req->sock)); + DelEntry(req, NULL); + FreeReq(req); + Log(); + } +} + +/* + *---------------------------------------------------------------------------- + * + * Routine: DelProxyReq + * + * Purpose: delete an XPA entry from the list + * + * Returns: none + * + *---------------------------------------------------------------------------- + */ +#ifdef ANSI_FUNC +static void +DelProxyReq (Req req, char *lbuf, int flag) +#else +static void DelProxyReq(req, lbuf, flag) + Req req; + char *lbuf; + int flag; +#endif +{ + int got=0; + char method[SZ_LINE]; + char omethod[SZ_LINE]; + char tbuf[SZ_LINE]; + + /* make sure we are accepting proxy requests */ + if( !doproxy ){ + strcpy(tbuf, + "XPA$ERROR: proxy requests not enabled in this xpans\n"); + XPAPuts(NULL, req->sock, tbuf, XPALongTimeout()); + return; + } + + if( lbuf != NULL ){ + if( sscanf(lbuf, "%s", method) == 1 ){ + /* fix method if we can determine its been through a firewall */ + strcpy(omethod, method); + FirewallEntry(req, method); + if( !strcmp(omethod, method) ) + strcpy(tbuf, method); + else + snprintf(tbuf, SZ_LINE, "@%s,%s", method, omethod); + /* free the specified entry */ + got = DelEntry(req, tbuf); + Log(); + if( flag ){ + if( got == 0 ) + XPAPuts(NULL, req->sock, "XPA$OK\n", XPALongTimeout()); + else + XPAPuts(NULL, req->sock, "XPA$ERROR entry does not exist\n", + XPALongTimeout()); + } + } + else{ + strcpy(tbuf, "XPA$ERROR 'del' requires 1 arg: ip:port\n"); + XPAPuts(NULL, req->sock, tbuf, XPALongTimeout()); + } + } + else{ + /* connection is closed -- free all entries for req, and delete req */ + DelEntry(req, "@"); + /* if this is the last entry, delete the request struct as well */ + if( req->entry == NULL ){ + FreeReq(req); + } + Log(); + } +} + +/* + *---------------------------------------------------------------------------- + * + * Routine: LookupReq + * + * Purpose: lookup a template in the XPA list + * + * Returns: number of matched lookups + * + *---------------------------------------------------------------------------- + */ +#ifdef ANSI_FUNC +static int +LookupReq (Req xreq, char *lbuf, int flag) +#else +static int LookupReq(xreq, lbuf, flag) + Req xreq; + char *lbuf; + int flag; +#endif +{ + int i; + int nrec; + int got=0; + int domethod=0; + int slen=1024; + int *lens; + char args[4][SZ_LINE]; + char ctmpl[SZ_LINE]; + char ntmpl[SZ_LINE]; + char tbuf[SZ_LINE]; + char type[SZ_LINE]; + char users[SZ_LINE]; + char method[SZ_LINE]; + char *user; + char *usercopy; + char **strings; + char *tstring; + Req req; + Entry entry; + + SplitArg(lbuf, 0); + nrec = sscanf(lbuf, "%s %s %s %s", args[0], args[1], args[2], args[3]); + switch(nrec){ + case 0: + goto error; + case 1: + strcpy(ctmpl, "*"); + strcpy(ntmpl, args[0]); + strcpy(type, "*"); + strcpy(users, "*"); + if( *args[0] == '@' ){ + strcpy(method, args[0]); + domethod = 1; + } + break; + case 2: + strcpy(ctmpl, "*"); + strcpy(ntmpl, args[0]); + strcpy(type, args[1]); + strcpy(users, "*"); + if( *args[0] == '@' ){ + snprintf(method, SZ_LINE, "%s:%s", args[0], args[1]); + domethod = 1; + } + break; + case 3: + strcpy(ctmpl, "*"); + strcpy(ntmpl, args[0]); + strcpy(type, args[1]); + strcpy(users, args[2]); + if( *args[0] == '@' ){ + strcpy(method, args[0]); + domethod = 1; + } + break; + case 4: + strcpy(ctmpl, args[0]); + strcpy(ntmpl, args[1]); + strcpy(type, args[2]); + strcpy(users, args[3]); + if( *args[0] == '@' ){ + snprintf(method, SZ_LINE, "%s:%s", args[0], args[1]); + domethod = 1; + } + break; + case 5: + goto error; + } + strings = (char **)xmalloc(slen * sizeof(char *)); + lens = (int *)xmalloc(slen * sizeof(int)); + lens[0] = 0; + for(req=reqhead; req!=NULL; req=req->next){ + for(entry=req->entry; entry!=NULL; entry=entry->next){ + /* check method or class:name */ + if( domethod ){ + if( strcmp(entry->method, method) ) + continue; + } + else{ + if( !tmatch(entry->xclass, ctmpl) || !tmatch(entry->name, ntmpl) ) + continue; + } + /* check type */ + if( strcmp(type, "*") && !strpbrk(entry->type, type) ) + continue; + /* check user */ + if( !strcmp(users, "*") || !strcmp(users, entry->user) ){ + user = entry->user; + } + else{ + user = NULL; + usercopy = (char *)xstrdup(users); + for(user=(char *)strtok(usercopy, " :;,"); + user!=NULL; + user=(char *)strtok(NULL," :;,")){ + if ( !strcasecmp(user, entry->user) ){ + break; + } + } + if( usercopy ) + xfree(usercopy); + } + if( !user ) + continue; + /* made it through all checks! */ + if( domethod || (*entry->method == '@') ){ + snprintf(tbuf, SZ_LINE, "%s %s %s %s %s %s\n", + entry->xclass, entry->name, + entry->type, XPANSMethod(NULL,1), entry->user, entry->info); + FPRINTF((stderr, "%sLookupReq: method lookup found:\n%s", _sp, tbuf)); + } + else{ + snprintf(tbuf, SZ_LINE, "%s %s %s %s %s %s\n", + entry->xclass, entry->name, + entry->type, entry->method, entry->user, entry->info); + FPRINTF((stderr, "%sLookupReq: class/name lookup got:\n%s", + _sp, tbuf)); + } + if( got >= (slen-2) ){ + slen *= 2; + strings = (char **)xrealloc(strings, slen * sizeof(char *)); + lens = (int *)xrealloc(lens, slen * sizeof(int)); + } + strings[got] = xstrdup(tbuf); + lens[got+1] = lens[got] + strlen(strings[got]); + got++; + } + } + if( flag ){ + strings[got] = xstrdup("XPA$OK\n"); + lens[got+1] = lens[got] + strlen(strings[got]); + got++; + } + /* write one buffer load: we have to avoid multiple writes in a row + because tcp_delay buffers these (i.e., the Nagle algorithm) and kills + the performance */ + if( got > 0 ){ + tstring = (char *)xcalloc(lens[got]+1, sizeof(char)); + for(i=0; i<got; i++){ + if( strings[i] ){ + strcpy(&(tstring[lens[i]]), strings[i]); + } + } + XPAPutBuf(NULL, xreq->sock, tstring, lens[got], XPALongTimeout()); + for(i=0; i<got; i++){ + if( strings[i] ) + xfree(strings[i]); + } + if( tstring ) + xfree(tstring); + } + if( strings ) + xfree(strings); + if( lens ) + xfree(lens); + return(got); + +error: + strcpy(tbuf, + "XPA$ERROR xpans 'lookup' requires: class:name [type] [user]\n"); + XPAPuts(NULL, xreq->sock, tbuf, XPALongTimeout()); + return(0); +} + +/* + *---------------------------------------------------------------------------- + * + * Routine: HelpReq + * + * Purpose: send help message + * + * Returns: none + * + *---------------------------------------------------------------------------- + */ +#ifdef ANSI_FUNC +static void +HelpReq (Req xreq, int flag) +#else +static void HelpReq(xreq, flag) + Req xreq; + int flag; +#endif +{ + /* XPAPuts(NULL, xreq->sock, helpbuf, XPALongTimeout()); */ + XPAPutBuf(NULL, xreq->sock, helpbuf, strlen(helpbuf), XPALongTimeout()); + if( flag ) + XPAPuts(NULL, xreq->sock, "XPA$OK\n", XPALongTimeout()); +} + +/* + *---------------------------------------------------------------------------- + * + * Routine: ListReq + * + * Purpose: list all entries in the XPA list + * + * Returns: number of entries listed + * + *---------------------------------------------------------------------------- + */ +#ifdef ANSI_FUNC +static int +ListReq (Req xreq, int flag) +#else +static int ListReq(xreq, flag) + Req xreq; + int flag; +#endif +{ + int got=0; + char tbuf[SZ_LINE]; + Req req; + Entry entry; + + for(req=reqhead; req!=NULL; req=req->next){ + for(entry=req->entry; entry!=NULL; entry=entry->next){ + snprintf(tbuf, SZ_LINE, "%s %s %s %s %s\n", + entry->xclass, entry->name, + entry->type, entry->method, entry->user); + XPAPuts(NULL, xreq->sock, tbuf, XPALongTimeout()); + got++; + } + } + if( flag ) + XPAPuts(NULL, xreq->sock, "XPA$OK\n", XPALongTimeout()); + return(got); +} + +/* + *---------------------------------------------------------------------------- + * + * Routine: StatusReq + * + * Purpose: send short "alive" message to inquiring server + * + * Returns: NONE + * + *---------------------------------------------------------------------------- + */ +#ifdef ANSI_FUNC +static void +StatusReq (Req xreq) +#else +static void StatusReq(xreq) + Req xreq; +#endif +{ + XPAPuts(NULL, xreq->sock, "XPA$OK\n", XPALongTimeout()); +} + +/* + *---------------------------------------------------------------------------- + * + * Routine: VersionReq + * + * Purpose: send version info to inquiring server + * + * Returns: NONE + * + *---------------------------------------------------------------------------- + */ +#ifdef ANSI_FUNC +static void +VersionReq (Req xreq, char *vstr) +#else +static void VersionReq(xreq, vstr) + Req xreq; + char *vstr; +#endif +{ + int ip=0; + int dowarn=0; + char tbuf[SZ_LINE]; + + /* version check: server version should be <= our version */ + if( word(vstr, tbuf, &ip) ){ + dowarn = (XPAVersionCheck(XPA_VERSION, tbuf)>0); + } + else{ + strcpy(tbuf, "unknown/pre-2.1"); + dowarn = 1; + } + if( dowarn ) + XPAVersionWarn(tbuf, XPA_VERSION); + snprintf(tbuf, SZ_LINE, "XPA$VERSION %s\n", XPA_VERSION); + XPAPuts(NULL, xreq->sock, tbuf, XPALongTimeout()); +} + +#ifdef ANSI_FUNC +void +usage (char *s) +#else +void usage(s) + char *s; +#endif +{ + fprintf(stderr, "\n"); + fprintf(stderr, "usage: xpans [-h] [-e] [-k msec] [-l log] [-p port] [-s slog] [-P n] \n"); + fprintf(stderr, "switches:\n"); + fprintf(stderr, "\t-h\tprint this message\n"); + fprintf(stderr, "\t-e\texit when there are no more XPA connections\n"); + fprintf(stderr, "\t-k msec\tsend keepalive messages every n sec\n"); + fprintf(stderr, "\t-l file\tlog data base entries to specified file\n"); + fprintf(stderr, "\t-p port\tlisten for connections on specified port\n"); + fprintf(stderr, "\t-s file\tlog security info to specified file\n"); + fprintf(stderr, "\t-P 1|2\taccept proxy requests (1) using separate thread (2) \n"); + fprintf(stderr, "\t--version display version and exit\n"); + fprintf(stderr, "\n(version: %s)\n", XPA_VERSION); + exit(1); +} + +/* + *---------------------------------------------------------------------------- + * + * Routine: KeepAliveReq + * + * Purpose: send keep alive to all open connections + * + * Returns: number of entries processed + * + *---------------------------------------------------------------------------- + */ +#ifdef ANSI_FUNC +static int +KeepAliveReq (void) +#else +static int KeepAliveReq() +#endif +{ + int got=0; + Req req; + + /* return if keepalive is turned off */ + if( !keepalive ) + return(0); + /* get current time */ + curt = time(NULL); + /* if keep alive time has passed, send keep alive messages */ + if( (curt - lastt) > ksec ){ + for(req=reqhead; req!=NULL; req=req->next){ + send(req->sock, " ", 1, MSG_OOB); + got++; + } + lastt = curt; + } + return(got); +} + +#ifdef ANSI_FUNC +int +main (int argc, char **argv) +#else +int +main(argc, argv) + int argc; + char **argv; +#endif +{ + char lbuf[SZ_LINE]; + char tbuf[SZ_LINE]; + char cmd[SZ_LINE]; + char method[SZ_LINE]; + int c; + int sock2; + int width; + int got; + int wp; + int cmdport; + int sval; + int nerr=0; + int oum; + int llen; + int reuse_addr=1; + int keep_alive=1; + unsigned int ip; + unsigned int cmdip; + unsigned short port=0; + socklen_t slen=sizeof(struct sockaddr_in); + struct sockaddr_in sock_in; + struct sockaddr_in sock_in2; +#if HAVE_LIBPTHREAD + pthread_t tid; +#endif +#if HAVE_SYS_UN_H + struct sockaddr_un sock_un; + struct sockaddr_un sock_un2; + char lockfile[SZ_LINE]; + int lockfd=-1; + struct flock lock; +#endif + fd_set readfds; + struct timeval tv; + struct timeval *tvp; + Req req, treq; + XPA xpa; + + /* display version and exit, if necessary */ + if( (argc == 2) && !strcmp(argv[1], "--version") ){ + fprintf(stderr, "%s\n", XPA_VERSION); + exit(0); + } + + /* init the XPA environment */ + XPAInitEnv(); + + /* Disable SIGPIPE so we do not die if the client dies. + * Rather, we will get an EOF on reading or writing. + */ + xsignal_sigpipe(); + + /* we want the args in the same order in which they arrived, and + gnu getopt sometimes changes things without this */ + putenv("POSIXLY_CORRECT=true"); + + /* process command line args */ + while ((c = getopt(argc, argv, "ef:hk:l:p:P:s:")) != -1){ + switch(c){ + case 'h': + usage(argv[0]); + exit(0); + case 'e': + exconn = 1; + break; + case 'f': +#if HAVE_SYS_UN_H + /* method is unix with specified file */ + putenv(xstrdup("XPA_METHOD=unix")); + snprintf(tbuf, SZ_LINE, "XPA_NSUNIX=%s", optarg); + putenv(xstrdup(tbuf)); + break; +#else + fprintf(stderr, "XPA$ERROR: UNIX sockets not supported on this host\n"); + exit(1); + break; +#endif + case 'k': + fprintf(stderr, + "XPA$KEEPALIVE: URG TCP data is changed by some Cisco routers into in-band data.\n"); + fprintf(stderr, + "Encountering such a router will break the keep-alive function and may break your\n"); + fprintf(stderr, "XPA server as well. Proceed with caution!\n"); + keepalive = 1; + ksec = atoi(optarg); + if( ksec <= 0 ) + ksec = 1; + break; + case 'l': + logfile = optarg; + break; + case 'p': + /* method is inet with specified port */ + putenv(xstrdup("XPA_METHOD=inet")); + snprintf(tbuf, SZ_LINE, "XPA_NSINET=$host:%d", atoi(optarg)); + putenv(xstrdup(tbuf)); + break; + case 'P': + if( istrue(optarg) ) + doproxy = 1; + else if( isfalse(optarg) ) + doproxy = 0; + else + doproxy = atoi(optarg); + if( doproxy < 0 ) + doproxy = 0; +#if HAVE_LIBPTHREAD==0 + if( doproxy >= 2 ){ + fprintf(stderr, + "XPA$ERROR: xpans not built with thread support on this host\n"); + exit(1); + } +#endif + break; + case 's': + if( !strcasecmp(optarg, "stdout") ){ + securefp = stdout; + } + else if( (securefp=fopen(optarg, "w")) == NULL ){ + perror("securefp"); + exit(1); + } + break; + } + } + + /* get default ip and port */ + strcpy(method, XPANSMethod(NULL, 0)); + mtype = XPAMethod(method); + localhost_ip = gethostip("$localhost"); + + /* start secure logging, if necessary */ + SecureLog("Starting xpans: %s", method); + /* set up communication method */ + switch(mtype){ + case XPA_INET: + XPAParseIpPort(method, &ip, &port); + if( (sock = xsocket(AF_INET, SOCK_STREAM, 0)) < 0 ){ + if( XPAVerbosity() > 1 ) + perror("xpans socket()"); + exit(1); + } + setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, + (char *)&keep_alive, sizeof(keep_alive)); + setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, + (char *)&reuse_addr, sizeof(reuse_addr)); + memset((char *)&sock_in, 0, sizeof(sock_in)); + sock_in.sin_family = AF_INET; + /* localhost only */ + if( ip == localhost_ip ) + sock_in.sin_addr.s_addr = htonl(ip); + /* any address will do */ + else + sock_in.sin_addr.s_addr = htonl(INADDR_ANY); + sock_in.sin_port = htons(port); + /* bind to a port -- an error indicates that another xpans is running */ + if( xbind(sock, (struct sockaddr *)&sock_in, sizeof(sock_in)) < 0 ){ + if( XPAVerbosity() > 1 ) + perror("xpans bind()"); + exit(1); + } + SecureLog("Opening INET socket: %d", sock); + break; +#if HAVE_SYS_UN_H + case XPA_UNIX: + /* with unix sockets, we lock a special file to signal any new xpans + process that it is not needed. This behavior mimicks the bind() + error with inet sockets */ + snprintf(lockfile, SZ_LINE, "%s-lock", method); + if( (lockfd=open(lockfile, O_CREAT|O_RDWR, 0666)) >=0 ){ + lock.l_type = F_WRLCK; /* F_RDLCK, F_WRLCK, F_UNLCK */ + lock.l_start = 0; /* byte offset, relative to l_whence */ + lock.l_whence = SEEK_SET; /* SEEK_SET, SEE_CUR, SEEK_END */ + lock.l_len = 1; /* #bytes (0 means to EOF) */ + /* if we can't get the lock, there is an xpans already running */ + if( xfcntl(lockfd, F_SETLK, &lock) < 0 ){ + close(lockfd); + if( XPAVerbosity() > 1 ) + fprintf(stderr, "XPA$ERROR: xpans already running\n"); + exit(1); + } + } + unlink(method); + if( (sock = xsocket(AF_UNIX, SOCK_STREAM, 0)) < 0 ){ + if( XPAVerbosity() > 1 ) + perror("xpans socket()"); + exit(1); + } + setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, + (char *)&keep_alive, sizeof(keep_alive)); + setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, + (char *)&reuse_addr, sizeof(reuse_addr)); + memset((char *)&sock_un, 0, sizeof(sock_un)); + sock_un.sun_family = AF_UNIX; + strcpy(sock_un.sun_path, method); + /* unset umask so that everyone can read and write */ + oum = umask(0); + /* bind to a port */ + if( xbind(sock, (struct sockaddr *)&sock_un, sizeof(sock_un)) < 0 ){ + if( XPAVerbosity() > 1 ) + perror("xpans bind()"); + exit(1); + } + /* reset umask */ + umask(oum); + SecureLog("opened UNIX socket: %d", sock); + break; +#endif + default: + break; + } + + /* listen for connections */ + if( listen(sock, XPA_MAXLISTEN) < 0 ){ + if( XPAVerbosity() > 1 ) + perror("xpans listen()"); + exit(1); + } + /* make sure we close on exec */ + xfcntl(sock, F_SETFD, FD_CLOEXEC); + + /* add an XPA access point for external processing */ + if( !(xpa=XPANew(XPANS_CLASS, XPANS_NAME, helpbuf, + send_cb, NULL, "fillbuf=false", + receive_cb, NULL, "fillbuf=false")) ){ + if( XPAVerbosity() > 1 ) + fprintf(stderr, "XPA$ERROR: failed to create access point for xpans\n"); + exit(1); + } + SecureLog("XPA access point: %s", xpa->name); + + /* init select parameters */ + width = FD_SETSIZE; + +#if HAVE_LIBPTHREAD + /* start up new thread for XPA main loop, if necessary */ + if( doproxy >= 2 ){ + if( pthread_create(&tid, NULL, doxpaloop, NULL) != 0 ){ + fprintf(stderr, + "XPA$ERROR: can't create new thread for XPA handler in xpans\n"); + exit(1); + } + } +#endif + + /* enter processing loop */ + while( 1 ){ + /* reset flag */ + FD_ZERO(&readfds); + /* add main listening socket */ + FD_SET(sock, &readfds); + /* add request lines */ + for(got=0, req=reqhead; req!=NULL; req=req->next){ + FD_SET(req->sock, &readfds); + got++; + } + /* add XPA selections */ + if( doproxy < 2 ) XPAAddSelect(NULL, &readfds); + /* if we once had entries but do not have them now, we might be done */ + if( exconn && nentry && !got ){ + goto done; + } + if( keepalive ){ + tv.tv_sec = ksec; + tv.tv_usec = 0; + tvp = &tv; + } + else{ + tvp = NULL; + } + /* wait for next request */ + sval = xselect(width, &readfds, NULL, NULL, tvp); + if( sval > 0 ){ +#if HAVE_LIBPTHREAD + /* lock the mutex before processing a reqest */ + if( doproxy >= 2 ) pthread_mutex_lock(&xpans_mutex); +#endif + /* process a new major request */ + if( FD_ISSET(sock, &readfds) ){ + /* new request */ + switch(mtype){ + case XPA_INET: + while( 1 ){ + slen = sizeof(struct sockaddr_in); + if((sock2=xaccept(sock, (struct sockaddr *)&sock_in2, &slen))>=0){ + cmdip = ntohl(sock_in2.sin_addr.s_addr); + cmdport = ntohs(sock_in2.sin_port); + /* make sure we close on exec */ + xfcntl(sock2, F_SETFD, FD_CLOEXEC); + NewReq(sock2, cmdip, cmdport); + SecureLog("accept %d: %x:%d (%s)", + sock2, cmdip, cmdport, getiphost(cmdip)); + break; + } + else{ + if( errno == EINTR ) + continue; + else + break; + } + } + break; +#if HAVE_SYS_UN_H + case XPA_UNIX: + while( 1 ){ + slen = sizeof(struct sockaddr_un); + if( (sock2=xaccept(sock, (struct sockaddr *)&sock_un2, &slen))>=0){ + /* make sure we close on exec */ + xfcntl(sock2, F_SETFD, FD_CLOEXEC); + NewReq(sock2, 0, 0); + SecureLog("accept from local socket"); + break; + } + else{ + if( errno == EINTR ) + continue; + else + break; + } + } + break; +#endif + default: + break; + } + } + /* process an existing request line */ + for(got=0, req=reqhead; req!=NULL; ){ + treq = req->next; + if( FD_ISSET(req->sock, &readfds) ){ + FPRINTF((stderr, "%sxpans existing request: %d\n", _sp, req->sock)); + if( XPAGets(NULL, req->sock, lbuf, SZ_LINE, XPAShortTimeout()) >0 ){ + llen = strlen(lbuf) - 1; + if( (lbuf[llen]) == '\n' ){ + /* ignore a single new-line, its a keep-alive message */ + if( llen == 0){ + FPRINTF((stderr, "%sxpans ignoring keep-alive\n", _sp)); + req = treq; + continue; + } + /* else remove new-line */ + else{ + lbuf[llen] = '\0'; + } + } + FPRINTF((stderr, "%sxpans request: %s\n", _sp, lbuf)); + SecureLog("cmd %d: %s", req->sock, lbuf); + /* process another request from this process */ + wp = 0; + /* get first token: command */ + if( !word(lbuf, cmd, &wp) ){ + strcpy(tbuf, "XPA$ERROR no xpans command specified\n"); + XPAPuts(NULL, req->sock, tbuf, XPALongTimeout()); + } + else{ + /* skip white space */ + while( isspace((int)lbuf[wp]) ) + wp++; + /* lookup the command */ + if( !strcmp(cmd, "status") ){ + StatusReq(req); + } + else if( !strcmp(cmd, "version") ){ + VersionReq(req, &(lbuf[wp])); + } + else if( !strcmp(cmd, "add") ){ + AddReq(req, &(lbuf[wp]), 1); + } + else if( !strcmp(cmd, "addproxy") ){ + AddProxyReq(req, &(lbuf[wp]), 1); + } + else if( !strcmp(cmd, "del") ){ + DelReq(req, &(lbuf[wp]), 1); + } + else if( !strcmp(cmd, "delproxy") ){ + DelProxyReq(req, &(lbuf[wp]), 1); + } + else if( !strcmp(cmd, "help") ){ + HelpReq(req, 1); + } + else if( !strcmp(cmd, "list") ){ + ListReq(req, 1); + } + else if( !strcmp(cmd, "lookup") ){ + LookupReq(req, &(lbuf[wp]), 1); + } + else{ + SecureLog("ignoring unknown command"); + snprintf(tbuf, SZ_LINE, + "XPA$ERROR unknown xpans request: %s\n", lbuf); + XPAPuts(NULL, req->sock, tbuf, XPALongTimeout()); + } + } + } + else{ + /* process dies: delete all entries associated with this sock */ + FPRINTF((stderr, "%sxpans request died: %d\n", _sp, req->sock)); + DelReq(req, NULL, 1); + } + } + req = treq; + } + + /* process xpa requests */ + if( doproxy < 2 ) XPAProcessSelect(&readfds, 0); +#if HAVE_LIBPTHREAD + /* unlock the mutex */ + if( doproxy >= 2 ) pthread_mutex_unlock(&xpans_mutex); +#endif + } + /* keep alive timer went off */ + else if( sval == 0 ){ + ; + } + /* error on select() */ + else{ + /* restart system call if interrupted */ + if( errno != EINTR ){ + /* all others are problematic */ + if( XPAVerbosity() > 1 ) + perror("xpans select()"); + if( ++nerr >= MAX_ERRORS ){ + if( XPAVerbosity() > 1 ) + fprintf(stderr, + "XPA$ERROR: too many select() errors in xpans\n"); + goto done; + } + } + } + /* see if its time to send keepalive probe */ + if( keepalive ) + KeepAliveReq(); + } + +done: + if( sock >=0 ) close(sock); + if( securefp && (securefp != stdout) ) fclose(securefp); +#if HAVE_SYS_UN_H + if( mtype == XPA_UNIX ){ + unlink(method); + if( lockfd >= 0 ){ + close(lockfd); + unlink(lockfile); + } + } +#endif + XPAFree(xpa); + return(0); +} diff --git a/xpa/xpap.h b/xpa/xpap.h new file mode 100644 index 0000000..ccf5fd8 --- /dev/null +++ b/xpa/xpap.h @@ -0,0 +1,236 @@ +/* + * Copyright (c) 1999-2003 Smithsonian Astrophysical Observatory + */ + +/* + * + * xpa.h - include file for the X Public Access mechanism + * + */ +#ifndef __xpap_h +#define __xpap_h + +#if HAVE_CONFIG_H +#include <conf.h> +#endif + +/* avoid use of system -- its not secure */ +#if USE_SPAWN == 0 +#define USE_LAUNCH 1 +#endif + +#if HAVE_UNISTD_H +#include <unistd.h> +#endif +#if HAVE_STRING_H +#include <string.h> +#endif +#if HAVE_STRINGS_H +#include <strings.h> +#endif +#if HAVE_STDLIB_H +#include <stdlib.h> +#endif +#if HAVE_MALLOC_H +#include <malloc.h> +#endif +#if HAVE_GETOPT_H +#include <getopt.h> +#endif +#if HAVE_SETJMP_H +#include <setjmp.h> +#endif +#if HAVE_PWD_H +#include <pwd.h> +#endif +#include <ctype.h> +#include <fcntl.h> +#include <errno.h> +#include <signal.h> +#include <time.h> +#include <sys/types.h> +#include <sys/time.h> +#include <sys/stat.h> +#if HAVE_SYS_SELECT_H +#include <sys/select.h> +#endif +#ifdef __STDC__ +#include <stdarg.h> +#else +#include <varargs.h> +#endif +#include <xport.h> +#include <tcp.h> +#include <word.h> +#include <xalloc.h> +#include <find.h> +#if USE_LAUNCH +#include <xlaunch.h> +#endif +#include <timedconn.h> + +/* B.Schoenhammer@bit-field.de 2009-09-21 */ +#if HAVE_MINGW32 +#ifdef HAVE_ATEXIT +#undef HAVE_ATEXIT +#endif +#endif + +/* make sure socklen_t is available, since some systems don't use it */ +#ifndef HAVE_SOCKLEN_T +#define socklen_t int +#endif + +/* the flag for setting non-blocking I/O varies a bit from Unix to Unix */ +#ifndef O_NONBLOCK +#ifdef O_NDELAY +#define O_NONBLOCK O_NDELAY +#endif +#endif + +#if HAVE_MINGW32==0 +/* we always want to know about errors when a read/write would block */ +#ifndef EWOULDBLOCK +#ifdef EAGAIN +#define EWOULDBLOCK EAGAIN +#endif +#else +#ifndef EAGAIN +#ifdef EWOULDBLOCK +#define EAGAIN EWOULDBLOCK +#endif +#endif +#endif +#endif + +/* not all systems define shutdown() params */ +#ifndef SHUT_RDWR +#define SHUT_RDWR 2 +#endif + +/* cisco routers can clear the URG flag by default, so use in-band */ +#define USE_KA_OOB 0 +/* KA_TYPE: 1->only access points, 2->only proxies 3->both */ +#define DEF_KA_TYPE 2 + +/* for listen() routine */ +#define XPA_MAXLISTEN 1000 + +/* status flags for xpa server */ +#define XPA_STATUS_ACTIVE 1 +#define XPA_STATUS_FREE 2 +#define XPA_STATUS_READBUF 4 +#define XPA_STATUS_ENDBUF 8 + +/* status flags for xpa clients */ +#define XPA_CLIENT_IDLE 0 +#define XPA_CLIENT_ACTIVE 1 +#define XPA_CLIENT_PROCESSING 2 +#define XPA_CLIENT_WAITING 3 + +/* server mode flags for receive, send, info */ +/* crafted so that they are turned on by default */ +#define XPA_MODE_BUF 1 +#define XPA_MODE_FILLBUF 2 +#define XPA_MODE_FREEBUF 4 +#define XPA_MODE_ACL 8 + +/* default modes for receive, send, info */ +#define XPA_DEF_MODE_REC (XPA_MODE_BUF|XPA_MODE_FILLBUF|XPA_MODE_FREEBUF|XPA_MODE_ACL) +#define XPA_DEF_MODE_SEND (XPA_MODE_BUF|XPA_MODE_FREEBUF|XPA_MODE_ACL) +#define XPA_DEF_MODE_INFO (XPA_MODE_ACL) + +/* default client info string */ +#define XPA_DEF_CLIENT_INFO "NONE" + +/* client mode flags */ +#define XPA_CLIENT_BUF 1 +#define XPA_CLIENT_FD 2 +#define XPA_CLIENT_ACK 4 +#define XPA_CLIENT_VERIFY 8 + +/* client select mode flags */ +#define XPA_CLIENT_SEL_XPA 1 +#define XPA_CLIENT_SEL_FORK 2 + +/* error codes -- these must match the strings in xpaMessbuf in xpa.c */ +/* always make 0 an OK return */ +#define XPA_RTN_OK 0 +#define XPA_RTN_NOAUTH 1 +#define XPA_RTN_NOCONN 2 +#define XPA_RTN_NOHOST 3 +#define XPA_RTN_NOBUF 4 +#define XPA_RTN_NOCMD 5 +#define XPA_RTN_NOREC 6 +#define XPA_RTN_NOSEND 7 +#define XPA_RTN_NOINFO 8 +#define XPA_RTN_UNCMD 9 +#define XPA_RTN_NOCMD2 10 +#define XPA_RTN_NOTARG 11 +#define XPA_RTN_NOCMD3 12 +#define XPA_RTN_NODATA 13 +#define XPA_RTN_ILLCMD 14 + +/* connection methods */ +#define XPA_INET 1 +#define XPA_UNIX 2 + +/* select loop types */ +#define XPA_XPA_LOOP 1 +#define XPA_XT_LOOP 2 +#define XPA_TCL_LOOP 3 + +/* name server management */ +#define XPA_NSINET "$host:$port" +#define XPA_NSPORT 14285 +#define XPA_NSUNIX "xpans_unix" +#define XPA_RETRIES 10 +#define XPA_NSDELAY 150 + +/* access control */ +#define XPA_ACLS "gisa" +#define XPA_ACLFILE "$HOME/acls.xpa" +#define XPA_DEFACL "*:* $host +; *:* $localhost +" + +/* port management */ +#define XPA_DEFPORT 28571 +#define XPA_PORTFILE "$HOME/ports.xpa" + +/* misc */ +#define XPA_IOSIZE 4096 +#define XPA_BIOSIZE 204800 + +#ifndef HAVE_CYGWIN +#define XPA_CONNECT_TIMEOUT_MODE 1 +#else +/* cygwin does not support interruptible connect(), so we have + to use non-blocking connect, which is less portable in general */ +#define XPA_CONNECT_TIMEOUT_MODE 2 +#endif + +/* these can be changed by user environment variable */ +#define XPA_MAXHOSTS 100 +#define XPA_SHORT_TIMEOUT 15 +#define XPA_LONG_TIMEOUT 180 +#define XPA_CONNECT_TIMEOUT 10 +#define XPA_TMPDIR "/tmp/.xpa" +#define XPA_VERBOSITY 1 +#define XPA_IOCALLSXPA 0 + +#define LOCALIP(ip) ((ip==gethostip("$localhost"))||(ip==gethostip("$host"))) + +#if HAVE_CYGWIN||HAVE_MINGW32 +#define XPANSNAME "xpans.exe" +#else +#define XPANSNAME "xpans" +#endif + +#define XPANS_CLASS "XPANS" +#define XPANS_NAME "xpans" + +/* for debugging */ +#define _sp XPALevelSpaces() + +#include <xpa.h> + +#endif /* __xpap.h */ diff --git a/xpa/xpaset.c b/xpa/xpaset.c new file mode 100644 index 0000000..4e4d8c2 --- /dev/null +++ b/xpa/xpaset.c @@ -0,0 +1,239 @@ +/* + * Copyright (c) 1999-2003 Smithsonian Astrophysical Observatory + */ + +#include <xpap.h> + +extern char *optarg; +extern int optind; + +#ifdef ANSI_FUNC +void +usage (char *s) +#else +void usage(s) + char *s; +#endif +{ + fprintf(stderr, "\n"); + fprintf(stderr, "usage:\n"); + fprintf(stderr, " <data> | %s [-h] [-i nsinet] [-m method] [-n] [-p] [-s] [-t sval,lval] [-u users] <tmpl|host:port> [paramlist]\n", s); + fprintf(stderr, "\n"); + fprintf(stderr, "switches:\n"); + fprintf(stderr, "\t-h\tprint this message\n"); + fprintf(stderr, "\t-i\toverride XPA_NSINET environment variable\n"); + fprintf(stderr, "\t-m\toverride XPA_METHOD environment variable\n"); + fprintf(stderr, "\t-n\tdon't wait for message after server completes\n"); + fprintf(stderr, "\t-p\tdon't read (or send) buf data from stdin\n"); + fprintf(stderr, "\t-s\tserver mode\n"); + fprintf(stderr, "\t-t \toverride XPA_[SHORT,LONG]_TIMEOUT environment variables\n"); + fprintf(stderr, "\t-u\toverride XPA_NSUSERS environment variable\n"); + fprintf(stderr, "\t-v\tverify message to stdout\n"); + fprintf(stderr, "\t--version display version and exit\n"); + fprintf(stderr, "\n"); + fprintf(stderr, "Data will be sent to access points matching the template or host:port.\n"); + fprintf(stderr, "Templates are of the form [class:]name. Wildcards *,?,[] are accepted.\n"); + fprintf(stderr, "A set of qualifying parameters can be appended.\n"); + fprintf(stderr, "\n"); + fprintf(stderr, "examples:\n"); + fprintf(stderr, "\tcsh> xpaset ds9 fits foo.fits < foo.fits\n"); + fprintf(stderr, "\tcsh> echo \"stop\" | xpaset bynars:28571\n"); + fprintf(stderr, "\n(version: %s)\n", XPA_VERSION); + exit(1); +} + +#ifdef ANSI_FUNC +int +main (int argc, char **argv) +#else +int +main(argc, argv) + int argc; + char **argv; +#endif +{ + int i; + int c; + int got; + int lp; + int errcode=0; + int server=0; + int hmax=XPA_MAXHOSTS; + char *paramlist=NULL; + char *xtemplate=NULL; + char lbuf[SZ_LINE]; + char tbuf[SZ_LINE]; + char mode[SZ_LINE]; + char cmd[SZ_LINE]; + char *s; + char **errs=NULL; + char **names=NULL; + int fd; + XPA xpa=NULL; + + /* display version and exit, if necessary */ + if( (argc == 2) && !strcmp(argv[1], "--version") ){ + fprintf(stderr, "%s\n", XPA_VERSION); + exit(0); + } + + /* make sure we have enough arguments */ + if( argc < 2 ) + usage(argv[0]); + + /* start with no mode flag */ + *mode = '\0'; + + /* read from stdin */ + fd = fileno(stdin); + + /* we want the args in the same order in which they arrived, and + gnu getopt sometimes changes things without this */ + putenv("POSIXLY_CORRECT=true"); + + /* process switch arguments */ + while ((c = getopt(argc, argv, "hi:m:npst:u:vwW")) != -1){ + switch(c){ + case 'h': + usage(argv[0]); + case 'i': + snprintf(cmd, SZ_LINE, "XPA_NSINET=%s", optarg); + putenv(xstrdup(cmd)); + break; + case 'm': + snprintf(cmd, SZ_LINE, "XPA_METHOD=%s", optarg); + putenv(xstrdup(cmd)); + break; + case 'n': + if( *mode != '\0' ) + strcat(mode, ","); + strcat(mode, "ack=false"); + break; + case 'p': + fd = -1; + break; + case 's': + server = 1; + if( xpa == NULL ) + xpa = XPAOpen(NULL); + break; + case 't': + { + int xip=0; + char xbuf[SZ_LINE]; + newdtable(",;"); + if( word(optarg, xbuf, &xip) && *xbuf && (*xbuf != '*') ){ + snprintf(cmd, SZ_LINE, "XPA_SHORT_TIMEOUT=%s", xbuf); + putenv(xstrdup(cmd)); + } + if( word(optarg, xbuf, &xip) && *xbuf && (*xbuf != '*') ){ + snprintf(cmd, SZ_LINE, "XPA_LONG_TIMEOUT=%s", xbuf); + putenv(xstrdup(cmd)); + } + freedtable(); + } + break; + case 'u': + snprintf(cmd, SZ_LINE, "XPA_NSUSERS=%s", optarg); + putenv(xstrdup(cmd)); + break; + case 'v': + if( *mode != '\0' ) + strcat(mode, ","); + strcat(mode, "verify=true"); + break; + /* for backward compatibility with 1.0 */ + case 'w': + case 'W': + break; + } + } + + /* no explicit host:port specified, so we should have a name */ + if( optind >= argc ){ + /* in server mode, we can skip the host on the command line */ + if( !server ) + usage(argv[0]); + } + else{ + xtemplate = xstrdup(argv[optind]); + optind++; + } + + /* make the paramlist */ + paramlist = XPAArgvParamlist(argc, argv, optind); + + /* init variables for names and ports */ + if( (s=(char *)getenv("XPA_MAXHOSTS")) != NULL ) + hmax = atoi(s); + names = (char **)xcalloc(hmax, sizeof(char *)); + errs = (char **)xcalloc(hmax, sizeof(char *)); + +again: + /* if we are in server mode, we might have to read a line from stdin + to grab the template and paramlist */ + if( server && (xtemplate==NULL) ){ + /* read description of template and paramlist */ + if( fgets(lbuf, SZ_LINE, stdin) == NULL ) + exit(errcode); + if( (*lbuf == '#') || (*lbuf == '\n') ) + goto again; + lp = 0; + if( word(lbuf, tbuf, &lp) && !strcmp(tbuf, "xpaset") && + word(lbuf, tbuf, &lp) ){ + xtemplate = xstrdup(tbuf); + paramlist = xstrdup(&(lbuf[lp])); + nowhite(paramlist, paramlist); + } + else{ + fprintf(stderr, "XPA$ERROR invalid command: %s", lbuf); + exit(++errcode); + } + } + + /* process xpa requests */ + got = XPASetFd(xpa, xtemplate, paramlist, mode, fd, names, errs, hmax); + + /* process errors */ + if( got == 0 ){ + fprintf(stderr, "XPA$ERROR no 'xpaset' access points match template: %s\n", + xtemplate); + errcode++; + } + else{ + /* display errors and free up strings */ + for(i=0; i<got; i++){ + if( errs[i] != NULL ){ + fprintf(stderr, "%s", errs[i]); + xfree(errs[i]); + errcode++; + } + if( names[i] != NULL ) + xfree(names[i]); + } + } + + /* free the paramlist */ + if( paramlist!= NULL ){ + xfree(paramlist); + paramlist = NULL; + } + /* and the template */ + if( xtemplate != NULL ){ + xfree(xtemplate); + xtemplate = NULL; + } + + /* if we are in server mode, go back for more */ + if( server ) + goto again; + /* else exit */ + else{ + /* clean up */ + if( errs ) xfree(errs); + if( names ) xfree(names); + XPACleanup(); + exit(errcode); + } + return(0); +} diff --git a/xpa/xpatests b/xpa/xpatests new file mode 100755 index 0000000..8362ea8 --- /dev/null +++ b/xpa/xpatests @@ -0,0 +1,67 @@ +#!/bin/sh + +if [ x"`xpaaccess i_xpa`" != xyes ]; then + echo "please start stest before running xpatests ..." + exit 1 +fi + +LOOPS=100 +TARGET="xpa*" +ITARGET="i_xpa" + +while [ x"$1" != x ]; do + case $1 in + -a) FLAGS="$FLAGS -m ack=false" + shift + continue;; + + -d) shift + FLAGS="$FLAGS -d $1" + shift + continue;; + + -f) shift + FLAGS="$FLAGS $1" + shift + continue;; + + -l) shift + LOOPS=$1 + shift + continue;; + + -q) FLAGS="$FLAGS -q" + shift + continue;; + + -s) shift + SUFFIX=.$1 + shift + continue;; + + -t) shift + TARGET=$1 + shift + continue;; + esac +done +FLAGS="-l $LOOPS $FLAGS" + +echo " " +echo "starting xpaget test with flags: $FLAGS" +./ctest${SUFFIX} ${FLAGS} -g "$TARGET" + +echo " " +echo "starting xpaset test with flags: $FLAGS" +./ctest${SUFFIX} ${FLAGS} -s "$TARGET" + +echo " " +echo "starting xpaget and xpaset test with flags: $FLAGS" +./ctest${SUFFIX} ${FLAGS} -b "$TARGET" + +echo " " +echo "starting xpainfo test with flags: $FLAGS" +./ctest${SUFFIX} ${FLAGS} -i "$ITARGET" + +echo " " +echo 'All done!' diff --git a/xpa/xport.h b/xpa/xport.h new file mode 100644 index 0000000..731abe5 --- /dev/null +++ b/xpa/xport.h @@ -0,0 +1,142 @@ +/* + * Copyright (c) 1999-2004 Smithsonian Astrophysical Observatory + */ + +/* + * + * xport.h - include file for platform-dependent system calls + * + */ +#ifndef __xport_h +#define __xport_h + +#if HAVE_CONFIG_H +#include <conf.h> +#endif + +#if HAVE_MINGW32 + +#define FD_SETSIZE 8192 +#include <winsock2.h> +#include <process.h> +#include <io.h> + +#ifdef EINPROGRESS +#undef EINPROGRESS +#endif +#define EINPROGRESS WSAEINPROGRESS +#ifdef EINTR +#undef EINTR +#endif +#define EINTR WSAEINTR +#ifdef ETIMEDOUT +#undef ETIMEDOUT +#endif +#define ETIMEDOUT WSAETIMEDOUT +#ifdef ECONNREFUSED +#undef ECONNREFUSED +#endif +#define ECONNREFUSED WSAECONNREFUSED +#ifdef EWOULDBLOCK +#undef EWOULDBLOCK +#endif +#define EWOULDBLOCK WSAEWOULDBLOCK +#ifdef EAGAIN +#undef EAGAIN +#endif +#define EAGAIN WSAEWOULDBLOCK + +#else + +#include <sys/types.h> +#include <sys/wait.h> +#include <sys/socket.h> +#include <netinet/in.h> /* struct in_addr, struct sockaddr_in */ +#include <netdb.h> /* gethostbyname() */ +#include <arpa/inet.h> /* inet_addr() */ +#if HAVE_SYS_UN_H +#include <sys/un.h> +#endif +#if HAVE_CYGWIN +#include <process.h> +#endif + +#endif + +/* common definitions (i.e. not yet requiring platform differentiation) */ + +#define xsocket(a,b,c) socket(a,b,c) +#define xbind(a,b,c) bind(a,b,c) +#define xaccept(a,b,c) accept(a,b,c) +#define xselect(a,b,c,d,e) select(a,b,c,d,e) + +/* UNIX */ +#if HAVE_MINGW32==0 + +#define xclose(a) close(a) + +#define xfcntl(a,b,c) fcntl(a,b,c) + +#define xfcntl_nonblock(a,b) \ + b = fcntl(a, F_GETFL, 0); \ + fcntl(a, F_SETFL, b|O_NONBLOCK) + +#define xfcntl_restore(a,b) fcntl(a, F_SETFL, b) + +#define xsocketstartup() + +#define xsocketcleanup() + +#define xfd_set_stdin(a,b) FD_SET(a,b) +#define xfd_isset_stdin(a,b) (a >= 0) && FD_ISSET(a,b) +#define xfd_clr_stdin(a,b) FD_CLR(a,b) + +#define xsignal_sigpipe() signal(SIGPIPE, SIG_IGN) + +#define xerrno errno + +#define xmkdir(a,b) mkdir(a,b) +#define xchmod(a,b) chmod(a,b) + +/* WINDOWS */ +#else + +#define xclose(a) closesocket(a) + +#define xfcntl(a,b,c) + +#define xfcntl_nonblock(a,b) \ + { \ + int iomode=1; \ + ioctlsocket(a, FIONBIO, (u_long FAR *) &iomode); \ + } + +#define xfcntl_restore(a,b) \ + { \ + int iomode=0; \ + ioctlsocket(a, FIONBIO, (u_long FAR *) &iomode); \ + } + +#define xsocketstartup() \ + { \ + WSADATA wsaData; \ + WSAStartup(MAKEWORD(2,0), &wsaData); \ + } + +#define xsocketcleanup() WSACleanup() + +#define xfd_set_stdin(a,b) setmode(a, O_BINARY) + +#define xfd_isset_stdin(a,b) (a >= 0) +#define xfd_clr_stdin(a,b) + +#define xsignal_sigpipe() + +#define xerrno WSAGetLastError() + +#define xmkdir(a,b) mkdir(a) +#define xchmod(a,b) chmod(a,b) + +#endif + +#endif /* __xport.h */ diff --git a/xpa/xtloop.c b/xpa/xtloop.c new file mode 100644 index 0000000..f712a9e --- /dev/null +++ b/xpa/xtloop.c @@ -0,0 +1,261 @@ +/* + * Copyright (c) 1999-2003 Smithsonian Astrophysical Observatory + */ + +#include <xpap.h> + +#if HAVE_XT + +#include <X11/Intrinsic.h> + +/* + *---------------------------------------------------------------------------- + * + * + * Private Routines and Data + * + * + *---------------------------------------------------------------------------- + */ + +/* + * + * record struct for maintining Xt info in Xt select loop + * + */ +typedef struct xpaxtrec{ + int fd; + void *client_data; + XtInputId id; +} *XPAXt, XPAXtRec; + +/* its such a pain to maintain this, so make it global! */ +static XtAppContext xpa_app=NULL; + +/* + *---------------------------------------------------------------------------- + * + * Routine: XPAXtHandler + * + * Purpose: handle one request for an xpaset or xpaget + * + * Return: none + * + *---------------------------------------------------------------------------- + */ +#ifdef ANSI_FUNC +static void +XPAXtHandler (XtPointer client_data, int *fd, XtInputId *id) +#else +static void XPAXtHandler(client_data, fd, id) + XtPointer client_data; + int *fd; + XtInputId *id; +#endif +{ + XPAXt xptr = (XPAXt)client_data; + if( (xptr == NULL) || (xptr->client_data == NULL) ) + return; + XPAHandler((XPA)xptr->client_data, xptr->fd); +} + +/* + *---------------------------------------------------------------------------- + * + * Routine: XPAXtEnableOneInput + * + * Purpose: Enable 1 XPA entry from the Xt event loop + * + * Results: none + * + *---------------------------------------------------------------------------- + */ +#ifdef ANSI_FUNC +static void +XPAXtEnableOneInput (void *client_data) +#else +static void XPAXtEnableOneInput(client_data) + void *client_data; +#endif +{ + XPAXt xptr = (XPAXt)client_data; + if( xptr == NULL ) + return; + if( xptr->id != (XtInputId)NULL ) + return; + if( xpa_app == NULL ){ + xptr->id = XtAddInput(xptr->fd, + (XtPointer)XtInputReadMask, + (XtInputCallbackProc)XPAXtHandler, + (XtPointer)xptr); + } + else{ + xptr->id = XtAppAddInput(xpa_app, xptr->fd, + (XtPointer)XtInputReadMask, + (XtInputCallbackProc)XPAXtHandler, + (XtPointer)xptr); + } +} + +/* + *---------------------------------------------------------------------------- + * + * Routine: XPAXtDisableOneInput + * + * Purpose: Disable 1 XPA entry from the Xt event loop + * + * Results: none + * + *---------------------------------------------------------------------------- + */ +#ifdef ANSI_FUNC +static void +XPAXtDisableOneInput (void *client_data) +#else +static void XPAXtDisableOneInput(client_data) + void *client_data; +#endif +{ + XPAXt xptr = (XPAXt)client_data; + if( xptr == NULL ) + return; + if( xptr->id == (XtInputId)NULL ) + return; + XtRemoveInput(xptr->id); + xptr->id = (XtInputId)NULL; +} + +/* + *---------------------------------------------------------------------------- + * + * Routine: XPAXtAddOneInput + * + * Purpose: Add 1 XPA entry to the Xt event loop + * + * Results: none + * + *---------------------------------------------------------------------------- + */ +#ifdef ANSI_FUNC +static void * +XPAXtAddOneInput (void *client_data, int fd) +#else +static void *XPAXtAddOneInput(client_data, fd) + void *client_data; + int fd; +#endif +{ + XPAXt xptr; + if( fd < 0 ) + return(NULL); + xptr = (XPAXt)xcalloc(1, sizeof(XPAXtRec)); + xptr->fd = fd; + xptr->client_data = client_data; + XPAXtEnableOneInput(xptr); + return(xptr); +} + +/* + *---------------------------------------------------------------------------- + * + * Routine: XPAXtDelOneInput + * + * Purpose: Delete 1 XPA entry from the Xt event loop (called by XPAFree) + * + * Results: none + * + *---------------------------------------------------------------------------- + */ +#ifdef ANSI_FUNC +static void +XPAXtDelOneInput (void *client_data) +#else +static void XPAXtDelOneInput(client_data) + void *client_data; +#endif +{ + XPAXt xptr = (XPAXt)client_data; + if( xptr == NULL) + return; + XPAXtDisableOneInput(xptr); + xfree(xptr); +} + +/* + *---------------------------------------------------------------------------- + * + * + * Public Routines and Data + * + * + *---------------------------------------------------------------------------- + */ + +/* + *---------------------------------------------------------------------------- + * + * Routine: XPAXtAddInput + * + * Purpose: Add XPA entries to the Xt event loop + * + * Results: number of xpa entried added + * + *---------------------------------------------------------------------------- + */ +#ifdef ANSI_FUNC +int +XPAXtAddInput (void *app, XPA xpa) +#else +int XPAXtAddInput(app, xpa) + void *app; + XPA xpa; +#endif +{ + XPA cur; + int got=0; + + /* save the app context */ + if( xpa_app == NULL ){ + xpa_app = (XtAppContext)app; + } + + /* if a specific xpa was specified, just add it */ + if( xpa != NULL ){ + /* remove old one */ + if( xpa->seldel && xpa->selptr ){ + (xpa->seldel)(xpa->selptr); + } + /* add new one */ + xpa->seldel = XPAXtDelOneInput; + xpa->seladd = XPAXtAddOneInput; + xpa->selon = XPAXtEnableOneInput; + xpa->seloff = XPAXtDisableOneInput; + xpa->selptr = XPAXtAddOneInput((void *)xpa, xpa->fd); + got = 1; + } + /* otherwise set up all xpa's */ + else{ + for(cur=(XPA)XPAListHead(); cur!=NULL; cur=cur->next){ + /* remove old one */ + if( cur->seldel && cur->selptr ){ + (cur->seldel)(cur->selptr); + } + /* add new one */ + cur->seldel = XPAXtDelOneInput; + cur->seladd = XPAXtAddOneInput; + cur->selon = XPAXtEnableOneInput; + cur->seloff = XPAXtDisableOneInput; + cur->selptr = XPAXtAddOneInput((void *)cur, cur->fd); + got++; + } + } + return(got); +} + +int xpa_xt = 1; + +#else + +int xpa_xt = 0; + +#endif |