Import xpa_2.1.15.orig.tar.gz
authorOle Streicher <debian@liska.ath.cx>
Thu, 25 Jul 2013 08:21:05 +0000 (09:21 +0100)
committerOle Streicher <debian@liska.ath.cx>
Thu, 25 Jul 2013 08:21:05 +0000 (09:21 +0100)
[dgit import orig xpa_2.1.15.orig.tar.gz]

133 files changed:
COPYING [new file with mode: 0644]
INSTALL [new file with mode: 0644]
Makefile.in [new file with mode: 0644]
README [new file with mode: 0644]
acl.c [new file with mode: 0644]
aclocal.m4 [new file with mode: 0644]
client.c [new file with mode: 0644]
clipboard.c [new file with mode: 0644]
command.c [new file with mode: 0644]
conf.h [new file with mode: 0644]
conf.h.in [new file with mode: 0644]
config.guess [new file with mode: 0755]
config.sub [new file with mode: 0755]
configure [new file with mode: 0755]
configure.ac [new file with mode: 0644]
ctest.c [new file with mode: 0644]
dns.c [new file with mode: 0644]
doc/Makefile [new file with mode: 0644]
doc/acl.html [new file with mode: 0644]
doc/changelog.html [new file with mode: 0644]
doc/changes.html [new file with mode: 0644]
doc/client.html [new file with mode: 0644]
doc/convert.html [new file with mode: 0644]
doc/env.html [new file with mode: 0644]
doc/examples.html [new file with mode: 0644]
doc/help.html [new file with mode: 0644]
doc/inet.html [new file with mode: 0644]
doc/info.html [new file with mode: 0644]
doc/intro.html [new file with mode: 0644]
doc/method.html [new file with mode: 0644]
doc/name.html [new file with mode: 0644]
doc/oom.html [new file with mode: 0644]
doc/programs.html [new file with mode: 0644]
doc/server.html [new file with mode: 0644]
doc/sman/xpa4.index [new file with mode: 0644]
doc/sman/xpa4.index.prop [new file with mode: 0644]
doc/sman/xpa4.index.version [new file with mode: 0644]
doc/sman/xpa8.index [new file with mode: 0644]
doc/sman/xpa8.index.prop [new file with mode: 0644]
doc/sman/xpa8.index.version [new file with mode: 0644]
doc/tcl.html [new file with mode: 0644]
doc/template.html [new file with mode: 0644]
doc/users.html [new file with mode: 0644]
doc/xpa.pdf [new file with mode: 0644]
doc/xpa.ps [new file with mode: 0644]
doc/xpamb.html [new file with mode: 0644]
doc/xpans.html [new file with mode: 0644]
doc/xt.html [new file with mode: 0644]
find.c [new file with mode: 0644]
find.h [new file with mode: 0644]
gtkloop.c [new file with mode: 0644]
install-sh [new file with mode: 0755]
man/man1/xpaaccess.1 [new file with mode: 0644]
man/man1/xpachanges.1 [new file with mode: 0644]
man/man1/xpaget.1 [new file with mode: 0644]
man/man1/xpainfo.1 [new file with mode: 0644]
man/man1/xpamb.1 [new file with mode: 0644]
man/man1/xpans.1 [new file with mode: 0644]
man/man1/xpaset.1 [new file with mode: 0644]
man/man3/xpaaccess.3 [new file with mode: 0644]
man/man3/xpaatexit.3 [new file with mode: 0644]
man/man3/xpacleanup.3 [new file with mode: 0644]
man/man3/xpaclient.3 [new file with mode: 0644]
man/man3/xpaclose.3 [new file with mode: 0644]
man/man3/xpacmdadd.3 [new file with mode: 0644]
man/man3/xpacmddel.3 [new file with mode: 0644]
man/man3/xpacmdnew.3 [new file with mode: 0644]
man/man3/xpafree.3 [new file with mode: 0644]
man/man3/xpaget.3 [new file with mode: 0644]
man/man3/xpagetfd.3 [new file with mode: 0644]
man/man3/xpainfo.3 [new file with mode: 0644]
man/man3/xpainfonew.3 [new file with mode: 0644]
man/man3/xpamacros.3 [new file with mode: 0644]
man/man3/xpamainloop.3 [new file with mode: 0644]
man/man3/xpanew.3 [new file with mode: 0644]
man/man3/xpanslookup.3 [new file with mode: 0644]
man/man3/xpaopen.3 [new file with mode: 0644]
man/man3/xpapoll.3 [new file with mode: 0644]
man/man3/xparace.3 [new file with mode: 0644]
man/man3/xpaserver.3 [new file with mode: 0644]
man/man3/xpaset.3 [new file with mode: 0644]
man/man3/xpasetfd.3 [new file with mode: 0644]
man/mann/xpa.n [new file with mode: 0644]
man/mann/xpaacl.n [new file with mode: 0644]
man/mann/xpacode.n [new file with mode: 0644]
man/mann/xpacommon.n [new file with mode: 0644]
man/mann/xpaconvert.n [new file with mode: 0644]
man/mann/xpaenv.n [new file with mode: 0644]
man/mann/xpainet.n [new file with mode: 0644]
man/mann/xpaintro.n [new file with mode: 0644]
man/mann/xpamethod.n [new file with mode: 0644]
man/mann/xpaname.n [new file with mode: 0644]
man/mann/xpaoom.n [new file with mode: 0644]
man/mann/xpatcl.n [new file with mode: 0644]
man/mann/xpatemplate.n [new file with mode: 0644]
man/mann/xpausers.n [new file with mode: 0644]
man/mann/xpaxt.n [new file with mode: 0644]
mklib [new file with mode: 0755]
oxpa.h [new file with mode: 0644]
pkgIndex.tcl [new file with mode: 0644]
port.c [new file with mode: 0644]
prsetup.h [new file with mode: 0644]
remote.c [new file with mode: 0644]
rtest.c [new file with mode: 0644]
saoconfig [new file with mode: 0755]
stest.c [new file with mode: 0644]
tcl.c [new file with mode: 0644]
tcl.m4 [new file with mode: 0644]
tclloop.c [new file with mode: 0644]
tcp.c [new file with mode: 0644]
tcp.h [new file with mode: 0644]
test.tcl [new file with mode: 0644]
timedconn.c [new file with mode: 0644]
timedconn.h [new file with mode: 0644]
tsj.c [new file with mode: 0644]
word.c [new file with mode: 0644]
word.h [new file with mode: 0644]
xalloc.c [new file with mode: 0644]
xalloc.h [new file with mode: 0644]
xlaunch.c [new file with mode: 0644]
xlaunch.h [new file with mode: 0644]
xpa.c [new file with mode: 0644]
xpa.h [new file with mode: 0644]
xpaaccess.c [new file with mode: 0644]
xpaget.c [new file with mode: 0644]
xpainfo.c [new file with mode: 0644]
xpaio.c [new file with mode: 0644]
xpamb.c [new file with mode: 0644]
xpans.c [new file with mode: 0644]
xpap.h [new file with mode: 0644]
xpaset.c [new file with mode: 0644]
xport.h [new file with mode: 0644]
xtloop.c [new file with mode: 0644]

diff --git a/COPYING b/COPYING
new file mode 100644 (file)
index 0000000..b1e3f5a
--- /dev/null
+++ b/COPYING
@@ -0,0 +1,504 @@
+                 GNU LESSER GENERAL PUBLIC LICENSE
+                      Version 2.1, February 1999
+
+ Copyright (C) 1991, 1999 Free Software Foundation, Inc.
+     59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+[This is the first released version of the Lesser GPL.  It also counts
+ as the successor of the GNU Library Public License, version 2, hence
+ the version number 2.1.]
+
+                           Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+Licenses are intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+
+  This license, the Lesser General Public License, applies to some
+specially designated software packages--typically libraries--of the
+Free Software Foundation and other authors who decide to use it.  You
+can use it too, but we suggest you first think carefully about whether
+this license or the ordinary General Public License is the better
+strategy to use in any particular case, based on the explanations below.
+
+  When we speak of free software, we are referring to freedom of use,
+not price.  Our General Public Licenses are designed to make sure that
+you have the freedom to distribute copies of free software (and charge
+for this service if you wish); that you receive source code or can get
+it if you want it; that you can change the software and use pieces of
+it in new free programs; and that you are informed that you can do
+these things.
+
+  To protect your rights, we need to make restrictions that forbid
+distributors to deny you these rights or to ask you to surrender these
+rights.  These restrictions translate to certain responsibilities for
+you if you distribute copies of the library or if you modify it.
+
+  For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you.  You must make sure that they, too, receive or can get the source
+code.  If you link other code with the library, you must provide
+complete object files to the recipients, so that they can relink them
+with the library after making changes to the library and recompiling
+it.  And you must show them these terms so they know their rights.
+
+  We protect your rights with a two-step method: (1) we copyright the
+library, and (2) we offer you this license, which gives you legal
+permission to copy, distribute and/or modify the library.
+
+  To protect each distributor, we want to make it very clear that
+there is no warranty for the free library.  Also, if the library is
+modified by someone else and passed on, the recipients should know
+that what they have is not the original version, so that the original
+author's reputation will not be affected by problems that might be
+introduced by others.
+\f
+  Finally, software patents pose a constant threat to the existence of
+any free program.  We wish to make sure that a company cannot
+effectively restrict the users of a free program by obtaining a
+restrictive license from a patent holder.  Therefore, we insist that
+any patent license obtained for a version of the library must be
+consistent with the full freedom of use specified in this license.
+
+  Most GNU software, including some libraries, is covered by the
+ordinary GNU General Public License.  This license, the GNU Lesser
+General Public License, applies to certain designated libraries, and
+is quite different from the ordinary General Public License.  We use
+this license for certain libraries in order to permit linking those
+libraries into non-free programs.
+
+  When a program is linked with a library, whether statically or using
+a shared library, the combination of the two is legally speaking a
+combined work, a derivative of the original library.  The ordinary
+General Public License therefore permits such linking only if the
+entire combination fits its criteria of freedom.  The Lesser General
+Public License permits more lax criteria for linking other code with
+the library.
+
+  We call this license the "Lesser" General Public License because it
+does Less to protect the user's freedom than the ordinary General
+Public License.  It also provides other free software developers Less
+of an advantage over competing non-free programs.  These disadvantages
+are the reason we use the ordinary General Public License for many
+libraries.  However, the Lesser license provides advantages in certain
+special circumstances.
+
+  For example, on rare occasions, there may be a special need to
+encourage the widest possible use of a certain library, so that it becomes
+a de-facto standard.  To achieve this, non-free programs must be
+allowed to use the library.  A more frequent case is that a free
+library does the same job as widely used non-free libraries.  In this
+case, there is little to gain by limiting the free library to free
+software only, so we use the Lesser General Public License.
+
+  In other cases, permission to use a particular library in non-free
+programs enables a greater number of people to use a large body of
+free software.  For example, permission to use the GNU C Library in
+non-free programs enables many more people to use the whole GNU
+operating system, as well as its variant, the GNU/Linux operating
+system.
+
+  Although the Lesser General Public License is Less protective of the
+users' freedom, it does ensure that the user of a program that is
+linked with the Library has the freedom and the wherewithal to run
+that program using a modified version of the Library.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.  Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library".  The
+former contains code derived from the library, whereas the latter must
+be combined with the library in order to run.
+\f
+                 GNU LESSER GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License Agreement applies to any software library or other
+program which contains a notice placed by the copyright holder or
+other authorized party saying it may be distributed under the terms of
+this Lesser General Public License (also called "this License").
+Each licensee is addressed as "you".
+
+  A "library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+  The "Library", below, refers to any such software library or work
+which has been distributed under these terms.  A "work based on the
+Library" means either the Library or any derivative work under
+copyright law: that is to say, a work containing the Library or a
+portion of it, either verbatim or with modifications and/or translated
+straightforwardly into another language.  (Hereinafter, translation is
+included without limitation in the term "modification".)
+
+  "Source code" for a work means the preferred form of the work for
+making modifications to it.  For a library, complete source code means
+all the source code for all modules it contains, plus any associated
+interface definition files, plus the scripts used to control compilation
+and installation of the library.
+
+  Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it).  Whether that is true depends on what the Library does
+and what the program that uses the Library does.
+  
+  1. You may copy and distribute verbatim copies of the Library's
+complete source code as you receive it, in any medium, provided that
+you conspicuously and appropriately publish on each copy an
+appropriate copyright notice and disclaimer of warranty; keep intact
+all the notices that refer to this License and to the absence of any
+warranty; and distribute a copy of this License along with the
+Library.
+
+  You may charge a fee for the physical act of transferring a copy,
+and you may at your option offer warranty protection in exchange for a
+fee.
+\f
+  2. You may modify your copy or copies of the Library or any portion
+of it, thus forming a work based on the Library, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) The modified work must itself be a software library.
+
+    b) You must cause the files modified to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    c) You must cause the whole of the work to be licensed at no
+    charge to all third parties under the terms of this License.
+
+    d) If a facility in the modified Library refers to a function or a
+    table of data to be supplied by an application program that uses
+    the facility, other than as an argument passed when the facility
+    is invoked, then you must make a good faith effort to ensure that,
+    in the event an application does not supply such function or
+    table, the facility still operates, and performs whatever part of
+    its purpose remains meaningful.
+
+    (For example, a function in a library to compute square roots has
+    a purpose that is entirely well-defined independent of the
+    application.  Therefore, Subsection 2d requires that any
+    application-supplied function or table used by this function must
+    be optional: if the application does not supply it, the square
+    root function must still compute square roots.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Library,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Library, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote
+it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Library.
+
+In addition, mere aggregation of another work not based on the Library
+with the Library (or with a work based on the Library) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library.  To do
+this, you must alter all the notices that refer to this License, so
+that they refer to the ordinary GNU General Public License, version 2,
+instead of to this License.  (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.)  Do not make any other change in
+these notices.
+\f
+  Once this change is made in a given copy, it is irreversible for
+that copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+  This option is useful when you wish to copy part of the code of
+the Library into a program that is not a library.
+
+  4. You may copy and distribute the Library (or a portion or
+derivative of it, under Section 2) in object code or executable form
+under the terms of Sections 1 and 2 above provided that you accompany
+it with the complete corresponding machine-readable source code, which
+must be distributed under the terms of Sections 1 and 2 above on a
+medium customarily used for software interchange.
+
+  If distribution of object code is made by offering access to copy
+from a designated place, then offering equivalent access to copy the
+source code from the same place satisfies the requirement to
+distribute the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  5. A program that contains no derivative of any portion of the
+Library, but is designed to work with the Library by being compiled or
+linked with it, is called a "work that uses the Library".  Such a
+work, in isolation, is not a derivative work of the Library, and
+therefore falls outside the scope of this License.
+
+  However, linking a "work that uses the Library" with the Library
+creates an executable that is a derivative of the Library (because it
+contains portions of the Library), rather than a "work that uses the
+library".  The executable is therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+  When a "work that uses the Library" uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be
+linked without the Library, or if the work is itself a library.  The
+threshold for this to be true is not precisely defined by law.
+
+  If such an object file uses only numerical parameters, data
+structure layouts and accessors, and small macros and small inline
+functions (ten lines or less in length), then the use of the object
+file is unrestricted, regardless of whether it is legally a derivative
+work.  (Executables containing this object code plus portions of the
+Library will still fall under Section 6.)
+
+  Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6,
+whether or not they are linked directly with the Library itself.
+\f
+  6. As an exception to the Sections above, you may also combine or
+link a "work that uses the Library" with the Library to produce a
+work containing portions of the Library, and distribute that work
+under terms of your choice, provided that the terms permit
+modification of the work for the customer's own use and reverse
+engineering for debugging such modifications.
+
+  You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License.  You must supply a copy of this License.  If the work
+during execution displays copyright notices, you must include the
+copyright notice for the Library among them, as well as a reference
+directing the user to the copy of this License.  Also, you must do one
+of these things:
+
+    a) Accompany the work with the complete corresponding
+    machine-readable source code for the Library including whatever
+    changes were used in the work (which must be distributed under
+    Sections 1 and 2 above); and, if the work is an executable linked
+    with the Library, with the complete machine-readable "work that
+    uses the Library", as object code and/or source code, so that the
+    user can modify the Library and then relink to produce a modified
+    executable containing the modified Library.  (It is understood
+    that the user who changes the contents of definitions files in the
+    Library will not necessarily be able to recompile the application
+    to use the modified definitions.)
+
+    b) Use a suitable shared library mechanism for linking with the
+    Library.  A suitable mechanism is one that (1) uses at run time a
+    copy of the library already present on the user's computer system,
+    rather than copying library functions into the executable, and (2)
+    will operate properly with a modified version of the library, if
+    the user installs one, as long as the modified version is
+    interface-compatible with the version that the work was made with.
+
+    c) Accompany the work with a written offer, valid for at
+    least three years, to give the same user the materials
+    specified in Subsection 6a, above, for a charge no more
+    than the cost of performing this distribution.
+
+    d) If distribution of the work is made by offering access to copy
+    from a designated place, offer equivalent access to copy the above
+    specified materials from the same place.
+
+    e) Verify that the user has already received a copy of these
+    materials or that you have already sent this user a copy.
+
+  For an executable, the required form of the "work that uses the
+Library" must include any data and utility programs needed for
+reproducing the executable from it.  However, as a special exception,
+the materials to be distributed need not include anything that is
+normally distributed (in either source or binary form) with the major
+components (compiler, kernel, and so on) of the operating system on
+which the executable runs, unless that component itself accompanies
+the executable.
+
+  It may happen that this requirement contradicts the license
+restrictions of other proprietary libraries that do not normally
+accompany the operating system.  Such a contradiction means you cannot
+use both them and the Library together in an executable that you
+distribute.
+\f
+  7. You may place library facilities that are a work based on the
+Library side-by-side in a single library together with other library
+facilities not covered by this License, and distribute such a combined
+library, provided that the separate distribution of the work based on
+the Library and of the other library facilities is otherwise
+permitted, and provided that you do these two things:
+
+    a) Accompany the combined library with a copy of the same work
+    based on the Library, uncombined with any other library
+    facilities.  This must be distributed under the terms of the
+    Sections above.
+
+    b) Give prominent notice with the combined library of the fact
+    that part of it is a work based on the Library, and explaining
+    where to find the accompanying uncombined form of the same work.
+
+  8. You may not copy, modify, sublicense, link with, or distribute
+the Library except as expressly provided under this License.  Any
+attempt otherwise to copy, modify, sublicense, link with, or
+distribute the Library is void, and will automatically terminate your
+rights under this License.  However, parties who have received copies,
+or rights, from you under this License will not have their licenses
+terminated so long as such parties remain in full compliance.
+
+  9. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Library or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Library or works based on it.
+
+  10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+subject to these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties with
+this License.
+\f
+  11. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Library at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Library by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Library.
+
+If any portion of this section is held invalid or unenforceable under any
+particular circumstance, the balance of the section is intended to apply,
+and the section as a whole is intended to apply in other circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  12. If the distribution and/or use of the Library is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Library under this License may add
+an explicit geographical distribution limitation excluding those countries,
+so that distribution is permitted only in or among countries not thus
+excluded.  In such case, this License incorporates the limitation as if
+written in the body of this License.
+
+  13. The Free Software Foundation may publish revised and/or new
+versions of the Lesser General Public License from time to time.
+Such new versions will be similar in spirit to the present version,
+but may differ in detail to address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Library
+specifies a version number of this License which applies to it and
+"any later version", you have the option of following the terms and
+conditions either of that version or of any later version published by
+the Free Software Foundation.  If the Library does not specify a
+license version number, you may choose any version ever published by
+the Free Software Foundation.
+\f
+  14. If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+write to the author to ask for permission.  For software which is
+copyrighted by the Free Software Foundation, write to the Free
+Software Foundation; we sometimes make exceptions for this.  Our
+decision will be guided by the two goals of preserving the free status
+of all derivatives of our free software and of promoting the sharing
+and reuse of software generally.
+
+                           NO WARRANTY
+
+  15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
+KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
+LIBRARY IS WITH YOU.  SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+  16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
+AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
+FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
+LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
+RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
+FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
+
+                    END OF TERMS AND CONDITIONS
+\f
+           How to Apply These Terms to Your New Libraries
+
+  If you develop a new library, and you want it to be of the greatest
+possible use to the public, we recommend making it free software that
+everyone can redistribute and change.  You can do so by permitting
+redistribution under these terms (or, alternatively, under the terms of the
+ordinary General Public License).
+
+  To apply these terms, attach the following notices to the library.  It is
+safest to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least the
+"copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the library's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2.1 of the License, or (at your option) any later version.
+
+    This library 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
+    Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public
+    License along with this library; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+Also add information on how to contact you by electronic and paper mail.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the library, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the
+  library `Frob' (a library for tweaking knobs) written by James Random Hacker.
+
+  <signature of Ty Coon>, 1 April 1990
+  Ty Coon, President of Vice
+
+That's all there is to it!
+
+
diff --git a/INSTALL b/INSTALL
new file mode 100644 (file)
index 0000000..5c50ba5
--- /dev/null
+++ b/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/Makefile.in b/Makefile.in
new file mode 100644 (file)
index 0000000..0c90f4d
--- /dev/null
@@ -0,0 +1,548 @@
+#
+# 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
+
+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;)
+
+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
+
+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/README b/README
new file mode 100644 (file)
index 0000000..52cb4cb
--- /dev/null
+++ b/README
@@ -0,0 +1,41 @@
+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
diff --git a/acl.c b/acl.c
new file mode 100644 (file)
index 0000000..24b4489
--- /dev/null
+++ b/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/aclocal.m4 b/aclocal.m4
new file mode 100644 (file)
index 0000000..bc7540d
--- /dev/null
@@ -0,0 +1 @@
+builtin(include,tcl.m4)
diff --git a/client.c b/client.c
new file mode 100644 (file)
index 0000000..f70ff40
--- /dev/null
+++ b/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/clipboard.c b/clipboard.c
new file mode 100644 (file)
index 0000000..68df675
--- /dev/null
@@ -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, &paramlist[lp], buf);
+    }
+    else if( !strncmp(cmd, "app", 3) ){
+      status = ClipBoardAppend(xpa, name, &paramlist[lp], buf);
+    }
+    else if( !strncmp(cmd, "del", 3) ){
+      status = ClipBoardDelete(xpa, name, &paramlist[lp]);
+    }
+#ifdef LATER
+    else if( !strncmp(cmd, "loa", 3) ){
+      status = ClipBoardLoad(xpa, name, &paramlist[lp], buf);
+    }
+    else if( !strncmp(cmd, "sav", 3) ){
+      status = ClipBoardSave(xpa, name, &paramlist[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/command.c b/command.c
new file mode 100644 (file)
index 0000000..2ea182d
--- /dev/null
+++ b/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, &paramlist[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,
+                                &paramlist[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/conf.h b/conf.h
new file mode 100644 (file)
index 0000000..4831f03
--- /dev/null
+++ b/conf.h
@@ -0,0 +1,91 @@
+/* conf.h.  Generated from conf.h.in by configure.  */
+/*
+ *     Copyright (c) 1999-2003 Smithsonian Astrophysical Observatory
+ */
+
+/* Define as 1 if you have string.h  */
+#define HAVE_STRING_H 1
+
+/* Define as 1 if you have stdlib.h  */
+#define HAVE_STDLIB_H 1
+
+/* Define as 1 if you have malloc.h  */
+#define HAVE_MALLOC_H 1
+
+/* Define as 1 if you have unistd.h  */
+#define HAVE_UNISTD_H 1
+
+/* Define as 1 if you have getopt.h  */
+#define HAVE_GETOPT_H 1
+
+/* Define as 1 if you have pwd.h  */
+#define HAVE_PWD_H 1
+
+/* Define as 1 if you have values.h  */
+#define HAVE_VALUES_H 1
+
+/* Define as 1 if you have dlfcn.h  */
+#define HAVE_DLFCN_H 1
+
+/* Define as 1 if you have sys/un.h  */
+#define HAVE_SYS_UN_H 1
+
+/* Define as 1 if you have sys/shm.h  */
+#define HAVE_SYS_SHM_H 1
+
+/* Define as 1 if you have sys/mman.h  */
+#define HAVE_SYS_MMAN_H 1
+
+/* Define as 1 if you have sys/ipc.h  */
+#define HAVE_SYS_IPC_H 1
+
+/* Define as 1 if you have setjmp.h  */
+#define HAVE_SETJMP_H 1
+
+/* Define as 1 if you have socklen_t */
+#define HAVE_SOCKLEN_T 1
+
+/* Define as 1 if you have strchr  */
+#define HAVE_STRCHR 1
+
+/* Define as 1 if you have memcpy  */
+#define HAVE_MEMCPY 1
+
+/* Define as 1 if you have snprintf  */
+#define HAVE_SNPRINTF 1
+
+/* Define as 1 if you have setenv  */
+#define HAVE_SETENV 1
+
+/* 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  */
+#define HAVE_ATEXIT 1
+
+/* 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 */
+#define HAVE_XT 1
+
+/* 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/conf.h.in b/conf.h.in
new file mode 100644 (file)
index 0000000..d78af89
--- /dev/null
+++ b/conf.h.in
@@ -0,0 +1,90 @@
+/*
+ *     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 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/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/config.guess b/config.guess
new file mode 100755 (executable)
index 0000000..22906b3
--- /dev/null
@@ -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/config.sub b/config.sub
new file mode 100755 (executable)
index 0000000..5705e54
--- /dev/null
@@ -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/configure b/configure
new file mode 100755 (executable)
index 0000000..9c209a7
--- /dev/null
+++ b/configure
@@ -0,0 +1,9696 @@
+#! /bin/sh
+# Guess values for system-dependent variables and create Makefiles.
+# Generated by GNU Autoconf 2.63 for xpa 2.1.15.
+#
+# Report bugs to <saord@cfa.harvard.edu>.
+#
+# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001,
+# 2002, 2003, 2004, 2005, 2006, 2007, 2008 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 more Bourne compatible
+DUALCASE=1; export DUALCASE # for MKS sh
+if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then
+  emulate sh
+  NULLCMD=:
+  # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which
+  # is contrary to our usage.  Disable this feature.
+  alias -g '${1+"$@"}'='"$@"'
+  setopt NO_GLOB_SUBST
+else
+  case `(set -o) 2>/dev/null` in
+  *posix*) set -o posix ;;
+esac
+
+fi
+
+
+
+
+# PATH needs CR
+# 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
+
+as_nl='
+'
+export as_nl
+# Printing a long string crashes Solaris 7 /usr/bin/printf.
+as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo
+if (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then
+  as_echo='printf %s\n'
+  as_echo_n='printf %s'
+else
+  if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then
+    as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"'
+    as_echo_n='/usr/ucb/echo -n'
+  else
+    as_echo_body='eval expr "X$1" : "X\\(.*\\)"'
+    as_echo_n_body='eval
+      arg=$1;
+      case $arg in
+      *"$as_nl"*)
+       expr "X$arg" : "X\\(.*\\)$as_nl";
+       arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;;
+      esac;
+      expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl"
+    '
+    export as_echo_n_body
+    as_echo_n='sh -c $as_echo_n_body as_echo'
+  fi
+  export as_echo_body
+  as_echo='sh -c $as_echo_body as_echo'
+fi
+
+# The user is always right.
+if test "${PATH_SEPARATOR+set}" != set; then
+  PATH_SEPARATOR=:
+  (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && {
+    (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 ||
+      PATH_SEPARATOR=';'
+  }
+fi
+
+# Support unset when possible.
+if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then
+  as_unset=unset
+else
+  as_unset=false
+fi
+
+
+# IFS
+# We need space, tab and new line, in precisely that order.  Quoting is
+# there to prevent editors from complaining about space-tab.
+# (If _AS_PATH_WALK were called with IFS unset, it would disable word
+# splitting by setting IFS to empty value.)
+IFS=" ""       $as_nl"
+
+# Find who we are.  Look in the path if we contain no directory separator.
+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
+IFS=$as_save_IFS
+
+     ;;
+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
+  $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2
+  { (exit 1); exit 1; }
+fi
+
+# Work around bugs in pre-3.0 UWIN ksh.
+for as_var in ENV MAIL MAILPATH
+do ($as_unset $as_var) >/dev/null 2>&1 && $as_unset $as_var
+done
+PS1='$ '
+PS2='> '
+PS4='+ '
+
+# NLS nuisances.
+LC_ALL=C
+export LC_ALL
+LANGUAGE=C
+export LANGUAGE
+
+# Required to use basename.
+if expr a : '\(a\)' >/dev/null 2>&1 &&
+   test "X`expr 00001 : '.*\(...\)'`" = X001; 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 ||
+$as_echo X/"$0" |
+    sed '/^.*\/\([^/][^/]*\)\/*$/{
+           s//\1/
+           q
+         }
+         /^X\/\(\/\/\)$/{
+           s//\1/
+           q
+         }
+         /^X\/\(\/\).*/{
+           s//\1/
+           q
+         }
+         s/.*/./; q'`
+
+# CDPATH.
+$as_unset CDPATH
+
+
+if test "x$CONFIG_SHELL" = x; then
+  if (eval ":") 2>/dev/null; then
+  as_have_required=yes
+else
+  as_have_required=no
+fi
+
+  if test $as_have_required = yes &&    (eval ":
+(as_func_return () {
+  (exit \$1)
+}
+as_func_success () {
+  as_func_return 0
+}
+as_func_failure () {
+  as_func_return 1
+}
+as_func_ret_success () {
+  return 0
+}
+as_func_ret_failure () {
+  return 1
+}
+
+exitcode=0
+if as_func_success; then
+  :
+else
+  exitcode=1
+  echo as_func_success failed.
+fi
+
+if as_func_failure; then
+  exitcode=1
+  echo as_func_failure succeeded.
+fi
+
+if as_func_ret_success; then
+  :
+else
+  exitcode=1
+  echo as_func_ret_success failed.
+fi
+
+if as_func_ret_failure; then
+  exitcode=1
+  echo as_func_ret_failure succeeded.
+fi
+
+if ( set x; as_func_ret_success y && test x = \"\$1\" ); then
+  :
+else
+  exitcode=1
+  echo positional parameters were not saved.
+fi
+
+test \$exitcode = 0) || { (exit 1); exit 1; }
+
+(
+  as_lineno_1=\$LINENO
+  as_lineno_2=\$LINENO
+  test \"x\$as_lineno_1\" != \"x\$as_lineno_2\" &&
+  test \"x\`expr \$as_lineno_1 + 1\`\" = \"x\$as_lineno_2\") || { (exit 1); exit 1; }
+") 2> /dev/null; then
+  :
+else
+  as_candidate_shells=
+    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=.
+  case $as_dir in
+        /*)
+          for as_base in sh bash ksh sh5; do
+            as_candidate_shells="$as_candidate_shells $as_dir/$as_base"
+          done;;
+       esac
+done
+IFS=$as_save_IFS
+
+
+      for as_shell in $as_candidate_shells $SHELL; do
+        # Try only shells that exist, to save several forks.
+        if { test -f "$as_shell" || test -f "$as_shell.exe"; } &&
+               { ("$as_shell") 2> /dev/null <<\_ASEOF
+if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then
+  emulate sh
+  NULLCMD=:
+  # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which
+  # is contrary to our usage.  Disable this feature.
+  alias -g '${1+"$@"}'='"$@"'
+  setopt NO_GLOB_SUBST
+else
+  case `(set -o) 2>/dev/null` in
+  *posix*) set -o posix ;;
+esac
+
+fi
+
+
+:
+_ASEOF
+}; then
+  CONFIG_SHELL=$as_shell
+              as_have_required=yes
+              if { "$as_shell" 2> /dev/null <<\_ASEOF
+if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then
+  emulate sh
+  NULLCMD=:
+  # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which
+  # is contrary to our usage.  Disable this feature.
+  alias -g '${1+"$@"}'='"$@"'
+  setopt NO_GLOB_SUBST
+else
+  case `(set -o) 2>/dev/null` in
+  *posix*) set -o posix ;;
+esac
+
+fi
+
+
+:
+(as_func_return () {
+  (exit $1)
+}
+as_func_success () {
+  as_func_return 0
+}
+as_func_failure () {
+  as_func_return 1
+}
+as_func_ret_success () {
+  return 0
+}
+as_func_ret_failure () {
+  return 1
+}
+
+exitcode=0
+if as_func_success; then
+  :
+else
+  exitcode=1
+  echo as_func_success failed.
+fi
+
+if as_func_failure; then
+  exitcode=1
+  echo as_func_failure succeeded.
+fi
+
+if as_func_ret_success; then
+  :
+else
+  exitcode=1
+  echo as_func_ret_success failed.
+fi
+
+if as_func_ret_failure; then
+  exitcode=1
+  echo as_func_ret_failure succeeded.
+fi
+
+if ( set x; as_func_ret_success y && test x = "$1" ); then
+  :
+else
+  exitcode=1
+  echo positional parameters were not saved.
+fi
+
+test $exitcode = 0) || { (exit 1); exit 1; }
+
+(
+  as_lineno_1=$LINENO
+  as_lineno_2=$LINENO
+  test "x$as_lineno_1" != "x$as_lineno_2" &&
+  test "x`expr $as_lineno_1 + 1`" = "x$as_lineno_2") || { (exit 1); exit 1; }
+
+_ASEOF
+}; then
+  break
+fi
+
+fi
+
+      done
+
+      if test "x$CONFIG_SHELL" != x; then
+  for as_var in BASH_ENV ENV
+       do ($as_unset $as_var) >/dev/null 2>&1 && $as_unset $as_var
+       done
+       export CONFIG_SHELL
+       exec "$CONFIG_SHELL" "$as_myself" ${1+"$@"}
+fi
+
+
+    if test $as_have_required = no; then
+  echo This script requires a shell more modern than all the
+      echo shells that I found on your system.  Please install a
+      echo modern shell, or manually run the script under such a
+      echo shell if you do have one.
+      { (exit 1); exit 1; }
+fi
+
+
+fi
+
+fi
+
+
+
+(eval "as_func_return () {
+  (exit \$1)
+}
+as_func_success () {
+  as_func_return 0
+}
+as_func_failure () {
+  as_func_return 1
+}
+as_func_ret_success () {
+  return 0
+}
+as_func_ret_failure () {
+  return 1
+}
+
+exitcode=0
+if as_func_success; then
+  :
+else
+  exitcode=1
+  echo as_func_success failed.
+fi
+
+if as_func_failure; then
+  exitcode=1
+  echo as_func_failure succeeded.
+fi
+
+if as_func_ret_success; then
+  :
+else
+  exitcode=1
+  echo as_func_ret_success failed.
+fi
+
+if as_func_ret_failure; then
+  exitcode=1
+  echo as_func_ret_failure succeeded.
+fi
+
+if ( set x; as_func_ret_success y && test x = \"\$1\" ); then
+  :
+else
+  exitcode=1
+  echo positional parameters were not saved.
+fi
+
+test \$exitcode = 0") || {
+  echo No shell found that supports shell functions.
+  echo Please tell bug-autoconf@gnu.org about your system,
+  echo including any error possibly output before this message.
+  echo This can help us improve future autoconf versions.
+  echo Configuration will now proceed without shell functions.
+}
+
+
+
+  as_lineno_1=$LINENO
+  as_lineno_2=$LINENO
+  test "x$as_lineno_1" != "x$as_lineno_2" &&
+  test "x`expr $as_lineno_1 + 1`" = "x$as_lineno_2" || {
+
+  # 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 after each line using $LINENO; the second 'sed'
+  # does the real work.  The second script uses 'N' to pair each
+  # line-number line with the line containing $LINENO, 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
+  # scripts with optimization help from Paolo Bonzini.  Blame Lee
+  # E. McMahon (1931-1989) for sed's syntax.  :-)
+  sed -n '
+    p
+    /[$]LINENO/=
+  ' <$as_myself |
+    sed '
+      s/[$]LINENO.*/&-/
+      t lineno
+      b
+      :lineno
+      N
+      :loop
+      s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/
+      t loop
+      s/-\n.*//
+    ' >$as_me.lineno &&
+  chmod +x "$as_me.lineno" ||
+    { $as_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 sensitive to this).
+  . "./$as_me.lineno"
+  # Exit status is that of the last command.
+  exit
+}
+
+
+if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then
+  as_dirname=dirname
+else
+  as_dirname=false
+fi
+
+ECHO_C= ECHO_N= ECHO_T=
+case `echo -n x` in
+-n*)
+  case `echo 'x\c'` in
+  *c*) ECHO_T='        ';;     # ECHO_T is single tab character.
+  *)   ECHO_C='\c';;
+  esac;;
+*)
+  ECHO_N='-n';;
+esac
+if expr a : '\(a\)' >/dev/null 2>&1 &&
+   test "X`expr 00001 : '.*\(...\)'`" = X001; then
+  as_expr=expr
+else
+  as_expr=false
+fi
+
+rm -f conf$$ conf$$.exe conf$$.file
+if test -d conf$$.dir; then
+  rm -f conf$$.dir/conf$$.file
+else
+  rm -f conf$$.dir
+  mkdir conf$$.dir 2>/dev/null
+fi
+if (echo >conf$$.file) 2>/dev/null; then
+  if ln -s conf$$.file conf$$ 2>/dev/null; then
+    as_ln_s='ln -s'
+    # ... but there are two gotchas:
+    # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail.
+    # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable.
+    # In both cases, we have to default to `cp -p'.
+    ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe ||
+      as_ln_s='cp -p'
+  elif ln conf$$.file conf$$ 2>/dev/null; then
+    as_ln_s=ln
+  else
+    as_ln_s='cp -p'
+  fi
+else
+  as_ln_s='cp -p'
+fi
+rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file
+rmdir conf$$.dir 2>/dev/null
+
+if mkdir -p . 2>/dev/null; then
+  as_mkdir_p=:
+else
+  test -d ./-p && rmdir ./-p
+  as_mkdir_p=false
+fi
+
+if test -x / >/dev/null 2>&1; then
+  as_test_x='test -x'
+else
+  if ls -dL / >/dev/null 2>&1; then
+    as_ls_L_option=L
+  else
+    as_ls_L_option=
+  fi
+  as_test_x='
+    eval sh -c '\''
+      if test -d "$1"; then
+       test -d "$1/.";
+      else
+       case $1 in
+       -*)set "./$1";;
+       esac;
+       case `ls -ld'$as_ls_L_option' "$1" 2>/dev/null` in
+       ???[sx]*):;;*)false;;esac;fi
+    '\'' sh
+  '
+fi
+as_executable_p=$as_test_x
+
+# 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'"
+
+
+
+exec 7<&0 </dev/null 6>&1
+
+# 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`
+
+#
+# Initializations.
+#
+ac_default_prefix=/usr/local
+ac_clean_files=
+ac_config_libobj_dir=.
+LIBOBJS=
+cross_compiling=no
+subdirs=
+MFLAGS=
+MAKEFLAGS=
+SHELL=${CONFIG_SHELL-/bin/sh}
+
+# Identity of this package.
+PACKAGE_NAME='xpa'
+PACKAGE_TARNAME='xpa'
+PACKAGE_VERSION='2.1.15'
+PACKAGE_STRING='xpa 2.1.15'
+PACKAGE_BUGREPORT='saord@cfa.harvard.edu'
+
+ac_unique_file="./xpa.h"
+# Factoring default headers for most tests.
+ac_includes_default="\
+#include <stdio.h>
+#ifdef HAVE_SYS_TYPES_H
+# include <sys/types.h>
+#endif
+#ifdef HAVE_SYS_STAT_H
+# include <sys/stat.h>
+#endif
+#ifdef STDC_HEADERS
+# include <stdlib.h>
+# include <stddef.h>
+#else
+# ifdef HAVE_STDLIB_H
+#  include <stdlib.h>
+# endif
+#endif
+#ifdef HAVE_STRING_H
+# if !defined STDC_HEADERS && defined HAVE_MEMORY_H
+#  include <memory.h>
+# endif
+# include <string.h>
+#endif
+#ifdef HAVE_STRINGS_H
+# include <strings.h>
+#endif
+#ifdef HAVE_INTTYPES_H
+# include <inttypes.h>
+#endif
+#ifdef HAVE_STDINT_H
+# include <stdint.h>
+#endif
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif"
+
+ac_subst_vars='LTLIBOBJS
+LIBOBJS
+EXTRA_LIBS
+GTK_LIBS
+GTK_CFLAGS
+TCL_LIBS
+TCL_CFLAGS
+TCL_STUB_LIB_SPEC
+TCL_STUB_LIB_FLAG
+TCL_STUB_LIB_FILE
+TCL_LIB_SPEC
+TCL_LIB_FLAG
+TCL_LIB_FILE
+TCL_SRC_DIR
+TCL_BIN_DIR
+TCL_VERSION
+X_EXTRA_LIBS
+X_LIBS
+X_PRE_LIBS
+X_CFLAGS
+XMKMF
+LLIB
+DOSHARED
+TLIB
+RANLIB
+SZ_LONG
+EGREP
+GREP
+CPP
+OBJEXT
+EXEEXT
+ac_ct_CC
+CPPFLAGS
+LDFLAGS
+CFLAGS
+CC
+host_os
+host_vendor
+host_cpu
+host
+build_os
+build_vendor
+build_cpu
+build
+target_alias
+host_alias
+build_alias
+LIBS
+ECHO_T
+ECHO_N
+ECHO_C
+DEFS
+mandir
+localedir
+libdir
+psdir
+pdfdir
+dvidir
+htmldir
+infodir
+docdir
+oldincludedir
+includedir
+localstatedir
+sharedstatedir
+sysconfdir
+datadir
+datarootdir
+libexecdir
+sbindir
+bindir
+program_transform_name
+prefix
+exec_prefix
+PACKAGE_BUGREPORT
+PACKAGE_STRING
+PACKAGE_VERSION
+PACKAGE_TARNAME
+PACKAGE_NAME
+PATH_SEPARATOR
+SHELL'
+ac_subst_files=''
+ac_user_opts='
+enable_option_checking
+enable_threaded_xpans
+enable_shared
+enable_posix_spawn
+with_x
+with_tcl
+with_threads
+with_gtk
+'
+      ac_precious_vars='build_alias
+host_alias
+target_alias
+CC
+CFLAGS
+LDFLAGS
+LIBS
+CPPFLAGS
+CPP
+XMKMF'
+
+
+# Initialize some variables set by options.
+ac_init_help=
+ac_init_version=false
+ac_unrecognized_opts=
+ac_unrecognized_sep=
+# 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.
+# (The list follows the same order as the GNU Coding Standards.)
+bindir='${exec_prefix}/bin'
+sbindir='${exec_prefix}/sbin'
+libexecdir='${exec_prefix}/libexec'
+datarootdir='${prefix}/share'
+datadir='${datarootdir}'
+sysconfdir='${prefix}/etc'
+sharedstatedir='${prefix}/com'
+localstatedir='${prefix}/var'
+includedir='${prefix}/include'
+oldincludedir='/usr/include'
+docdir='${datarootdir}/doc/${PACKAGE_TARNAME}'
+infodir='${datarootdir}/info'
+htmldir='${docdir}'
+dvidir='${docdir}'
+pdfdir='${docdir}'
+psdir='${docdir}'
+libdir='${exec_prefix}/lib'
+localedir='${datarootdir}/locale'
+mandir='${datarootdir}/man'
+
+ac_prev=
+ac_dashdash=
+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
+
+  case $ac_option in
+  *=*) ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;;
+  *)   ac_optarg=yes ;;
+  esac
+
+  # Accept the important Cygnus configure options, so we can diagnose typos.
+
+  case $ac_dashdash$ac_option in
+  --)
+    ac_dashdash=yes ;;
+
+  -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)
+    ac_prev=datadir ;;
+  -datadir=* | --datadir=* | --datadi=* | --datad=*)
+    datadir=$ac_optarg ;;
+
+  -datarootdir | --datarootdir | --datarootdi | --datarootd | --dataroot \
+  | --dataroo | --dataro | --datar)
+    ac_prev=datarootdir ;;
+  -datarootdir=* | --datarootdir=* | --datarootdi=* | --datarootd=* \
+  | --dataroot=* | --dataroo=* | --dataro=* | --datar=*)
+    datarootdir=$ac_optarg ;;
+
+  -disable-* | --disable-*)
+    ac_useropt=`expr "x$ac_option" : 'x-*disable-\(.*\)'`
+    # Reject names that are not valid shell variable names.
+    expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
+      { $as_echo "$as_me: error: invalid feature name: $ac_useropt" >&2
+   { (exit 1); exit 1; }; }
+    ac_useropt_orig=$ac_useropt
+    ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+    case $ac_user_opts in
+      *"
+"enable_$ac_useropt"
+"*) ;;
+      *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--disable-$ac_useropt_orig"
+        ac_unrecognized_sep=', ';;
+    esac
+    eval enable_$ac_useropt=no ;;
+
+  -docdir | --docdir | --docdi | --doc | --do)
+    ac_prev=docdir ;;
+  -docdir=* | --docdir=* | --docdi=* | --doc=* | --do=*)
+    docdir=$ac_optarg ;;
+
+  -dvidir | --dvidir | --dvidi | --dvid | --dvi | --dv)
+    ac_prev=dvidir ;;
+  -dvidir=* | --dvidir=* | --dvidi=* | --dvid=* | --dvi=* | --dv=*)
+    dvidir=$ac_optarg ;;
+
+  -enable-* | --enable-*)
+    ac_useropt=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'`
+    # Reject names that are not valid shell variable names.
+    expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
+      { $as_echo "$as_me: error: invalid feature name: $ac_useropt" >&2
+   { (exit 1); exit 1; }; }
+    ac_useropt_orig=$ac_useropt
+    ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+    case $ac_user_opts in
+      *"
+"enable_$ac_useropt"
+"*) ;;
+      *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--enable-$ac_useropt_orig"
+        ac_unrecognized_sep=', ';;
+    esac
+    eval enable_$ac_useropt=\$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 ;;
+
+  -htmldir | --htmldir | --htmldi | --htmld | --html | --htm | --ht)
+    ac_prev=htmldir ;;
+  -htmldir=* | --htmldir=* | --htmldi=* | --htmld=* | --html=* | --htm=* \
+  | --ht=*)
+    htmldir=$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 ;;
+
+  -localedir | --localedir | --localedi | --localed | --locale)
+    ac_prev=localedir ;;
+  -localedir=* | --localedir=* | --localedi=* | --localed=* | --locale=*)
+    localedir=$ac_optarg ;;
+
+  -localstatedir | --localstatedir | --localstatedi | --localstated \
+  | --localstate | --localstat | --localsta | --localst | --locals)
+    ac_prev=localstatedir ;;
+  -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \
+  | --localstate=* | --localstat=* | --localsta=* | --localst=* | --locals=*)
+    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 ;;
+
+  -pdfdir | --pdfdir | --pdfdi | --pdfd | --pdf | --pd)
+    ac_prev=pdfdir ;;
+  -pdfdir=* | --pdfdir=* | --pdfdi=* | --pdfd=* | --pdf=* | --pd=*)
+    pdfdir=$ac_optarg ;;
+
+  -psdir | --psdir | --psdi | --psd | --ps)
+    ac_prev=psdir ;;
+  -psdir=* | --psdir=* | --psdi=* | --psd=* | --ps=*)
+    psdir=$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_useropt=`expr "x$ac_option" : 'x-*with-\([^=]*\)'`
+    # Reject names that are not valid shell variable names.
+    expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
+      { $as_echo "$as_me: error: invalid package name: $ac_useropt" >&2
+   { (exit 1); exit 1; }; }
+    ac_useropt_orig=$ac_useropt
+    ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+    case $ac_user_opts in
+      *"
+"with_$ac_useropt"
+"*) ;;
+      *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--with-$ac_useropt_orig"
+        ac_unrecognized_sep=', ';;
+    esac
+    eval with_$ac_useropt=\$ac_optarg ;;
+
+  -without-* | --without-*)
+    ac_useropt=`expr "x$ac_option" : 'x-*without-\(.*\)'`
+    # Reject names that are not valid shell variable names.
+    expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
+      { $as_echo "$as_me: error: invalid package name: $ac_useropt" >&2
+   { (exit 1); exit 1; }; }
+    ac_useropt_orig=$ac_useropt
+    ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+    case $ac_user_opts in
+      *"
+"with_$ac_useropt"
+"*) ;;
+      *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--without-$ac_useropt_orig"
+        ac_unrecognized_sep=', ';;
+    esac
+    eval with_$ac_useropt=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 ;;
+
+  -*) { $as_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 &&
+      { $as_echo "$as_me: error: invalid variable name: $ac_envvar" >&2
+   { (exit 1); exit 1; }; }
+    eval $ac_envvar=\$ac_optarg
+    export $ac_envvar ;;
+
+  *)
+    # FIXME: should be removed in autoconf 3.0.
+    $as_echo "$as_me: WARNING: you should use --build, --host, --target" >&2
+    expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null &&
+      $as_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'`
+  { $as_echo "$as_me: error: missing argument to $ac_option" >&2
+   { (exit 1); exit 1; }; }
+fi
+
+if test -n "$ac_unrecognized_opts"; then
+  case $enable_option_checking in
+    no) ;;
+    fatal) { $as_echo "$as_me: error: unrecognized options: $ac_unrecognized_opts" >&2
+   { (exit 1); exit 1; }; } ;;
+    *)     $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 ;;
+  esac
+fi
+
+# Check all directory arguments for consistency.
+for ac_var in  exec_prefix prefix bindir sbindir libexecdir datarootdir \
+               datadir sysconfdir sharedstatedir localstatedir includedir \
+               oldincludedir docdir infodir htmldir dvidir pdfdir psdir \
+               libdir localedir mandir
+do
+  eval ac_val=\$$ac_var
+  # Remove trailing slashes.
+  case $ac_val in
+    */ )
+      ac_val=`expr "X$ac_val" : 'X\(.*[^/]\)' \| "X$ac_val" : 'X\(.*\)'`
+      eval $ac_var=\$ac_val;;
+  esac
+  # Be sure to have absolute directory names.
+  case $ac_val in
+    [\\/$]* | ?:[\\/]* )  continue;;
+    NONE | '' ) case $ac_var in *prefix ) continue;; esac;;
+  esac
+  { $as_echo "$as_me: error: expected an absolute directory name for --$ac_var: $ac_val" >&2
+   { (exit 1); exit 1; }; }
+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
+    $as_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
+
+
+ac_pwd=`pwd` && test -n "$ac_pwd" &&
+ac_ls_di=`ls -di .` &&
+ac_pwd_ls_di=`cd "$ac_pwd" && ls -di .` ||
+  { $as_echo "$as_me: error: working directory cannot be determined" >&2
+   { (exit 1); exit 1; }; }
+test "X$ac_ls_di" = "X$ac_pwd_ls_di" ||
+  { $as_echo "$as_me: error: pwd does not report name of working directory" >&2
+   { (exit 1); exit 1; }; }
+
+
+# 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 the parent directory.
+  ac_confdir=`$as_dirname -- "$as_myself" ||
+$as_expr X"$as_myself" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+        X"$as_myself" : 'X\(//\)[^/]' \| \
+        X"$as_myself" : 'X\(//\)$' \| \
+        X"$as_myself" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$as_myself" |
+    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
+  test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .."
+  { $as_echo "$as_me: error: cannot find sources ($ac_unique_file) in $srcdir" >&2
+   { (exit 1); exit 1; }; }
+fi
+ac_msg="sources are in $srcdir, but \`cd $srcdir' does not work"
+ac_abs_confdir=`(
+       cd "$srcdir" && test -r "./$ac_unique_file" || { $as_echo "$as_me: error: $ac_msg" >&2
+   { (exit 1); exit 1; }; }
+       pwd)`
+# When building in place, set srcdir=.
+if test "$ac_abs_confdir" = "$ac_pwd"; then
+  srcdir=.
+fi
+# Remove unnecessary trailing slashes from srcdir.
+# Double slashes in file names in object file debugging info
+# mess up M-x gdb in Emacs.
+case $srcdir in
+*/) srcdir=`expr "X$srcdir" : 'X\(.*[^/]\)' \| "X$srcdir" : 'X\(.*\)'`;;
+esac
+for ac_var in $ac_precious_vars; do
+  eval ac_env_${ac_var}_set=\${${ac_var}+set}
+  eval ac_env_${ac_var}_value=\$${ac_var}
+  eval ac_cv_env_${ac_var}_set=\${${ac_var}+set}
+  eval ac_cv_env_${ac_var}_value=\$${ac_var}
+done
+
+#
+# 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.15 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 \`..']
+
+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]
+  --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]
+  --datarootdir=DIR       read-only arch.-independent data root [PREFIX/share]
+  --datadir=DIR           read-only architecture-independent data [DATAROOTDIR]
+  --infodir=DIR           info documentation [DATAROOTDIR/info]
+  --localedir=DIR         locale-dependent data [DATAROOTDIR/locale]
+  --mandir=DIR            man documentation [DATAROOTDIR/man]
+  --docdir=DIR            documentation root [DATAROOTDIR/doc/xpa]
+  --htmldir=DIR           html documentation [DOCDIR]
+  --dvidir=DIR            dvi documentation [DOCDIR]
+  --pdfdir=DIR            pdf documentation [DOCDIR]
+  --psdir=DIR             ps documentation [DOCDIR]
+_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.15:";;
+   esac
+  cat <<\_ACEOF
+
+Optional Features:
+  --disable-option-checking  ignore unrecognized --enable/--with options
+  --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>
+  LIBS        libraries to pass to the linker, e.g. -l<library>
+  CPPFLAGS    C/C++/Objective C preprocessor flags, e.g. -I<include dir> if
+              you have headers in a nonstandard directory <include dir>
+  CPP         C preprocessor
+  XMKMF       Path to xmkmf, Makefile generator for X Window System
+
+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 <saord@cfa.harvard.edu>.
+_ACEOF
+ac_status=$?
+fi
+
+if test "$ac_init_help" = "recursive"; then
+  # If there are subdirs, report their specific --help.
+  for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue
+    test -d "$ac_dir" ||
+      { cd "$srcdir" && ac_pwd=`pwd` && srcdir=. && test -d "$ac_dir"; } ||
+      continue
+    ac_builddir=.
+
+case "$ac_dir" in
+.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;;
+*)
+  ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'`
+  # A ".." for each directory in $ac_dir_suffix.
+  ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'`
+  case $ac_top_builddir_sub in
+  "") ac_top_builddir_sub=. ac_top_build_prefix= ;;
+  *)  ac_top_build_prefix=$ac_top_builddir_sub/ ;;
+  esac ;;
+esac
+ac_abs_top_builddir=$ac_pwd
+ac_abs_builddir=$ac_pwd$ac_dir_suffix
+# for backward compatibility:
+ac_top_builddir=$ac_top_build_prefix
+
+case $srcdir in
+  .)  # We are building in place.
+    ac_srcdir=.
+    ac_top_srcdir=$ac_top_builddir_sub
+    ac_abs_top_srcdir=$ac_pwd ;;
+  [\\/]* | ?:[\\/]* )  # Absolute name.
+    ac_srcdir=$srcdir$ac_dir_suffix;
+    ac_top_srcdir=$srcdir
+    ac_abs_top_srcdir=$srcdir ;;
+  *) # Relative name.
+    ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix
+    ac_top_srcdir=$ac_top_build_prefix$srcdir
+    ac_abs_top_srcdir=$ac_pwd/$srcdir ;;
+esac
+ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix
+
+    cd "$ac_dir" || { ac_status=$?; continue; }
+    # Check for guested 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
+    else
+      $as_echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2
+    fi || ac_status=$?
+    cd "$ac_pwd" || { ac_status=$?; break; }
+  done
+fi
+
+test -n "$ac_init_help" && exit $ac_status
+if $ac_init_version; then
+  cat <<\_ACEOF
+xpa configure 2.1.15
+generated by GNU Autoconf 2.63
+
+Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001,
+2002, 2003, 2004, 2005, 2006, 2007, 2008 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
+fi
+cat >config.log <<_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.15, which was
+generated by GNU Autoconf 2.63.  Invocation command line was
+
+  $ $0 $@
+
+_ACEOF
+exec 5>>config.log
+{
+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`
+/usr/bin/hostinfo      = `(/usr/bin/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=.
+  $as_echo "PATH: $as_dir"
+done
+IFS=$as_save_IFS
+
+} >&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_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=`$as_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_arg'"
+      ;;
+    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: Use '\'' to represent an apostrophe within the trap.
+# WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug.
+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,
+(
+  for ac_var in `(set) 2>&1 | sed -n '\''s/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'\''`; do
+    eval ac_val=\$$ac_var
+    case $ac_val in #(
+    *${as_nl}*)
+      case $ac_var in #(
+      *_cv_*) { $as_echo "$as_me:$LINENO: WARNING: cache variable $ac_var contains a newline" >&5
+$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;;
+      esac
+      case $ac_var in #(
+      _ | IFS | as_nl) ;; #(
+      BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #(
+      *) $as_unset $ac_var ;;
+      esac ;;
+    esac
+  done
+  (set) 2>&1 |
+    case $as_nl`(ac_space='\'' '\''; set) 2>&1` in #(
+    *${as_nl}ac_space=\ *)
+      sed -n \
+       "s/'\''/'\''\\\\'\'''\''/g;
+         s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\''\\2'\''/p"
+      ;; #(
+    *)
+      sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p"
+      ;;
+    esac |
+    sort
+)
+    echo
+
+    cat <<\_ASBOX
+## ----------------- ##
+## Output variables. ##
+## ----------------- ##
+_ASBOX
+    echo
+    for ac_var in $ac_subst_vars
+    do
+      eval ac_val=\$$ac_var
+      case $ac_val in
+      *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;;
+      esac
+      $as_echo "$ac_var='\''$ac_val'\''"
+    done | sort
+    echo
+
+    if test -n "$ac_subst_files"; then
+      cat <<\_ASBOX
+## ------------------- ##
+## File substitutions. ##
+## ------------------- ##
+_ASBOX
+      echo
+      for ac_var in $ac_subst_files
+      do
+       eval ac_val=\$$ac_var
+       case $ac_val in
+       *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;;
+       esac
+       $as_echo "$ac_var='\''$ac_val'\''"
+      done | sort
+      echo
+    fi
+
+    if test -s confdefs.h; then
+      cat <<\_ASBOX
+## ----------- ##
+## confdefs.h. ##
+## ----------- ##
+_ASBOX
+      echo
+      cat confdefs.h
+      echo
+    fi
+    test "$ac_signal" != 0 &&
+      $as_echo "$as_me: caught signal $ac_signal"
+    $as_echo "$as_me: exit $exit_status"
+  } >&5
+  rm -f core *.core core.conftest.* &&
+    rm -f -r 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 -f -r conftest* 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 an explicitly selected file to automatically selected ones.
+ac_site_file1=NONE
+ac_site_file2=NONE
+if test -n "$CONFIG_SITE"; then
+  ac_site_file1=$CONFIG_SITE
+elif test "x$prefix" != xNONE; then
+  ac_site_file1=$prefix/share/config.site
+  ac_site_file2=$prefix/etc/config.site
+else
+  ac_site_file1=$ac_default_prefix/share/config.site
+  ac_site_file2=$ac_default_prefix/etc/config.site
+fi
+for ac_site_file in "$ac_site_file1" "$ac_site_file2"
+do
+  test "x$ac_site_file" = xNONE && continue
+  if test -r "$ac_site_file"; then
+    { $as_echo "$as_me:$LINENO: loading site script $ac_site_file" >&5
+$as_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
+    { $as_echo "$as_me:$LINENO: loading cache $cache_file" >&5
+$as_echo "$as_me: loading cache $cache_file" >&6;}
+    case $cache_file in
+      [\\/]* | ?:[\\/]* ) . "$cache_file";;
+      *)                      . "./$cache_file";;
+    esac
+  fi
+else
+  { $as_echo "$as_me:$LINENO: creating cache $cache_file" >&5
+$as_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 $ac_precious_vars; 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,)
+      { $as_echo "$as_me:$LINENO: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5
+$as_echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;}
+      ac_cache_corrupted=: ;;
+    ,set)
+      { $as_echo "$as_me:$LINENO: error: \`$ac_var' was not set in the previous run" >&5
+$as_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
+       # differences in whitespace do not lead to failure.
+       ac_old_val_w=`echo x $ac_old_val`
+       ac_new_val_w=`echo x $ac_new_val`
+       if test "$ac_old_val_w" != "$ac_new_val_w"; then
+         { $as_echo "$as_me:$LINENO: error: \`$ac_var' has changed since the previous run:" >&5
+$as_echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;}
+         ac_cache_corrupted=:
+       else
+         { $as_echo "$as_me:$LINENO: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5
+$as_echo "$as_me: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&2;}
+         eval $ac_var=\$ac_old_val
+       fi
+       { $as_echo "$as_me:$LINENO:   former value:  \`$ac_old_val'" >&5
+$as_echo "$as_me:   former value:  \`$ac_old_val'" >&2;}
+       { $as_echo "$as_me:$LINENO:   current value: \`$ac_new_val'" >&5
+$as_echo "$as_me:   current value: \`$ac_new_val'" >&2;}
+      fi;;
+  esac
+  # Pass precious variables to config.status.
+  if test "$ac_new_set" = set; then
+    case $ac_new_val in
+    *\'*) ac_arg=$ac_var=`$as_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
+  { $as_echo "$as_me:$LINENO: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+  { $as_echo "$as_me:$LINENO: error: changes in the environment can compromise the build" >&5
+$as_echo "$as_me: error: changes in the environment can compromise the build" >&2;}
+  { { $as_echo "$as_me:$LINENO: error: run \`make distclean' and/or \`rm $cache_file' and start over" >&5
+$as_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
+  { { $as_echo "$as_me:$LINENO: error: cannot find install-sh or install.sh in \"$srcdir\" \"$srcdir/..\" \"$srcdir/../..\"" >&5
+$as_echo "$as_me: error: cannot find install-sh or install.sh in \"$srcdir\" \"$srcdir/..\" \"$srcdir/../..\"" >&2;}
+   { (exit 1); exit 1; }; }
+fi
+
+# These three variables are undocumented and unsupported,
+# and are intended to be withdrawn in a future Autoconf release.
+# They can cause serious problems if a builder's source tree is in a directory
+# whose full name contains unusual characters.
+ac_config_guess="$SHELL $ac_aux_dir/config.guess"  # Please don't use this var.
+ac_config_sub="$SHELL $ac_aux_dir/config.sub"  # Please don't use this var.
+ac_configure="$SHELL $ac_aux_dir/configure"  # Please don't use this var.
+
+
+# Make sure we can run config.sub.
+$SHELL "$ac_aux_dir/config.sub" sun4 >/dev/null 2>&1 ||
+  { { $as_echo "$as_me:$LINENO: error: cannot run $SHELL $ac_aux_dir/config.sub" >&5
+$as_echo "$as_me: error: cannot run $SHELL $ac_aux_dir/config.sub" >&2;}
+   { (exit 1); exit 1; }; }
+
+{ $as_echo "$as_me:$LINENO: checking build system type" >&5
+$as_echo_n "checking build system type... " >&6; }
+if test "${ac_cv_build+set}" = set; then
+  $as_echo_n "(cached) " >&6
+else
+  ac_build_alias=$build_alias
+test "x$ac_build_alias" = x &&
+  ac_build_alias=`$SHELL "$ac_aux_dir/config.guess"`
+test "x$ac_build_alias" = x &&
+  { { $as_echo "$as_me:$LINENO: error: cannot guess build type; you must specify one" >&5
+$as_echo "$as_me: error: cannot guess build type; you must specify one" >&2;}
+   { (exit 1); exit 1; }; }
+ac_cv_build=`$SHELL "$ac_aux_dir/config.sub" $ac_build_alias` ||
+  { { $as_echo "$as_me:$LINENO: error: $SHELL $ac_aux_dir/config.sub $ac_build_alias failed" >&5
+$as_echo "$as_me: error: $SHELL $ac_aux_dir/config.sub $ac_build_alias failed" >&2;}
+   { (exit 1); exit 1; }; }
+
+fi
+{ $as_echo "$as_me:$LINENO: result: $ac_cv_build" >&5
+$as_echo "$ac_cv_build" >&6; }
+case $ac_cv_build in
+*-*-*) ;;
+*) { { $as_echo "$as_me:$LINENO: error: invalid value of canonical build" >&5
+$as_echo "$as_me: error: invalid value of canonical build" >&2;}
+   { (exit 1); exit 1; }; };;
+esac
+build=$ac_cv_build
+ac_save_IFS=$IFS; IFS='-'
+set x $ac_cv_build
+shift
+build_cpu=$1
+build_vendor=$2
+shift; shift
+# Remember, the first character of IFS is used to create $*,
+# except with old shells:
+build_os=$*
+IFS=$ac_save_IFS
+case $build_os in *\ *) build_os=`echo "$build_os" | sed 's/ /-/g'`;; esac
+
+
+{ $as_echo "$as_me:$LINENO: checking host system type" >&5
+$as_echo_n "checking host system type... " >&6; }
+if test "${ac_cv_host+set}" = set; then
+  $as_echo_n "(cached) " >&6
+else
+  if test "x$host_alias" = x; then
+  ac_cv_host=$ac_cv_build
+else
+  ac_cv_host=`$SHELL "$ac_aux_dir/config.sub" $host_alias` ||
+    { { $as_echo "$as_me:$LINENO: error: $SHELL $ac_aux_dir/config.sub $host_alias failed" >&5
+$as_echo "$as_me: error: $SHELL $ac_aux_dir/config.sub $host_alias failed" >&2;}
+   { (exit 1); exit 1; }; }
+fi
+
+fi
+{ $as_echo "$as_me:$LINENO: result: $ac_cv_host" >&5
+$as_echo "$ac_cv_host" >&6; }
+case $ac_cv_host in
+*-*-*) ;;
+*) { { $as_echo "$as_me:$LINENO: error: invalid value of canonical host" >&5
+$as_echo "$as_me: error: invalid value of canonical host" >&2;}
+   { (exit 1); exit 1; }; };;
+esac
+host=$ac_cv_host
+ac_save_IFS=$IFS; IFS='-'
+set x $ac_cv_host
+shift
+host_cpu=$1
+host_vendor=$2
+shift; shift
+# Remember, the first character of IFS is used to create $*,
+# except with old shells:
+host_os=$*
+IFS=$ac_save_IFS
+case $host_os in *\ *) host_os=`echo "$host_os" | sed 's/ /-/g'`;; esac
+
+
+
+# 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
+{ $as_echo "$as_me:$LINENO: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if test "${ac_cv_prog_CC+set}" = set; then
+  $as_echo_n "(cached) " >&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 { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_prog_CC="${ac_tool_prefix}gcc"
+    $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+done
+IFS=$as_save_IFS
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+  { $as_echo "$as_me:$LINENO: result: $CC" >&5
+$as_echo "$CC" >&6; }
+else
+  { $as_echo "$as_me:$LINENO: result: no" >&5
+$as_echo "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
+{ $as_echo "$as_me:$LINENO: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if test "${ac_cv_prog_ac_ct_CC+set}" = set; then
+  $as_echo_n "(cached) " >&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 { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_prog_ac_ct_CC="gcc"
+    $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_CC=$ac_cv_prog_ac_ct_CC
+if test -n "$ac_ct_CC"; then
+  { $as_echo "$as_me:$LINENO: result: $ac_ct_CC" >&5
+$as_echo "$ac_ct_CC" >&6; }
+else
+  { $as_echo "$as_me:$LINENO: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+  if test "x$ac_ct_CC" = x; then
+    CC=""
+  else
+    case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:$LINENO: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+    CC=$ac_ct_CC
+  fi
+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
+{ $as_echo "$as_me:$LINENO: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if test "${ac_cv_prog_CC+set}" = set; then
+  $as_echo_n "(cached) " >&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 { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_prog_CC="${ac_tool_prefix}cc"
+    $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+done
+IFS=$as_save_IFS
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+  { $as_echo "$as_me:$LINENO: result: $CC" >&5
+$as_echo "$CC" >&6; }
+else
+  { $as_echo "$as_me:$LINENO: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+  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
+{ $as_echo "$as_me:$LINENO: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if test "${ac_cv_prog_CC+set}" = set; then
+  $as_echo_n "(cached) " >&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 { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$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"
+    $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+done
+IFS=$as_save_IFS
+
+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
+  { $as_echo "$as_me:$LINENO: result: $CC" >&5
+$as_echo "$CC" >&6; }
+else
+  { $as_echo "$as_me:$LINENO: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$CC"; then
+  if test -n "$ac_tool_prefix"; then
+  for ac_prog in cl.exe
+  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
+{ $as_echo "$as_me:$LINENO: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if test "${ac_cv_prog_CC+set}" = set; then
+  $as_echo_n "(cached) " >&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 { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_prog_CC="$ac_tool_prefix$ac_prog"
+    $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+done
+IFS=$as_save_IFS
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+  { $as_echo "$as_me:$LINENO: result: $CC" >&5
+$as_echo "$CC" >&6; }
+else
+  { $as_echo "$as_me:$LINENO: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+    test -n "$CC" && break
+  done
+fi
+if test -z "$CC"; then
+  ac_ct_CC=$CC
+  for ac_prog in cl.exe
+do
+  # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+{ $as_echo "$as_me:$LINENO: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if test "${ac_cv_prog_ac_ct_CC+set}" = set; then
+  $as_echo_n "(cached) " >&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 { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_prog_ac_ct_CC="$ac_prog"
+    $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_CC=$ac_cv_prog_ac_ct_CC
+if test -n "$ac_ct_CC"; then
+  { $as_echo "$as_me:$LINENO: result: $ac_ct_CC" >&5
+$as_echo "$ac_ct_CC" >&6; }
+else
+  { $as_echo "$as_me:$LINENO: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+  test -n "$ac_ct_CC" && break
+done
+
+  if test "x$ac_ct_CC" = x; then
+    CC=""
+  else
+    case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:$LINENO: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+    CC=$ac_ct_CC
+  fi
+fi
+
+fi
+
+
+test -z "$CC" && { { $as_echo "$as_me:$LINENO: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+{ { $as_echo "$as_me:$LINENO: error: no acceptable C compiler found in \$PATH
+See \`config.log' for more details." >&5
+$as_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.
+$as_echo "$as_me:$LINENO: checking for C compiler version" >&5
+set X $ac_compile
+ac_compiler=$2
+{ (ac_try="$ac_compiler --version >&5"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+  (eval "$ac_compiler --version >&5") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }
+{ (ac_try="$ac_compiler -v >&5"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+  (eval "$ac_compiler -v >&5") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }
+{ (ac_try="$ac_compiler -V >&5"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+  (eval "$ac_compiler -V >&5") 2>&5
+  ac_status=$?
+  $as_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.out.dSYM 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.
+{ $as_echo "$as_me:$LINENO: checking for C compiler default output file name" >&5
+$as_echo_n "checking for C compiler default output file name... " >&6; }
+ac_link_default=`$as_echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'`
+
+# The possible output files:
+ac_files="a.out conftest.exe conftest a.exe a_out.exe b.out conftest.*"
+
+ac_rmfiles=
+for ac_file in $ac_files
+do
+  case $ac_file in
+    *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;;
+    * ) ac_rmfiles="$ac_rmfiles $ac_file";;
+  esac
+done
+rm -f $ac_rmfiles
+
+if { (ac_try="$ac_link_default"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+  (eval "$ac_link_default") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; then
+  # Autoconf-2.13 could set the ac_cv_exeext variable to `no'.
+# So ignore a value of `no', otherwise this would lead to `EXEEXT = no'
+# in a Makefile.  We should not override ac_cv_exeext if it was cached,
+# so that the user can short-circuit this test for compilers unknown to
+# Autoconf.
+for ac_file in $ac_files ''
+do
+  test -f "$ac_file" || continue
+  case $ac_file in
+    *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj )
+       ;;
+    [ab].out )
+       # We found the default executable, but exeext='' is most
+       # certainly right.
+       break;;
+    *.* )
+        if test "${ac_cv_exeext+set}" = set && test "$ac_cv_exeext" != no;
+       then :; else
+          ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'`
+       fi
+       # We set ac_cv_exeext here because the later test for it is not
+       # safe: cross compilers may not add the suffix if given an `-o'
+       # argument, so we may need to know it at that point already.
+       # Even if this section looks crufty: it has the advantage of
+       # actually working.
+       break;;
+    * )
+       break;;
+  esac
+done
+test "$ac_cv_exeext" = no && ac_cv_exeext=
+
+else
+  ac_file=''
+fi
+
+{ $as_echo "$as_me:$LINENO: result: $ac_file" >&5
+$as_echo "$ac_file" >&6; }
+if test -z "$ac_file"; then
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+{ { $as_echo "$as_me:$LINENO: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+{ { $as_echo "$as_me:$LINENO: error: C compiler cannot create executables
+See \`config.log' for more details." >&5
+$as_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
+
+# Check that the compiler produces executables we can run.  If not, either
+# the compiler is broken, or we cross compile.
+{ $as_echo "$as_me:$LINENO: checking whether the C compiler works" >&5
+$as_echo_n "checking whether the C compiler works... " >&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'
+  { (case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+  (eval "$ac_try") 2>&5
+  ac_status=$?
+  $as_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
+       { { $as_echo "$as_me:$LINENO: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+{ { $as_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
+$as_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
+{ $as_echo "$as_me:$LINENO: result: yes" >&5
+$as_echo "yes" >&6; }
+
+rm -f -r a.out a.out.dSYM a.exe conftest$ac_cv_exeext b.out
+ac_clean_files=$ac_clean_files_save
+# Check that the compiler produces executables we can run.  If not, either
+# the compiler is broken, or we cross compile.
+{ $as_echo "$as_me:$LINENO: checking whether we are cross compiling" >&5
+$as_echo_n "checking whether we are cross compiling... " >&6; }
+{ $as_echo "$as_me:$LINENO: result: $cross_compiling" >&5
+$as_echo "$cross_compiling" >&6; }
+
+{ $as_echo "$as_me:$LINENO: checking for suffix of executables" >&5
+$as_echo_n "checking for suffix of executables... " >&6; }
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+  (eval "$ac_link") 2>&5
+  ac_status=$?
+  $as_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 | *.map | *.inf | *.dSYM | *.o | *.obj ) ;;
+    *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'`
+         break;;
+    * ) break;;
+  esac
+done
+else
+  { { $as_echo "$as_me:$LINENO: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+{ { $as_echo "$as_me:$LINENO: error: cannot compute suffix of executables: cannot compile and link
+See \`config.log' for more details." >&5
+$as_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
+{ $as_echo "$as_me:$LINENO: result: $ac_cv_exeext" >&5
+$as_echo "$ac_cv_exeext" >&6; }
+
+rm -f conftest.$ac_ext
+EXEEXT=$ac_cv_exeext
+ac_exeext=$EXEEXT
+{ $as_echo "$as_me:$LINENO: checking for suffix of object files" >&5
+$as_echo_n "checking for suffix of object files... " >&6; }
+if test "${ac_cv_objext+set}" = set; then
+  $as_echo_n "(cached) " >&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 { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+  (eval "$ac_compile") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; then
+  for ac_file in conftest.o conftest.obj conftest.*; do
+  test -f "$ac_file" || continue;
+  case $ac_file in
+    *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM ) ;;
+    *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'`
+       break;;
+  esac
+done
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+{ { $as_echo "$as_me:$LINENO: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+{ { $as_echo "$as_me:$LINENO: error: cannot compute suffix of object files: cannot compile
+See \`config.log' for more details." >&5
+$as_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
+{ $as_echo "$as_me:$LINENO: result: $ac_cv_objext" >&5
+$as_echo "$ac_cv_objext" >&6; }
+OBJEXT=$ac_cv_objext
+ac_objext=$OBJEXT
+{ $as_echo "$as_me:$LINENO: checking whether we are using the GNU C compiler" >&5
+$as_echo_n "checking whether we are using the GNU C compiler... " >&6; }
+if test "${ac_cv_c_compiler_gnu+set}" = set; then
+  $as_echo_n "(cached) " >&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 { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_compiler_gnu=yes
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_compiler_gnu=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ac_cv_c_compiler_gnu=$ac_compiler_gnu
+
+fi
+{ $as_echo "$as_me:$LINENO: result: $ac_cv_c_compiler_gnu" >&5
+$as_echo "$ac_cv_c_compiler_gnu" >&6; }
+if test $ac_compiler_gnu = yes; then
+  GCC=yes
+else
+  GCC=
+fi
+ac_test_CFLAGS=${CFLAGS+set}
+ac_save_CFLAGS=$CFLAGS
+{ $as_echo "$as_me:$LINENO: checking whether $CC accepts -g" >&5
+$as_echo_n "checking whether $CC accepts -g... " >&6; }
+if test "${ac_cv_prog_cc_g+set}" = set; then
+  $as_echo_n "(cached) " >&6
+else
+  ac_save_c_werror_flag=$ac_c_werror_flag
+   ac_c_werror_flag=yes
+   ac_cv_prog_cc_g=no
+   CFLAGS="-g"
+   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 { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_cv_prog_cc_g=yes
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       CFLAGS=""
+      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 { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  :
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_c_werror_flag=$ac_save_c_werror_flag
+        CFLAGS="-g"
+        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 { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_cv_prog_cc_g=yes
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+   ac_c_werror_flag=$ac_save_c_werror_flag
+fi
+{ $as_echo "$as_me:$LINENO: result: $ac_cv_prog_cc_g" >&5
+$as_echo "$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
+{ $as_echo "$as_me:$LINENO: checking for $CC option to accept ISO C89" >&5
+$as_echo_n "checking for $CC option to accept ISO C89... " >&6; }
+if test "${ac_cv_prog_cc_c89+set}" = set; then
+  $as_echo_n "(cached) " >&6
+else
+  ac_cv_prog_cc_c89=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 -std 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 -std.  */
+int osf4_cc_array ['\x00' == 0 ? 1 : -1];
+
+/* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters
+   inside strings and character constants.  */
+#define FOO(x) 'x'
+int xlc6_cc_array[FOO(a) == 'x' ? 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
+for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std \
+       -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__"
+do
+  CC="$ac_save_CC $ac_arg"
+  rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_cv_prog_cc_c89=$ac_arg
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+
+fi
+
+rm -f core conftest.err conftest.$ac_objext
+  test "x$ac_cv_prog_cc_c89" != "xno" && break
+done
+rm -f conftest.$ac_ext
+CC=$ac_save_CC
+
+fi
+# AC_CACHE_VAL
+case "x$ac_cv_prog_cc_c89" in
+  x)
+    { $as_echo "$as_me:$LINENO: result: none needed" >&5
+$as_echo "none needed" >&6; } ;;
+  xno)
+    { $as_echo "$as_me:$LINENO: result: unsupported" >&5
+$as_echo "unsupported" >&6; } ;;
+  *)
+    CC="$CC $ac_cv_prog_cc_c89"
+    { $as_echo "$as_me:$LINENO: result: $ac_cv_prog_cc_c89" >&5
+$as_echo "$ac_cv_prog_cc_c89" >&6; } ;;
+esac
+
+
+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
+{ $as_echo "$as_me:$LINENO: checking how to run the C preprocessor" >&5
+$as_echo_n "checking how to run the C preprocessor... " >&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
+  $as_echo_n "(cached) " >&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 { (ac_try="$ac_cpp conftest.$ac_ext"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&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
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } >/dev/null && {
+        test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       }; then
+  :
+else
+  $as_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 nonexistent 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 { (ac_try="$ac_cpp conftest.$ac_ext"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&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
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } >/dev/null && {
+        test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       }; then
+  # Broken: success on invalid input.
+continue
+else
+  $as_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
+{ $as_echo "$as_me:$LINENO: result: $CPP" >&5
+$as_echo "$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 { (ac_try="$ac_cpp conftest.$ac_ext"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&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
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } >/dev/null && {
+        test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       }; then
+  :
+else
+  $as_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 nonexistent 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 { (ac_try="$ac_cpp conftest.$ac_ext"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&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
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } >/dev/null && {
+        test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       }; then
+  # Broken: success on invalid input.
+continue
+else
+  $as_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
+  { { $as_echo "$as_me:$LINENO: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+{ { $as_echo "$as_me:$LINENO: error: C preprocessor \"$CPP\" fails sanity check
+See \`config.log' for more details." >&5
+$as_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
+
+
+{ $as_echo "$as_me:$LINENO: checking for grep that handles long lines and -e" >&5
+$as_echo_n "checking for grep that handles long lines and -e... " >&6; }
+if test "${ac_cv_path_GREP+set}" = set; then
+  $as_echo_n "(cached) " >&6
+else
+  if test -z "$GREP"; then
+  ac_path_GREP_found=false
+  # Loop through the user's path and test for each of PROGNAME-LIST
+  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for ac_prog in grep ggrep; do
+    for ac_exec_ext in '' $ac_executable_extensions; do
+      ac_path_GREP="$as_dir/$ac_prog$ac_exec_ext"
+      { test -f "$ac_path_GREP" && $as_test_x "$ac_path_GREP"; } || continue
+# Check for GNU ac_path_GREP and select it if it is found.
+  # Check for GNU $ac_path_GREP
+case `"$ac_path_GREP" --version 2>&1` in
+*GNU*)
+  ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_found=:;;
+*)
+  ac_count=0
+  $as_echo_n 0123456789 >"conftest.in"
+  while :
+  do
+    cat "conftest.in" "conftest.in" >"conftest.tmp"
+    mv "conftest.tmp" "conftest.in"
+    cp "conftest.in" "conftest.nl"
+    $as_echo 'GREP' >> "conftest.nl"
+    "$ac_path_GREP" -e 'GREP$' -e '-(cannot match)-' < "conftest.nl" >"conftest.out" 2>/dev/null || break
+    diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break
+    ac_count=`expr $ac_count + 1`
+    if test $ac_count -gt ${ac_path_GREP_max-0}; then
+      # Best one so far, save it but keep looking for a better one
+      ac_cv_path_GREP="$ac_path_GREP"
+      ac_path_GREP_max=$ac_count
+    fi
+    # 10*(2^10) chars as input seems more than enough
+    test $ac_count -gt 10 && break
+  done
+  rm -f conftest.in conftest.tmp conftest.nl conftest.out;;
+esac
+
+      $ac_path_GREP_found && break 3
+    done
+  done
+done
+IFS=$as_save_IFS
+  if test -z "$ac_cv_path_GREP"; then
+    { { $as_echo "$as_me:$LINENO: error: no acceptable grep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" >&5
+$as_echo "$as_me: error: no acceptable grep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" >&2;}
+   { (exit 1); exit 1; }; }
+  fi
+else
+  ac_cv_path_GREP=$GREP
+fi
+
+fi
+{ $as_echo "$as_me:$LINENO: result: $ac_cv_path_GREP" >&5
+$as_echo "$ac_cv_path_GREP" >&6; }
+ GREP="$ac_cv_path_GREP"
+
+
+{ $as_echo "$as_me:$LINENO: checking for egrep" >&5
+$as_echo_n "checking for egrep... " >&6; }
+if test "${ac_cv_path_EGREP+set}" = set; then
+  $as_echo_n "(cached) " >&6
+else
+  if echo a | $GREP -E '(a|b)' >/dev/null 2>&1
+   then ac_cv_path_EGREP="$GREP -E"
+   else
+     if test -z "$EGREP"; then
+  ac_path_EGREP_found=false
+  # Loop through the user's path and test for each of PROGNAME-LIST
+  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for ac_prog in egrep; do
+    for ac_exec_ext in '' $ac_executable_extensions; do
+      ac_path_EGREP="$as_dir/$ac_prog$ac_exec_ext"
+      { test -f "$ac_path_EGREP" && $as_test_x "$ac_path_EGREP"; } || continue
+# Check for GNU ac_path_EGREP and select it if it is found.
+  # Check for GNU $ac_path_EGREP
+case `"$ac_path_EGREP" --version 2>&1` in
+*GNU*)
+  ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_found=:;;
+*)
+  ac_count=0
+  $as_echo_n 0123456789 >"conftest.in"
+  while :
+  do
+    cat "conftest.in" "conftest.in" >"conftest.tmp"
+    mv "conftest.tmp" "conftest.in"
+    cp "conftest.in" "conftest.nl"
+    $as_echo 'EGREP' >> "conftest.nl"
+    "$ac_path_EGREP" 'EGREP$' < "conftest.nl" >"conftest.out" 2>/dev/null || break
+    diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break
+    ac_count=`expr $ac_count + 1`
+    if test $ac_count -gt ${ac_path_EGREP_max-0}; then
+      # Best one so far, save it but keep looking for a better one
+      ac_cv_path_EGREP="$ac_path_EGREP"
+      ac_path_EGREP_max=$ac_count
+    fi
+    # 10*(2^10) chars as input seems more than enough
+    test $ac_count -gt 10 && break
+  done
+  rm -f conftest.in conftest.tmp conftest.nl conftest.out;;
+esac
+
+      $ac_path_EGREP_found && break 3
+    done
+  done
+done
+IFS=$as_save_IFS
+  if test -z "$ac_cv_path_EGREP"; then
+    { { $as_echo "$as_me:$LINENO: error: no acceptable egrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" >&5
+$as_echo "$as_me: error: no acceptable egrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" >&2;}
+   { (exit 1); exit 1; }; }
+  fi
+else
+  ac_cv_path_EGREP=$EGREP
+fi
+
+   fi
+fi
+{ $as_echo "$as_me:$LINENO: result: $ac_cv_path_EGREP" >&5
+$as_echo "$ac_cv_path_EGREP" >&6; }
+ EGREP="$ac_cv_path_EGREP"
+
+
+{ $as_echo "$as_me:$LINENO: checking for ANSI C header files" >&5
+$as_echo_n "checking for ANSI C header files... " >&6; }
+if test "${ac_cv_header_stdc+set}" = set; then
+  $as_echo_n "(cached) " >&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 { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_cv_header_stdc=yes
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_cv_header_stdc=no
+fi
+
+rm -f core 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>
+#include <stdlib.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))
+      return 2;
+  return 0;
+}
+_ACEOF
+rm -f conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+  (eval "$ac_link") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && { ac_try='./conftest$ac_exeext'
+  { (case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+  (eval "$ac_try") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  :
+else
+  $as_echo "$as_me: program exited with status $ac_status" >&5
+$as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+( exit $ac_status )
+ac_cv_header_stdc=no
+fi
+rm -rf conftest.dSYM
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext
+fi
+
+
+fi
+fi
+{ $as_echo "$as_me:$LINENO: result: $ac_cv_header_stdc" >&5
+$as_echo "$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=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
+{ $as_echo "$as_me:$LINENO: checking for $ac_header" >&5
+$as_echo_n "checking for $ac_header... " >&6; }
+if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
+  $as_echo_n "(cached) " >&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 { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  eval "$as_ac_Header=yes"
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       eval "$as_ac_Header=no"
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+ac_res=`eval 'as_val=${'$as_ac_Header'}
+                $as_echo "$as_val"'`
+              { $as_echo "$as_me:$LINENO: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+as_val=`eval 'as_val=${'$as_ac_Header'}
+                $as_echo "$as_val"'`
+   if test "x$as_val" = x""yes; then
+  cat >>confdefs.h <<_ACEOF
+#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+
+done
+
+
+# The cast to long int 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.
+{ $as_echo "$as_me:$LINENO: checking size of long" >&5
+$as_echo_n "checking size of long... " >&6; }
+if test "${ac_cv_sizeof_long+set}" = set; then
+  $as_echo_n "(cached) " >&6
+else
+  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 int) (sizeof (long))) >= 0)];
+test_array [0] = 0
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; 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 int) (sizeof (long))) <= $ac_mid)];
+test_array [0] = 0
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_hi=$ac_mid; break
+else
+  $as_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 core conftest.err conftest.$ac_objext conftest.$ac_ext
+  done
+else
+  $as_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 int) (sizeof (long))) < 0)];
+test_array [0] = 0
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; 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 int) (sizeof (long))) >= $ac_mid)];
+test_array [0] = 0
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_lo=$ac_mid; break
+else
+  $as_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 core conftest.err conftest.$ac_objext conftest.$ac_ext
+  done
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_lo= ac_hi=
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+
+rm -f core 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 int) (sizeof (long))) <= $ac_mid)];
+test_array [0] = 0
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_hi=$ac_mid
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_lo=`expr '(' $ac_mid ')' + 1`
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+done
+case $ac_lo in
+?*) ac_cv_sizeof_long=$ac_lo;;
+'') if test "$ac_cv_type_long" = yes; then
+     { { $as_echo "$as_me:$LINENO: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+{ { $as_echo "$as_me:$LINENO: error: cannot compute sizeof (long)
+See \`config.log' for more details." >&5
+$as_echo "$as_me: error: cannot compute sizeof (long)
+See \`config.log' for more details." >&2;}
+   { (exit 77); exit 77; }; }; }
+   else
+     ac_cv_sizeof_long=0
+   fi ;;
+esac
+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
+static long int longval () { return (long int) (sizeof (long)); }
+static unsigned long int ulongval () { return (long int) (sizeof (long)); }
+#include <stdio.h>
+#include <stdlib.h>
+int
+main ()
+{
+
+  FILE *f = fopen ("conftest.val", "w");
+  if (! f)
+    return 1;
+  if (((long int) (sizeof (long))) < 0)
+    {
+      long int i = longval ();
+      if (i != ((long int) (sizeof (long))))
+       return 1;
+      fprintf (f, "%ld", i);
+    }
+  else
+    {
+      unsigned long int i = ulongval ();
+      if (i != ((long int) (sizeof (long))))
+       return 1;
+      fprintf (f, "%lu", i);
+    }
+  /* Do not output a trailing newline, as this causes \r\n confusion
+     on some platforms.  */
+  return ferror (f) || fclose (f) != 0;
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+  (eval "$ac_link") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && { ac_try='./conftest$ac_exeext'
+  { (case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+  (eval "$ac_try") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  ac_cv_sizeof_long=`cat conftest.val`
+else
+  $as_echo "$as_me: program exited with status $ac_status" >&5
+$as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+( exit $ac_status )
+if test "$ac_cv_type_long" = yes; then
+     { { $as_echo "$as_me:$LINENO: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+{ { $as_echo "$as_me:$LINENO: error: cannot compute sizeof (long)
+See \`config.log' for more details." >&5
+$as_echo "$as_me: error: cannot compute sizeof (long)
+See \`config.log' for more details." >&2;}
+   { (exit 77); exit 77; }; }; }
+   else
+     ac_cv_sizeof_long=0
+   fi
+fi
+rm -rf conftest.dSYM
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext
+fi
+rm -f conftest.val
+fi
+{ $as_echo "$as_me:$LINENO: result: $ac_cv_sizeof_long" >&5
+$as_echo "$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
+{ $as_echo "$as_me:$LINENO: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if test "${ac_cv_prog_RANLIB+set}" = set; then
+  $as_echo_n "(cached) " >&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 { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_prog_RANLIB="${ac_tool_prefix}ranlib"
+    $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+done
+IFS=$as_save_IFS
+
+fi
+fi
+RANLIB=$ac_cv_prog_RANLIB
+if test -n "$RANLIB"; then
+  { $as_echo "$as_me:$LINENO: result: $RANLIB" >&5
+$as_echo "$RANLIB" >&6; }
+else
+  { $as_echo "$as_me:$LINENO: result: no" >&5
+$as_echo "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
+{ $as_echo "$as_me:$LINENO: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if test "${ac_cv_prog_ac_ct_RANLIB+set}" = set; then
+  $as_echo_n "(cached) " >&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 { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_prog_ac_ct_RANLIB="ranlib"
+    $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_RANLIB=$ac_cv_prog_ac_ct_RANLIB
+if test -n "$ac_ct_RANLIB"; then
+  { $as_echo "$as_me:$LINENO: result: $ac_ct_RANLIB" >&5
+$as_echo "$ac_ct_RANLIB" >&6; }
+else
+  { $as_echo "$as_me:$LINENO: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+  if test "x$ac_ct_RANLIB" = x; then
+    RANLIB=":"
+  else
+    case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:$LINENO: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+    RANLIB=$ac_ct_RANLIB
+  fi
+else
+  RANLIB="$ac_cv_prog_RANLIB"
+fi
+
+
+{ $as_echo "$as_me:$LINENO: checking for ANSI C header files" >&5
+$as_echo_n "checking for ANSI C header files... " >&6; }
+if test "${ac_cv_header_stdc+set}" = set; then
+  $as_echo_n "(cached) " >&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 { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_cv_header_stdc=yes
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_cv_header_stdc=no
+fi
+
+rm -f core 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>
+#include <stdlib.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))
+      return 2;
+  return 0;
+}
+_ACEOF
+rm -f conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+  (eval "$ac_link") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && { ac_try='./conftest$ac_exeext'
+  { (case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+  (eval "$ac_try") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  :
+else
+  $as_echo "$as_me: program exited with status $ac_status" >&5
+$as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+( exit $ac_status )
+ac_cv_header_stdc=no
+fi
+rm -rf conftest.dSYM
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext
+fi
+
+
+fi
+fi
+{ $as_echo "$as_me:$LINENO: result: $ac_cv_header_stdc" >&5
+$as_echo "$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=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
+if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
+  { $as_echo "$as_me:$LINENO: checking for $ac_header" >&5
+$as_echo_n "checking for $ac_header... " >&6; }
+if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
+  $as_echo_n "(cached) " >&6
+fi
+ac_res=`eval 'as_val=${'$as_ac_Header'}
+                $as_echo "$as_val"'`
+              { $as_echo "$as_me:$LINENO: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+else
+  # Is the header compilable?
+{ $as_echo "$as_me:$LINENO: checking $ac_header usability" >&5
+$as_echo_n "checking $ac_header usability... " >&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 { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_header_compiler=yes
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_header_compiler=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+{ $as_echo "$as_me:$LINENO: result: $ac_header_compiler" >&5
+$as_echo "$ac_header_compiler" >&6; }
+
+# Is the header present?
+{ $as_echo "$as_me:$LINENO: checking $ac_header presence" >&5
+$as_echo_n "checking $ac_header presence... " >&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 { (ac_try="$ac_cpp conftest.$ac_ext"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&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
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } >/dev/null && {
+        test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       }; then
+  ac_header_preproc=yes
+else
+  $as_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
+{ $as_echo "$as_me:$LINENO: result: $ac_header_preproc" >&5
+$as_echo "$ac_header_preproc" >&6; }
+
+# So?  What about this header?
+case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in
+  yes:no: )
+    { $as_echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5
+$as_echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;}
+    { $as_echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5
+$as_echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;}
+    ac_header_preproc=yes
+    ;;
+  no:yes:* )
+    { $as_echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5
+$as_echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;}
+    { $as_echo "$as_me:$LINENO: WARNING: $ac_header:     check for missing prerequisite headers?" >&5
+$as_echo "$as_me: WARNING: $ac_header:     check for missing prerequisite headers?" >&2;}
+    { $as_echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5
+$as_echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;}
+    { $as_echo "$as_me:$LINENO: WARNING: $ac_header:     section \"Present But Cannot Be Compiled\"" >&5
+$as_echo "$as_me: WARNING: $ac_header:     section \"Present But Cannot Be Compiled\"" >&2;}
+    { $as_echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5
+$as_echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;}
+    { $as_echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5
+$as_echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;}
+    ( cat <<\_ASBOX
+## ------------------------------------ ##
+## Report this to saord@cfa.harvard.edu ##
+## ------------------------------------ ##
+_ASBOX
+     ) | sed "s/^/$as_me: WARNING:     /" >&2
+    ;;
+esac
+{ $as_echo "$as_me:$LINENO: checking for $ac_header" >&5
+$as_echo_n "checking for $ac_header... " >&6; }
+if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
+  $as_echo_n "(cached) " >&6
+else
+  eval "$as_ac_Header=\$ac_header_preproc"
+fi
+ac_res=`eval 'as_val=${'$as_ac_Header'}
+                $as_echo "$as_val"'`
+              { $as_echo "$as_me:$LINENO: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+
+fi
+as_val=`eval 'as_val=${'$as_ac_Header'}
+                $as_echo "$as_val"'`
+   if test "x$as_val" = x""yes; then
+  cat >>confdefs.h <<_ACEOF
+#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+
+done
+
+
+for ac_header in getopt.h
+do
+as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
+if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
+  { $as_echo "$as_me:$LINENO: checking for $ac_header" >&5
+$as_echo_n "checking for $ac_header... " >&6; }
+if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
+  $as_echo_n "(cached) " >&6
+fi
+ac_res=`eval 'as_val=${'$as_ac_Header'}
+                $as_echo "$as_val"'`
+              { $as_echo "$as_me:$LINENO: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+else
+  # Is the header compilable?
+{ $as_echo "$as_me:$LINENO: checking $ac_header usability" >&5
+$as_echo_n "checking $ac_header usability... " >&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 { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_header_compiler=yes
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_header_compiler=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+{ $as_echo "$as_me:$LINENO: result: $ac_header_compiler" >&5
+$as_echo "$ac_header_compiler" >&6; }
+
+# Is the header present?
+{ $as_echo "$as_me:$LINENO: checking $ac_header presence" >&5
+$as_echo_n "checking $ac_header presence... " >&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 { (ac_try="$ac_cpp conftest.$ac_ext"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&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
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } >/dev/null && {
+        test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       }; then
+  ac_header_preproc=yes
+else
+  $as_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
+{ $as_echo "$as_me:$LINENO: result: $ac_header_preproc" >&5
+$as_echo "$ac_header_preproc" >&6; }
+
+# So?  What about this header?
+case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in
+  yes:no: )
+    { $as_echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5
+$as_echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;}
+    { $as_echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5
+$as_echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;}
+    ac_header_preproc=yes
+    ;;
+  no:yes:* )
+    { $as_echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5
+$as_echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;}
+    { $as_echo "$as_me:$LINENO: WARNING: $ac_header:     check for missing prerequisite headers?" >&5
+$as_echo "$as_me: WARNING: $ac_header:     check for missing prerequisite headers?" >&2;}
+    { $as_echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5
+$as_echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;}
+    { $as_echo "$as_me:$LINENO: WARNING: $ac_header:     section \"Present But Cannot Be Compiled\"" >&5
+$as_echo "$as_me: WARNING: $ac_header:     section \"Present But Cannot Be Compiled\"" >&2;}
+    { $as_echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5
+$as_echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;}
+    { $as_echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5
+$as_echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;}
+    ( cat <<\_ASBOX
+## ------------------------------------ ##
+## Report this to saord@cfa.harvard.edu ##
+## ------------------------------------ ##
+_ASBOX
+     ) | sed "s/^/$as_me: WARNING:     /" >&2
+    ;;
+esac
+{ $as_echo "$as_me:$LINENO: checking for $ac_header" >&5
+$as_echo_n "checking for $ac_header... " >&6; }
+if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
+  $as_echo_n "(cached) " >&6
+else
+  eval "$as_ac_Header=\$ac_header_preproc"
+fi
+ac_res=`eval 'as_val=${'$as_ac_Header'}
+                $as_echo "$as_val"'`
+              { $as_echo "$as_me:$LINENO: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+
+fi
+as_val=`eval 'as_val=${'$as_ac_Header'}
+                $as_echo "$as_val"'`
+   if test "x$as_val" = x""yes; then
+  cat >>confdefs.h <<_ACEOF
+#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+
+done
+
+
+for ac_header in pwd.h
+do
+as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
+if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
+  { $as_echo "$as_me:$LINENO: checking for $ac_header" >&5
+$as_echo_n "checking for $ac_header... " >&6; }
+if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
+  $as_echo_n "(cached) " >&6
+fi
+ac_res=`eval 'as_val=${'$as_ac_Header'}
+                $as_echo "$as_val"'`
+              { $as_echo "$as_me:$LINENO: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+else
+  # Is the header compilable?
+{ $as_echo "$as_me:$LINENO: checking $ac_header usability" >&5
+$as_echo_n "checking $ac_header usability... " >&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 { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_header_compiler=yes
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_header_compiler=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+{ $as_echo "$as_me:$LINENO: result: $ac_header_compiler" >&5
+$as_echo "$ac_header_compiler" >&6; }
+
+# Is the header present?
+{ $as_echo "$as_me:$LINENO: checking $ac_header presence" >&5
+$as_echo_n "checking $ac_header presence... " >&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 { (ac_try="$ac_cpp conftest.$ac_ext"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&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
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } >/dev/null && {
+        test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       }; then
+  ac_header_preproc=yes
+else
+  $as_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
+{ $as_echo "$as_me:$LINENO: result: $ac_header_preproc" >&5
+$as_echo "$ac_header_preproc" >&6; }
+
+# So?  What about this header?
+case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in
+  yes:no: )
+    { $as_echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5
+$as_echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;}
+    { $as_echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5
+$as_echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;}
+    ac_header_preproc=yes
+    ;;
+  no:yes:* )
+    { $as_echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5
+$as_echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;}
+    { $as_echo "$as_me:$LINENO: WARNING: $ac_header:     check for missing prerequisite headers?" >&5
+$as_echo "$as_me: WARNING: $ac_header:     check for missing prerequisite headers?" >&2;}
+    { $as_echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5
+$as_echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;}
+    { $as_echo "$as_me:$LINENO: WARNING: $ac_header:     section \"Present But Cannot Be Compiled\"" >&5
+$as_echo "$as_me: WARNING: $ac_header:     section \"Present But Cannot Be Compiled\"" >&2;}
+    { $as_echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5
+$as_echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;}
+    { $as_echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5
+$as_echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;}
+    ( cat <<\_ASBOX
+## ------------------------------------ ##
+## Report this to saord@cfa.harvard.edu ##
+## ------------------------------------ ##
+_ASBOX
+     ) | sed "s/^/$as_me: WARNING:     /" >&2
+    ;;
+esac
+{ $as_echo "$as_me:$LINENO: checking for $ac_header" >&5
+$as_echo_n "checking for $ac_header... " >&6; }
+if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
+  $as_echo_n "(cached) " >&6
+else
+  eval "$as_ac_Header=\$ac_header_preproc"
+fi
+ac_res=`eval 'as_val=${'$as_ac_Header'}
+                $as_echo "$as_val"'`
+              { $as_echo "$as_me:$LINENO: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+
+fi
+as_val=`eval 'as_val=${'$as_ac_Header'}
+                $as_echo "$as_val"'`
+   if test "x$as_val" = x""yes; then
+  cat >>confdefs.h <<_ACEOF
+#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+
+done
+
+
+for ac_header in values.h
+do
+as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
+if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
+  { $as_echo "$as_me:$LINENO: checking for $ac_header" >&5
+$as_echo_n "checking for $ac_header... " >&6; }
+if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
+  $as_echo_n "(cached) " >&6
+fi
+ac_res=`eval 'as_val=${'$as_ac_Header'}
+                $as_echo "$as_val"'`
+              { $as_echo "$as_me:$LINENO: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+else
+  # Is the header compilable?
+{ $as_echo "$as_me:$LINENO: checking $ac_header usability" >&5
+$as_echo_n "checking $ac_header usability... " >&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 { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_header_compiler=yes
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_header_compiler=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+{ $as_echo "$as_me:$LINENO: result: $ac_header_compiler" >&5
+$as_echo "$ac_header_compiler" >&6; }
+
+# Is the header present?
+{ $as_echo "$as_me:$LINENO: checking $ac_header presence" >&5
+$as_echo_n "checking $ac_header presence... " >&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 { (ac_try="$ac_cpp conftest.$ac_ext"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&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
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } >/dev/null && {
+        test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       }; then
+  ac_header_preproc=yes
+else
+  $as_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
+{ $as_echo "$as_me:$LINENO: result: $ac_header_preproc" >&5
+$as_echo "$ac_header_preproc" >&6; }
+
+# So?  What about this header?
+case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in
+  yes:no: )
+    { $as_echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5
+$as_echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;}
+    { $as_echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5
+$as_echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;}
+    ac_header_preproc=yes
+    ;;
+  no:yes:* )
+    { $as_echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5
+$as_echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;}
+    { $as_echo "$as_me:$LINENO: WARNING: $ac_header:     check for missing prerequisite headers?" >&5
+$as_echo "$as_me: WARNING: $ac_header:     check for missing prerequisite headers?" >&2;}
+    { $as_echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5
+$as_echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;}
+    { $as_echo "$as_me:$LINENO: WARNING: $ac_header:     section \"Present But Cannot Be Compiled\"" >&5
+$as_echo "$as_me: WARNING: $ac_header:     section \"Present But Cannot Be Compiled\"" >&2;}
+    { $as_echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5
+$as_echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;}
+    { $as_echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5
+$as_echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;}
+    ( cat <<\_ASBOX
+## ------------------------------------ ##
+## Report this to saord@cfa.harvard.edu ##
+## ------------------------------------ ##
+_ASBOX
+     ) | sed "s/^/$as_me: WARNING:     /" >&2
+    ;;
+esac
+{ $as_echo "$as_me:$LINENO: checking for $ac_header" >&5
+$as_echo_n "checking for $ac_header... " >&6; }
+if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
+  $as_echo_n "(cached) " >&6
+else
+  eval "$as_ac_Header=\$ac_header_preproc"
+fi
+ac_res=`eval 'as_val=${'$as_ac_Header'}
+                $as_echo "$as_val"'`
+              { $as_echo "$as_me:$LINENO: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+
+fi
+as_val=`eval 'as_val=${'$as_ac_Header'}
+                $as_echo "$as_val"'`
+   if test "x$as_val" = x""yes; then
+  cat >>confdefs.h <<_ACEOF
+#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+
+done
+
+
+for ac_header in dlfcn.h
+do
+as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
+if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
+  { $as_echo "$as_me:$LINENO: checking for $ac_header" >&5
+$as_echo_n "checking for $ac_header... " >&6; }
+if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
+  $as_echo_n "(cached) " >&6
+fi
+ac_res=`eval 'as_val=${'$as_ac_Header'}
+                $as_echo "$as_val"'`
+              { $as_echo "$as_me:$LINENO: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+else
+  # Is the header compilable?
+{ $as_echo "$as_me:$LINENO: checking $ac_header usability" >&5
+$as_echo_n "checking $ac_header usability... " >&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 { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_header_compiler=yes
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_header_compiler=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+{ $as_echo "$as_me:$LINENO: result: $ac_header_compiler" >&5
+$as_echo "$ac_header_compiler" >&6; }
+
+# Is the header present?
+{ $as_echo "$as_me:$LINENO: checking $ac_header presence" >&5
+$as_echo_n "checking $ac_header presence... " >&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 { (ac_try="$ac_cpp conftest.$ac_ext"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&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
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } >/dev/null && {
+        test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       }; then
+  ac_header_preproc=yes
+else
+  $as_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
+{ $as_echo "$as_me:$LINENO: result: $ac_header_preproc" >&5
+$as_echo "$ac_header_preproc" >&6; }
+
+# So?  What about this header?
+case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in
+  yes:no: )
+    { $as_echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5
+$as_echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;}
+    { $as_echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5
+$as_echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;}
+    ac_header_preproc=yes
+    ;;
+  no:yes:* )
+    { $as_echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5
+$as_echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;}
+    { $as_echo "$as_me:$LINENO: WARNING: $ac_header:     check for missing prerequisite headers?" >&5
+$as_echo "$as_me: WARNING: $ac_header:     check for missing prerequisite headers?" >&2;}
+    { $as_echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5
+$as_echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;}
+    { $as_echo "$as_me:$LINENO: WARNING: $ac_header:     section \"Present But Cannot Be Compiled\"" >&5
+$as_echo "$as_me: WARNING: $ac_header:     section \"Present But Cannot Be Compiled\"" >&2;}
+    { $as_echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5
+$as_echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;}
+    { $as_echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5
+$as_echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;}
+    ( cat <<\_ASBOX
+## ------------------------------------ ##
+## Report this to saord@cfa.harvard.edu ##
+## ------------------------------------ ##
+_ASBOX
+     ) | sed "s/^/$as_me: WARNING:     /" >&2
+    ;;
+esac
+{ $as_echo "$as_me:$LINENO: checking for $ac_header" >&5
+$as_echo_n "checking for $ac_header... " >&6; }
+if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
+  $as_echo_n "(cached) " >&6
+else
+  eval "$as_ac_Header=\$ac_header_preproc"
+fi
+ac_res=`eval 'as_val=${'$as_ac_Header'}
+                $as_echo "$as_val"'`
+              { $as_echo "$as_me:$LINENO: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+
+fi
+as_val=`eval 'as_val=${'$as_ac_Header'}
+                $as_echo "$as_val"'`
+   if test "x$as_val" = x""yes; then
+  cat >>confdefs.h <<_ACEOF
+#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+
+done
+
+
+for ac_header in setjmp.h
+do
+as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
+if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
+  { $as_echo "$as_me:$LINENO: checking for $ac_header" >&5
+$as_echo_n "checking for $ac_header... " >&6; }
+if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
+  $as_echo_n "(cached) " >&6
+fi
+ac_res=`eval 'as_val=${'$as_ac_Header'}
+                $as_echo "$as_val"'`
+              { $as_echo "$as_me:$LINENO: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+else
+  # Is the header compilable?
+{ $as_echo "$as_me:$LINENO: checking $ac_header usability" >&5
+$as_echo_n "checking $ac_header usability... " >&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 { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_header_compiler=yes
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_header_compiler=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+{ $as_echo "$as_me:$LINENO: result: $ac_header_compiler" >&5
+$as_echo "$ac_header_compiler" >&6; }
+
+# Is the header present?
+{ $as_echo "$as_me:$LINENO: checking $ac_header presence" >&5
+$as_echo_n "checking $ac_header presence... " >&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 { (ac_try="$ac_cpp conftest.$ac_ext"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&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
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } >/dev/null && {
+        test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       }; then
+  ac_header_preproc=yes
+else
+  $as_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
+{ $as_echo "$as_me:$LINENO: result: $ac_header_preproc" >&5
+$as_echo "$ac_header_preproc" >&6; }
+
+# So?  What about this header?
+case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in
+  yes:no: )
+    { $as_echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5
+$as_echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;}
+    { $as_echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5
+$as_echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;}
+    ac_header_preproc=yes
+    ;;
+  no:yes:* )
+    { $as_echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5
+$as_echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;}
+    { $as_echo "$as_me:$LINENO: WARNING: $ac_header:     check for missing prerequisite headers?" >&5
+$as_echo "$as_me: WARNING: $ac_header:     check for missing prerequisite headers?" >&2;}
+    { $as_echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5
+$as_echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;}
+    { $as_echo "$as_me:$LINENO: WARNING: $ac_header:     section \"Present But Cannot Be Compiled\"" >&5
+$as_echo "$as_me: WARNING: $ac_header:     section \"Present But Cannot Be Compiled\"" >&2;}
+    { $as_echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5
+$as_echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;}
+    { $as_echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5
+$as_echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;}
+    ( cat <<\_ASBOX
+## ------------------------------------ ##
+## Report this to saord@cfa.harvard.edu ##
+## ------------------------------------ ##
+_ASBOX
+     ) | sed "s/^/$as_me: WARNING:     /" >&2
+    ;;
+esac
+{ $as_echo "$as_me:$LINENO: checking for $ac_header" >&5
+$as_echo_n "checking for $ac_header... " >&6; }
+if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
+  $as_echo_n "(cached) " >&6
+else
+  eval "$as_ac_Header=\$ac_header_preproc"
+fi
+ac_res=`eval 'as_val=${'$as_ac_Header'}
+                $as_echo "$as_val"'`
+              { $as_echo "$as_me:$LINENO: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+
+fi
+as_val=`eval 'as_val=${'$as_ac_Header'}
+                $as_echo "$as_val"'`
+   if test "x$as_val" = x""yes; then
+  cat >>confdefs.h <<_ACEOF
+#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+
+done
+
+
+for ac_header in sys/un.h
+do
+as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
+if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
+  { $as_echo "$as_me:$LINENO: checking for $ac_header" >&5
+$as_echo_n "checking for $ac_header... " >&6; }
+if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
+  $as_echo_n "(cached) " >&6
+fi
+ac_res=`eval 'as_val=${'$as_ac_Header'}
+                $as_echo "$as_val"'`
+              { $as_echo "$as_me:$LINENO: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+else
+  # Is the header compilable?
+{ $as_echo "$as_me:$LINENO: checking $ac_header usability" >&5
+$as_echo_n "checking $ac_header usability... " >&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 { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_header_compiler=yes
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_header_compiler=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+{ $as_echo "$as_me:$LINENO: result: $ac_header_compiler" >&5
+$as_echo "$ac_header_compiler" >&6; }
+
+# Is the header present?
+{ $as_echo "$as_me:$LINENO: checking $ac_header presence" >&5
+$as_echo_n "checking $ac_header presence... " >&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 { (ac_try="$ac_cpp conftest.$ac_ext"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&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
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } >/dev/null && {
+        test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       }; then
+  ac_header_preproc=yes
+else
+  $as_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
+{ $as_echo "$as_me:$LINENO: result: $ac_header_preproc" >&5
+$as_echo "$ac_header_preproc" >&6; }
+
+# So?  What about this header?
+case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in
+  yes:no: )
+    { $as_echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5
+$as_echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;}
+    { $as_echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5
+$as_echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;}
+    ac_header_preproc=yes
+    ;;
+  no:yes:* )
+    { $as_echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5
+$as_echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;}
+    { $as_echo "$as_me:$LINENO: WARNING: $ac_header:     check for missing prerequisite headers?" >&5
+$as_echo "$as_me: WARNING: $ac_header:     check for missing prerequisite headers?" >&2;}
+    { $as_echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5
+$as_echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;}
+    { $as_echo "$as_me:$LINENO: WARNING: $ac_header:     section \"Present But Cannot Be Compiled\"" >&5
+$as_echo "$as_me: WARNING: $ac_header:     section \"Present But Cannot Be Compiled\"" >&2;}
+    { $as_echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5
+$as_echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;}
+    { $as_echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5
+$as_echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;}
+    ( cat <<\_ASBOX
+## ------------------------------------ ##
+## Report this to saord@cfa.harvard.edu ##
+## ------------------------------------ ##
+_ASBOX
+     ) | sed "s/^/$as_me: WARNING:     /" >&2
+    ;;
+esac
+{ $as_echo "$as_me:$LINENO: checking for $ac_header" >&5
+$as_echo_n "checking for $ac_header... " >&6; }
+if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
+  $as_echo_n "(cached) " >&6
+else
+  eval "$as_ac_Header=\$ac_header_preproc"
+fi
+ac_res=`eval 'as_val=${'$as_ac_Header'}
+                $as_echo "$as_val"'`
+              { $as_echo "$as_me:$LINENO: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+
+fi
+as_val=`eval 'as_val=${'$as_ac_Header'}
+                $as_echo "$as_val"'`
+   if test "x$as_val" = x""yes; then
+  cat >>confdefs.h <<_ACEOF
+#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+
+done
+
+
+for ac_header in sys/shm.h
+do
+as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
+if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
+  { $as_echo "$as_me:$LINENO: checking for $ac_header" >&5
+$as_echo_n "checking for $ac_header... " >&6; }
+if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
+  $as_echo_n "(cached) " >&6
+fi
+ac_res=`eval 'as_val=${'$as_ac_Header'}
+                $as_echo "$as_val"'`
+              { $as_echo "$as_me:$LINENO: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+else
+  # Is the header compilable?
+{ $as_echo "$as_me:$LINENO: checking $ac_header usability" >&5
+$as_echo_n "checking $ac_header usability... " >&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 { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_header_compiler=yes
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_header_compiler=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+{ $as_echo "$as_me:$LINENO: result: $ac_header_compiler" >&5
+$as_echo "$ac_header_compiler" >&6; }
+
+# Is the header present?
+{ $as_echo "$as_me:$LINENO: checking $ac_header presence" >&5
+$as_echo_n "checking $ac_header presence... " >&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 { (ac_try="$ac_cpp conftest.$ac_ext"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&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
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } >/dev/null && {
+        test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       }; then
+  ac_header_preproc=yes
+else
+  $as_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
+{ $as_echo "$as_me:$LINENO: result: $ac_header_preproc" >&5
+$as_echo "$ac_header_preproc" >&6; }
+
+# So?  What about this header?
+case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in
+  yes:no: )
+    { $as_echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5
+$as_echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;}
+    { $as_echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5
+$as_echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;}
+    ac_header_preproc=yes
+    ;;
+  no:yes:* )
+    { $as_echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5
+$as_echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;}
+    { $as_echo "$as_me:$LINENO: WARNING: $ac_header:     check for missing prerequisite headers?" >&5
+$as_echo "$as_me: WARNING: $ac_header:     check for missing prerequisite headers?" >&2;}
+    { $as_echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5
+$as_echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;}
+    { $as_echo "$as_me:$LINENO: WARNING: $ac_header:     section \"Present But Cannot Be Compiled\"" >&5
+$as_echo "$as_me: WARNING: $ac_header:     section \"Present But Cannot Be Compiled\"" >&2;}
+    { $as_echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5
+$as_echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;}
+    { $as_echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5
+$as_echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;}
+    ( cat <<\_ASBOX
+## ------------------------------------ ##
+## Report this to saord@cfa.harvard.edu ##
+## ------------------------------------ ##
+_ASBOX
+     ) | sed "s/^/$as_me: WARNING:     /" >&2
+    ;;
+esac
+{ $as_echo "$as_me:$LINENO: checking for $ac_header" >&5
+$as_echo_n "checking for $ac_header... " >&6; }
+if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
+  $as_echo_n "(cached) " >&6
+else
+  eval "$as_ac_Header=\$ac_header_preproc"
+fi
+ac_res=`eval 'as_val=${'$as_ac_Header'}
+                $as_echo "$as_val"'`
+              { $as_echo "$as_me:$LINENO: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+
+fi
+as_val=`eval 'as_val=${'$as_ac_Header'}
+                $as_echo "$as_val"'`
+   if test "x$as_val" = x""yes; then
+  cat >>confdefs.h <<_ACEOF
+#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+
+done
+
+
+for ac_header in sys/mman.h
+do
+as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
+if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
+  { $as_echo "$as_me:$LINENO: checking for $ac_header" >&5
+$as_echo_n "checking for $ac_header... " >&6; }
+if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
+  $as_echo_n "(cached) " >&6
+fi
+ac_res=`eval 'as_val=${'$as_ac_Header'}
+                $as_echo "$as_val"'`
+              { $as_echo "$as_me:$LINENO: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+else
+  # Is the header compilable?
+{ $as_echo "$as_me:$LINENO: checking $ac_header usability" >&5
+$as_echo_n "checking $ac_header usability... " >&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 { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_header_compiler=yes
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_header_compiler=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+{ $as_echo "$as_me:$LINENO: result: $ac_header_compiler" >&5
+$as_echo "$ac_header_compiler" >&6; }
+
+# Is the header present?
+{ $as_echo "$as_me:$LINENO: checking $ac_header presence" >&5
+$as_echo_n "checking $ac_header presence... " >&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 { (ac_try="$ac_cpp conftest.$ac_ext"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&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
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } >/dev/null && {
+        test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       }; then
+  ac_header_preproc=yes
+else
+  $as_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
+{ $as_echo "$as_me:$LINENO: result: $ac_header_preproc" >&5
+$as_echo "$ac_header_preproc" >&6; }
+
+# So?  What about this header?
+case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in
+  yes:no: )
+    { $as_echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5
+$as_echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;}
+    { $as_echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5
+$as_echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;}
+    ac_header_preproc=yes
+    ;;
+  no:yes:* )
+    { $as_echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5
+$as_echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;}
+    { $as_echo "$as_me:$LINENO: WARNING: $ac_header:     check for missing prerequisite headers?" >&5
+$as_echo "$as_me: WARNING: $ac_header:     check for missing prerequisite headers?" >&2;}
+    { $as_echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5
+$as_echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;}
+    { $as_echo "$as_me:$LINENO: WARNING: $ac_header:     section \"Present But Cannot Be Compiled\"" >&5
+$as_echo "$as_me: WARNING: $ac_header:     section \"Present But Cannot Be Compiled\"" >&2;}
+    { $as_echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5
+$as_echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;}
+    { $as_echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5
+$as_echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;}
+    ( cat <<\_ASBOX
+## ------------------------------------ ##
+## Report this to saord@cfa.harvard.edu ##
+## ------------------------------------ ##
+_ASBOX
+     ) | sed "s/^/$as_me: WARNING:     /" >&2
+    ;;
+esac
+{ $as_echo "$as_me:$LINENO: checking for $ac_header" >&5
+$as_echo_n "checking for $ac_header... " >&6; }
+if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
+  $as_echo_n "(cached) " >&6
+else
+  eval "$as_ac_Header=\$ac_header_preproc"
+fi
+ac_res=`eval 'as_val=${'$as_ac_Header'}
+                $as_echo "$as_val"'`
+              { $as_echo "$as_me:$LINENO: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+
+fi
+as_val=`eval 'as_val=${'$as_ac_Header'}
+                $as_echo "$as_val"'`
+   if test "x$as_val" = x""yes; then
+  cat >>confdefs.h <<_ACEOF
+#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+
+done
+
+
+for ac_header in sys/ipc.h
+do
+as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
+if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
+  { $as_echo "$as_me:$LINENO: checking for $ac_header" >&5
+$as_echo_n "checking for $ac_header... " >&6; }
+if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
+  $as_echo_n "(cached) " >&6
+fi
+ac_res=`eval 'as_val=${'$as_ac_Header'}
+                $as_echo "$as_val"'`
+              { $as_echo "$as_me:$LINENO: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+else
+  # Is the header compilable?
+{ $as_echo "$as_me:$LINENO: checking $ac_header usability" >&5
+$as_echo_n "checking $ac_header usability... " >&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 { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_header_compiler=yes
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_header_compiler=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+{ $as_echo "$as_me:$LINENO: result: $ac_header_compiler" >&5
+$as_echo "$ac_header_compiler" >&6; }
+
+# Is the header present?
+{ $as_echo "$as_me:$LINENO: checking $ac_header presence" >&5
+$as_echo_n "checking $ac_header presence... " >&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 { (ac_try="$ac_cpp conftest.$ac_ext"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&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
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } >/dev/null && {
+        test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       }; then
+  ac_header_preproc=yes
+else
+  $as_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
+{ $as_echo "$as_me:$LINENO: result: $ac_header_preproc" >&5
+$as_echo "$ac_header_preproc" >&6; }
+
+# So?  What about this header?
+case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in
+  yes:no: )
+    { $as_echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5
+$as_echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;}
+    { $as_echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5
+$as_echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;}
+    ac_header_preproc=yes
+    ;;
+  no:yes:* )
+    { $as_echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5
+$as_echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;}
+    { $as_echo "$as_me:$LINENO: WARNING: $ac_header:     check for missing prerequisite headers?" >&5
+$as_echo "$as_me: WARNING: $ac_header:     check for missing prerequisite headers?" >&2;}
+    { $as_echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5
+$as_echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;}
+    { $as_echo "$as_me:$LINENO: WARNING: $ac_header:     section \"Present But Cannot Be Compiled\"" >&5
+$as_echo "$as_me: WARNING: $ac_header:     section \"Present But Cannot Be Compiled\"" >&2;}
+    { $as_echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5
+$as_echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;}
+    { $as_echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5
+$as_echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;}
+    ( cat <<\_ASBOX
+## ------------------------------------ ##
+## Report this to saord@cfa.harvard.edu ##
+## ------------------------------------ ##
+_ASBOX
+     ) | sed "s/^/$as_me: WARNING:     /" >&2
+    ;;
+esac
+{ $as_echo "$as_me:$LINENO: checking for $ac_header" >&5
+$as_echo_n "checking for $ac_header... " >&6; }
+if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
+  $as_echo_n "(cached) " >&6
+else
+  eval "$as_ac_Header=\$ac_header_preproc"
+fi
+ac_res=`eval 'as_val=${'$as_ac_Header'}
+                $as_echo "$as_val"'`
+              { $as_echo "$as_me:$LINENO: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+
+fi
+as_val=`eval 'as_val=${'$as_ac_Header'}
+                $as_echo "$as_val"'`
+   if test "x$as_val" = x""yes; then
+  cat >>confdefs.h <<_ACEOF
+#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+
+done
+
+
+{ $as_echo "$as_me:$LINENO: checking for socklen_t" >&5
+$as_echo_n "checking for socklen_t... " >&6; }
+if test "${ac_cv_type_socklen_t+set}" = set; then
+  $as_echo_n "(cached) " >&6
+else
+  ac_cv_type_socklen_t=no
+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 (sizeof (socklen_t))
+       return 0;
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  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 (sizeof ((socklen_t)))
+         return 0;
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  :
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_cv_type_socklen_t=yes
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+{ $as_echo "$as_me:$LINENO: result: $ac_cv_type_socklen_t" >&5
+$as_echo "$ac_cv_type_socklen_t" >&6; }
+if test "x$ac_cv_type_socklen_t" = x""yes; then
+
+cat >>confdefs.h <<_ACEOF
+#define HAVE_SOCKLEN_T 1
+_ACEOF
+
+
+fi
+
+
+{ $as_echo "$as_me:$LINENO: checking for an ANSI C-conforming const" >&5
+$as_echo_n "checking for an ANSI C-conforming const... " >&6; }
+if test "${ac_cv_c_const+set}" = set; then
+  $as_echo_n "(cached) " >&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 cs;
+  /* SunOS 4.1.1 cc rejects this.  */
+  char const *const *pcpcc;
+  char **ppc;
+  /* 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";
+  pcpcc = &g + (g ? g-g : 0);
+  /* HPUX 7.0 cc rejects these. */
+  ++pcpcc;
+  ppc = (char**) pcpcc;
+  pcpcc = (char const *const *) ppc;
+  { /* SCO 3.2v4 cc rejects this.  */
+    char *t;
+    char const *s = 0 ? (char *) 0 : (char const *) 0;
+
+    *t++ = 0;
+    if (s) return 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;
+    if (!foo) return 0;
+  }
+  return !cs[0] && !zero.x;
+#endif
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_cv_c_const=yes
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_cv_c_const=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+{ $as_echo "$as_me:$LINENO: result: $ac_cv_c_const" >&5
+$as_echo "$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=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh`
+{ $as_echo "$as_me:$LINENO: checking for $ac_func" >&5
+$as_echo_n "checking for $ac_func... " >&6; }
+if { as_var=$as_ac_var; eval "test \"\${$as_var+set}\" = set"; }; then
+  $as_echo_n "(cached) " >&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 GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+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
+#endif
+
+int
+main ()
+{
+return $ac_func ();
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+  (eval "$ac_link") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest$ac_exeext && {
+        test "$cross_compiling" = yes ||
+        $as_test_x conftest$ac_exeext
+       }; then
+  eval "$as_ac_var=yes"
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       eval "$as_ac_var=no"
+fi
+
+rm -rf conftest.dSYM
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+      conftest$ac_exeext conftest.$ac_ext
+fi
+ac_res=`eval 'as_val=${'$as_ac_var'}
+                $as_echo "$as_val"'`
+              { $as_echo "$as_me:$LINENO: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+as_val=`eval 'as_val=${'$as_ac_var'}
+                $as_echo "$as_val"'`
+   if test "x$as_val" = x""yes; then
+  cat >>confdefs.h <<_ACEOF
+#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+done
+
+
+{ $as_echo "$as_me:$LINENO: checking for connect" >&5
+$as_echo_n "checking for connect... " >&6; }
+if test "${ac_cv_func_connect+set}" = set; then
+  $as_echo_n "(cached) " >&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 GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+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
+#endif
+
+int
+main ()
+{
+return connect ();
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+  (eval "$ac_link") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest$ac_exeext && {
+        test "$cross_compiling" = yes ||
+        $as_test_x conftest$ac_exeext
+       }; then
+  ac_cv_func_connect=yes
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_cv_func_connect=no
+fi
+
+rm -rf conftest.dSYM
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+      conftest$ac_exeext conftest.$ac_ext
+fi
+{ $as_echo "$as_me:$LINENO: result: $ac_cv_func_connect" >&5
+$as_echo "$ac_cv_func_connect" >&6; }
+
+if test $ac_cv_func_connect = no; then
+  { $as_echo "$as_me:$LINENO: checking for connect in -lsocket" >&5
+$as_echo_n "checking for connect in -lsocket... " >&6; }
+if test "${ac_cv_lib_socket_connect+set}" = set; then
+  $as_echo_n "(cached) " >&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 GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char connect ();
+int
+main ()
+{
+return connect ();
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+  (eval "$ac_link") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest$ac_exeext && {
+        test "$cross_compiling" = yes ||
+        $as_test_x conftest$ac_exeext
+       }; then
+  ac_cv_lib_socket_connect=yes
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_cv_lib_socket_connect=no
+fi
+
+rm -rf conftest.dSYM
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+      conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:$LINENO: result: $ac_cv_lib_socket_connect" >&5
+$as_echo "$ac_cv_lib_socket_connect" >&6; }
+if test "x$ac_cv_lib_socket_connect" = x""yes; then
+  EXTRA_LIBS="$EXTRA_LIBS -lsocket"
+fi
+
+fi
+{ $as_echo "$as_me:$LINENO: checking for gethostbyname" >&5
+$as_echo_n "checking for gethostbyname... " >&6; }
+if test "${ac_cv_func_gethostbyname+set}" = set; then
+  $as_echo_n "(cached) " >&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 GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+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
+#endif
+
+int
+main ()
+{
+return gethostbyname ();
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+  (eval "$ac_link") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest$ac_exeext && {
+        test "$cross_compiling" = yes ||
+        $as_test_x conftest$ac_exeext
+       }; then
+  ac_cv_func_gethostbyname=yes
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_cv_func_gethostbyname=no
+fi
+
+rm -rf conftest.dSYM
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+      conftest$ac_exeext conftest.$ac_ext
+fi
+{ $as_echo "$as_me:$LINENO: result: $ac_cv_func_gethostbyname" >&5
+$as_echo "$ac_cv_func_gethostbyname" >&6; }
+
+if test $ac_cv_func_gethostbyname = no; then
+  { $as_echo "$as_me:$LINENO: checking for gethostbyname in -lnsl" >&5
+$as_echo_n "checking for gethostbyname in -lnsl... " >&6; }
+if test "${ac_cv_lib_nsl_gethostbyname+set}" = set; then
+  $as_echo_n "(cached) " >&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 GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char gethostbyname ();
+int
+main ()
+{
+return gethostbyname ();
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+  (eval "$ac_link") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest$ac_exeext && {
+        test "$cross_compiling" = yes ||
+        $as_test_x conftest$ac_exeext
+       }; then
+  ac_cv_lib_nsl_gethostbyname=yes
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_cv_lib_nsl_gethostbyname=no
+fi
+
+rm -rf conftest.dSYM
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+      conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:$LINENO: result: $ac_cv_lib_nsl_gethostbyname" >&5
+$as_echo "$ac_cv_lib_nsl_gethostbyname" >&6; }
+if test "x$ac_cv_lib_nsl_gethostbyname" = x""yes; then
+  EXTRA_LIBS="$EXTRA_LIBS -lnsl"
+fi
+
+fi
+# AC_CHECK_LIB(db, snprintf, EXTRA_LIBS="$EXTRA_LIBS -ldb")
+
+#
+# checks specific to this project
+#
+
+{ $as_echo "$as_me:$LINENO: checking for threaded xpans" >&5
+$as_echo_n "checking for threaded xpans... " >&6; }
+# Check whether --enable-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
+  { $as_echo "$as_me:$LINENO: result: $fun_ok" >&5
+$as_echo "$fun_ok" >&6; }
+  { $as_echo "$as_me:$LINENO: checking for pthread_create in -lpthread" >&5
+$as_echo_n "checking for pthread_create in -lpthread... " >&6; }
+if test "${ac_cv_lib_pthread_pthread_create+set}" = set; then
+  $as_echo_n "(cached) " >&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 GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char pthread_create ();
+int
+main ()
+{
+return pthread_create ();
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+  (eval "$ac_link") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest$ac_exeext && {
+        test "$cross_compiling" = yes ||
+        $as_test_x conftest$ac_exeext
+       }; then
+  ac_cv_lib_pthread_pthread_create=yes
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_cv_lib_pthread_pthread_create=no
+fi
+
+rm -rf conftest.dSYM
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+      conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:$LINENO: result: $ac_cv_lib_pthread_pthread_create" >&5
+$as_echo "$ac_cv_lib_pthread_pthread_create" >&6; }
+if test "x$ac_cv_lib_pthread_pthread_create" = x""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
+    { { $as_echo "$as_me:$LINENO: error: no threads found ... can't use enable-threaded-xpans" >&5
+$as_echo "$as_me: error: no threads found ... can't use enable-threaded-xpans" >&2;}
+   { (exit 1); exit 1; }; }
+  fi
+else
+  { $as_echo "$as_me:$LINENO: result: $fun_ok" >&5
+$as_echo "$fun_ok" >&6; }
+fi
+
+
+{ $as_echo "$as_me:$LINENO: checking for shared library build" >&5
+$as_echo_n "checking for shared library build... " >&6; }
+# Check whether --enable-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
+
+{ $as_echo "$as_me:$LINENO: result: $fun_ok" >&5
+$as_echo "$fun_ok" >&6; }
+
+{ $as_echo "$as_me:$LINENO: checking for request to use posix_spawn" >&5
+$as_echo_n "checking for request to use posix_spawn... " >&6; }
+# Check whether --enable-posix_spawn was given.
+if test "${enable_posix_spawn+set}" = set; then
+  enableval=$enable_posix_spawn; fun_ok=$enableval
+else
+  fun_ok=no
+fi
+
+{ $as_echo "$as_me:$LINENO: result: $fun_ok" >&5
+$as_echo "$fun_ok" >&6; }
+if test "$fun_ok" = "yes"; then
+
+
+for ac_func in posix_spawn _NSGetEnviron
+do
+as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh`
+{ $as_echo "$as_me:$LINENO: checking for $ac_func" >&5
+$as_echo_n "checking for $ac_func... " >&6; }
+if { as_var=$as_ac_var; eval "test \"\${$as_var+set}\" = set"; }; then
+  $as_echo_n "(cached) " >&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 GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+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
+#endif
+
+int
+main ()
+{
+return $ac_func ();
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+  (eval "$ac_link") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest$ac_exeext && {
+        test "$cross_compiling" = yes ||
+        $as_test_x conftest$ac_exeext
+       }; then
+  eval "$as_ac_var=yes"
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       eval "$as_ac_var=no"
+fi
+
+rm -rf conftest.dSYM
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+      conftest$ac_exeext conftest.$ac_ext
+fi
+ac_res=`eval 'as_val=${'$as_ac_var'}
+                $as_echo "$as_val"'`
+              { $as_echo "$as_me:$LINENO: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+as_val=`eval 'as_val=${'$as_ac_var'}
+                $as_echo "$as_val"'`
+   if test "x$as_val" = x""yes; then
+  cat >>confdefs.h <<_ACEOF
+#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+done
+
+
+for ac_header in crt_externs.h
+do
+as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
+if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
+  { $as_echo "$as_me:$LINENO: checking for $ac_header" >&5
+$as_echo_n "checking for $ac_header... " >&6; }
+if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
+  $as_echo_n "(cached) " >&6
+fi
+ac_res=`eval 'as_val=${'$as_ac_Header'}
+                $as_echo "$as_val"'`
+              { $as_echo "$as_me:$LINENO: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+else
+  # Is the header compilable?
+{ $as_echo "$as_me:$LINENO: checking $ac_header usability" >&5
+$as_echo_n "checking $ac_header usability... " >&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 { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_header_compiler=yes
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_header_compiler=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+{ $as_echo "$as_me:$LINENO: result: $ac_header_compiler" >&5
+$as_echo "$ac_header_compiler" >&6; }
+
+# Is the header present?
+{ $as_echo "$as_me:$LINENO: checking $ac_header presence" >&5
+$as_echo_n "checking $ac_header presence... " >&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 { (ac_try="$ac_cpp conftest.$ac_ext"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&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
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } >/dev/null && {
+        test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       }; then
+  ac_header_preproc=yes
+else
+  $as_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
+{ $as_echo "$as_me:$LINENO: result: $ac_header_preproc" >&5
+$as_echo "$ac_header_preproc" >&6; }
+
+# So?  What about this header?
+case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in
+  yes:no: )
+    { $as_echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5
+$as_echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;}
+    { $as_echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5
+$as_echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;}
+    ac_header_preproc=yes
+    ;;
+  no:yes:* )
+    { $as_echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5
+$as_echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;}
+    { $as_echo "$as_me:$LINENO: WARNING: $ac_header:     check for missing prerequisite headers?" >&5
+$as_echo "$as_me: WARNING: $ac_header:     check for missing prerequisite headers?" >&2;}
+    { $as_echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5
+$as_echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;}
+    { $as_echo "$as_me:$LINENO: WARNING: $ac_header:     section \"Present But Cannot Be Compiled\"" >&5
+$as_echo "$as_me: WARNING: $ac_header:     section \"Present But Cannot Be Compiled\"" >&2;}
+    { $as_echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5
+$as_echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;}
+    { $as_echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5
+$as_echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;}
+    ( cat <<\_ASBOX
+## ------------------------------------ ##
+## Report this to saord@cfa.harvard.edu ##
+## ------------------------------------ ##
+_ASBOX
+     ) | sed "s/^/$as_me: WARNING:     /" >&2
+    ;;
+esac
+{ $as_echo "$as_me:$LINENO: checking for $ac_header" >&5
+$as_echo_n "checking for $ac_header... " >&6; }
+if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
+  $as_echo_n "(cached) " >&6
+else
+  eval "$as_ac_Header=\$ac_header_preproc"
+fi
+ac_res=`eval 'as_val=${'$as_ac_Header'}
+                $as_echo "$as_val"'`
+              { $as_echo "$as_me:$LINENO: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+
+fi
+as_val=`eval 'as_val=${'$as_ac_Header'}
+                $as_echo "$as_val"'`
+   if test "x$as_val" = x""yes; then
+  cat >>confdefs.h <<_ACEOF
+#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+
+done
+
+fi
+
+{ $as_echo "$as_me:$LINENO: checking for X" >&5
+$as_echo_n "checking for X... " >&6; }
+
+
+# Check whether --with-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
+  case $x_includes,$x_libraries in #(
+    *\'*) { { $as_echo "$as_me:$LINENO: error: cannot use X directory names containing '" >&5
+$as_echo "$as_me: error: cannot use X directory names containing '" >&2;}
+   { (exit 1); exit 1; }; };; #(
+    *,NONE | NONE,*) if test "${ac_cv_have_x+set}" = set; then
+  $as_echo_n "(cached) " >&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 -f -r conftest.dir
+if mkdir conftest.dir; then
+  cd conftest.dir
+  cat >Imakefile <<'_ACEOF'
+incroot:
+       @echo incroot='${INCROOT}'
+usrlibdir:
+       @echo usrlibdir='${USRLIBDIR}'
+libdir:
+       @echo libdir='${LIBDIR}'
+_ACEOF
+  if (export CC; ${XMKMF-xmkmf}) >/dev/null 2>/dev/null && test -f Makefile; then
+    # GNU make sometimes prints "make[1]: Entering...", which would confuse us.
+    for ac_var in incroot usrlibdir libdir; do
+      eval "ac_im_$ac_var=\`\${MAKE-make} $ac_var 2>/dev/null | sed -n 's/^$ac_var=//p'\`"
+    done
+    # Open Windows xmkmf reportedly sets LIBDIR instead of USRLIBDIR.
+    for ac_extension in a so sl dylib la dll; 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) ac_x_includes= ;;
+       *) test -f "$ac_im_incroot/X11/Xos.h" && ac_x_includes=$ac_im_incroot;;
+    esac
+    case $ac_im_usrlibdir in
+       /usr/lib | /usr/lib64 | /lib | /lib64) ;;
+       *) test -d "$ac_im_usrlibdir" && ac_x_libraries=$ac_im_usrlibdir ;;
+    esac
+  fi
+  cd ..
+  rm -f -r 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 Xlib.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/Xlib.h>
+_ACEOF
+if { (ac_try="$ac_cpp conftest.$ac_ext"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&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
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } >/dev/null && {
+        test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       }; then
+  # We can compile using X headers with no special include directory.
+ac_x_includes=
+else
+  $as_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/Xlib.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="-lX11 $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/Xlib.h>
+int
+main ()
+{
+XrmInitialize ()
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+  (eval "$ac_link") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest$ac_exeext && {
+        test "$cross_compiling" = yes ||
+        $as_test_x conftest$ac_exeext
+       }; then
+  LIBS=$ac_save_LIBS
+# We can link X programs with no special library path.
+ac_x_libraries=
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       LIBS=$ac_save_LIBS
+for ac_dir in `$as_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 dylib la dll; do
+    if test -r "$ac_dir/libX11.$ac_extension"; then
+      ac_x_libraries=$ac_dir
+      break 2
+    fi
+  done
+done
+fi
+
+rm -rf conftest.dSYM
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+      conftest$ac_exeext conftest.$ac_ext
+fi # $ac_x_libraries = no
+
+case $ac_x_includes,$ac_x_libraries in #(
+  no,* | *,no | *\'*)
+    # Didn't find X, or a directory has "'" in its name.
+    ac_cv_have_x="have_x=no";; #(
+  *)
+    # 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'"
+esac
+fi
+;; #(
+    *) have_x=yes;;
+  esac
+  eval "$ac_cv_have_x"
+fi # $with_x != no
+
+if test "$have_x" != yes; then
+  { $as_echo "$as_me:$LINENO: result: $have_x" >&5
+$as_echo "$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'"
+  { $as_echo "$as_me:$LINENO: result: libraries $x_libraries, headers $x_includes" >&5
+$as_echo "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 . . . .
+    { $as_echo "$as_me:$LINENO: checking whether -R must be followed by a space" >&5
+$as_echo_n "checking whether -R must be followed by a space... " >&6; }
+    ac_xsave_LIBS=$LIBS; LIBS="$LIBS -R$x_libraries"
+    ac_xsave_c_werror_flag=$ac_c_werror_flag
+    ac_c_werror_flag=yes
+    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 { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+  (eval "$ac_link") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest$ac_exeext && {
+        test "$cross_compiling" = yes ||
+        $as_test_x conftest$ac_exeext
+       }; then
+  { $as_echo "$as_me:$LINENO: result: no" >&5
+$as_echo "no" >&6; }
+       X_LIBS="$X_LIBS -R$x_libraries"
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       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 { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+  (eval "$ac_link") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest$ac_exeext && {
+        test "$cross_compiling" = yes ||
+        $as_test_x conftest$ac_exeext
+       }; then
+  { $as_echo "$as_me:$LINENO: result: yes" >&5
+$as_echo "yes" >&6; }
+         X_LIBS="$X_LIBS -R $x_libraries"
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       { $as_echo "$as_me:$LINENO: result: neither works" >&5
+$as_echo "neither works" >&6; }
+fi
+
+rm -rf conftest.dSYM
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+      conftest$ac_exeext conftest.$ac_ext
+fi
+
+rm -rf conftest.dSYM
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+      conftest$ac_exeext conftest.$ac_ext
+    ac_c_werror_flag=$ac_xsave_c_werror_flag
+    LIBS=$ac_xsave_LIBS
+  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 GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char XOpenDisplay ();
+int
+main ()
+{
+return XOpenDisplay ();
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+  (eval "$ac_link") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest$ac_exeext && {
+        test "$cross_compiling" = yes ||
+        $as_test_x conftest$ac_exeext
+       }; then
+  :
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       { $as_echo "$as_me:$LINENO: checking for dnet_ntoa in -ldnet" >&5
+$as_echo_n "checking for dnet_ntoa in -ldnet... " >&6; }
+if test "${ac_cv_lib_dnet_dnet_ntoa+set}" = set; then
+  $as_echo_n "(cached) " >&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 GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char dnet_ntoa ();
+int
+main ()
+{
+return dnet_ntoa ();
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+  (eval "$ac_link") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest$ac_exeext && {
+        test "$cross_compiling" = yes ||
+        $as_test_x conftest$ac_exeext
+       }; then
+  ac_cv_lib_dnet_dnet_ntoa=yes
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_cv_lib_dnet_dnet_ntoa=no
+fi
+
+rm -rf conftest.dSYM
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+      conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:$LINENO: result: $ac_cv_lib_dnet_dnet_ntoa" >&5
+$as_echo "$ac_cv_lib_dnet_dnet_ntoa" >&6; }
+if test "x$ac_cv_lib_dnet_dnet_ntoa" = x""yes; then
+  X_EXTRA_LIBS="$X_EXTRA_LIBS -ldnet"
+fi
+
+    if test $ac_cv_lib_dnet_dnet_ntoa = no; then
+      { $as_echo "$as_me:$LINENO: checking for dnet_ntoa in -ldnet_stub" >&5
+$as_echo_n "checking for dnet_ntoa in -ldnet_stub... " >&6; }
+if test "${ac_cv_lib_dnet_stub_dnet_ntoa+set}" = set; then
+  $as_echo_n "(cached) " >&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 GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char dnet_ntoa ();
+int
+main ()
+{
+return dnet_ntoa ();
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+  (eval "$ac_link") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest$ac_exeext && {
+        test "$cross_compiling" = yes ||
+        $as_test_x conftest$ac_exeext
+       }; then
+  ac_cv_lib_dnet_stub_dnet_ntoa=yes
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_cv_lib_dnet_stub_dnet_ntoa=no
+fi
+
+rm -rf conftest.dSYM
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+      conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:$LINENO: result: $ac_cv_lib_dnet_stub_dnet_ntoa" >&5
+$as_echo "$ac_cv_lib_dnet_stub_dnet_ntoa" >&6; }
+if test "x$ac_cv_lib_dnet_stub_dnet_ntoa" = x""yes; then
+  X_EXTRA_LIBS="$X_EXTRA_LIBS -ldnet_stub"
+fi
+
+    fi
+fi
+
+rm -rf conftest.dSYM
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+      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.
+    { $as_echo "$as_me:$LINENO: checking for gethostbyname" >&5
+$as_echo_n "checking for gethostbyname... " >&6; }
+if test "${ac_cv_func_gethostbyname+set}" = set; then
+  $as_echo_n "(cached) " >&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 GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+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
+#endif
+
+int
+main ()
+{
+return gethostbyname ();
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+  (eval "$ac_link") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest$ac_exeext && {
+        test "$cross_compiling" = yes ||
+        $as_test_x conftest$ac_exeext
+       }; then
+  ac_cv_func_gethostbyname=yes
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_cv_func_gethostbyname=no
+fi
+
+rm -rf conftest.dSYM
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+      conftest$ac_exeext conftest.$ac_ext
+fi
+{ $as_echo "$as_me:$LINENO: result: $ac_cv_func_gethostbyname" >&5
+$as_echo "$ac_cv_func_gethostbyname" >&6; }
+
+    if test $ac_cv_func_gethostbyname = no; then
+      { $as_echo "$as_me:$LINENO: checking for gethostbyname in -lnsl" >&5
+$as_echo_n "checking for gethostbyname in -lnsl... " >&6; }
+if test "${ac_cv_lib_nsl_gethostbyname+set}" = set; then
+  $as_echo_n "(cached) " >&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 GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char gethostbyname ();
+int
+main ()
+{
+return gethostbyname ();
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+  (eval "$ac_link") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest$ac_exeext && {
+        test "$cross_compiling" = yes ||
+        $as_test_x conftest$ac_exeext
+       }; then
+  ac_cv_lib_nsl_gethostbyname=yes
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_cv_lib_nsl_gethostbyname=no
+fi
+
+rm -rf conftest.dSYM
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+      conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:$LINENO: result: $ac_cv_lib_nsl_gethostbyname" >&5
+$as_echo "$ac_cv_lib_nsl_gethostbyname" >&6; }
+if test "x$ac_cv_lib_nsl_gethostbyname" = x""yes; then
+  X_EXTRA_LIBS="$X_EXTRA_LIBS -lnsl"
+fi
+
+      if test $ac_cv_lib_nsl_gethostbyname = no; then
+       { $as_echo "$as_me:$LINENO: checking for gethostbyname in -lbsd" >&5
+$as_echo_n "checking for gethostbyname in -lbsd... " >&6; }
+if test "${ac_cv_lib_bsd_gethostbyname+set}" = set; then
+  $as_echo_n "(cached) " >&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 GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char gethostbyname ();
+int
+main ()
+{
+return gethostbyname ();
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+  (eval "$ac_link") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest$ac_exeext && {
+        test "$cross_compiling" = yes ||
+        $as_test_x conftest$ac_exeext
+       }; then
+  ac_cv_lib_bsd_gethostbyname=yes
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_cv_lib_bsd_gethostbyname=no
+fi
+
+rm -rf conftest.dSYM
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+      conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:$LINENO: result: $ac_cv_lib_bsd_gethostbyname" >&5
+$as_echo "$ac_cv_lib_bsd_gethostbyname" >&6; }
+if test "x$ac_cv_lib_bsd_gethostbyname" = x""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.
+    { $as_echo "$as_me:$LINENO: checking for connect" >&5
+$as_echo_n "checking for connect... " >&6; }
+if test "${ac_cv_func_connect+set}" = set; then
+  $as_echo_n "(cached) " >&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 GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+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
+#endif
+
+int
+main ()
+{
+return connect ();
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+  (eval "$ac_link") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest$ac_exeext && {
+        test "$cross_compiling" = yes ||
+        $as_test_x conftest$ac_exeext
+       }; then
+  ac_cv_func_connect=yes
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_cv_func_connect=no
+fi
+
+rm -rf conftest.dSYM
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+      conftest$ac_exeext conftest.$ac_ext
+fi
+{ $as_echo "$as_me:$LINENO: result: $ac_cv_func_connect" >&5
+$as_echo "$ac_cv_func_connect" >&6; }
+
+    if test $ac_cv_func_connect = no; then
+      { $as_echo "$as_me:$LINENO: checking for connect in -lsocket" >&5
+$as_echo_n "checking for connect in -lsocket... " >&6; }
+if test "${ac_cv_lib_socket_connect+set}" = set; then
+  $as_echo_n "(cached) " >&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 GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char connect ();
+int
+main ()
+{
+return connect ();
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+  (eval "$ac_link") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest$ac_exeext && {
+        test "$cross_compiling" = yes ||
+        $as_test_x conftest$ac_exeext
+       }; then
+  ac_cv_lib_socket_connect=yes
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_cv_lib_socket_connect=no
+fi
+
+rm -rf conftest.dSYM
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+      conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:$LINENO: result: $ac_cv_lib_socket_connect" >&5
+$as_echo "$ac_cv_lib_socket_connect" >&6; }
+if test "x$ac_cv_lib_socket_connect" = x""yes; then
+  X_EXTRA_LIBS="-lsocket $X_EXTRA_LIBS"
+fi
+
+    fi
+
+    # Guillermo Gomez says -lposix is necessary on A/UX.
+    { $as_echo "$as_me:$LINENO: checking for remove" >&5
+$as_echo_n "checking for remove... " >&6; }
+if test "${ac_cv_func_remove+set}" = set; then
+  $as_echo_n "(cached) " >&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 GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+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
+#endif
+
+int
+main ()
+{
+return remove ();
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+  (eval "$ac_link") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest$ac_exeext && {
+        test "$cross_compiling" = yes ||
+        $as_test_x conftest$ac_exeext
+       }; then
+  ac_cv_func_remove=yes
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_cv_func_remove=no
+fi
+
+rm -rf conftest.dSYM
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+      conftest$ac_exeext conftest.$ac_ext
+fi
+{ $as_echo "$as_me:$LINENO: result: $ac_cv_func_remove" >&5
+$as_echo "$ac_cv_func_remove" >&6; }
+
+    if test $ac_cv_func_remove = no; then
+      { $as_echo "$as_me:$LINENO: checking for remove in -lposix" >&5
+$as_echo_n "checking for remove in -lposix... " >&6; }
+if test "${ac_cv_lib_posix_remove+set}" = set; then
+  $as_echo_n "(cached) " >&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 GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char remove ();
+int
+main ()
+{
+return remove ();
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+  (eval "$ac_link") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest$ac_exeext && {
+        test "$cross_compiling" = yes ||
+        $as_test_x conftest$ac_exeext
+       }; then
+  ac_cv_lib_posix_remove=yes
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_cv_lib_posix_remove=no
+fi
+
+rm -rf conftest.dSYM
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+      conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:$LINENO: result: $ac_cv_lib_posix_remove" >&5
+$as_echo "$ac_cv_lib_posix_remove" >&6; }
+if test "x$ac_cv_lib_posix_remove" = x""yes; then
+  X_EXTRA_LIBS="$X_EXTRA_LIBS -lposix"
+fi
+
+    fi
+
+    # BSDI BSD/OS 2.1 needs -lipc for XOpenDisplay.
+    { $as_echo "$as_me:$LINENO: checking for shmat" >&5
+$as_echo_n "checking for shmat... " >&6; }
+if test "${ac_cv_func_shmat+set}" = set; then
+  $as_echo_n "(cached) " >&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 GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+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
+#endif
+
+int
+main ()
+{
+return shmat ();
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+  (eval "$ac_link") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest$ac_exeext && {
+        test "$cross_compiling" = yes ||
+        $as_test_x conftest$ac_exeext
+       }; then
+  ac_cv_func_shmat=yes
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_cv_func_shmat=no
+fi
+
+rm -rf conftest.dSYM
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+      conftest$ac_exeext conftest.$ac_ext
+fi
+{ $as_echo "$as_me:$LINENO: result: $ac_cv_func_shmat" >&5
+$as_echo "$ac_cv_func_shmat" >&6; }
+
+    if test $ac_cv_func_shmat = no; then
+      { $as_echo "$as_me:$LINENO: checking for shmat in -lipc" >&5
+$as_echo_n "checking for shmat in -lipc... " >&6; }
+if test "${ac_cv_lib_ipc_shmat+set}" = set; then
+  $as_echo_n "(cached) " >&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 GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char shmat ();
+int
+main ()
+{
+return shmat ();
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+  (eval "$ac_link") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest$ac_exeext && {
+        test "$cross_compiling" = yes ||
+        $as_test_x conftest$ac_exeext
+       }; then
+  ac_cv_lib_ipc_shmat=yes
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_cv_lib_ipc_shmat=no
+fi
+
+rm -rf conftest.dSYM
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+      conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:$LINENO: result: $ac_cv_lib_ipc_shmat" >&5
+$as_echo "$ac_cv_lib_ipc_shmat" >&6; }
+if test "x$ac_cv_lib_ipc_shmat" = x""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
+  { $as_echo "$as_me:$LINENO: checking for IceConnectionNumber in -lICE" >&5
+$as_echo_n "checking for IceConnectionNumber in -lICE... " >&6; }
+if test "${ac_cv_lib_ICE_IceConnectionNumber+set}" = set; then
+  $as_echo_n "(cached) " >&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 GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char IceConnectionNumber ();
+int
+main ()
+{
+return IceConnectionNumber ();
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+  (eval "$ac_link") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest$ac_exeext && {
+        test "$cross_compiling" = yes ||
+        $as_test_x conftest$ac_exeext
+       }; then
+  ac_cv_lib_ICE_IceConnectionNumber=yes
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_cv_lib_ICE_IceConnectionNumber=no
+fi
+
+rm -rf conftest.dSYM
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+      conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:$LINENO: result: $ac_cv_lib_ICE_IceConnectionNumber" >&5
+$as_echo "$ac_cv_lib_ICE_IceConnectionNumber" >&6; }
+if test "x$ac_cv_lib_ICE_IceConnectionNumber" = x""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 was given.
+if test "${with_tcl+set}" = set; then
+  withval=$with_tcl; with_tclconfig=${withval}
+fi
+
+       { $as_echo "$as_me:$LINENO: checking for Tcl configuration" >&5
+$as_echo_n "checking for Tcl configuration... " >&6; }
+       if test x"${withval}" != xno ; then
+       if test "${ac_cv_c_tclconfig+set}" = set; then
+  $as_echo_n "(cached) " >&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
+                   { $as_echo "$as_me:$LINENO: result: ${with_tclconfig} directory doesn't contain tclConfig.sh" >&5
+$as_echo "${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
+           { $as_echo "$as_me:$LINENO: result: skipping Tcl configuration" >&5
+$as_echo "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"
+           { $as_echo "$as_me:$LINENO: result: can't find Tcl configuration definitions" >&5
+$as_echo "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}
+           { $as_echo "$as_me:$LINENO: result: found $TCL_BIN_DIR/tclConfig.sh" >&5
+$as_echo "found $TCL_BIN_DIR/tclConfig.sh" >&6; }
+       fi
+    fi
+
+if test x"${no_tcl}" = x ; then
+
+    { $as_echo "$as_me:$LINENO: checking for existence of $TCL_BIN_DIR/tclConfig.sh" >&5
+$as_echo_n "checking for existence of $TCL_BIN_DIR/tclConfig.sh... " >&6; }
+
+    if test -f "$TCL_BIN_DIR/tclConfig.sh" ; then
+        { $as_echo "$as_me:$LINENO: result: loading" >&5
+$as_echo "loading" >&6; }
+       . $TCL_BIN_DIR/tclConfig.sh
+    else
+        { $as_echo "$as_me:$LINENO: result: file not found" >&5
+$as_echo "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"
+        { $as_echo "$as_me:$LINENO: result: Tcl support will utilize stubs library: $TCL_LIBS" >&5
+$as_echo "Tcl support will utilize stubs library: $TCL_LIBS" >&6; }
+      else
+        TCL_LIBS="$TCL_LIB_SPEC"
+        { $as_echo "$as_me:$LINENO: result: Tcl support will utilize library: $TCL_LIBS" >&5
+$as_echo "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
+
+        { $as_echo "$as_me:$LINENO: result: warning: tcl.h not found with --with-tcl ... tcl build might fail" >&5
+$as_echo "warning: tcl.h not found with --with-tcl ... tcl build might fail" >&6; }
+      else
+        { $as_echo "$as_me:$LINENO: result: $TCL_PREFIX/include/tcl.h not found ... use --with-tcl to build tcl explicitly" >&5
+$as_echo "$TCL_PREFIX/include/tcl.h not found ... use --with-tcl to build tcl explicitly" >&6; }
+      fi
+    fi
+fi
+
+
+
+{ $as_echo "$as_me:$LINENO: checking for incorporation of thread support" >&5
+$as_echo_n "checking for incorporation of thread support... " >&6; }
+
+# Check whether --with-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
+  { $as_echo "$as_me:$LINENO: result: yes" >&5
+$as_echo "yes" >&6; }
+  CFLAGS="$CFLAGS -D_REENTRANT"
+else
+  { $as_echo "$as_me:$LINENO: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+{ $as_echo "$as_me:$LINENO: checking for gtk" >&5
+$as_echo_n "checking for gtk... " >&6; }
+
+# Check whether --with-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
+  { $as_echo "$as_me:$LINENO: result: yes ($withval)" >&5
+$as_echo "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=""
+  { $as_echo "$as_me:$LINENO: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+
+# restore LDFLAGS
+LDFLAGS="$LDFLAGS $XLDFLAGS"
+
+{ $as_echo "$as_me:$LINENO: checking $host_os configuration" >&5
+$as_echo_n "checking $host_os configuration... " >&6; }
+case $host_os in
+    *cygwin*|*Cygwin* )
+        cat >>confdefs.h <<\_ACEOF
+#define HAVE_CYGWIN 1
+_ACEOF
+
+        { $as_echo "$as_me:$LINENO: result: flagging Cygwin" >&5
+$as_echo "flagging Cygwin" >&6; }
+        ;;
+    *mingw32*|*Mingw32*)
+        CFLAGS="$CFLAGS -mconsole"
+       EXTRA_LIBS="$EXTRA_LIBS -lwsock32"
+        cat >>confdefs.h <<\_ACEOF
+#define HAVE_MINGW32 1
+_ACEOF
+
+        { $as_echo "$as_me:$LINENO: result: flagging MinGW" >&5
+$as_echo "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=""
+          { $as_echo "$as_me:$LINENO: result: removing -I/usr/local/include" >&5
+$as_echo "removing -I/usr/local/include" >&6; }
+        fi
+       ;;
+    *osf*|*Osf*)
+         { $as_echo "$as_me:$LINENO: checking for snprintf in -ldb" >&5
+$as_echo_n "checking for snprintf in -ldb... " >&6; }
+if test "${ac_cv_lib_db_snprintf+set}" = set; then
+  $as_echo_n "(cached) " >&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 GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char snprintf ();
+int
+main ()
+{
+return snprintf ();
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+  (eval "$ac_link") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest$ac_exeext && {
+        test "$cross_compiling" = yes ||
+        $as_test_x conftest$ac_exeext
+       }; then
+  ac_cv_lib_db_snprintf=yes
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_cv_lib_db_snprintf=no
+fi
+
+rm -rf conftest.dSYM
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+      conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:$LINENO: result: $ac_cv_lib_db_snprintf" >&5
+$as_echo "$ac_cv_lib_db_snprintf" >&6; }
+if test "x$ac_cv_lib_db_snprintf" = x""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"
+           { $as_echo "$as_me:$LINENO: result: adding -fPIC to gcc" >&5
+$as_echo "adding -fPIC to gcc" >&6; }
+         else
+            { $as_echo "$as_me:$LINENO: result: none" >&5
+$as_echo "none" >&6; }
+         fi
+       else
+            { $as_echo "$as_me:$LINENO: result: none" >&5
+$as_echo "none" >&6; }
+       fi
+        ;;
+esac
+
+
+
+ac_config_files="$ac_config_files Makefile"
+
+
+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, we kill variables containing newlines.
+# 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.
+(
+  for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do
+    eval ac_val=\$$ac_var
+    case $ac_val in #(
+    *${as_nl}*)
+      case $ac_var in #(
+      *_cv_*) { $as_echo "$as_me:$LINENO: WARNING: cache variable $ac_var contains a newline" >&5
+$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;;
+      esac
+      case $ac_var in #(
+      _ | IFS | as_nl) ;; #(
+      BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #(
+      *) $as_unset $ac_var ;;
+      esac ;;
+    esac
+  done
+
+  (set) 2>&1 |
+    case $as_nl`(ac_space=' '; set) 2>&1` in #(
+    *${as_nl}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 "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p"
+      ;;
+    esac |
+    sort
+) |
+  sed '
+     /^ac_cv_env_/b end
+     t clear
+     :clear
+     s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/
+     t end
+     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" &&
+      { $as_echo "$as_me:$LINENO: updating cache $cache_file" >&5
+$as_echo "$as_me: updating cache $cache_file" >&6;}
+    cat confcache >$cache_file
+  else
+    { $as_echo "$as_me:$LINENO: not updating unwritable cache $cache_file" >&5
+$as_echo "$as_me: not updating unwritable cache $cache_file" >&6;}
+  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}'
+
+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_script='s/\$U\././;s/\.o$//;s/\.obj$//'
+  ac_i=`$as_echo "$ac_i" | sed "$ac_script"`
+  # 2. Prepend LIBOBJDIR.  When used with automake>=1.10 LIBOBJDIR
+  #    will be set to the directory where LIBOBJS objects are built.
+  ac_libobjs="$ac_libobjs \${LIBOBJDIR}$ac_i\$U.$ac_objext"
+  ac_ltlibobjs="$ac_ltlibobjs \${LIBOBJDIR}$ac_i"'$U.lo'
+done
+LIBOBJS=$ac_libobjs
+
+LTLIBOBJS=$ac_ltlibobjs
+
+
+
+: ${CONFIG_STATUS=./config.status}
+ac_write_fail=0
+ac_clean_files_save=$ac_clean_files
+ac_clean_files="$ac_clean_files $CONFIG_STATUS"
+{ $as_echo "$as_me:$LINENO: creating $CONFIG_STATUS" >&5
+$as_echo "$as_me: creating $CONFIG_STATUS" >&6;}
+cat >$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+#! $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 || ac_write_fail=1
+## --------------------- ##
+## M4sh Initialization.  ##
+## --------------------- ##
+
+# Be more Bourne compatible
+DUALCASE=1; export DUALCASE # for MKS sh
+if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then
+  emulate sh
+  NULLCMD=:
+  # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which
+  # is contrary to our usage.  Disable this feature.
+  alias -g '${1+"$@"}'='"$@"'
+  setopt NO_GLOB_SUBST
+else
+  case `(set -o) 2>/dev/null` in
+  *posix*) set -o posix ;;
+esac
+
+fi
+
+
+
+
+# PATH needs CR
+# 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
+
+as_nl='
+'
+export as_nl
+# Printing a long string crashes Solaris 7 /usr/bin/printf.
+as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo
+if (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then
+  as_echo='printf %s\n'
+  as_echo_n='printf %s'
+else
+  if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then
+    as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"'
+    as_echo_n='/usr/ucb/echo -n'
+  else
+    as_echo_body='eval expr "X$1" : "X\\(.*\\)"'
+    as_echo_n_body='eval
+      arg=$1;
+      case $arg in
+      *"$as_nl"*)
+       expr "X$arg" : "X\\(.*\\)$as_nl";
+       arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;;
+      esac;
+      expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl"
+    '
+    export as_echo_n_body
+    as_echo_n='sh -c $as_echo_n_body as_echo'
+  fi
+  export as_echo_body
+  as_echo='sh -c $as_echo_body as_echo'
+fi
+
+# The user is always right.
+if test "${PATH_SEPARATOR+set}" != set; then
+  PATH_SEPARATOR=:
+  (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && {
+    (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 ||
+      PATH_SEPARATOR=';'
+  }
+fi
+
+# Support unset when possible.
+if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then
+  as_unset=unset
+else
+  as_unset=false
+fi
+
+
+# IFS
+# We need space, tab and new line, in precisely that order.  Quoting is
+# there to prevent editors from complaining about space-tab.
+# (If _AS_PATH_WALK were called with IFS unset, it would disable word
+# splitting by setting IFS to empty value.)
+IFS=" ""       $as_nl"
+
+# Find who we are.  Look in the path if we contain no directory separator.
+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
+IFS=$as_save_IFS
+
+     ;;
+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
+  $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2
+  { (exit 1); exit 1; }
+fi
+
+# Work around bugs in pre-3.0 UWIN ksh.
+for as_var in ENV MAIL MAILPATH
+do ($as_unset $as_var) >/dev/null 2>&1 && $as_unset $as_var
+done
+PS1='$ '
+PS2='> '
+PS4='+ '
+
+# NLS nuisances.
+LC_ALL=C
+export LC_ALL
+LANGUAGE=C
+export LANGUAGE
+
+# Required to use basename.
+if expr a : '\(a\)' >/dev/null 2>&1 &&
+   test "X`expr 00001 : '.*\(...\)'`" = X001; 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 ||
+$as_echo X/"$0" |
+    sed '/^.*\/\([^/][^/]*\)\/*$/{
+           s//\1/
+           q
+         }
+         /^X\/\(\/\/\)$/{
+           s//\1/
+           q
+         }
+         /^X\/\(\/\).*/{
+           s//\1/
+           q
+         }
+         s/.*/./; q'`
+
+# CDPATH.
+$as_unset CDPATH
+
+
+
+  as_lineno_1=$LINENO
+  as_lineno_2=$LINENO
+  test "x$as_lineno_1" != "x$as_lineno_2" &&
+  test "x`expr $as_lineno_1 + 1`" = "x$as_lineno_2" || {
+
+  # 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 after each line using $LINENO; the second 'sed'
+  # does the real work.  The second script uses 'N' to pair each
+  # line-number line with the line containing $LINENO, 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
+  # scripts with optimization help from Paolo Bonzini.  Blame Lee
+  # E. McMahon (1931-1989) for sed's syntax.  :-)
+  sed -n '
+    p
+    /[$]LINENO/=
+  ' <$as_myself |
+    sed '
+      s/[$]LINENO.*/&-/
+      t lineno
+      b
+      :lineno
+      N
+      :loop
+      s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/
+      t loop
+      s/-\n.*//
+    ' >$as_me.lineno &&
+  chmod +x "$as_me.lineno" ||
+    { $as_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 sensitive to this).
+  . "./$as_me.lineno"
+  # Exit status is that of the last command.
+  exit
+}
+
+
+if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then
+  as_dirname=dirname
+else
+  as_dirname=false
+fi
+
+ECHO_C= ECHO_N= ECHO_T=
+case `echo -n x` in
+-n*)
+  case `echo 'x\c'` in
+  *c*) ECHO_T='        ';;     # ECHO_T is single tab character.
+  *)   ECHO_C='\c';;
+  esac;;
+*)
+  ECHO_N='-n';;
+esac
+if expr a : '\(a\)' >/dev/null 2>&1 &&
+   test "X`expr 00001 : '.*\(...\)'`" = X001; then
+  as_expr=expr
+else
+  as_expr=false
+fi
+
+rm -f conf$$ conf$$.exe conf$$.file
+if test -d conf$$.dir; then
+  rm -f conf$$.dir/conf$$.file
+else
+  rm -f conf$$.dir
+  mkdir conf$$.dir 2>/dev/null
+fi
+if (echo >conf$$.file) 2>/dev/null; then
+  if ln -s conf$$.file conf$$ 2>/dev/null; then
+    as_ln_s='ln -s'
+    # ... but there are two gotchas:
+    # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail.
+    # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable.
+    # In both cases, we have to default to `cp -p'.
+    ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe ||
+      as_ln_s='cp -p'
+  elif ln conf$$.file conf$$ 2>/dev/null; then
+    as_ln_s=ln
+  else
+    as_ln_s='cp -p'
+  fi
+else
+  as_ln_s='cp -p'
+fi
+rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file
+rmdir conf$$.dir 2>/dev/null
+
+if mkdir -p . 2>/dev/null; then
+  as_mkdir_p=:
+else
+  test -d ./-p && rmdir ./-p
+  as_mkdir_p=false
+fi
+
+if test -x / >/dev/null 2>&1; then
+  as_test_x='test -x'
+else
+  if ls -dL / >/dev/null 2>&1; then
+    as_ls_L_option=L
+  else
+    as_ls_L_option=
+  fi
+  as_test_x='
+    eval sh -c '\''
+      if test -d "$1"; then
+       test -d "$1/.";
+      else
+       case $1 in
+       -*)set "./$1";;
+       esac;
+       case `ls -ld'$as_ls_L_option' "$1" 2>/dev/null` in
+       ???[sx]*):;;*)false;;esac;fi
+    '\'' sh
+  '
+fi
+as_executable_p=$as_test_x
+
+# 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'"
+
+
+exec 6>&1
+
+# Save the log message, to keep $[0] and so on meaningful, and to
+# report actual input values of CONFIG_FILES etc. instead of their
+# values after options handling.
+ac_log="
+This file was extended by xpa $as_me 2.1.15, which was
+generated by GNU Autoconf 2.63.  Invocation command line was
+
+  CONFIG_FILES    = $CONFIG_FILES
+  CONFIG_HEADERS  = $CONFIG_HEADERS
+  CONFIG_LINKS    = $CONFIG_LINKS
+  CONFIG_COMMANDS = $CONFIG_COMMANDS
+  $ $0 $@
+
+on `(hostname || uname -n) 2>/dev/null | sed 1q`
+"
+
+_ACEOF
+
+case $ac_config_files in *"
+"*) set x $ac_config_files; shift; ac_config_files=$*;;
+esac
+
+case $ac_config_headers in *"
+"*) set x $ac_config_headers; shift; ac_config_headers=$*;;
+esac
+
+
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+# Files that config.status was made for.
+config_files="$ac_config_files"
+config_headers="$ac_config_headers"
+
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+ac_cs_usage="\
+\`$as_me' instantiates files from templates according to the
+current configuration.
+
+Usage: $0 [OPTION]... [FILE]...
+
+  -h, --help       print this help, then exit
+  -V, --version    print version number and configuration settings, then exit
+  -q, --quiet, --silent
+                   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_write_fail=1
+ac_cs_version="\\
+xpa config.status 2.1.15
+configured by $0, generated by GNU Autoconf 2.63,
+  with options \\"`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`\\"
+
+Copyright (C) 2008 Free Software Foundation, Inc.
+This config.status script is free software; the Free Software Foundation
+gives unlimited permission to copy, distribute and modify it."
+
+ac_pwd='$ac_pwd'
+srcdir='$srcdir'
+test -n "\$AWK" || AWK=awk
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+# The default lists apply if the user does not specify any file.
+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
+    ;;
+  esac
+
+  case $ac_option in
+  # Handling of the options.
+  -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r)
+    ac_cs_recheck=: ;;
+  --version | --versio | --versi | --vers | --ver | --ve | --v | -V )
+    $as_echo "$ac_cs_version"; exit ;;
+  --debug | --debu | --deb | --de | --d | -d )
+    debug=: ;;
+  --file | --fil | --fi | --f )
+    $ac_shift
+    case $ac_optarg in
+    *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;;
+    esac
+    CONFIG_FILES="$CONFIG_FILES '$ac_optarg'"
+    ac_need_defaults=false;;
+  --header | --heade | --head | --hea )
+    $ac_shift
+    case $ac_optarg in
+    *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;;
+    esac
+    CONFIG_HEADERS="$CONFIG_HEADERS '$ac_optarg'"
+    ac_need_defaults=false;;
+  --he | --h)
+    # Conflict between --help and --header
+    { $as_echo "$as_me: error: ambiguous option: $1
+Try \`$0 --help' for more information." >&2
+   { (exit 1); exit 1; }; };;
+  --help | --hel | -h )
+    $as_echo "$ac_cs_usage"; exit ;;
+  -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+  | -silent | --silent | --silen | --sile | --sil | --si | --s)
+    ac_cs_silent=: ;;
+
+  # This is an error.
+  -*) { $as_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"
+     ac_need_defaults=false ;;
+
+  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 || ac_write_fail=1
+if \$ac_cs_recheck; then
+  set X '$SHELL' '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion
+  shift
+  \$as_echo "running CONFIG_SHELL=$SHELL \$*" >&6
+  CONFIG_SHELL='$SHELL'
+  export CONFIG_SHELL
+  exec "\$@"
+fi
+
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+exec 5>>config.log
+{
+  echo
+  sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX
+## Running $as_me. ##
+_ASBOX
+  $as_echo "$ac_log"
+} >&5
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+
+# Handling of arguments.
+for ac_config_target in $ac_config_targets
+do
+  case $ac_config_target in
+    "conf.h") CONFIG_HEADERS="$CONFIG_HEADERS conf.h" ;;
+    "Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;;
+
+  *) { { $as_echo "$as_me:$LINENO: error: invalid argument: $ac_config_target" >&5
+$as_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 against having it here, and in addition,
+# creating and moving files from /tmp can sometimes cause problems.
+# Hook for its removal unless debugging.
+# Note that there is a small window in which the directory will not be cleaned:
+# after its creation but before its name has been assigned to `$tmp'.
+$debug ||
+{
+  tmp=
+  trap 'exit_status=$?
+  { test -z "$tmp" || test ! -d "$tmp" || rm -fr "$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 "./confXXXXXX") 2>/dev/null` &&
+  test -n "$tmp" && test -d "$tmp"
+}  ||
+{
+  tmp=./conf$$-$RANDOM
+  (umask 077 && mkdir "$tmp")
+} ||
+{
+   $as_echo "$as_me: cannot create a temporary directory in ." >&2
+   { (exit 1); exit 1; }
+}
+
+# Set up the scripts for CONFIG_FILES section.
+# No need to generate them if there are no CONFIG_FILES.
+# This happens for instance with `./config.status config.h'.
+if test -n "$CONFIG_FILES"; then
+
+
+ac_cr='\r'
+ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' </dev/null 2>/dev/null`
+if test "$ac_cs_awk_cr" = "a${ac_cr}b"; then
+  ac_cs_awk_cr='\\r'
+else
+  ac_cs_awk_cr=$ac_cr
+fi
+
+echo 'BEGIN {' >"$tmp/subs1.awk" &&
+_ACEOF
+
+
+{
+  echo "cat >conf$$subs.awk <<_ACEOF" &&
+  echo "$ac_subst_vars" | sed 's/.*/&!$&$ac_delim/' &&
+  echo "_ACEOF"
+} >conf$$subs.sh ||
+  { { $as_echo "$as_me:$LINENO: error: could not make $CONFIG_STATUS" >&5
+$as_echo "$as_me: error: could not make $CONFIG_STATUS" >&2;}
+   { (exit 1); exit 1; }; }
+ac_delim_num=`echo "$ac_subst_vars" | grep -c '$'`
+ac_delim='%!_!# '
+for ac_last_try in false false false false false :; do
+  . ./conf$$subs.sh ||
+    { { $as_echo "$as_me:$LINENO: error: could not make $CONFIG_STATUS" >&5
+$as_echo "$as_me: error: could not make $CONFIG_STATUS" >&2;}
+   { (exit 1); exit 1; }; }
+
+  ac_delim_n=`sed -n "s/.*$ac_delim\$/X/p" conf$$subs.awk | grep -c X`
+  if test $ac_delim_n = $ac_delim_num; then
+    break
+  elif $ac_last_try; then
+    { { $as_echo "$as_me:$LINENO: error: could not make $CONFIG_STATUS" >&5
+$as_echo "$as_me: error: could not make $CONFIG_STATUS" >&2;}
+   { (exit 1); exit 1; }; }
+  else
+    ac_delim="$ac_delim!$ac_delim _$ac_delim!! "
+  fi
+done
+rm -f conf$$subs.sh
+
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+cat >>"\$tmp/subs1.awk" <<\\_ACAWK &&
+_ACEOF
+sed -n '
+h
+s/^/S["/; s/!.*/"]=/
+p
+g
+s/^[^!]*!//
+:repl
+t repl
+s/'"$ac_delim"'$//
+t delim
+:nl
+h
+s/\(.\{148\}\).*/\1/
+t more1
+s/["\\]/\\&/g; s/^/"/; s/$/\\n"\\/
+p
+n
+b repl
+:more1
+s/["\\]/\\&/g; s/^/"/; s/$/"\\/
+p
+g
+s/.\{148\}//
+t nl
+:delim
+h
+s/\(.\{148\}\).*/\1/
+t more2
+s/["\\]/\\&/g; s/^/"/; s/$/"/
+p
+b
+:more2
+s/["\\]/\\&/g; s/^/"/; s/$/"\\/
+p
+g
+s/.\{148\}//
+t delim
+' <conf$$subs.awk | sed '
+/^[^""]/{
+  N
+  s/\n//
+}
+' >>$CONFIG_STATUS || ac_write_fail=1
+rm -f conf$$subs.awk
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+_ACAWK
+cat >>"\$tmp/subs1.awk" <<_ACAWK &&
+  for (key in S) S_is_set[key] = 1
+  FS = "\a"
+
+}
+{
+  line = $ 0
+  nfields = split(line, field, "@")
+  substed = 0
+  len = length(field[1])
+  for (i = 2; i < nfields; i++) {
+    key = field[i]
+    keylen = length(key)
+    if (S_is_set[key]) {
+      value = S[key]
+      line = substr(line, 1, len) "" value "" substr(line, len + keylen + 3)
+      len += length(value) + length(field[++i])
+      substed = 1
+    } else
+      len += 1 + keylen
+  }
+
+  print line
+}
+
+_ACAWK
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+if sed "s/$ac_cr//" < /dev/null > /dev/null 2>&1; then
+  sed "s/$ac_cr\$//; s/$ac_cr/$ac_cs_awk_cr/g"
+else
+  cat
+fi < "$tmp/subs1.awk" > "$tmp/subs.awk" \
+  || { { $as_echo "$as_me:$LINENO: error: could not setup config files machinery" >&5
+$as_echo "$as_me: error: could not setup config files machinery" >&2;}
+   { (exit 1); exit 1; }; }
+_ACEOF
+
+# 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
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+fi # test -n "$CONFIG_FILES"
+
+# Set up the scripts for CONFIG_HEADERS section.
+# No need to generate them if there are no CONFIG_HEADERS.
+# This happens for instance with `./config.status Makefile'.
+if test -n "$CONFIG_HEADERS"; then
+cat >"$tmp/defines.awk" <<\_ACAWK ||
+BEGIN {
+_ACEOF
+
+# Transform confdefs.h into an awk script `defines.awk', embedded as
+# here-document in config.status, that substitutes the proper values into
+# config.h.in to produce config.h.
+
+# Create a delimiter string that does not exist in confdefs.h, to ease
+# handling of long lines.
+ac_delim='%!_!# '
+for ac_last_try in false false :; do
+  ac_t=`sed -n "/$ac_delim/p" confdefs.h`
+  if test -z "$ac_t"; then
+    break
+  elif $ac_last_try; then
+    { { $as_echo "$as_me:$LINENO: error: could not make $CONFIG_HEADERS" >&5
+$as_echo "$as_me: error: could not make $CONFIG_HEADERS" >&2;}
+   { (exit 1); exit 1; }; }
+  else
+    ac_delim="$ac_delim!$ac_delim _$ac_delim!! "
+  fi
+done
+
+# For the awk script, D is an array of macro values keyed by name,
+# likewise P contains macro parameters if any.  Preserve backslash
+# newline sequences.
+
+ac_word_re=[_$as_cr_Letters][_$as_cr_alnum]*
+sed -n '
+s/.\{148\}/&'"$ac_delim"'/g
+t rset
+:rset
+s/^[    ]*#[    ]*define[       ][      ]*/ /
+t def
+d
+:def
+s/\\$//
+t bsnl
+s/["\\]/\\&/g
+s/^ \('"$ac_word_re"'\)\(([^()]*)\)[    ]*\(.*\)/P["\1"]="\2"\
+D["\1"]=" \3"/p
+s/^ \('"$ac_word_re"'\)[        ]*\(.*\)/D["\1"]=" \2"/p
+d
+:bsnl
+s/["\\]/\\&/g
+s/^ \('"$ac_word_re"'\)\(([^()]*)\)[    ]*\(.*\)/P["\1"]="\2"\
+D["\1"]=" \3\\\\\\n"\\/p
+t cont
+s/^ \('"$ac_word_re"'\)[        ]*\(.*\)/D["\1"]=" \2\\\\\\n"\\/p
+t cont
+d
+:cont
+n
+s/.\{148\}/&'"$ac_delim"'/g
+t clear
+:clear
+s/\\$//
+t bsnlc
+s/["\\]/\\&/g; s/^/"/; s/$/"/p
+d
+:bsnlc
+s/["\\]/\\&/g; s/^/"/; s/$/\\\\\\n"\\/p
+b cont
+' <confdefs.h | sed '
+s/'"$ac_delim"'/"\\\
+"/g' >>$CONFIG_STATUS || ac_write_fail=1
+
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+  for (key in D) D_is_set[key] = 1
+  FS = "\a"
+}
+/^[\t ]*#[\t ]*(define|undef)[\t ]+$ac_word_re([\t (]|\$)/ {
+  line = \$ 0
+  split(line, arg, " ")
+  if (arg[1] == "#") {
+    defundef = arg[2]
+    mac1 = arg[3]
+  } else {
+    defundef = substr(arg[1], 2)
+    mac1 = arg[2]
+  }
+  split(mac1, mac2, "(") #)
+  macro = mac2[1]
+  prefix = substr(line, 1, index(line, defundef) - 1)
+  if (D_is_set[macro]) {
+    # Preserve the white space surrounding the "#".
+    print prefix "define", macro P[macro] D[macro]
+    next
+  } else {
+    # Replace #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.
+    if (defundef == "undef") {
+      print "/*", prefix defundef, macro, "*/"
+      next
+    }
+  }
+}
+{ print }
+_ACAWK
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+  { { $as_echo "$as_me:$LINENO: error: could not setup config headers machinery" >&5
+$as_echo "$as_me: error: could not setup config headers machinery" >&2;}
+   { (exit 1); exit 1; }; }
+fi # test -n "$CONFIG_HEADERS"
+
+
+eval set X "  :F $CONFIG_FILES  :H $CONFIG_HEADERS    "
+shift
+for ac_tag
+do
+  case $ac_tag in
+  :[FHLC]) ac_mode=$ac_tag; continue;;
+  esac
+  case $ac_mode$ac_tag in
+  :[FHL]*:*);;
+  :L* | :C*:*) { { $as_echo "$as_me:$LINENO: error: invalid tag $ac_tag" >&5
+$as_echo "$as_me: error: invalid tag $ac_tag" >&2;}
+   { (exit 1); exit 1; }; };;
+  :[FH]-) ac_tag=-:-;;
+  :[FH]*) ac_tag=$ac_tag:$ac_tag.in;;
+  esac
+  ac_save_IFS=$IFS
+  IFS=:
+  set x $ac_tag
+  IFS=$ac_save_IFS
+  shift
+  ac_file=$1
+  shift
+
+  case $ac_mode in
+  :L) ac_source=$1;;
+  :[FH])
+    ac_file_inputs=
+    for ac_f
+    do
+      case $ac_f in
+      -) ac_f="$tmp/stdin";;
+      *) # Look for the file first in the build tree, then in the source tree
+        # (if the path is not absolute).  The absolute path cannot be DOS-style,
+        # because $ac_f cannot contain `:'.
+        test -f "$ac_f" ||
+          case $ac_f in
+          [\\/$]*) false;;
+          *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";;
+          esac ||
+          { { $as_echo "$as_me:$LINENO: error: cannot find input file: $ac_f" >&5
+$as_echo "$as_me: error: cannot find input file: $ac_f" >&2;}
+   { (exit 1); exit 1; }; };;
+      esac
+      case $ac_f in *\'*) ac_f=`$as_echo "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac
+      ac_file_inputs="$ac_file_inputs '$ac_f'"
+    done
+
+    # 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.  */
+    configure_input='Generated from '`
+         $as_echo "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g'
+       `' by configure.'
+    if test x"$ac_file" != x-; then
+      configure_input="$ac_file.  $configure_input"
+      { $as_echo "$as_me:$LINENO: creating $ac_file" >&5
+$as_echo "$as_me: creating $ac_file" >&6;}
+    fi
+    # Neutralize special characters interpreted by sed in replacement strings.
+    case $configure_input in #(
+    *\&* | *\|* | *\\* )
+       ac_sed_conf_input=`$as_echo "$configure_input" |
+       sed 's/[\\\\&|]/\\\\&/g'`;; #(
+    *) ac_sed_conf_input=$configure_input;;
+    esac
+
+    case $ac_tag in
+    *:-:* | *:-) cat >"$tmp/stdin" \
+      || { { $as_echo "$as_me:$LINENO: error: could not create $ac_file" >&5
+$as_echo "$as_me: error: could not create $ac_file" >&2;}
+   { (exit 1); exit 1; }; } ;;
+    esac
+    ;;
+  esac
+
+  ac_dir=`$as_dirname -- "$ac_file" ||
+$as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+        X"$ac_file" : 'X\(//\)[^/]' \| \
+        X"$ac_file" : 'X\(//\)$' \| \
+        X"$ac_file" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$ac_file" |
+    sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+           s//\1/
+           q
+         }
+         /^X\(\/\/\)[^/].*/{
+           s//\1/
+           q
+         }
+         /^X\(\/\/\)$/{
+           s//\1/
+           q
+         }
+         /^X\(\/\).*/{
+           s//\1/
+           q
+         }
+         s/.*/./; q'`
+  { as_dir="$ac_dir"
+  case $as_dir in #(
+  -*) as_dir=./$as_dir;;
+  esac
+  test -d "$as_dir" || { $as_mkdir_p && mkdir -p "$as_dir"; } || {
+    as_dirs=
+    while :; do
+      case $as_dir in #(
+      *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'(
+      *) as_qdir=$as_dir;;
+      esac
+      as_dirs="'$as_qdir' $as_dirs"
+      as_dir=`$as_dirname -- "$as_dir" ||
+$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+        X"$as_dir" : 'X\(//\)[^/]' \| \
+        X"$as_dir" : 'X\(//\)$' \| \
+        X"$as_dir" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$as_dir" |
+    sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+           s//\1/
+           q
+         }
+         /^X\(\/\/\)[^/].*/{
+           s//\1/
+           q
+         }
+         /^X\(\/\/\)$/{
+           s//\1/
+           q
+         }
+         /^X\(\/\).*/{
+           s//\1/
+           q
+         }
+         s/.*/./; q'`
+      test -d "$as_dir" && break
+    done
+    test -z "$as_dirs" || eval "mkdir $as_dirs"
+  } || test -d "$as_dir" || { { $as_echo "$as_me:$LINENO: error: cannot create directory $as_dir" >&5
+$as_echo "$as_me: error: cannot create directory $as_dir" >&2;}
+   { (exit 1); exit 1; }; }; }
+  ac_builddir=.
+
+case "$ac_dir" in
+.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;;
+*)
+  ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'`
+  # A ".." for each directory in $ac_dir_suffix.
+  ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'`
+  case $ac_top_builddir_sub in
+  "") ac_top_builddir_sub=. ac_top_build_prefix= ;;
+  *)  ac_top_build_prefix=$ac_top_builddir_sub/ ;;
+  esac ;;
+esac
+ac_abs_top_builddir=$ac_pwd
+ac_abs_builddir=$ac_pwd$ac_dir_suffix
+# for backward compatibility:
+ac_top_builddir=$ac_top_build_prefix
+
+case $srcdir in
+  .)  # We are building in place.
+    ac_srcdir=.
+    ac_top_srcdir=$ac_top_builddir_sub
+    ac_abs_top_srcdir=$ac_pwd ;;
+  [\\/]* | ?:[\\/]* )  # Absolute name.
+    ac_srcdir=$srcdir$ac_dir_suffix;
+    ac_top_srcdir=$srcdir
+    ac_abs_top_srcdir=$srcdir ;;
+  *) # Relative name.
+    ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix
+    ac_top_srcdir=$ac_top_build_prefix$srcdir
+    ac_abs_top_srcdir=$ac_pwd/$srcdir ;;
+esac
+ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix
+
+
+  case $ac_mode in
+  :F)
+  #
+  # CONFIG_FILE
+  #
+
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+# If the template does not know about datarootdir, expand it.
+# FIXME: This hack should be removed a few years after 2.60.
+ac_datarootdir_hack=; ac_datarootdir_seen=
+
+ac_sed_dataroot='
+/datarootdir/ {
+  p
+  q
+}
+/@datadir@/p
+/@docdir@/p
+/@infodir@/p
+/@localedir@/p
+/@mandir@/p
+'
+case `eval "sed -n \"\$ac_sed_dataroot\" $ac_file_inputs"` in
+*datarootdir*) ac_datarootdir_seen=yes;;
+*@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*)
+  { $as_echo "$as_me:$LINENO: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5
+$as_echo "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;}
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+  ac_datarootdir_hack='
+  s&@datadir@&$datadir&g
+  s&@docdir@&$docdir&g
+  s&@infodir@&$infodir&g
+  s&@localedir@&$localedir&g
+  s&@mandir@&$mandir&g
+    s&\\\${datarootdir}&$datarootdir&g' ;;
+esac
+_ACEOF
+
+# Neutralize VPATH when `$srcdir' = `.'.
+# Shell code in configure.ac might set extrasub.
+# FIXME: do we really want to maintain this feature?
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+ac_sed_extra="$ac_vpsub
+$extrasub
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+:t
+/@[a-zA-Z_][a-zA-Z_0-9]*@/!b
+s|@configure_input@|$ac_sed_conf_input|;t t
+s&@top_builddir@&$ac_top_builddir_sub&;t t
+s&@top_build_prefix@&$ac_top_build_prefix&;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&@abs_top_builddir@&$ac_abs_top_builddir&;t t
+$ac_datarootdir_hack
+"
+eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$tmp/subs.awk" >$tmp/out \
+  || { { $as_echo "$as_me:$LINENO: error: could not create $ac_file" >&5
+$as_echo "$as_me: error: could not create $ac_file" >&2;}
+   { (exit 1); exit 1; }; }
+
+test -z "$ac_datarootdir_hack$ac_datarootdir_seen" &&
+  { ac_out=`sed -n '/\${datarootdir}/p' "$tmp/out"`; test -n "$ac_out"; } &&
+  { ac_out=`sed -n '/^[         ]*datarootdir[  ]*:*=/p' "$tmp/out"`; test -z "$ac_out"; } &&
+  { $as_echo "$as_me:$LINENO: WARNING: $ac_file contains a reference to the variable \`datarootdir'
+which seems to be undefined.  Please make sure it is defined." >&5
+$as_echo "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir'
+which seems to be undefined.  Please make sure it is defined." >&2;}
+
+  rm -f "$tmp/stdin"
+  case $ac_file in
+  -) cat "$tmp/out" && rm -f "$tmp/out";;
+  *) rm -f "$ac_file" && mv "$tmp/out" "$ac_file";;
+  esac \
+  || { { $as_echo "$as_me:$LINENO: error: could not create $ac_file" >&5
+$as_echo "$as_me: error: could not create $ac_file" >&2;}
+   { (exit 1); exit 1; }; }
+ ;;
+  :H)
+  #
+  # CONFIG_HEADER
+  #
+  if test x"$ac_file" != x-; then
+    {
+      $as_echo "/* $configure_input  */" \
+      && eval '$AWK -f "$tmp/defines.awk"' "$ac_file_inputs"
+    } >"$tmp/config.h" \
+      || { { $as_echo "$as_me:$LINENO: error: could not create $ac_file" >&5
+$as_echo "$as_me: error: could not create $ac_file" >&2;}
+   { (exit 1); exit 1; }; }
+    if diff "$ac_file" "$tmp/config.h" >/dev/null 2>&1; then
+      { $as_echo "$as_me:$LINENO: $ac_file is unchanged" >&5
+$as_echo "$as_me: $ac_file is unchanged" >&6;}
+    else
+      rm -f "$ac_file"
+      mv "$tmp/config.h" "$ac_file" \
+       || { { $as_echo "$as_me:$LINENO: error: could not create $ac_file" >&5
+$as_echo "$as_me: error: could not create $ac_file" >&2;}
+   { (exit 1); exit 1; }; }
+    fi
+  else
+    $as_echo "/* $configure_input  */" \
+      && eval '$AWK -f "$tmp/defines.awk"' "$ac_file_inputs" \
+      || { { $as_echo "$as_me:$LINENO: error: could not create -" >&5
+$as_echo "$as_me: error: could not create -" >&2;}
+   { (exit 1); exit 1; }; }
+  fi
+ ;;
+
+
+  esac
+
+done # for ac_tag
+
+
+{ (exit 0); exit 0; }
+_ACEOF
+chmod +x $CONFIG_STATUS
+ac_clean_files=$ac_clean_files_save
+
+test $ac_write_fail = 0 ||
+  { { $as_echo "$as_me:$LINENO: error: write failure creating $CONFIG_STATUS" >&5
+$as_echo "$as_me: error: write failure creating $CONFIG_STATUS" >&2;}
+   { (exit 1); exit 1; }; }
+
+
+# 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
+if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then
+  { $as_echo "$as_me:$LINENO: WARNING: unrecognized options: $ac_unrecognized_opts" >&5
+$as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;}
+fi
+
diff --git a/configure.ac b/configure.ac
new file mode 100644 (file)
index 0000000..9731067
--- /dev/null
@@ -0,0 +1,213 @@
+#      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.15, saord@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_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)
+
+AC_OUTPUT
diff --git a/ctest.c b/ctest.c
new file mode 100644 (file)
index 0000000..b4827d1
--- /dev/null
+++ b/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", &paramlist[6]);
+      *len = 0;
+      *buf = NULL;
+      XPAError(xpa, &paramlist[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", &paramlist[6]);
+      XPAError(xpa, &paramlist[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/dns.c b/dns.c
new file mode 100644 (file)
index 0000000..32e33b1
--- /dev/null
+++ b/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/doc/Makefile b/doc/Makefile
new file mode 100644 (file)
index 0000000..eda8931
--- /dev/null
@@ -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/doc/acl.html b/doc/acl.html
new file mode 100644 (file)
index 0000000..b1f458d
--- /dev/null
@@ -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/doc/changelog.html b/doc/changelog.html
new file mode 100644 (file)
index 0000000..20a1c19
--- /dev/null
@@ -0,0 +1,801 @@
+<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.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/doc/changes.html b/doc/changes.html
new file mode 100644 (file)
index 0000000..8488985
--- /dev/null
@@ -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/doc/client.html b/doc/client.html
new file mode 100644 (file)
index 0000000..5648d85
--- /dev/null
@@ -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 &lt;xpa.h&gt;
+
+  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 &lt;xpa.h&gt;
+</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 &lt;xpa.h&gt;
+
+  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 &lt;xpa.h&gt;
+
+  #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&lt;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 &lt;xpa.h&gt;
+
+  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 &lt;xpa.h&gt;
+
+  #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&lt;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 &lt;xpa.h&gt;
+
+  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 &lt;xpa.h&gt;
+
+  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 &lt;xpa.h&gt;
+  #define NXPA 10
+  int  i, got;
+  int fds[NXPA];
+  char *names[NXPA];
+  char *messages[NXPA];
+  for(i=0; i&lt;NXPA; i++)
+    fds[i] = open(...);
+  got = XPAGetFd(NULL, "ds9", "file", NULL, fds, names, messages, NXPA);
+  for(i=0; i&lt;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 &lt;xpa.h&gt;
+
+  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 &lt;xpa.h&gt;
+
+  #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&lt;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 &lt;xpa.h&gt;
+
+  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 &lt;xpa.h&gt;
+
+  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 &lt;xpa.h&gt;
+
+  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 &lt;xpa.h&gt;
+
+  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 &lt;xpa.h&gt;
+
+  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 &lt;xpa.h&gt;
+
+  char **classes;
+  char **names;
+  char **methods;
+  char **infos;
+  int i, n;
+  n = XPANSLookup(NULL, "foo*", "g", &classes, &names, &methods, &infos);
+  for(i=0; i&lt;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 &lt;xpa.h&gt;
+
+  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/doc/convert.html b/doc/convert.html
new file mode 100644 (file)
index 0000000..a8d0dd2
--- /dev/null
@@ -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/doc/env.html b/doc/env.html
new file mode 100644 (file)
index 0000000..4a71e80
--- /dev/null
@@ -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/doc/examples.html b/doc/examples.html
new file mode 100644 (file)
index 0000000..0bd68d4
--- /dev/null
@@ -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/doc/help.html b/doc/help.html
new file mode 100644 (file)
index 0000000..dfe51f9
--- /dev/null
@@ -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/doc/inet.html b/doc/inet.html
new file mode 100644 (file)
index 0000000..3155885
--- /dev/null
@@ -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/doc/info.html b/doc/info.html
new file mode 100644 (file)
index 0000000..75837bd
--- /dev/null
@@ -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/doc/intro.html b/doc/intro.html
new file mode 100644 (file)
index 0000000..f9c9947
--- /dev/null
@@ -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/doc/method.html b/doc/method.html
new file mode 100644 (file)
index 0000000..d85fc89
--- /dev/null
@@ -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/doc/name.html b/doc/name.html
new file mode 100644 (file)
index 0000000..5269378
--- /dev/null
@@ -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/doc/oom.html b/doc/oom.html
new file mode 100644 (file)
index 0000000..360740e
--- /dev/null
@@ -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/doc/programs.html b/doc/programs.html
new file mode 100644 (file)
index 0000000..b37031f
--- /dev/null
@@ -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>
+  &lt;data&gt; | xpaset  [-h] [-i nsinet] [-m method] [-n] [-p] [-s] [-t sval,lval] [-u users] [-v] &lt;template&gt; [paramlist]
+
+  xpaget  [-h] [-i nsinet] [-m method] [-s] [-t sval,lval] [-u users] &lt;template&gt; [paramlist]
+       
+  xpainfo [-h] [-i nsinet] [-m method] [-n] [-s] [-t sval,lval] [-u users] &lt;template&gt; [paramlist]
+
+  xpaaccess [-c] [-h] [-i nsinet] [-m method] [-n] [-u users] [-v|-V] &lt;template&gt; [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>
+&lt;data&gt; | xpaset  [-h] [-i nsinet] [-m method] [-n] [-p] [-s] [-t sval,lval] [-u users] [-v] &lt;template|host:port&gt; [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] &lt;template|host:port&gt; [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] &lt;template|host:port&gt; [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 &lt;template&gt; [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/doc/server.html b/doc/server.html
new file mode 100644 (file)
index 0000000..2e10b11
--- /dev/null
@@ -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 &lt;xpa.h&gt;
+
+  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 &lt;xpa.h&gt;
+</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 &lt;xpa.h&gt;
+
+  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 &lt;xpa.h&gt;
+
+  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 &lt;xpa.h&gt;
+
+  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 &lt;xpa.h&gt;
+
+  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 &lt;xpa.h&gt;
+
+  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 &lt;xpa.h&gt;
+
+  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 &lt;xpa.h&gt;
+
+  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 &lt;xpa.h&gt;
+
+  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 &lt;xpa.h&gt;
+
+  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 &lt;xpa.h&gt;
+
+  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 &lt;xpa.h&gt;
+
+  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/doc/sman/xpa4.index b/doc/sman/xpa4.index
new file mode 100644 (file)
index 0000000..7c5a98a
Binary files /dev/null and b/doc/sman/xpa4.index differ
diff --git a/doc/sman/xpa4.index.prop b/doc/sman/xpa4.index.prop
new file mode 100644 (file)
index 0000000..0d0dd69
Binary files /dev/null and b/doc/sman/xpa4.index.prop differ
diff --git a/doc/sman/xpa4.index.version b/doc/sman/xpa4.index.version
new file mode 100644 (file)
index 0000000..accb620
--- /dev/null
@@ -0,0 +1,2 @@
+SMAN_DATA_VERSION 1.2
+VERSION 1.01
diff --git a/doc/sman/xpa8.index b/doc/sman/xpa8.index
new file mode 100644 (file)
index 0000000..e9f998c
Binary files /dev/null and b/doc/sman/xpa8.index differ
diff --git a/doc/sman/xpa8.index.prop b/doc/sman/xpa8.index.prop
new file mode 100644 (file)
index 0000000..54b3108
Binary files /dev/null and b/doc/sman/xpa8.index.prop differ
diff --git a/doc/sman/xpa8.index.version b/doc/sman/xpa8.index.version
new file mode 100644 (file)
index 0000000..accb620
--- /dev/null
@@ -0,0 +1,2 @@
+SMAN_DATA_VERSION 1.2
+VERSION 1.01
diff --git a/doc/tcl.html b/doc/tcl.html
new file mode 100644 (file)
index 0000000..8feb46a
--- /dev/null
@@ -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 &lt;option&gt;]
+</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/doc/template.html b/doc/template.html
new file mode 100644 (file)
index 0000000..6a9a0d0
--- /dev/null
@@ -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/doc/users.html b/doc/users.html
new file mode 100644 (file)
index 0000000..a849442
--- /dev/null
@@ -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/doc/xpa.pdf b/doc/xpa.pdf
new file mode 100644 (file)
index 0000000..e2c4855
Binary files /dev/null and b/doc/xpa.pdf differ
diff --git a/doc/xpa.ps b/doc/xpa.ps
new file mode 100644 (file)
index 0000000..21d4910
--- /dev/null
@@ -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/doc/xpamb.html b/doc/xpamb.html
new file mode 100644 (file)
index 0000000..79e46e9
--- /dev/null
@@ -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/doc/xpans.html b/doc/xpans.html
new file mode 100644 (file)
index 0000000..a0aebb2
--- /dev/null
@@ -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/doc/xt.html b/doc/xt.html
new file mode 100644 (file)
index 0000000..2b68604
--- /dev/null
@@ -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/find.c b/find.c
new file mode 100644 (file)
index 0000000..cf4d9ca
--- /dev/null
+++ b/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/find.h b/find.h
new file mode 100644 (file)
index 0000000..96336a0
--- /dev/null
+++ b/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/gtkloop.c b/gtkloop.c
new file mode 100644 (file)
index 0000000..df5137e
--- /dev/null
+++ b/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/install-sh b/install-sh
new file mode 100755 (executable)
index 0000000..36f96f3
--- /dev/null
@@ -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/man/man1/xpaaccess.1 b/man/man1/xpaaccess.1
new file mode 100644 (file)
index 0000000..a3aa7a6
--- /dev/null
@@ -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/man/man1/xpachanges.1 b/man/man1/xpachanges.1
new file mode 100644 (file)
index 0000000..f910bbe
--- /dev/null
@@ -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/man/man1/xpaget.1 b/man/man1/xpaget.1
new file mode 100644 (file)
index 0000000..12d94d9
--- /dev/null
@@ -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/man/man1/xpainfo.1 b/man/man1/xpainfo.1
new file mode 100644 (file)
index 0000000..2ad7f81
--- /dev/null
@@ -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/man/man1/xpamb.1 b/man/man1/xpamb.1
new file mode 100644 (file)
index 0000000..37f06f4
--- /dev/null
@@ -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/man/man1/xpans.1 b/man/man1/xpans.1
new file mode 100644 (file)
index 0000000..3573725
--- /dev/null
@@ -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/man/man1/xpaset.1 b/man/man1/xpaset.1
new file mode 100644 (file)
index 0000000..943a708
--- /dev/null
@@ -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/man/man3/xpaaccess.3 b/man/man3/xpaaccess.3
new file mode 100644 (file)
index 0000000..a7e25e8
--- /dev/null
@@ -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/man/man3/xpaatexit.3 b/man/man3/xpaatexit.3
new file mode 100644 (file)
index 0000000..4ff2c7d
--- /dev/null
@@ -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/man/man3/xpacleanup.3 b/man/man3/xpacleanup.3
new file mode 100644 (file)
index 0000000..57ec12e
--- /dev/null
@@ -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/man/man3/xpaclient.3 b/man/man3/xpaclient.3
new file mode 100644 (file)
index 0000000..804f57b
--- /dev/null
@@ -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/man/man3/xpaclose.3 b/man/man3/xpaclose.3
new file mode 100644 (file)
index 0000000..15e5941
--- /dev/null
@@ -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/man/man3/xpacmdadd.3 b/man/man3/xpacmdadd.3
new file mode 100644 (file)
index 0000000..9c4b7e5
--- /dev/null
@@ -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/man/man3/xpacmddel.3 b/man/man3/xpacmddel.3
new file mode 100644 (file)
index 0000000..21bf0be
--- /dev/null
@@ -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/man/man3/xpacmdnew.3 b/man/man3/xpacmdnew.3
new file mode 100644 (file)
index 0000000..8a1cb94
--- /dev/null
@@ -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/man/man3/xpafree.3 b/man/man3/xpafree.3
new file mode 100644 (file)
index 0000000..53783eb
--- /dev/null
@@ -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/man/man3/xpaget.3 b/man/man3/xpaget.3
new file mode 100644 (file)
index 0000000..4f03cf6
--- /dev/null
@@ -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/man/man3/xpagetfd.3 b/man/man3/xpagetfd.3
new file mode 100644 (file)
index 0000000..1899880
--- /dev/null
@@ -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/man/man3/xpainfo.3 b/man/man3/xpainfo.3
new file mode 100644 (file)
index 0000000..4f51a05
--- /dev/null
@@ -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/man/man3/xpainfonew.3 b/man/man3/xpainfonew.3
new file mode 100644 (file)
index 0000000..bab9739
--- /dev/null
@@ -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/man/man3/xpamacros.3 b/man/man3/xpamacros.3
new file mode 100644 (file)
index 0000000..c9a6ab5
--- /dev/null
@@ -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/man/man3/xpamainloop.3 b/man/man3/xpamainloop.3
new file mode 100644 (file)
index 0000000..ff01099
--- /dev/null
@@ -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/man/man3/xpanew.3 b/man/man3/xpanew.3
new file mode 100644 (file)
index 0000000..f4f72b6
--- /dev/null
@@ -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/man/man3/xpanslookup.3 b/man/man3/xpanslookup.3
new file mode 100644 (file)
index 0000000..8725e3e
--- /dev/null
@@ -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/man/man3/xpaopen.3 b/man/man3/xpaopen.3
new file mode 100644 (file)
index 0000000..c62af06
--- /dev/null
@@ -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/man/man3/xpapoll.3 b/man/man3/xpapoll.3
new file mode 100644 (file)
index 0000000..61d3c28
--- /dev/null
@@ -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/man/man3/xparace.3 b/man/man3/xparace.3
new file mode 100644 (file)
index 0000000..6100196
--- /dev/null
@@ -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/man/man3/xpaserver.3 b/man/man3/xpaserver.3
new file mode 100644 (file)
index 0000000..a0803aa
--- /dev/null
@@ -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/man/man3/xpaset.3 b/man/man3/xpaset.3
new file mode 100644 (file)
index 0000000..d9dd7c0
--- /dev/null
@@ -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/man/man3/xpasetfd.3 b/man/man3/xpasetfd.3
new file mode 100644 (file)
index 0000000..5017a38
--- /dev/null
@@ -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/man/mann/xpa.n b/man/mann/xpa.n
new file mode 100644 (file)
index 0000000..189a601
--- /dev/null
@@ -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/man/mann/xpaacl.n b/man/mann/xpaacl.n
new file mode 100644 (file)
index 0000000..d339c5d
--- /dev/null
@@ -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/man/mann/xpacode.n b/man/mann/xpacode.n
new file mode 100644 (file)
index 0000000..b13c7ae
--- /dev/null
@@ -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/man/mann/xpacommon.n b/man/mann/xpacommon.n
new file mode 100644 (file)
index 0000000..1a456ed
--- /dev/null
@@ -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/man/mann/xpaconvert.n b/man/mann/xpaconvert.n
new file mode 100644 (file)
index 0000000..035ef0b
--- /dev/null
@@ -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/man/mann/xpaenv.n b/man/mann/xpaenv.n
new file mode 100644 (file)
index 0000000..ead081c
--- /dev/null
@@ -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/man/mann/xpainet.n b/man/mann/xpainet.n
new file mode 100644 (file)
index 0000000..4847654
--- /dev/null
@@ -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/man/mann/xpaintro.n b/man/mann/xpaintro.n
new file mode 100644 (file)
index 0000000..2978e6b
--- /dev/null
@@ -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/man/mann/xpamethod.n b/man/mann/xpamethod.n
new file mode 100644 (file)
index 0000000..faecd86
--- /dev/null
@@ -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/man/mann/xpaname.n b/man/mann/xpaname.n
new file mode 100644 (file)
index 0000000..cdb6839
--- /dev/null
@@ -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/man/mann/xpaoom.n b/man/mann/xpaoom.n
new file mode 100644 (file)
index 0000000..9dfdc3f
--- /dev/null
@@ -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/man/mann/xpatcl.n b/man/mann/xpatcl.n
new file mode 100644 (file)
index 0000000..9156d5e
--- /dev/null
@@ -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/man/mann/xpatemplate.n b/man/mann/xpatemplate.n
new file mode 100644 (file)
index 0000000..f8fc55a
--- /dev/null
@@ -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/man/mann/xpausers.n b/man/mann/xpausers.n
new file mode 100644 (file)
index 0000000..2823e3d
--- /dev/null
@@ -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/man/mann/xpaxt.n b/man/mann/xpaxt.n
new file mode 100644 (file)
index 0000000..8885dd4
--- /dev/null
@@ -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/mklib b/mklib
new file mode 100755 (executable)
index 0000000..c900b3e
--- /dev/null
+++ b/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/oxpa.h b/oxpa.h
new file mode 100644 (file)
index 0000000..40804b2
--- /dev/null
+++ b/oxpa.h
@@ -0,0 +1,553 @@
+/*
+ *     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>
+
+#define XPA_MAJOR_VERSION 2
+#define XPA_MINOR_VERSION 1
+#define XPA_PATCH_LEVEL 14
+#define XPA_VERSION "2.1.14"
+
+/* #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,
+    int  *len
+#endif
+);
+
+typedef int (*ReceiveCb)(
+#ifdef ANSI_FUNC
+    void *client_data,
+    void *call_data,
+    char *paramlist,
+    char *buf,
+    int  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;
+  int 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;
+  int start;
+  int end;
+  int 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;
+  int  *lenptr;
+  int bufsize;
+  int fd;
+  /* xpaset parameters */
+  char *buf;
+  int len;
+  int 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() */
+  int 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, int 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, int *len));
+int XPAReceiveLTimeout _PRx((void *client_data, void *call_data,
+                            char *paramlist, char *buf, int len));
+int XPASendSTimeout _PRx((void *client_data, void *call_data,
+                         char *paramlist, char **buf, int *len));
+int XPAReceiveSTimeout _PRx((void *client_data, void *call_data,
+                            char *paramlist, char *buf, int 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, int len));
+int XPASendCommands _PRx((void *client_data, void *call_data,
+                         char *paramlist, char **buf, int *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, int len));
+int XPACmdInternalSend _PRx((void *client_data, void *call_data,
+                            char *paramlist, char **buf, int *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, int *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, int 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, int len));
+int XPASendAcl _PRx((void *client_data, void *call_data,
+                    char *paramlist, char **buf, int *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, int len));
+int XPASendRemote _PRx((void *client_data, void *call_data,
+                       char *paramlist, char **buf, int *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, int len));
+int XPASendClipboard _PRx((void *client_data, void *call_data,
+                          char *paramlist, char **buf, int *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, int *len, int timeout));
+int XPAPutBuf _PRx((XPA xpa, int fd, char *buf, int 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/pkgIndex.tcl b/pkgIndex.tcl
new file mode 100644 (file)
index 0000000..75d2435
--- /dev/null
@@ -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/port.c b/port.c
new file mode 100644 (file)
index 0000000..f3751ac
--- /dev/null
+++ b/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/prsetup.h b/prsetup.h
new file mode 100644 (file)
index 0000000..0314171
--- /dev/null
+++ b/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/remote.c b/remote.c
new file mode 100644 (file)
index 0000000..1b1689c
--- /dev/null
+++ b/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/rtest.c b/rtest.c
new file mode 100644 (file)
index 0000000..348711b
--- /dev/null
+++ b/rtest.c
@@ -0,0 +1,224 @@
+/*
+ *     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;
+  int verbose=0;
+  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':
+      verbose = 1;
+      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/saoconfig b/saoconfig
new file mode 100755 (executable)
index 0000000..64534d1
--- /dev/null
+++ b/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" $*
+  ;;
+
+  jove*)
+  ./configure  $CF                                     \
+               --prefix=${HOME}                        \
+               CC=icc 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/stest.c b/stest.c
new file mode 100644 (file)
index 0000000..afceb89
--- /dev/null
+++ b/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", &paramlist[6]);
+      *len = 0;
+      *buf = NULL;
+      if( strlen(paramlist) > 6 )
+       XPAError(xpa, &paramlist[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", &paramlist[5]);
+       /* child forks a command and exits */
+       if(!(fork())){
+         system(&paramlist[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", &paramlist[6]);
+      if( strlen(paramlist) > 6 )
+       XPAError(xpa, &paramlist[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", &paramlist[5]);
+       /* child forks a command and exits */
+       if(!(fork())){
+         system(&paramlist[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/tcl.c b/tcl.c
new file mode 100644 (file)
index 0000000..8d104bf
--- /dev/null
+++ b/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, int len)
+#else
+static int XPATclReceive(client_data, call_data, paramlist, buf, len)
+     void *client_data;
+     void *call_data;
+     char *paramlist;
+     char *buf;
+     int 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, int *len)
+#else
+static int XPATclSend(client_data, call_data, paramlist, buf, len)
+     void *client_data;
+     void *call_data;
+     char *paramlist;
+     char **buf;
+     int *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)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)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;
+  size_t 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  =   (int *)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;
+  size_t 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 */
+Tclxpa_Unload() {}
+Tclxpa_SafeUnload() {}
+Tclxpa_SafeInit() {}
+
+
+int xpa_tclbinding = 1;
+
+#else
+
+int xpa_tclbinding = 0;
+
+#endif
diff --git a/tcl.m4 b/tcl.m4
new file mode 100644 (file)
index 0000000..8125361
--- /dev/null
+++ b/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/tclloop.c b/tclloop.c
new file mode 100644 (file)
index 0000000..7c26818
--- /dev/null
+++ b/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
+#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/tcp.c b/tcp.c
new file mode 100644 (file)
index 0000000..ddd4366
--- /dev/null
+++ b/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/tcp.h b/tcp.h
new file mode 100644 (file)
index 0000000..c22b874
--- /dev/null
+++ b/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/test.tcl b/test.tcl
new file mode 100644 (file)
index 0000000..bfc413c
--- /dev/null
+++ b/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/timedconn.c b/timedconn.c
new file mode 100644 (file)
index 0000000..ff8202f
--- /dev/null
@@ -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/timedconn.h b/timedconn.h
new file mode 100644 (file)
index 0000000..e46e69d
--- /dev/null
@@ -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/tsj.c b/tsj.c
new file mode 100644 (file)
index 0000000..93cf853
--- /dev/null
+++ b/tsj.c
@@ -0,0 +1,49 @@
+/* gcc -g -Wall -o tsj tsj.c -I. -L. -lxpa */
+#include <xpa.h>
+#include <string.h>
+#include <setjmp.h>
+
+#define MAXB 1024
+#define GB (1024 * 1024 * 1024)
+
+char *xmalloc(int size);
+void xfree(char *buf);
+
+int main(int argc, char **argv)
+{
+  char iter=0;
+  int i=0;
+  int n=0;
+  char tbuf[100];
+  char *bufs[MAXB];
+  jmp_buf env;
+
+loop:
+  iter++;
+  if( setjmp(env) == 0 ){
+    XPASaveJmp((void *)env);
+    fprintf(stdout, "continue? ");
+    fgets(tbuf, 99, stdin);
+    if( *tbuf != 'y' ){
+      fprintf(stdout, "exiting ...\n");
+      return 0;
+    }
+    else{
+      fprintf(stderr, "allocating ...\n");
+      for(n=0; n<MAXB; n++){
+       bufs[n] = (char *)xmalloc(GB);
+       memset(bufs[n], iter, GB);
+       fprintf(stderr, "%d\n", n);
+      }
+    }
+  }
+  else{
+    for(i=0; i<n+1; i++){
+      if( bufs[i] ) xfree(bufs[i]);
+    }
+    n = 0;
+    fprintf(stderr, "freed up memory for next iteration\n");
+    goto loop;
+  }
+  return 0;
+}
diff --git a/word.c b/word.c
new file mode 100644 (file)
index 0000000..2d60eb0
--- /dev/null
+++ b/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/word.h b/word.h
new file mode 100644 (file)
index 0000000..5778574
--- /dev/null
+++ b/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/xalloc.c b/xalloc.c
new file mode 100644 (file)
index 0000000..18234db
--- /dev/null
+++ b/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/xalloc.h b/xalloc.h
new file mode 100644 (file)
index 0000000..c25fb32
--- /dev/null
+++ b/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/xlaunch.c b/xlaunch.c
new file mode 100644 (file)
index 0000000..9f064d1
--- /dev/null
+++ b/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/xlaunch.h b/xlaunch.h
new file mode 100644 (file)
index 0000000..d6488ea
--- /dev/null
+++ b/xlaunch.h
@@ -0,0 +1,84 @@
+/*
+ *     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_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.c b/xpa.c
new file mode 100644 (file)
index 0000000..2454d64
--- /dev/null
+++ b/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.h b/xpa.h
new file mode 100644 (file)
index 0000000..c89ad55
--- /dev/null
+++ b/xpa.h
@@ -0,0 +1,560 @@
+/*
+ *     Copyright (c) 1999-2003 Smithsonian Astrophysical Observatory
+ */
+
+/*
+ *
+ * xpa.h - include file for the X Public Access mechanism
+ *
+ */
+
+#ifndef        __xpa_h
+#define        __xpa_h
+
+#if HAVE_CONFIG_H
+#include <conf.h>
+#endif
+
+#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 15
+#define XPA_VERSION "2.1.15"
+
+/* #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/xpaaccess.c b/xpaaccess.c
new file mode 100644 (file)
index 0000000..81643ac
--- /dev/null
@@ -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/xpaget.c b/xpaget.c
new file mode 100644 (file)
index 0000000..ea70121
--- /dev/null
+++ b/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/xpainfo.c b/xpainfo.c
new file mode 100644 (file)
index 0000000..6436703
--- /dev/null
+++ b/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/xpaio.c b/xpaio.c
new file mode 100644 (file)
index 0000000..a5e7473
--- /dev/null
+++ b/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/xpamb.c b/xpamb.c
new file mode 100644 (file)
index 0000000..4e58fb5
--- /dev/null
+++ b/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, &paramlist[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/xpans.c b/xpans.c
new file mode 100644 (file)
index 0000000..af727aa
--- /dev/null
+++ b/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/xpap.h b/xpap.h
new file mode 100644 (file)
index 0000000..f679758
--- /dev/null
+++ b/xpap.h
@@ -0,0 +1,230 @@
+/*
+ *     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_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>
+#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/xpaset.c b/xpaset.c
new file mode 100644 (file)
index 0000000..4e4d8c2
--- /dev/null
+++ b/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/xport.h b/xport.h
new file mode 100644 (file)
index 0000000..73b4508
--- /dev/null
+++ b/xport.h
@@ -0,0 +1,136 @@
+/*
+ *     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>
+
+#ifndef        EINPROGRESS
+#define EINPROGRESS    WSAEINPROGRESS
+#endif
+#ifndef        EINTR
+#define EINTR          WSAEINTR
+#endif
+#ifndef ETIMEDOUT
+#define ETIMEDOUT      WSAETIMEDOUT
+#endif
+#ifndef ECONNREFUSED
+#define ECONNREFUSED   WSAECONNREFUSED
+#endif
+#ifndef EWOULDBLOCK
+#define EWOULDBLOCK    WSAEWOULDBLOCK
+#endif
+#ifndef EAGAIN
+#define EAGAIN         WSAEWOULDBLOCK
+#endif
+
+#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/xtloop.c b/xtloop.c
new file mode 100644 (file)
index 0000000..f712a9e
--- /dev/null
+++ b/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