From ce67d0cdeaa37c3e856e23ae4010480887165630 Mon Sep 17 00:00:00 2001 From: Reto Zingg Date: Tue, 7 Apr 2009 22:54:49 +0300 Subject: [PATCH] initial load of upstream version 1.06.32 --- .cvsignore | 17 + GNUmakefile | 121 + Makefile | 14 + Makefile.common | 452 + Makefile.config.in | 253 + README | 55 + Windows/.cvsignore | 9 + Windows/ConfigureWin32.bat | 7 + Windows/ReadMeWin32.txt | 116 + Windows/UsingCURLinWin32.txt | 64 + Windows/abyss.dsp | 140 + Windows/all.dsp | 97 + Windows/all.vcproj | 67 + Windows/configwin32.dsp | 97 + Windows/configwin32.vcproj | 71 + Windows/cpptest.dsp | 102 + Windows/cpptest.vcproj | 168 + Windows/query_meerkat.dsp | 100 + Windows/query_meerkat.vcproj | 168 + Windows/rpctest.dsp | 236 + Windows/rpctest.vcproj | 574 ++ Windows/transport_config_win32.h | 26 + Windows/win32_config.h | 2 + Windows/xmlrpc.dsp | 258 + Windows/xmlrpc.dsw | 194 + Windows/xmlrpc.sln | 229 + Windows/xmlrpc.vcproj | 1013 ++ Windows/xmlrpc_sample_add_asynch_client.dsp | 102 + Windows/xmlrpc_sample_add_asynch_client.vcproj | 168 + Windows/xmlrpc_sample_add_server.dsp | 140 + Windows/xmlrpc_sample_add_server.vcproj | 338 + Windows/xmlrpc_sample_add_server_w32httpsys.dsp | 104 + Windows/xmlrpc_sample_add_server_w32httpsys.vcproj | 168 + Windows/xmlrpc_sample_add_sync_client.dsp | 104 + Windows/xmlrpc_sample_add_sync_client.vcproj | 168 + Windows/xmlrpc_sample_auth_client.dsp | 104 + Windows/xmlrpc_sample_auth_client.vcproj | 168 + Windows/xmlrpc_win32_config.h | 130 + aclocal.m4 | 545 ++ autom4te.cache/output.0 | 7573 +++++++++++++++ autom4te.cache/requests | 225 + autom4te.cache/traces.0 | 286 + conf/abyss_root/conf/abyss.conf | 56 + conf/abyss_root/conf/mime.types | 276 + conf/abyss_root/htdocs/index.htm | 21 + conf/abyss_root/htdocs/pwrabyss.gif | Bin 0 -> 2198 bytes config.guess | 1459 +++ config.sub | 1549 +++ configure | 7573 +++++++++++++++ configure.in | 650 ++ doc/COPYING | 143 + doc/CREDITS | 19 + doc/DEVELOPING | 82 + doc/HISTORY | 61 + doc/INSTALL | 129 + doc/SECURITY | 50 + doc/TESTING | 96 + doc/TODO | 71 + doc/configure_doc | 189 + examples/.cvsignore | 13 + examples/Makefile | 141 + examples/README | 34 + examples/auth_client.c | 80 + examples/cpp/.cvsignore | 6 + examples/cpp/Makefile | 98 + examples/cpp/meerkat-app-list.cpp | 106 + examples/cpp/sample_add_client_complex.cpp | 71 + examples/cpp/xmlrpc_inetd_server.cpp | 65 + examples/cpp/xmlrpc_loop_server.cpp | 68 + examples/cpp/xmlrpc_sample_add_client.cpp | 39 + examples/cpp/xmlrpc_sample_add_server.cpp | 60 + examples/gen_sample_add_xml.c | 73 + examples/query-meerkat.c | 156 + examples/synch_client.c | 66 + examples/xmlrpc_asynch_client.c | 122 + examples/xmlrpc_inetd_server.c | 106 + examples/xmlrpc_loop_server.c | 134 + examples/xmlrpc_sample_add_client.c | 76 + examples/xmlrpc_sample_add_server.c | 80 + examples/xmlrpc_sample_add_server_cgi.c | 57 + examples/xmlrpc_sample_add_server_w32httpsys.c | 190 + examples/xmlrpc_server_validatee.c | 402 + examples/xmlrpc_socket_server.c | 91 + include/Makefile | 79 + include/xmlrpc-c/.cvsignore | 1 + include/xmlrpc-c/abyss.h | 527 ++ include/xmlrpc-c/base.h | 616 ++ include/xmlrpc-c/base.hpp | 312 + include/xmlrpc-c/base64.hpp | 25 + include/xmlrpc-c/base_int.h | 176 + include/xmlrpc-c/client.h | 246 + include/xmlrpc-c/client.hpp | 283 + include/xmlrpc-c/client_global.h | 141 + include/xmlrpc-c/client_int.h | 102 + include/xmlrpc-c/client_simple.hpp | 44 + include/xmlrpc-c/client_transport.hpp | 342 + include/xmlrpc-c/girerr.hpp | 31 + include/xmlrpc-c/girmem.hpp | 74 + include/xmlrpc-c/oldcppwrapper.hpp | 419 + include/xmlrpc-c/oldxmlrpc.h | 2 + include/xmlrpc-c/registry.hpp | 175 + include/xmlrpc-c/server.h | 122 + include/xmlrpc-c/server_abyss.h | 211 + include/xmlrpc-c/server_abyss.hpp | 117 + include/xmlrpc-c/server_cgi.h | 49 + include/xmlrpc-c/server_w32httpsys.h | 95 + include/xmlrpc-c/sleep_int.h | 7 + include/xmlrpc-c/string_int.h | 60 + include/xmlrpc-c/timeout.hpp | 20 + include/xmlrpc-c/transport.h | 81 + include/xmlrpc-c/util.h | 313 + include/xmlrpc-c/util_int.h | 13 + include/xmlrpc-c/xml.hpp | 30 + include/xmlrpc-c/xmlparser.h | 97 + install-sh | 251 + lib/Makefile | 52 + lib/abyss/Makefile | 38 + lib/abyss/README | 23 + lib/abyss/change.log | 34 + lib/abyss/conf/abyss.conf | 56 + lib/abyss/conf/mime.types | 276 + lib/abyss/htdocs/index.htm | 21 + lib/abyss/htdocs/pwrabyss.gif | Bin 0 -> 2198 bytes lib/abyss/license.txt | 27 + lib/abyss/patch_notes.txt | 114 + lib/abyss/readme.txt | 160 + lib/abyss/src/Abyss.dsp | 134 + lib/abyss/src/Abyss.dsw | 29 + lib/abyss/src/Makefile | 73 + lib/abyss/src/abyss_info.h | 20 + lib/abyss/src/conf.c | 379 + lib/abyss/src/conn.c | 637 ++ lib/abyss/src/conn.h | 98 + lib/abyss/src/data.c | 640 ++ lib/abyss/src/data.h | 124 + lib/abyss/src/date.c | 192 + lib/abyss/src/date.h | 34 + lib/abyss/src/file.c | 244 + lib/abyss/src/file.h | 130 + lib/abyss/src/http.c | 857 ++ lib/abyss/src/http.h | 46 + lib/abyss/src/main.c | 243 + lib/abyss/src/response.c | 657 ++ lib/abyss/src/server.c | 1794 ++++ lib/abyss/src/server.h | 78 + lib/abyss/src/session.c | 137 + lib/abyss/src/session.h | 60 + lib/abyss/src/socket.c | 230 + lib/abyss/src/socket.h | 149 + lib/abyss/src/socket_unix.c | 501 + lib/abyss/src/socket_unix.h | 10 + lib/abyss/src/socket_win.c | 456 + lib/abyss/src/socket_win.h | 10 + lib/abyss/src/thread.h | 70 + lib/abyss/src/thread_fork.c | 323 + lib/abyss/src/thread_pthread.c | 221 + lib/abyss/src/thread_windows.c | 167 + lib/abyss/src/token.c | 54 + lib/abyss/src/token.h | 11 + lib/abyss/src/trace.c | 78 + lib/abyss/src/trace.h | 11 + lib/abyss/version.txt | 1 + lib/curl_transport/Makefile | 51 + lib/curl_transport/xmlrpc_curl_transport.c | 1864 ++++ lib/curl_transport/xmlrpc_curl_transport.h | 8 + lib/expat/Makefile | 36 + lib/expat/expat.dsw | 75 + lib/expat/expat.html | 86 + lib/expat/gennmtab/.cvsignore | 1 + lib/expat/gennmtab/Makefile | 45 + lib/expat/gennmtab/gennmtab.c | 433 + lib/expat/gennmtab/gennmtab.dsp | 110 + lib/expat/xmlparse/Makefile | 57 + lib/expat/xmlparse/xmlparse.c | 4057 ++++++++ lib/expat/xmlparse/xmlparse.dsp | 279 + lib/expat/xmlparse/xmlparse.h | 552 ++ lib/expat/xmltok/.cvsignore | 1 + lib/expat/xmltok/Makefile | 66 + lib/expat/xmltok/ascii.h | 86 + lib/expat/xmltok/asciitab.h | 37 + lib/expat/xmltok/dllmain.c | 15 + lib/expat/xmltok/iasciitab.h | 38 + lib/expat/xmltok/latin1tab.h | 37 + lib/expat/xmltok/utf8tab.h | 38 + lib/expat/xmltok/xmldef.h | 52 + lib/expat/xmltok/xmlrole.c | 1266 +++ lib/expat/xmltok/xmlrole.h | 99 + lib/expat/xmltok/xmltok.c | 1561 ++++ lib/expat/xmltok/xmltok.dsp | 259 + lib/expat/xmltok/xmltok.h | 327 + lib/expat/xmltok/xmltok_impl.c | 1774 ++++ lib/expat/xmltok/xmltok_impl.h | 46 + lib/expat/xmltok/xmltok_ns.c | 96 + lib/expat/xmlwf/.cvsignore | 1 + lib/expat/xmlwf/Makefile.in | 209 + lib/expat/xmlwf/codepage.c | 65 + lib/expat/xmlwf/codepage.h | 7 + lib/expat/xmlwf/filemap.h | 17 + lib/expat/xmlwf/readfilemap.c | 74 + lib/expat/xmlwf/unixfilemap.c | 57 + lib/expat/xmlwf/win32filemap.c | 95 + lib/expat/xmlwf/xmlfile.c | 217 + lib/expat/xmlwf/xmlfile.h | 11 + lib/expat/xmlwf/xmltchar.h | 36 + lib/expat/xmlwf/xmlwf.c | 766 ++ lib/expat/xmlwf/xmlwf.dsp | 136 + lib/libutil/Makefile | 71 + lib/libutil/casprintf.c | 93 + lib/libutil/error.c | 158 + lib/libutil/make_printable.c | 100 + lib/libutil/memblock.c | 214 + lib/libutil/resource.c | 31 + lib/libutil/sleep.c | 18 + lib/libwww_transport/Makefile | 45 + lib/libwww_transport/xmlrpc_libwww_transport.c | 937 ++ lib/libwww_transport/xmlrpc_libwww_transport.h | 8 + lib/util/Makefile | 52 + lib/util/casprintf.c | 93 + lib/util/cmdline_parser.c | 449 + lib/util/getoptx.c | 466 + lib/util/getoptx.h | 51 + lib/util/include/bool.h | 18 + lib/util/include/c_util.h | 20 + lib/util/include/casprintf.h | 21 + lib/util/include/cmdline_parser.h | 59 + lib/util/include/girmath.h | 8 + lib/util/include/girstring.h | 47 + lib/util/include/inline.h | 19 + lib/util/include/linklist.h | 193 + lib/util/include/mallocvar.h | 100 + lib/util/include/pthreadx.h | 68 + lib/util/include/unistdx.h | 14 + lib/util/pthreadx_win32.c | 101 + lib/wininet_transport/Makefile | 40 + lib/wininet_transport/xmlrpc_wininet_transport.c | 919 ++ lib/wininet_transport/xmlrpc_wininet_transport.h | 8 + ltconfig | 3078 ++++++ ltmain.sh | 4012 ++++++++ missing | 190 + mkinstalldirs | 40 + src/.cvsignore | 5 + src/Makefile | 203 + src/cpp/Makefile | 190 + src/cpp/XmlRpcCpp.cpp | 395 + src/cpp/base64.cpp | 234 + src/cpp/client.cpp | 962 ++ src/cpp/client_simple.cpp | 169 + src/cpp/curl.cpp | 285 + src/cpp/dll.make | 13 + src/cpp/dylib.make | 21 + src/cpp/env_wrap.cpp | 18 + src/cpp/env_wrap.hpp | 26 + src/cpp/fault.cpp | 35 + src/cpp/girerr.cpp | 28 + src/cpp/girmem.cpp | 156 + src/cpp/irix.make | 22 + src/cpp/libwww.cpp | 160 + src/cpp/outcome.cpp | 57 + src/cpp/param_list.cpp | 259 + src/cpp/registry.cpp | 365 + src/cpp/server_abyss.cpp | 372 + src/cpp/test/.cvsignore | 1 + src/cpp/test/Makefile | 91 + src/cpp/test/server_abyss.cpp | 215 + src/cpp/test/server_abyss.hpp | 8 + src/cpp/test/test.cpp | 820 ++ src/cpp/test/testclient.cpp | 643 ++ src/cpp/test/testclient.hpp | 9 + src/cpp/test/testclient_dummy.cpp | 29 + src/cpp/test/tools.cpp | 64 + src/cpp/test/tools.hpp | 72 + src/cpp/unix.make | 23 + src/cpp/value.cpp | 768 ++ src/cpp/wininet.cpp | 168 + src/cpp/xml.cpp | 168 + src/registry.c | 492 + src/registry.h | 30 + src/system_method.c | 807 ++ src/system_method.h | 14 + src/test/.cvsignore | 2 + src/test/Makefile | 93 + src/test/cgi.c | 60 + src/test/cgi.h | 2 + src/test/cgitest1.c | 79 + src/test/client.c | 255 + src/test/client.h | 2 + src/test/client_dummy.c | 14 + src/test/data/req_no_params.xml | 9 + src/test/data/req_out_of_order.xml | 12 + src/test/data/req_value_name.xml | 14 + src/test/data/sample_add_call.xml | 8 + src/test/eftest_wrapper.sh | 17 + src/test/http-req-simple.txt | 11 + src/test/method_registry.c | 524 ++ src/test/method_registry.h | 7 + src/test/parse_xml.c | 388 + src/test/parse_xml.h | 2 + src/test/req_no_params.xml | 9 + src/test/serialize.c | 283 + src/test/serialize.h | 2 + src/test/server_abyss.c | 92 + src/test/server_abyss.h | 2 + src/test/test.c | 741 ++ src/test/test.h | 75 + src/test/value.c | 1326 +++ src/test/value.h | 2 + src/test/xml_data.c | 196 + src/test/xml_data.h | 25 + src/trace.c | 62 + src/xmlrpc_array.c | 255 + src/xmlrpc_authcookie.c | 85 + src/xmlrpc_base64.c | 266 + src/xmlrpc_builddecomp.c | 971 ++ src/xmlrpc_client.c | 1011 ++ src/xmlrpc_client_global.c | 414 + src/xmlrpc_data.c | 852 ++ src/xmlrpc_datetime.c | 480 + src/xmlrpc_expat.c | 480 + src/xmlrpc_libxml2.c | 427 + src/xmlrpc_parse.c | 990 ++ src/xmlrpc_serialize.c | 611 ++ src/xmlrpc_server_abyss.c | 1201 +++ src/xmlrpc_server_cgi.c | 323 + src/xmlrpc_server_w32httpsys.c | 924 ++ src/xmlrpc_struct.c | 610 ++ src/xmlrpc_utf8.c | 386 + stamp-h.in | 1 + tools/.cvsignore | 1 + tools/Makefile | 33 + tools/Makefile.common | 36 + tools/binmode-rpc-kit/COPYING | 24 + tools/binmode-rpc-kit/Makefile | 5 + tools/binmode-rpc-kit/README | 31 + tools/binmode-rpc-kit/binmode-rpc-rfc.txt | 338 + tools/binmode-rpc-kit/binmode-rpc2xml-rpc | 552 ++ tools/binmode-rpc-kit/examples/good-1.binmode | Bin 0 -> 80 bytes tools/binmode-rpc-kit/examples/good-1.xml | 32 + tools/binmode-rpc-kit/examples/good-2.binmode | Bin 0 -> 36 bytes tools/binmode-rpc-kit/examples/good-2.xml | 12 + tools/binmode-rpc-kit/examples/good-3.binmode | Bin 0 -> 18 bytes tools/binmode-rpc-kit/examples/good-3.xml | 8 + tools/binmode-rpc-kit/examples/good-4.binmode | Bin 0 -> 76 bytes tools/binmode-rpc-kit/examples/good-4.xml | 17 + tools/binmode-rpc-kit/examples/good-5.binmode | Bin 0 -> 51 bytes tools/binmode-rpc-kit/examples/good-5.xml | 19 + tools/binmode-rpc-kit/examples/good-6.binmode | Bin 0 -> 52 bytes tools/binmode-rpc-kit/examples/good-6.xml | 8 + tools/binmode-rpc-kit/examples/invalid-1.binmode | Bin 0 -> 19 bytes tools/binmode-rpc-kit/examples/invalid-2.binmode | Bin 0 -> 33 bytes tools/binmode-rpc-kit/examples/invalid-3.binmode | 1 + tools/binmode-rpc-kit/examples/invalid-4.binmode | Bin 0 -> 51 bytes tools/binmode-rpc-kit/examples/invalid-5.binmode | Bin 0 -> 51 bytes tools/binmode-rpc-kit/oct2bin | 12 + tools/interop-server/interop-cgi.c | 215 + tools/turbocharger/.cvsignore | 1 + tools/turbocharger/Makefile | 5 + tools/turbocharger/README | 37 + tools/turbocharger/mod_gzip.c | 9843 ++++++++++++++++++++ tools/turbocharger/mod_gzip.c.diff | 365 + tools/xml-rpc-api2cpp/.cvsignore | 1 + tools/xml-rpc-api2cpp/DataType.cpp | 195 + tools/xml-rpc-api2cpp/DataType.hpp | 43 + tools/xml-rpc-api2cpp/Makefile | 67 + tools/xml-rpc-api2cpp/README | 6 + tools/xml-rpc-api2cpp/SystemProxy.cpp | 39 + tools/xml-rpc-api2cpp/SystemProxy.hpp | 48 + tools/xml-rpc-api2cpp/XmlRpcClass.cpp | 78 + tools/xml-rpc-api2cpp/XmlRpcClass.hpp | 19 + tools/xml-rpc-api2cpp/XmlRpcFunction.cpp | 137 + tools/xml-rpc-api2cpp/XmlRpcFunction.hpp | 37 + tools/xml-rpc-api2cpp/xml-rpc-api2cpp.1 | 62 + tools/xml-rpc-api2cpp/xml-rpc-api2cpp.cpp | 157 + tools/xml-rpc-api2txt | 147 + tools/xml-rpc-api2txt.1 | 47 + tools/xmlrpc/.cvsignore | 1 + tools/xmlrpc/Makefile | 66 + tools/xmlrpc/dumpvalue.c | 367 + tools/xmlrpc/dumpvalue.h | 10 + tools/xmlrpc/xmlrpc.c | 514 + tools/xmlrpc/xmlrpc.html | 249 + tools/xmlrpc_transport/.cvsignore | 1 + tools/xmlrpc_transport/Makefile | 64 + tools/xmlrpc_transport/xmlrpc_transport.c | 289 + tools/xmlrpc_transport/xmlrpc_transport.html | 95 + unix-common.make | 71 + xmlrpc-c-config.in | 178 + xmlrpc-c-config.test.in | 155 + xmlrpc_amconfig.h.in | 23 + xmlrpc_config.h.in | 50 + 389 files changed, 109184 insertions(+) create mode 100644 .cvsignore create mode 100644 GNUmakefile create mode 100644 Makefile create mode 100644 Makefile.common create mode 100644 Makefile.config.in create mode 100644 Makefile.depend create mode 100644 README create mode 100644 Windows/.cvsignore create mode 100644 Windows/ConfigureWin32.bat create mode 100644 Windows/ReadMeWin32.txt create mode 100644 Windows/UsingCURLinWin32.txt create mode 100644 Windows/abyss.dsp create mode 100644 Windows/all.dsp create mode 100644 Windows/all.vcproj create mode 100644 Windows/configwin32.dsp create mode 100644 Windows/configwin32.vcproj create mode 100644 Windows/cpptest.dsp create mode 100644 Windows/cpptest.vcproj create mode 100644 Windows/query_meerkat.dsp create mode 100644 Windows/query_meerkat.vcproj create mode 100644 Windows/rpctest.dsp create mode 100644 Windows/rpctest.vcproj create mode 100644 Windows/transport_config_win32.h create mode 100644 Windows/win32_config.h create mode 100644 Windows/xmlrpc.dsp create mode 100644 Windows/xmlrpc.dsw create mode 100644 Windows/xmlrpc.sln create mode 100644 Windows/xmlrpc.vcproj create mode 100644 Windows/xmlrpc_sample_add_asynch_client.dsp create mode 100644 Windows/xmlrpc_sample_add_asynch_client.vcproj create mode 100644 Windows/xmlrpc_sample_add_server.dsp create mode 100644 Windows/xmlrpc_sample_add_server.vcproj create mode 100644 Windows/xmlrpc_sample_add_server_w32httpsys.dsp create mode 100644 Windows/xmlrpc_sample_add_server_w32httpsys.vcproj create mode 100644 Windows/xmlrpc_sample_add_sync_client.dsp create mode 100644 Windows/xmlrpc_sample_add_sync_client.vcproj create mode 100644 Windows/xmlrpc_sample_auth_client.dsp create mode 100644 Windows/xmlrpc_sample_auth_client.vcproj create mode 100644 Windows/xmlrpc_win32_config.h create mode 100644 aclocal.m4 create mode 100644 autom4te.cache/output.0 create mode 100644 autom4te.cache/requests create mode 100644 autom4te.cache/traces.0 create mode 100644 conf/abyss_root/conf/abyss.conf create mode 100644 conf/abyss_root/conf/mime.types create mode 100644 conf/abyss_root/htdocs/index.htm create mode 100644 conf/abyss_root/htdocs/pwrabyss.gif create mode 100755 config.guess create mode 100755 config.sub create mode 100755 configure create mode 100644 configure.in create mode 100644 doc/COPYING create mode 100644 doc/CREDITS create mode 100644 doc/DEVELOPING create mode 100644 doc/HISTORY create mode 100644 doc/INSTALL create mode 100644 doc/SECURITY create mode 100644 doc/TESTING create mode 100644 doc/TODO create mode 100644 doc/configure_doc create mode 100644 examples/.cvsignore create mode 100644 examples/Makefile create mode 100644 examples/README create mode 100644 examples/auth_client.c create mode 100644 examples/cpp/.cvsignore create mode 100644 examples/cpp/Makefile create mode 100644 examples/cpp/meerkat-app-list.cpp create mode 100644 examples/cpp/sample_add_client_complex.cpp create mode 100644 examples/cpp/xmlrpc_inetd_server.cpp create mode 100644 examples/cpp/xmlrpc_loop_server.cpp create mode 100644 examples/cpp/xmlrpc_sample_add_client.cpp create mode 100644 examples/cpp/xmlrpc_sample_add_server.cpp create mode 100644 examples/gen_sample_add_xml.c create mode 100644 examples/query-meerkat.c create mode 100644 examples/synch_client.c create mode 100644 examples/xmlrpc_asynch_client.c create mode 100644 examples/xmlrpc_inetd_server.c create mode 100644 examples/xmlrpc_loop_server.c create mode 100644 examples/xmlrpc_sample_add_client.c create mode 100644 examples/xmlrpc_sample_add_server.c create mode 100644 examples/xmlrpc_sample_add_server_cgi.c create mode 100644 examples/xmlrpc_sample_add_server_w32httpsys.c create mode 100644 examples/xmlrpc_server_validatee.c create mode 100644 examples/xmlrpc_socket_server.c create mode 100644 include/Makefile create mode 100644 include/xmlrpc-c/.cvsignore create mode 100644 include/xmlrpc-c/abyss.h create mode 100644 include/xmlrpc-c/base.h create mode 100644 include/xmlrpc-c/base.hpp create mode 100644 include/xmlrpc-c/base64.hpp create mode 100644 include/xmlrpc-c/base_int.h create mode 100644 include/xmlrpc-c/client.h create mode 100644 include/xmlrpc-c/client.hpp create mode 100644 include/xmlrpc-c/client_global.h create mode 100644 include/xmlrpc-c/client_int.h create mode 100644 include/xmlrpc-c/client_simple.hpp create mode 100644 include/xmlrpc-c/client_transport.hpp create mode 100644 include/xmlrpc-c/girerr.hpp create mode 100644 include/xmlrpc-c/girmem.hpp create mode 100644 include/xmlrpc-c/oldcppwrapper.hpp create mode 100644 include/xmlrpc-c/oldxmlrpc.h create mode 100644 include/xmlrpc-c/registry.hpp create mode 100644 include/xmlrpc-c/server.h create mode 100644 include/xmlrpc-c/server_abyss.h create mode 100644 include/xmlrpc-c/server_abyss.hpp create mode 100644 include/xmlrpc-c/server_cgi.h create mode 100644 include/xmlrpc-c/server_w32httpsys.h create mode 100644 include/xmlrpc-c/sleep_int.h create mode 100644 include/xmlrpc-c/string_int.h create mode 100644 include/xmlrpc-c/timeout.hpp create mode 100644 include/xmlrpc-c/transport.h create mode 100644 include/xmlrpc-c/util.h create mode 100644 include/xmlrpc-c/util_int.h create mode 100644 include/xmlrpc-c/xml.hpp create mode 100644 include/xmlrpc-c/xmlparser.h create mode 100755 install-sh create mode 100644 lib/Makefile create mode 100644 lib/Makefile.depend create mode 100644 lib/abyss/Makefile create mode 100644 lib/abyss/Makefile.depend create mode 100644 lib/abyss/README create mode 100644 lib/abyss/change.log create mode 100644 lib/abyss/conf/abyss.conf create mode 100644 lib/abyss/conf/mime.types create mode 100644 lib/abyss/htdocs/index.htm create mode 100644 lib/abyss/htdocs/pwrabyss.gif create mode 100644 lib/abyss/license.txt create mode 100644 lib/abyss/patch_notes.txt create mode 100644 lib/abyss/readme.txt create mode 100644 lib/abyss/src/Abyss.dsp create mode 100644 lib/abyss/src/Abyss.dsw create mode 100644 lib/abyss/src/Makefile create mode 100644 lib/abyss/src/Makefile.depend create mode 100644 lib/abyss/src/abyss_info.h create mode 100644 lib/abyss/src/conf.c create mode 100644 lib/abyss/src/conn.c create mode 100644 lib/abyss/src/conn.h create mode 100644 lib/abyss/src/data.c create mode 100644 lib/abyss/src/data.h create mode 100644 lib/abyss/src/date.c create mode 100644 lib/abyss/src/date.h create mode 100644 lib/abyss/src/file.c create mode 100644 lib/abyss/src/file.h create mode 100644 lib/abyss/src/http.c create mode 100644 lib/abyss/src/http.h create mode 100644 lib/abyss/src/main.c create mode 100644 lib/abyss/src/response.c create mode 100644 lib/abyss/src/server.c create mode 100644 lib/abyss/src/server.h create mode 100644 lib/abyss/src/session.c create mode 100644 lib/abyss/src/session.h create mode 100644 lib/abyss/src/socket.c create mode 100644 lib/abyss/src/socket.h create mode 100644 lib/abyss/src/socket_unix.c create mode 100644 lib/abyss/src/socket_unix.h create mode 100644 lib/abyss/src/socket_win.c create mode 100644 lib/abyss/src/socket_win.h create mode 100644 lib/abyss/src/thread.h create mode 100644 lib/abyss/src/thread_fork.c create mode 100644 lib/abyss/src/thread_pthread.c create mode 100644 lib/abyss/src/thread_windows.c create mode 100644 lib/abyss/src/token.c create mode 100644 lib/abyss/src/token.h create mode 100644 lib/abyss/src/trace.c create mode 100644 lib/abyss/src/trace.h create mode 100644 lib/abyss/version.txt create mode 100644 lib/curl_transport/Makefile create mode 100644 lib/curl_transport/Makefile.depend create mode 100644 lib/curl_transport/xmlrpc_curl_transport.c create mode 100644 lib/curl_transport/xmlrpc_curl_transport.h create mode 100644 lib/expat/Makefile create mode 100644 lib/expat/Makefile.depend create mode 100644 lib/expat/expat.dsw create mode 100644 lib/expat/expat.html create mode 100644 lib/expat/gennmtab/.cvsignore create mode 100644 lib/expat/gennmtab/Makefile create mode 100644 lib/expat/gennmtab/Makefile.depend create mode 100644 lib/expat/gennmtab/gennmtab.c create mode 100644 lib/expat/gennmtab/gennmtab.dsp create mode 100644 lib/expat/xmlparse/Makefile create mode 100644 lib/expat/xmlparse/Makefile.depend create mode 100644 lib/expat/xmlparse/xmlparse.c create mode 100644 lib/expat/xmlparse/xmlparse.dsp create mode 100644 lib/expat/xmlparse/xmlparse.h create mode 100644 lib/expat/xmltok/.cvsignore create mode 100644 lib/expat/xmltok/Makefile create mode 100644 lib/expat/xmltok/Makefile.depend create mode 100644 lib/expat/xmltok/ascii.h create mode 100644 lib/expat/xmltok/asciitab.h create mode 100644 lib/expat/xmltok/dllmain.c create mode 100644 lib/expat/xmltok/iasciitab.h create mode 100644 lib/expat/xmltok/latin1tab.h create mode 100644 lib/expat/xmltok/utf8tab.h create mode 100644 lib/expat/xmltok/xmldef.h create mode 100644 lib/expat/xmltok/xmlrole.c create mode 100644 lib/expat/xmltok/xmlrole.h create mode 100644 lib/expat/xmltok/xmltok.c create mode 100644 lib/expat/xmltok/xmltok.dsp create mode 100644 lib/expat/xmltok/xmltok.h create mode 100644 lib/expat/xmltok/xmltok_impl.c create mode 100644 lib/expat/xmltok/xmltok_impl.h create mode 100644 lib/expat/xmltok/xmltok_ns.c create mode 100644 lib/expat/xmlwf/.cvsignore create mode 100644 lib/expat/xmlwf/Makefile.in create mode 100644 lib/expat/xmlwf/codepage.c create mode 100644 lib/expat/xmlwf/codepage.h create mode 100644 lib/expat/xmlwf/filemap.h create mode 100644 lib/expat/xmlwf/readfilemap.c create mode 100644 lib/expat/xmlwf/unixfilemap.c create mode 100644 lib/expat/xmlwf/win32filemap.c create mode 100644 lib/expat/xmlwf/xmlfile.c create mode 100644 lib/expat/xmlwf/xmlfile.h create mode 100644 lib/expat/xmlwf/xmltchar.h create mode 100644 lib/expat/xmlwf/xmlwf.c create mode 100644 lib/expat/xmlwf/xmlwf.dsp create mode 100644 lib/libutil/Makefile create mode 100644 lib/libutil/Makefile.depend create mode 100644 lib/libutil/casprintf.c create mode 100644 lib/libutil/error.c create mode 100644 lib/libutil/make_printable.c create mode 100644 lib/libutil/memblock.c create mode 100644 lib/libutil/resource.c create mode 100644 lib/libutil/sleep.c create mode 100644 lib/libwww_transport/Makefile create mode 100644 lib/libwww_transport/Makefile.depend create mode 100644 lib/libwww_transport/xmlrpc_libwww_transport.c create mode 100644 lib/libwww_transport/xmlrpc_libwww_transport.h create mode 100644 lib/util/Makefile create mode 100644 lib/util/Makefile.depend create mode 100644 lib/util/casprintf.c create mode 100644 lib/util/cmdline_parser.c create mode 100644 lib/util/getoptx.c create mode 100644 lib/util/getoptx.h create mode 100644 lib/util/include/bool.h create mode 100644 lib/util/include/c_util.h create mode 100644 lib/util/include/casprintf.h create mode 100644 lib/util/include/cmdline_parser.h create mode 100644 lib/util/include/girmath.h create mode 100644 lib/util/include/girstring.h create mode 100644 lib/util/include/inline.h create mode 100644 lib/util/include/linklist.h create mode 100644 lib/util/include/mallocvar.h create mode 100644 lib/util/include/pthreadx.h create mode 100644 lib/util/include/unistdx.h create mode 100644 lib/util/pthreadx_win32.c create mode 100644 lib/wininet_transport/Makefile create mode 100644 lib/wininet_transport/xmlrpc_wininet_transport.c create mode 100644 lib/wininet_transport/xmlrpc_wininet_transport.h create mode 100755 ltconfig create mode 100644 ltmain.sh create mode 100755 missing create mode 100755 mkinstalldirs create mode 100644 src/.cvsignore create mode 100644 src/Makefile create mode 100644 src/Makefile.depend create mode 100644 src/cpp/Makefile create mode 100644 src/cpp/Makefile.depend create mode 100644 src/cpp/XmlRpcCpp.cpp create mode 100644 src/cpp/base64.cpp create mode 100644 src/cpp/client.cpp create mode 100644 src/cpp/client_simple.cpp create mode 100644 src/cpp/curl.cpp create mode 100644 src/cpp/dll.make create mode 100644 src/cpp/dylib.make create mode 100644 src/cpp/env_wrap.cpp create mode 100644 src/cpp/env_wrap.hpp create mode 100644 src/cpp/fault.cpp create mode 100644 src/cpp/girerr.cpp create mode 100644 src/cpp/girmem.cpp create mode 100644 src/cpp/irix.make create mode 100644 src/cpp/libwww.cpp create mode 100644 src/cpp/outcome.cpp create mode 100644 src/cpp/param_list.cpp create mode 100644 src/cpp/registry.cpp create mode 100644 src/cpp/server_abyss.cpp create mode 100644 src/cpp/test/.cvsignore create mode 100644 src/cpp/test/Makefile create mode 100644 src/cpp/test/Makefile.depend create mode 100644 src/cpp/test/server_abyss.cpp create mode 100644 src/cpp/test/server_abyss.hpp create mode 100644 src/cpp/test/test.cpp create mode 100644 src/cpp/test/testclient.cpp create mode 100644 src/cpp/test/testclient.hpp create mode 100644 src/cpp/test/testclient_dummy.cpp create mode 100644 src/cpp/test/tools.cpp create mode 100644 src/cpp/test/tools.hpp create mode 100644 src/cpp/unix.make create mode 100644 src/cpp/value.cpp create mode 100644 src/cpp/wininet.cpp create mode 100644 src/cpp/xml.cpp create mode 100644 src/registry.c create mode 100644 src/registry.h create mode 100644 src/system_method.c create mode 100644 src/system_method.h create mode 100644 src/test/.cvsignore create mode 100644 src/test/Makefile create mode 100644 src/test/Makefile.depend create mode 100644 src/test/cgi.c create mode 100644 src/test/cgi.h create mode 100644 src/test/cgitest1.c create mode 100644 src/test/client.c create mode 100644 src/test/client.h create mode 100644 src/test/client_dummy.c create mode 100644 src/test/data/req_no_params.xml create mode 100644 src/test/data/req_out_of_order.xml create mode 100644 src/test/data/req_value_name.xml create mode 100644 src/test/data/sample_add_call.xml create mode 100644 src/test/eftest_wrapper.sh create mode 100644 src/test/http-req-simple.txt create mode 100644 src/test/method_registry.c create mode 100644 src/test/method_registry.h create mode 100644 src/test/parse_xml.c create mode 100644 src/test/parse_xml.h create mode 100644 src/test/req_no_params.xml create mode 100644 src/test/serialize.c create mode 100644 src/test/serialize.h create mode 100644 src/test/server_abyss.c create mode 100644 src/test/server_abyss.h create mode 100644 src/test/test.c create mode 100644 src/test/test.h create mode 100644 src/test/value.c create mode 100644 src/test/value.h create mode 100644 src/test/xml_data.c create mode 100644 src/test/xml_data.h create mode 100644 src/trace.c create mode 100644 src/xmlrpc_array.c create mode 100644 src/xmlrpc_authcookie.c create mode 100644 src/xmlrpc_base64.c create mode 100644 src/xmlrpc_builddecomp.c create mode 100644 src/xmlrpc_client.c create mode 100644 src/xmlrpc_client_global.c create mode 100644 src/xmlrpc_data.c create mode 100644 src/xmlrpc_datetime.c create mode 100644 src/xmlrpc_expat.c create mode 100644 src/xmlrpc_libxml2.c create mode 100644 src/xmlrpc_parse.c create mode 100644 src/xmlrpc_serialize.c create mode 100644 src/xmlrpc_server_abyss.c create mode 100644 src/xmlrpc_server_cgi.c create mode 100644 src/xmlrpc_server_w32httpsys.c create mode 100644 src/xmlrpc_struct.c create mode 100644 src/xmlrpc_utf8.c create mode 100644 stamp-h.in create mode 100644 tools/.cvsignore create mode 100644 tools/Makefile create mode 100644 tools/Makefile.common create mode 100644 tools/binmode-rpc-kit/COPYING create mode 100644 tools/binmode-rpc-kit/Makefile create mode 100644 tools/binmode-rpc-kit/README create mode 100644 tools/binmode-rpc-kit/binmode-rpc-rfc.txt create mode 100755 tools/binmode-rpc-kit/binmode-rpc2xml-rpc create mode 100644 tools/binmode-rpc-kit/examples/good-1.binmode create mode 100644 tools/binmode-rpc-kit/examples/good-1.xml create mode 100644 tools/binmode-rpc-kit/examples/good-2.binmode create mode 100644 tools/binmode-rpc-kit/examples/good-2.xml create mode 100644 tools/binmode-rpc-kit/examples/good-3.binmode create mode 100644 tools/binmode-rpc-kit/examples/good-3.xml create mode 100644 tools/binmode-rpc-kit/examples/good-4.binmode create mode 100644 tools/binmode-rpc-kit/examples/good-4.xml create mode 100644 tools/binmode-rpc-kit/examples/good-5.binmode create mode 100644 tools/binmode-rpc-kit/examples/good-5.xml create mode 100644 tools/binmode-rpc-kit/examples/good-6.binmode create mode 100644 tools/binmode-rpc-kit/examples/good-6.xml create mode 100644 tools/binmode-rpc-kit/examples/invalid-1.binmode create mode 100644 tools/binmode-rpc-kit/examples/invalid-2.binmode create mode 100644 tools/binmode-rpc-kit/examples/invalid-3.binmode create mode 100644 tools/binmode-rpc-kit/examples/invalid-4.binmode create mode 100644 tools/binmode-rpc-kit/examples/invalid-5.binmode create mode 100755 tools/binmode-rpc-kit/oct2bin create mode 100644 tools/interop-server/interop-cgi.c create mode 100644 tools/turbocharger/.cvsignore create mode 100644 tools/turbocharger/Makefile create mode 100644 tools/turbocharger/README create mode 100644 tools/turbocharger/mod_gzip.c create mode 100644 tools/turbocharger/mod_gzip.c.diff create mode 100644 tools/xml-rpc-api2cpp/.cvsignore create mode 100644 tools/xml-rpc-api2cpp/DataType.cpp create mode 100644 tools/xml-rpc-api2cpp/DataType.hpp create mode 100644 tools/xml-rpc-api2cpp/Makefile create mode 100644 tools/xml-rpc-api2cpp/Makefile.depend create mode 100644 tools/xml-rpc-api2cpp/README create mode 100644 tools/xml-rpc-api2cpp/SystemProxy.cpp create mode 100644 tools/xml-rpc-api2cpp/SystemProxy.hpp create mode 100644 tools/xml-rpc-api2cpp/XmlRpcClass.cpp create mode 100644 tools/xml-rpc-api2cpp/XmlRpcClass.hpp create mode 100644 tools/xml-rpc-api2cpp/XmlRpcFunction.cpp create mode 100644 tools/xml-rpc-api2cpp/XmlRpcFunction.hpp create mode 100644 tools/xml-rpc-api2cpp/xml-rpc-api2cpp.1 create mode 100644 tools/xml-rpc-api2cpp/xml-rpc-api2cpp.cpp create mode 100755 tools/xml-rpc-api2txt create mode 100644 tools/xml-rpc-api2txt.1 create mode 100644 tools/xmlrpc/.cvsignore create mode 100644 tools/xmlrpc/Makefile create mode 100644 tools/xmlrpc/Makefile.depend create mode 100644 tools/xmlrpc/dumpvalue.c create mode 100644 tools/xmlrpc/dumpvalue.h create mode 100644 tools/xmlrpc/xmlrpc.c create mode 100644 tools/xmlrpc/xmlrpc.html create mode 100644 tools/xmlrpc_transport/.cvsignore create mode 100644 tools/xmlrpc_transport/Makefile create mode 100644 tools/xmlrpc_transport/Makefile.depend create mode 100644 tools/xmlrpc_transport/xmlrpc_transport.c create mode 100644 tools/xmlrpc_transport/xmlrpc_transport.html create mode 100644 unix-common.make create mode 100644 xmlrpc-c-config.in create mode 100644 xmlrpc-c-config.test.in create mode 100644 xmlrpc_amconfig.h.in create mode 100644 xmlrpc_config.h.in diff --git a/.cvsignore b/.cvsignore new file mode 100644 index 0000000..2e9a254 --- /dev/null +++ b/.cvsignore @@ -0,0 +1,17 @@ +Makefile.config +autom4te.cache +configure +config.log +stamp-h +stamp-h1 +config.cache +libtool +config.status +xmlrpc_config.h +xmlrpc_amconfig.h +xmlrpc-c-config +xmlrpc-c-config.test +xmlrpc-c.spec +transport_config.h +version.h + diff --git a/GNUmakefile b/GNUmakefile new file mode 100644 index 0000000..0d5353c --- /dev/null +++ b/GNUmakefile @@ -0,0 +1,121 @@ +ifeq ($(SRCDIR)x,x) +SRCDIR = $(CURDIR) +endif +SUBDIR = . +BUILDDIR = $(SRCDIR) +VPATH = .:$(SRCDIR) + +include $(SRCDIR)/Makefile.config + +SUBDIRS = include lib src tools examples + +PROGRAMS_TO_INSTALL = xmlrpc-c-config + +# We're in a transition between the bloated, complex GNU +# Autoconf/Automake style of build, in which 'configure' creates all +# the make files, to simpler static make files. Some directories have +# been converted; some haven't. So we have the hack of putting +# 'xmlrpc_config.h' as the first dependency of 'all' to make sure +# 'configure runs before anything in the case that the user neglects +# to run 'configure' before doing 'make'. + +default: xmlrpc_config.h all + +.PHONY: all +all: xmlrpc-c-config xmlrpc-c-config.test $(SUBDIRS:%=%/all) + +version.h: $(BUILDDIR)/Makefile.config + rm -f $@ + echo '/* This file was generated by a make rule */' >>$@ + echo '#define XMLRPC_C_VERSION "$(XMLRPC_C_VERSION)"' >>$@ + +# We don't want Makefile.common's rule for version.h +OMIT_VERSION_H = Y + +# We dont' want Makefile.common's rule for transport_config.h +OMIT_TRANSPORT_CONFIG_H = Y + +transport_config.h: $(BUILDDIR)/Makefile.config + rm -f $@ + echo '/* This file was generated by a make rule */' >>$@ +ifeq ($(MUST_BUILD_WININET_CLIENT),yes) + echo '#define MUST_BUILD_WININET_CLIENT 1' >>$@ +else + echo '#define MUST_BUILD_WININET_CLIENT 0' >>$@ +endif +ifeq ($(MUST_BUILD_CURL_CLIENT),yes) + echo '#define MUST_BUILD_CURL_CLIENT 1' >>$@ +else + echo '#define MUST_BUILD_CURL_CLIENT 0' >>$@ +endif +ifeq ($(MUST_BUILD_LIBWWW_CLIENT),yes) + echo '#define MUST_BUILD_LIBWWW_CLIENT 1' >>$@ +else + echo '#define MUST_BUILD_LIBWWW_CLIENT 0' >>$@ +endif + echo "static const char * const XMLRPC_DEFAULT_TRANSPORT =" >>$@ +ifeq ($(MUST_BUILD_LIBWWW_CLIENT),yes) + echo '"libwww";' >>$@ +else + ifeq ($(MUST_BUILD_CURL_CLIENT),yes) + echo '"curl";' >>$@ + else + ifeq ($(MUST_BUILD_WININET_CLIENT),yes) + echo '"wininet";' >>$@ + else + @echo 'ERROR: no client XML transport configured'; rm $@; false + endif + endif +endif + +.PHONY: clean clean-local +clean: $(SUBDIRS:%=%/clean) clean-common clean-local + +clean-local: + rm -f transport_config.h + +.PHONY: distclean distclean-local +distclean: $(SUBDIRS:%=%/distclean) distclean-common distclean-local + +distclean-local: clean-local + rm -f config.log config.status Makefile.config libtool + rm -f xmlrpc_config.h xmlrpc_amconfig.h stamp-h + rm -f xmlrpc-c-config xmlrpc-c-config.test + +check: $(SUBDIRS:%=%/check) + +.PHONY: tags +tags: $(SUBDIRS:%=%/tags) TAGS + +DISTFILES = + +.PHONY: distdir +distdir: distdir-common + +.PHONY: install +install: $(SUBDIRS:%=%/install) install-common install-compat-hdr + +.PHONY: install-compat-hdr +install-compat-hdr: +# Install old names of header files for backward compatibility + cd $(DESTDIR)$(HEADERINST_DIR); \ + rm -f xmlrpc.h xmlrpc_client.h xmlrpc_server.h xmlrpc_cgi.h \ + xmlrpc_server_abyss.h xmlrpc_abyss.h \ + xmlrpc_server_w32httpsys.h \ + XmlRpcCpp.h; \ + $(LN_S) xmlrpc-c/oldxmlrpc.h xmlrpc.h; \ + $(LN_S) xmlrpc-c/client.h xmlrpc_client.h; \ + $(LN_S) xmlrpc-c/server.h xmlrpc_server.h; \ + $(LN_S) xmlrpc-c/server_cgi.h xmlrpc_cgi.h; \ + $(LN_S) xmlrpc-c/server_abyss.h xmlrpc_abyss.h; \ + $(LN_S) xmlrpc-c/server_w32httpsys.h xmlrpc_server_w32httpsys.h; \ + $(LN_S) xmlrpc-c/oldcppwrapper.hpp XmlRpcCpp.h ;\ + +.PHONY: dep +dep: version.h $(BUILDDIR)/include/xmlrpc-c/config.h $(SUBDIRS:%=%/dep) + +xmlrpc-c-config xmlrpc-c-config.test xmlrpc_config.h xmlrpc_amconfig.h \ + :%:%.in $(SRCDIR)/configure + $(SRCDIR)/configure + +include $(SRCDIR)/Makefile.common diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..af667d6 --- /dev/null +++ b/Makefile @@ -0,0 +1,14 @@ +# The make files for this package exploit features of GNU Make that +# other Makes do not have. Because it is a common mistake for users +# to try to build with a different Make, we have this make file that +# does nothing but tell the user to use GNU Make. + +# If the user were using GNU Make now, this file would not get used because +# GNU Make uses a make file named "GNUmakefile" in preference to "Makefile" +# if it exists. This package contains a "GNUmakefile". + +all install clean dep depend: + @echo "You must use GNU Make to build this. You are running some " + @echo "other Make. GNU Make may be installed on your system with " + @echo "the name 'gmake'. If not, see http://www.gnu.org/software ." + @echo diff --git a/Makefile.common b/Makefile.common new file mode 100644 index 0000000..342b35d --- /dev/null +++ b/Makefile.common @@ -0,0 +1,452 @@ +# -*-makefile-*- <-- an Emacs control + +# This file contains rules and variable settings for the convenience +# of every other make file in the package. + +# No make file is required to use this file, but it usually saves a lot +# of duplication. + +# The following make variables are meaningful as input to this file: +# +# SRCDIR: Name of directory which is the top of the Xmlrpc-c source tree. +# BUILDDIR: Name of directory which is the top of the Xmlrpc-c build tree. + +LIBTOOL = $(SRCDIR)/libtool +LINK = $(LIBTOOL) --mode=link $(CCLD) + +GCC_WARNINGS = -Wall -Wundef -Wimplicit -W -Winline -Wundef + # We need -Wwrite-strings after we fix all the missing consts + +GCC_C_WARNINGS = $(GCC_WARNINGS) \ + -Wmissing-declarations -Wstrict-prototypes -Wmissing-prototypes + +GCC_CXX_WARNINGS = $(GCC_WARNINGS) -Woverloaded-virtual -Wsynth + +# The NDEBUG macro says not to build code that assumes there are no bugs. +# This makes the code go faster. The main thing it does is tell the C library +# to make assert() a no-op as opposed to generating code to check the +# assertion and crash the program if it isn't really true. You can add +# -UNDEBUG (in any of various ways) to override this. +# +CFLAGS_COMMON = -DNDEBUG +CXXFLAGS_COMMON = -DNDEBUG + +ifeq ($(C_COMPILER_GNU),yes) + CFLAGS_COMMON += $(GCC_C_WARNINGS) -fno-common -g -O3 +endif + +ifeq ($(CXX_COMPILER_GNU),yes) + CXXFLAGS_COMMON += $(GCC_CXX_WARNINGS) -g +endif + +DISTDIR = $(BUILDDIR)/$(PACKAGE)-$(VERSION)/$(SUBDIR) + +# MAJ and MIN are major and minor version numbers for shared libraries. +# Libtool builds are controlled by LDFLAGS_VERSINFO instead. +MAJ = 3 +MIN = 06 + +# LDFLAGS_VERSINFO is a libtool link option (--version-info) that +# tells it what version numbers to put on the shared libraries (and +# maybe in those special libtool link files). Exactly how it works is +# somewhat mysterious; it's designed to be part of a linking system +# where you always use libtool to link the libraries, and libtool +# figures out which if any version of a library meets the link's +# requirements. But we expect our libraries to be linked with the +# regular (non-libtool) linker, so what we care about is the major, +# minor, and revision numbers in the file names and sonames. Libtool +# has an option --version-number that supposedly lets us specify that, +# but it doesn't seem to work. All I get is 0.0.0. So we manipulate +# --version-info instead. +# +# This appears to work: in the option --version-info A.B.C: +# +# C is the minor number +# B is the revision number +# A minus C is the major number. +# +# So you would get libxmlrpc.so.A-C.C.B . +# +# Our strategy is to make the library version numbers the same as the +# Xmlrpc-c version numbers except that we update the major number when and +# only when we make a non-backward-compatible change to the library. So +# e.g. libxmlrpc for Xmlrpc-c 1.06.01 is named libxmlrpc.so.3.6.1. + +LDFLAGS_VERSINFO = -version-info 9:15:6 # 3.6.15 + +# CURDIR was introduced in GNU Make 3.77. +ifeq ($(CURDIR)x,x) + CURDIR := $(shell /bin/pwd) +endif + +LIBXMLRPC_UTIL = $(BUILDDIR)/lib/libutil/libxmlrpc_util.la +LIBXMLRPC = $(BUILDDIR)/src/libxmlrpc.la +LIBXMLRPC_CLIENT = $(BUILDDIR)/src/libxmlrpc_client.la +LIBXMLRPC_SERVER = $(BUILDDIR)/src/libxmlrpc_server.la +LIBXMLRPC_SERVER_ABYSS = $(BUILDDIR)/src/libxmlrpc_server_abyss.la +LIBXMLRPC_SERVER_CGI = $(BUILDDIR)/src/libxmlrpc_server_cgi.la +LIBXMLRPC_ABYSS = $(BUILDDIR)/lib/abyss/src/libxmlrpc_abyss.la +LIBXMLRPC_XMLPARSE = $(BUILDDIR)/lib/expat/xmlparse/libxmlrpc_xmlparse.la +LIBXMLRPC_XMLTOK = $(BUILDDIR)/lib/expat/xmltok/libxmlrpc_xmltok.la +LIBXMLRPC_UTIL_A = $(BUILDDIR)/lib/libutil/.libs/libxmlrpc_util.a +LIBXMLRPC_A = $(BUILDDIR)/src/.libs/libxmlrpc.a +LIBXMLRPC_CLIENT_A = $(BUILDDIR)/src/.libs/libxmlrpc_client.a +LIBXMLRPC_SERVER_A = $(BUILDDIR)/src/.libs/libxmlrpc_server.a +LIBXMLRPC_SERVER_ABYSS_A = $(BUILDDIR)/src/.libs/libxmlrpc_server_abyss.a +LIBXMLRPC_SERVER_CGI_A = $(BUILDDIR)/src/.libs/libxmlrpc_server_cgi.a +LIBXMLRPC_ABYSS_A = $(BUILDDIR)/lib/abyss/src/.libs/libxmlrpc_abyss.a +LIBXMLRPC_XMLPARSE_A = $(BUILDDIR)/lib/expat/xmlparse/.libs/libxmlrpc_xmlparse.a +LIBXMLRPC_XMLTOK_A = $(BUILDDIR)/lib/expat/xmltok/.libs/libxmlrpc_xmltok.a +LIBXMLRPC_CPP = $(BUILDDIR)/src/cpp/libxmlrpc_cpp.a +LIBXMLRPC++ = $(BUILDDIR)/src/cpp/libxmlrpc++.a +LIBXMLRPC_CLIENT++ = $(BUILDDIR)/src/cpp/libxmlrpc_client++.a +LIBXMLRPC_SERVER++ = $(BUILDDIR)/src/cpp/libxmlrpc_server++.a +LIBXMLRPC_SERVER_ABYSS++ = $(BUILDDIR)/src/cpp/libxmlrpc_server_abyss++.a + +CASPRINTF = $(BUILDDIR)/lib/util/casprintf.o + +UTILS = $(CASPRINTF) + + +# LIBXMLRPC_XML is the list of Xmlrpc-c libraries we need to parse +# XML. If we're using an external library to parse XML, this is null. +# LDLIBS_XMLRPC_XML is the corresonding -l options. + +ifneq ($(ENABLE_LIBXML2_BACKEND),yes) + # We're using the internal Expat XML parser + LIBXMLRPC_XML = $(LIBXMLRPC_XMLPARSE) $(LIBXMLRPC_XMLTOK) + LDLIBS_XML = \ + -L$(BUILDDIR)/lib/expat/xmlparse/.libs \ + -lxmlrpc_xmlparse \ + -L$(BUILDDIR)/lib/expat/xmltok/.libs \ + -lxmlrpc_xmltok +else + LDLIBS_XML = $(shell xml2-config --libs) +endif + + +############################################################################## +# BUILD RULES # +############################################################################## + +# We use the srcdir and blddir symbolic links simply to make the make +# rules easier to read in the make output. We could use $(SRCDIR) and +# $(BLDDIR) variables, but that makes the compile and link commands +# a mile long. Note that Make sometime figures that a directory which +# is a dependency is newer than the symbolic link pointing to it and wants +# to rebuild the symbolic link. So we don't make $(BLDDIR) a +# dependency of 'blddir'. + +blddir: + $(LN_S) $(BLDDIR) $@ + +srcdir: + $(LN_S) $(SRCDIR) $@ + +$(SUBDIRS:%=%/all): %/all: $(CURDIR)/% + $(MAKE) -C $(dir $@) -f $(SRCDIR)/$(SUBDIR)/$(dir $@)Makefile \ + $(notdir $@) + +$(SUBDIRS:%=%/install): %/install: $(CURDIR)/% + $(MAKE) -C $(dir $@) -f $(SRCDIR)/$(SUBDIR)/$(dir $@)Makefile \ + $(notdir $@) + +$(SUBDIRS:%=%/clean): %/clean: $(CURDIR)/% + $(MAKE) -C $(dir $@) -f $(SRCDIR)/$(SUBDIR)/$(dir $@)Makefile \ + $(notdir $@) + +$(SUBDIRS:%=%/distclean): %/distclean: $(CURDIR)/% + $(MAKE) -C $(dir $@) -f $(SRCDIR)/$(SUBDIR)/$(dir $@)Makefile \ + $(notdir $@) + +$(SUBDIRS:%=%/check): %/check: $(CURDIR)/% + $(MAKE) -C $(dir $@) -f $(SRCDIR)/$(SUBDIR)/$(dir $@)Makefile \ + $(notdir $@) + +$(SUBDIRS:%=%/distdir): %/distdir: $(CURDIR)/% + $(MAKE) -C $(dir $@) -f $(SRCDIR)/$(SUBDIR)/$(dir $@)Makefile \ + $(notdir $@) + +$(SUBDIRS:%=%/dep): %/dep: $(CURDIR)/% + $(MAKE) -C $(dir $@) -f $(SRCDIR)/$(SUBDIR)/$(dir $@)Makefile \ + $(notdir $@) + +$(BUILDDIR)/lib/wininet_transport/xmlrpc_wininet_transport.lo: FORCE + $(MAKE) -C $(dir $@) -f $(SRCDIR)/lib/wininet_transport/Makefile \ + $(notdir $@) + +$(BUILDDIR)/lib/curl_transport/xmlrpc_curl_transport.lo: FORCE + $(MAKE) -C $(dir $@) -f $(SRCDIR)/lib/curl_transport/Makefile \ + $(notdir $@) + +$(BUILDDIR)/lib/libwww_transport/xmlrpc_libwww_transport.lo: FORCE + $(MAKE) -C $(dir $@) -f $(SRCDIR)/lib/libwww_transport/Makefile \ + $(notdir $@) + +$(LIBXMLRPC_ABYSS): FORCE + $(MAKE) -C $(dir $@) -f $(SRCDIR)/lib/abyss/src/Makefile \ + $(notdir $@) + +$(LIBXMLRPC_XMLPARSE): FORCE + $(MAKE) -C $(dir $@) -f $(SRCDIR)/lib/expat/xmlparse/Makefile \ + $(notdir $@) + +$(LIBXMLRPC_XMLTOK): FORCE + $(MAKE) -C $(dir $@) -f $(SRCDIR)/lib/expat/xmltok/Makefile \ + $(notdir $@) + +$(LIBXMLRPC_UTIL): FORCE + $(MAKE) -C $(dir $@) -f $(SRCDIR)/lib/libutil/Makefile \ + $(notdir $@) + +$(LIBXMLRPC) $(LIBXMLRPC_CLIENT) $(LIBXMLRPC_SERVER): FORCE + $(MAKE) -C $(dir $@) -f $(SRCDIR)/src/Makefile \ + $(notdir $@) + +$(LIBXMLRPC++) $(LIBXMLRPC_CLIENT++) $(LIBXMLRPC_SERVER++) \ + $(LIBXMLRPC_SERVER_ABYSS++): FORCE + $(MAKE) -C $(dir $@) -f $(SRCDIR)/src/cpp/Makefile \ + $(notdir $@) + +$(LIBXMLRPC_UTIL_A): $(LIBXMLRPC_UTIL) +$(LIBXMLRPC_A): $(LIBXMLRPC) +$(LIBXMLRPC_CLIENT_A): $(LIBXMLRPC_CLIENT) +$(LIBXMLRPC_SERVER_ABYSS_A): $(LIBXMLRPC_SERVER_ABYSS) +$(LIBXMLRPC_CGI_A): $(LIBXMLRPC_CGI) +$(LIBXMLRPC_ABYSS_A): $(LIBXMLRPC_ABYSS) +$(LIBXMLRPC_XMLPARSE_A): $(LIBXMLRPC_XMLPARSE) +$(LIBXMLRPC_XMLTOK_A): $(LIBXMLRPC_XMLTOK) + +$(UTILS): FORCE + $(MAKE) -C $(dir $@) -f $(SRCDIR)/lib/util/Makefile \ + $(notdir $@) + +# About version.h: This is a built header file, which means it is a supreme +# pain in the ass. The biggest problem is that when we automatically make +# dependencies (Makefile.depend), it doesn't exist yet. This means Gcc +# generates a dependency on it being in the local directory. Therefore, +# we generate it in the local directory, as a symbolic link, wherever it +# is needed. But the original is always in the top level directory, +# generated by a rule in that directory's make file. Problem 2 is that +# the top directory's make file includes Makefile.common, so the rules +# below conflict with it. That's what OMIT_VERSION_H is for. + +ifneq ($(OMIT_VERSION_H),Y) + +$(BUILDDIR)/version.h: + $(MAKE) -C $(dir $@) -f $(SRCDIR)/GNUmakefile $(notdir $@) + +version.h: $(BUILDDIR)/version.h + $(LN_S) $< $@ + +endif + +$(BUILDDIR)/include/xmlrpc-c/config.h: + $(MAKE) -C $(BUILDDIR)/include -f $(SRCDIR)/include/Makefile \ + xmlrpc-c/config.h + +ifneq ($(OMIT_TRANSPORT_CONFIG_H),Y) +$(BUILDDIR)/transport_config.h: + $(MAKE) -C $(dir $@) $(notdir $@) +endif + +$(ALL_OBJS): $(BUILDDIR)/include/xmlrpc-c/config.h + + +############################################################################## +# SHARED LIBRARY RULES # +############################################################################## + +ifeq ($(SHARED_LIB_TYPE),unix) + include $(SRCDIR)/unix-common.make + endif + +ifeq ($(SHARED_LIB_TYPE),irix) + include $(SRCDIR)/irix-common.make + endif + +ifeq ($(SHARED_LIB_TYPE),dll) + include $(SRCDIR)/dll-common.make + endif + +ifeq ($(SHARED_LIB_TYPE),dylib) + include $(SRCDIR)/dylib-common.make + endif + +ifeq ($(SHARED_LIB_TYPE),NONE) + install-shared-libraries: + endif + + +############################################################################## +# INSTALL RULES # +# (except shared libraries) # +############################################################################## + +MKINSTALLDIRS = $(SHELL) $(SRCDIR)/mkinstalldirs + +.PHONY: install-common install-libraries install-headers install-bin +install-common: \ + install-ltlibraries install-static-libraries install-shared-libraries \ + install-headers install-bin + +INSTALL_LIB_CMD = $(INSTALL_DATA) $$p $(DESTDIR)$(LIBINST_DIR)/$$p +RANLIB_CMD = $(RANLIB) $(DESTDIR)$(LIBINST_DIR)/$$p + +install-static-libraries: $(STATIC_LIBRARIES_TO_INSTALL) + $(MKINSTALLDIRS) $(DESTDIR)$(LIBINST_DIR) + @list='$(STATIC_LIBRARIES_TO_INSTALL)'; for p in $$list; do \ + if test -f $$p; then \ + echo " $(INSTALL_LIB_CMD)"; \ + $(INSTALL_LIB_CMD); \ + else :; fi; \ + done + @$(POST_INSTALL) + @list='$(STATIC_LIBRARIES_TO_INSTALL)'; for p in $$list; do \ + if test -f $$p; then \ + echo " $(RANLIB_CMD)"; \ + $(RANLIB_CMD); \ + else :; fi; \ + done + +LIBTOOL_INSTALL_CMD = $(LIBTOOL) --mode=install \ + $(INSTALL_SHLIB) $$p $(DESTDIR)$(LIBINST_DIR)/$$p + +install-ltlibraries: $(LTLIBRARIES_TO_INSTALL) + $(MKINSTALLDIRS) $(DESTDIR)$(LIBINST_DIR) + @list='$(LTLIBRARIES_TO_INSTALL)'; for p in $$list; do \ + if test -f $$p; then \ + echo " $(LIBTOOL_INSTALL_CMD)"; \ + $(LIBTOOL_INSTALL_CMD); \ + else :; fi; \ + done + +HEADERDESTDIR = $(DESTDIR)$(HEADERINST_DIR) +INSTALL_HDR_CMD = $(INSTALL_DATA) $$d$$p $(HEADERDESTDIR)/$$p + +install-headers: $(HEADERS_TO_INSTALL) + $(MKINSTALLDIRS) $(HEADERDESTDIR) + $(MKINSTALLDIRS) $(HEADERDESTDIR)/xmlrpc-c + @list='$(HEADERS_TO_INSTALL)'; for p in $$list; do \ + if test -f "$$p"; then d= ; else d="$(srcdir)/"; fi; \ + echo " $(INSTALL_HDR_CMD)"; \ + $(INSTALL_HDR_CMD); \ + done + + +INSTALL_PROGRAM_CMD = $(INSTALL_PROGRAM) $$p $(DESTDIR)$(PROGRAMINST_DIR)/$$p + +install-bin: $(PROGRAMS_TO_INSTALL) $(DESTDIR)$(PROGRAMINST_DIR) + @list='$(PROGRAMS_TO_INSTALL)'; \ + for p in $$list; do \ + echo "$(INSTALL_PROGRAM_CMD)"; \ + $(INSTALL_PROGRAM_CMD); \ + done + +$(DESTDIR)$(PROGRAMINST_DIR): + $(MKINSTALLDIRS) $@ + + +############################################################################## +# MISCELLANEOUS RULES # +############################################################################## + +.PHONY: clean-common +clean-common: + rm -f *.o *.a *.s *.i *.la *.lo + rm -f *.$(SHLIB_SUFFIX) *.$(SHLIB_SUFFIX).* + rm -rf .libs + +.PHONY: distclean-common +distclean-common: +# Makefile.depend is generated by 'make dep' and contains only dependencies +# that make parts get _rebuilt_ when parts upon which they depend change. +# It does not contain dependencies that are necessary to cause a part to +# get built in the first place. E.g. if foo.c uses bar.h and bar.h gets built +# by a make rule, you must put the dependency of foo.c on bar.h somewhere +# besides Makefile.depend. +# +# Because of this, a user doesn't need Makefile.depend, because he +# doesn't modify source files. A developer, on the other hand, must make his +# own Makefile.depend, because 'make dep' creates Makefile.depend with +# absolute pathnames, specific to the developer's system. +# +# So we empty out Makefile.depend here. The developer must do 'make dep' if +# he wants to edit and rebuild. +# +# Other projects have 'make distclean' _remove_ Makefile.depend and then +# have 'make' automatically build Makefile.depend. We have +# found that to be an utter disaster -- it's way too complicated and prone +# to failure, especially with built .h files. Better not to burden the user, +# who gains nothing from it, with that. +# + cat /dev/null >Makefile.depend + rm -f TAGS + rm -f blddir srcdir +ifneq ($(OMIT_VERSION_H),Y) + rm -f version.h +endif + +.PHONY: distdir-common +distdir-common: + @for file in $(DISTFILES); do \ + d=$(SRCDIR); \ + if test -d $$d/$$file; then \ + cp -pr $$d/$$file $(DISTDIR)/$$file; \ + else \ + test -f $(DISTDIR)/$$file \ + || ln $$d/$$file $(DISTDIR)/$$file 2> /dev/null \ + || cp -p $$d/$$file $(DISTDIR)/$$file || :; \ + fi; \ + done + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + test -f $$subdir/TAGS && tags="$$tags -i $$here/$$subdir/TAGS"; \ + fi; \ + done; \ + list='$(SOURCES) $(HEADERS)'; \ + unique=`for i in $$list; do echo $$i; done | \ + awk ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(ETAGS_ARGS)$$unique$(LISP)$$tags" \ + || (cd $(srcdir) && etags $(ETAGS_ARGS) $$tags $$unique $(LISP) -o $$here/TAGS) + +DEP_SOURCES = $(wildcard *.c *.cpp) + +# This is a filter to turn "foo.o:" rules into "foo.o foo.lo:" because Libtool +# uses .lo for object files. I'd like to purge the build of Libtool some day +# and eliminate this complication. + +LIBTOOL_DEPEND_MASSAGER = perl -walnpe's{^(.*)\.o:}{$$1.o $$1.lo:}' + + + +.PHONY: dep-common +dep-common: FORCE +ifneq ($(DEP_SOURCES)x,x) + -$(CC) -MM -MG -I. $(INCLUDES) $(DEP_SOURCES) | \ + $(LIBTOOL_DEPEND_MASSAGER) \ + >Makefile.depend +endif + +Makefile.depend: + cat /dev/null >$@ + +# The automatic dependency generation is a pain in the butt and +# totally unnecessary for people just installing the distributed code, +# so to avoid needless failures in the field and a complex build, the +# 'distclean' target simply makes Makefile.depend an empty file. A +# developer may do 'make dep' to create a Makefile.depend full of real +# dependencies. + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: + + +# Use the FORCE target as a dependency to force a target to get remade +FORCE: diff --git a/Makefile.config.in b/Makefile.config.in new file mode 100644 index 0000000..07f37af --- /dev/null +++ b/Makefile.config.in @@ -0,0 +1,253 @@ +# Makefile.config is generated by 'configure' using Makefile.config.in +# as a template and information that 'configure' gathers from the build +# system and from user options. + +# Makefile.config should someday replace most of the other files that +# 'configure' generates, thus simplifying development and customization. +# Makefile.config is intended to contain information specific to the +# particular build environment or user build choices. + +# Furthermore, most of the logic in 'configure', and thus 'configure.in', +# should go into the make files to simplify the build. Makefile.config +# should just pass raw configure variables through to the make file. + +# Tokens of the form @TOKEN@ in the template file get replaced by +# 'configure' with the values of variables of the same name within +# 'configure', because of a AC_SUBST(TOKEN) statement in the +# 'configure.in' from which 'configure' was built. + +# Here are the options the user chose on 'configure': + +ENABLE_ABYSS_SERVER = @ENABLE_ABYSS_SERVER@ +ENABLE_ABYSS_THREADS = @ENABLE_ABYSS_THREADS@ +ENABLE_CPLUSPLUS = @ENABLE_CPLUSPLUS@ +ENABLE_CGI_SERVER = @ENABLE_CGI_SERVER@ +ENABLE_LIBXML2_BACKEND = @ENABLE_LIBXML2_BACKEND@ + +MUST_BUILD_WININET_CLIENT = @MUST_BUILD_WININET_CLIENT@ +MUST_BUILD_CURL_CLIENT = @MUST_BUILD_CURL_CLIENT@ +MUST_BUILD_LIBWWW_CLIENT = @MUST_BUILD_LIBWWW_CLIENT@ + +HAVE_WCHAR_H_DEFINE = @HAVE_WCHAR_H_DEFINE@ + +# Stuff 'configure' figured out about our build platform: + +SHELL = @SHELL@ +CC = @CC@ +CXX = @CXX@ +CCLD = $(CC) +CXXLD = $(CXX) +AR = ar +RANLIB = @RANLIB@ +LN_S = @LN_S@ +INSTALL = $(SRCDIR)/install-sh + +C_COMPILER_GNU = @C_COMPILER_GNU@ +CXX_COMPILER_GNU = @CXX_COMPILER_GNU@ + +# Stuff 'configure' figured out via AC_CANONICAL_HOST macro in configure.in +# and config.guess program and 'configure' command options: + +# HOST_OS names the operating system on which Xmlrpc-c is to run. +# E.g. "linux-gnu". +HOST_OS = @host_os@ + +# Hardcoded in configure.in: +XMLRPC_C_VERSION = @VERSION@ + +############################################################################### + +MUST_BUILD_CLIENT = no +ifeq ($(MUST_BUILD_WININET_CLIENT),yes) + MUST_BUILD_CLIENT = yes +endif +ifeq ($(MUST_BUILD_CURL_CLIENT),yes) + MUST_BUILD_CLIENT = yes +endif +ifeq ($(MUST_BUILD_LIBWWW_CLIENT),yes) + MUST_BUILD_CLIENT = yes +endif + + +############################################################################## +# SHARED LIBRARY STUFF +############################################################################## + +# Shared libraries are very difficult, because how you build and use +# them varies greatly from one platform to the next. # There are two +# ways shared libraries get built in the Xmlrpc-c build: Libtool and +# direct. In the beginning, there was just Libtool. Libtool is +# supposed to solve the problem of the diversity of shared libraries, +# but it does it by adding a layer of complexity and yet another build +# tool a developer has to know. The encapsulation of shared library +# building reduced flexibility and makes diagnosing problems much +# harder. So we are phasing out Libtool. New libraries (in +# particular, the C++ ones) don't involve Libtool. Some day, the +# older ones won't either, but we aren't as good yet with the direct +# method as with Libtool, and we don't want to break something that's +# working. + +# First, we break down shared library schemes into a few major types, +# and indicate the type by SHARED_LIB_TYPE. + +# We also have a bunch of other make variables that reflect the different +# ways we have to build on and for different platforms: + +# CFLAGS_SHLIB is a set of flags needed to compile a module which will +# become part of a shared library. + +# On older systems, you have to make shared libraries out of position +# independent code, so you need -fpic or -fPIC here. (The rule is: if +# -fpic works, use it. If it bombs, go to -fPIC). On newer systems, +# it isn't necessary, but can save real memory at the expense of +# execution speed. Without position independent code, the library +# loader may have to patch addresses into the executable text. On an +# older system, this would cause a program crash because the loader +# would be writing into read-only shared memory. But on newer +# systems, the system silently creates a private mapping of the page +# or segment being modified (the "copy on write" phenomenon). So it +# needs its own private real page frame. + +# We have seen -fPIC required on IA64 and AMD64 machines (GNU +# compiler/linker). Build-time linking fails without it. I don't +# know why -- history seems to be repeating itself. 2005.02.23. + +# SHLIB_CLIB is the link option to include the C library in a shared library, +# normally "-lc". On typical systems, this serves no purpose. On some, +# though, it causes information about which C library to use to be recorded +# in the shared library and thus choose the correct library among several or +# avoid using an incompatible one. But on some systems, the link fails. +# On 2002.09.30, "John H. DuBois III" reports that on +# SCO OpenServer, he gets the following error message with -lc: +# +# -lc; relocations referenced ; from file(s) /usr/ccs/lib/libc.so(random.o); +# fatal error: relocations remain against allocatable but non-writable +# section: ; .text +# +# On Bryan's system, with gcc 2.95.3 and glibc 2.2.2, -lc causes +# throws (from anywhere in a program that links the shared library) +# not to work. I have no idea how. + +# LDFLAGS_SHLIB is the linker (Ld) flags needed to generate a shared +# library from object files. It may use $(SONAME) as the soname for +# the shared library being created (assuming sonames exist). + +# We build shared libraries only for platforms for which we've figured +# out how. For the rest, we have this default: +SHARED_LIB_TYPE = NONE + +ifeq ($(HOST_OS),linux-gnu) + # Assume linker is GNU Compiler (gcc) + SHARED_LIB_TYPE = unix + SHLIB_SUFFIX = so +# SHLIB_CLIB = -lc + LDFLAGS_SHLIB = -shared -Wl,-soname,$(SONAME) $(SHLIB_CLIB) +endif + +ifeq ($(findstring solaris,$(HOST_OS)),solaris) + # This code is not finished; that's why we don't set SHARED_LIB_TYPE. + # If you can finish it and make it work on AIX, please do. + # SHARED_LIB_TYPE = unix + SHLIB_SUFFIX = so + # Solaris compiler can't take multiple ld options as -Wl,-a,-b . Ld sees + # -a,-b in that case. + LDFLAGS_SHLIB = -Wl,-Bdynamic -Wl,-G -Wl,-h -Wl,$(SONAME) + CFLAGS_SHLIB = -Kpic +endif + +ifeq ($(HOST_OS),aix) + # This code is not finished; that's why we don't set SHARED_LIB_TYPE. + # If you can finish it and make it work on AIX, please do. + # SHARED_LIB_TYPE = unix + SHLIB_SUFFIX = a + LDFLAGS_SHLIB = -qmkshrobj +endif + +ifeq ($(HOST_OS),irix) + # This code is not finished; that's why we don't set SHARED_LIB_TYPE. + # If you can finish it and make it work on AIX, please do. + # SHARED_LIB_TYPE = irix + SHLIB_SUFFIX = so + LDFLAGS_SHLIB = -shared -n32 +endif + +ifeq ($(HOST_OS),hpux) + # This code is not finished; that's why we don't set SHARED_LIB_TYPE. + # If you can finish it and make it work on AIX, please do. + # SHARED_LIB_TYPE = unix + SHLIB_SUFFIX = sl + LDFLAGS_SHLIB: -shared -fPIC +endif + +ifeq ($(HOST_OS),osf) + # This code is not finished; that's why we don't set SHARED_LIB_TYPE. + # If you can finish it and make it work on AIX, please do. + # SHARED_LIB_TYPE = unix + SHLIB_SUFFIX = so + LDFLAGS_SHLIB = -shared -expect_unresolved +endif + +ifeq ($(findstring netbsd,$(HOST_OS)),netbsd) + # This code is not finished; that's why we don't set SHARED_LIB_TYPE. + # If you can finish it and make it work on AIX, please do. + # SHARED_LIB_TYPE = unix + SHLIB_SUFFIX = so + CFLAGS_SHLIB = -fpic +endif + +ifeq ($(HOST_OS),darwin) + # This code is not finished; that's why we don't set SHARED_LIB_TYPE. + # If you can finish it and make it work on AIX, please do. + # SHARED_LIB_TYPE = dylib + SHLIB_SUFFIX = dylib +endif + +ifeq ($(HOST_OS),beos) + # This code is not finished; that's why we don't set SHARED_LIB_TYPE. + # If you can finish it and make it work on AIX, please do. + # SHARED_LIB_TYPE = unix + SHLIB_SUFFIX = so + LDFLAGS_SHLIB = -nostart +endif + +ifeq ($(HOST_OS),cygwin) + # This code is not finished; that's why we don't set SHARED_LIB_TYPE. + # If you can finish it and make it work on AIX, please do. + # SHARED_LIB_TYPE = dll + SHLIB_SUFFIX = dll +endif + +############################################################################## +# MISCELLANEOUS +############################################################################## + +# BUILDTOOL_CC is the compiler to use to generate build tools, which we +# will then run to build product. The typical reason this would be +# different from CC is that you're cross-compiling: the product will run +# in Environment A, but you're building in Environment B, so you must +# build the build toos for Environment B. + +# The cross compiling user can update Makefile.config or override +# BUILDTOOL_CC on a make command. + +BUILDTOOL_CC = $(CC) +BUILDTOOL_CCLD = $(CCLD) + +# Here are the commands 'make install' uses to install various kinds of files: + +INSTALL_PROGRAM = $(INSTALL) -c -m 755 +INSTALL_SHLIB = $(INSTALL) -c -m 755 +INSTALL_DATA = $(INSTALL) -c -m 644 +INSTALL_SCRIPT = $(INSTALL) -c -m 755 + +# Here are the locations at which 'make install' puts files: + +# DESTDIR is designed to be overriden at make time in order to relocate +# the entire install into a subdirectory. +DESTDIR = + +exec_prefix = @exec_prefix@ +prefix = @prefix@ +LIBINST_DIR = @libdir@ +HEADERINST_DIR = @includedir@ +PROGRAMINST_DIR = @bindir@ diff --git a/Makefile.depend b/Makefile.depend new file mode 100644 index 0000000..e69de29 diff --git a/README b/README new file mode 100644 index 0000000..eefe8e1 --- /dev/null +++ b/README @@ -0,0 +1,55 @@ +This is the source code for XML-RPC for C/C++, called Xmlrpc-c for short. + +XML-RPC for C/C++ is programming libraries and related tools to help you +write an XML-RPC server or client in C or C++. + +Documentation for the package is at + + http://xmlrpc-c.sourceforge.net/doc + +See the Xmlrpc-c website at: + + http://xmlrpc-c.sourceforge.net/ + + +PREREQUISITES +------------- + +To build a useful Xmlrpc-c client library, you'll need to have at +least one HTTP library. Xmlrpc-c knows how to use W3C Libwww (Version +5.3.2 or newer), Curl, and Wininet. The configurator gives you the +option of building libraries that use any or all of these, and +defaults to every one you appear to have installed. If you don't +appear to have any installed, the configurator causes the build to +omit client facilities altogether. + +Information about W3C Libwww, including how to get it are at +. + +For Curl, see . + +Wininet comes with Windows, and isn't available for any other platform. + +You also need an XML parser/builder library. An old version of Expat +is included in the package and used by default, so there's no actual +prerequisite here. But if you separately obtain Libxml2, you can +configure the build to use that instead. There's no really pressing +reason to do that, though. + +BUILDING, INSTALLING +-------------------- + +See the file doc/INSTALL. + +In the simplest case, it's just a conventional + + $ ./configure + $ make + $ make install + + +ADDITIONAL INFORMATION +---------------------- + +See the doc/ directory of the source tree for information about the +source code. User documentation is on the web, as described above. diff --git a/Windows/.cvsignore b/Windows/.cvsignore new file mode 100644 index 0000000..cc8f7bb --- /dev/null +++ b/Windows/.cvsignore @@ -0,0 +1,9 @@ +Debug +Release +*.log +*.ncb +*.opt +*.plg +*.suo +BuildLog.htm + diff --git a/Windows/ConfigureWin32.bat b/Windows/ConfigureWin32.bat new file mode 100644 index 0000000..75d8421 --- /dev/null +++ b/Windows/ConfigureWin32.bat @@ -0,0 +1,7 @@ +@echo off +echo creating Win32 header files... +copy .\xmlrpc_win32_config.h ..\config.h +copy .\xmlrpc_win32_config.h ..\xmlrpc_config.h +copy .\transport_config_win32.h ..\transport_config.h +echo completed creating win32 header files. +pause diff --git a/Windows/ReadMeWin32.txt b/Windows/ReadMeWin32.txt new file mode 100644 index 0000000..48fa1d3 --- /dev/null +++ b/Windows/ReadMeWin32.txt @@ -0,0 +1,116 @@ +Build Instructions For XML-RPC For C/C++ On Windows +--------------------------------------------------- + +The following instructions do not fully work in this release. There +is no trivial way to build this release for Windows. The last release +that was known to build without special effort on the part of the user +is 1.02. + +Since then, nobody has maintained the code for Windows, and changes that +were made for other platforms broke some things for Windows. Most likely, +anyone with a passing knowledge of building C code on Windows could +update this code to work on Windows without any in-depth study of it. If +you do so, please contribute your work to save other users the trouble. + +The majority of the work that needs to be done to make the code build on +Windows is simply adjusting project files to reflect the fact that files +have been created, deleted, and moved since they were written. + + +This release includes the option to compile an "http.sys" version of an +XML-RPC server. If you do not wish to build in the http.sys server, +set the MUST_BUILD_HTTP_SYS_SERVER to 0 in the transport_config_win32.h and/or +the transport_config.h file. Successful conpilation requires installation +of the Microsoft Platform SDK for Windows XP SP2 (or later) to get the latest +header and link libraries required to support this functionality. After +installation, be sure to properly register the directories as documented +in the Platform SDK help file topic "Installing the Platform SDK with +Visual Studio". Download the Platform SDK from: +http://www.microsoft.com/msdownload/platformsdk/sdkupdate/ + +To create the three headers required for Win32 WinInet compilation, run the +ConfigureWin32.bat found in the Windows directory. If you wish to alter the +transports that are built to include curl or libwww, adjust the preprocessor +definitions at the top of the transport_config_win32.h and/or +the transport_config.h files. See the file UsingCURLinWin32.txt for +more information on using the curl transport. + +To compile, open the xmlrpc.dsw file in Visual Studio 6 or greater. The +project will convert and work fine in Visual Studio 2003 as well - +other versions of Visual Studio were not tested. +NOTE: If you get an error while opening or converting the project files, +it is likely due to using WinRar or similar to decompress the distribution +tarball. You can use WinZip or another utility to correctly decompress the +.tgz file. + +Suggested testing for evaluation of the library involves a few projects. +Here is a quick getting started guide: + +1) Set the Active Project to query_meerkat and build it in release or debug + modes. The dependent projects will be built automatically. In the + project settings dialog, add the argument for what you wish to query + meerkat for - "Windows" is a good query. Run the project. This will + query the meerkat server for articles related to windows and output the + results to the console. + +2) Set the Active Project to xmlrpc_sample_add_server and build it in + release or debug modes. The dependent projects will be built + automatically. In the project settings dialog, add the argument for + the port to 8080. This will run the server sample which adds two + numbers and returns a result. You should run this from a command + prompt instead of through Visual Studio so you may run the sample + client as well. + +3) Set the Active Project to xmlrpc_sample_add_sync_client or + xmlrpc_sample_add_async_client and build it in release or debug modes. + The dependent projects will be built automatically. This will run + the client sample which submits two numbers to be added to the server + application as described above and displays the result. Note that the + client example comes in the sync and async varieties. + +Steven Bone +July 27, 2005 +sbone@pobox.com + +WIN32 CHANGES + +Changes from the 1.02 release for Win32: +1) Option to easily disable the http.sys server for those who do not need + it or wish to download the Platform SDK. + +Changes from the 1.01 -> 1.02 release for Win32: +1) Project files for gennmtab, xmlparse, and xmltok updated to include the + path to the xmlrpc_config.h file. +2) Bugfix for WinInet authentication. +3) Supports xmlrpc_xportparms, xmlrpc_wininet_xportparms added + *potential breaking change* - now by default we fail on invalid + SSL certs, use the xmlrpc_wininet_xportparms option to enable old + behavior. +4) Added project file for xmlrpc_sample_auth_client +5) Added project and src for a http.sys based xmlrpc-c server. See comments + in the source files. This supports Windows XP SP2 and Windows Server + 2003 and allows other http.sys based applications to bind to the same + port. In Server 2003, IIS uses http.sys and thus the XML-RPC server + can be run on the standard port 80 along with IIS. The sample also + supports https and basic authentication. It tested OK with + http://validator.xmlrpc.com/ Note that the Platform SDK headers and + link libraries for Windows XP SP2 or newer are required to compile + xmlrpc-c for this module. If you are not using this server, it is + safe to exclude the xmlrpc_server_w32httpsys.c file from the xmlrpc + project and these dependencies will not be required. You can get the + latest platform SDK at + http://www.microsoft.com/msdownload/platformsdk/sdkupdate/ + Be sure after installation to choose the program to "register the PSDK + directories with Visual Studio" so the newer headers are found. +6) Better support for libcurl. Updated project files, transport_config_win32.h, + added documentation UsingCURLinWin32.txt. + +Changes from the 1.00 -> 1.01 release for Win32: +1) Project files now reflect static linking for the expat XML library. +2) Example projects were created/updated to keep them in sync with the + distribution. The project files were moved into the .\Windows + directory +3) Projects for the rpc and cpp tests were created. The + xmlrpc_win32_config.h defines the directory for the test files relative + to the output directory +4) Major refactoring of the Wininet Transport. \ No newline at end of file diff --git a/Windows/UsingCURLinWin32.txt b/Windows/UsingCURLinWin32.txt new file mode 100644 index 0000000..fe8b934 --- /dev/null +++ b/Windows/UsingCURLinWin32.txt @@ -0,0 +1,64 @@ +Background: +Let’s say you need to support a xmlrpc-c client running as a service. In this +situation you cannot use WinInet. Details of the restriction can be found on +the libcurl website or various Microsoft KB articles. The alternative is to use +libcurl. This document describes the steps required to use libcurl as your +transport mechanism as supported by the latest files and projects provided in +the xmlrpc-c distribution. The assumption is that you can successfully compile +the distribution of xmlrpc-c. + +Overview: +The default projects in xmlrpc-c create standalone executables that do not +require other DLL’s (release mode). While the case can be made for this +behavior pro and con, it is beyond this document to justify it. Therefore, we +need to create static link libraries for libcurl that mimics this behavior. +Once the link libraries are created, we can then add them (plus the requisite +curl headers) into the xmlrpc-c project. Finally, we enable the compilation of +the curl transport file and tell xmlrpc-c that we will be using curl. Lastly, +we build and test the project. + +Steps to use CURL with Win32 xmlrpc-c: +1. Download the CURL source. In the “include” folder of the CURL distribution, +copy the curl directory to the “lib” directory of xmlbpc-c. When you are done +with this step, you should have a curl.h file located in the directory +xmlrpc-c\lib\curl\. The xmlrpc project looks in this relative path for the +necessary headers. + +2. In the CURL distribution, lib directory, is a file called Makefile.vc6. Edit +this file. The line starting with CCNODBG should be changed to: +CCNODBG = cl.exe /MT /O2 /DNDEBUG +The /MT option links with the Multithreaded non-dll version of the c runtime. +If this change is not made, the project will not link, as this is the default +setting for the xmlrpc-c projects. In debug mode, we use the dll version of the +c runtime as it makes memory leak checking tools work better. + +3. Open a command prompt window and run the vcvars32.bat file in your Visual C++ +distribution. If you are using Studio 2002 or 2003, use the “Visual Studio +Command Prompt” from the Start menu to open the console. + +4. Compile release and debug mode libraries. For the purposes of this tutorial, +we are going to build only the curl library without ssl or zlib support. In the +command prompt, navigate to the curl\lib directory and execute the following +commands: +nmake -f Makefile.vc6 CFG=debug +nmake -f Makefile.vc6 CFG=release + +5. The above step should have generated two static link libraries in the +curl\lib directory: libcurl.lib and libcurld.lib. Copy these files into the +root of the xmlrpc-c\lib\ directory. This step ends our involvement with the +actual CURL distribution. The remainder of the steps are for XMLRPC-C. + +6. Open the xmlrpc-c Visual Studio workspace (Instructions for VC++ 6, other +versions are slightly different). In File View, expand the xmlrpc project. +Under “Source Files” there is an entry for xmlrpc_curl_transport.c This is not +included in any build paths by default. To enable it for compilation, right +click the file to change the settings. In the dropdown, select “All +Configurations.” Pick the General tab and uncheck the “Exclude File From Build” +setting. Press OK to save your changes to the project. + +7. In the “Header Files” section of the xmlrpc project is a file called +“transport_config.h”. Edit this file to set the MUST_BUILD_CURL_CLIENT to 1, +and if you wish to change the default transport to curl, change the +XMLRPC_DEFAULT_TRANSPORT to “curl”. + +8. Compile and test one or more of the sample client projects. diff --git a/Windows/abyss.dsp b/Windows/abyss.dsp new file mode 100644 index 0000000..8b19d8a --- /dev/null +++ b/Windows/abyss.dsp @@ -0,0 +1,140 @@ +# Microsoft Developer Studio Project File - Name="abyss" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Static Library" 0x0104 + +CFG=abyss - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "abyss.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "abyss.mak" CFG="abyss - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "abyss - Win32 Release" (based on "Win32 (x86) Static Library") +!MESSAGE "abyss - Win32 Debug" (based on "Win32 (x86) Static Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "abyss - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release\Abyss" +# PROP Intermediate_Dir "Release\Abyss" +# PROP Target_Dir "" +MTL=midl.exe +LINK32=link.exe -lib +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c +# ADD CPP /nologo /MT /W3 /GX /O2 /I "..\\" /I "..\include" /I "..\lib\util\include" /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /D "ABYSS_WIN32" /D "_THREAD" /YX /FD /c +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo /out:"..\lib\abyss.lib" + +!ELSEIF "$(CFG)" == "abyss - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug\abyss" +# PROP Intermediate_Dir "Debug\abyss" +# PROP Target_Dir "" +MTL=midl.exe +LINK32=link.exe -lib +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c +# ADD CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /I "..\\" /I "..\include" /I "..\lib\util\include" /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /D "ABYSS_WIN32" /D "_THREAD" /YX /FD /GZ /c +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo /out:"..\lib\abyssD.lib" + +!ENDIF + +# Begin Target + +# Name "abyss - Win32 Release" +# Name "abyss - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=..\lib\abyss\src\conf.c +# End Source File +# Begin Source File + +SOURCE=..\lib\abyss\src\conn.c +# End Source File +# Begin Source File + +SOURCE=..\lib\abyss\src\data.c +# End Source File +# Begin Source File + +SOURCE=..\lib\abyss\src\file.c +# End Source File +# Begin Source File + +SOURCE=..\lib\abyss\src\http.c +# End Source File +# Begin Source File + +SOURCE=..\lib\abyss\src\server.c +# End Source File +# Begin Source File + +SOURCE=..\lib\abyss\src\socket.c +# End Source File +# Begin Source File + +SOURCE=..\lib\abyss\src\thread.c +# End Source File +# Begin Source File + +SOURCE=..\lib\abyss\src\token.c +# End Source File +# Begin Source File + +SOURCE=..\lib\abyss\src\trace.c +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=..\lib\abyss\src\token.h +# End Source File +# End Group +# End Target +# End Project diff --git a/Windows/all.dsp b/Windows/all.dsp new file mode 100644 index 0000000..c3f9955 --- /dev/null +++ b/Windows/all.dsp @@ -0,0 +1,97 @@ +# Microsoft Developer Studio Project File - Name="all" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) External Target" 0x0106 + +CFG=all - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "all.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "all.mak" CFG="all - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "all - Win32 Release" (based on "Win32 (x86) External Target") +!MESSAGE "all - Win32 Debug" (based on "Win32 (x86) External Target") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" + +!IF "$(CFG)" == "all - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Cmd_Line "" +# PROP BASE Rebuild_Opt "" +# PROP BASE Target_File "../config.h" +# PROP BASE Bsc_Name "" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Cmd_Line "" +# PROP Rebuild_Opt "" +# PROP Target_File "../all" +# PROP Bsc_Name "" +# PROP Target_Dir "" + +!ELSEIF "$(CFG)" == "all - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Cmd_Line "" +# PROP BASE Rebuild_Opt "" +# PROP BASE Target_File "../config.h" +# PROP BASE Bsc_Name "" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "" +# PROP Intermediate_Dir "" +# PROP Cmd_Line "" +# PROP Rebuild_Opt "" +# PROP Target_File "../all" +# PROP Bsc_Name "" +# PROP Target_Dir "" + +!ENDIF + +# Begin Target + +# Name "all - Win32 Release" +# Name "all - Win32 Debug" + +!IF "$(CFG)" == "all - Win32 Release" + +!ELSEIF "$(CFG)" == "all - Win32 Debug" + +!ENDIF + +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# End Group +# Begin Group "Resource Files" + +# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" +# End Group +# End Target +# End Project diff --git a/Windows/all.vcproj b/Windows/all.vcproj new file mode 100644 index 0000000..b3e1baa --- /dev/null +++ b/Windows/all.vcproj @@ -0,0 +1,67 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Windows/configwin32.dsp b/Windows/configwin32.dsp new file mode 100644 index 0000000..e806f15 --- /dev/null +++ b/Windows/configwin32.dsp @@ -0,0 +1,97 @@ +# Microsoft Developer Studio Project File - Name="configwin32" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) External Target" 0x0106 + +CFG=configwin32 - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "configwin32.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "configwin32.mak" CFG="configwin32 - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "configwin32 - Win32 Release" (based on "Win32 (x86) External Target") +!MESSAGE "configwin32 - Win32 Debug" (based on "Win32 (x86) External Target") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" + +!IF "$(CFG)" == "configwin32 - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Cmd_Line "ConfigureWin32.bat" +# PROP BASE Rebuild_Opt "" +# PROP BASE Target_File "../config.h" +# PROP BASE Bsc_Name "" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Cmd_Line "ConfigureWin32.bat" +# PROP Rebuild_Opt "" +# PROP Target_File "../config.h" +# PROP Bsc_Name "" +# PROP Target_Dir "" + +!ELSEIF "$(CFG)" == "configwin32 - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Cmd_Line "ConfigureWin32.bat" +# PROP BASE Rebuild_Opt "" +# PROP BASE Target_File "../config.h" +# PROP BASE Bsc_Name "" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "" +# PROP Intermediate_Dir "" +# PROP Cmd_Line "ConfigureWin32.bat" +# PROP Rebuild_Opt "" +# PROP Target_File "../config.h" +# PROP Bsc_Name "" +# PROP Target_Dir "" + +!ENDIF + +# Begin Target + +# Name "configwin32 - Win32 Release" +# Name "configwin32 - Win32 Debug" + +!IF "$(CFG)" == "configwin32 - Win32 Release" + +!ELSEIF "$(CFG)" == "configwin32 - Win32 Debug" + +!ENDIF + +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# End Group +# Begin Group "Resource Files" + +# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" +# End Group +# End Target +# End Project diff --git a/Windows/configwin32.vcproj b/Windows/configwin32.vcproj new file mode 100644 index 0000000..f7ce8b7 --- /dev/null +++ b/Windows/configwin32.vcproj @@ -0,0 +1,71 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Windows/cpptest.dsp b/Windows/cpptest.dsp new file mode 100644 index 0000000..babbc98 --- /dev/null +++ b/Windows/cpptest.dsp @@ -0,0 +1,102 @@ +# Microsoft Developer Studio Project File - Name="cpptest" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + +CFG=cpptest - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "cpptest.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "cpptest.mak" CFG="cpptest - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "cpptest - Win32 Release" (based on "Win32 (x86) Console Application") +!MESSAGE "cpptest - Win32 Debug" (based on "Win32 (x86) Console Application") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "cpptest" +# PROP Scc_LocalPath ".." +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "cpptest - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release\cpptest" +# PROP Intermediate_Dir "Release\cpptest" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /MT /W3 /GX /O2 /I "..\\" /I "..\src" /D "NDEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib ..\lib\xmlrpc.lib /nologo /subsystem:console /machine:I386 /out:"..\bin\cpptest.exe" + +!ELSEIF "$(CFG)" == "cpptest - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug\cpptest" +# PROP Intermediate_Dir "Debug\cpptest" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c +# ADD CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /I "..\\" /I "..\src" /D "_DEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib ..\lib\xmlrpcD.lib /nologo /subsystem:console /debug /machine:I386 /out:"..\bin\cpptest.exe" /pdbtype:sept + +!ENDIF + +# Begin Target + +# Name "cpptest - Win32 Release" +# Name "cpptest - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=..\src\cpptest.cpp +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# End Group +# Begin Group "Resource Files" + +# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" +# End Group +# End Target +# End Project diff --git a/Windows/cpptest.vcproj b/Windows/cpptest.vcproj new file mode 100644 index 0000000..1d50717 --- /dev/null +++ b/Windows/cpptest.vcproj @@ -0,0 +1,168 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Windows/query_meerkat.dsp b/Windows/query_meerkat.dsp new file mode 100644 index 0000000..2ffb15b --- /dev/null +++ b/Windows/query_meerkat.dsp @@ -0,0 +1,100 @@ +# Microsoft Developer Studio Project File - Name="query_meerkat" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + +CFG=query_meerkat - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "query_meerkat.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "query_meerkat.mak" CFG="query_meerkat - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "query_meerkat - Win32 Release" (based on "Win32 (x86) Console Application") +!MESSAGE "query_meerkat - Win32 Debug" (based on "Win32 (x86) Console Application") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "query_meerkat" +# PROP Scc_LocalPath ".." +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "query_meerkat - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release\query_meerkat" +# PROP Intermediate_Dir "Release\query_meerkat" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /MT /W3 /GX /O2 /I "..\\" /I "..\include" /D "NDEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 +# ADD LINK32 ..\lib\xmlrpc.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib WinInet.lib /nologo /subsystem:console /machine:I386 /out:"..\bin\query_meerkat.exe" + +!ELSEIF "$(CFG)" == "query_meerkat - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug\query_meerkat" +# PROP Intermediate_Dir "Debug\query_meerkat" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c +# ADD CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /I "..\\" /I "..\include" /D "_DEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept +# ADD LINK32 ..\lib\xmlrpcD.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib WinInet.lib /nologo /subsystem:console /debug /machine:I386 /out:"..\bin\query_meerkatD.exe" /pdbtype:sept + +!ENDIF + +# Begin Target + +# Name "query_meerkat - Win32 Release" +# Name "query_meerkat - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE="..\examples\query-meerkat.c" +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# End Group +# Begin Group "Resource Files" + +# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" +# End Group +# End Target +# End Project diff --git a/Windows/query_meerkat.vcproj b/Windows/query_meerkat.vcproj new file mode 100644 index 0000000..4159629 --- /dev/null +++ b/Windows/query_meerkat.vcproj @@ -0,0 +1,168 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Windows/rpctest.dsp b/Windows/rpctest.dsp new file mode 100644 index 0000000..f47498b --- /dev/null +++ b/Windows/rpctest.dsp @@ -0,0 +1,236 @@ +# Microsoft Developer Studio Project File - Name="rpctest" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + +CFG=rpctest - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "rpctest.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "rpctest.mak" CFG="rpctest - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "rpctest - Win32 Release" (based on "Win32 (x86) Console Application") +!MESSAGE "rpctest - Win32 Debug" (based on "Win32 (x86) Console Application") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "rpctest" +# PROP Scc_LocalPath ".." +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "rpctest - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release\rpctest" +# PROP Intermediate_Dir "Release\rpctest" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /MT /W3 /GX /O2 /I "..\\" /I "..\include" /I "../lib/util/include" /D "NDEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D "ABYSS_WIN32" /YX /FD /c +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 +# ADD LINK32 ..\lib\xmlrpc.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib Ws2_32.lib Wininet.lib /nologo /subsystem:console /machine:I386 /out:"..\bin\rpctest.exe" +# Begin Special Build Tool +SOURCE="$(InputPath)" +PostBuild_Desc=Copy test files +PostBuild_Cmds=copy ..\src\testdata\*.* . +# End Special Build Tool + +!ELSEIF "$(CFG)" == "rpctest - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug\rpctest" +# PROP Intermediate_Dir "Debug\rpctest" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c +# ADD CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /I "..\\" /I "..\include" /I "../lib/util/include" /D "_DEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D "ABYSS_WIN32" /YX /FD /GZ /c +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept +# ADD LINK32 ..\lib\xmlrpcD.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib Ws2_32.lib Wininet.lib /nologo /subsystem:console /debug /machine:I386 /out:"..\bin\rpctestD.exe" /pdbtype:sept +# Begin Special Build Tool +SOURCE="$(InputPath)" +PostBuild_Desc=Copy test files +PostBuild_Cmds=copy ..\src\testdata\*.* . +# End Special Build Tool + +!ENDIF + +# Begin Target + +# Name "rpctest - Win32 Release" +# Name "rpctest - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=..\src\test\cgi.c +# End Source File +# Begin Source File + +SOURCE=..\src\test\client.c +# End Source File +# Begin Source File + +SOURCE=..\lib\abyss\src\conf.c +# End Source File +# Begin Source File + +SOURCE=..\lib\abyss\src\conn.c +# End Source File +# Begin Source File + +SOURCE=..\lib\abyss\src\data.c +# End Source File +# Begin Source File + +SOURCE=..\lib\abyss\src\file.c +# End Source File +# Begin Source File + +SOURCE=..\lib\abyss\src\http.c +# End Source File +# Begin Source File + +SOURCE=..\src\test\parse_xml.c +# End Source File +# Begin Source File + +SOURCE=..\src\test\serialize.c +# End Source File +# Begin Source File + +SOURCE=..\lib\abyss\src\server.c +# End Source File +# Begin Source File + +SOURCE=..\src\test\server_abyss.c +# End Source File +# Begin Source File + +SOURCE=..\lib\abyss\src\socket.c +# End Source File +# Begin Source File + +SOURCE=..\src\test\test.c +# End Source File +# Begin Source File + +SOURCE=..\lib\abyss\src\thread.c +# End Source File +# Begin Source File + +SOURCE=..\lib\abyss\src\token.c +# End Source File +# Begin Source File + +SOURCE=..\lib\abyss\src\token.h +# End Source File +# Begin Source File + +SOURCE=..\lib\abyss\src\trace.c +# End Source File +# Begin Source File + +SOURCE=..\src\test\value.c +# End Source File +# Begin Source File + +SOURCE=..\src\test\xml_data.c +# End Source File +# Begin Source File + +SOURCE=..\src\xmlrpc_server_abyss.c +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=..\src\test\client.h +# End Source File +# Begin Source File + +SOURCE=..\src\test\parse_xml.h +# End Source File +# Begin Source File + +SOURCE=..\src\test\serialize.h +# End Source File +# Begin Source File + +SOURCE=..\src\test\server_abyss.h +# End Source File +# Begin Source File + +SOURCE=..\src\test\test.h +# End Source File +# Begin Source File + +SOURCE=..\src\test\value.h +# End Source File +# Begin Source File + +SOURCE=..\src\test\xml_data.h +# End Source File +# End Group +# Begin Group "Resource Files" + +# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" +# End Group +# Begin Group "TestFiles" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE="..\src\testdata\http-req-simple.txt" +# End Source File +# Begin Source File + +SOURCE=..\src\testdata\req_no_params.xml +# End Source File +# Begin Source File + +SOURCE=..\src\testdata\req_out_of_order.xml +# End Source File +# Begin Source File + +SOURCE=..\src\testdata\req_value_name.xml +# End Source File +# End Group +# End Target +# End Project diff --git a/Windows/rpctest.vcproj b/Windows/rpctest.vcproj new file mode 100644 index 0000000..90b53b3 --- /dev/null +++ b/Windows/rpctest.vcproj @@ -0,0 +1,574 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Windows/transport_config_win32.h b/Windows/transport_config_win32.h new file mode 100644 index 0000000..09f1ca9 --- /dev/null +++ b/Windows/transport_config_win32.h @@ -0,0 +1,26 @@ +#define MUST_BUILD_WININET_CLIENT 1 +#define MUST_BUILD_CURL_CLIENT 0 +#define MUST_BUILD_LIBWWW_CLIENT 0 +static const char * const XMLRPC_DEFAULT_TRANSPORT = "wininet"; + +/* +Set to zero if you do not wish to build the http.sys +based XMLRPC-C Server +*/ +#define MUST_BUILD_HTTP_SYS_SERVER 1 + +/* +We use pragma statements to tell the linker what we need to link with. +Since Curl requires Winsock, Winmm, and libcurl, and no other +project does, if we are building curl support we tell the linker +what libs we need to add. +*/ +#if MUST_BUILD_CURL_CLIENT > 0 +#ifdef _DEBUG +#pragma comment( lib, "../lib/libcurld.lib" ) +#else +#pragma comment( lib, "../lib/libcurl.lib" ) +#endif +#pragma comment( lib, "Winmm.lib" ) +#pragma comment( lib, "Ws2_32.lib" ) +#endif \ No newline at end of file diff --git a/Windows/win32_config.h b/Windows/win32_config.h new file mode 100644 index 0000000..6aaadb0 --- /dev/null +++ b/Windows/win32_config.h @@ -0,0 +1,2 @@ +#include "xmlrpc_config.h" + diff --git a/Windows/xmlrpc.dsp b/Windows/xmlrpc.dsp new file mode 100644 index 0000000..9182914 --- /dev/null +++ b/Windows/xmlrpc.dsp @@ -0,0 +1,258 @@ +# Microsoft Developer Studio Project File - Name="xmlrpc" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Static Library" 0x0104 + +CFG=xmlrpc - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "xmlrpc.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "xmlrpc.mak" CFG="xmlrpc - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "xmlrpc - Win32 Release" (based on "Win32 (x86) Static Library") +!MESSAGE "xmlrpc - Win32 Debug" (based on "Win32 (x86) Static Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "xmlrpc" +# PROP Scc_LocalPath ".." +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "xmlrpc - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release\xmlrpc" +# PROP Intermediate_Dir "Release\xmlrpc" +# PROP Target_Dir "" +MTL=midl.exe +LINK32=link.exe -lib +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c +# ADD CPP /nologo /MT /W3 /GX /O2 /I "../lib/" /I "../lib/curl_transport" /I "../lib/util/include" /I "../include" /I "../" /I "../lib/expat/xmlparse" /I "../lib/w3c-libwww-5.3.2/Library/src" /I "../lib/abyss/src" /I "../lib/wininet_transport" /D "NDEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /D "ABYSS_WIN32" /D "CURL_STATICLIB" /FR /YX /FD /c +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo /out:"..\lib\xmlrpc.lib" + +!ELSEIF "$(CFG)" == "xmlrpc - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug\xmlrpc" +# PROP Intermediate_Dir "Debug\xmlrpc" +# PROP Target_Dir "" +MTL=midl.exe +LINK32=link.exe -lib +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c +# ADD CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /I "../lib/" /I "../lib/curl_transport" /I "../lib/util/include" /I "../include" /I "../" /I "../lib/expat/xmlparse" /I "../lib/w3c-libwww-5.3.2/Library/src" /I "../lib/abyss/src" /I "../lib/wininet_transport" /D "_DEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /D "ABYSS_WIN32" /D "CURL_STATICLIB" /YX /FD /GZ /c +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo /out:"..\lib\xmlrpcD.lib" + +!ENDIF + +# Begin Target + +# Name "xmlrpc - Win32 Release" +# Name "xmlrpc - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat;cc" +# Begin Source File + +SOURCE=..\lib\util\casprintf.c +# End Source File +# Begin Source File + +SOURCE=..\lib\util\pthreadx_win32.c +# End Source File +# Begin Source File + +SOURCE=..\src\xmlrpc_array.c +# End Source File +# Begin Source File + +SOURCE=..\src\xmlrpc_authcookie.c +# End Source File +# Begin Source File + +SOURCE=..\src\xmlrpc_base64.c +# End Source File +# Begin Source File + +SOURCE=..\src\xmlrpc_builddecomp.c +# End Source File +# Begin Source File + +SOURCE=..\src\xmlrpc_client.c +# End Source File +# Begin Source File + +SOURCE=..\lib\curl_transport\xmlrpc_curl_transport.c +# PROP Exclude_From_Build 1 +# End Source File +# Begin Source File + +SOURCE=..\src\xmlrpc_data.c +# End Source File +# Begin Source File + +SOURCE=..\src\xmlrpc_datetime.c +# End Source File +# Begin Source File + +SOURCE=..\src\xmlrpc_expat.c +# End Source File +# Begin Source File + +SOURCE=..\src\xmlrpc_libxml2.c +# PROP Exclude_From_Build 1 +# End Source File +# Begin Source File + +SOURCE=..\src\xmlrpc_parse.c +# End Source File +# Begin Source File + +SOURCE=..\src\xmlrpc_registry.c +# End Source File +# Begin Source File + +SOURCE=..\src\xmlrpc_serialize.c +# End Source File +# Begin Source File + +SOURCE=..\src\xmlrpc_server_abyss.c +# End Source File +# Begin Source File + +SOURCE=..\src\xmlrpc_server_w32httpsys.c +# End Source File +# Begin Source File + +SOURCE=..\src\xmlrpc_struct.c +# End Source File +# Begin Source File + +SOURCE=..\src\xmlrpc_strutil.c +# End Source File +# Begin Source File + +SOURCE=..\src\xmlrpc_support.c +# End Source File +# Begin Source File + +SOURCE=..\src\xmlrpc_utf8.c +# End Source File +# Begin Source File + +SOURCE=..\lib\wininet_transport\xmlrpc_wininet_transport.c +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE="..\include\xmlrpc-c\abyss.h" +# End Source File +# Begin Source File + +SOURCE="..\include\xmlrpc-c\base.h" +# End Source File +# Begin Source File + +SOURCE=..\lib\util\include\bool.h +# End Source File +# Begin Source File + +SOURCE="..\include\xmlrpc-c\client.h" +# End Source File +# Begin Source File + +SOURCE="..\include\xmlrpc-c\client_int.h" +# End Source File +# Begin Source File + +SOURCE=..\lib\util\include\mallocvar.h +# End Source File +# Begin Source File + +SOURCE=..\lib\util\include\pthreadx.h +# End Source File +# Begin Source File + +SOURCE="..\include\xmlrpc-c\server.h" +# End Source File +# Begin Source File + +SOURCE="..\include\xmlrpc-c\server_abyss.h" +# End Source File +# Begin Source File + +SOURCE="..\include\xmlrpc-c\server_cgi.h" +# End Source File +# Begin Source File + +SOURCE="..\include\xmlrpc-c\server_w32httpsys.h" +# End Source File +# Begin Source File + +SOURCE="..\include\xmlrpc-c\transport.h" +# End Source File +# Begin Source File + +SOURCE=..\transport_config.h +# End Source File +# Begin Source File + +SOURCE="..\include\xmlrpc-c\transport_int.h" +# End Source File +# Begin Source File + +SOURCE="..\include\xmlrpc-c\xmlparser.h" +# End Source File +# Begin Source File + +SOURCE=..\xmlrpc_config.h +# End Source File +# Begin Source File + +SOURCE=..\lib\curl_transport\xmlrpc_curl_transport.h +# End Source File +# Begin Source File + +SOURCE=..\lib\wininet_transport\xmlrpc_wininet_transport.h +# End Source File +# End Group +# End Target +# End Project diff --git a/Windows/xmlrpc.dsw b/Windows/xmlrpc.dsw new file mode 100644 index 0000000..b98b772 --- /dev/null +++ b/Windows/xmlrpc.dsw @@ -0,0 +1,194 @@ +Microsoft Developer Studio Workspace File, Format Version 6.00 +# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! + +############################################################################### + +Project: "cpptest"=".\cpptest.dsp" - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ + Begin Project Dependency + Project_Dep_Name xmlrpc + End Project Dependency +}}} + +############################################################################### + +Project: "gennmtab"="..\lib\expat\gennmtab\gennmtab.dsp" - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "query_meerkat"=".\query_meerkat.dsp" - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ + Begin Project Dependency + Project_Dep_Name xmlrpc + End Project Dependency +}}} + +############################################################################### + +Project: "rpctest"=".\rpctest.dsp" - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ + Begin Project Dependency + Project_Dep_Name xmlrpc + End Project Dependency +}}} + +############################################################################### + +Project: "xmlparse"="..\lib\expat\xmlparse\xmlparse.dsp" - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ + Begin Project Dependency + Project_Dep_Name xmltok + End Project Dependency +}}} + +############################################################################### + +Project: "xmlrpc"=".\xmlrpc.dsp" - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ + Begin Project Dependency + Project_Dep_Name xmlparse + End Project Dependency +}}} + +############################################################################### + +Project: "xmlrpc_sample_add_asynch_client"=".\xmlrpc_sample_add_asynch_client.dsp" - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ + Begin Project Dependency + Project_Dep_Name xmlrpc + End Project Dependency +}}} + +############################################################################### + +Project: "xmlrpc_sample_add_server"=".\xmlrpc_sample_add_server.dsp" - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ + Begin Project Dependency + Project_Dep_Name xmlrpc + End Project Dependency +}}} + +############################################################################### + +Project: "xmlrpc_sample_add_server_w32httpsys"=".\xmlrpc_sample_add_server_w32httpsys.dsp" - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ + Begin Project Dependency + Project_Dep_Name xmlrpc + End Project Dependency +}}} + +############################################################################### + +Project: "xmlrpc_sample_add_sync_client"=".\xmlrpc_sample_add_sync_client.dsp" - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ + Begin Project Dependency + Project_Dep_Name xmlrpc + End Project Dependency +}}} + +############################################################################### + +Project: "xmlrpc_sample_auth_client"=".\xmlrpc_sample_auth_client.dsp" - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ + Begin Project Dependency + Project_Dep_Name xmlrpc + End Project Dependency +}}} + +############################################################################### + +Project: "xmltok"="..\lib\expat\xmltok\xmltok.dsp" - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ + Begin Project Dependency + Project_Dep_Name gennmtab + End Project Dependency +}}} + +############################################################################### + +Global: + +Package=<5> +{{{ +}}} + +Package=<3> +{{{ +}}} + +############################################################################### + diff --git a/Windows/xmlrpc.sln b/Windows/xmlrpc.sln new file mode 100644 index 0000000..635a409 --- /dev/null +++ b/Windows/xmlrpc.sln @@ -0,0 +1,229 @@ +Microsoft Visual Studio Solution File, Format Version 8.00 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "all", "all.vcproj", "{5CB3B96A-1CFF-49AD-AF5F-35203E0492F2}" + ProjectSection(ProjectDependencies) = postProject + {D50B8203-D6C2-4EC9-907C-F01A3BDA71AC} = {D50B8203-D6C2-4EC9-907C-F01A3BDA71AC} + {4137D986-8134-44FB-A482-50CC046CC450} = {4137D986-8134-44FB-A482-50CC046CC450} + {77DEDE54-768E-4ECA-9B2C-EF57ADFC0A05} = {77DEDE54-768E-4ECA-9B2C-EF57ADFC0A05} + {3D641981-D76D-412B-AD0F-EC2CF58611AA} = {3D641981-D76D-412B-AD0F-EC2CF58611AA} + {D6CF56C7-5E6D-4C9E-A81C-F3EEE29951AC} = {D6CF56C7-5E6D-4C9E-A81C-F3EEE29951AC} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "configwin32", "configwin32.vcproj", "{E5089B87-0C26-47A9-B758-CC0C718F7987}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "cpptest", "cpptest.vcproj", "{2040C78A-0231-4C59-BBD7-61DB95FA85B1}" + ProjectSection(ProjectDependencies) = postProject + {26FCCB92-53CA-40F3-AC9F-2EFFC745BD79} = {26FCCB92-53CA-40F3-AC9F-2EFFC745BD79} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "gennmtab", "..\lib\expat\gennmtab\gennmtab.vcproj", "{9E017925-D88F-46A2-892F-EF1FCCAE170F}" + ProjectSection(ProjectDependencies) = postProject + {E5089B87-0C26-47A9-B758-CC0C718F7987} = {E5089B87-0C26-47A9-B758-CC0C718F7987} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "query_meerkat", "query_meerkat.vcproj", "{6DF77399-72AE-4155-A30D-7AEFF8A0A914}" + ProjectSection(ProjectDependencies) = postProject + {26FCCB92-53CA-40F3-AC9F-2EFFC745BD79} = {26FCCB92-53CA-40F3-AC9F-2EFFC745BD79} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "rpctest", "rpctest.vcproj", "{D50B8203-D6C2-4EC9-907C-F01A3BDA71AC}" + ProjectSection(ProjectDependencies) = postProject + {26FCCB92-53CA-40F3-AC9F-2EFFC745BD79} = {26FCCB92-53CA-40F3-AC9F-2EFFC745BD79} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "xmlparse", "..\lib\expat\xmlparse\xmlparse.vcproj", "{401073F1-642F-4CE3-B38E-6F5321758C93}" + ProjectSection(ProjectDependencies) = postProject + {D9B03722-EA42-40C7-A1A8-01282B600948} = {D9B03722-EA42-40C7-A1A8-01282B600948} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "xmlrpc", "xmlrpc.vcproj", "{26FCCB92-53CA-40F3-AC9F-2EFFC745BD79}" + ProjectSection(ProjectDependencies) = postProject + {401073F1-642F-4CE3-B38E-6F5321758C93} = {401073F1-642F-4CE3-B38E-6F5321758C93} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "xmlrpc_sample_add_asynch_client", "xmlrpc_sample_add_asynch_client.vcproj", "{D6CF56C7-5E6D-4C9E-A81C-F3EEE29951AC}" + ProjectSection(ProjectDependencies) = postProject + {26FCCB92-53CA-40F3-AC9F-2EFFC745BD79} = {26FCCB92-53CA-40F3-AC9F-2EFFC745BD79} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "xmlrpc_sample_add_server", "xmlrpc_sample_add_server.vcproj", "{3D641981-D76D-412B-AD0F-EC2CF58611AA}" + ProjectSection(ProjectDependencies) = postProject + {26FCCB92-53CA-40F3-AC9F-2EFFC745BD79} = {26FCCB92-53CA-40F3-AC9F-2EFFC745BD79} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "xmlrpc_sample_add_server_w32httpsys", "xmlrpc_sample_add_server_w32httpsys.vcproj", "{80160353-BE0D-463C-A87A-BBFBD977DB3B}" + ProjectSection(ProjectDependencies) = postProject + {26FCCB92-53CA-40F3-AC9F-2EFFC745BD79} = {26FCCB92-53CA-40F3-AC9F-2EFFC745BD79} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "xmlrpc_sample_add_sync_client", "xmlrpc_sample_add_sync_client.vcproj", "{77DEDE54-768E-4ECA-9B2C-EF57ADFC0A05}" + ProjectSection(ProjectDependencies) = postProject + {26FCCB92-53CA-40F3-AC9F-2EFFC745BD79} = {26FCCB92-53CA-40F3-AC9F-2EFFC745BD79} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "xmlrpc_sample_auth_client", "xmlrpc_sample_auth_client.vcproj", "{4137D986-8134-44FB-A482-50CC046CC450}" + ProjectSection(ProjectDependencies) = postProject + {26FCCB92-53CA-40F3-AC9F-2EFFC745BD79} = {26FCCB92-53CA-40F3-AC9F-2EFFC745BD79} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "xmltok", "..\lib\expat\xmltok\xmltok.vcproj", "{D9B03722-EA42-40C7-A1A8-01282B600948}" + ProjectSection(ProjectDependencies) = postProject + {9E017925-D88F-46A2-892F-EF1FCCAE170F} = {9E017925-D88F-46A2-892F-EF1FCCAE170F} + EndProjectSection +EndProject +Global + GlobalSection(SolutionConfiguration) = preSolution + Debug = Debug + Debug DLL = Debug DLL + MinSize DLL = MinSize DLL + Release = Release + Release DLL = Release DLL + EndGlobalSection + GlobalSection(ProjectConfiguration) = postSolution + {5CB3B96A-1CFF-49AD-AF5F-35203E0492F2}.Debug.ActiveCfg = Debug|Win32 + {5CB3B96A-1CFF-49AD-AF5F-35203E0492F2}.Debug.Build.0 = Debug|Win32 + {5CB3B96A-1CFF-49AD-AF5F-35203E0492F2}.Debug DLL.ActiveCfg = Debug|Win32 + {5CB3B96A-1CFF-49AD-AF5F-35203E0492F2}.Debug DLL.Build.0 = Debug|Win32 + {5CB3B96A-1CFF-49AD-AF5F-35203E0492F2}.MinSize DLL.ActiveCfg = Release|Win32 + {5CB3B96A-1CFF-49AD-AF5F-35203E0492F2}.MinSize DLL.Build.0 = Release|Win32 + {5CB3B96A-1CFF-49AD-AF5F-35203E0492F2}.Release.ActiveCfg = Release|Win32 + {5CB3B96A-1CFF-49AD-AF5F-35203E0492F2}.Release.Build.0 = Release|Win32 + {5CB3B96A-1CFF-49AD-AF5F-35203E0492F2}.Release DLL.ActiveCfg = Release|Win32 + {5CB3B96A-1CFF-49AD-AF5F-35203E0492F2}.Release DLL.Build.0 = Release|Win32 + {E5089B87-0C26-47A9-B758-CC0C718F7987}.Debug.ActiveCfg = Debug|Win32 + {E5089B87-0C26-47A9-B758-CC0C718F7987}.Debug.Build.0 = Debug|Win32 + {E5089B87-0C26-47A9-B758-CC0C718F7987}.Debug DLL.ActiveCfg = Debug|Win32 + {E5089B87-0C26-47A9-B758-CC0C718F7987}.Debug DLL.Build.0 = Debug|Win32 + {E5089B87-0C26-47A9-B758-CC0C718F7987}.MinSize DLL.ActiveCfg = Release|Win32 + {E5089B87-0C26-47A9-B758-CC0C718F7987}.MinSize DLL.Build.0 = Release|Win32 + {E5089B87-0C26-47A9-B758-CC0C718F7987}.Release.ActiveCfg = Release|Win32 + {E5089B87-0C26-47A9-B758-CC0C718F7987}.Release.Build.0 = Release|Win32 + {E5089B87-0C26-47A9-B758-CC0C718F7987}.Release DLL.ActiveCfg = Release|Win32 + {E5089B87-0C26-47A9-B758-CC0C718F7987}.Release DLL.Build.0 = Release|Win32 + {2040C78A-0231-4C59-BBD7-61DB95FA85B1}.Debug.ActiveCfg = Debug|Win32 + {2040C78A-0231-4C59-BBD7-61DB95FA85B1}.Debug.Build.0 = Debug|Win32 + {2040C78A-0231-4C59-BBD7-61DB95FA85B1}.Debug DLL.ActiveCfg = Debug|Win32 + {2040C78A-0231-4C59-BBD7-61DB95FA85B1}.Debug DLL.Build.0 = Debug|Win32 + {2040C78A-0231-4C59-BBD7-61DB95FA85B1}.MinSize DLL.ActiveCfg = Debug|Win32 + {2040C78A-0231-4C59-BBD7-61DB95FA85B1}.MinSize DLL.Build.0 = Debug|Win32 + {2040C78A-0231-4C59-BBD7-61DB95FA85B1}.Release.ActiveCfg = Release|Win32 + {2040C78A-0231-4C59-BBD7-61DB95FA85B1}.Release.Build.0 = Release|Win32 + {2040C78A-0231-4C59-BBD7-61DB95FA85B1}.Release DLL.ActiveCfg = Release|Win32 + {2040C78A-0231-4C59-BBD7-61DB95FA85B1}.Release DLL.Build.0 = Release|Win32 + {9E017925-D88F-46A2-892F-EF1FCCAE170F}.Debug.ActiveCfg = Debug|Win32 + {9E017925-D88F-46A2-892F-EF1FCCAE170F}.Debug.Build.0 = Debug|Win32 + {9E017925-D88F-46A2-892F-EF1FCCAE170F}.Debug DLL.ActiveCfg = Debug|Win32 + {9E017925-D88F-46A2-892F-EF1FCCAE170F}.Debug DLL.Build.0 = Debug|Win32 + {9E017925-D88F-46A2-892F-EF1FCCAE170F}.MinSize DLL.ActiveCfg = Release|Win32 + {9E017925-D88F-46A2-892F-EF1FCCAE170F}.MinSize DLL.Build.0 = Release|Win32 + {9E017925-D88F-46A2-892F-EF1FCCAE170F}.Release.ActiveCfg = Release|Win32 + {9E017925-D88F-46A2-892F-EF1FCCAE170F}.Release.Build.0 = Release|Win32 + {9E017925-D88F-46A2-892F-EF1FCCAE170F}.Release DLL.ActiveCfg = Release|Win32 + {9E017925-D88F-46A2-892F-EF1FCCAE170F}.Release DLL.Build.0 = Release|Win32 + {6DF77399-72AE-4155-A30D-7AEFF8A0A914}.Debug.ActiveCfg = Debug|Win32 + {6DF77399-72AE-4155-A30D-7AEFF8A0A914}.Debug.Build.0 = Debug|Win32 + {6DF77399-72AE-4155-A30D-7AEFF8A0A914}.Debug DLL.ActiveCfg = Debug|Win32 + {6DF77399-72AE-4155-A30D-7AEFF8A0A914}.Debug DLL.Build.0 = Debug|Win32 + {6DF77399-72AE-4155-A30D-7AEFF8A0A914}.MinSize DLL.ActiveCfg = Release|Win32 + {6DF77399-72AE-4155-A30D-7AEFF8A0A914}.MinSize DLL.Build.0 = Release|Win32 + {6DF77399-72AE-4155-A30D-7AEFF8A0A914}.Release.ActiveCfg = Release|Win32 + {6DF77399-72AE-4155-A30D-7AEFF8A0A914}.Release.Build.0 = Release|Win32 + {6DF77399-72AE-4155-A30D-7AEFF8A0A914}.Release DLL.ActiveCfg = Release|Win32 + {6DF77399-72AE-4155-A30D-7AEFF8A0A914}.Release DLL.Build.0 = Release|Win32 + {D50B8203-D6C2-4EC9-907C-F01A3BDA71AC}.Debug.ActiveCfg = Debug|Win32 + {D50B8203-D6C2-4EC9-907C-F01A3BDA71AC}.Debug.Build.0 = Debug|Win32 + {D50B8203-D6C2-4EC9-907C-F01A3BDA71AC}.Debug DLL.ActiveCfg = Debug|Win32 + {D50B8203-D6C2-4EC9-907C-F01A3BDA71AC}.Debug DLL.Build.0 = Debug|Win32 + {D50B8203-D6C2-4EC9-907C-F01A3BDA71AC}.MinSize DLL.ActiveCfg = Release|Win32 + {D50B8203-D6C2-4EC9-907C-F01A3BDA71AC}.MinSize DLL.Build.0 = Release|Win32 + {D50B8203-D6C2-4EC9-907C-F01A3BDA71AC}.Release.ActiveCfg = Release|Win32 + {D50B8203-D6C2-4EC9-907C-F01A3BDA71AC}.Release.Build.0 = Release|Win32 + {D50B8203-D6C2-4EC9-907C-F01A3BDA71AC}.Release DLL.ActiveCfg = Release|Win32 + {D50B8203-D6C2-4EC9-907C-F01A3BDA71AC}.Release DLL.Build.0 = Release|Win32 + {401073F1-642F-4CE3-B38E-6F5321758C93}.Debug.ActiveCfg = Debug|Win32 + {401073F1-642F-4CE3-B38E-6F5321758C93}.Debug.Build.0 = Debug|Win32 + {401073F1-642F-4CE3-B38E-6F5321758C93}.Debug DLL.ActiveCfg = Debug DLL|Win32 + {401073F1-642F-4CE3-B38E-6F5321758C93}.Debug DLL.Build.0 = Debug DLL|Win32 + {401073F1-642F-4CE3-B38E-6F5321758C93}.MinSize DLL.ActiveCfg = MinSize DLL|Win32 + {401073F1-642F-4CE3-B38E-6F5321758C93}.MinSize DLL.Build.0 = MinSize DLL|Win32 + {401073F1-642F-4CE3-B38E-6F5321758C93}.Release.ActiveCfg = Release|Win32 + {401073F1-642F-4CE3-B38E-6F5321758C93}.Release.Build.0 = Release|Win32 + {401073F1-642F-4CE3-B38E-6F5321758C93}.Release DLL.ActiveCfg = Release DLL|Win32 + {401073F1-642F-4CE3-B38E-6F5321758C93}.Release DLL.Build.0 = Release DLL|Win32 + {26FCCB92-53CA-40F3-AC9F-2EFFC745BD79}.Debug.ActiveCfg = Debug|Win32 + {26FCCB92-53CA-40F3-AC9F-2EFFC745BD79}.Debug.Build.0 = Debug|Win32 + {26FCCB92-53CA-40F3-AC9F-2EFFC745BD79}.Debug DLL.ActiveCfg = Debug|Win32 + {26FCCB92-53CA-40F3-AC9F-2EFFC745BD79}.Debug DLL.Build.0 = Debug|Win32 + {26FCCB92-53CA-40F3-AC9F-2EFFC745BD79}.MinSize DLL.ActiveCfg = Release|Win32 + {26FCCB92-53CA-40F3-AC9F-2EFFC745BD79}.MinSize DLL.Build.0 = Release|Win32 + {26FCCB92-53CA-40F3-AC9F-2EFFC745BD79}.Release.ActiveCfg = Release|Win32 + {26FCCB92-53CA-40F3-AC9F-2EFFC745BD79}.Release.Build.0 = Release|Win32 + {26FCCB92-53CA-40F3-AC9F-2EFFC745BD79}.Release DLL.ActiveCfg = Release|Win32 + {26FCCB92-53CA-40F3-AC9F-2EFFC745BD79}.Release DLL.Build.0 = Release|Win32 + {D6CF56C7-5E6D-4C9E-A81C-F3EEE29951AC}.Debug.ActiveCfg = Debug|Win32 + {D6CF56C7-5E6D-4C9E-A81C-F3EEE29951AC}.Debug.Build.0 = Debug|Win32 + {D6CF56C7-5E6D-4C9E-A81C-F3EEE29951AC}.Debug DLL.ActiveCfg = Debug|Win32 + {D6CF56C7-5E6D-4C9E-A81C-F3EEE29951AC}.Debug DLL.Build.0 = Debug|Win32 + {D6CF56C7-5E6D-4C9E-A81C-F3EEE29951AC}.MinSize DLL.ActiveCfg = Release|Win32 + {D6CF56C7-5E6D-4C9E-A81C-F3EEE29951AC}.MinSize DLL.Build.0 = Release|Win32 + {D6CF56C7-5E6D-4C9E-A81C-F3EEE29951AC}.Release.ActiveCfg = Release|Win32 + {D6CF56C7-5E6D-4C9E-A81C-F3EEE29951AC}.Release.Build.0 = Release|Win32 + {D6CF56C7-5E6D-4C9E-A81C-F3EEE29951AC}.Release DLL.ActiveCfg = Release|Win32 + {D6CF56C7-5E6D-4C9E-A81C-F3EEE29951AC}.Release DLL.Build.0 = Release|Win32 + {3D641981-D76D-412B-AD0F-EC2CF58611AA}.Debug.ActiveCfg = Debug|Win32 + {3D641981-D76D-412B-AD0F-EC2CF58611AA}.Debug.Build.0 = Debug|Win32 + {3D641981-D76D-412B-AD0F-EC2CF58611AA}.Debug DLL.ActiveCfg = Debug|Win32 + {3D641981-D76D-412B-AD0F-EC2CF58611AA}.Debug DLL.Build.0 = Debug|Win32 + {3D641981-D76D-412B-AD0F-EC2CF58611AA}.MinSize DLL.ActiveCfg = Debug|Win32 + {3D641981-D76D-412B-AD0F-EC2CF58611AA}.MinSize DLL.Build.0 = Debug|Win32 + {3D641981-D76D-412B-AD0F-EC2CF58611AA}.Release.ActiveCfg = Release|Win32 + {3D641981-D76D-412B-AD0F-EC2CF58611AA}.Release.Build.0 = Release|Win32 + {3D641981-D76D-412B-AD0F-EC2CF58611AA}.Release DLL.ActiveCfg = Release|Win32 + {3D641981-D76D-412B-AD0F-EC2CF58611AA}.Release DLL.Build.0 = Release|Win32 + {80160353-BE0D-463C-A87A-BBFBD977DB3B}.Debug.ActiveCfg = Debug|Win32 + {80160353-BE0D-463C-A87A-BBFBD977DB3B}.Debug.Build.0 = Debug|Win32 + {80160353-BE0D-463C-A87A-BBFBD977DB3B}.Debug DLL.ActiveCfg = Debug|Win32 + {80160353-BE0D-463C-A87A-BBFBD977DB3B}.Debug DLL.Build.0 = Debug|Win32 + {80160353-BE0D-463C-A87A-BBFBD977DB3B}.MinSize DLL.ActiveCfg = Release|Win32 + {80160353-BE0D-463C-A87A-BBFBD977DB3B}.MinSize DLL.Build.0 = Release|Win32 + {80160353-BE0D-463C-A87A-BBFBD977DB3B}.Release.ActiveCfg = Release|Win32 + {80160353-BE0D-463C-A87A-BBFBD977DB3B}.Release.Build.0 = Release|Win32 + {80160353-BE0D-463C-A87A-BBFBD977DB3B}.Release DLL.ActiveCfg = Release|Win32 + {80160353-BE0D-463C-A87A-BBFBD977DB3B}.Release DLL.Build.0 = Release|Win32 + {77DEDE54-768E-4ECA-9B2C-EF57ADFC0A05}.Debug.ActiveCfg = Debug|Win32 + {77DEDE54-768E-4ECA-9B2C-EF57ADFC0A05}.Debug.Build.0 = Debug|Win32 + {77DEDE54-768E-4ECA-9B2C-EF57ADFC0A05}.Debug DLL.ActiveCfg = Debug|Win32 + {77DEDE54-768E-4ECA-9B2C-EF57ADFC0A05}.Debug DLL.Build.0 = Debug|Win32 + {77DEDE54-768E-4ECA-9B2C-EF57ADFC0A05}.MinSize DLL.ActiveCfg = Release|Win32 + {77DEDE54-768E-4ECA-9B2C-EF57ADFC0A05}.MinSize DLL.Build.0 = Release|Win32 + {77DEDE54-768E-4ECA-9B2C-EF57ADFC0A05}.Release.ActiveCfg = Release|Win32 + {77DEDE54-768E-4ECA-9B2C-EF57ADFC0A05}.Release.Build.0 = Release|Win32 + {77DEDE54-768E-4ECA-9B2C-EF57ADFC0A05}.Release DLL.ActiveCfg = Release|Win32 + {77DEDE54-768E-4ECA-9B2C-EF57ADFC0A05}.Release DLL.Build.0 = Release|Win32 + {4137D986-8134-44FB-A482-50CC046CC450}.Debug.ActiveCfg = Debug|Win32 + {4137D986-8134-44FB-A482-50CC046CC450}.Debug.Build.0 = Debug|Win32 + {4137D986-8134-44FB-A482-50CC046CC450}.Debug DLL.ActiveCfg = Debug|Win32 + {4137D986-8134-44FB-A482-50CC046CC450}.Debug DLL.Build.0 = Debug|Win32 + {4137D986-8134-44FB-A482-50CC046CC450}.MinSize DLL.ActiveCfg = Debug|Win32 + {4137D986-8134-44FB-A482-50CC046CC450}.MinSize DLL.Build.0 = Debug|Win32 + {4137D986-8134-44FB-A482-50CC046CC450}.Release.ActiveCfg = Release|Win32 + {4137D986-8134-44FB-A482-50CC046CC450}.Release.Build.0 = Release|Win32 + {4137D986-8134-44FB-A482-50CC046CC450}.Release DLL.ActiveCfg = Release|Win32 + {4137D986-8134-44FB-A482-50CC046CC450}.Release DLL.Build.0 = Release|Win32 + {D9B03722-EA42-40C7-A1A8-01282B600948}.Debug.ActiveCfg = Debug|Win32 + {D9B03722-EA42-40C7-A1A8-01282B600948}.Debug.Build.0 = Debug|Win32 + {D9B03722-EA42-40C7-A1A8-01282B600948}.Debug DLL.ActiveCfg = Debug DLL|Win32 + {D9B03722-EA42-40C7-A1A8-01282B600948}.Debug DLL.Build.0 = Debug DLL|Win32 + {D9B03722-EA42-40C7-A1A8-01282B600948}.MinSize DLL.ActiveCfg = Debug DLL|Win32 + {D9B03722-EA42-40C7-A1A8-01282B600948}.MinSize DLL.Build.0 = Debug DLL|Win32 + {D9B03722-EA42-40C7-A1A8-01282B600948}.Release.ActiveCfg = Release|Win32 + {D9B03722-EA42-40C7-A1A8-01282B600948}.Release.Build.0 = Release|Win32 + {D9B03722-EA42-40C7-A1A8-01282B600948}.Release DLL.ActiveCfg = Release DLL|Win32 + {D9B03722-EA42-40C7-A1A8-01282B600948}.Release DLL.Build.0 = Release DLL|Win32 + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + EndGlobalSection + GlobalSection(ExtensibilityAddIns) = postSolution + EndGlobalSection +EndGlobal diff --git a/Windows/xmlrpc.vcproj b/Windows/xmlrpc.vcproj new file mode 100644 index 0000000..6a6804c --- /dev/null +++ b/Windows/xmlrpc.vcproj @@ -0,0 +1,1013 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Windows/xmlrpc_sample_add_asynch_client.dsp b/Windows/xmlrpc_sample_add_asynch_client.dsp new file mode 100644 index 0000000..91e63a8 --- /dev/null +++ b/Windows/xmlrpc_sample_add_asynch_client.dsp @@ -0,0 +1,102 @@ +# Microsoft Developer Studio Project File - Name="xmlrpc_sample_add_asynch_client" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + +CFG=xmlrpc_sample_add_asynch_client - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "xmlrpc_sample_add_asynch_client.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "xmlrpc_sample_add_asynch_client.mak" CFG="xmlrpc_sample_add_asynch_client - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "xmlrpc_sample_add_asynch_client - Win32 Release" (based on "Win32 (x86) Console Application") +!MESSAGE "xmlrpc_sample_add_asynch_client - Win32 Debug" (based on "Win32 (x86) Console Application") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "xmlrpc_sample_add_asynch_client" +# PROP Scc_LocalPath ".." +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "xmlrpc_sample_add_asynch_client - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release\xmlrpc_sample_add_asynch_client" +# PROP Intermediate_Dir "Release\xmlrpc_sample_add_asynch_client" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /MT /W3 /GX /O2 /I "..\\" /I "..\include" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 +# ADD LINK32 ..\lib\xmlrpc.lib WinInet.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 /out:"..\bin\xmlrpc_sample_add_asynch_client.exe" + +!ELSEIF "$(CFG)" == "xmlrpc_sample_add_asynch_client - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug\xmlrpc_sample_add_asynch_client" +# PROP Intermediate_Dir "Debug\xmlrpc_sample_add_asynch_client" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c +# ADD CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /I "..\\" /I "..\include" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept +# ADD LINK32 ..\lib\xmlrpcD.lib WinInet.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /out:"..\bin\xmlrpc_sample_add_asynch_clientD.exe" /pdbtype:sept + +!ENDIF + +# Begin Target + +# Name "xmlrpc_sample_add_asynch_client - Win32 Release" +# Name "xmlrpc_sample_add_asynch_client - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=..\examples\xmlrpc_asynch_client.c +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# End Group +# Begin Group "Resource Files" + +# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" +# End Group +# End Target +# End Project diff --git a/Windows/xmlrpc_sample_add_asynch_client.vcproj b/Windows/xmlrpc_sample_add_asynch_client.vcproj new file mode 100644 index 0000000..9576b6c --- /dev/null +++ b/Windows/xmlrpc_sample_add_asynch_client.vcproj @@ -0,0 +1,168 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Windows/xmlrpc_sample_add_server.dsp b/Windows/xmlrpc_sample_add_server.dsp new file mode 100644 index 0000000..abb8127 --- /dev/null +++ b/Windows/xmlrpc_sample_add_server.dsp @@ -0,0 +1,140 @@ +# Microsoft Developer Studio Project File - Name="xmlrpc_sample_add_server" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + +CFG=xmlrpc_sample_add_server - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "xmlrpc_sample_add_server.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "xmlrpc_sample_add_server.mak" CFG="xmlrpc_sample_add_server - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "xmlrpc_sample_add_server - Win32 Release" (based on "Win32 (x86) Console Application") +!MESSAGE "xmlrpc_sample_add_server - Win32 Debug" (based on "Win32 (x86) Console Application") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "xmlrpc_sample_add_server" +# PROP Scc_LocalPath ".." +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "xmlrpc_sample_add_server - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir ".\Release\xmlrpc_sample_add_server" +# PROP Intermediate_Dir ".\Release\xmlrpc_sample_add_server" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /MT /W3 /GX /O2 /I "..\\" /I "..\include" /D "NDEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D "ABYSS_WIN32" /D "_THREAD" /YX /FD /c +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 +# ADD LINK32 kernel32.lib user32.lib gdi32.lib ..\lib\xmlrpc.lib ws2_32.lib /nologo /subsystem:console /machine:I386 /out:"..\bin\xmlrpc_sample_add_server.exe" +# SUBTRACT LINK32 /pdb:none + +!ELSEIF "$(CFG)" == "xmlrpc_sample_add_server - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir ".\Debug\xmlrpc_sample_add_server" +# PROP Intermediate_Dir ".\Debug\xmlrpc_sample_add_server" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c +# ADD CPP /nologo /MDd /W3 /GX /Zi /Od /I "..\\" /I "..\include" /D "_DEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D "ABYSS_WIN32" /D "_THREAD" /YX /FD /GZ /c +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept +# ADD LINK32 kernel32.lib user32.lib gdi32.lib ..\lib\xmlrpcD.lib ws2_32.lib /nologo /subsystem:console /debug /machine:I386 /out:"..\bin\xmlrpc_sample_add_serverD.exe" /pdbtype:sept +# SUBTRACT LINK32 /pdb:none + +!ENDIF + +# Begin Target + +# Name "xmlrpc_sample_add_server - Win32 Release" +# Name "xmlrpc_sample_add_server - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=..\lib\abyss\src\conf.c +# End Source File +# Begin Source File + +SOURCE=..\lib\abyss\src\conn.c +# End Source File +# Begin Source File + +SOURCE=..\lib\abyss\src\data.c +# End Source File +# Begin Source File + +SOURCE=..\lib\abyss\src\file.c +# End Source File +# Begin Source File + +SOURCE=..\lib\abyss\src\http.c +# End Source File +# Begin Source File + +SOURCE=..\lib\abyss\src\server.c +# End Source File +# Begin Source File + +SOURCE=..\lib\abyss\src\socket.c +# End Source File +# Begin Source File + +SOURCE=..\lib\abyss\src\thread.c +# End Source File +# Begin Source File + +SOURCE=..\lib\abyss\src\trace.c +# End Source File +# Begin Source File + +SOURCE=..\examples\xmlrpc_sample_add_server.c +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# End Group +# Begin Group "Resource Files" + +# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" +# End Group +# End Target +# End Project diff --git a/Windows/xmlrpc_sample_add_server.vcproj b/Windows/xmlrpc_sample_add_server.vcproj new file mode 100644 index 0000000..2168061 --- /dev/null +++ b/Windows/xmlrpc_sample_add_server.vcproj @@ -0,0 +1,338 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Windows/xmlrpc_sample_add_server_w32httpsys.dsp b/Windows/xmlrpc_sample_add_server_w32httpsys.dsp new file mode 100644 index 0000000..c716f3f --- /dev/null +++ b/Windows/xmlrpc_sample_add_server_w32httpsys.dsp @@ -0,0 +1,104 @@ +# Microsoft Developer Studio Project File - Name="xmlrpc_sample_add_server_w32httpsys" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + +CFG=xmlrpc_sample_add_server_w32httpsys - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "xmlrpc_sample_add_server_w32httpsys.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "xmlrpc_sample_add_server_w32httpsys.mak" CFG="xmlrpc_sample_add_server_w32httpsys - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "xmlrpc_sample_add_server_w32httpsys - Win32 Release" (based on "Win32 (x86) Console Application") +!MESSAGE "xmlrpc_sample_add_server_w32httpsys - Win32 Debug" (based on "Win32 (x86) Console Application") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "xmlrpc_sample_add_server_w32httpsys" +# PROP Scc_LocalPath ".." +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "xmlrpc_sample_add_server_w32httpsys - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir ".\Release\xmlrpc_sample_add_server_w32httpsys" +# PROP Intermediate_Dir ".\Release\xmlrpc_sample_add_server_w32httpsys" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /MT /W3 /GX /O2 /I "..\\" /I "..\include" /D "NDEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D "ABYSS_WIN32" /D "_THREAD" /YX /FD /c +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 +# ADD LINK32 kernel32.lib user32.lib gdi32.lib ..\lib\xmlrpc.lib ws2_32.lib /nologo /subsystem:console /machine:I386 /out:"..\bin\xmlrpc_sample_add_server_w32httpsys.exe" +# SUBTRACT LINK32 /pdb:none + +!ELSEIF "$(CFG)" == "xmlrpc_sample_add_server_w32httpsys - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir ".\Debug\xmlrpc_sample_add_server_w32httpsys" +# PROP Intermediate_Dir ".\Debug\xmlrpc_sample_add_server_w32httpsys" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c +# ADD CPP /nologo /MDd /W3 /GX /Zi /Od /I "..\\" /I "..\include" /D "_DEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D "ABYSS_WIN32" /D "_THREAD" /YX /FD /GZ /c +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept +# ADD LINK32 kernel32.lib user32.lib gdi32.lib ..\lib\xmlrpcD.lib ws2_32.lib /nologo /subsystem:console /debug /machine:I386 /out:"..\bin\xmlrpc_sample_add_server_w32httpsysD.exe" /pdbtype:sept +# SUBTRACT LINK32 /pdb:none + +!ENDIF + +# Begin Target + +# Name "xmlrpc_sample_add_server_w32httpsys - Win32 Release" +# Name "xmlrpc_sample_add_server_w32httpsys - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=..\examples\xmlrpc_sample_add_server_w32httpsys.c +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# End Group +# Begin Group "Resource Files" + +# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" +# End Group +# End Target +# End Project diff --git a/Windows/xmlrpc_sample_add_server_w32httpsys.vcproj b/Windows/xmlrpc_sample_add_server_w32httpsys.vcproj new file mode 100644 index 0000000..620f24b --- /dev/null +++ b/Windows/xmlrpc_sample_add_server_w32httpsys.vcproj @@ -0,0 +1,168 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Windows/xmlrpc_sample_add_sync_client.dsp b/Windows/xmlrpc_sample_add_sync_client.dsp new file mode 100644 index 0000000..c784456 --- /dev/null +++ b/Windows/xmlrpc_sample_add_sync_client.dsp @@ -0,0 +1,104 @@ +# Microsoft Developer Studio Project File - Name="xmlrpc_sample_add_sync_client" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + +CFG=xmlrpc_sample_add_sync_client - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "xmlrpc_sample_add_sync_client.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "xmlrpc_sample_add_sync_client.mak" CFG="xmlrpc_sample_add_sync_client - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "xmlrpc_sample_add_sync_client - Win32 Release" (based on "Win32 (x86) Console Application") +!MESSAGE "xmlrpc_sample_add_sync_client - Win32 Debug" (based on "Win32 (x86) Console Application") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "xmlrpc_sample_add_sync_client" +# PROP Scc_LocalPath ".." +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "xmlrpc_sample_add_sync_client - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir ".\Release\xmlrpc_sample_add_sync_client" +# PROP Intermediate_Dir ".\Release\xmlrpc_sample_add_sync_client" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /MT /W3 /GX /O2 /I "..\\" /I "..\include" /D "NDEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 +# ADD LINK32 ..\lib\xmlrpc.lib kernel32.lib user32.lib gdi32.lib WinInet.lib /nologo /subsystem:console /machine:I386 /out:"..\bin\xmlrpc_sample_add_sync_client.exe" +# SUBTRACT LINK32 /pdb:none + +!ELSEIF "$(CFG)" == "xmlrpc_sample_add_sync_client - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir ".\Debug\xmlrpc_sample_add_sync_client" +# PROP Intermediate_Dir ".\Debug\xmlrpc_sample_add_sync_client" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c +# ADD CPP /nologo /MDd /W3 /Gm /GX /Zi /Od /I "..\\" /I "..\include" /D "_DEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept +# ADD LINK32 ..\lib\xmlrpcD.lib kernel32.lib user32.lib gdi32.lib WinInet.lib /nologo /subsystem:console /debug /machine:I386 /out:"..\bin\xmlrpc_sample_add_sync_clientD.exe" /pdbtype:sept +# SUBTRACT LINK32 /pdb:none + +!ENDIF + +# Begin Target + +# Name "xmlrpc_sample_add_sync_client - Win32 Release" +# Name "xmlrpc_sample_add_sync_client - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=..\examples\xmlrpc_sample_add_client.c +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# End Group +# Begin Group "Resource Files" + +# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" +# End Group +# End Target +# End Project diff --git a/Windows/xmlrpc_sample_add_sync_client.vcproj b/Windows/xmlrpc_sample_add_sync_client.vcproj new file mode 100644 index 0000000..b280a52 --- /dev/null +++ b/Windows/xmlrpc_sample_add_sync_client.vcproj @@ -0,0 +1,168 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Windows/xmlrpc_sample_auth_client.dsp b/Windows/xmlrpc_sample_auth_client.dsp new file mode 100644 index 0000000..6edd252 --- /dev/null +++ b/Windows/xmlrpc_sample_auth_client.dsp @@ -0,0 +1,104 @@ +# Microsoft Developer Studio Project File - Name="xmlrpc_sample_auth_client" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + +CFG=xmlrpc_sample_auth_client - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "xmlrpc_sample_auth_client.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "xmlrpc_sample_auth_client.mak" CFG="xmlrpc_sample_auth_client - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "xmlrpc_sample_auth_client - Win32 Release" (based on "Win32 (x86) Console Application") +!MESSAGE "xmlrpc_sample_auth_client - Win32 Debug" (based on "Win32 (x86) Console Application") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "xmlrpc_sample_auth_client" +# PROP Scc_LocalPath ".." +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "xmlrpc_sample_auth_client - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir ".\Release\xmlrpc_sample_auth_client" +# PROP Intermediate_Dir ".\Release\xmlrpc_sample_auth_client" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /MT /W3 /GX /O2 /I "..\\" /I "..\include" /D "NDEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 +# ADD LINK32 ..\lib\xmlrpc.lib kernel32.lib user32.lib gdi32.lib WinInet.lib /nologo /subsystem:console /machine:I386 /out:"..\bin\xmlrpc_sample_auth_client.exe" +# SUBTRACT LINK32 /pdb:none + +!ELSEIF "$(CFG)" == "xmlrpc_sample_auth_client - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir ".\Debug\xmlrpc_sample_auth_client" +# PROP Intermediate_Dir ".\Debug\xmlrpc_sample_auth_client" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c +# ADD CPP /nologo /MDd /W3 /Gm /GX /Zi /Od /I "..\\" /I "..\include" /D "_DEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept +# ADD LINK32 ..\lib\xmlrpcD.lib kernel32.lib user32.lib gdi32.lib WinInet.lib /nologo /subsystem:console /debug /machine:I386 /out:"..\bin\xmlrpc_sample_auth_clientD.exe" /pdbtype:sept +# SUBTRACT LINK32 /pdb:none + +!ENDIF + +# Begin Target + +# Name "xmlrpc_sample_auth_client - Win32 Release" +# Name "xmlrpc_sample_auth_client - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=..\examples\auth_client.c +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# End Group +# Begin Group "Resource Files" + +# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" +# End Group +# End Target +# End Project diff --git a/Windows/xmlrpc_sample_auth_client.vcproj b/Windows/xmlrpc_sample_auth_client.vcproj new file mode 100644 index 0000000..f61e10d --- /dev/null +++ b/Windows/xmlrpc_sample_auth_client.vcproj @@ -0,0 +1,168 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Windows/xmlrpc_win32_config.h b/Windows/xmlrpc_win32_config.h new file mode 100644 index 0000000..a84eead --- /dev/null +++ b/Windows/xmlrpc_win32_config.h @@ -0,0 +1,130 @@ +#pragma once + +/* From xmlrpc_amconfig.h */ + +/* Define to `unsigned' if doesn't define. */ +/* #undef size_t */ + +/* Define if you have the setgroups function. */ +/* #undef HAVE_SETGROUPS */ + +/* #undef HAVE_ASPRINTF */ + +/* Define if you have the wcsncmp function. */ +#define HAVE_WCSNCMP 1 + +/* Define if you have the header file. */ +#define HAVE_STDARG_H 1 + +#define HAVE_SYS_FILIO_H 0 + +#define HAVE_SYS_IOCTL_H 0 + +/* Define if you have the header file. */ +#define HAVE_WCHAR_H 1 + +/* Define if you have the socket library (-lsocket). */ +/* #undef HAVE_LIBSOCKET */ + +/* Name of package */ +#define PACKAGE "xmlrpc-c" + + +/* Win32 version of xmlrpc_config.h + + Logical macros are 0 or 1 instead of the more traditional defined and + undefined. That's so we can distinguish when compiling code between + "false" and some problem with the code. +*/ + +#define _CRT_SECURE_NO_DEPRECATE + +/* Define if va_list is actually an array. */ +#define VA_LIST_IS_ARRAY 0 + +/* Define if we're using a copy of libwww with built-in SSL support. */ +#define HAVE_LIBWWW_SSL 0 + +/* Used to mark unused variables under GCC... */ +#define ATTR_UNUSED + +#define HAVE_UNICODE_WCHAR + +#define DIRECTORY_SEPARATOR "\\" + + +/* Windows-specific includes. */ + +#include +#include +#include +#if !defined (vsnprintf) + #define vsnprintf _vsnprintf +#endif +#if !defined (snprintf) + #define snprintf _snprintf +#endif +#if !defined (popen) + #define popen _popen +#endif + + +#include +#include +#include /* for _chdir() */ + +/* We are linking against the multithreaded versions + of the Microsoft runtimes - this makes gmtime + equiv to gmtime_r in that Windows gmtime is threadsafe +*/ +#if !defined (gmtime_r) +static struct tm* gmtime_r(const time_t *timep, struct tm* result) +{ + struct tm *local; + + local = gmtime(timep); + memcpy(result,local,sizeof(struct tm)); + return result; +} + +#endif + +#ifndef socklen_t +typedef unsigned int socklen_t; +#endif + +/* inttypes.h */ +#ifndef int8_t +typedef signed char int8_t; +#endif +#ifndef uint8_t +typedef unsigned char uint8_t; +#endif +#ifndef int16_t +typedef signed short int16_t; +#endif +#ifndef uint16_t +typedef unsigned short uint16_t; +#endif +#ifndef int32_t +typedef signed int int32_t; +#endif +#ifndef uint32_t +typedef unsigned int uint32_t; +#endif +#ifndef int64_t +typedef __int64 int64_t; +#endif +#ifndef uint64_t +typedef unsigned __int64 uint64_t; +#endif + +#define __inline__ __inline + +#define HAVE_SETENV 1 +__inline BOOL setenv(const char* name, const char* value, int i) +{ + return (SetEnvironmentVariable(name, value) != 0) ? TRUE : FALSE; +} + +#define strcasecmp(a,b) stricmp((a),(b)) diff --git a/aclocal.m4 b/aclocal.m4 new file mode 100644 index 0000000..9f6a125 --- /dev/null +++ b/aclocal.m4 @@ -0,0 +1,545 @@ +dnl aclocal.m4 generated automatically by aclocal 1.4 + +dnl Copyright (C) 1994, 1995-8, 1999 Free Software Foundation, Inc. +dnl This file is free software; the Free Software Foundation +dnl gives unlimited permission to copy and/or distribute it, +dnl with or without modifications, as long as this notice is preserved. + +dnl This program is distributed in the hope that it will be useful, +dnl but WITHOUT ANY WARRANTY, to the extent permitted by law; without +dnl even the implied warranty of MERCHANTABILITY or FITNESS FOR A +dnl PARTICULAR PURPOSE. + +# Like AC_CONFIG_HEADER, but automatically create stamp file. + +AC_DEFUN(AM_CONFIG_HEADER, +[AC_PREREQ([2.12]) +AC_CONFIG_HEADER([$1]) +dnl When config.status generates a header, we must update the stamp-h file. +dnl This file resides in the same directory as the config header +dnl that is generated. We must strip everything past the first ":", +dnl and everything past the last "/". +AC_OUTPUT_COMMANDS(changequote(<<,>>)dnl +ifelse(patsubst(<<$1>>, <<[^ ]>>, <<>>), <<>>, +<>CONFIG_HEADERS" || echo timestamp > patsubst(<<$1>>, <<^\([^:]*/\)?.*>>, <<\1>>)stamp-h<<>>dnl>>, +<>; do + case " <<$>>CONFIG_HEADERS " in + *" <<$>>am_file "*<<)>> + echo timestamp > `echo <<$>>am_file | sed -e 's%:.*%%' -e 's%[^/]*$%%'`stamp-h$am_indx + ;; + esac + am_indx=`expr "<<$>>am_indx" + 1` +done<<>>dnl>>) +changequote([,]))]) + +# Do all the work for Automake. This macro actually does too much -- +# some checks are only needed if your package does certain things. +# But this isn't really a big deal. + +# serial 1 + +dnl Usage: +dnl AM_INIT_AUTOMAKE(package,version, [no-define]) + +AC_DEFUN(AM_INIT_AUTOMAKE, +[AC_REQUIRE([AC_PROG_INSTALL]) +PACKAGE=[$1] +AC_SUBST(PACKAGE) +VERSION=[$2] +AC_SUBST(VERSION) +dnl test to see if srcdir already configured +if test "`cd $srcdir && pwd`" != "`pwd`" && test -f $srcdir/config.status; then + AC_MSG_ERROR([source directory already configured; run "make distclean" there first]) +fi +ifelse([$3],, +AC_DEFINE_UNQUOTED(PACKAGE, "$PACKAGE", [Name of package]) +AC_DEFINE_UNQUOTED(VERSION, "$VERSION", [Version number of package])) +AC_REQUIRE([AM_SANITY_CHECK]) +AC_REQUIRE([AC_ARG_PROGRAM]) +dnl FIXME This is truly gross. +missing_dir=`cd $ac_aux_dir && pwd` +AM_MISSING_PROG(ACLOCAL, aclocal, $missing_dir) +AM_MISSING_PROG(AUTOCONF, autoconf, $missing_dir) +AM_MISSING_PROG(AUTOMAKE, automake, $missing_dir) +AM_MISSING_PROG(AUTOHEADER, autoheader, $missing_dir) +AM_MISSING_PROG(MAKEINFO, makeinfo, $missing_dir) +AC_REQUIRE([AC_PROG_MAKE_SET])]) + +# +# Check to make sure that the build environment is sane. +# + +AC_DEFUN(AM_SANITY_CHECK, +[AC_MSG_CHECKING([whether build environment is sane]) +# Just in case +sleep 1 +echo timestamp > conftestfile +# Do `set' in a subshell so we don't clobber the current shell's +# arguments. Must try -L first in case configure is actually a +# symlink; some systems play weird games with the mod time of symlinks +# (eg FreeBSD returns the mod time of the symlink's containing +# directory). +if ( + set X `ls -Lt $srcdir/configure conftestfile 2> /dev/null` + if test "[$]*" = "X"; then + # -L didn't work. + set X `ls -t $srcdir/configure conftestfile` + fi + if test "[$]*" != "X $srcdir/configure conftestfile" \ + && test "[$]*" != "X conftestfile $srcdir/configure"; then + + # If neither matched, then we have a broken ls. This can happen + # if, for instance, CONFIG_SHELL is bash and it inherits a + # broken ls alias from the environment. This has actually + # happened. Such a system could not be considered "sane". + AC_MSG_ERROR([ls -t appears to fail. Make sure there is not a broken +alias in your environment]) + fi + + test "[$]2" = conftestfile + ) +then + # Ok. + : +else + AC_MSG_ERROR([newly created file is older than distributed files! +Check your system clock]) +fi +rm -f conftest* +AC_MSG_RESULT(yes)]) + +dnl AM_MISSING_PROG(NAME, PROGRAM, DIRECTORY) +dnl The program must properly implement --version. +AC_DEFUN(AM_MISSING_PROG, +[AC_MSG_CHECKING(for working $2) +# Run test in a subshell; some versions of sh will print an error if +# an executable is not found, even if stderr is redirected. +# Redirect stdin to placate older versions of autoconf. Sigh. +if ($2 --version) < /dev/null > /dev/null 2>&1; then + $1=$2 + AC_MSG_RESULT(found) +else + $1="$3/missing $2" + AC_MSG_RESULT(missing) +fi +AC_SUBST($1)]) + + +# serial 40 AC_PROG_LIBTOOL +AC_DEFUN(AC_PROG_LIBTOOL, +[AC_REQUIRE([AC_LIBTOOL_SETUP])dnl + +# Save cache, so that ltconfig can load it +AC_CACHE_SAVE + +# Actually configure libtool. ac_aux_dir is where install-sh is found. +CC="$CC" CFLAGS="$CFLAGS" CPPFLAGS="$CPPFLAGS" \ +LD="$LD" LDFLAGS="$LDFLAGS" LIBS="$LIBS" \ +LN_S="$LN_S" NM="$NM" RANLIB="$RANLIB" \ +DLLTOOL="$DLLTOOL" AS="$AS" OBJDUMP="$OBJDUMP" \ +${CONFIG_SHELL-/bin/sh} $ac_aux_dir/ltconfig --no-reexec \ +$libtool_flags --no-verify $ac_aux_dir/ltmain.sh $lt_target \ +|| AC_MSG_ERROR([libtool configure failed]) + +# Reload cache, that may have been modified by ltconfig +AC_CACHE_LOAD + +# This can be used to rebuild libtool when needed +LIBTOOL_DEPS="$ac_aux_dir/ltconfig $ac_aux_dir/ltmain.sh" + +# Always use our own libtool. +LIBTOOL='$(SHELL) $(top_builddir)/libtool' +AC_SUBST(LIBTOOL)dnl + +# Redirect the config.log output again, so that the ltconfig log is not +# clobbered by the next message. +exec 5>>./config.log +]) + +AC_DEFUN(AC_LIBTOOL_SETUP, +[AC_PREREQ(2.13)dnl +AC_REQUIRE([AC_ENABLE_SHARED])dnl +AC_REQUIRE([AC_ENABLE_STATIC])dnl +AC_REQUIRE([AC_ENABLE_FAST_INSTALL])dnl +AC_REQUIRE([AC_CANONICAL_HOST])dnl +AC_REQUIRE([AC_CANONICAL_BUILD])dnl +AC_REQUIRE([AC_PROG_RANLIB])dnl +AC_REQUIRE([AC_PROG_CC])dnl +AC_REQUIRE([AC_PROG_LD])dnl +AC_REQUIRE([AC_PROG_NM])dnl +AC_REQUIRE([AC_PROG_LN_S])dnl +dnl + +case "$target" in +NONE) lt_target="$host" ;; +*) lt_target="$target" ;; +esac + +# Check for any special flags to pass to ltconfig. +# +# the following will cause an existing older ltconfig to fail, so +# we ignore this at the expense of the cache file... Checking this +# will just take longer ... bummer! +#libtool_flags="--cache-file=$cache_file" +# +test "$enable_shared" = no && libtool_flags="$libtool_flags --disable-shared" +test "$enable_static" = no && libtool_flags="$libtool_flags --disable-static" +test "$enable_fast_install" = no && libtool_flags="$libtool_flags --disable-fast-install" +test "$ac_cv_prog_gcc" = yes && libtool_flags="$libtool_flags --with-gcc" +test "$ac_cv_prog_gnu_ld" = yes && libtool_flags="$libtool_flags --with-gnu-ld" +ifdef([AC_PROVIDE_AC_LIBTOOL_DLOPEN], +[libtool_flags="$libtool_flags --enable-dlopen"]) +ifdef([AC_PROVIDE_AC_LIBTOOL_WIN32_DLL], +[libtool_flags="$libtool_flags --enable-win32-dll"]) +AC_ARG_ENABLE(libtool-lock, + [ --disable-libtool-lock avoid locking (might break parallel builds)]) +test "x$enable_libtool_lock" = xno && libtool_flags="$libtool_flags --disable-lock" +test x"$silent" = xyes && libtool_flags="$libtool_flags --silent" + +# Some flags need to be propagated to the compiler or linker for good +# libtool support. +case "$lt_target" in +*-*-irix6*) + # Find out which ABI we are using. + echo '[#]line __oline__ "configure"' > conftest.$ac_ext + if AC_TRY_EVAL(ac_compile); then + case "`/usr/bin/file conftest.o`" in + *32-bit*) + LD="${LD-ld} -32" + ;; + *N32*) + LD="${LD-ld} -n32" + ;; + *64-bit*) + LD="${LD-ld} -64" + ;; + esac + fi + rm -rf conftest* + ;; + +*-*-sco3.2v5*) + # On SCO OpenServer 5, we need -belf to get full-featured binaries. + SAVE_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS -belf" + AC_CACHE_CHECK([whether the C compiler needs -belf], lt_cv_cc_needs_belf, + [AC_TRY_LINK([],[],[lt_cv_cc_needs_belf=yes],[lt_cv_cc_needs_belf=no])]) + if test x"$lt_cv_cc_needs_belf" != x"yes"; then + # this is probably gcc 2.8.0, egcs 1.0 or newer; no need for -belf + CFLAGS="$SAVE_CFLAGS" + fi + ;; + +ifdef([AC_PROVIDE_AC_LIBTOOL_WIN32_DLL], +[*-*-cygwin* | *-*-mingw*) + AC_CHECK_TOOL(DLLTOOL, dlltool, false) + AC_CHECK_TOOL(AS, as, false) + AC_CHECK_TOOL(OBJDUMP, objdump, false) + ;; +]) +esac +]) + +# AC_LIBTOOL_DLOPEN - enable checks for dlopen support +AC_DEFUN(AC_LIBTOOL_DLOPEN, [AC_BEFORE([$0],[AC_LIBTOOL_SETUP])]) + +# AC_LIBTOOL_WIN32_DLL - declare package support for building win32 dll's +AC_DEFUN(AC_LIBTOOL_WIN32_DLL, [AC_BEFORE([$0], [AC_LIBTOOL_SETUP])]) + +# AC_ENABLE_SHARED - implement the --enable-shared flag +# Usage: AC_ENABLE_SHARED[(DEFAULT)] +# Where DEFAULT is either `yes' or `no'. If omitted, it defaults to +# `yes'. +AC_DEFUN(AC_ENABLE_SHARED, [dnl +define([AC_ENABLE_SHARED_DEFAULT], ifelse($1, no, no, yes))dnl +AC_ARG_ENABLE(shared, +changequote(<<, >>)dnl +<< --enable-shared[=PKGS] build shared libraries [default=>>AC_ENABLE_SHARED_DEFAULT], +changequote([, ])dnl +[p=${PACKAGE-default} +case "$enableval" in +yes) enable_shared=yes ;; +no) enable_shared=no ;; +*) + enable_shared=no + # Look at the argument we got. We use all the common list separators. + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}:," + for pkg in $enableval; do + if test "X$pkg" = "X$p"; then + enable_shared=yes + fi + done + IFS="$ac_save_ifs" + ;; +esac], +enable_shared=AC_ENABLE_SHARED_DEFAULT)dnl +]) + +# AC_DISABLE_SHARED - set the default shared flag to --disable-shared +AC_DEFUN(AC_DISABLE_SHARED, [AC_BEFORE([$0],[AC_LIBTOOL_SETUP])dnl +AC_ENABLE_SHARED(no)]) + +# AC_ENABLE_STATIC - implement the --enable-static flag +# Usage: AC_ENABLE_STATIC[(DEFAULT)] +# Where DEFAULT is either `yes' or `no'. If omitted, it defaults to +# `yes'. +AC_DEFUN(AC_ENABLE_STATIC, [dnl +define([AC_ENABLE_STATIC_DEFAULT], ifelse($1, no, no, yes))dnl +AC_ARG_ENABLE(static, +changequote(<<, >>)dnl +<< --enable-static[=PKGS] build static libraries [default=>>AC_ENABLE_STATIC_DEFAULT], +changequote([, ])dnl +[p=${PACKAGE-default} +case "$enableval" in +yes) enable_static=yes ;; +no) enable_static=no ;; +*) + enable_static=no + # Look at the argument we got. We use all the common list separators. + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}:," + for pkg in $enableval; do + if test "X$pkg" = "X$p"; then + enable_static=yes + fi + done + IFS="$ac_save_ifs" + ;; +esac], +enable_static=AC_ENABLE_STATIC_DEFAULT)dnl +]) + +# AC_DISABLE_STATIC - set the default static flag to --disable-static +AC_DEFUN(AC_DISABLE_STATIC, [AC_BEFORE([$0],[AC_LIBTOOL_SETUP])dnl +AC_ENABLE_STATIC(no)]) + + +# AC_ENABLE_FAST_INSTALL - implement the --enable-fast-install flag +# Usage: AC_ENABLE_FAST_INSTALL[(DEFAULT)] +# Where DEFAULT is either `yes' or `no'. If omitted, it defaults to +# `yes'. +AC_DEFUN(AC_ENABLE_FAST_INSTALL, [dnl +define([AC_ENABLE_FAST_INSTALL_DEFAULT], ifelse($1, no, no, yes))dnl +AC_ARG_ENABLE(fast-install, +changequote(<<, >>)dnl +<< --enable-fast-install[=PKGS] optimize for fast installation [default=>>AC_ENABLE_FAST_INSTALL_DEFAULT], +changequote([, ])dnl +[p=${PACKAGE-default} +case "$enableval" in +yes) enable_fast_install=yes ;; +no) enable_fast_install=no ;; +*) + enable_fast_install=no + # Look at the argument we got. We use all the common list separators. + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}:," + for pkg in $enableval; do + if test "X$pkg" = "X$p"; then + enable_fast_install=yes + fi + done + IFS="$ac_save_ifs" + ;; +esac], +enable_fast_install=AC_ENABLE_FAST_INSTALL_DEFAULT)dnl +]) + +# AC_ENABLE_FAST_INSTALL - set the default to --disable-fast-install +AC_DEFUN(AC_DISABLE_FAST_INSTALL, [AC_BEFORE([$0],[AC_LIBTOOL_SETUP])dnl +AC_ENABLE_FAST_INSTALL(no)]) + +# AC_PROG_LD - find the path to the GNU or non-GNU linker +AC_DEFUN(AC_PROG_LD, +[AC_ARG_WITH(gnu-ld, +[ --with-gnu-ld assume the C compiler uses GNU ld [default=no]], +test "$withval" = no || with_gnu_ld=yes, with_gnu_ld=no) +AC_REQUIRE([AC_PROG_CC])dnl +AC_REQUIRE([AC_CANONICAL_HOST])dnl +AC_REQUIRE([AC_CANONICAL_BUILD])dnl +ac_prog=ld +if test "$ac_cv_prog_gcc" = yes; then + # Check if gcc -print-prog-name=ld gives a path. + AC_MSG_CHECKING([for ld used by GCC]) + ac_prog=`($CC -print-prog-name=ld) 2>&5` + case "$ac_prog" in + # Accept absolute paths. +changequote(,)dnl + [\\/]* | [A-Za-z]:[\\/]*) + re_direlt='/[^/][^/]*/\.\./' +changequote([,])dnl + # Canonicalize the path of ld + ac_prog=`echo $ac_prog| sed 's%\\\\%/%g'` + while echo $ac_prog | grep "$re_direlt" > /dev/null 2>&1; do + ac_prog=`echo $ac_prog| sed "s%$re_direlt%/%"` + done + test -z "$LD" && LD="$ac_prog" + ;; + "") + # If it fails, then pretend we aren't using GCC. + ac_prog=ld + ;; + *) + # If it is relative, then search for the first ld in PATH. + with_gnu_ld=unknown + ;; + esac +elif test "$with_gnu_ld" = yes; then + AC_MSG_CHECKING([for GNU ld]) +else + AC_MSG_CHECKING([for non-GNU ld]) +fi +AC_CACHE_VAL(ac_cv_path_LD, +[if test -z "$LD"; then + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}${PATH_SEPARATOR-:}" + for ac_dir in $PATH; do + test -z "$ac_dir" && ac_dir=. + if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then + ac_cv_path_LD="$ac_dir/$ac_prog" + # Check to see if the program is GNU ld. I'd rather use --version, + # but apparently some GNU ld's only accept -v. + # Break only if it was the GNU/non-GNU ld that we prefer. + if "$ac_cv_path_LD" -v 2>&1 < /dev/null | egrep '(GNU|with BFD)' > /dev/null; then + test "$with_gnu_ld" != no && break + else + test "$with_gnu_ld" != yes && break + fi + fi + done + IFS="$ac_save_ifs" +else + ac_cv_path_LD="$LD" # Let the user override the test with a path. +fi]) +LD="$ac_cv_path_LD" +if test -n "$LD"; then + AC_MSG_RESULT($LD) +else + AC_MSG_RESULT(no) +fi +test -z "$LD" && AC_MSG_ERROR([no acceptable ld found in \$PATH]) +AC_PROG_LD_GNU +]) + +AC_DEFUN(AC_PROG_LD_GNU, +[AC_CACHE_CHECK([if the linker ($LD) is GNU ld], ac_cv_prog_gnu_ld, +[# I'd rather use --version here, but apparently some GNU ld's only accept -v. +if $LD -v 2>&1 &5; then + ac_cv_prog_gnu_ld=yes +else + ac_cv_prog_gnu_ld=no +fi]) +]) + +# AC_PROG_NM - find the path to a BSD-compatible name lister +AC_DEFUN(AC_PROG_NM, +[AC_MSG_CHECKING([for BSD-compatible nm]) +AC_CACHE_VAL(ac_cv_path_NM, +[if test -n "$NM"; then + # Let the user override the test. + ac_cv_path_NM="$NM" +else + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}${PATH_SEPARATOR-:}" + for ac_dir in $PATH /usr/ccs/bin /usr/ucb /bin; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/nm || test -f $ac_dir/nm$ac_exeext ; then + # Check to see if the nm accepts a BSD-compat flag. + # Adding the `sed 1q' prevents false positives on HP-UX, which says: + # nm: unknown option "B" ignored + if ($ac_dir/nm -B /dev/null 2>&1 | sed '1q'; exit 0) | egrep /dev/null >/dev/null; then + ac_cv_path_NM="$ac_dir/nm -B" + break + elif ($ac_dir/nm -p /dev/null 2>&1 | sed '1q'; exit 0) | egrep /dev/null >/dev/null; then + ac_cv_path_NM="$ac_dir/nm -p" + break + else + ac_cv_path_NM=${ac_cv_path_NM="$ac_dir/nm"} # keep the first match, but + continue # so that we can try to find one that supports BSD flags + fi + fi + done + IFS="$ac_save_ifs" + test -z "$ac_cv_path_NM" && ac_cv_path_NM=nm +fi]) +NM="$ac_cv_path_NM" +AC_MSG_RESULT([$NM]) +]) + +# AC_CHECK_LIBM - check for math library +AC_DEFUN(AC_CHECK_LIBM, +[AC_REQUIRE([AC_CANONICAL_HOST])dnl +LIBM= +case "$lt_target" in +*-*-beos* | *-*-cygwin*) + # These system don't have libm + ;; +*-ncr-sysv4.3*) + AC_CHECK_LIB(mw, _mwvalidcheckl, LIBM="-lmw") + AC_CHECK_LIB(m, main, LIBM="$LIBM -lm") + ;; +*) + AC_CHECK_LIB(m, main, LIBM="-lm") + ;; +esac +]) + +# AC_LIBLTDL_CONVENIENCE[(dir)] - sets LIBLTDL to the link flags for +# the libltdl convenience library and INCLTDL to the include flags for +# the libltdl header and adds --enable-ltdl-convenience to the +# configure arguments. Note that LIBLTDL and INCLTDL are not +# AC_SUBSTed, nor is AC_CONFIG_SUBDIRS called. If DIR is not +# provided, it is assumed to be `libltdl'. LIBLTDL will be prefixed +# with '${top_builddir}/' and INCLTDL will be prefixed with +# '${top_srcdir}/' (note the single quotes!). If your package is not +# flat and you're not using automake, define top_builddir and +# top_srcdir appropriately in the Makefiles. +AC_DEFUN(AC_LIBLTDL_CONVENIENCE, [AC_BEFORE([$0],[AC_LIBTOOL_SETUP])dnl + case "$enable_ltdl_convenience" in + no) AC_MSG_ERROR([this package needs a convenience libltdl]) ;; + "") enable_ltdl_convenience=yes + ac_configure_args="$ac_configure_args --enable-ltdl-convenience" ;; + esac + LIBLTDL='${top_builddir}/'ifelse($#,1,[$1],['libltdl'])/libltdlc.la + INCLTDL='-I${top_srcdir}/'ifelse($#,1,[$1],['libltdl']) +]) + +# AC_LIBLTDL_INSTALLABLE[(dir)] - sets LIBLTDL to the link flags for +# the libltdl installable library and INCLTDL to the include flags for +# the libltdl header and adds --enable-ltdl-install to the configure +# arguments. Note that LIBLTDL and INCLTDL are not AC_SUBSTed, nor is +# AC_CONFIG_SUBDIRS called. If DIR is not provided and an installed +# libltdl is not found, it is assumed to be `libltdl'. LIBLTDL will +# be prefixed with '${top_builddir}/' and INCLTDL will be prefixed +# with '${top_srcdir}/' (note the single quotes!). If your package is +# not flat and you're not using automake, define top_builddir and +# top_srcdir appropriately in the Makefiles. +# In the future, this macro may have to be called after AC_PROG_LIBTOOL. +AC_DEFUN(AC_LIBLTDL_INSTALLABLE, [AC_BEFORE([$0],[AC_LIBTOOL_SETUP])dnl + AC_CHECK_LIB(ltdl, main, + [test x"$enable_ltdl_install" != xyes && enable_ltdl_install=no], + [if test x"$enable_ltdl_install" = xno; then + AC_MSG_WARN([libltdl not installed, but installation disabled]) + else + enable_ltdl_install=yes + fi + ]) + if test x"$enable_ltdl_install" = x"yes"; then + ac_configure_args="$ac_configure_args --enable-ltdl-install" + LIBLTDL='${top_builddir}/'ifelse($#,1,[$1],['libltdl'])/libltdl.la + INCLTDL='-I${top_srcdir}/'ifelse($#,1,[$1],['libltdl']) + else + ac_configure_args="$ac_configure_args --enable-ltdl-install=no" + LIBLTDL="-lltdl" + INCLTDL= + fi +]) + +dnl old names +AC_DEFUN(AM_PROG_LIBTOOL, [indir([AC_PROG_LIBTOOL])])dnl +AC_DEFUN(AM_ENABLE_SHARED, [indir([AC_ENABLE_SHARED], $@)])dnl +AC_DEFUN(AM_ENABLE_STATIC, [indir([AC_ENABLE_STATIC], $@)])dnl +AC_DEFUN(AM_DISABLE_SHARED, [indir([AC_DISABLE_SHARED], $@)])dnl +AC_DEFUN(AM_DISABLE_STATIC, [indir([AC_DISABLE_STATIC], $@)])dnl +AC_DEFUN(AM_PROG_LD, [indir([AC_PROG_LD])])dnl +AC_DEFUN(AM_PROG_NM, [indir([AC_PROG_NM])])dnl + +dnl This is just to silence aclocal about the macro not being used +ifelse([AC_DISABLE_FAST_INSTALL])dnl + diff --git a/autom4te.cache/output.0 b/autom4te.cache/output.0 new file mode 100644 index 0000000..e4acf16 --- /dev/null +++ b/autom4te.cache/output.0 @@ -0,0 +1,7573 @@ +@%:@! /bin/sh +@%:@ Guess values for system-dependent variables and create Makefiles. +@%:@ Generated by GNU Autoconf 2.59. +@%:@ +@%:@ Copyright (C) 2003 Free Software Foundation, Inc. +@%:@ This configure script is free software; the Free Software Foundation +@%:@ gives unlimited permission to copy, distribute and modify it. +## --------------------- ## +## M4sh Initialization. ## +## --------------------- ## + +# Be Bourne compatible +if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then + emulate sh + NULLCMD=: + # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which + # is contrary to our usage. Disable this feature. + alias -g '${1+"$@"}'='"$@"' +elif test -n "${BASH_VERSION+set}" && (set -o posix) >/dev/null 2>&1; then + set -o posix +fi +DUALCASE=1; export DUALCASE # for MKS sh + +# Support unset when possible. +if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then + as_unset=unset +else + as_unset=false +fi + + +# Work around bugs in pre-3.0 UWIN ksh. +$as_unset ENV MAIL MAILPATH +PS1='$ ' +PS2='> ' +PS4='+ ' + +# NLS nuisances. +for as_var in \ + LANG LANGUAGE LC_ADDRESS LC_ALL LC_COLLATE LC_CTYPE LC_IDENTIFICATION \ + LC_MEASUREMENT LC_MESSAGES LC_MONETARY LC_NAME LC_NUMERIC LC_PAPER \ + LC_TELEPHONE LC_TIME +do + if (set +x; test -z "`(eval $as_var=C; export $as_var) 2>&1`"); then + eval $as_var=C; export $as_var + else + $as_unset $as_var + fi +done + +# Required to use basename. +if expr a : '\(a\)' >/dev/null 2>&1; then + as_expr=expr +else + as_expr=false +fi + +if (basename /) >/dev/null 2>&1 && test "X`basename / 2>&1`" = "X/"; then + as_basename=basename +else + as_basename=false +fi + + +# Name of the executable. +as_me=`$as_basename "$0" || +$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ + X"$0" : 'X\(//\)$' \| \ + X"$0" : 'X\(/\)$' \| \ + . : '\(.\)' 2>/dev/null || +echo X/"$0" | + sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/; q; } + /^X\/\(\/\/\)$/{ s//\1/; q; } + /^X\/\(\/\).*/{ s//\1/; q; } + s/.*/./; q'` + + +# PATH needs CR, and LINENO needs CR and PATH. +# Avoid depending upon Character Ranges. +as_cr_letters='abcdefghijklmnopqrstuvwxyz' +as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' +as_cr_Letters=$as_cr_letters$as_cr_LETTERS +as_cr_digits='0123456789' +as_cr_alnum=$as_cr_Letters$as_cr_digits + +# The user is always right. +if test "${PATH_SEPARATOR+set}" != set; then + echo "#! /bin/sh" >conf$$.sh + echo "exit 0" >>conf$$.sh + chmod +x conf$$.sh + if (PATH="/nonexistent;."; conf$$.sh) >/dev/null 2>&1; then + PATH_SEPARATOR=';' + else + PATH_SEPARATOR=: + fi + rm -f conf$$.sh +fi + + + as_lineno_1=$LINENO + as_lineno_2=$LINENO + as_lineno_3=`(expr $as_lineno_1 + 1) 2>/dev/null` + test "x$as_lineno_1" != "x$as_lineno_2" && + test "x$as_lineno_3" = "x$as_lineno_2" || { + # Find who we are. Look in the path if we contain no path at all + # relative or not. + case $0 in + *[\\/]* ) as_myself=$0 ;; + *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break +done + + ;; + esac + # We did not find ourselves, most probably we were run as `sh COMMAND' + # in which case we are not to be found in the path. + if test "x$as_myself" = x; then + as_myself=$0 + fi + if test ! -f "$as_myself"; then + { echo "$as_me: error: cannot find myself; rerun with an absolute path" >&2 + { (exit 1); exit 1; }; } + fi + case $CONFIG_SHELL in + '') + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for as_base in sh bash ksh sh5; do + case $as_dir in + /*) + if ("$as_dir/$as_base" -c ' + as_lineno_1=$LINENO + as_lineno_2=$LINENO + as_lineno_3=`(expr $as_lineno_1 + 1) 2>/dev/null` + test "x$as_lineno_1" != "x$as_lineno_2" && + test "x$as_lineno_3" = "x$as_lineno_2" ') 2>/dev/null; then + $as_unset BASH_ENV || test "${BASH_ENV+set}" != set || { BASH_ENV=; export BASH_ENV; } + $as_unset ENV || test "${ENV+set}" != set || { ENV=; export ENV; } + CONFIG_SHELL=$as_dir/$as_base + export CONFIG_SHELL + exec "$CONFIG_SHELL" "$0" ${1+"$@"} + fi;; + esac + done +done +;; + esac + + # Create $as_me.lineno as a copy of $as_myself, but with $LINENO + # uniformly replaced by the line number. The first 'sed' inserts a + # line-number line before each line; the second 'sed' does the real + # work. The second script uses 'N' to pair each line-number line + # with the numbered line, and appends trailing '-' during + # substitution so that $LINENO is not a special case at line end. + # (Raja R Harinath suggested sed '=', and Paul Eggert wrote the + # second 'sed' script. Blame Lee E. McMahon for sed's syntax. :-) + sed '=' <$as_myself | + sed ' + N + s,$,-, + : loop + s,^\(['$as_cr_digits']*\)\(.*\)[$]LINENO\([^'$as_cr_alnum'_]\),\1\2\1\3, + t loop + s,-$,, + s,^['$as_cr_digits']*\n,, + ' >$as_me.lineno && + chmod +x $as_me.lineno || + { echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2 + { (exit 1); exit 1; }; } + + # Don't try to exec as it changes $[0], causing all sort of problems + # (the dirname of $[0] is not the place where we might find the + # original and so on. Autoconf is especially sensible to this). + . ./$as_me.lineno + # Exit status is that of the last command. + exit +} + + +case `echo "testing\c"; echo 1,2,3`,`echo -n testing; echo 1,2,3` in + *c*,-n*) ECHO_N= ECHO_C=' +' ECHO_T=' ' ;; + *c*,* ) ECHO_N=-n ECHO_C= ECHO_T= ;; + *) ECHO_N= ECHO_C='\c' ECHO_T= ;; +esac + +if expr a : '\(a\)' >/dev/null 2>&1; then + as_expr=expr +else + as_expr=false +fi + +rm -f conf$$ conf$$.exe conf$$.file +echo >conf$$.file +if ln -s conf$$.file conf$$ 2>/dev/null; then + # We could just check for DJGPP; but this test a) works b) is more generic + # and c) will remain valid once DJGPP supports symlinks (DJGPP 2.04). + if test -f conf$$.exe; then + # Don't use ln at all; we don't have any links + as_ln_s='cp -p' + else + as_ln_s='ln -s' + fi +elif ln conf$$.file conf$$ 2>/dev/null; then + as_ln_s=ln +else + as_ln_s='cp -p' +fi +rm -f conf$$ conf$$.exe conf$$.file + +if mkdir -p . 2>/dev/null; then + as_mkdir_p=: +else + test -d ./-p && rmdir ./-p + as_mkdir_p=false +fi + +as_executable_p="test -f" + +# Sed expression to map a string onto a valid CPP name. +as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" + +# Sed expression to map a string onto a valid variable name. +as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" + + +# IFS +# We need space, tab and new line, in precisely that order. +as_nl=' +' +IFS=" $as_nl" + +# CDPATH. +$as_unset CDPATH + + +# Name of the host. +# hostname on some systems (SVR3.2, Linux) returns a bogus exit status, +# so uname gets run too. +ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q` + +exec 6>&1 + +# +# Initializations. +# +ac_default_prefix=/usr/local +ac_config_libobj_dir=. +cross_compiling=no +subdirs= +MFLAGS= +MAKEFLAGS= +SHELL=${CONFIG_SHELL-/bin/sh} + +# Maximum number of lines to put in a shell here document. +# This variable seems obsolete. It should probably be removed, and +# only ac_max_sed_lines should be used. +: ${ac_max_here_lines=38} + +# Identity of this package. +PACKAGE_NAME= +PACKAGE_TARNAME= +PACKAGE_VERSION= +PACKAGE_STRING= +PACKAGE_BUGREPORT= + +ac_unique_file="include/xmlrpc-c/base.h" +# Factoring default headers for most tests. +ac_includes_default="\ +#include +#if HAVE_SYS_TYPES_H +# include +#endif +#if HAVE_SYS_STAT_H +# include +#endif +#if STDC_HEADERS +# include +# include +#else +# if HAVE_STDLIB_H +# include +# endif +#endif +#if HAVE_STRING_H +# if !STDC_HEADERS && HAVE_MEMORY_H +# include +# endif +# include +#endif +#if HAVE_STRINGS_H +# include +#endif +#if HAVE_INTTYPES_H +# include +#else +# if HAVE_STDINT_H +# include +# endif +#endif +#if HAVE_UNISTD_H +# include +#endif" + +ac_subst_vars='SHELL PATH_SEPARATOR PACKAGE_NAME PACKAGE_TARNAME PACKAGE_VERSION PACKAGE_STRING PACKAGE_BUGREPORT exec_prefix prefix program_transform_name bindir sbindir libexecdir datadir sysconfdir sharedstatedir localstatedir libdir includedir oldincludedir infodir mandir build_alias host_alias target_alias DEFS ECHO_C ECHO_N ECHO_T LIBS INSTALL_PROGRAM INSTALL_SCRIPT INSTALL_DATA PACKAGE VERSION ACLOCAL AUTOCONF AUTOMAKE AUTOHEADER MAKEINFO SET_MAKE VERSION_INFO build build_cpu build_vendor build_os host host_cpu host_vendor host_os have_wininet_config MUST_BUILD_WININET_CLIENT have_curl_config MUST_BUILD_CURL_CLIENT have_libwww_config MUST_BUILD_LIBWWW_CLIENT LIBXMLRPC_CLIENT_LA CLIENTTEST XMLRPC_CLIENT_H XMLRPC_TRANSPORT_H SYNCH_CLIENT ASYNCH_CLIENT AUTH_CLIENT QUERY_MEERKAT ENABLE_ABYSS_SERVER ABYSS_SUBDIR LIBXMLRPC_ABYSS_SERVER_LA SERVERTEST VALIDATEE XMLRPC_ABYSS_H SERVER ENABLE_CGI_SERVER ENABLE_CPLUSPLUS LIBXMLRPC_CPP_A CPPTEST XMLRPCCPP_H XML_RPC_API2CPP_SUBDIR FEATURE_LIST CC CFLAGS LDFLAGS CPPFLAGS ac_ct_CC EXEEXT OBJEXT CXX CXXFLAGS ac_ct_CXX LSOCKET CPP EGREP HAVE_WCHAR_H_DEFINE HAVE_SYS_FILIO_H_DEFINE HAVE_SYS_IOCTL_H_DEFINE VA_LIST_IS_ARRAY_DEFINE ATTR_UNUSED DIRECTORY_SEPARATOR ENABLE_ABYSS_THREADS WININET_CONFIG WININET_CFLAGS WININET_LDADD WININET_LIBDIR WININET_RPATH WININET_WL_RPATH LIBWWW_CONFIG LIBWWW_LDADD LIBWWW_LIBDIR LIBWWW_RPATH LIBWWW_WL_RPATH CURL_CONFIG CURL_LDADD CURL_LIBDIR CURL_RPATH CURL_WL_RPATH HAVE_LIBWWW_SSL_DEFINE have_xml2_config ENABLE_LIBXML2_BACKEND C_COMPILER_GNU CXX_COMPILER_GNU CC_WARN_FLAGS CPP_WARN_FLAGS BUILDDIR RANLIB ac_ct_RANLIB LN_S LIBTOOL LIB@&t@OBJS LTLIBOBJS' +ac_subst_files='' + +# Initialize some variables set by options. +ac_init_help= +ac_init_version=false +# The variables have the same names as the options, with +# dashes changed to underlines. +cache_file=/dev/null +exec_prefix=NONE +no_create= +no_recursion= +prefix=NONE +program_prefix=NONE +program_suffix=NONE +program_transform_name=s,x,x, +silent= +site= +srcdir= +verbose= +x_includes=NONE +x_libraries=NONE + +# Installation directory options. +# These are left unexpanded so users can "make install exec_prefix=/foo" +# and all the variables that are supposed to be based on exec_prefix +# by default will actually change. +# Use braces instead of parens because sh, perl, etc. also accept them. +bindir='${exec_prefix}/bin' +sbindir='${exec_prefix}/sbin' +libexecdir='${exec_prefix}/libexec' +datadir='${prefix}/share' +sysconfdir='${prefix}/etc' +sharedstatedir='${prefix}/com' +localstatedir='${prefix}/var' +libdir='${exec_prefix}/lib' +includedir='${prefix}/include' +oldincludedir='/usr/include' +infodir='${prefix}/info' +mandir='${prefix}/man' + +ac_prev= +for ac_option +do + # If the previous option needs an argument, assign it. + if test -n "$ac_prev"; then + eval "$ac_prev=\$ac_option" + ac_prev= + continue + fi + + ac_optarg=`expr "x$ac_option" : 'x[^=]*=\(.*\)'` + + # Accept the important Cygnus configure options, so we can diagnose typos. + + case $ac_option in + + -bindir | --bindir | --bindi | --bind | --bin | --bi) + ac_prev=bindir ;; + -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*) + bindir=$ac_optarg ;; + + -build | --build | --buil | --bui | --bu) + ac_prev=build_alias ;; + -build=* | --build=* | --buil=* | --bui=* | --bu=*) + build_alias=$ac_optarg ;; + + -cache-file | --cache-file | --cache-fil | --cache-fi \ + | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c) + ac_prev=cache_file ;; + -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \ + | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*) + cache_file=$ac_optarg ;; + + --config-cache | -C) + cache_file=config.cache ;; + + -datadir | --datadir | --datadi | --datad | --data | --dat | --da) + ac_prev=datadir ;; + -datadir=* | --datadir=* | --datadi=* | --datad=* | --data=* | --dat=* \ + | --da=*) + datadir=$ac_optarg ;; + + -disable-* | --disable-*) + ac_feature=`expr "x$ac_option" : 'x-*disable-\(.*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_feature" : ".*[^-_$as_cr_alnum]" >/dev/null && + { echo "$as_me: error: invalid feature name: $ac_feature" >&2 + { (exit 1); exit 1; }; } + ac_feature=`echo $ac_feature | sed 's/-/_/g'` + eval "enable_$ac_feature=no" ;; + + -enable-* | --enable-*) + ac_feature=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_feature" : ".*[^-_$as_cr_alnum]" >/dev/null && + { echo "$as_me: error: invalid feature name: $ac_feature" >&2 + { (exit 1); exit 1; }; } + ac_feature=`echo $ac_feature | sed 's/-/_/g'` + case $ac_option in + *=*) ac_optarg=`echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"`;; + *) ac_optarg=yes ;; + esac + eval "enable_$ac_feature='$ac_optarg'" ;; + + -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \ + | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \ + | --exec | --exe | --ex) + ac_prev=exec_prefix ;; + -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \ + | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \ + | --exec=* | --exe=* | --ex=*) + exec_prefix=$ac_optarg ;; + + -gas | --gas | --ga | --g) + # Obsolete; use --with-gas. + with_gas=yes ;; + + -help | --help | --hel | --he | -h) + ac_init_help=long ;; + -help=r* | --help=r* | --hel=r* | --he=r* | -hr*) + ac_init_help=recursive ;; + -help=s* | --help=s* | --hel=s* | --he=s* | -hs*) + ac_init_help=short ;; + + -host | --host | --hos | --ho) + ac_prev=host_alias ;; + -host=* | --host=* | --hos=* | --ho=*) + host_alias=$ac_optarg ;; + + -includedir | --includedir | --includedi | --included | --include \ + | --includ | --inclu | --incl | --inc) + ac_prev=includedir ;; + -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \ + | --includ=* | --inclu=* | --incl=* | --inc=*) + includedir=$ac_optarg ;; + + -infodir | --infodir | --infodi | --infod | --info | --inf) + ac_prev=infodir ;; + -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*) + infodir=$ac_optarg ;; + + -libdir | --libdir | --libdi | --libd) + ac_prev=libdir ;; + -libdir=* | --libdir=* | --libdi=* | --libd=*) + libdir=$ac_optarg ;; + + -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \ + | --libexe | --libex | --libe) + ac_prev=libexecdir ;; + -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \ + | --libexe=* | --libex=* | --libe=*) + libexecdir=$ac_optarg ;; + + -localstatedir | --localstatedir | --localstatedi | --localstated \ + | --localstate | --localstat | --localsta | --localst \ + | --locals | --local | --loca | --loc | --lo) + ac_prev=localstatedir ;; + -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \ + | --localstate=* | --localstat=* | --localsta=* | --localst=* \ + | --locals=* | --local=* | --loca=* | --loc=* | --lo=*) + localstatedir=$ac_optarg ;; + + -mandir | --mandir | --mandi | --mand | --man | --ma | --m) + ac_prev=mandir ;; + -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*) + mandir=$ac_optarg ;; + + -nfp | --nfp | --nf) + # Obsolete; use --without-fp. + with_fp=no ;; + + -no-create | --no-create | --no-creat | --no-crea | --no-cre \ + | --no-cr | --no-c | -n) + no_create=yes ;; + + -no-recursion | --no-recursion | --no-recursio | --no-recursi \ + | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) + no_recursion=yes ;; + + -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \ + | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \ + | --oldin | --oldi | --old | --ol | --o) + ac_prev=oldincludedir ;; + -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \ + | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \ + | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*) + oldincludedir=$ac_optarg ;; + + -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) + ac_prev=prefix ;; + -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*) + prefix=$ac_optarg ;; + + -program-prefix | --program-prefix | --program-prefi | --program-pref \ + | --program-pre | --program-pr | --program-p) + ac_prev=program_prefix ;; + -program-prefix=* | --program-prefix=* | --program-prefi=* \ + | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*) + program_prefix=$ac_optarg ;; + + -program-suffix | --program-suffix | --program-suffi | --program-suff \ + | --program-suf | --program-su | --program-s) + ac_prev=program_suffix ;; + -program-suffix=* | --program-suffix=* | --program-suffi=* \ + | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*) + program_suffix=$ac_optarg ;; + + -program-transform-name | --program-transform-name \ + | --program-transform-nam | --program-transform-na \ + | --program-transform-n | --program-transform- \ + | --program-transform | --program-transfor \ + | --program-transfo | --program-transf \ + | --program-trans | --program-tran \ + | --progr-tra | --program-tr | --program-t) + ac_prev=program_transform_name ;; + -program-transform-name=* | --program-transform-name=* \ + | --program-transform-nam=* | --program-transform-na=* \ + | --program-transform-n=* | --program-transform-=* \ + | --program-transform=* | --program-transfor=* \ + | --program-transfo=* | --program-transf=* \ + | --program-trans=* | --program-tran=* \ + | --progr-tra=* | --program-tr=* | --program-t=*) + program_transform_name=$ac_optarg ;; + + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil) + silent=yes ;; + + -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) + ac_prev=sbindir ;; + -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ + | --sbi=* | --sb=*) + sbindir=$ac_optarg ;; + + -sharedstatedir | --sharedstatedir | --sharedstatedi \ + | --sharedstated | --sharedstate | --sharedstat | --sharedsta \ + | --sharedst | --shareds | --shared | --share | --shar \ + | --sha | --sh) + ac_prev=sharedstatedir ;; + -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \ + | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \ + | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \ + | --sha=* | --sh=*) + sharedstatedir=$ac_optarg ;; + + -site | --site | --sit) + ac_prev=site ;; + -site=* | --site=* | --sit=*) + site=$ac_optarg ;; + + -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) + ac_prev=srcdir ;; + -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) + srcdir=$ac_optarg ;; + + -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \ + | --syscon | --sysco | --sysc | --sys | --sy) + ac_prev=sysconfdir ;; + -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \ + | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*) + sysconfdir=$ac_optarg ;; + + -target | --target | --targe | --targ | --tar | --ta | --t) + ac_prev=target_alias ;; + -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*) + target_alias=$ac_optarg ;; + + -v | -verbose | --verbose | --verbos | --verbo | --verb) + verbose=yes ;; + + -version | --version | --versio | --versi | --vers | -V) + ac_init_version=: ;; + + -with-* | --with-*) + ac_package=`expr "x$ac_option" : 'x-*with-\([^=]*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_package" : ".*[^-_$as_cr_alnum]" >/dev/null && + { echo "$as_me: error: invalid package name: $ac_package" >&2 + { (exit 1); exit 1; }; } + ac_package=`echo $ac_package| sed 's/-/_/g'` + case $ac_option in + *=*) ac_optarg=`echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"`;; + *) ac_optarg=yes ;; + esac + eval "with_$ac_package='$ac_optarg'" ;; + + -without-* | --without-*) + ac_package=`expr "x$ac_option" : 'x-*without-\(.*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_package" : ".*[^-_$as_cr_alnum]" >/dev/null && + { echo "$as_me: error: invalid package name: $ac_package" >&2 + { (exit 1); exit 1; }; } + ac_package=`echo $ac_package | sed 's/-/_/g'` + eval "with_$ac_package=no" ;; + + --x) + # Obsolete; use --with-x. + with_x=yes ;; + + -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \ + | --x-incl | --x-inc | --x-in | --x-i) + ac_prev=x_includes ;; + -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \ + | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*) + x_includes=$ac_optarg ;; + + -x-libraries | --x-libraries | --x-librarie | --x-librari \ + | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l) + ac_prev=x_libraries ;; + -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \ + | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*) + x_libraries=$ac_optarg ;; + + -*) { echo "$as_me: error: unrecognized option: $ac_option +Try \`$0 --help' for more information." >&2 + { (exit 1); exit 1; }; } + ;; + + *=*) + ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='` + # Reject names that are not valid shell variable names. + expr "x$ac_envvar" : ".*[^_$as_cr_alnum]" >/dev/null && + { echo "$as_me: error: invalid variable name: $ac_envvar" >&2 + { (exit 1); exit 1; }; } + ac_optarg=`echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` + eval "$ac_envvar='$ac_optarg'" + export $ac_envvar ;; + + *) + # FIXME: should be removed in autoconf 3.0. + echo "$as_me: WARNING: you should use --build, --host, --target" >&2 + expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null && + echo "$as_me: WARNING: invalid host type: $ac_option" >&2 + : ${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option} + ;; + + esac +done + +if test -n "$ac_prev"; then + ac_option=--`echo $ac_prev | sed 's/_/-/g'` + { echo "$as_me: error: missing argument to $ac_option" >&2 + { (exit 1); exit 1; }; } +fi + +# Be sure to have absolute paths. +for ac_var in exec_prefix prefix +do + eval ac_val=$`echo $ac_var` + case $ac_val in + [\\/$]* | ?:[\\/]* | NONE | '' ) ;; + *) { echo "$as_me: error: expected an absolute directory name for --$ac_var: $ac_val" >&2 + { (exit 1); exit 1; }; };; + esac +done + +# Be sure to have absolute paths. +for ac_var in bindir sbindir libexecdir datadir sysconfdir sharedstatedir \ + localstatedir libdir includedir oldincludedir infodir mandir +do + eval ac_val=$`echo $ac_var` + case $ac_val in + [\\/$]* | ?:[\\/]* ) ;; + *) { echo "$as_me: error: expected an absolute directory name for --$ac_var: $ac_val" >&2 + { (exit 1); exit 1; }; };; + esac +done + +# There might be people who depend on the old broken behavior: `$host' +# used to hold the argument of --host etc. +# FIXME: To remove some day. +build=$build_alias +host=$host_alias +target=$target_alias + +# FIXME: To remove some day. +if test "x$host_alias" != x; then + if test "x$build_alias" = x; then + cross_compiling=maybe + echo "$as_me: WARNING: If you wanted to set the --build type, don't use --host. + If a cross compiler is detected then cross compile mode will be used." >&2 + elif test "x$build_alias" != "x$host_alias"; then + cross_compiling=yes + fi +fi + +ac_tool_prefix= +test -n "$host_alias" && ac_tool_prefix=$host_alias- + +test "$silent" = yes && exec 6>/dev/null + + +# Find the source files, if location was not specified. +if test -z "$srcdir"; then + ac_srcdir_defaulted=yes + # Try the directory containing this script, then its parent. + ac_confdir=`(dirname "$0") 2>/dev/null || +$as_expr X"$0" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$0" : 'X\(//\)[^/]' \| \ + X"$0" : 'X\(//\)$' \| \ + X"$0" : 'X\(/\)' \| \ + . : '\(.\)' 2>/dev/null || +echo X"$0" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; } + /^X\(\/\/\)[^/].*/{ s//\1/; q; } + /^X\(\/\/\)$/{ s//\1/; q; } + /^X\(\/\).*/{ s//\1/; q; } + s/.*/./; q'` + srcdir=$ac_confdir + if test ! -r $srcdir/$ac_unique_file; then + srcdir=.. + fi +else + ac_srcdir_defaulted=no +fi +if test ! -r $srcdir/$ac_unique_file; then + if test "$ac_srcdir_defaulted" = yes; then + { echo "$as_me: error: cannot find sources ($ac_unique_file) in $ac_confdir or .." >&2 + { (exit 1); exit 1; }; } + else + { echo "$as_me: error: cannot find sources ($ac_unique_file) in $srcdir" >&2 + { (exit 1); exit 1; }; } + fi +fi +(cd $srcdir && test -r ./$ac_unique_file) 2>/dev/null || + { echo "$as_me: error: sources are in $srcdir, but \`cd $srcdir' does not work" >&2 + { (exit 1); exit 1; }; } +srcdir=`echo "$srcdir" | sed 's%\([^\\/]\)[\\/]*$%\1%'` +ac_env_build_alias_set=${build_alias+set} +ac_env_build_alias_value=$build_alias +ac_cv_env_build_alias_set=${build_alias+set} +ac_cv_env_build_alias_value=$build_alias +ac_env_host_alias_set=${host_alias+set} +ac_env_host_alias_value=$host_alias +ac_cv_env_host_alias_set=${host_alias+set} +ac_cv_env_host_alias_value=$host_alias +ac_env_target_alias_set=${target_alias+set} +ac_env_target_alias_value=$target_alias +ac_cv_env_target_alias_set=${target_alias+set} +ac_cv_env_target_alias_value=$target_alias +ac_env_CC_set=${CC+set} +ac_env_CC_value=$CC +ac_cv_env_CC_set=${CC+set} +ac_cv_env_CC_value=$CC +ac_env_CFLAGS_set=${CFLAGS+set} +ac_env_CFLAGS_value=$CFLAGS +ac_cv_env_CFLAGS_set=${CFLAGS+set} +ac_cv_env_CFLAGS_value=$CFLAGS +ac_env_LDFLAGS_set=${LDFLAGS+set} +ac_env_LDFLAGS_value=$LDFLAGS +ac_cv_env_LDFLAGS_set=${LDFLAGS+set} +ac_cv_env_LDFLAGS_value=$LDFLAGS +ac_env_CPPFLAGS_set=${CPPFLAGS+set} +ac_env_CPPFLAGS_value=$CPPFLAGS +ac_cv_env_CPPFLAGS_set=${CPPFLAGS+set} +ac_cv_env_CPPFLAGS_value=$CPPFLAGS +ac_env_CXX_set=${CXX+set} +ac_env_CXX_value=$CXX +ac_cv_env_CXX_set=${CXX+set} +ac_cv_env_CXX_value=$CXX +ac_env_CXXFLAGS_set=${CXXFLAGS+set} +ac_env_CXXFLAGS_value=$CXXFLAGS +ac_cv_env_CXXFLAGS_set=${CXXFLAGS+set} +ac_cv_env_CXXFLAGS_value=$CXXFLAGS +ac_env_CPP_set=${CPP+set} +ac_env_CPP_value=$CPP +ac_cv_env_CPP_set=${CPP+set} +ac_cv_env_CPP_value=$CPP + +# +# Report the --help message. +# +if test "$ac_init_help" = "long"; then + # Omit some internal or obsolete options to make the list less imposing. + # This message is too long to be a string in the A/UX 3.1 sh. + cat <<_ACEOF +\`configure' configures this package to adapt to many kinds of systems. + +Usage: $0 [OPTION]... [VAR=VALUE]... + +To assign environment variables (e.g., CC, CFLAGS...), specify them as +VAR=VALUE. See below for descriptions of some of the useful variables. + +Defaults for the options are specified in brackets. + +Configuration: + -h, --help display this help and exit + --help=short display options specific to this package + --help=recursive display the short help of all the included packages + -V, --version display version information and exit + -q, --quiet, --silent do not print \`checking...' messages + --cache-file=FILE cache test results in FILE [disabled] + -C, --config-cache alias for \`--cache-file=config.cache' + -n, --no-create do not create output files + --srcdir=DIR find the sources in DIR [configure dir or \`..'] + +_ACEOF + + cat <<_ACEOF +Installation directories: + --prefix=PREFIX install architecture-independent files in PREFIX + [$ac_default_prefix] + --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX + [PREFIX] + +By default, \`make install' will install all the files in +\`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify +an installation prefix other than \`$ac_default_prefix' using \`--prefix', +for instance \`--prefix=\$HOME'. + +For better control, use the options below. + +Fine tuning of the installation directories: + --bindir=DIR user executables [EPREFIX/bin] + --sbindir=DIR system admin executables [EPREFIX/sbin] + --libexecdir=DIR program executables [EPREFIX/libexec] + --datadir=DIR read-only architecture-independent data [PREFIX/share] + --sysconfdir=DIR read-only single-machine data [PREFIX/etc] + --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com] + --localstatedir=DIR modifiable single-machine data [PREFIX/var] + --libdir=DIR object code libraries [EPREFIX/lib] + --includedir=DIR C header files [PREFIX/include] + --oldincludedir=DIR C header files for non-gcc [/usr/include] + --infodir=DIR info documentation [PREFIX/info] + --mandir=DIR man documentation [PREFIX/man] +_ACEOF + + cat <<\_ACEOF + +Program names: + --program-prefix=PREFIX prepend PREFIX to installed program names + --program-suffix=SUFFIX append SUFFIX to installed program names + --program-transform-name=PROGRAM run sed PROGRAM on installed program names + +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 + + cat <<\_ACEOF + +Optional Features: + --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no) + --enable-FEATURE[=ARG] include FEATURE [ARG=yes] + --disable-wininet-client Don't build the Wininet client transport + --disable-curl-client Don't build the Curl client transport + --disable-libwww-client Don't build the Libwww client transport + --disable-abyss-server Don't build the Abyss server module + --disable-cgi-server Don't build the CGI server module + --disable-cplusplus Don't build the C++ wrapper classes or tools + --disable-abyss-threads Use fork in Abyss instead of pthreads + --enable-libxml2-backend Use libxml2 instead of built-in expat + --enable-shared=PKGS build shared libraries default=yes + --enable-static=PKGS build static libraries default=yes + --enable-fast-install=PKGS optimize for fast installation default=yes + --disable-libtool-lock avoid locking (might break parallel builds) + +Optional Packages: + --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] + --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no) + --with-libwww-ssl Include libwww SSL capability. + + --with-gnu-ld assume the C compiler uses GNU ld default=no + +Some influential environment variables: + CC C compiler command + CFLAGS C compiler flags + LDFLAGS linker flags, e.g. -L if you have libraries in a + nonstandard directory + CPPFLAGS C/C++ preprocessor flags, e.g. -I if you have + headers in a nonstandard directory + CXX C++ compiler command + CXXFLAGS C++ compiler flags + CPP C preprocessor + +Use these variables to override the choices made by `configure' or to help +it to find libraries and programs with nonstandard names/locations. + +_ACEOF +fi + +if test "$ac_init_help" = "recursive"; then + # If there are subdirs, report their specific --help. + ac_popdir=`pwd` + for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue + test -d $ac_dir || continue + ac_builddir=. + +if test "$ac_dir" != .; then + ac_dir_suffix=/`echo "$ac_dir" | sed 's,^\.[\\/],,'` + # A "../" for each directory in $ac_dir_suffix. + ac_top_builddir=`echo "$ac_dir_suffix" | sed 's,/[^\\/]*,../,g'` +else + ac_dir_suffix= ac_top_builddir= +fi + +case $srcdir in + .) # No --srcdir option. We are building in place. + ac_srcdir=. + if test -z "$ac_top_builddir"; then + ac_top_srcdir=. + else + ac_top_srcdir=`echo $ac_top_builddir | sed 's,/$,,'` + fi ;; + [\\/]* | ?:[\\/]* ) # Absolute path. + ac_srcdir=$srcdir$ac_dir_suffix; + ac_top_srcdir=$srcdir ;; + *) # Relative path. + ac_srcdir=$ac_top_builddir$srcdir$ac_dir_suffix + ac_top_srcdir=$ac_top_builddir$srcdir ;; +esac + +# Do not use `cd foo && pwd` to compute absolute paths, because +# the directories may not exist. +case `pwd` in +.) ac_abs_builddir="$ac_dir";; +*) + case "$ac_dir" in + .) ac_abs_builddir=`pwd`;; + [\\/]* | ?:[\\/]* ) ac_abs_builddir="$ac_dir";; + *) ac_abs_builddir=`pwd`/"$ac_dir";; + esac;; +esac +case $ac_abs_builddir in +.) ac_abs_top_builddir=${ac_top_builddir}.;; +*) + case ${ac_top_builddir}. in + .) ac_abs_top_builddir=$ac_abs_builddir;; + [\\/]* | ?:[\\/]* ) ac_abs_top_builddir=${ac_top_builddir}.;; + *) ac_abs_top_builddir=$ac_abs_builddir/${ac_top_builddir}.;; + esac;; +esac +case $ac_abs_builddir in +.) ac_abs_srcdir=$ac_srcdir;; +*) + case $ac_srcdir in + .) ac_abs_srcdir=$ac_abs_builddir;; + [\\/]* | ?:[\\/]* ) ac_abs_srcdir=$ac_srcdir;; + *) ac_abs_srcdir=$ac_abs_builddir/$ac_srcdir;; + esac;; +esac +case $ac_abs_builddir in +.) ac_abs_top_srcdir=$ac_top_srcdir;; +*) + case $ac_top_srcdir in + .) ac_abs_top_srcdir=$ac_abs_builddir;; + [\\/]* | ?:[\\/]* ) ac_abs_top_srcdir=$ac_top_srcdir;; + *) ac_abs_top_srcdir=$ac_abs_builddir/$ac_top_srcdir;; + esac;; +esac + + cd $ac_dir + # Check for guested configure; otherwise get Cygnus style configure. + if test -f $ac_srcdir/configure.gnu; then + echo + $SHELL $ac_srcdir/configure.gnu --help=recursive + elif test -f $ac_srcdir/configure; then + echo + $SHELL $ac_srcdir/configure --help=recursive + elif test -f $ac_srcdir/configure.ac || + test -f $ac_srcdir/configure.in; then + echo + $ac_configure --help + else + echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2 + fi + cd $ac_popdir + done +fi + +test -n "$ac_init_help" && exit 0 +if $ac_init_version; then + cat <<\_ACEOF + +Copyright (C) 2003 Free Software Foundation, Inc. +This configure script is free software; the Free Software Foundation +gives unlimited permission to copy, distribute and modify it. +_ACEOF + exit 0 +fi +exec 5>config.log +cat >&5 <<_ACEOF +This file contains any messages produced by compilers while +running configure, to aid debugging if configure makes a mistake. + +It was created by $as_me, which was +generated by GNU Autoconf 2.59. Invocation command line was + + $ $0 $@ + +_ACEOF +{ +cat <<_ASUNAME +@%:@@%:@ --------- @%:@@%:@ +@%:@@%:@ Platform. @%:@@%:@ +@%:@@%:@ --------- @%:@@%:@ + +hostname = `(hostname || uname -n) 2>/dev/null | sed 1q` +uname -m = `(uname -m) 2>/dev/null || echo unknown` +uname -r = `(uname -r) 2>/dev/null || echo unknown` +uname -s = `(uname -s) 2>/dev/null || echo unknown` +uname -v = `(uname -v) 2>/dev/null || echo unknown` + +/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown` +/bin/uname -X = `(/bin/uname -X) 2>/dev/null || echo unknown` + +/bin/arch = `(/bin/arch) 2>/dev/null || echo unknown` +/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null || echo unknown` +/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown` +hostinfo = `(hostinfo) 2>/dev/null || echo unknown` +/bin/machine = `(/bin/machine) 2>/dev/null || echo unknown` +/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null || echo unknown` +/bin/universe = `(/bin/universe) 2>/dev/null || echo unknown` + +_ASUNAME + +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + echo "PATH: $as_dir" +done + +} >&5 + +cat >&5 <<_ACEOF + + +@%:@@%:@ ----------- @%:@@%:@ +@%:@@%:@ Core tests. @%:@@%:@ +@%:@@%:@ ----------- @%:@@%:@ + +_ACEOF + + +# Keep a trace of the command line. +# Strip out --no-create and --no-recursion so they do not pile up. +# Strip out --silent because we don't want to record it for future runs. +# Also quote any args containing shell meta-characters. +# Make two passes to allow for proper duplicate-argument suppression. +ac_configure_args= +ac_configure_args0= +ac_configure_args1= +ac_sep= +ac_must_keep_next=false +for ac_pass in 1 2 +do + for ac_arg + do + case $ac_arg in + -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;; + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil) + continue ;; + *" "*|*" "*|*[\[\]\~\#\$\^\&\*\(\)\{\}\\\|\;\<\>\?\"\']*) + ac_arg=`echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; + esac + case $ac_pass in + 1) ac_configure_args0="$ac_configure_args0 '$ac_arg'" ;; + 2) + ac_configure_args1="$ac_configure_args1 '$ac_arg'" + if test $ac_must_keep_next = true; then + ac_must_keep_next=false # Got value, back to normal. + else + case $ac_arg in + *=* | --config-cache | -C | -disable-* | --disable-* \ + | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \ + | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \ + | -with-* | --with-* | -without-* | --without-* | --x) + case "$ac_configure_args0 " in + "$ac_configure_args1"*" '$ac_arg' "* ) continue ;; + esac + ;; + -* ) ac_must_keep_next=true ;; + esac + fi + ac_configure_args="$ac_configure_args$ac_sep'$ac_arg'" + # Get rid of the leading space. + ac_sep=" " + ;; + esac + done +done +$as_unset ac_configure_args0 || test "${ac_configure_args0+set}" != set || { ac_configure_args0=; export ac_configure_args0; } +$as_unset ac_configure_args1 || test "${ac_configure_args1+set}" != set || { ac_configure_args1=; export ac_configure_args1; } + +# When interrupted or exit'd, cleanup temporary files, and complete +# config.log. We remove comments because anyway the quotes in there +# would cause problems or look ugly. +# WARNING: Be sure not to use single quotes in there, as some shells, +# such as our DU 5.0 friend, will then `close' the trap. +trap 'exit_status=$? + # Save into config.log some information that might help in debugging. + { + echo + + cat <<\_ASBOX +@%:@@%:@ ---------------- @%:@@%:@ +@%:@@%:@ Cache variables. @%:@@%:@ +@%:@@%:@ ---------------- @%:@@%:@ +_ASBOX + echo + # The following way of writing the cache mishandles newlines in values, +{ + (set) 2>&1 | + case `(ac_space='"'"' '"'"'; set | grep ac_space) 2>&1` in + *ac_space=\ *) + sed -n \ + "s/'"'"'/'"'"'\\\\'"'"''"'"'/g; + s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='"'"'\\2'"'"'/p" + ;; + *) + sed -n \ + "s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1=\\2/p" + ;; + esac; +} + echo + + cat <<\_ASBOX +@%:@@%:@ ----------------- @%:@@%:@ +@%:@@%:@ Output variables. @%:@@%:@ +@%:@@%:@ ----------------- @%:@@%:@ +_ASBOX + echo + for ac_var in $ac_subst_vars + do + eval ac_val=$`echo $ac_var` + echo "$ac_var='"'"'$ac_val'"'"'" + done | sort + echo + + if test -n "$ac_subst_files"; then + cat <<\_ASBOX +@%:@@%:@ ------------- @%:@@%:@ +@%:@@%:@ Output files. @%:@@%:@ +@%:@@%:@ ------------- @%:@@%:@ +_ASBOX + echo + for ac_var in $ac_subst_files + do + eval ac_val=$`echo $ac_var` + echo "$ac_var='"'"'$ac_val'"'"'" + done | sort + echo + fi + + if test -s confdefs.h; then + cat <<\_ASBOX +@%:@@%:@ ----------- @%:@@%:@ +@%:@@%:@ confdefs.h. @%:@@%:@ +@%:@@%:@ ----------- @%:@@%:@ +_ASBOX + echo + sed "/^$/d" confdefs.h | sort + echo + fi + test "$ac_signal" != 0 && + echo "$as_me: caught signal $ac_signal" + echo "$as_me: exit $exit_status" + } >&5 + rm -f core *.core && + rm -rf conftest* confdefs* conf$$* $ac_clean_files && + exit $exit_status + ' 0 +for ac_signal in 1 2 13 15; do + trap 'ac_signal='$ac_signal'; { (exit 1); exit 1; }' $ac_signal +done +ac_signal=0 + +# confdefs.h avoids OS command line length limits that DEFS can exceed. +rm -rf conftest* confdefs.h +# AIX cpp loses on an empty file, so make sure it contains at least a newline. +echo >confdefs.h + +# Predefined preprocessor variables. + +cat >>confdefs.h <<_ACEOF +@%:@define PACKAGE_NAME "$PACKAGE_NAME" +_ACEOF + + +cat >>confdefs.h <<_ACEOF +@%:@define PACKAGE_TARNAME "$PACKAGE_TARNAME" +_ACEOF + + +cat >>confdefs.h <<_ACEOF +@%:@define PACKAGE_VERSION "$PACKAGE_VERSION" +_ACEOF + + +cat >>confdefs.h <<_ACEOF +@%:@define PACKAGE_STRING "$PACKAGE_STRING" +_ACEOF + + +cat >>confdefs.h <<_ACEOF +@%:@define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT" +_ACEOF + + +# Let the site file select an alternate cache file if it wants to. +# Prefer explicitly selected file to automatically selected ones. +if test -z "$CONFIG_SITE"; then + if test "x$prefix" != xNONE; then + CONFIG_SITE="$prefix/share/config.site $prefix/etc/config.site" + else + CONFIG_SITE="$ac_default_prefix/share/config.site $ac_default_prefix/etc/config.site" + fi +fi +for ac_site_file in $CONFIG_SITE; do + if test -r "$ac_site_file"; then + { echo "$as_me:$LINENO: loading site script $ac_site_file" >&5 +echo "$as_me: loading site script $ac_site_file" >&6;} + sed 's/^/| /' "$ac_site_file" >&5 + . "$ac_site_file" + fi +done + +if test -r "$cache_file"; then + # Some versions of bash will fail to source /dev/null (special + # files actually), so we avoid doing that. + if test -f "$cache_file"; then + { echo "$as_me:$LINENO: loading cache $cache_file" >&5 +echo "$as_me: loading cache $cache_file" >&6;} + case $cache_file in + [\\/]* | ?:[\\/]* ) . $cache_file;; + *) . ./$cache_file;; + esac + fi +else + { echo "$as_me:$LINENO: creating cache $cache_file" >&5 +echo "$as_me: creating cache $cache_file" >&6;} + >$cache_file +fi + +# Check that the precious variables saved in the cache have kept the same +# value. +ac_cache_corrupted=false +for ac_var in `(set) 2>&1 | + sed -n 's/^ac_env_\([a-zA-Z_0-9]*\)_set=.*/\1/p'`; do + eval ac_old_set=\$ac_cv_env_${ac_var}_set + eval ac_new_set=\$ac_env_${ac_var}_set + eval ac_old_val="\$ac_cv_env_${ac_var}_value" + eval ac_new_val="\$ac_env_${ac_var}_value" + case $ac_old_set,$ac_new_set in + set,) + { echo "$as_me:$LINENO: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5 +echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;} + ac_cache_corrupted=: ;; + ,set) + { echo "$as_me:$LINENO: error: \`$ac_var' was not set in the previous run" >&5 +echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;} + ac_cache_corrupted=: ;; + ,);; + *) + if test "x$ac_old_val" != "x$ac_new_val"; then + { echo "$as_me:$LINENO: error: \`$ac_var' has changed since the previous run:" >&5 +echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;} + { echo "$as_me:$LINENO: former value: $ac_old_val" >&5 +echo "$as_me: former value: $ac_old_val" >&2;} + { echo "$as_me:$LINENO: current value: $ac_new_val" >&5 +echo "$as_me: current value: $ac_new_val" >&2;} + ac_cache_corrupted=: + fi;; + esac + # Pass precious variables to config.status. + if test "$ac_new_set" = set; then + case $ac_new_val in + *" "*|*" "*|*[\[\]\~\#\$\^\&\*\(\)\{\}\\\|\;\<\>\?\"\']*) + ac_arg=$ac_var=`echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;; + *) ac_arg=$ac_var=$ac_new_val ;; + esac + case " $ac_configure_args " in + *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy. + *) ac_configure_args="$ac_configure_args '$ac_arg'" ;; + esac + fi +done +if $ac_cache_corrupted; then + { echo "$as_me:$LINENO: error: changes in the environment can compromise the build" >&5 +echo "$as_me: error: changes in the environment can compromise the build" >&2;} + { { echo "$as_me:$LINENO: error: run \`make distclean' and/or \`rm $cache_file' and start over" >&5 +echo "$as_me: error: run \`make distclean' and/or \`rm $cache_file' and start over" >&2;} + { (exit 1); exit 1; }; } +fi + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + + + + + + + + + + + + + + + + + + + + ac_config_headers="$ac_config_headers xmlrpc_amconfig.h" + + ac_config_commands="$ac_config_commands default-1" + + + +ac_aux_dir= +for ac_dir in $srcdir $srcdir/.. $srcdir/../..; do + if test -f $ac_dir/install-sh; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/install-sh -c" + break + elif test -f $ac_dir/install.sh; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/install.sh -c" + break + elif test -f $ac_dir/shtool; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/shtool install -c" + break + fi +done +if test -z "$ac_aux_dir"; then + { { echo "$as_me:$LINENO: error: cannot find install-sh or install.sh in $srcdir $srcdir/.. $srcdir/../.." >&5 +echo "$as_me: error: cannot find install-sh or install.sh in $srcdir $srcdir/.. $srcdir/../.." >&2;} + { (exit 1); exit 1; }; } +fi +ac_config_guess="$SHELL $ac_aux_dir/config.guess" +ac_config_sub="$SHELL $ac_aux_dir/config.sub" +ac_configure="$SHELL $ac_aux_dir/configure" # This should be Cygnus configure. + +# Find a good install program. We prefer a C program (faster), +# so one script is as good as another. But avoid the broken or +# incompatible versions: +# SysV /etc/install, /usr/sbin/install +# SunOS /usr/etc/install +# IRIX /sbin/install +# AIX /bin/install +# AmigaOS /C/install, which installs bootblocks on floppy discs +# AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag +# AFS /usr/afsws/bin/install, which mishandles nonexistent args +# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff" +# OS/2's system install, which has a completely different semantic +# ./install, which can be erroneously created by make from ./install.sh. +echo "$as_me:$LINENO: checking for a BSD-compatible install" >&5 +echo $ECHO_N "checking for a BSD-compatible install... $ECHO_C" >&6 +if test -z "$INSTALL"; then +if test "${ac_cv_path_install+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + # Account for people who put trailing slashes in PATH elements. +case $as_dir/ in + ./ | .// | /cC/* | \ + /etc/* | /usr/sbin/* | /usr/etc/* | /sbin/* | /usr/afsws/bin/* | \ + ?:\\/os2\\/install\\/* | ?:\\/OS2\\/INSTALL\\/* | \ + /usr/ucb/* ) ;; + *) + # OSF1 and SCO ODT 3.0 have their own names for install. + # Don't use installbsd from OSF since it installs stuff as root + # by default. + for ac_prog in ginstall scoinst install; do + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_prog$ac_exec_ext"; then + if test $ac_prog = install && + grep dspmsg "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then + # AIX install. It has an incompatible calling convention. + : + elif test $ac_prog = install && + grep pwplus "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then + # program-specific install script used by HP pwplus--don't use. + : + else + ac_cv_path_install="$as_dir/$ac_prog$ac_exec_ext -c" + break 3 + fi + fi + done + done + ;; +esac +done + + +fi + if test "${ac_cv_path_install+set}" = set; then + INSTALL=$ac_cv_path_install + else + # As a last resort, use the slow shell script. We don't cache a + # path for INSTALL within a source directory, because that will + # break other packages using the cache if that directory is + # removed, or if the path is relative. + INSTALL=$ac_install_sh + fi +fi +echo "$as_me:$LINENO: result: $INSTALL" >&5 +echo "${ECHO_T}$INSTALL" >&6 + +# Use test -z because SunOS4 sh mishandles braces in ${var-val}. +# It thinks the first close brace ends the variable substitution. +test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}' + +test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL}' + +test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644' + +echo "$as_me:$LINENO: checking whether build environment is sane" >&5 +echo $ECHO_N "checking whether build environment is sane... $ECHO_C" >&6 +# Just in case +sleep 1 +echo timestamp > conftestfile +# Do `set' in a subshell so we don't clobber the current shell's +# arguments. Must try -L first in case configure is actually a +# symlink; some systems play weird games with the mod time of symlinks +# (eg FreeBSD returns the mod time of the symlink's containing +# directory). +if ( + set X `ls -Lt $srcdir/configure conftestfile 2> /dev/null` + if test "$*" = "X"; then + # -L didn't work. + set X `ls -t $srcdir/configure conftestfile` + fi + if test "$*" != "X $srcdir/configure conftestfile" \ + && test "$*" != "X conftestfile $srcdir/configure"; then + + # If neither matched, then we have a broken ls. This can happen + # if, for instance, CONFIG_SHELL is bash and it inherits a + # broken ls alias from the environment. This has actually + # happened. Such a system could not be considered "sane". + { { echo "$as_me:$LINENO: error: ls -t appears to fail. Make sure there is not a broken +alias in your environment" >&5 +echo "$as_me: error: ls -t appears to fail. Make sure there is not a broken +alias in your environment" >&2;} + { (exit 1); exit 1; }; } + fi + + test "$2" = conftestfile + ) +then + # Ok. + : +else + { { echo "$as_me:$LINENO: error: newly created file is older than distributed files! +Check your system clock" >&5 +echo "$as_me: error: newly created file is older than distributed files! +Check your system clock" >&2;} + { (exit 1); exit 1; }; } +fi +rm -f conftest* +echo "$as_me:$LINENO: result: yes" >&5 +echo "${ECHO_T}yes" >&6 +test "$program_prefix" != NONE && + program_transform_name="s,^,$program_prefix,;$program_transform_name" +# Use a double $ so make ignores it. +test "$program_suffix" != NONE && + program_transform_name="s,\$,$program_suffix,;$program_transform_name" +# Double any \ or $. echo might interpret backslashes. +# By default was `s,x,x', remove it if useless. +cat <<\_ACEOF >conftest.sed +s/[\\$]/&&/g;s/;s,x,x,$// +_ACEOF +program_transform_name=`echo $program_transform_name | sed -f conftest.sed` +rm conftest.sed + +echo "$as_me:$LINENO: checking whether ${MAKE-make} sets \$(MAKE)" >&5 +echo $ECHO_N "checking whether ${MAKE-make} sets \$(MAKE)... $ECHO_C" >&6 +set dummy ${MAKE-make}; ac_make=`echo "$2" | sed 'y,:./+-,___p_,'` +if eval "test \"\${ac_cv_prog_make_${ac_make}_set+set}\" = set"; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.make <<\_ACEOF +all: + @echo 'ac_maketemp="$(MAKE)"' +_ACEOF +# GNU make sometimes prints "make[1]: Entering...", which would confuse us. +eval `${MAKE-make} -f conftest.make 2>/dev/null | grep temp=` +if test -n "$ac_maketemp"; then + eval ac_cv_prog_make_${ac_make}_set=yes +else + eval ac_cv_prog_make_${ac_make}_set=no +fi +rm -f conftest.make +fi +if eval "test \"`echo '$ac_cv_prog_make_'${ac_make}_set`\" = yes"; then + echo "$as_me:$LINENO: result: yes" >&5 +echo "${ECHO_T}yes" >&6 + SET_MAKE= +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 + SET_MAKE="MAKE=${MAKE-make}" +fi + + +PACKAGE=xmlrpc-c + +VERSION=1.06.31 + +if test "`cd $srcdir && pwd`" != "`pwd`" && test -f $srcdir/config.status; then + { { echo "$as_me:$LINENO: error: source directory already configured; run \"make distclean\" there first" >&5 +echo "$as_me: error: source directory already configured; run \"make distclean\" there first" >&2;} + { (exit 1); exit 1; }; } +fi + +cat >>confdefs.h <<_ACEOF +@%:@define PACKAGE "$PACKAGE" +_ACEOF + + +cat >>confdefs.h <<_ACEOF +@%:@define VERSION "$VERSION" +_ACEOF + + + +missing_dir=`cd $ac_aux_dir && pwd` +echo "$as_me:$LINENO: checking for working aclocal" >&5 +echo $ECHO_N "checking for working aclocal... $ECHO_C" >&6 +# Run test in a subshell; some versions of sh will print an error if +# an executable is not found, even if stderr is redirected. +# Redirect stdin to placate older versions of autoconf. Sigh. +if (aclocal --version) < /dev/null > /dev/null 2>&1; then + ACLOCAL=aclocal + echo "$as_me:$LINENO: result: found" >&5 +echo "${ECHO_T}found" >&6 +else + ACLOCAL="$missing_dir/missing aclocal" + echo "$as_me:$LINENO: result: missing" >&5 +echo "${ECHO_T}missing" >&6 +fi + +echo "$as_me:$LINENO: checking for working autoconf" >&5 +echo $ECHO_N "checking for working autoconf... $ECHO_C" >&6 +# Run test in a subshell; some versions of sh will print an error if +# an executable is not found, even if stderr is redirected. +# Redirect stdin to placate older versions of autoconf. Sigh. +if (autoconf --version) < /dev/null > /dev/null 2>&1; then + AUTOCONF=autoconf + echo "$as_me:$LINENO: result: found" >&5 +echo "${ECHO_T}found" >&6 +else + AUTOCONF="$missing_dir/missing autoconf" + echo "$as_me:$LINENO: result: missing" >&5 +echo "${ECHO_T}missing" >&6 +fi + +echo "$as_me:$LINENO: checking for working automake" >&5 +echo $ECHO_N "checking for working automake... $ECHO_C" >&6 +# Run test in a subshell; some versions of sh will print an error if +# an executable is not found, even if stderr is redirected. +# Redirect stdin to placate older versions of autoconf. Sigh. +if (automake --version) < /dev/null > /dev/null 2>&1; then + AUTOMAKE=automake + echo "$as_me:$LINENO: result: found" >&5 +echo "${ECHO_T}found" >&6 +else + AUTOMAKE="$missing_dir/missing automake" + echo "$as_me:$LINENO: result: missing" >&5 +echo "${ECHO_T}missing" >&6 +fi + +echo "$as_me:$LINENO: checking for working autoheader" >&5 +echo $ECHO_N "checking for working autoheader... $ECHO_C" >&6 +# Run test in a subshell; some versions of sh will print an error if +# an executable is not found, even if stderr is redirected. +# Redirect stdin to placate older versions of autoconf. Sigh. +if (autoheader --version) < /dev/null > /dev/null 2>&1; then + AUTOHEADER=autoheader + echo "$as_me:$LINENO: result: found" >&5 +echo "${ECHO_T}found" >&6 +else + AUTOHEADER="$missing_dir/missing autoheader" + echo "$as_me:$LINENO: result: missing" >&5 +echo "${ECHO_T}missing" >&6 +fi + +echo "$as_me:$LINENO: checking for working makeinfo" >&5 +echo $ECHO_N "checking for working makeinfo... $ECHO_C" >&6 +# Run test in a subshell; some versions of sh will print an error if +# an executable is not found, even if stderr is redirected. +# Redirect stdin to placate older versions of autoconf. Sigh. +if (makeinfo --version) < /dev/null > /dev/null 2>&1; then + MAKEINFO=makeinfo + echo "$as_me:$LINENO: result: found" >&5 +echo "${ECHO_T}found" >&6 +else + MAKEINFO="$missing_dir/missing makeinfo" + echo "$as_me:$LINENO: result: missing" >&5 +echo "${ECHO_T}missing" >&6 +fi + + + +VERSION_INFO="-version-info 7:0:6" + + +# Make sure we can run config.sub. +$ac_config_sub sun4 >/dev/null 2>&1 || + { { echo "$as_me:$LINENO: error: cannot run $ac_config_sub" >&5 +echo "$as_me: error: cannot run $ac_config_sub" >&2;} + { (exit 1); exit 1; }; } + +echo "$as_me:$LINENO: checking build system type" >&5 +echo $ECHO_N "checking build system type... $ECHO_C" >&6 +if test "${ac_cv_build+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_cv_build_alias=$build_alias +test -z "$ac_cv_build_alias" && + ac_cv_build_alias=`$ac_config_guess` +test -z "$ac_cv_build_alias" && + { { echo "$as_me:$LINENO: error: cannot guess build type; you must specify one" >&5 +echo "$as_me: error: cannot guess build type; you must specify one" >&2;} + { (exit 1); exit 1; }; } +ac_cv_build=`$ac_config_sub $ac_cv_build_alias` || + { { echo "$as_me:$LINENO: error: $ac_config_sub $ac_cv_build_alias failed" >&5 +echo "$as_me: error: $ac_config_sub $ac_cv_build_alias failed" >&2;} + { (exit 1); exit 1; }; } + +fi +echo "$as_me:$LINENO: result: $ac_cv_build" >&5 +echo "${ECHO_T}$ac_cv_build" >&6 +build=$ac_cv_build +build_cpu=`echo $ac_cv_build | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\1/'` +build_vendor=`echo $ac_cv_build | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\2/'` +build_os=`echo $ac_cv_build | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\3/'` + + +echo "$as_me:$LINENO: checking host system type" >&5 +echo $ECHO_N "checking host system type... $ECHO_C" >&6 +if test "${ac_cv_host+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_cv_host_alias=$host_alias +test -z "$ac_cv_host_alias" && + ac_cv_host_alias=$ac_cv_build_alias +ac_cv_host=`$ac_config_sub $ac_cv_host_alias` || + { { echo "$as_me:$LINENO: error: $ac_config_sub $ac_cv_host_alias failed" >&5 +echo "$as_me: error: $ac_config_sub $ac_cv_host_alias failed" >&2;} + { (exit 1); exit 1; }; } + +fi +echo "$as_me:$LINENO: result: $ac_cv_host" >&5 +echo "${ECHO_T}$ac_cv_host" >&6 +host=$ac_cv_host +host_cpu=`echo $ac_cv_host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\1/'` +host_vendor=`echo $ac_cv_host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\2/'` +host_os=`echo $ac_cv_host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\3/'` + + + +test -z "$target" && target=NONE + + +FEATURE_LIST= + +# Check whether --enable-wininet-client or --disable-wininet-client was given. +if test "${enable_wininet_client+set}" = set; then + enableval="$enable_wininet_client" + +else + enable_wininet_client=maybe +fi; + +if test $enable_wininet_client = maybe; then + # Extract the first word of "wininet-config", so it can be a program name with args. +set dummy wininet-config; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_have_wininet_config+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$have_wininet_config"; then + ac_cv_prog_have_wininet_config="$have_wininet_config" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_have_wininet_config="yes" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + + test -z "$ac_cv_prog_have_wininet_config" && ac_cv_prog_have_wininet_config="no" +fi +fi +have_wininet_config=$ac_cv_prog_have_wininet_config +if test -n "$have_wininet_config"; then + echo "$as_me:$LINENO: result: $have_wininet_config" >&5 +echo "${ECHO_T}$have_wininet_config" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + + if test $have_wininet_config = no; then + { echo "$as_me:$LINENO: You don't appear to have Wininet installed (no working wininet-config in your command search path), so we will not build the Wininet client XML transport" >&5 +echo "$as_me: You don't appear to have Wininet installed (no working wininet-config in your command search path), so we will not build the Wininet client XML transport" >&6;} + MUST_BUILD_WININET_CLIENT=no + else + MUST_BUILD_WININET_CLIENT=yes + fi +else + MUST_BUILD_WININET_CLIENT=$enable_wininet_client +fi + +echo "$as_me:$LINENO: checking whether to build Wininet client XML transport module" >&5 +echo $ECHO_N "checking whether to build Wininet client XML transport module... $ECHO_C" >&6 +echo "$as_me:$LINENO: result: $MUST_BUILD_WININET_CLIENT" >&5 +echo "${ECHO_T}$MUST_BUILD_WININET_CLIENT" >&6 + + + +# Check whether --enable-curl-client or --disable-curl-client was given. +if test "${enable_curl_client+set}" = set; then + enableval="$enable_curl_client" + +else + enable_curl_client=maybe +fi; + +if test $enable_curl_client = maybe; then + # Extract the first word of "curl-config", so it can be a program name with args. +set dummy curl-config; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_have_curl_config+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$have_curl_config"; then + ac_cv_prog_have_curl_config="$have_curl_config" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_have_curl_config="yes" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + + test -z "$ac_cv_prog_have_curl_config" && ac_cv_prog_have_curl_config="no" +fi +fi +have_curl_config=$ac_cv_prog_have_curl_config +if test -n "$have_curl_config"; then + echo "$as_me:$LINENO: result: $have_curl_config" >&5 +echo "${ECHO_T}$have_curl_config" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + + if test $have_curl_config = no; then + { echo "$as_me:$LINENO: You don't appear to have Curl installed (no working curl-config in your command search path), so we will not build the Curl client XML transport" >&5 +echo "$as_me: You don't appear to have Curl installed (no working curl-config in your command search path), so we will not build the Curl client XML transport" >&6;} + MUST_BUILD_CURL_CLIENT=no + else + MUST_BUILD_CURL_CLIENT=yes + fi +else + MUST_BUILD_CURL_CLIENT=$enable_curl_client +fi + +echo "$as_me:$LINENO: checking whether to build Curl client XML transport module" >&5 +echo $ECHO_N "checking whether to build Curl client XML transport module... $ECHO_C" >&6 +echo "$as_me:$LINENO: result: $MUST_BUILD_CURL_CLIENT" >&5 +echo "${ECHO_T}$MUST_BUILD_CURL_CLIENT" >&6 + + + +# Check whether --enable-libwww-client or --disable-libwww-client was given. +if test "${enable_libwww_client+set}" = set; then + enableval="$enable_libwww_client" + +else + enable_libwww_client=maybe +fi; + +if test $enable_libwww_client = maybe; then + # Extract the first word of "libwww-config", so it can be a program name with args. +set dummy libwww-config; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_have_libwww_config+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$have_libwww_config"; then + ac_cv_prog_have_libwww_config="$have_libwww_config" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_have_libwww_config="yes" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + + test -z "$ac_cv_prog_have_libwww_config" && ac_cv_prog_have_libwww_config="no" +fi +fi +have_libwww_config=$ac_cv_prog_have_libwww_config +if test -n "$have_libwww_config"; then + echo "$as_me:$LINENO: result: $have_libwww_config" >&5 +echo "${ECHO_T}$have_libwww_config" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + + if test $have_libwww_config = no; then + { echo "$as_me:$LINENO: You don't appear to have Libwww installed (no working libwww-config in your command search path), so we will not build the Libwww client XML transport" >&5 +echo "$as_me: You don't appear to have Libwww installed (no working libwww-config in your command search path), so we will not build the Libwww client XML transport" >&6;} + MUST_BUILD_LIBWWW_CLIENT=no + else + MUST_BUILD_LIBWWW_CLIENT=yes + fi +else + MUST_BUILD_LIBWWW_CLIENT=$enable_libwww_client +fi + +echo "$as_me:$LINENO: checking whether to build Libwww client XML transport module" >&5 +echo $ECHO_N "checking whether to build Libwww client XML transport module... $ECHO_C" >&6 +echo "$as_me:$LINENO: result: $MUST_BUILD_LIBWWW_CLIENT" >&5 +echo "${ECHO_T}$MUST_BUILD_LIBWWW_CLIENT" >&6 + + + +if test "$MUST_BUILD_WININET_CLIENT $MUST_BUILD_CURL_CLIENT $MUST_BUILD_LIBWWW_CLIENT" = "no no no"; then + { echo "$as_me:$LINENO: We are not building any client XML transport, therefore we will not build the client library at all." >&5 +echo "$as_me: We are not building any client XML transport, therefore we will not build the client library at all." >&6;} +fi + + + +LIBXMLRPC_CLIENT_LA=libxmlrpc_client.la + +CLIENTTEST=clienttest + +XMLRPC_CLIENT_H=xmlrpc_client.h + +XMLRPC_TRANSPORT_H=xmlrpc_transport.h + +SYNCH_CLIENT=synch_client + +ASYNCH_CLIENT=asynch_client + +AUTH_CLIENT=auth_client + +QUERY_MEERKAT=query-meerkat + + +if test $MUST_BUILD_WININET_CLIENT = yes; then + FEATURE_LIST="wininet-client $FEATURE_LIST" +fi +if test $MUST_BUILD_CURL_CLIENT = yes; then + FEATURE_LIST="curl-client $FEATURE_LIST" +fi +if test $MUST_BUILD_LIBWWW_CLIENT = yes; then + FEATURE_LIST="libwww-client $FEATURE_LIST" +fi + +echo "$as_me:$LINENO: checking whether to build Abyss server module" >&5 +echo $ECHO_N "checking whether to build Abyss server module... $ECHO_C" >&6 +# Check whether --enable-abyss-server or --disable-abyss-server was given. +if test "${enable_abyss_server+set}" = set; then + enableval="$enable_abyss_server" + +else + enable_abyss_server=yes +fi; +echo "$as_me:$LINENO: result: $enable_abyss_server" >&5 +echo "${ECHO_T}$enable_abyss_server" >&6 +ENABLE_ABYSS_SERVER=$enable_abyss_server + + +ABYSS_SUBDIR= +LIBXMLRPC_ABYSS_SERVER_LA= +SERVERTEST= +VALIDATEE= +XMLRPC_ABYSS_H= +SERVER= +if test x"$enable_abyss_server" != xno; then + FEATURE_LIST="abyss-server $FEATURE_LIST" + ABYSS_SUBDIR=abyss + LIBXMLRPC_ABYSS_SERVER_LA=libxmlrpc_abyss_server.la + SERVERTEST=servertest + VALIDATEE=validatee + XMLRPC_ABYSS_H=xmlrpc_abyss.h + SERVER=server +fi + + + + + + + +echo "$as_me:$LINENO: checking whether to build CGI server module" >&5 +echo $ECHO_N "checking whether to build CGI server module... $ECHO_C" >&6 +# Check whether --enable-cgi-server or --disable-cgi-server was given. +if test "${enable_cgi_server+set}" = set; then + enableval="$enable_cgi_server" + +else + enable_cgi_server=yes +fi; +echo "$as_me:$LINENO: result: $enable_cgi_server" >&5 +echo "${ECHO_T}$enable_cgi_server" >&6 +ENABLE_CGI_SERVER=$enable_cgi_server + + +echo "$as_me:$LINENO: checking whether to build C++ wrappers and tools" >&5 +echo $ECHO_N "checking whether to build C++ wrappers and tools... $ECHO_C" >&6 +# Check whether --enable-cplusplus or --disable-cplusplus was given. +if test "${enable_cplusplus+set}" = set; then + enableval="$enable_cplusplus" + +else + enable_cplusplus=yes +fi; +echo "$as_me:$LINENO: result: $enable_cplusplus" >&5 +echo "${ECHO_T}$enable_cplusplus" >&6 +ENABLE_CPLUSPLUS=$enable_cplusplus + + +LIBXMLRPC_CPP_A= +CPPTEST= +XMLRPCCPP_H= +XML_RPC_API2CPP_SUBDIR= +MEERKAT_APP_LIST= +INTEROP_CLIENT_SUBDIR= +if test x"$enable_cplusplus" != xno; then + FEATURE_LIST="c++ $FEATURE_LIST" + LIBXMLRPC_CPP_A=libxmlrpc_cpp.a + CPPTEST=cpptest + XMLRPCCPP_H=XmlRpcCpp.h + + if test $MUST_BUILD_LIBWWW_CLIENT = yes; then + XML_RPC_API2CPP_SUBDIR=xml-rpc-api2cpp + elif test $MUST_BUILD_CURL_CLIENT = yes; then + XML_RPC_API2CPP_SUBDIR=xml-rpc-api2cpp + fi +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 +if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args. +set dummy ${ac_tool_prefix}gcc; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_CC+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_CC="${ac_tool_prefix}gcc" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + echo "$as_me:$LINENO: result: $CC" >&5 +echo "${ECHO_T}$CC" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + +fi +if test -z "$ac_cv_prog_CC"; then + ac_ct_CC=$CC + # Extract the first word of "gcc", so it can be a program name with args. +set dummy gcc; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_ac_ct_CC+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$ac_ct_CC"; then + ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_CC="gcc" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + +fi +fi +ac_ct_CC=$ac_cv_prog_ac_ct_CC +if test -n "$ac_ct_CC"; then + echo "$as_me:$LINENO: result: $ac_ct_CC" >&5 +echo "${ECHO_T}$ac_ct_CC" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + + CC=$ac_ct_CC +else + CC="$ac_cv_prog_CC" +fi + +if test -z "$CC"; then + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args. +set dummy ${ac_tool_prefix}cc; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_CC+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_CC="${ac_tool_prefix}cc" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + echo "$as_me:$LINENO: result: $CC" >&5 +echo "${ECHO_T}$CC" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + +fi +if test -z "$ac_cv_prog_CC"; then + ac_ct_CC=$CC + # Extract the first word of "cc", so it can be a program name with args. +set dummy cc; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_ac_ct_CC+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$ac_ct_CC"; then + ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_CC="cc" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + +fi +fi +ac_ct_CC=$ac_cv_prog_ac_ct_CC +if test -n "$ac_ct_CC"; then + echo "$as_me:$LINENO: result: $ac_ct_CC" >&5 +echo "${ECHO_T}$ac_ct_CC" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + + CC=$ac_ct_CC +else + CC="$ac_cv_prog_CC" +fi + +fi +if test -z "$CC"; then + # Extract the first word of "cc", so it can be a program name with args. +set dummy cc; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_CC+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else + ac_prog_rejected=no +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then + ac_prog_rejected=yes + continue + fi + ac_cv_prog_CC="cc" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + +if test $ac_prog_rejected = yes; then + # We found a bogon in the path, so make sure we never use it. + set dummy $ac_cv_prog_CC + shift + if test $@%:@ != 0; then + # We chose a different compiler from the bogus one. + # However, it has the same basename, so the bogon will be chosen + # first if we set CC to just the basename; use the full file name. + shift + ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@" + fi +fi +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + echo "$as_me:$LINENO: result: $CC" >&5 +echo "${ECHO_T}$CC" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + +fi +if test -z "$CC"; then + if test -n "$ac_tool_prefix"; then + for ac_prog in cl + do + # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. +set dummy $ac_tool_prefix$ac_prog; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_CC+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_CC="$ac_tool_prefix$ac_prog" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + echo "$as_me:$LINENO: result: $CC" >&5 +echo "${ECHO_T}$CC" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + + test -n "$CC" && break + done +fi +if test -z "$CC"; then + ac_ct_CC=$CC + for ac_prog in cl +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_ac_ct_CC+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$ac_ct_CC"; then + ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_CC="$ac_prog" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + +fi +fi +ac_ct_CC=$ac_cv_prog_ac_ct_CC +if test -n "$ac_ct_CC"; then + echo "$as_me:$LINENO: result: $ac_ct_CC" >&5 +echo "${ECHO_T}$ac_ct_CC" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + + test -n "$ac_ct_CC" && break +done + + CC=$ac_ct_CC +fi + +fi + + +test -z "$CC" && { { echo "$as_me:$LINENO: error: no acceptable C compiler found in \$PATH +See \`config.log' for more details." >&5 +echo "$as_me: error: no acceptable C compiler found in \$PATH +See \`config.log' for more details." >&2;} + { (exit 1); exit 1; }; } + +# Provide some information about the compiler. +echo "$as_me:$LINENO:" \ + "checking for C compiler version" >&5 +ac_compiler=`set X $ac_compile; echo $2` +{ (eval echo "$as_me:$LINENO: \"$ac_compiler --version &5\"") >&5 + (eval $ac_compiler --version &5) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } +{ (eval echo "$as_me:$LINENO: \"$ac_compiler -v &5\"") >&5 + (eval $ac_compiler -v &5) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } +{ (eval echo "$as_me:$LINENO: \"$ac_compiler -V &5\"") >&5 + (eval $ac_compiler -V &5) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } + +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +ac_clean_files_save=$ac_clean_files +ac_clean_files="$ac_clean_files a.out a.exe b.out" +# Try to create an executable without -o first, disregard a.out. +# It will help us diagnose broken compilers, and finding out an intuition +# of exeext. +echo "$as_me:$LINENO: checking for C compiler default output file name" >&5 +echo $ECHO_N "checking for C compiler default output file name... $ECHO_C" >&6 +ac_link_default=`echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'` +if { (eval echo "$as_me:$LINENO: \"$ac_link_default\"") >&5 + (eval $ac_link_default) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; then + # Find the output, starting from the most likely. This scheme is +# not robust to junk in `.', hence go to wildcards (a.*) only as a last +# resort. + +# Be careful to initialize this variable, since it used to be cached. +# Otherwise an old cache value of `no' led to `EXEEXT = no' in a Makefile. +ac_cv_exeext= +# b.out is created by i960 compilers. +for ac_file in a_out.exe a.exe conftest.exe a.out conftest a.* conftest.* b.out +do + test -f "$ac_file" || continue + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.o | *.obj ) + ;; + conftest.$ac_ext ) + # This is the source file. + ;; + [ab].out ) + # We found the default executable, but exeext='' is most + # certainly right. + break;; + *.* ) + ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` + # FIXME: I believe we export ac_cv_exeext for Libtool, + # but it would be cool to find out if it's true. Does anybody + # maintain Libtool? --akim. + export ac_cv_exeext + break;; + * ) + break;; + esac +done +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +{ { echo "$as_me:$LINENO: error: C compiler cannot create executables +See \`config.log' for more details." >&5 +echo "$as_me: error: C compiler cannot create executables +See \`config.log' for more details." >&2;} + { (exit 77); exit 77; }; } +fi + +ac_exeext=$ac_cv_exeext +echo "$as_me:$LINENO: result: $ac_file" >&5 +echo "${ECHO_T}$ac_file" >&6 + +# Check the compiler produces executables we can run. If not, either +# the compiler is broken, or we cross compile. +echo "$as_me:$LINENO: checking whether the C compiler works" >&5 +echo $ECHO_N "checking whether the C compiler works... $ECHO_C" >&6 +# FIXME: These cross compiler hacks should be removed for Autoconf 3.0 +# If not cross compiling, check that we can run a simple program. +if test "$cross_compiling" != yes; then + if { ac_try='./$ac_file' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + cross_compiling=no + else + if test "$cross_compiling" = maybe; then + cross_compiling=yes + else + { { echo "$as_me:$LINENO: error: cannot run C compiled programs. +If you meant to cross compile, use \`--host'. +See \`config.log' for more details." >&5 +echo "$as_me: error: cannot run C compiled programs. +If you meant to cross compile, use \`--host'. +See \`config.log' for more details." >&2;} + { (exit 1); exit 1; }; } + fi + fi +fi +echo "$as_me:$LINENO: result: yes" >&5 +echo "${ECHO_T}yes" >&6 + +rm -f a.out a.exe conftest$ac_cv_exeext b.out +ac_clean_files=$ac_clean_files_save +# Check the compiler produces executables we can run. If not, either +# the compiler is broken, or we cross compile. +echo "$as_me:$LINENO: checking whether we are cross compiling" >&5 +echo $ECHO_N "checking whether we are cross compiling... $ECHO_C" >&6 +echo "$as_me:$LINENO: result: $cross_compiling" >&5 +echo "${ECHO_T}$cross_compiling" >&6 + +echo "$as_me:$LINENO: checking for suffix of executables" >&5 +echo $ECHO_N "checking for suffix of executables... $ECHO_C" >&6 +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; then + # If both `conftest.exe' and `conftest' are `present' (well, observable) +# catch `conftest.exe'. For instance with Cygwin, `ls conftest' will +# work properly (i.e., refer to `conftest.exe'), while it won't with +# `rm'. +for ac_file in conftest.exe conftest conftest.*; do + test -f "$ac_file" || continue + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.o | *.obj ) ;; + *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` + export ac_cv_exeext + break;; + * ) break;; + esac +done +else + { { echo "$as_me:$LINENO: error: cannot compute suffix of executables: cannot compile and link +See \`config.log' for more details." >&5 +echo "$as_me: error: cannot compute suffix of executables: cannot compile and link +See \`config.log' for more details." >&2;} + { (exit 1); exit 1; }; } +fi + +rm -f conftest$ac_cv_exeext +echo "$as_me:$LINENO: result: $ac_cv_exeext" >&5 +echo "${ECHO_T}$ac_cv_exeext" >&6 + +rm -f conftest.$ac_ext +EXEEXT=$ac_cv_exeext +ac_exeext=$EXEEXT +echo "$as_me:$LINENO: checking for suffix of object files" >&5 +echo $ECHO_N "checking for suffix of object files... $ECHO_C" >&6 +if test "${ac_cv_objext+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.o conftest.obj +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; then + for ac_file in `(ls conftest.o conftest.obj; ls conftest.*) 2>/dev/null`; do + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg ) ;; + *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'` + break;; + esac +done +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +{ { echo "$as_me:$LINENO: error: cannot compute suffix of object files: cannot compile +See \`config.log' for more details." >&5 +echo "$as_me: error: cannot compute suffix of object files: cannot compile +See \`config.log' for more details." >&2;} + { (exit 1); exit 1; }; } +fi + +rm -f conftest.$ac_cv_objext conftest.$ac_ext +fi +echo "$as_me:$LINENO: result: $ac_cv_objext" >&5 +echo "${ECHO_T}$ac_cv_objext" >&6 +OBJEXT=$ac_cv_objext +ac_objext=$OBJEXT +echo "$as_me:$LINENO: checking whether we are using the GNU C compiler" >&5 +echo $ECHO_N "checking whether we are using the GNU C compiler... $ECHO_C" >&6 +if test "${ac_cv_c_compiler_gnu+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ +#ifndef __GNUC__ + choke me +#endif + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_compiler_gnu=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_compiler_gnu=no +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +ac_cv_c_compiler_gnu=$ac_compiler_gnu + +fi +echo "$as_me:$LINENO: result: $ac_cv_c_compiler_gnu" >&5 +echo "${ECHO_T}$ac_cv_c_compiler_gnu" >&6 +GCC=`test $ac_compiler_gnu = yes && echo yes` +ac_test_CFLAGS=${CFLAGS+set} +ac_save_CFLAGS=$CFLAGS +CFLAGS="-g" +echo "$as_me:$LINENO: checking whether $CC accepts -g" >&5 +echo $ECHO_N "checking whether $CC accepts -g... $ECHO_C" >&6 +if test "${ac_cv_prog_cc_g+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_prog_cc_g=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_cv_prog_cc_g=no +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +fi +echo "$as_me:$LINENO: result: $ac_cv_prog_cc_g" >&5 +echo "${ECHO_T}$ac_cv_prog_cc_g" >&6 +if test "$ac_test_CFLAGS" = set; then + CFLAGS=$ac_save_CFLAGS +elif test $ac_cv_prog_cc_g = yes; then + if test "$GCC" = yes; then + CFLAGS="-g -O2" + else + CFLAGS="-g" + fi +else + if test "$GCC" = yes; then + CFLAGS="-O2" + else + CFLAGS= + fi +fi +echo "$as_me:$LINENO: checking for $CC option to accept ANSI C" >&5 +echo $ECHO_N "checking for $CC option to accept ANSI C... $ECHO_C" >&6 +if test "${ac_cv_prog_cc_stdc+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_cv_prog_cc_stdc=no +ac_save_CC=$CC +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +#include +#include +#include +/* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */ +struct buf { int x; }; +FILE * (*rcsopen) (struct buf *, struct stat *, int); +static char *e (p, i) + char **p; + int i; +{ + return p[i]; +} +static char *f (char * (*g) (char **, int), char **p, ...) +{ + char *s; + va_list v; + va_start (v,p); + s = g (p, va_arg (v,int)); + va_end (v); + return s; +} + +/* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has + function prototypes and stuff, but not '\xHH' hex character constants. + These don't provoke an error unfortunately, instead are silently treated + as 'x'. The following induces an error, until -std1 is added to get + proper ANSI mode. Curiously '\x00'!='x' always comes out true, for an + array size at least. It's necessary to write '\x00'==0 to get something + that's true only with -std1. */ +int osf4_cc_array ['\x00' == 0 ? 1 : -1]; + +int test (int i, double x); +struct s1 {int (*f) (int a);}; +struct s2 {int (*f) (double a);}; +int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int); +int argc; +char **argv; +int +main () +{ +return f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1]; + ; + return 0; +} +_ACEOF +# Don't try gcc -ansi; that turns off useful extensions and +# breaks some systems' header files. +# AIX -qlanglvl=ansi +# Ultrix and OSF/1 -std1 +# HP-UX 10.20 and later -Ae +# HP-UX older versions -Aa -D_HPUX_SOURCE +# SVR4 -Xc -D__EXTENSIONS__ +for ac_arg in "" -qlanglvl=ansi -std1 -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__" +do + CC="$ac_save_CC $ac_arg" + rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_prog_cc_stdc=$ac_arg +break +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +fi +rm -f conftest.err conftest.$ac_objext +done +rm -f conftest.$ac_ext conftest.$ac_objext +CC=$ac_save_CC + +fi + +case "x$ac_cv_prog_cc_stdc" in + x|xno) + echo "$as_me:$LINENO: result: none needed" >&5 +echo "${ECHO_T}none needed" >&6 ;; + *) + echo "$as_me:$LINENO: result: $ac_cv_prog_cc_stdc" >&5 +echo "${ECHO_T}$ac_cv_prog_cc_stdc" >&6 + CC="$CC $ac_cv_prog_cc_stdc" ;; +esac + +# Some people use a C++ compiler to compile C. Since we use `exit', +# in C++ we need to declare it. In case someone uses the same compiler +# for both compiling C and C++ we need to have the C++ compiler decide +# the declaration of exit, since it's the most demanding environment. +cat >conftest.$ac_ext <<_ACEOF +@%:@ifndef __cplusplus + choke me +@%:@endif +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + for ac_declaration in \ + '' \ + 'extern "C" void std::exit (int) throw (); using std::exit;' \ + 'extern "C" void std::exit (int); using std::exit;' \ + 'extern "C" void exit (int) throw ();' \ + 'extern "C" void exit (int);' \ + 'void exit (int);' +do + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_declaration +@%:@include +int +main () +{ +exit (42); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + : +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +continue +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_declaration +int +main () +{ +exit (42); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + break +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +done +rm -f conftest* +if test -n "$ac_declaration"; then + echo '#ifdef __cplusplus' >>confdefs.h + echo $ac_declaration >>confdefs.h + echo '#endif' >>confdefs.h +fi + +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + +if test x"$enable_cplusplus" != xno; then + ac_ext=cc +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu +if test -n "$ac_tool_prefix"; then + for ac_prog in $CCC g++ c++ gpp aCC CC cxx cc++ cl FCC KCC RCC xlC_r xlC + do + # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. +set dummy $ac_tool_prefix$ac_prog; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_CXX+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$CXX"; then + ac_cv_prog_CXX="$CXX" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_CXX="$ac_tool_prefix$ac_prog" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + +fi +fi +CXX=$ac_cv_prog_CXX +if test -n "$CXX"; then + echo "$as_me:$LINENO: result: $CXX" >&5 +echo "${ECHO_T}$CXX" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + + test -n "$CXX" && break + done +fi +if test -z "$CXX"; then + ac_ct_CXX=$CXX + for ac_prog in $CCC g++ c++ gpp aCC CC cxx cc++ cl FCC KCC RCC xlC_r xlC +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_ac_ct_CXX+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$ac_ct_CXX"; then + ac_cv_prog_ac_ct_CXX="$ac_ct_CXX" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_CXX="$ac_prog" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + +fi +fi +ac_ct_CXX=$ac_cv_prog_ac_ct_CXX +if test -n "$ac_ct_CXX"; then + echo "$as_me:$LINENO: result: $ac_ct_CXX" >&5 +echo "${ECHO_T}$ac_ct_CXX" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + + test -n "$ac_ct_CXX" && break +done +test -n "$ac_ct_CXX" || ac_ct_CXX="g++" + + CXX=$ac_ct_CXX +fi + + +# Provide some information about the compiler. +echo "$as_me:$LINENO:" \ + "checking for C++ compiler version" >&5 +ac_compiler=`set X $ac_compile; echo $2` +{ (eval echo "$as_me:$LINENO: \"$ac_compiler --version &5\"") >&5 + (eval $ac_compiler --version &5) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } +{ (eval echo "$as_me:$LINENO: \"$ac_compiler -v &5\"") >&5 + (eval $ac_compiler -v &5) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } +{ (eval echo "$as_me:$LINENO: \"$ac_compiler -V &5\"") >&5 + (eval $ac_compiler -V &5) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } + +echo "$as_me:$LINENO: checking whether we are using the GNU C++ compiler" >&5 +echo $ECHO_N "checking whether we are using the GNU C++ compiler... $ECHO_C" >&6 +if test "${ac_cv_cxx_compiler_gnu+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ +#ifndef __GNUC__ + choke me +#endif + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_cxx_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_compiler_gnu=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_compiler_gnu=no +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +ac_cv_cxx_compiler_gnu=$ac_compiler_gnu + +fi +echo "$as_me:$LINENO: result: $ac_cv_cxx_compiler_gnu" >&5 +echo "${ECHO_T}$ac_cv_cxx_compiler_gnu" >&6 +GXX=`test $ac_compiler_gnu = yes && echo yes` +ac_test_CXXFLAGS=${CXXFLAGS+set} +ac_save_CXXFLAGS=$CXXFLAGS +CXXFLAGS="-g" +echo "$as_me:$LINENO: checking whether $CXX accepts -g" >&5 +echo $ECHO_N "checking whether $CXX accepts -g... $ECHO_C" >&6 +if test "${ac_cv_prog_cxx_g+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_cxx_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_prog_cxx_g=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_cv_prog_cxx_g=no +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +fi +echo "$as_me:$LINENO: result: $ac_cv_prog_cxx_g" >&5 +echo "${ECHO_T}$ac_cv_prog_cxx_g" >&6 +if test "$ac_test_CXXFLAGS" = set; then + CXXFLAGS=$ac_save_CXXFLAGS +elif test $ac_cv_prog_cxx_g = yes; then + if test "$GXX" = yes; then + CXXFLAGS="-g -O2" + else + CXXFLAGS="-g" + fi +else + if test "$GXX" = yes; then + CXXFLAGS="-O2" + else + CXXFLAGS= + fi +fi +for ac_declaration in \ + '' \ + 'extern "C" void std::exit (int) throw (); using std::exit;' \ + 'extern "C" void std::exit (int); using std::exit;' \ + 'extern "C" void exit (int) throw ();' \ + 'extern "C" void exit (int);' \ + 'void exit (int);' +do + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_declaration +@%:@include +int +main () +{ +exit (42); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_cxx_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + : +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +continue +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_declaration +int +main () +{ +exit (42); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_cxx_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + break +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +done +rm -f conftest* +if test -n "$ac_declaration"; then + echo '#ifdef __cplusplus' >>confdefs.h + echo $ac_declaration >>confdefs.h + echo '#endif' >>confdefs.h +fi + +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 + +fi + + + +# Code by albert chin to check for various +# oddball networking libraries. Solaris and some other operating systems +# hide their networking code in various places. (Yes, this links too many +# of our libraries against -lsocket, but a finer-grained mechanism would +# require too much testing.) +echo "$as_me:$LINENO: checking for socket" >&5 +echo $ECHO_N "checking for socket... $ECHO_C" >&6 +if test "${ac_cv_func_socket+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +/* Define socket to an innocuous variant, in case declares socket. + For example, HP-UX 11i declares gettimeofday. */ +#define socket innocuous_socket + +/* System header to define __stub macros and hopefully few prototypes, + which can conflict with char socket (); below. + Prefer to if __STDC__ is defined, since + exists even on freestanding compilers. */ + +#ifdef __STDC__ +# include +#else +# include +#endif + +#undef socket + +/* Override any gcc2 internal prototype to avoid an error. */ +#ifdef __cplusplus +extern "C" +{ +#endif +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char socket (); +/* 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_socket) || defined (__stub___socket) +choke me +#else +char (*f) () = socket; +#endif +#ifdef __cplusplus +} +#endif + +int +main () +{ +return f != socket; + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_func_socket=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_cv_func_socket=no +fi +rm -f conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +fi +echo "$as_me:$LINENO: result: $ac_cv_func_socket" >&5 +echo "${ECHO_T}$ac_cv_func_socket" >&6 +if test $ac_cv_func_socket = yes; then + : +else + +echo "$as_me:$LINENO: checking for socket in -lsocket" >&5 +echo $ECHO_N "checking for socket in -lsocket... $ECHO_C" >&6 +if test "${ac_cv_lib_socket_socket+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lsocket $LIBS" + +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +/* Override any gcc2 internal prototype to avoid an error. */ +#ifdef __cplusplus +extern "C" +#endif +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char socket (); +int +main () +{ +socket (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_lib_socket_socket=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_cv_lib_socket_socket=no +fi +rm -f conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +echo "$as_me:$LINENO: result: $ac_cv_lib_socket_socket" >&5 +echo "${ECHO_T}$ac_cv_lib_socket_socket" >&6 +if test $ac_cv_lib_socket_socket = yes; then + cat >>confdefs.h <<_ACEOF +@%:@define HAVE_LIBSOCKET 1 +_ACEOF + + LIBS="-lsocket $LIBS" + +fi + +fi + + +# Above sets LIBS, which is not all that useful because we don't want +# to include every library in every link. It also sets +# ac_cv_lib_socket_socket, which we use to pass more specific information +# to the configuration files. + +if test x"$ac_cv_lib_socket_socket" = xyes; then + LSOCKET=-lsocket +else + LSOCKET= +fi + + +# For some reason, we don't seem to need this on Solaris. If you do +# need it, go ahead and try it. +# AC_CHECK_FUNC(gethostent, , AC_CHECK_LIB(nsl, gethostent)) + + + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu +echo "$as_me:$LINENO: checking how to run the C preprocessor" >&5 +echo $ECHO_N "checking how to run the C preprocessor... $ECHO_C" >&6 +# On Suns, sometimes $CPP names a directory. +if test -n "$CPP" && test -d "$CPP"; then + CPP= +fi +if test -z "$CPP"; then + if test "${ac_cv_prog_CPP+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + # Double quotes because CPP needs to be expanded + for CPP in "$CC -E" "$CC -E -traditional-cpp" "/lib/cpp" + do + ac_preproc_ok=false +for ac_c_preproc_warn_flag in '' yes +do + # Use a header file that comes with gcc, so configuring glibc + # with a fresh cross-compiler works. + # Prefer to if __STDC__ is defined, since + # 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 +@%:@else +@%:@ include +@%:@endif + Syntax error +_ACEOF +if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 + (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null; then + if test -s conftest.err; then + ac_cpp_err=$ac_c_preproc_warn_flag + ac_cpp_err=$ac_cpp_err$ac_c_werror_flag + else + ac_cpp_err= + fi +else + ac_cpp_err=yes +fi +if test -z "$ac_cpp_err"; then + : +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + # Broken: fails on valid input. +continue +fi +rm -f conftest.err conftest.$ac_ext + + # OK, works on sane cases. Now check whether non-existent headers + # can be detected and how. + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +@%:@include +_ACEOF +if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 + (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null; then + if test -s conftest.err; then + ac_cpp_err=$ac_c_preproc_warn_flag + ac_cpp_err=$ac_cpp_err$ac_c_werror_flag + else + ac_cpp_err= + fi +else + ac_cpp_err=yes +fi +if test -z "$ac_cpp_err"; then + # Broken: success on invalid input. +continue +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + # Passes both tests. +ac_preproc_ok=: +break +fi +rm -f conftest.err conftest.$ac_ext + +done +# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. +rm -f conftest.err conftest.$ac_ext +if $ac_preproc_ok; then + break +fi + + done + ac_cv_prog_CPP=$CPP + +fi + CPP=$ac_cv_prog_CPP +else + ac_cv_prog_CPP=$CPP +fi +echo "$as_me:$LINENO: result: $CPP" >&5 +echo "${ECHO_T}$CPP" >&6 +ac_preproc_ok=false +for ac_c_preproc_warn_flag in '' yes +do + # Use a header file that comes with gcc, so configuring glibc + # with a fresh cross-compiler works. + # Prefer to if __STDC__ is defined, since + # 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 +@%:@else +@%:@ include +@%:@endif + Syntax error +_ACEOF +if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 + (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null; then + if test -s conftest.err; then + ac_cpp_err=$ac_c_preproc_warn_flag + ac_cpp_err=$ac_cpp_err$ac_c_werror_flag + else + ac_cpp_err= + fi +else + ac_cpp_err=yes +fi +if test -z "$ac_cpp_err"; then + : +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + # Broken: fails on valid input. +continue +fi +rm -f conftest.err conftest.$ac_ext + + # OK, works on sane cases. Now check whether non-existent headers + # can be detected and how. + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +@%:@include +_ACEOF +if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 + (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null; then + if test -s conftest.err; then + ac_cpp_err=$ac_c_preproc_warn_flag + ac_cpp_err=$ac_cpp_err$ac_c_werror_flag + else + ac_cpp_err= + fi +else + ac_cpp_err=yes +fi +if test -z "$ac_cpp_err"; then + # Broken: success on invalid input. +continue +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + # Passes both tests. +ac_preproc_ok=: +break +fi +rm -f conftest.err conftest.$ac_ext + +done +# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. +rm -f conftest.err conftest.$ac_ext +if $ac_preproc_ok; then + : +else + { { echo "$as_me:$LINENO: error: C preprocessor \"$CPP\" fails sanity check +See \`config.log' for more details." >&5 +echo "$as_me: error: C preprocessor \"$CPP\" fails sanity check +See \`config.log' for more details." >&2;} + { (exit 1); exit 1; }; } +fi + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +echo "$as_me:$LINENO: checking for egrep" >&5 +echo $ECHO_N "checking for egrep... $ECHO_C" >&6 +if test "${ac_cv_prog_egrep+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if echo a | (grep -E '(a|b)') >/dev/null 2>&1 + then ac_cv_prog_egrep='grep -E' + else ac_cv_prog_egrep='egrep' + fi +fi +echo "$as_me:$LINENO: result: $ac_cv_prog_egrep" >&5 +echo "${ECHO_T}$ac_cv_prog_egrep" >&6 + EGREP=$ac_cv_prog_egrep + + +echo "$as_me:$LINENO: checking for ANSI C header files" >&5 +echo $ECHO_N "checking for ANSI C header files... $ECHO_C" >&6 +if test "${ac_cv_header_stdc+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +#include +#include +#include + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_header_stdc=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_cv_header_stdc=no +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext + +if test $ac_cv_header_stdc = yes; then + # SunOS 4.x string.h does not declare mem*, contrary to ANSI. + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include + +_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 + +_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 +#if ((' ' & 0x0FF) == 0x020) +# define ISLOWER(c) ('a' <= (c) && (c) <= 'z') +# define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c)) +#else +# define ISLOWER(c) \ + (('a' <= (c) && (c) <= 'i') \ + || ('j' <= (c) && (c) <= 'r') \ + || ('s' <= (c) && (c) <= 'z')) +# define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c)) +#endif + +#define XOR(e, f) (((e) && !(f)) || (!(e) && (f))) +int +main () +{ + int i; + for (i = 0; i < 256; i++) + if (XOR (islower (i), ISLOWER (i)) + || toupper (i) != TOUPPER (i)) + exit(2); + exit (0); +} +_ACEOF +rm -f conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { ac_try='./conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + : +else + echo "$as_me: program exited with status $ac_status" >&5 +echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +( exit $ac_status ) +ac_cv_header_stdc=no +fi +rm -f core *.core gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext +fi +fi +fi +echo "$as_me:$LINENO: result: $ac_cv_header_stdc" >&5 +echo "${ECHO_T}$ac_cv_header_stdc" >&6 +if test $ac_cv_header_stdc = yes; then + +cat >>confdefs.h <<\_ACEOF +@%:@define STDC_HEADERS 1 +_ACEOF + +fi + + + +# On IRIX 5.3, sys/types and inttypes.h are conflicting. + + + + + + + + + +for ac_header in sys/types.h sys/stat.h stdlib.h string.h memory.h strings.h \ + inttypes.h stdint.h unistd.h +do +as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh` +echo "$as_me:$LINENO: checking for $ac_header" >&5 +echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6 +if eval "test \"\${$as_ac_Header+set}\" = set"; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default + +@%:@include <$ac_header> +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + eval "$as_ac_Header=yes" +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +eval "$as_ac_Header=no" +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +fi +echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5 +echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6 +if test `eval echo '${'$as_ac_Header'}'` = yes; then + cat >>confdefs.h <<_ACEOF +@%:@define `echo "HAVE_$ac_header" | $as_tr_cpp` 1 +_ACEOF + +fi + +done + + + +for ac_header in wchar.h +do +as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh` +if eval "test \"\${$as_ac_Header+set}\" = set"; then + echo "$as_me:$LINENO: checking for $ac_header" >&5 +echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6 +if eval "test \"\${$as_ac_Header+set}\" = set"; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +fi +echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5 +echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6 +else + # Is the header compilable? +echo "$as_me:$LINENO: checking $ac_header usability" >&5 +echo $ECHO_N "checking $ac_header usability... $ECHO_C" >&6 +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +@%:@include <$ac_header> +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_header_compiler=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_header_compiler=no +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +echo "$as_me:$LINENO: result: $ac_header_compiler" >&5 +echo "${ECHO_T}$ac_header_compiler" >&6 + +# Is the header present? +echo "$as_me:$LINENO: checking $ac_header presence" >&5 +echo $ECHO_N "checking $ac_header presence... $ECHO_C" >&6 +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +@%:@include <$ac_header> +_ACEOF +if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 + (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null; then + if test -s conftest.err; then + ac_cpp_err=$ac_c_preproc_warn_flag + ac_cpp_err=$ac_cpp_err$ac_c_werror_flag + else + ac_cpp_err= + fi +else + ac_cpp_err=yes +fi +if test -z "$ac_cpp_err"; then + ac_header_preproc=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_header_preproc=no +fi +rm -f conftest.err conftest.$ac_ext +echo "$as_me:$LINENO: result: $ac_header_preproc" >&5 +echo "${ECHO_T}$ac_header_preproc" >&6 + +# So? What about this header? +case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in + yes:no: ) + { echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5 +echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5 +echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;} + ac_header_preproc=yes + ;; + no:yes:* ) + { echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5 +echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: check for missing prerequisite headers?" >&5 +echo "$as_me: WARNING: $ac_header: check for missing prerequisite headers?" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5 +echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&5 +echo "$as_me: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5 +echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5 +echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;} + ( + cat <<\_ASBOX +@%:@@%:@ ------------------------------------------ @%:@@%:@ +@%:@@%:@ Report this to the AC_PACKAGE_NAME lists. @%:@@%:@ +@%:@@%:@ ------------------------------------------ @%:@@%:@ +_ASBOX + ) | + sed "s/^/$as_me: WARNING: /" >&2 + ;; +esac +echo "$as_me:$LINENO: checking for $ac_header" >&5 +echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6 +if eval "test \"\${$as_ac_Header+set}\" = set"; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + eval "$as_ac_Header=\$ac_header_preproc" +fi +echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5 +echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6 + +fi +if test `eval echo '${'$as_ac_Header'}'` = yes; then + cat >>confdefs.h <<_ACEOF +@%:@define `echo "HAVE_$ac_header" | $as_tr_cpp` 1 +_ACEOF + +fi + +done + + +if test x"$ac_cv_header_wchar_h" = xyes; then + HAVE_WCHAR_H_DEFINE=1 +else + HAVE_WCHAR_H_DEFINE=0 +fi + + +# Needed by Abyss on Solaris: + + +for ac_header in sys/filio.h +do +as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh` +if eval "test \"\${$as_ac_Header+set}\" = set"; then + echo "$as_me:$LINENO: checking for $ac_header" >&5 +echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6 +if eval "test \"\${$as_ac_Header+set}\" = set"; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +fi +echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5 +echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6 +else + # Is the header compilable? +echo "$as_me:$LINENO: checking $ac_header usability" >&5 +echo $ECHO_N "checking $ac_header usability... $ECHO_C" >&6 +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +@%:@include <$ac_header> +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_header_compiler=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_header_compiler=no +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +echo "$as_me:$LINENO: result: $ac_header_compiler" >&5 +echo "${ECHO_T}$ac_header_compiler" >&6 + +# Is the header present? +echo "$as_me:$LINENO: checking $ac_header presence" >&5 +echo $ECHO_N "checking $ac_header presence... $ECHO_C" >&6 +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +@%:@include <$ac_header> +_ACEOF +if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 + (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null; then + if test -s conftest.err; then + ac_cpp_err=$ac_c_preproc_warn_flag + ac_cpp_err=$ac_cpp_err$ac_c_werror_flag + else + ac_cpp_err= + fi +else + ac_cpp_err=yes +fi +if test -z "$ac_cpp_err"; then + ac_header_preproc=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_header_preproc=no +fi +rm -f conftest.err conftest.$ac_ext +echo "$as_me:$LINENO: result: $ac_header_preproc" >&5 +echo "${ECHO_T}$ac_header_preproc" >&6 + +# So? What about this header? +case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in + yes:no: ) + { echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5 +echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5 +echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;} + ac_header_preproc=yes + ;; + no:yes:* ) + { echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5 +echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: check for missing prerequisite headers?" >&5 +echo "$as_me: WARNING: $ac_header: check for missing prerequisite headers?" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5 +echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&5 +echo "$as_me: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5 +echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5 +echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;} + ( + cat <<\_ASBOX +@%:@@%:@ ------------------------------------------ @%:@@%:@ +@%:@@%:@ Report this to the AC_PACKAGE_NAME lists. @%:@@%:@ +@%:@@%:@ ------------------------------------------ @%:@@%:@ +_ASBOX + ) | + sed "s/^/$as_me: WARNING: /" >&2 + ;; +esac +echo "$as_me:$LINENO: checking for $ac_header" >&5 +echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6 +if eval "test \"\${$as_ac_Header+set}\" = set"; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + eval "$as_ac_Header=\$ac_header_preproc" +fi +echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5 +echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6 + +fi +if test `eval echo '${'$as_ac_Header'}'` = yes; then + cat >>confdefs.h <<_ACEOF +@%:@define `echo "HAVE_$ac_header" | $as_tr_cpp` 1 +_ACEOF + +fi + +done + +if test x"$ac_cv_header_sys_filio_h" = xyes; then + HAVE_SYS_FILIO_H_DEFINE=1 +else + HAVE_SYS_FILIO_H_DEFINE=0 +fi + + +# Needed by Abyss on Solaris: + + +for ac_header in sys/ioctl.h +do +as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh` +if eval "test \"\${$as_ac_Header+set}\" = set"; then + echo "$as_me:$LINENO: checking for $ac_header" >&5 +echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6 +if eval "test \"\${$as_ac_Header+set}\" = set"; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +fi +echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5 +echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6 +else + # Is the header compilable? +echo "$as_me:$LINENO: checking $ac_header usability" >&5 +echo $ECHO_N "checking $ac_header usability... $ECHO_C" >&6 +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +@%:@include <$ac_header> +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_header_compiler=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_header_compiler=no +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +echo "$as_me:$LINENO: result: $ac_header_compiler" >&5 +echo "${ECHO_T}$ac_header_compiler" >&6 + +# Is the header present? +echo "$as_me:$LINENO: checking $ac_header presence" >&5 +echo $ECHO_N "checking $ac_header presence... $ECHO_C" >&6 +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +@%:@include <$ac_header> +_ACEOF +if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 + (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null; then + if test -s conftest.err; then + ac_cpp_err=$ac_c_preproc_warn_flag + ac_cpp_err=$ac_cpp_err$ac_c_werror_flag + else + ac_cpp_err= + fi +else + ac_cpp_err=yes +fi +if test -z "$ac_cpp_err"; then + ac_header_preproc=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_header_preproc=no +fi +rm -f conftest.err conftest.$ac_ext +echo "$as_me:$LINENO: result: $ac_header_preproc" >&5 +echo "${ECHO_T}$ac_header_preproc" >&6 + +# So? What about this header? +case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in + yes:no: ) + { echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5 +echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5 +echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;} + ac_header_preproc=yes + ;; + no:yes:* ) + { echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5 +echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: check for missing prerequisite headers?" >&5 +echo "$as_me: WARNING: $ac_header: check for missing prerequisite headers?" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5 +echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&5 +echo "$as_me: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5 +echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5 +echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;} + ( + cat <<\_ASBOX +@%:@@%:@ ------------------------------------------ @%:@@%:@ +@%:@@%:@ Report this to the AC_PACKAGE_NAME lists. @%:@@%:@ +@%:@@%:@ ------------------------------------------ @%:@@%:@ +_ASBOX + ) | + sed "s/^/$as_me: WARNING: /" >&2 + ;; +esac +echo "$as_me:$LINENO: checking for $ac_header" >&5 +echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6 +if eval "test \"\${$as_ac_Header+set}\" = set"; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + eval "$as_ac_Header=\$ac_header_preproc" +fi +echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5 +echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6 + +fi +if test `eval echo '${'$as_ac_Header'}'` = yes; then + cat >>confdefs.h <<_ACEOF +@%:@define `echo "HAVE_$ac_header" | $as_tr_cpp` 1 +_ACEOF + +fi + +done + +if test x"$ac_cv_header_sys_ioctl_h" = xyes; then + HAVE_SYS_IOCTL_H_DEFINE=1 +else + HAVE_SYS_IOCTL_H_DEFINE=0 +fi + + + + +for ac_header in stdarg.h +do +as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh` +if eval "test \"\${$as_ac_Header+set}\" = set"; then + echo "$as_me:$LINENO: checking for $ac_header" >&5 +echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6 +if eval "test \"\${$as_ac_Header+set}\" = set"; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +fi +echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5 +echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6 +else + # Is the header compilable? +echo "$as_me:$LINENO: checking $ac_header usability" >&5 +echo $ECHO_N "checking $ac_header usability... $ECHO_C" >&6 +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +@%:@include <$ac_header> +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_header_compiler=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_header_compiler=no +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +echo "$as_me:$LINENO: result: $ac_header_compiler" >&5 +echo "${ECHO_T}$ac_header_compiler" >&6 + +# Is the header present? +echo "$as_me:$LINENO: checking $ac_header presence" >&5 +echo $ECHO_N "checking $ac_header presence... $ECHO_C" >&6 +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +@%:@include <$ac_header> +_ACEOF +if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 + (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null; then + if test -s conftest.err; then + ac_cpp_err=$ac_c_preproc_warn_flag + ac_cpp_err=$ac_cpp_err$ac_c_werror_flag + else + ac_cpp_err= + fi +else + ac_cpp_err=yes +fi +if test -z "$ac_cpp_err"; then + ac_header_preproc=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_header_preproc=no +fi +rm -f conftest.err conftest.$ac_ext +echo "$as_me:$LINENO: result: $ac_header_preproc" >&5 +echo "${ECHO_T}$ac_header_preproc" >&6 + +# So? What about this header? +case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in + yes:no: ) + { echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5 +echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5 +echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;} + ac_header_preproc=yes + ;; + no:yes:* ) + { echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5 +echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: check for missing prerequisite headers?" >&5 +echo "$as_me: WARNING: $ac_header: check for missing prerequisite headers?" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5 +echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&5 +echo "$as_me: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5 +echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5 +echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;} + ( + cat <<\_ASBOX +@%:@@%:@ ------------------------------------------ @%:@@%:@ +@%:@@%:@ Report this to the AC_PACKAGE_NAME lists. @%:@@%:@ +@%:@@%:@ ------------------------------------------ @%:@@%:@ +_ASBOX + ) | + sed "s/^/$as_me: WARNING: /" >&2 + ;; +esac +echo "$as_me:$LINENO: checking for $ac_header" >&5 +echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6 +if eval "test \"\${$as_ac_Header+set}\" = set"; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + eval "$as_ac_Header=\$ac_header_preproc" +fi +echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5 +echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6 + +fi +if test `eval echo '${'$as_ac_Header'}'` = yes; then + cat >>confdefs.h <<_ACEOF +@%:@define `echo "HAVE_$ac_header" | $as_tr_cpp` 1 +_ACEOF + +else + +{ { echo "$as_me:$LINENO: error: stdarg.h is required to build this library" >&5 +echo "$as_me: error: stdarg.h is required to build this library" >&2;} + { (exit 1); exit 1; }; } + +fi + +done + + + + +echo "$as_me:$LINENO: checking for size_t" >&5 +echo $ECHO_N "checking for size_t... $ECHO_C" >&6 +if test "${ac_cv_type_size_t+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +int +main () +{ +if ((size_t *) 0) + return 0; +if (sizeof (size_t)) + return 0; + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_type_size_t=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_cv_type_size_t=no +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +fi +echo "$as_me:$LINENO: result: $ac_cv_type_size_t" >&5 +echo "${ECHO_T}$ac_cv_type_size_t" >&6 +if test $ac_cv_type_size_t = yes; then + : +else + +cat >>confdefs.h <<_ACEOF +@%:@define size_t unsigned +_ACEOF + +fi + + +va_list_is_array=no +echo "$as_me:$LINENO: checking whether va_list is an array" >&5 +echo $ECHO_N "checking whether va_list is an array... $ECHO_C" >&6 +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +#include + +int +main () +{ +va_list list1, list2; list1 = list2; + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + : +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +va_list_is_array=yes +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +echo "$as_me:$LINENO: result: $va_list_is_array" >&5 +echo "${ECHO_T}$va_list_is_array" >&6 +if test x"$va_list_is_array" = xyes; then + VA_LIST_IS_ARRAY_DEFINE=1 +else + VA_LIST_IS_ARRAY_DEFINE=0 +fi + + +echo "$as_me:$LINENO: checking whether compiler has __attribute__" >&5 +echo $ECHO_N "checking whether compiler has __attribute__... $ECHO_C" >&6 +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ +int x __attribute__((__unused__)); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + compiler_has_attribute=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +compiler_has_attribute=no +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +echo "$as_me:$LINENO: result: $compiler_has_attribute" >&5 +echo "${ECHO_T}$compiler_has_attribute" >&6 +if test x"$compiler_has_attribute" = xyes; then + ATTR_UNUSED="__attribute__((__unused__))" +else + ATTR_UNUSED= +fi + + + + +echo "$as_me:$LINENO: checking for vsnprintf" >&5 +echo $ECHO_N "checking for vsnprintf... $ECHO_C" >&6 +if test "${ac_cv_func_vsnprintf+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +/* Define vsnprintf to an innocuous variant, in case declares vsnprintf. + For example, HP-UX 11i declares gettimeofday. */ +#define vsnprintf innocuous_vsnprintf + +/* System header to define __stub macros and hopefully few prototypes, + which can conflict with char vsnprintf (); below. + Prefer to if __STDC__ is defined, since + exists even on freestanding compilers. */ + +#ifdef __STDC__ +# include +#else +# include +#endif + +#undef vsnprintf + +/* Override any gcc2 internal prototype to avoid an error. */ +#ifdef __cplusplus +extern "C" +{ +#endif +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char vsnprintf (); +/* 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_vsnprintf) || defined (__stub___vsnprintf) +choke me +#else +char (*f) () = vsnprintf; +#endif +#ifdef __cplusplus +} +#endif + +int +main () +{ +return f != vsnprintf; + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_func_vsnprintf=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_cv_func_vsnprintf=no +fi +rm -f conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +fi +echo "$as_me:$LINENO: result: $ac_cv_func_vsnprintf" >&5 +echo "${ECHO_T}$ac_cv_func_vsnprintf" >&6 +if test $ac_cv_func_vsnprintf = yes; then + : +else + +{ { echo "$as_me:$LINENO: error: your C library does not provide vsnprintf" >&5 +echo "$as_me: error: your C library does not provide vsnprintf" >&2;} + { (exit 1); exit 1; }; } + +fi + + + +for ac_func in wcsncmp +do +as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh` +echo "$as_me:$LINENO: checking for $ac_func" >&5 +echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6 +if eval "test \"\${$as_ac_var+set}\" = set"; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +/* Define $ac_func to an innocuous variant, in case declares $ac_func. + For example, HP-UX 11i 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 to if __STDC__ is defined, since + exists even on freestanding compilers. */ + +#ifdef __STDC__ +# include +#else +# include +#endif + +#undef $ac_func + +/* Override any gcc2 internal prototype to avoid an error. */ +#ifdef __cplusplus +extern "C" +{ +#endif +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char $ac_func (); +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined (__stub_$ac_func) || defined (__stub___$ac_func) +choke me +#else +char (*f) () = $ac_func; +#endif +#ifdef __cplusplus +} +#endif + +int +main () +{ +return f != $ac_func; + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + eval "$as_ac_var=yes" +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +eval "$as_ac_var=no" +fi +rm -f conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +fi +echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_var'}'`" >&5 +echo "${ECHO_T}`eval echo '${'$as_ac_var'}'`" >&6 +if test `eval echo '${'$as_ac_var'}'` = yes; then + cat >>confdefs.h <<_ACEOF +@%:@define `echo "HAVE_$ac_func" | $as_tr_cpp` 1 +_ACEOF + +fi +done + + + +for ac_func in setgroups +do +as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh` +echo "$as_me:$LINENO: checking for $ac_func" >&5 +echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6 +if eval "test \"\${$as_ac_var+set}\" = set"; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +/* Define $ac_func to an innocuous variant, in case declares $ac_func. + For example, HP-UX 11i 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 to if __STDC__ is defined, since + exists even on freestanding compilers. */ + +#ifdef __STDC__ +# include +#else +# include +#endif + +#undef $ac_func + +/* Override any gcc2 internal prototype to avoid an error. */ +#ifdef __cplusplus +extern "C" +{ +#endif +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char $ac_func (); +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined (__stub_$ac_func) || defined (__stub___$ac_func) +choke me +#else +char (*f) () = $ac_func; +#endif +#ifdef __cplusplus +} +#endif + +int +main () +{ +return f != $ac_func; + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + eval "$as_ac_var=yes" +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +eval "$as_ac_var=no" +fi +rm -f conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +fi +echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_var'}'`" >&5 +echo "${ECHO_T}`eval echo '${'$as_ac_var'}'`" >&6 +if test `eval echo '${'$as_ac_var'}'` = yes; then + cat >>confdefs.h <<_ACEOF +@%:@define `echo "HAVE_$ac_func" | $as_tr_cpp` 1 +_ACEOF + +fi +done + + + +for ac_func in asprintf +do +as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh` +echo "$as_me:$LINENO: checking for $ac_func" >&5 +echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6 +if eval "test \"\${$as_ac_var+set}\" = set"; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +/* Define $ac_func to an innocuous variant, in case declares $ac_func. + For example, HP-UX 11i 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 to if __STDC__ is defined, since + exists even on freestanding compilers. */ + +#ifdef __STDC__ +# include +#else +# include +#endif + +#undef $ac_func + +/* Override any gcc2 internal prototype to avoid an error. */ +#ifdef __cplusplus +extern "C" +{ +#endif +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char $ac_func (); +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined (__stub_$ac_func) || defined (__stub___$ac_func) +choke me +#else +char (*f) () = $ac_func; +#endif +#ifdef __cplusplus +} +#endif + +int +main () +{ +return f != $ac_func; + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + eval "$as_ac_var=yes" +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +eval "$as_ac_var=no" +fi +rm -f conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +fi +echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_var'}'`" >&5 +echo "${ECHO_T}`eval echo '${'$as_ac_var'}'`" >&6 +if test `eval echo '${'$as_ac_var'}'` = yes; then + cat >>confdefs.h <<_ACEOF +@%:@define `echo "HAVE_$ac_func" | $as_tr_cpp` 1 +_ACEOF + +fi +done + + + +for ac_func in setenv +do +as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh` +echo "$as_me:$LINENO: checking for $ac_func" >&5 +echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6 +if eval "test \"\${$as_ac_var+set}\" = set"; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +/* Define $ac_func to an innocuous variant, in case declares $ac_func. + For example, HP-UX 11i 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 to if __STDC__ is defined, since + exists even on freestanding compilers. */ + +#ifdef __STDC__ +# include +#else +# include +#endif + +#undef $ac_func + +/* Override any gcc2 internal prototype to avoid an error. */ +#ifdef __cplusplus +extern "C" +{ +#endif +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char $ac_func (); +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined (__stub_$ac_func) || defined (__stub___$ac_func) +choke me +#else +char (*f) () = $ac_func; +#endif +#ifdef __cplusplus +} +#endif + +int +main () +{ +return f != $ac_func; + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + eval "$as_ac_var=yes" +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +eval "$as_ac_var=no" +fi +rm -f conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +fi +echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_var'}'`" >&5 +echo "${ECHO_T}`eval echo '${'$as_ac_var'}'`" >&6 +if test `eval echo '${'$as_ac_var'}'` = yes; then + cat >>confdefs.h <<_ACEOF +@%:@define `echo "HAVE_$ac_func" | $as_tr_cpp` 1 +_ACEOF + +fi +done + + + + +DIRECTORY_SEPARATOR="/" + + + + +echo "$as_me:$LINENO: checking whether to use Abyss pthread function" >&5 +echo $ECHO_N "checking whether to use Abyss pthread function... $ECHO_C" >&6 +# Check whether --enable-abyss-threads or --disable-abyss-threads was given. +if test "${enable_abyss_threads+set}" = set; then + enableval="$enable_abyss_threads" + +else + enable_abyss_threads=yes +fi; +echo "$as_me:$LINENO: result: $enable_abyss_threads" >&5 +echo "${ECHO_T}$enable_abyss_threads" >&6 + +ENABLE_ABYSS_THREADS=$enable_abyss_threads + + +if test x"$enable_abyss_threads" != xno; then + CFLAGS="$CFLAGS -D_THREAD" +fi + + + +if test $MUST_BUILD_WININET_CLIENT = yes; then + + for ac_prog in wininet-xmlrpc-config wininet-config +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_path_WININET_CONFIG+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + case $WININET_CONFIG in + [\\/]* | ?:[\\/]*) + ac_cv_path_WININET_CONFIG="$WININET_CONFIG" # Let the user override the test with a path. + ;; + *) + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_path_WININET_CONFIG="$as_dir/$ac_word$ac_exec_ext" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + + ;; +esac +fi +WININET_CONFIG=$ac_cv_path_WININET_CONFIG + +if test -n "$WININET_CONFIG"; then + echo "$as_me:$LINENO: result: $WININET_CONFIG" >&5 +echo "${ECHO_T}$WININET_CONFIG" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + + test -n "$WININET_CONFIG" && break +done +test -n "$WININET_CONFIG" || WININET_CONFIG="no" + + if test "x$WININET_CONFIG" = "xno"; then + { { echo "$as_me:$LINENO: error: wininet lib not found; see './configure --help'" >&5 +echo "$as_me: error: wininet lib not found; see './configure --help'" >&2;} + { (exit 1); exit 1; }; } + fi + + echo "$as_me:$LINENO: checking for wininet version >= 1.0.0" >&5 +echo $ECHO_N "checking for wininet version >= 1.0.0... $ECHO_C" >&6 + W3VER=`$WININET_CONFIG --version` + WININET_MAJOR=\ +`echo $W3VER|sed 's/\([0-9]*\)\.\([0-9]*\)\.\([0-9]*\)/\1/'` + WININET_MINOR=\ +`echo $W3VER|sed 's/\([0-9]*\)\.\([0-9]*\)\.\([0-9]*\)/\2/'` + WININET_MICRO=\ +`echo $W3VER|sed 's/\([0-9]*\)\.\([0-9]*\)\.\([0-9]*\)/\3/'` + echo "$as_me:$LINENO: result: $WININET_MAJOR.$WININET_MINOR.$WININET_MICRO" >&5 +echo "${ECHO_T}$WININET_MAJOR.$WININET_MINOR.$WININET_MICRO" >&6 + + WININET_VERSION_OK=yes + if test $WININET_MAJOR -lt 1; then + WININET_VERSION_OK=no + else + if test $WININET_MAJOR -eq 1 -a $WININET_MINOR -lt 0; then + WININET_VERSION_OK=no + else + if test $WININET_MAJOR -eq 1 -a $WININET_MINOR -eq 0 \ + -a $WININET_MICRO -lt 0; then + WININET_VERSION_OK=no + fi + fi + fi + if test "x$WININET_VERSION_OK" = "xno"; then + { { echo "$as_me:$LINENO: error: wininet version >= 1.0.0 required" >&5 +echo "$as_me: error: wininet version >= 1.0.0 required" >&2;} + { (exit 1); exit 1; }; } + fi + + WININET_CFLAGS="`$WININET_CONFIG --cflags`" + + CFLAGS="$CFLAGS $WININET_CFLAGS" + + WININET_LDADD="`$WININET_CONFIG --libs`" + + + echo "$as_me:$LINENO: checking for wininet library directory" >&5 +echo $ECHO_N "checking for wininet library directory... $ECHO_C" >&6 + if $WININET_CONFIG --rpath-dir > /dev/null 2>&1; then + WININET_LIBDIR="`$WININET_CONFIG --rpath-dir`" + else + WININET_LIBDIR="`$WININET_CONFIG --prefix`/lib" + fi + echo "$as_me:$LINENO: result: $WININET_LIBDIR" >&5 +echo "${ECHO_T}$WININET_LIBDIR" >&6 + + WININET_RPATH="-rpath $WININET_LIBDIR" + + WININET_WL_RPATH="-Wl,--rpath -Wl,$WININET_LIBDIR" + + +fi # MUST_BUILD_WININET_CLIENT + + +if test $MUST_BUILD_LIBWWW_CLIENT = yes; then + + for ac_prog in libwww-xmlrpc-config libwww-config +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_path_LIBWWW_CONFIG+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + case $LIBWWW_CONFIG in + [\\/]* | ?:[\\/]*) + ac_cv_path_LIBWWW_CONFIG="$LIBWWW_CONFIG" # Let the user override the test with a path. + ;; + *) + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_path_LIBWWW_CONFIG="$as_dir/$ac_word$ac_exec_ext" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + + ;; +esac +fi +LIBWWW_CONFIG=$ac_cv_path_LIBWWW_CONFIG + +if test -n "$LIBWWW_CONFIG"; then + echo "$as_me:$LINENO: result: $LIBWWW_CONFIG" >&5 +echo "${ECHO_T}$LIBWWW_CONFIG" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + + test -n "$LIBWWW_CONFIG" && break +done +test -n "$LIBWWW_CONFIG" || LIBWWW_CONFIG="no" + + if test "x$LIBWWW_CONFIG" = "xno"; then + { { echo "$as_me:$LINENO: error: w3c-libwww not found; see './configure --help'" >&5 +echo "$as_me: error: w3c-libwww not found; see './configure --help'" >&2;} + { (exit 1); exit 1; }; } + fi + + echo "$as_me:$LINENO: checking for w3c-libwww version >= 5.2.8" >&5 +echo $ECHO_N "checking for w3c-libwww version >= 5.2.8... $ECHO_C" >&6 + W3VER=`$LIBWWW_CONFIG --version` + LIBWWW_MAJOR=\ +`echo $W3VER|sed 's/\([0-9]*\)\.\([0-9]*\)\.\([0-9]*\)/\1/'` + LIBWWW_MINOR=\ +`echo $W3VER|sed 's/\([0-9]*\)\.\([0-9]*\)\.\([0-9]*\)/\2/'` + LIBWWW_MICRO=\ +`echo $W3VER|sed 's/\([0-9]*\)\.\([0-9]*\)\.\([0-9]*\)/\3/'` + echo "$as_me:$LINENO: result: $LIBWWW_MAJOR.$LIBWWW_MINOR.$LIBWWW_MICRO" >&5 +echo "${ECHO_T}$LIBWWW_MAJOR.$LIBWWW_MINOR.$LIBWWW_MICRO" >&6 + + LIBWWW_VERSION_OK=yes + if test $LIBWWW_MAJOR -lt 5; then + LIBWWW_VERSION_OK=no + else + if test $LIBWWW_MAJOR -eq 5 -a $LIBWWW_MINOR -lt 2; then + LIBWWW_VERSION_OK=no + else + if test $LIBWWW_MAJOR -eq 5 -a $LIBWWW_MINOR -eq 2 \ + -a $LIBWWW_MICRO -lt 8; then + LIBWWW_VERSION_OK=no + fi + fi + fi + if test "x$LIBWWW_VERSION_OK" = "xno"; then + { { echo "$as_me:$LINENO: error: w3c-libwww version >= 5.2.8 required" >&5 +echo "$as_me: error: w3c-libwww version >= 5.2.8 required" >&2;} + { (exit 1); exit 1; }; } + fi + + LIBWWW_LDADD="`$LIBWWW_CONFIG --libs`" + + + echo "$as_me:$LINENO: checking for libwww library directory" >&5 +echo $ECHO_N "checking for libwww library directory... $ECHO_C" >&6 + if $LIBWWW_CONFIG --rpath-dir > /dev/null 2>&1; then + LIBWWW_LIBDIR="`$LIBWWW_CONFIG --rpath-dir`" + else + LIBWWW_LIBDIR="`$LIBWWW_CONFIG --prefix`/lib" + fi + echo "$as_me:$LINENO: result: $LIBWWW_LIBDIR" >&5 +echo "${ECHO_T}$LIBWWW_LIBDIR" >&6 + + + # Some ancient rpath stuff, now disabled. I turned this off because it + # breaks Debian (and Mandrake?) policy, and we don't use it anymore. + # If you have multiple copies of w3c-libwww lying around, you can turn + # it back on. + #LIBWWW_RPATH="-rpath $LIBWWW_LIBDIR" + LIBWWW_RPATH="" + + #LIBWWW_WL_RPATH="-Wl,--rpath -Wl,$LIBWWW_LIBDIR" + LIBWWW_WL_RPATH="" + + +fi # MUST_BUILD_LIBWWW_CLIENT + + + +if test $MUST_BUILD_CURL_CLIENT = yes; then + + for ac_prog in curl-xmlrpc-config curl-config +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_path_CURL_CONFIG+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + case $CURL_CONFIG in + [\\/]* | ?:[\\/]*) + ac_cv_path_CURL_CONFIG="$CURL_CONFIG" # Let the user override the test with a path. + ;; + *) + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_path_CURL_CONFIG="$as_dir/$ac_word$ac_exec_ext" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + + ;; +esac +fi +CURL_CONFIG=$ac_cv_path_CURL_CONFIG + +if test -n "$CURL_CONFIG"; then + echo "$as_me:$LINENO: result: $CURL_CONFIG" >&5 +echo "${ECHO_T}$CURL_CONFIG" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + + test -n "$CURL_CONFIG" && break +done +test -n "$CURL_CONFIG" || CURL_CONFIG="no" + + if test "x$CURL_CONFIG" = "xno"; then + { { echo "$as_me:$LINENO: error: cURL not found; see './configure --help'" >&5 +echo "$as_me: error: cURL not found; see './configure --help'" >&2;} + { (exit 1); exit 1; }; } + fi + + + CURL_LDADD=`$CURL_CONFIG --libs` + + + echo "$as_me:$LINENO: checking for curl library directory" >&5 +echo $ECHO_N "checking for curl library directory... $ECHO_C" >&6 + CURL_LIBDIR="`$CURL_CONFIG --prefix`/lib" + + echo "$as_me:$LINENO: result: $CURL_LIBDIR" >&5 +echo "${ECHO_T}$CURL_LIBDIR" >&6 + + CURL_RPATH="-rpath $CURL_LIBDIR" + + CURL_WL_RPATH="-Wl,--rpath -Wl,$CURL_LIBDIR" + + +fi # MUST_BUILD_CURL_CLIENT + + + + +# Check whether --with-libwww-ssl or --without-libwww-ssl was given. +if test "${with_libwww_ssl+set}" = set; then + withval="$with_libwww_ssl" + +fi; + +if test x"$enable_libwww_client" != xno; then + echo "$as_me:$LINENO: checking whether to use SSL with libwww" >&5 +echo $ECHO_N "checking whether to use SSL with libwww... $ECHO_C" >&6 + if test x"$with_libwww_ssl" = xyes; then + echo "$as_me:$LINENO: result: yes" >&5 +echo "${ECHO_T}yes" >&6 + HAVE_LIBWWW_SSL_DEFINE=1 + else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 + HAVE_LIBWWW_SSL_DEFINE=0 + fi +fi + + +# Check whether --enable-libxml2-backend or --disable-libxml2-backend was given. +if test "${enable_libxml2_backend+set}" = set; then + enableval="$enable_libxml2_backend" + +else + enable_libxml2_backend=no +fi; +echo "$as_me:$LINENO: checking whether to build the libxml2 backend" >&5 +echo $ECHO_N "checking whether to build the libxml2 backend... $ECHO_C" >&6 +echo "$as_me:$LINENO: result: $enable_libxml2_backend" >&5 +echo "${ECHO_T}$enable_libxml2_backend" >&6 + +if test $enable_libxml2_backend = yes; then + # Extract the first word of "xml2-config", so it can be a program name with args. +set dummy xml2-config; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_have_xml2_config+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$have_xml2_config"; then + ac_cv_prog_have_xml2_config="$have_xml2_config" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_have_xml2_config="yes" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + + test -z "$ac_cv_prog_have_xml2_config" && ac_cv_prog_have_xml2_config="no" +fi +fi +have_xml2_config=$ac_cv_prog_have_xml2_config +if test -n "$have_xml2_config"; then + echo "$as_me:$LINENO: result: $have_xml2_config" >&5 +echo "${ECHO_T}$have_xml2_config" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + + if test $have_xml2_config = no; then + { { echo "$as_me:$LINENO: error: You specified --enable-libxml2_backend, but don't appear to have libxml2 installed (no working xml2-config inyour command search path), so we cannot not build for libxml2" >&5 +echo "$as_me: error: You specified --enable-libxml2_backend, but don't appear to have libxml2 installed (no working xml2-config inyour command search path), so we cannot not build for libxml2" >&2;} + { (exit 1); exit 1; }; } + fi +fi +ENABLE_LIBXML2_BACKEND=$enable_libxml2_backend + + +C_COMPILER_GNU=$ac_cv_c_compiler_gnu + +CXX_COMPILER_GNU=$ac_cv_cxx_compiler_gnu + + +CC_WARN_FLAGS= + +CPP_WARN_FLAGS= + + + +BUILDDIR=`pwd` + + +# Check whether --enable-shared or --disable-shared was given. +if test "${enable_shared+set}" = set; then + enableval="$enable_shared" + p=${PACKAGE-default} +case "$enableval" in +yes) enable_shared=yes ;; +no) enable_shared=no ;; +*) + enable_shared=no + # Look at the argument we got. We use all the common list separators. + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}:," + for pkg in $enableval; do + if test "X$pkg" = "X$p"; then + enable_shared=yes + fi + done + IFS="$ac_save_ifs" + ;; +esac +else + enable_shared=yes +fi; +# Check whether --enable-static or --disable-static was given. +if test "${enable_static+set}" = set; then + enableval="$enable_static" + p=${PACKAGE-default} +case "$enableval" in +yes) enable_static=yes ;; +no) enable_static=no ;; +*) + enable_static=no + # Look at the argument we got. We use all the common list separators. + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}:," + for pkg in $enableval; do + if test "X$pkg" = "X$p"; then + enable_static=yes + fi + done + IFS="$ac_save_ifs" + ;; +esac +else + enable_static=yes +fi; +# Check whether --enable-fast-install or --disable-fast-install was given. +if test "${enable_fast_install+set}" = set; then + enableval="$enable_fast_install" + p=${PACKAGE-default} +case "$enableval" in +yes) enable_fast_install=yes ;; +no) enable_fast_install=no ;; +*) + enable_fast_install=no + # Look at the argument we got. We use all the common list separators. + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}:," + for pkg in $enableval; do + if test "X$pkg" = "X$p"; then + enable_fast_install=yes + fi + done + IFS="$ac_save_ifs" + ;; +esac +else + enable_fast_install=yes +fi; +if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}ranlib", so it can be a program name with args. +set dummy ${ac_tool_prefix}ranlib; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_RANLIB+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$RANLIB"; then + ac_cv_prog_RANLIB="$RANLIB" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_RANLIB="${ac_tool_prefix}ranlib" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + +fi +fi +RANLIB=$ac_cv_prog_RANLIB +if test -n "$RANLIB"; then + echo "$as_me:$LINENO: result: $RANLIB" >&5 +echo "${ECHO_T}$RANLIB" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + +fi +if test -z "$ac_cv_prog_RANLIB"; then + ac_ct_RANLIB=$RANLIB + # Extract the first word of "ranlib", so it can be a program name with args. +set dummy ranlib; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_ac_ct_RANLIB+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$ac_ct_RANLIB"; then + ac_cv_prog_ac_ct_RANLIB="$ac_ct_RANLIB" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_RANLIB="ranlib" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + + test -z "$ac_cv_prog_ac_ct_RANLIB" && ac_cv_prog_ac_ct_RANLIB=":" +fi +fi +ac_ct_RANLIB=$ac_cv_prog_ac_ct_RANLIB +if test -n "$ac_ct_RANLIB"; then + echo "$as_me:$LINENO: result: $ac_ct_RANLIB" >&5 +echo "${ECHO_T}$ac_ct_RANLIB" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + + RANLIB=$ac_ct_RANLIB +else + RANLIB="$ac_cv_prog_RANLIB" +fi + + +# Check whether --with-gnu-ld or --without-gnu-ld was given. +if test "${with_gnu_ld+set}" = set; then + withval="$with_gnu_ld" + test "$withval" = no || with_gnu_ld=yes +else + with_gnu_ld=no +fi; +ac_prog=ld +if test "$ac_cv_c_compiler_gnu" = yes; then + # Check if gcc -print-prog-name=ld gives a path. + echo "$as_me:$LINENO: checking for ld used by GCC" >&5 +echo $ECHO_N "checking for ld used by GCC... $ECHO_C" >&6 + ac_prog=`($CC -print-prog-name=ld) 2>&5` + case "$ac_prog" in + # Accept absolute paths. + [\\/]* | [A-Za-z]:[\\/]*) + re_direlt='/[^/][^/]*/\.\./' + # Canonicalize the path of ld + ac_prog=`echo $ac_prog| sed 's%\\\\%/%g'` + while echo $ac_prog | grep "$re_direlt" > /dev/null 2>&1; do + ac_prog=`echo $ac_prog| sed "s%$re_direlt%/%"` + done + test -z "$LD" && LD="$ac_prog" + ;; + "") + # If it fails, then pretend we aren't using GCC. + ac_prog=ld + ;; + *) + # If it is relative, then search for the first ld in PATH. + with_gnu_ld=unknown + ;; + esac +elif test "$with_gnu_ld" = yes; then + echo "$as_me:$LINENO: checking for GNU ld" >&5 +echo $ECHO_N "checking for GNU ld... $ECHO_C" >&6 +else + echo "$as_me:$LINENO: checking for non-GNU ld" >&5 +echo $ECHO_N "checking for non-GNU ld... $ECHO_C" >&6 +fi +if test "${ac_cv_path_LD+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -z "$LD"; then + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}${PATH_SEPARATOR-:}" + for ac_dir in $PATH; do + test -z "$ac_dir" && ac_dir=. + if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then + ac_cv_path_LD="$ac_dir/$ac_prog" + # Check to see if the program is GNU ld. I'd rather use --version, + # but apparently some GNU ld's only accept -v. + # Break only if it was the GNU/non-GNU ld that we prefer. + if "$ac_cv_path_LD" -v 2>&1 < /dev/null | egrep '(GNU|with BFD)' > /dev/null; then + test "$with_gnu_ld" != no && break + else + test "$with_gnu_ld" != yes && break + fi + fi + done + IFS="$ac_save_ifs" +else + ac_cv_path_LD="$LD" # Let the user override the test with a path. +fi +fi + +LD="$ac_cv_path_LD" +if test -n "$LD"; then + echo "$as_me:$LINENO: result: $LD" >&5 +echo "${ECHO_T}$LD" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi +test -z "$LD" && { { echo "$as_me:$LINENO: error: no acceptable ld found in \$PATH" >&5 +echo "$as_me: error: no acceptable ld found in \$PATH" >&2;} + { (exit 1); exit 1; }; } +echo "$as_me:$LINENO: checking if the linker ($LD) is GNU ld" >&5 +echo $ECHO_N "checking if the linker ($LD) is GNU ld... $ECHO_C" >&6 +if test "${ac_cv_prog_gnu_ld+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + # I'd rather use --version here, but apparently some GNU ld's only accept -v. +if $LD -v 2>&1 &5; then + ac_cv_prog_gnu_ld=yes +else + ac_cv_prog_gnu_ld=no +fi +fi +echo "$as_me:$LINENO: result: $ac_cv_prog_gnu_ld" >&5 +echo "${ECHO_T}$ac_cv_prog_gnu_ld" >&6 + + +echo "$as_me:$LINENO: checking for BSD-compatible nm" >&5 +echo $ECHO_N "checking for BSD-compatible nm... $ECHO_C" >&6 +if test "${ac_cv_path_NM+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$NM"; then + # Let the user override the test. + ac_cv_path_NM="$NM" +else + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}${PATH_SEPARATOR-:}" + for ac_dir in $PATH /usr/ccs/bin /usr/ucb /bin; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/nm || test -f $ac_dir/nm$ac_exeext ; then + # Check to see if the nm accepts a BSD-compat flag. + # Adding the `sed 1q' prevents false positives on HP-UX, which says: + # nm: unknown option "B" ignored + if ($ac_dir/nm -B /dev/null 2>&1 | sed '1q'; exit 0) | egrep /dev/null >/dev/null; then + ac_cv_path_NM="$ac_dir/nm -B" + break + elif ($ac_dir/nm -p /dev/null 2>&1 | sed '1q'; exit 0) | egrep /dev/null >/dev/null; then + ac_cv_path_NM="$ac_dir/nm -p" + break + else + ac_cv_path_NM=${ac_cv_path_NM="$ac_dir/nm"} # keep the first match, but + continue # so that we can try to find one that supports BSD flags + fi + fi + done + IFS="$ac_save_ifs" + test -z "$ac_cv_path_NM" && ac_cv_path_NM=nm +fi +fi + +NM="$ac_cv_path_NM" +echo "$as_me:$LINENO: result: $NM" >&5 +echo "${ECHO_T}$NM" >&6 + +echo "$as_me:$LINENO: checking whether ln -s works" >&5 +echo $ECHO_N "checking whether ln -s works... $ECHO_C" >&6 +LN_S=$as_ln_s +if test "$LN_S" = "ln -s"; then + echo "$as_me:$LINENO: result: yes" >&5 +echo "${ECHO_T}yes" >&6 +else + echo "$as_me:$LINENO: result: no, using $LN_S" >&5 +echo "${ECHO_T}no, using $LN_S" >&6 +fi + + +case "$target" in +NONE) lt_target="$host" ;; +*) lt_target="$target" ;; +esac + +# Check for any special flags to pass to ltconfig. +# +# the following will cause an existing older ltconfig to fail, so +# we ignore this at the expense of the cache file... Checking this +# will just take longer ... bummer! +#libtool_flags="--cache-file=$cache_file" +# +test "$enable_shared" = no && libtool_flags="$libtool_flags --disable-shared" +test "$enable_static" = no && libtool_flags="$libtool_flags --disable-static" +test "$enable_fast_install" = no && libtool_flags="$libtool_flags --disable-fast-install" +test "$ac_cv_c_compiler_gnu" = yes && libtool_flags="$libtool_flags --with-gcc" +test "$ac_cv_prog_gnu_ld" = yes && libtool_flags="$libtool_flags --with-gnu-ld" + + +# Check whether --enable-libtool-lock or --disable-libtool-lock was given. +if test "${enable_libtool_lock+set}" = set; then + enableval="$enable_libtool_lock" + +fi; +test "x$enable_libtool_lock" = xno && libtool_flags="$libtool_flags --disable-lock" +test x"$silent" = xyes && libtool_flags="$libtool_flags --silent" + +# Some flags need to be propagated to the compiler or linker for good +# libtool support. +case "$lt_target" in +*-*-irix6*) + # Find out which ABI we are using. + echo '#line __oline__ "configure"' > conftest.$ac_ext + if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; then + case "`/usr/bin/file conftest.o`" in + *32-bit*) + LD="${LD-ld} -32" + ;; + *N32*) + LD="${LD-ld} -n32" + ;; + *64-bit*) + LD="${LD-ld} -64" + ;; + esac + fi + rm -rf conftest* + ;; + +*-*-sco3.2v5*) + # On SCO OpenServer 5, we need -belf to get full-featured binaries. + SAVE_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS -belf" + echo "$as_me:$LINENO: checking whether the C compiler needs -belf" >&5 +echo $ECHO_N "checking whether the C compiler needs -belf... $ECHO_C" >&6 +if test "${lt_cv_cc_needs_belf+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + lt_cv_cc_needs_belf=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +lt_cv_cc_needs_belf=no +fi +rm -f conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +fi +echo "$as_me:$LINENO: result: $lt_cv_cc_needs_belf" >&5 +echo "${ECHO_T}$lt_cv_cc_needs_belf" >&6 + if test x"$lt_cv_cc_needs_belf" != x"yes"; then + # this is probably gcc 2.8.0, egcs 1.0 or newer; no need for -belf + CFLAGS="$SAVE_CFLAGS" + fi + ;; + + +esac + + +# Save cache, so that ltconfig can load it +cat >confcache <<\_ACEOF +# This file is a shell script that caches the results of configure +# tests run on this system so they can be shared between configure +# scripts and configure runs, see configure's option --config-cache. +# It is not useful on other systems. If it contains results you don't +# want to keep, you may remove or edit it. +# +# config.status only pays attention to the cache file if you give it +# the --recheck option to rerun configure. +# +# `ac_cv_env_foo' variables (set or unset) will be overridden when +# loading this file, other *unset* `ac_cv_foo' will be assigned the +# following values. + +_ACEOF + +# The following way of writing the cache mishandles newlines in values, +# but we know of no workaround that is simple, portable, and efficient. +# So, don't put newlines in cache variables' values. +# Ultrix sh set writes to stderr and can't be redirected directly, +# and sets the high bit in the cache file unless we assign to the vars. +{ + (set) 2>&1 | + case `(ac_space=' '; set | grep ac_space) 2>&1` in + *ac_space=\ *) + # `set' does not quote correctly, so add quotes (double-quote + # substitution turns \\\\ into \\, and sed turns \\ into \). + sed -n \ + "s/'/'\\\\''/g; + s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p" + ;; + *) + # `set' quotes correctly as required by POSIX, so do not add quotes. + sed -n \ + "s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1=\\2/p" + ;; + esac; +} | + sed ' + t clear + : clear + s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/ + t end + /^ac_cv_env/!s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/ + : end' >>confcache +if diff $cache_file confcache >/dev/null 2>&1; then :; else + if test -w $cache_file; then + test "x$cache_file" != "x/dev/null" && echo "updating cache $cache_file" + cat confcache >$cache_file + else + echo "not updating unwritable cache $cache_file" + fi +fi +rm -f confcache + +# Actually configure libtool. ac_aux_dir is where install-sh is found. +CC="$CC" CFLAGS="$CFLAGS" CPPFLAGS="$CPPFLAGS" \ +LD="$LD" LDFLAGS="$LDFLAGS" LIBS="$LIBS" \ +LN_S="$LN_S" NM="$NM" RANLIB="$RANLIB" \ +DLLTOOL="$DLLTOOL" AS="$AS" OBJDUMP="$OBJDUMP" \ +${CONFIG_SHELL-/bin/sh} $ac_aux_dir/ltconfig --no-reexec \ +$libtool_flags --no-verify $ac_aux_dir/ltmain.sh $lt_target \ +|| { { echo "$as_me:$LINENO: error: libtool configure failed" >&5 +echo "$as_me: error: libtool configure failed" >&2;} + { (exit 1); exit 1; }; } + +# Reload cache, that may have been modified by ltconfig +if test -r "$cache_file"; then + # Some versions of bash will fail to source /dev/null (special + # files actually), so we avoid doing that. + if test -f "$cache_file"; then + { echo "$as_me:$LINENO: loading cache $cache_file" >&5 +echo "$as_me: loading cache $cache_file" >&6;} + case $cache_file in + [\\/]* | ?:[\\/]* ) . $cache_file;; + *) . ./$cache_file;; + esac + fi +else + { echo "$as_me:$LINENO: creating cache $cache_file" >&5 +echo "$as_me: creating cache $cache_file" >&6;} + >$cache_file +fi + + +# This can be used to rebuild libtool when needed +LIBTOOL_DEPS="$ac_aux_dir/ltconfig $ac_aux_dir/ltmain.sh" + +# Always use our own libtool. +LIBTOOL='$(SHELL) $(top_builddir)/libtool' + +# Redirect the config.log output again, so that the ltconfig log is not +# clobbered by the next message. +exec 5>>./config.log + + + + + + ac_config_files="$ac_config_files xmlrpc-c-config xmlrpc-c-config.test Makefile.config xmlrpc_config.h" +cat >confcache <<\_ACEOF +# This file is a shell script that caches the results of configure +# tests run on this system so they can be shared between configure +# scripts and configure runs, see configure's option --config-cache. +# It is not useful on other systems. If it contains results you don't +# want to keep, you may remove or edit it. +# +# config.status only pays attention to the cache file if you give it +# the --recheck option to rerun configure. +# +# `ac_cv_env_foo' variables (set or unset) will be overridden when +# loading this file, other *unset* `ac_cv_foo' will be assigned the +# following values. + +_ACEOF + +# The following way of writing the cache mishandles newlines in values, +# but we know of no workaround that is simple, portable, and efficient. +# So, don't put newlines in cache variables' values. +# Ultrix sh set writes to stderr and can't be redirected directly, +# and sets the high bit in the cache file unless we assign to the vars. +{ + (set) 2>&1 | + case `(ac_space=' '; set | grep ac_space) 2>&1` in + *ac_space=\ *) + # `set' does not quote correctly, so add quotes (double-quote + # substitution turns \\\\ into \\, and sed turns \\ into \). + sed -n \ + "s/'/'\\\\''/g; + s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p" + ;; + *) + # `set' quotes correctly as required by POSIX, so do not add quotes. + sed -n \ + "s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1=\\2/p" + ;; + esac; +} | + sed ' + t clear + : clear + s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/ + t end + /^ac_cv_env/!s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/ + : end' >>confcache +if diff $cache_file confcache >/dev/null 2>&1; then :; else + if test -w $cache_file; then + test "x$cache_file" != "x/dev/null" && echo "updating cache $cache_file" + cat confcache >$cache_file + else + echo "not updating unwritable cache $cache_file" + fi +fi +rm -f confcache + +test "x$prefix" = xNONE && prefix=$ac_default_prefix +# Let make expand exec_prefix. +test "x$exec_prefix" = xNONE && exec_prefix='${prefix}' + +# VPATH may cause trouble with some makes, so we remove $(srcdir), +# ${srcdir} and @srcdir@ from VPATH if srcdir is ".", strip leading and +# trailing colons and then remove the whole line if VPATH becomes empty +# (actually we leave an empty line to preserve line numbers). +if test "x$srcdir" = x.; then + ac_vpsub='/^[ ]*VPATH[ ]*=/{ +s/:*\$(srcdir):*/:/; +s/:*\${srcdir}:*/:/; +s/:*@srcdir@:*/:/; +s/^\([^=]*=[ ]*\):*/\1/; +s/:*$//; +s/^[^=]*=[ ]*$//; +}' +fi + +DEFS=-DHAVE_CONFIG_H + +ac_libobjs= +ac_ltlibobjs= +for ac_i in : $LIB@&t@OBJS; do test "x$ac_i" = x: && continue + # 1. Remove the extension, and $U if already installed. + ac_i=`echo "$ac_i" | + sed 's/\$U\././;s/\.o$//;s/\.obj$//'` + # 2. Add them. + ac_libobjs="$ac_libobjs $ac_i\$U.$ac_objext" + ac_ltlibobjs="$ac_ltlibobjs $ac_i"'$U.lo' +done +LIB@&t@OBJS=$ac_libobjs + +LTLIBOBJS=$ac_ltlibobjs + + + +: ${CONFIG_STATUS=./config.status} +ac_clean_files_save=$ac_clean_files +ac_clean_files="$ac_clean_files $CONFIG_STATUS" +{ echo "$as_me:$LINENO: creating $CONFIG_STATUS" >&5 +echo "$as_me: creating $CONFIG_STATUS" >&6;} +cat >$CONFIG_STATUS <<_ACEOF +#! $SHELL +# Generated by $as_me. +# Run this file to recreate the current configuration. +# Compiler output produced by configure, useful for debugging +# configure, is in config.log if it exists. + +debug=false +ac_cs_recheck=false +ac_cs_silent=false +SHELL=\${CONFIG_SHELL-$SHELL} +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF +## --------------------- ## +## M4sh Initialization. ## +## --------------------- ## + +# Be Bourne compatible +if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then + emulate sh + NULLCMD=: + # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which + # is contrary to our usage. Disable this feature. + alias -g '${1+"$@"}'='"$@"' +elif test -n "${BASH_VERSION+set}" && (set -o posix) >/dev/null 2>&1; then + set -o posix +fi +DUALCASE=1; export DUALCASE # for MKS sh + +# Support unset when possible. +if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then + as_unset=unset +else + as_unset=false +fi + + +# Work around bugs in pre-3.0 UWIN ksh. +$as_unset ENV MAIL MAILPATH +PS1='$ ' +PS2='> ' +PS4='+ ' + +# NLS nuisances. +for as_var in \ + LANG LANGUAGE LC_ADDRESS LC_ALL LC_COLLATE LC_CTYPE LC_IDENTIFICATION \ + LC_MEASUREMENT LC_MESSAGES LC_MONETARY LC_NAME LC_NUMERIC LC_PAPER \ + LC_TELEPHONE LC_TIME +do + if (set +x; test -z "`(eval $as_var=C; export $as_var) 2>&1`"); then + eval $as_var=C; export $as_var + else + $as_unset $as_var + fi +done + +# Required to use basename. +if expr a : '\(a\)' >/dev/null 2>&1; then + as_expr=expr +else + as_expr=false +fi + +if (basename /) >/dev/null 2>&1 && test "X`basename / 2>&1`" = "X/"; then + as_basename=basename +else + as_basename=false +fi + + +# Name of the executable. +as_me=`$as_basename "$0" || +$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ + X"$0" : 'X\(//\)$' \| \ + X"$0" : 'X\(/\)$' \| \ + . : '\(.\)' 2>/dev/null || +echo X/"$0" | + sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/; q; } + /^X\/\(\/\/\)$/{ s//\1/; q; } + /^X\/\(\/\).*/{ s//\1/; q; } + s/.*/./; q'` + + +# PATH needs CR, and LINENO needs CR and PATH. +# Avoid depending upon Character Ranges. +as_cr_letters='abcdefghijklmnopqrstuvwxyz' +as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' +as_cr_Letters=$as_cr_letters$as_cr_LETTERS +as_cr_digits='0123456789' +as_cr_alnum=$as_cr_Letters$as_cr_digits + +# The user is always right. +if test "${PATH_SEPARATOR+set}" != set; then + echo "#! /bin/sh" >conf$$.sh + echo "exit 0" >>conf$$.sh + chmod +x conf$$.sh + if (PATH="/nonexistent;."; conf$$.sh) >/dev/null 2>&1; then + PATH_SEPARATOR=';' + else + PATH_SEPARATOR=: + fi + rm -f conf$$.sh +fi + + + as_lineno_1=$LINENO + as_lineno_2=$LINENO + as_lineno_3=`(expr $as_lineno_1 + 1) 2>/dev/null` + test "x$as_lineno_1" != "x$as_lineno_2" && + test "x$as_lineno_3" = "x$as_lineno_2" || { + # Find who we are. Look in the path if we contain no path at all + # relative or not. + case $0 in + *[\\/]* ) as_myself=$0 ;; + *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break +done + + ;; + esac + # We did not find ourselves, most probably we were run as `sh COMMAND' + # in which case we are not to be found in the path. + if test "x$as_myself" = x; then + as_myself=$0 + fi + if test ! -f "$as_myself"; then + { { echo "$as_me:$LINENO: error: cannot find myself; rerun with an absolute path" >&5 +echo "$as_me: error: cannot find myself; rerun with an absolute path" >&2;} + { (exit 1); exit 1; }; } + fi + case $CONFIG_SHELL in + '') + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for as_base in sh bash ksh sh5; do + case $as_dir in + /*) + if ("$as_dir/$as_base" -c ' + as_lineno_1=$LINENO + as_lineno_2=$LINENO + as_lineno_3=`(expr $as_lineno_1 + 1) 2>/dev/null` + test "x$as_lineno_1" != "x$as_lineno_2" && + test "x$as_lineno_3" = "x$as_lineno_2" ') 2>/dev/null; then + $as_unset BASH_ENV || test "${BASH_ENV+set}" != set || { BASH_ENV=; export BASH_ENV; } + $as_unset ENV || test "${ENV+set}" != set || { ENV=; export ENV; } + CONFIG_SHELL=$as_dir/$as_base + export CONFIG_SHELL + exec "$CONFIG_SHELL" "$0" ${1+"$@"} + fi;; + esac + done +done +;; + esac + + # Create $as_me.lineno as a copy of $as_myself, but with $LINENO + # uniformly replaced by the line number. The first 'sed' inserts a + # line-number line before each line; the second 'sed' does the real + # work. The second script uses 'N' to pair each line-number line + # with the numbered line, and appends trailing '-' during + # substitution so that $LINENO is not a special case at line end. + # (Raja R Harinath suggested sed '=', and Paul Eggert wrote the + # second 'sed' script. Blame Lee E. McMahon for sed's syntax. :-) + sed '=' <$as_myself | + sed ' + N + s,$,-, + : loop + s,^\(['$as_cr_digits']*\)\(.*\)[$]LINENO\([^'$as_cr_alnum'_]\),\1\2\1\3, + t loop + s,-$,, + s,^['$as_cr_digits']*\n,, + ' >$as_me.lineno && + chmod +x $as_me.lineno || + { { echo "$as_me:$LINENO: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&5 +echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2;} + { (exit 1); exit 1; }; } + + # Don't try to exec as it changes $[0], causing all sort of problems + # (the dirname of $[0] is not the place where we might find the + # original and so on. Autoconf is especially sensible to this). + . ./$as_me.lineno + # Exit status is that of the last command. + exit +} + + +case `echo "testing\c"; echo 1,2,3`,`echo -n testing; echo 1,2,3` in + *c*,-n*) ECHO_N= ECHO_C=' +' ECHO_T=' ' ;; + *c*,* ) ECHO_N=-n ECHO_C= ECHO_T= ;; + *) ECHO_N= ECHO_C='\c' ECHO_T= ;; +esac + +if expr a : '\(a\)' >/dev/null 2>&1; then + as_expr=expr +else + as_expr=false +fi + +rm -f conf$$ conf$$.exe conf$$.file +echo >conf$$.file +if ln -s conf$$.file conf$$ 2>/dev/null; then + # We could just check for DJGPP; but this test a) works b) is more generic + # and c) will remain valid once DJGPP supports symlinks (DJGPP 2.04). + if test -f conf$$.exe; then + # Don't use ln at all; we don't have any links + as_ln_s='cp -p' + else + as_ln_s='ln -s' + fi +elif ln conf$$.file conf$$ 2>/dev/null; then + as_ln_s=ln +else + as_ln_s='cp -p' +fi +rm -f conf$$ conf$$.exe conf$$.file + +if mkdir -p . 2>/dev/null; then + as_mkdir_p=: +else + test -d ./-p && rmdir ./-p + as_mkdir_p=false +fi + +as_executable_p="test -f" + +# Sed expression to map a string onto a valid CPP name. +as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" + +# Sed expression to map a string onto a valid variable name. +as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" + + +# IFS +# We need space, tab and new line, in precisely that order. +as_nl=' +' +IFS=" $as_nl" + +# CDPATH. +$as_unset CDPATH + +exec 6>&1 + +# Open the log real soon, to keep \$[0] and so on meaningful, and to +# report actual input values of CONFIG_FILES etc. instead of their +# values after options handling. Logging --version etc. is OK. +exec 5>>config.log +{ + echo + sed 'h;s/./-/g;s/^.../@%:@@%:@ /;s/...$/ @%:@@%:@/;p;x;p;x' <<_ASBOX +@%:@@%:@ Running $as_me. @%:@@%:@ +_ASBOX +} >&5 +cat >&5 <<_CSEOF + +This file was extended by $as_me, which was +generated by GNU Autoconf 2.59. Invocation command line was + + CONFIG_FILES = $CONFIG_FILES + CONFIG_HEADERS = $CONFIG_HEADERS + CONFIG_LINKS = $CONFIG_LINKS + CONFIG_COMMANDS = $CONFIG_COMMANDS + $ $0 $@ + +_CSEOF +echo "on `(hostname || uname -n) 2>/dev/null | sed 1q`" >&5 +echo >&5 +_ACEOF + +# Files that config.status was made for. +if test -n "$ac_config_files"; then + echo "config_files=\"$ac_config_files\"" >>$CONFIG_STATUS +fi + +if test -n "$ac_config_headers"; then + echo "config_headers=\"$ac_config_headers\"" >>$CONFIG_STATUS +fi + +if test -n "$ac_config_links"; then + echo "config_links=\"$ac_config_links\"" >>$CONFIG_STATUS +fi + +if test -n "$ac_config_commands"; then + echo "config_commands=\"$ac_config_commands\"" >>$CONFIG_STATUS +fi + +cat >>$CONFIG_STATUS <<\_ACEOF + +ac_cs_usage="\ +\`$as_me' instantiates files from templates according to the +current configuration. + +Usage: $0 [OPTIONS] [FILE]... + + -h, --help print this help, then exit + -V, --version print version number, then exit + -q, --quiet do not print progress messages + -d, --debug don't remove temporary files + --recheck update $as_me by reconfiguring in the same conditions + --file=FILE[:TEMPLATE] + instantiate the configuration file FILE + --header=FILE[:TEMPLATE] + instantiate the configuration header FILE + +Configuration files: +$config_files + +Configuration headers: +$config_headers + +Configuration commands: +$config_commands + +Report bugs to ." +_ACEOF + +cat >>$CONFIG_STATUS <<_ACEOF +ac_cs_version="\\ +config.status +configured by $0, generated by GNU Autoconf 2.59, + with options \\"`echo "$ac_configure_args" | sed 's/[\\""\`\$]/\\\\&/g'`\\" + +Copyright (C) 2003 Free Software Foundation, Inc. +This config.status script is free software; the Free Software Foundation +gives unlimited permission to copy, distribute and modify it." +srcdir=$srcdir +INSTALL="$INSTALL" +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF +# If no file are specified by the user, then we need to provide default +# value. By we need to know if files were specified by the user. +ac_need_defaults=: +while test $# != 0 +do + case $1 in + --*=*) + ac_option=`expr "x$1" : 'x\([^=]*\)='` + ac_optarg=`expr "x$1" : 'x[^=]*=\(.*\)'` + ac_shift=: + ;; + -*) + ac_option=$1 + ac_optarg=$2 + ac_shift=shift + ;; + *) # This is not an option, so the user has probably given explicit + # arguments. + ac_option=$1 + ac_need_defaults=false;; + esac + + case $ac_option in + # Handling of the options. +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF + -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) + ac_cs_recheck=: ;; + --version | --vers* | -V ) + echo "$ac_cs_version"; exit 0 ;; + --he | --h) + # Conflict between --help and --header + { { echo "$as_me:$LINENO: error: ambiguous option: $1 +Try \`$0 --help' for more information." >&5 +echo "$as_me: error: ambiguous option: $1 +Try \`$0 --help' for more information." >&2;} + { (exit 1); exit 1; }; };; + --help | --hel | -h ) + echo "$ac_cs_usage"; exit 0 ;; + --debug | --d* | -d ) + debug=: ;; + --file | --fil | --fi | --f ) + $ac_shift + CONFIG_FILES="$CONFIG_FILES $ac_optarg" + ac_need_defaults=false;; + --header | --heade | --head | --hea ) + $ac_shift + CONFIG_HEADERS="$CONFIG_HEADERS $ac_optarg" + ac_need_defaults=false;; + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil | --si | --s) + ac_cs_silent=: ;; + + # This is an error. + -*) { { echo "$as_me:$LINENO: error: unrecognized option: $1 +Try \`$0 --help' for more information." >&5 +echo "$as_me: error: unrecognized option: $1 +Try \`$0 --help' for more information." >&2;} + { (exit 1); exit 1; }; } ;; + + *) ac_config_targets="$ac_config_targets $1" ;; + + esac + shift +done + +ac_configure_extra_args= + +if $ac_cs_silent; then + exec 6>/dev/null + ac_configure_extra_args="$ac_configure_extra_args --silent" +fi + +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF +if \$ac_cs_recheck; then + echo "running $SHELL $0 " $ac_configure_args \$ac_configure_extra_args " --no-create --no-recursion" >&6 + exec $SHELL $0 $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion +fi + +_ACEOF + +cat >>$CONFIG_STATUS <<_ACEOF +# +# INIT-COMMANDS section. +# + + + +_ACEOF + + + +cat >>$CONFIG_STATUS <<\_ACEOF +for ac_config_target in $ac_config_targets +do + case "$ac_config_target" in + # Handling of arguments. + "xmlrpc-c-config" ) CONFIG_FILES="$CONFIG_FILES xmlrpc-c-config" ;; + "xmlrpc-c-config.test" ) CONFIG_FILES="$CONFIG_FILES xmlrpc-c-config.test" ;; + "Makefile.config" ) CONFIG_FILES="$CONFIG_FILES Makefile.config" ;; + "xmlrpc_config.h" ) CONFIG_FILES="$CONFIG_FILES xmlrpc_config.h" ;; + "default-1" ) CONFIG_COMMANDS="$CONFIG_COMMANDS default-1" ;; + "xmlrpc_amconfig.h" ) CONFIG_HEADERS="$CONFIG_HEADERS xmlrpc_amconfig.h" ;; + *) { { echo "$as_me:$LINENO: error: invalid argument: $ac_config_target" >&5 +echo "$as_me: error: invalid argument: $ac_config_target" >&2;} + { (exit 1); exit 1; }; };; + esac +done + +# If the user did not use the arguments to specify the items to instantiate, +# then the envvar interface is used. Set only those that are not. +# We use the long form for the default assignment because of an extremely +# bizarre bug on SunOS 4.1.3. +if $ac_need_defaults; then + test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files + test "${CONFIG_HEADERS+set}" = set || CONFIG_HEADERS=$config_headers + test "${CONFIG_COMMANDS+set}" = set || CONFIG_COMMANDS=$config_commands +fi + +# Have a temporary directory for convenience. Make it in the build tree +# simply because there is no reason to put it here, and in addition, +# creating and moving files from /tmp can sometimes cause problems. +# Create a temporary directory, and hook for its removal unless debugging. +$debug || +{ + trap 'exit_status=$?; rm -rf $tmp && exit $exit_status' 0 + trap '{ (exit 1); exit 1; }' 1 2 13 15 +} + +# Create a (secure) tmp directory for tmp files. + +{ + tmp=`(umask 077 && mktemp -d -q "./confstatXXXXXX") 2>/dev/null` && + test -n "$tmp" && test -d "$tmp" +} || +{ + tmp=./confstat$$-$RANDOM + (umask 077 && mkdir $tmp) +} || +{ + echo "$me: cannot create a temporary directory in ." >&2 + { (exit 1); exit 1; } +} + +_ACEOF + +cat >>$CONFIG_STATUS <<_ACEOF + +# +# CONFIG_FILES section. +# + +# No need to generate the scripts if there are no CONFIG_FILES. +# This happens for instance when ./config.status config.h +if test -n "\$CONFIG_FILES"; then + # Protect against being on the right side of a sed subst in config.status. + sed 's/,@/@@/; s/@,/@@/; s/,;t t\$/@;t t/; /@;t t\$/s/[\\\\&,]/\\\\&/g; + s/@@/,@/; s/@@/@,/; s/@;t t\$/,;t t/' >\$tmp/subs.sed <<\\CEOF +s,@SHELL@,$SHELL,;t t +s,@PATH_SEPARATOR@,$PATH_SEPARATOR,;t t +s,@PACKAGE_NAME@,$PACKAGE_NAME,;t t +s,@PACKAGE_TARNAME@,$PACKAGE_TARNAME,;t t +s,@PACKAGE_VERSION@,$PACKAGE_VERSION,;t t +s,@PACKAGE_STRING@,$PACKAGE_STRING,;t t +s,@PACKAGE_BUGREPORT@,$PACKAGE_BUGREPORT,;t t +s,@exec_prefix@,$exec_prefix,;t t +s,@prefix@,$prefix,;t t +s,@program_transform_name@,$program_transform_name,;t t +s,@bindir@,$bindir,;t t +s,@sbindir@,$sbindir,;t t +s,@libexecdir@,$libexecdir,;t t +s,@datadir@,$datadir,;t t +s,@sysconfdir@,$sysconfdir,;t t +s,@sharedstatedir@,$sharedstatedir,;t t +s,@localstatedir@,$localstatedir,;t t +s,@libdir@,$libdir,;t t +s,@includedir@,$includedir,;t t +s,@oldincludedir@,$oldincludedir,;t t +s,@infodir@,$infodir,;t t +s,@mandir@,$mandir,;t t +s,@build_alias@,$build_alias,;t t +s,@host_alias@,$host_alias,;t t +s,@target_alias@,$target_alias,;t t +s,@DEFS@,$DEFS,;t t +s,@ECHO_C@,$ECHO_C,;t t +s,@ECHO_N@,$ECHO_N,;t t +s,@ECHO_T@,$ECHO_T,;t t +s,@LIBS@,$LIBS,;t t +s,@INSTALL_PROGRAM@,$INSTALL_PROGRAM,;t t +s,@INSTALL_SCRIPT@,$INSTALL_SCRIPT,;t t +s,@INSTALL_DATA@,$INSTALL_DATA,;t t +s,@PACKAGE@,$PACKAGE,;t t +s,@VERSION@,$VERSION,;t t +s,@ACLOCAL@,$ACLOCAL,;t t +s,@AUTOCONF@,$AUTOCONF,;t t +s,@AUTOMAKE@,$AUTOMAKE,;t t +s,@AUTOHEADER@,$AUTOHEADER,;t t +s,@MAKEINFO@,$MAKEINFO,;t t +s,@SET_MAKE@,$SET_MAKE,;t t +s,@VERSION_INFO@,$VERSION_INFO,;t t +s,@build@,$build,;t t +s,@build_cpu@,$build_cpu,;t t +s,@build_vendor@,$build_vendor,;t t +s,@build_os@,$build_os,;t t +s,@host@,$host,;t t +s,@host_cpu@,$host_cpu,;t t +s,@host_vendor@,$host_vendor,;t t +s,@host_os@,$host_os,;t t +s,@have_wininet_config@,$have_wininet_config,;t t +s,@MUST_BUILD_WININET_CLIENT@,$MUST_BUILD_WININET_CLIENT,;t t +s,@have_curl_config@,$have_curl_config,;t t +s,@MUST_BUILD_CURL_CLIENT@,$MUST_BUILD_CURL_CLIENT,;t t +s,@have_libwww_config@,$have_libwww_config,;t t +s,@MUST_BUILD_LIBWWW_CLIENT@,$MUST_BUILD_LIBWWW_CLIENT,;t t +s,@LIBXMLRPC_CLIENT_LA@,$LIBXMLRPC_CLIENT_LA,;t t +s,@CLIENTTEST@,$CLIENTTEST,;t t +s,@XMLRPC_CLIENT_H@,$XMLRPC_CLIENT_H,;t t +s,@XMLRPC_TRANSPORT_H@,$XMLRPC_TRANSPORT_H,;t t +s,@SYNCH_CLIENT@,$SYNCH_CLIENT,;t t +s,@ASYNCH_CLIENT@,$ASYNCH_CLIENT,;t t +s,@AUTH_CLIENT@,$AUTH_CLIENT,;t t +s,@QUERY_MEERKAT@,$QUERY_MEERKAT,;t t +s,@ENABLE_ABYSS_SERVER@,$ENABLE_ABYSS_SERVER,;t t +s,@ABYSS_SUBDIR@,$ABYSS_SUBDIR,;t t +s,@LIBXMLRPC_ABYSS_SERVER_LA@,$LIBXMLRPC_ABYSS_SERVER_LA,;t t +s,@SERVERTEST@,$SERVERTEST,;t t +s,@VALIDATEE@,$VALIDATEE,;t t +s,@XMLRPC_ABYSS_H@,$XMLRPC_ABYSS_H,;t t +s,@SERVER@,$SERVER,;t t +s,@ENABLE_CGI_SERVER@,$ENABLE_CGI_SERVER,;t t +s,@ENABLE_CPLUSPLUS@,$ENABLE_CPLUSPLUS,;t t +s,@LIBXMLRPC_CPP_A@,$LIBXMLRPC_CPP_A,;t t +s,@CPPTEST@,$CPPTEST,;t t +s,@XMLRPCCPP_H@,$XMLRPCCPP_H,;t t +s,@XML_RPC_API2CPP_SUBDIR@,$XML_RPC_API2CPP_SUBDIR,;t t +s,@FEATURE_LIST@,$FEATURE_LIST,;t t +s,@CC@,$CC,;t t +s,@CFLAGS@,$CFLAGS,;t t +s,@LDFLAGS@,$LDFLAGS,;t t +s,@CPPFLAGS@,$CPPFLAGS,;t t +s,@ac_ct_CC@,$ac_ct_CC,;t t +s,@EXEEXT@,$EXEEXT,;t t +s,@OBJEXT@,$OBJEXT,;t t +s,@CXX@,$CXX,;t t +s,@CXXFLAGS@,$CXXFLAGS,;t t +s,@ac_ct_CXX@,$ac_ct_CXX,;t t +s,@LSOCKET@,$LSOCKET,;t t +s,@CPP@,$CPP,;t t +s,@EGREP@,$EGREP,;t t +s,@HAVE_WCHAR_H_DEFINE@,$HAVE_WCHAR_H_DEFINE,;t t +s,@HAVE_SYS_FILIO_H_DEFINE@,$HAVE_SYS_FILIO_H_DEFINE,;t t +s,@HAVE_SYS_IOCTL_H_DEFINE@,$HAVE_SYS_IOCTL_H_DEFINE,;t t +s,@VA_LIST_IS_ARRAY_DEFINE@,$VA_LIST_IS_ARRAY_DEFINE,;t t +s,@ATTR_UNUSED@,$ATTR_UNUSED,;t t +s,@DIRECTORY_SEPARATOR@,$DIRECTORY_SEPARATOR,;t t +s,@ENABLE_ABYSS_THREADS@,$ENABLE_ABYSS_THREADS,;t t +s,@WININET_CONFIG@,$WININET_CONFIG,;t t +s,@WININET_CFLAGS@,$WININET_CFLAGS,;t t +s,@WININET_LDADD@,$WININET_LDADD,;t t +s,@WININET_LIBDIR@,$WININET_LIBDIR,;t t +s,@WININET_RPATH@,$WININET_RPATH,;t t +s,@WININET_WL_RPATH@,$WININET_WL_RPATH,;t t +s,@LIBWWW_CONFIG@,$LIBWWW_CONFIG,;t t +s,@LIBWWW_LDADD@,$LIBWWW_LDADD,;t t +s,@LIBWWW_LIBDIR@,$LIBWWW_LIBDIR,;t t +s,@LIBWWW_RPATH@,$LIBWWW_RPATH,;t t +s,@LIBWWW_WL_RPATH@,$LIBWWW_WL_RPATH,;t t +s,@CURL_CONFIG@,$CURL_CONFIG,;t t +s,@CURL_LDADD@,$CURL_LDADD,;t t +s,@CURL_LIBDIR@,$CURL_LIBDIR,;t t +s,@CURL_RPATH@,$CURL_RPATH,;t t +s,@CURL_WL_RPATH@,$CURL_WL_RPATH,;t t +s,@HAVE_LIBWWW_SSL_DEFINE@,$HAVE_LIBWWW_SSL_DEFINE,;t t +s,@have_xml2_config@,$have_xml2_config,;t t +s,@ENABLE_LIBXML2_BACKEND@,$ENABLE_LIBXML2_BACKEND,;t t +s,@C_COMPILER_GNU@,$C_COMPILER_GNU,;t t +s,@CXX_COMPILER_GNU@,$CXX_COMPILER_GNU,;t t +s,@CC_WARN_FLAGS@,$CC_WARN_FLAGS,;t t +s,@CPP_WARN_FLAGS@,$CPP_WARN_FLAGS,;t t +s,@BUILDDIR@,$BUILDDIR,;t t +s,@RANLIB@,$RANLIB,;t t +s,@ac_ct_RANLIB@,$ac_ct_RANLIB,;t t +s,@LN_S@,$LN_S,;t t +s,@LIBTOOL@,$LIBTOOL,;t t +s,@LIB@&t@OBJS@,$LIB@&t@OBJS,;t t +s,@LTLIBOBJS@,$LTLIBOBJS,;t t +CEOF + +_ACEOF + + cat >>$CONFIG_STATUS <<\_ACEOF + # Split the substitutions into bite-sized pieces for seds with + # small command number limits, like on Digital OSF/1 and HP-UX. + ac_max_sed_lines=48 + ac_sed_frag=1 # Number of current file. + ac_beg=1 # First line for current file. + ac_end=$ac_max_sed_lines # Line after last line for current file. + ac_more_lines=: + ac_sed_cmds= + while $ac_more_lines; do + if test $ac_beg -gt 1; then + sed "1,${ac_beg}d; ${ac_end}q" $tmp/subs.sed >$tmp/subs.frag + else + sed "${ac_end}q" $tmp/subs.sed >$tmp/subs.frag + fi + if test ! -s $tmp/subs.frag; then + ac_more_lines=false + else + # The purpose of the label and of the branching condition is to + # speed up the sed processing (if there are no `@' at all, there + # is no need to browse any of the substitutions). + # These are the two extra sed commands mentioned above. + (echo ':t + /@[a-zA-Z_][a-zA-Z_0-9]*@/!b' && cat $tmp/subs.frag) >$tmp/subs-$ac_sed_frag.sed + if test -z "$ac_sed_cmds"; then + ac_sed_cmds="sed -f $tmp/subs-$ac_sed_frag.sed" + else + ac_sed_cmds="$ac_sed_cmds | sed -f $tmp/subs-$ac_sed_frag.sed" + fi + ac_sed_frag=`expr $ac_sed_frag + 1` + ac_beg=$ac_end + ac_end=`expr $ac_end + $ac_max_sed_lines` + fi + done + if test -z "$ac_sed_cmds"; then + ac_sed_cmds=cat + fi +fi # test -n "$CONFIG_FILES" + +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF +for ac_file in : $CONFIG_FILES; do test "x$ac_file" = x: && continue + # Support "outfile[:infile[:infile...]]", defaulting infile="outfile.in". + case $ac_file in + - | *:- | *:-:* ) # input from stdin + cat >$tmp/stdin + ac_file_in=`echo "$ac_file" | sed 's,[^:]*:,,'` + ac_file=`echo "$ac_file" | sed 's,:.*,,'` ;; + *:* ) ac_file_in=`echo "$ac_file" | sed 's,[^:]*:,,'` + ac_file=`echo "$ac_file" | sed 's,:.*,,'` ;; + * ) ac_file_in=$ac_file.in ;; + esac + + # Compute @srcdir@, @top_srcdir@, and @INSTALL@ for subdirectories. + ac_dir=`(dirname "$ac_file") 2>/dev/null || +$as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$ac_file" : 'X\(//\)[^/]' \| \ + X"$ac_file" : 'X\(//\)$' \| \ + X"$ac_file" : 'X\(/\)' \| \ + . : '\(.\)' 2>/dev/null || +echo X"$ac_file" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; } + /^X\(\/\/\)[^/].*/{ s//\1/; q; } + /^X\(\/\/\)$/{ s//\1/; q; } + /^X\(\/\).*/{ s//\1/; q; } + s/.*/./; q'` + { if $as_mkdir_p; then + mkdir -p "$ac_dir" + else + as_dir="$ac_dir" + as_dirs= + while test ! -d "$as_dir"; do + as_dirs="$as_dir $as_dirs" + as_dir=`(dirname "$as_dir") 2>/dev/null || +$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$as_dir" : 'X\(//\)[^/]' \| \ + X"$as_dir" : 'X\(//\)$' \| \ + X"$as_dir" : 'X\(/\)' \| \ + . : '\(.\)' 2>/dev/null || +echo X"$as_dir" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; } + /^X\(\/\/\)[^/].*/{ s//\1/; q; } + /^X\(\/\/\)$/{ s//\1/; q; } + /^X\(\/\).*/{ s//\1/; q; } + s/.*/./; q'` + done + test ! -n "$as_dirs" || mkdir $as_dirs + fi || { { echo "$as_me:$LINENO: error: cannot create directory \"$ac_dir\"" >&5 +echo "$as_me: error: cannot create directory \"$ac_dir\"" >&2;} + { (exit 1); exit 1; }; }; } + + ac_builddir=. + +if test "$ac_dir" != .; then + ac_dir_suffix=/`echo "$ac_dir" | sed 's,^\.[\\/],,'` + # A "../" for each directory in $ac_dir_suffix. + ac_top_builddir=`echo "$ac_dir_suffix" | sed 's,/[^\\/]*,../,g'` +else + ac_dir_suffix= ac_top_builddir= +fi + +case $srcdir in + .) # No --srcdir option. We are building in place. + ac_srcdir=. + if test -z "$ac_top_builddir"; then + ac_top_srcdir=. + else + ac_top_srcdir=`echo $ac_top_builddir | sed 's,/$,,'` + fi ;; + [\\/]* | ?:[\\/]* ) # Absolute path. + ac_srcdir=$srcdir$ac_dir_suffix; + ac_top_srcdir=$srcdir ;; + *) # Relative path. + ac_srcdir=$ac_top_builddir$srcdir$ac_dir_suffix + ac_top_srcdir=$ac_top_builddir$srcdir ;; +esac + +# Do not use `cd foo && pwd` to compute absolute paths, because +# the directories may not exist. +case `pwd` in +.) ac_abs_builddir="$ac_dir";; +*) + case "$ac_dir" in + .) ac_abs_builddir=`pwd`;; + [\\/]* | ?:[\\/]* ) ac_abs_builddir="$ac_dir";; + *) ac_abs_builddir=`pwd`/"$ac_dir";; + esac;; +esac +case $ac_abs_builddir in +.) ac_abs_top_builddir=${ac_top_builddir}.;; +*) + case ${ac_top_builddir}. in + .) ac_abs_top_builddir=$ac_abs_builddir;; + [\\/]* | ?:[\\/]* ) ac_abs_top_builddir=${ac_top_builddir}.;; + *) ac_abs_top_builddir=$ac_abs_builddir/${ac_top_builddir}.;; + esac;; +esac +case $ac_abs_builddir in +.) ac_abs_srcdir=$ac_srcdir;; +*) + case $ac_srcdir in + .) ac_abs_srcdir=$ac_abs_builddir;; + [\\/]* | ?:[\\/]* ) ac_abs_srcdir=$ac_srcdir;; + *) ac_abs_srcdir=$ac_abs_builddir/$ac_srcdir;; + esac;; +esac +case $ac_abs_builddir in +.) ac_abs_top_srcdir=$ac_top_srcdir;; +*) + case $ac_top_srcdir in + .) ac_abs_top_srcdir=$ac_abs_builddir;; + [\\/]* | ?:[\\/]* ) ac_abs_top_srcdir=$ac_top_srcdir;; + *) ac_abs_top_srcdir=$ac_abs_builddir/$ac_top_srcdir;; + esac;; +esac + + + case $INSTALL in + [\\/$]* | ?:[\\/]* ) ac_INSTALL=$INSTALL ;; + *) ac_INSTALL=$ac_top_builddir$INSTALL ;; + esac + + if test x"$ac_file" != x-; then + { echo "$as_me:$LINENO: creating $ac_file" >&5 +echo "$as_me: creating $ac_file" >&6;} + rm -f "$ac_file" + fi + # Let's still pretend it is `configure' which instantiates (i.e., don't + # use $as_me), people would be surprised to read: + # /* config.h. Generated by config.status. */ + if test x"$ac_file" = x-; then + configure_input= + else + configure_input="$ac_file. " + fi + configure_input=$configure_input"Generated from `echo $ac_file_in | + sed 's,.*/,,'` by configure." + + # First look for the input files in the build tree, otherwise in the + # src tree. + ac_file_inputs=`IFS=: + for f in $ac_file_in; do + case $f in + -) echo $tmp/stdin ;; + [\\/$]*) + # Absolute (can't be DOS-style, as IFS=:) + test -f "$f" || { { echo "$as_me:$LINENO: error: cannot find input file: $f" >&5 +echo "$as_me: error: cannot find input file: $f" >&2;} + { (exit 1); exit 1; }; } + echo "$f";; + *) # Relative + if test -f "$f"; then + # Build tree + echo "$f" + elif test -f "$srcdir/$f"; then + # Source tree + echo "$srcdir/$f" + else + # /dev/null tree + { { echo "$as_me:$LINENO: error: cannot find input file: $f" >&5 +echo "$as_me: error: cannot find input file: $f" >&2;} + { (exit 1); exit 1; }; } + fi;; + esac + done` || { (exit 1); exit 1; } +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF + sed "$ac_vpsub +$extrasub +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF +:t +/@[a-zA-Z_][a-zA-Z_0-9]*@/!b +s,@configure_input@,$configure_input,;t t +s,@srcdir@,$ac_srcdir,;t t +s,@abs_srcdir@,$ac_abs_srcdir,;t t +s,@top_srcdir@,$ac_top_srcdir,;t t +s,@abs_top_srcdir@,$ac_abs_top_srcdir,;t t +s,@builddir@,$ac_builddir,;t t +s,@abs_builddir@,$ac_abs_builddir,;t t +s,@top_builddir@,$ac_top_builddir,;t t +s,@abs_top_builddir@,$ac_abs_top_builddir,;t t +s,@INSTALL@,$ac_INSTALL,;t t +" $ac_file_inputs | (eval "$ac_sed_cmds") >$tmp/out + rm -f $tmp/stdin + if test x"$ac_file" != x-; then + mv $tmp/out $ac_file + else + cat $tmp/out + rm -f $tmp/out + fi + +done +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF + +# +# CONFIG_HEADER section. +# + +# These sed commands are passed to sed as "A NAME B NAME C VALUE D", where +# NAME is the cpp macro being defined and VALUE is the value it is being given. +# +# ac_d sets the value in "#define NAME VALUE" lines. +ac_dA='s,^\([ ]*\)#\([ ]*define[ ][ ]*\)' +ac_dB='[ ].*$,\1#\2' +ac_dC=' ' +ac_dD=',;t' +# ac_u turns "#undef NAME" without trailing blanks into "#define NAME VALUE". +ac_uA='s,^\([ ]*\)#\([ ]*\)undef\([ ][ ]*\)' +ac_uB='$,\1#\2define\3' +ac_uC=' ' +ac_uD=',;t' + +for ac_file in : $CONFIG_HEADERS; do test "x$ac_file" = x: && continue + # Support "outfile[:infile[:infile...]]", defaulting infile="outfile.in". + case $ac_file in + - | *:- | *:-:* ) # input from stdin + cat >$tmp/stdin + ac_file_in=`echo "$ac_file" | sed 's,[^:]*:,,'` + ac_file=`echo "$ac_file" | sed 's,:.*,,'` ;; + *:* ) ac_file_in=`echo "$ac_file" | sed 's,[^:]*:,,'` + ac_file=`echo "$ac_file" | sed 's,:.*,,'` ;; + * ) ac_file_in=$ac_file.in ;; + esac + + test x"$ac_file" != x- && { echo "$as_me:$LINENO: creating $ac_file" >&5 +echo "$as_me: creating $ac_file" >&6;} + + # First look for the input files in the build tree, otherwise in the + # src tree. + ac_file_inputs=`IFS=: + for f in $ac_file_in; do + case $f in + -) echo $tmp/stdin ;; + [\\/$]*) + # Absolute (can't be DOS-style, as IFS=:) + test -f "$f" || { { echo "$as_me:$LINENO: error: cannot find input file: $f" >&5 +echo "$as_me: error: cannot find input file: $f" >&2;} + { (exit 1); exit 1; }; } + # Do quote $f, to prevent DOS paths from being IFS'd. + echo "$f";; + *) # Relative + if test -f "$f"; then + # Build tree + echo "$f" + elif test -f "$srcdir/$f"; then + # Source tree + echo "$srcdir/$f" + else + # /dev/null tree + { { echo "$as_me:$LINENO: error: cannot find input file: $f" >&5 +echo "$as_me: error: cannot find input file: $f" >&2;} + { (exit 1); exit 1; }; } + fi;; + esac + done` || { (exit 1); exit 1; } + # Remove the trailing spaces. + sed 's/[ ]*$//' $ac_file_inputs >$tmp/in + +_ACEOF + +# Transform confdefs.h into two sed scripts, `conftest.defines' and +# `conftest.undefs', that substitutes the proper values into +# config.h.in to produce config.h. The first handles `#define' +# templates, and the second `#undef' templates. +# And first: Protect against being on the right side of a sed subst in +# config.status. Protect against being in an unquoted here document +# in config.status. +rm -f conftest.defines conftest.undefs +# Using a here document instead of a string reduces the quoting nightmare. +# Putting comments in sed scripts is not portable. +# +# `end' is used to avoid that the second main sed command (meant for +# 0-ary CPP macros) applies to n-ary macro definitions. +# See the Autoconf documentation for `clear'. +cat >confdef2sed.sed <<\_ACEOF +s/[\\&,]/\\&/g +s,[\\$`],\\&,g +t clear +: clear +s,^[ ]*#[ ]*define[ ][ ]*\([^ (][^ (]*\)\(([^)]*)\)[ ]*\(.*\)$,${ac_dA}\1${ac_dB}\1\2${ac_dC}\3${ac_dD},gp +t end +s,^[ ]*#[ ]*define[ ][ ]*\([^ ][^ ]*\)[ ]*\(.*\)$,${ac_dA}\1${ac_dB}\1${ac_dC}\2${ac_dD},gp +: end +_ACEOF +# If some macros were called several times there might be several times +# the same #defines, which is useless. Nevertheless, we may not want to +# sort them, since we want the *last* AC-DEFINE to be honored. +uniq confdefs.h | sed -n -f confdef2sed.sed >conftest.defines +sed 's/ac_d/ac_u/g' conftest.defines >conftest.undefs +rm -f confdef2sed.sed + +# This sed command replaces #undef with comments. This is necessary, for +# example, in the case of _POSIX_SOURCE, which is predefined and required +# on some systems where configure will not decide to define it. +cat >>conftest.undefs <<\_ACEOF +s,^[ ]*#[ ]*undef[ ][ ]*[a-zA-Z_][a-zA-Z_0-9]*,/* & */, +_ACEOF + +# Break up conftest.defines because some shells have a limit on the size +# of here documents, and old seds have small limits too (100 cmds). +echo ' # Handle all the #define templates only if necessary.' >>$CONFIG_STATUS +echo ' if grep "^[ ]*#[ ]*define" $tmp/in >/dev/null; then' >>$CONFIG_STATUS +echo ' # If there are no defines, we may have an empty if/fi' >>$CONFIG_STATUS +echo ' :' >>$CONFIG_STATUS +rm -f conftest.tail +while grep . conftest.defines >/dev/null +do + # Write a limited-size here document to $tmp/defines.sed. + echo ' cat >$tmp/defines.sed <>$CONFIG_STATUS + # Speed up: don't consider the non `#define' lines. + echo '/^[ ]*#[ ]*define/!b' >>$CONFIG_STATUS + # Work around the forget-to-reset-the-flag bug. + echo 't clr' >>$CONFIG_STATUS + echo ': clr' >>$CONFIG_STATUS + sed ${ac_max_here_lines}q conftest.defines >>$CONFIG_STATUS + echo 'CEOF + sed -f $tmp/defines.sed $tmp/in >$tmp/out + rm -f $tmp/in + mv $tmp/out $tmp/in +' >>$CONFIG_STATUS + sed 1,${ac_max_here_lines}d conftest.defines >conftest.tail + rm -f conftest.defines + mv conftest.tail conftest.defines +done +rm -f conftest.defines +echo ' fi # grep' >>$CONFIG_STATUS +echo >>$CONFIG_STATUS + +# Break up conftest.undefs because some shells have a limit on the size +# of here documents, and old seds have small limits too (100 cmds). +echo ' # Handle all the #undef templates' >>$CONFIG_STATUS +rm -f conftest.tail +while grep . conftest.undefs >/dev/null +do + # Write a limited-size here document to $tmp/undefs.sed. + echo ' cat >$tmp/undefs.sed <>$CONFIG_STATUS + # Speed up: don't consider the non `#undef' + echo '/^[ ]*#[ ]*undef/!b' >>$CONFIG_STATUS + # Work around the forget-to-reset-the-flag bug. + echo 't clr' >>$CONFIG_STATUS + echo ': clr' >>$CONFIG_STATUS + sed ${ac_max_here_lines}q conftest.undefs >>$CONFIG_STATUS + echo 'CEOF + sed -f $tmp/undefs.sed $tmp/in >$tmp/out + rm -f $tmp/in + mv $tmp/out $tmp/in +' >>$CONFIG_STATUS + sed 1,${ac_max_here_lines}d conftest.undefs >conftest.tail + rm -f conftest.undefs + mv conftest.tail conftest.undefs +done +rm -f conftest.undefs + +cat >>$CONFIG_STATUS <<\_ACEOF + # Let's still pretend it is `configure' which instantiates (i.e., don't + # use $as_me), people would be surprised to read: + # /* config.h. Generated by config.status. */ + if test x"$ac_file" = x-; then + echo "/* Generated by configure. */" >$tmp/config.h + else + echo "/* $ac_file. Generated by configure. */" >$tmp/config.h + fi + cat $tmp/in >>$tmp/config.h + rm -f $tmp/in + if test x"$ac_file" != x-; then + if diff $ac_file $tmp/config.h >/dev/null 2>&1; then + { echo "$as_me:$LINENO: $ac_file is unchanged" >&5 +echo "$as_me: $ac_file is unchanged" >&6;} + else + ac_dir=`(dirname "$ac_file") 2>/dev/null || +$as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$ac_file" : 'X\(//\)[^/]' \| \ + X"$ac_file" : 'X\(//\)$' \| \ + X"$ac_file" : 'X\(/\)' \| \ + . : '\(.\)' 2>/dev/null || +echo X"$ac_file" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; } + /^X\(\/\/\)[^/].*/{ s//\1/; q; } + /^X\(\/\/\)$/{ s//\1/; q; } + /^X\(\/\).*/{ s//\1/; q; } + s/.*/./; q'` + { if $as_mkdir_p; then + mkdir -p "$ac_dir" + else + as_dir="$ac_dir" + as_dirs= + while test ! -d "$as_dir"; do + as_dirs="$as_dir $as_dirs" + as_dir=`(dirname "$as_dir") 2>/dev/null || +$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$as_dir" : 'X\(//\)[^/]' \| \ + X"$as_dir" : 'X\(//\)$' \| \ + X"$as_dir" : 'X\(/\)' \| \ + . : '\(.\)' 2>/dev/null || +echo X"$as_dir" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; } + /^X\(\/\/\)[^/].*/{ s//\1/; q; } + /^X\(\/\/\)$/{ s//\1/; q; } + /^X\(\/\).*/{ s//\1/; q; } + s/.*/./; q'` + done + test ! -n "$as_dirs" || mkdir $as_dirs + fi || { { echo "$as_me:$LINENO: error: cannot create directory \"$ac_dir\"" >&5 +echo "$as_me: error: cannot create directory \"$ac_dir\"" >&2;} + { (exit 1); exit 1; }; }; } + + rm -f $ac_file + mv $tmp/config.h $ac_file + fi + else + cat $tmp/config.h + rm -f $tmp/config.h + fi +done +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF + +# +# CONFIG_COMMANDS section. +# +for ac_file in : $CONFIG_COMMANDS; do test "x$ac_file" = x: && continue + ac_dest=`echo "$ac_file" | sed 's,:.*,,'` + ac_source=`echo "$ac_file" | sed 's,[^:]*:,,'` + ac_dir=`(dirname "$ac_dest") 2>/dev/null || +$as_expr X"$ac_dest" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$ac_dest" : 'X\(//\)[^/]' \| \ + X"$ac_dest" : 'X\(//\)$' \| \ + X"$ac_dest" : 'X\(/\)' \| \ + . : '\(.\)' 2>/dev/null || +echo X"$ac_dest" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; } + /^X\(\/\/\)[^/].*/{ s//\1/; q; } + /^X\(\/\/\)$/{ s//\1/; q; } + /^X\(\/\).*/{ s//\1/; q; } + s/.*/./; q'` + { if $as_mkdir_p; then + mkdir -p "$ac_dir" + else + as_dir="$ac_dir" + as_dirs= + while test ! -d "$as_dir"; do + as_dirs="$as_dir $as_dirs" + as_dir=`(dirname "$as_dir") 2>/dev/null || +$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$as_dir" : 'X\(//\)[^/]' \| \ + X"$as_dir" : 'X\(//\)$' \| \ + X"$as_dir" : 'X\(/\)' \| \ + . : '\(.\)' 2>/dev/null || +echo X"$as_dir" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; } + /^X\(\/\/\)[^/].*/{ s//\1/; q; } + /^X\(\/\/\)$/{ s//\1/; q; } + /^X\(\/\).*/{ s//\1/; q; } + s/.*/./; q'` + done + test ! -n "$as_dirs" || mkdir $as_dirs + fi || { { echo "$as_me:$LINENO: error: cannot create directory \"$ac_dir\"" >&5 +echo "$as_me: error: cannot create directory \"$ac_dir\"" >&2;} + { (exit 1); exit 1; }; }; } + + ac_builddir=. + +if test "$ac_dir" != .; then + ac_dir_suffix=/`echo "$ac_dir" | sed 's,^\.[\\/],,'` + # A "../" for each directory in $ac_dir_suffix. + ac_top_builddir=`echo "$ac_dir_suffix" | sed 's,/[^\\/]*,../,g'` +else + ac_dir_suffix= ac_top_builddir= +fi + +case $srcdir in + .) # No --srcdir option. We are building in place. + ac_srcdir=. + if test -z "$ac_top_builddir"; then + ac_top_srcdir=. + else + ac_top_srcdir=`echo $ac_top_builddir | sed 's,/$,,'` + fi ;; + [\\/]* | ?:[\\/]* ) # Absolute path. + ac_srcdir=$srcdir$ac_dir_suffix; + ac_top_srcdir=$srcdir ;; + *) # Relative path. + ac_srcdir=$ac_top_builddir$srcdir$ac_dir_suffix + ac_top_srcdir=$ac_top_builddir$srcdir ;; +esac + +# Do not use `cd foo && pwd` to compute absolute paths, because +# the directories may not exist. +case `pwd` in +.) ac_abs_builddir="$ac_dir";; +*) + case "$ac_dir" in + .) ac_abs_builddir=`pwd`;; + [\\/]* | ?:[\\/]* ) ac_abs_builddir="$ac_dir";; + *) ac_abs_builddir=`pwd`/"$ac_dir";; + esac;; +esac +case $ac_abs_builddir in +.) ac_abs_top_builddir=${ac_top_builddir}.;; +*) + case ${ac_top_builddir}. in + .) ac_abs_top_builddir=$ac_abs_builddir;; + [\\/]* | ?:[\\/]* ) ac_abs_top_builddir=${ac_top_builddir}.;; + *) ac_abs_top_builddir=$ac_abs_builddir/${ac_top_builddir}.;; + esac;; +esac +case $ac_abs_builddir in +.) ac_abs_srcdir=$ac_srcdir;; +*) + case $ac_srcdir in + .) ac_abs_srcdir=$ac_abs_builddir;; + [\\/]* | ?:[\\/]* ) ac_abs_srcdir=$ac_srcdir;; + *) ac_abs_srcdir=$ac_abs_builddir/$ac_srcdir;; + esac;; +esac +case $ac_abs_builddir in +.) ac_abs_top_srcdir=$ac_top_srcdir;; +*) + case $ac_top_srcdir in + .) ac_abs_top_srcdir=$ac_abs_builddir;; + [\\/]* | ?:[\\/]* ) ac_abs_top_srcdir=$ac_top_srcdir;; + *) ac_abs_top_srcdir=$ac_abs_builddir/$ac_top_srcdir;; + esac;; +esac + + + { echo "$as_me:$LINENO: executing $ac_dest commands" >&5 +echo "$as_me: executing $ac_dest commands" >&6;} + case $ac_dest in + default-1 ) test -z "$CONFIG_HEADERS" || echo timestamp > stamp-h ;; + esac +done +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF + +{ (exit 0); exit 0; } +_ACEOF +chmod +x $CONFIG_STATUS +ac_clean_files=$ac_clean_files_save + + +# configure is writing to config.log, and then calls config.status. +# config.status does its own redirection, appending to config.log. +# Unfortunately, on DOS this fails, as config.log is still kept open +# by configure, so config.status won't be able to write to it; its +# output is simply discarded. So we exec the FD to /dev/null, +# effectively closing config.log, so it can be properly (re)opened and +# appended to by config.status. When coming back to configure, we +# need to make the FD available again. +if test "$no_create" != yes; then + ac_cs_success=: + ac_config_status_args= + test "$silent" = yes && + ac_config_status_args="$ac_config_status_args --quiet" + exec 5>/dev/null + $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false + exec 5>>config.log + # Use ||, not &&, to avoid exiting from the if with $? = 1, which + # would make configure fail if this is the last instruction. + $ac_cs_success || { (exit 1); exit 1; } +fi + +chmod +x xmlrpc-c-config +chmod +x xmlrpc-c-config.test diff --git a/autom4te.cache/requests b/autom4te.cache/requests new file mode 100644 index 0000000..37b7fbc --- /dev/null +++ b/autom4te.cache/requests @@ -0,0 +1,225 @@ +# This file was generated. +# It contains the lists of macros which have been traced. +# It can be safely removed. + +@request = ( + bless( [ + '0', + 1, + [ + '/subsys/autoconf/share' + ], + [ + '/subsys/autoconf/share/autoconf/autoconf.m4f', + 'aclocal.m4', + 'configure.in' + ], + { + 'AC_CANONICAL_SYSTEM' => 1, + 'AC_HEADER_STAT' => 1, + 'AC_FUNC_STRFTIME' => 1, + 'AC_PROG_RANLIB' => 1, + 'AC_C_VOLATILE' => 1, + 'AC_FUNC_WAIT3' => 1, + 'AC_CONFIG_AUX_DIR' => 1, + 'AC_REPLACE_FNMATCH' => 1, + 'AC_FUNC_SETPGRP' => 1, + 'AC_HEADER_TIME' => 1, + 'AC_FUNC_SETVBUF_REVERSED' => 1, + 'AC_HEADER_SYS_WAIT' => 1, + 'AC_TYPE_UID_T' => 1, + 'AM_CONDITIONAL' => 1, + 'AC_CHECK_LIB' => 1, + 'AC_PROG_LN_S' => 1, + 'AC_FUNC_MEMCMP' => 1, + 'AM_PROG_CC_C_O' => 1, + 'AC_CONFIG_LIBOBJ_DIR' => 1, + 'AC_FUNC_FORK' => 1, + 'AC_FUNC_GETGROUPS' => 1, + 'AC_HEADER_MAJOR' => 1, + 'AC_FUNC_STRNLEN' => 1, + 'AC_FUNC_STRTOD' => 1, + 'AC_HEADER_DIRENT' => 1, + 'AC_FUNC_UTIME_NULL' => 1, + 'AC_FUNC_MBRTOWC' => 1, + '_m4_warn' => 1, + 'AC_CONFIG_FILES' => 1, + 'AC_FUNC_ALLOCA' => 1, + 'AC_C_CONST' => 1, + 'AC_CHECK_MEMBERS' => 1, + 'AC_FUNC_REALLOC' => 1, + 'include' => 1, + 'AC_FUNC_OBSTACK' => 1, + 'AC_FUNC_LSTAT' => 1, + 'AC_STRUCT_TIMEZONE' => 1, + 'AC_FUNC_GETPGRP' => 1, + 'AC_DEFINE_TRACE_LITERAL' => 1, + 'AC_CHECK_HEADERS' => 1, + 'AC_TYPE_MODE_T' => 1, + 'AC_CHECK_TYPES' => 1, + 'AC_PROG_YACC' => 1, + 'AC_TYPE_PID_T' => 1, + 'AC_FUNC_STRERROR_R' => 1, + 'AM_AUTOMAKE_VERSION' => 1, + 'AC_STRUCT_ST_BLOCKS' => 1, + 'AC_FUNC_SELECT_ARGTYPES' => 1, + 'AC_FUNC_LSTAT_FOLLOWS_SLASHED_SYMLINK' => 1, + 'AC_TYPE_SIGNAL' => 1, + 'AC_PROG_GCC_TRADITIONAL' => 1, + 'm4_sinclude' => 1, + 'AC_PROG_CPP' => 1, + 'AC_FUNC_STAT' => 1, + 'AC_PROG_INSTALL' => 1, + 'sinclude' => 1, + 'AC_CONFIG_SUBDIRS' => 1, + 'AM_GNU_GETTEXT' => 1, + 'AC_FUNC_STRCOLL' => 1, + 'AC_LIBSOURCE' => 1, + 'AC_C_INLINE' => 1, + 'AC_FUNC_CHOWN' => 1, + 'AC_FUNC_GETMNTENT' => 1, + 'AC_INIT' => 1, + 'AC_PROG_LEX' => 1, + 'AH_OUTPUT' => 1, + 'AC_HEADER_STDC' => 1, + 'AC_FUNC_GETLOADAVG' => 1, + 'AC_TYPE_SIZE_T' => 1, + 'AC_CHECK_FUNCS' => 1, + 'AC_DECL_SYS_SIGLIST' => 1, + 'AC_FUNC_MKTIME' => 1, + 'AC_PROG_MAKE_SET' => 1, + 'AC_CONFIG_LINKS' => 1, + 'AC_PROG_CXX' => 1, + 'AC_CANONICAL_HOST' => 1, + 'AC_FUNC_CLOSEDIR_VOID' => 1, + 'm4_pattern_allow' => 1, + 'm4_include' => 1, + 'm4_pattern_forbid' => 1, + 'AC_PROG_AWK' => 1, + 'AC_FUNC_VPRINTF' => 1, + 'AC_CONFIG_HEADERS' => 1, + 'AC_TYPE_OFF_T' => 1, + 'AC_PATH_X' => 1, + 'AC_FUNC_MALLOC' => 1, + 'AM_MAINTAINER_MODE' => 1, + 'AC_FUNC_ERROR_AT_LINE' => 1, + 'AC_FUNC_FSEEKO' => 1, + 'AC_STRUCT_TM' => 1, + 'AC_FUNC_MMAP' => 1, + 'AM_INIT_AUTOMAKE' => 1, + 'AC_SUBST' => 1, + 'AC_PROG_LIBTOOL' => 1, + 'AC_PROG_CC' => 1 + } + ], 'Autom4te::Request' ), + bless( [ + '1', + 1, + [ + '/subsys2/autoconf/share' + ], + [ + '/subsys2/autoconf/share/autoconf/autoconf.m4f', + 'aclocal.m4', + 'configure.in' + ], + { + 'AC_CANONICAL_SYSTEM' => 1, + 'AC_HEADER_STAT' => 1, + 'AC_FUNC_STRFTIME' => 1, + 'AC_PROG_RANLIB' => 1, + 'AC_C_VOLATILE' => 1, + 'AC_FUNC_WAIT3' => 1, + 'AC_CONFIG_AUX_DIR' => 1, + 'AC_REPLACE_FNMATCH' => 1, + 'AC_FUNC_SETPGRP' => 1, + 'AC_HEADER_TIME' => 1, + 'AC_FUNC_SETVBUF_REVERSED' => 1, + 'AC_HEADER_SYS_WAIT' => 1, + 'AC_TYPE_UID_T' => 1, + 'AM_CONDITIONAL' => 1, + 'AC_CHECK_LIB' => 1, + 'AC_PROG_LN_S' => 1, + 'AC_FUNC_MEMCMP' => 1, + 'AM_PROG_CC_C_O' => 1, + 'AC_CONFIG_LIBOBJ_DIR' => 1, + 'AC_FUNC_FORK' => 1, + 'AC_FUNC_GETGROUPS' => 1, + 'AC_HEADER_MAJOR' => 1, + 'AC_FUNC_STRNLEN' => 1, + 'AC_FUNC_STRTOD' => 1, + 'AC_HEADER_DIRENT' => 1, + 'AC_FUNC_UTIME_NULL' => 1, + 'AC_FUNC_MBRTOWC' => 1, + '_m4_warn' => 1, + 'AC_CONFIG_FILES' => 1, + 'AC_FUNC_ALLOCA' => 1, + 'AC_C_CONST' => 1, + 'AC_CHECK_MEMBERS' => 1, + 'AC_FUNC_REALLOC' => 1, + 'include' => 1, + 'AC_FUNC_OBSTACK' => 1, + 'AC_FUNC_LSTAT' => 1, + 'AC_STRUCT_TIMEZONE' => 1, + 'AC_FUNC_GETPGRP' => 1, + 'AC_DEFINE_TRACE_LITERAL' => 1, + 'AC_CHECK_HEADERS' => 1, + 'AC_TYPE_MODE_T' => 1, + 'AC_CHECK_TYPES' => 1, + 'AC_PROG_YACC' => 1, + 'AC_TYPE_PID_T' => 1, + 'AC_FUNC_STRERROR_R' => 1, + 'AM_AUTOMAKE_VERSION' => 1, + 'AC_STRUCT_ST_BLOCKS' => 1, + 'AC_FUNC_SELECT_ARGTYPES' => 1, + 'AC_FUNC_LSTAT_FOLLOWS_SLASHED_SYMLINK' => 1, + 'AC_TYPE_SIGNAL' => 1, + 'AC_PROG_GCC_TRADITIONAL' => 1, + 'm4_sinclude' => 1, + 'AC_PROG_CPP' => 1, + 'AC_FUNC_STAT' => 1, + 'AC_PROG_INSTALL' => 1, + 'sinclude' => 1, + 'AC_CONFIG_SUBDIRS' => 1, + 'AM_GNU_GETTEXT' => 1, + 'AC_FUNC_STRCOLL' => 1, + 'AC_LIBSOURCE' => 1, + 'AC_C_INLINE' => 1, + 'AC_FUNC_CHOWN' => 1, + 'AC_FUNC_GETMNTENT' => 1, + 'AC_INIT' => 1, + 'AC_PROG_LEX' => 1, + 'AH_OUTPUT' => 1, + 'AC_HEADER_STDC' => 1, + 'AC_FUNC_GETLOADAVG' => 1, + 'AC_TYPE_SIZE_T' => 1, + 'AC_CHECK_FUNCS' => 1, + 'AC_DECL_SYS_SIGLIST' => 1, + 'AC_FUNC_MKTIME' => 1, + 'AC_PROG_MAKE_SET' => 1, + 'AC_CONFIG_LINKS' => 1, + 'AC_PROG_CXX' => 1, + 'AC_CANONICAL_HOST' => 1, + 'AC_FUNC_CLOSEDIR_VOID' => 1, + 'm4_pattern_allow' => 1, + 'm4_include' => 1, + 'm4_pattern_forbid' => 1, + 'AC_PROG_AWK' => 1, + 'AC_FUNC_VPRINTF' => 1, + 'AC_CONFIG_HEADERS' => 1, + 'AC_TYPE_OFF_T' => 1, + 'AC_PATH_X' => 1, + 'AC_FUNC_MALLOC' => 1, + 'AM_MAINTAINER_MODE' => 1, + 'AC_FUNC_ERROR_AT_LINE' => 1, + 'AC_FUNC_FSEEKO' => 1, + 'AC_STRUCT_TM' => 1, + 'AC_FUNC_MMAP' => 1, + 'AM_INIT_AUTOMAKE' => 1, + 'AC_SUBST' => 1, + 'AC_PROG_LIBTOOL' => 1, + 'AC_PROG_CC' => 1 + } + ], 'Autom4te::Request' ) + ); + diff --git a/autom4te.cache/traces.0 b/autom4te.cache/traces.0 new file mode 100644 index 0000000..38d5970 --- /dev/null +++ b/autom4te.cache/traces.0 @@ -0,0 +1,286 @@ +m4trace:configure.in:3: -1- AC_INIT([include/xmlrpc-c/base.h]) +m4trace:configure.in:3: -1- m4_pattern_forbid([^_?A[CHUM]_]) +m4trace:configure.in:3: -1- m4_pattern_forbid([_AC_]) +m4trace:configure.in:3: -1- m4_pattern_forbid([^LIBOBJS$], [do not use LIBOBJS directly, use AC_LIBOBJ (see section `AC_LIBOBJ vs LIBOBJS']) +m4trace:configure.in:3: -1- m4_pattern_allow([^AS_FLAGS$]) +m4trace:configure.in:3: -1- m4_pattern_forbid([^_?m4_]) +m4trace:configure.in:3: -1- m4_pattern_forbid([^dnl$]) +m4trace:configure.in:3: -1- m4_pattern_forbid([^_?AS_]) +m4trace:configure.in:3: -1- AC_SUBST([SHELL], [${CONFIG_SHELL-/bin/sh}]) +m4trace:configure.in:3: -1- AC_SUBST([PATH_SEPARATOR]) +m4trace:configure.in:3: -1- AC_SUBST([PACKAGE_NAME], [m4_ifdef([AC_PACKAGE_NAME], ['AC_PACKAGE_NAME'])]) +m4trace:configure.in:3: -1- AC_SUBST([PACKAGE_TARNAME], [m4_ifdef([AC_PACKAGE_TARNAME], ['AC_PACKAGE_TARNAME'])]) +m4trace:configure.in:3: -1- AC_SUBST([PACKAGE_VERSION], [m4_ifdef([AC_PACKAGE_VERSION], ['AC_PACKAGE_VERSION'])]) +m4trace:configure.in:3: -1- AC_SUBST([PACKAGE_STRING], [m4_ifdef([AC_PACKAGE_STRING], ['AC_PACKAGE_STRING'])]) +m4trace:configure.in:3: -1- AC_SUBST([PACKAGE_BUGREPORT], [m4_ifdef([AC_PACKAGE_BUGREPORT], ['AC_PACKAGE_BUGREPORT'])]) +m4trace:configure.in:3: -1- AC_SUBST([exec_prefix], [NONE]) +m4trace:configure.in:3: -1- AC_SUBST([prefix], [NONE]) +m4trace:configure.in:3: -1- AC_SUBST([program_transform_name], [s,x,x,]) +m4trace:configure.in:3: -1- AC_SUBST([bindir], ['${exec_prefix}/bin']) +m4trace:configure.in:3: -1- AC_SUBST([sbindir], ['${exec_prefix}/sbin']) +m4trace:configure.in:3: -1- AC_SUBST([libexecdir], ['${exec_prefix}/libexec']) +m4trace:configure.in:3: -1- AC_SUBST([datadir], ['${prefix}/share']) +m4trace:configure.in:3: -1- AC_SUBST([sysconfdir], ['${prefix}/etc']) +m4trace:configure.in:3: -1- AC_SUBST([sharedstatedir], ['${prefix}/com']) +m4trace:configure.in:3: -1- AC_SUBST([localstatedir], ['${prefix}/var']) +m4trace:configure.in:3: -1- AC_SUBST([libdir], ['${exec_prefix}/lib']) +m4trace:configure.in:3: -1- AC_SUBST([includedir], ['${prefix}/include']) +m4trace:configure.in:3: -1- AC_SUBST([oldincludedir], ['/usr/include']) +m4trace:configure.in:3: -1- AC_SUBST([infodir], ['${prefix}/info']) +m4trace:configure.in:3: -1- AC_SUBST([mandir], ['${prefix}/man']) +m4trace:configure.in:3: -1- AC_DEFINE_TRACE_LITERAL([PACKAGE_NAME]) +m4trace:configure.in:3: -1- AH_OUTPUT([PACKAGE_NAME], [/* Define to the full name of this package. */ +#undef PACKAGE_NAME]) +m4trace:configure.in:3: -1- AC_DEFINE_TRACE_LITERAL([PACKAGE_TARNAME]) +m4trace:configure.in:3: -1- AH_OUTPUT([PACKAGE_TARNAME], [/* Define to the one symbol short name of this package. */ +#undef PACKAGE_TARNAME]) +m4trace:configure.in:3: -1- AC_DEFINE_TRACE_LITERAL([PACKAGE_VERSION]) +m4trace:configure.in:3: -1- AH_OUTPUT([PACKAGE_VERSION], [/* Define to the version of this package. */ +#undef PACKAGE_VERSION]) +m4trace:configure.in:3: -1- AC_DEFINE_TRACE_LITERAL([PACKAGE_STRING]) +m4trace:configure.in:3: -1- AH_OUTPUT([PACKAGE_STRING], [/* Define to the full name and version of this package. */ +#undef PACKAGE_STRING]) +m4trace:configure.in:3: -1- AC_DEFINE_TRACE_LITERAL([PACKAGE_BUGREPORT]) +m4trace:configure.in:3: -1- AH_OUTPUT([PACKAGE_BUGREPORT], [/* Define to the address where bug reports for this package should be sent. */ +#undef PACKAGE_BUGREPORT]) +m4trace:configure.in:3: -1- AC_SUBST([build_alias]) +m4trace:configure.in:3: -1- AC_SUBST([host_alias]) +m4trace:configure.in:3: -1- AC_SUBST([target_alias]) +m4trace:configure.in:3: -1- AC_SUBST([DEFS]) +m4trace:configure.in:3: -1- AC_SUBST([ECHO_C]) +m4trace:configure.in:3: -1- AC_SUBST([ECHO_N]) +m4trace:configure.in:3: -1- AC_SUBST([ECHO_T]) +m4trace:configure.in:3: -1- AC_SUBST([LIBS]) +m4trace:configure.in:4: -1- AC_CONFIG_HEADERS([xmlrpc_amconfig.h]) +m4trace:configure.in:4: -1- _m4_warn([obsolete], [The macro `AC_OUTPUT_COMMANDS' is obsolete. +You should run autoupdate.], [autoconf/status.m4:318: AC_OUTPUT_COMMANDS is expanded from... +aclocal.m4:34: AM_CONFIG_HEADER is expanded from... +configure.in:4: the top level]) +m4trace:configure.in:4: -3- _m4_warn([obsolete], [The macro `_AC_OUTPUT_COMMANDS_CNT' is obsolete. +You should run autoupdate.], [autoconf/status.m4:321: _AC_OUTPUT_COMMANDS_CNT is expanded from... +autoconf/status.m4:318: AC_OUTPUT_COMMANDS is expanded from... +aclocal.m4:34: AM_CONFIG_HEADER is expanded from... +configure.in:4: the top level]) +m4trace:configure.in:11: -1- AM_INIT_AUTOMAKE([xmlrpc-c], [1.06.31]) +m4trace:configure.in:11: -1- AC_PROG_INSTALL +m4trace:configure.in:11: -1- AC_SUBST([INSTALL_PROGRAM]) +m4trace:configure.in:11: -1- AC_SUBST([INSTALL_SCRIPT]) +m4trace:configure.in:11: -1- AC_SUBST([INSTALL_DATA]) +m4trace:configure.in:11: -1- AC_SUBST([PACKAGE]) +m4trace:configure.in:11: -1- AC_SUBST([VERSION]) +m4trace:configure.in:11: -2- AC_DEFINE_TRACE_LITERAL([PACKAGE]) +m4trace:configure.in:11: -2- AH_OUTPUT([PACKAGE], [/* Name of package */ +#undef PACKAGE]) +m4trace:configure.in:11: -2- AC_DEFINE_TRACE_LITERAL([VERSION]) +m4trace:configure.in:11: -2- AH_OUTPUT([VERSION], [/* Version number of package */ +#undef VERSION]) +m4trace:configure.in:11: -1- AC_SUBST([ACLOCAL]) +m4trace:configure.in:11: -1- AC_SUBST([AUTOCONF]) +m4trace:configure.in:11: -1- AC_SUBST([AUTOMAKE]) +m4trace:configure.in:11: -1- AC_SUBST([AUTOHEADER]) +m4trace:configure.in:11: -1- AC_SUBST([MAKEINFO]) +m4trace:configure.in:11: -1- AC_PROG_MAKE_SET +m4trace:configure.in:11: -1- AC_SUBST([SET_MAKE]) +m4trace:configure.in:17: -1- AC_SUBST([VERSION_INFO]) +m4trace:configure.in:23: -1- AC_CANONICAL_HOST +m4trace:configure.in:23: -1- AC_SUBST([build], [$ac_cv_build]) +m4trace:configure.in:23: -1- AC_SUBST([build_cpu], [`echo $ac_cv_build | sed 's/^\([[^-]]*\)-\([[^-]]*\)-\(.*\)$/\1/'`]) +m4trace:configure.in:23: -1- AC_SUBST([build_vendor], [`echo $ac_cv_build | sed 's/^\([[^-]]*\)-\([[^-]]*\)-\(.*\)$/\2/'`]) +m4trace:configure.in:23: -1- AC_SUBST([build_os], [`echo $ac_cv_build | sed 's/^\([[^-]]*\)-\([[^-]]*\)-\(.*\)$/\3/'`]) +m4trace:configure.in:23: -1- AC_SUBST([host], [$ac_cv_host]) +m4trace:configure.in:23: -1- AC_SUBST([host_cpu], [`echo $ac_cv_host | sed 's/^\([[^-]]*\)-\([[^-]]*\)-\(.*\)$/\1/'`]) +m4trace:configure.in:23: -1- AC_SUBST([host_vendor], [`echo $ac_cv_host | sed 's/^\([[^-]]*\)-\([[^-]]*\)-\(.*\)$/\2/'`]) +m4trace:configure.in:23: -1- AC_SUBST([host_os], [`echo $ac_cv_host | sed 's/^\([[^-]]*\)-\([[^-]]*\)-\(.*\)$/\3/'`]) +m4trace:configure.in:41: -1- AC_SUBST([have_wininet_config]) +m4trace:configure.in:54: -1- AC_SUBST([MUST_BUILD_WININET_CLIENT]) +m4trace:configure.in:62: -1- AC_SUBST([have_curl_config]) +m4trace:configure.in:75: -1- AC_SUBST([MUST_BUILD_CURL_CLIENT]) +m4trace:configure.in:83: -1- AC_SUBST([have_libwww_config]) +m4trace:configure.in:96: -1- AC_SUBST([MUST_BUILD_LIBWWW_CLIENT]) +m4trace:configure.in:107: -1- AC_SUBST([LIBXMLRPC_CLIENT_LA]) +m4trace:configure.in:109: -1- AC_SUBST([CLIENTTEST]) +m4trace:configure.in:111: -1- AC_SUBST([XMLRPC_CLIENT_H]) +m4trace:configure.in:113: -1- AC_SUBST([XMLRPC_TRANSPORT_H]) +m4trace:configure.in:115: -1- AC_SUBST([SYNCH_CLIENT]) +m4trace:configure.in:117: -1- AC_SUBST([ASYNCH_CLIENT]) +m4trace:configure.in:119: -1- AC_SUBST([AUTH_CLIENT]) +m4trace:configure.in:121: -1- AC_SUBST([QUERY_MEERKAT]) +m4trace:configure.in:140: -1- AC_SUBST([ENABLE_ABYSS_SERVER]) +m4trace:configure.in:158: -1- AC_SUBST([ABYSS_SUBDIR]) +m4trace:configure.in:159: -1- AC_SUBST([LIBXMLRPC_ABYSS_SERVER_LA]) +m4trace:configure.in:160: -1- AC_SUBST([SERVERTEST]) +m4trace:configure.in:161: -1- AC_SUBST([VALIDATEE]) +m4trace:configure.in:162: -1- AC_SUBST([XMLRPC_ABYSS_H]) +m4trace:configure.in:163: -1- AC_SUBST([SERVER]) +m4trace:configure.in:172: -1- AC_SUBST([ENABLE_CGI_SERVER]) +m4trace:configure.in:181: -1- AC_SUBST([ENABLE_CPLUSPLUS]) +m4trace:configure.in:202: -1- AC_SUBST([LIBXMLRPC_CPP_A]) +m4trace:configure.in:203: -1- AC_SUBST([CPPTEST]) +m4trace:configure.in:204: -1- AC_SUBST([XMLRPCCPP_H]) +m4trace:configure.in:205: -1- AC_SUBST([XML_RPC_API2CPP_SUBDIR]) +m4trace:configure.in:208: -1- AC_SUBST([FEATURE_LIST]) +m4trace:configure.in:215: -1- AC_PROG_CC +m4trace:configure.in:215: -1- AC_SUBST([CC]) +m4trace:configure.in:215: -1- AC_SUBST([CFLAGS]) +m4trace:configure.in:215: -1- AC_SUBST([LDFLAGS]) +m4trace:configure.in:215: -1- AC_SUBST([CPPFLAGS]) +m4trace:configure.in:215: -1- AC_SUBST([CC]) +m4trace:configure.in:215: -1- AC_SUBST([ac_ct_CC]) +m4trace:configure.in:215: -1- AC_SUBST([CC]) +m4trace:configure.in:215: -1- AC_SUBST([ac_ct_CC]) +m4trace:configure.in:215: -1- AC_SUBST([CC]) +m4trace:configure.in:215: -1- AC_SUBST([CC]) +m4trace:configure.in:215: -1- AC_SUBST([ac_ct_CC]) +m4trace:configure.in:215: -1- AC_SUBST([EXEEXT], [$ac_cv_exeext]) +m4trace:configure.in:215: -1- AC_SUBST([OBJEXT], [$ac_cv_objext]) +m4trace:configure.in:217: -1- AC_PROG_CXX +m4trace:configure.in:217: -1- AC_SUBST([CXX]) +m4trace:configure.in:217: -1- AC_SUBST([CXXFLAGS]) +m4trace:configure.in:217: -1- AC_SUBST([LDFLAGS]) +m4trace:configure.in:217: -1- AC_SUBST([CPPFLAGS]) +m4trace:configure.in:217: -1- AC_SUBST([CXX]) +m4trace:configure.in:217: -1- AC_SUBST([ac_ct_CXX]) +m4trace:configure.in:230: -2- AC_CHECK_LIB([socket], [socket]) +m4trace:configure.in:230: -2- AH_OUTPUT([HAVE_LIBSOCKET], [/* Define to 1 if you have the `socket\' library (-lsocket). */ +#undef HAVE_LIBSOCKET]) +m4trace:configure.in:230: -2- AC_DEFINE_TRACE_LITERAL([HAVE_LIBSOCKET]) +m4trace:configure.in:242: -1- AC_SUBST([LSOCKET]) +m4trace:configure.in:253: -1- _m4_warn([obsolete], [The macro `AC_STDC_HEADERS' is obsolete. +You should run autoupdate.], [autoconf/oldnames.m4:96: AC_STDC_HEADERS is expanded from... +configure.in:253: the top level]) +m4trace:configure.in:253: -1- AC_HEADER_STDC([]) +m4trace:configure.in:253: -1- AC_PROG_CPP +m4trace:configure.in:253: -1- AC_SUBST([CPP]) +m4trace:configure.in:253: -1- AC_SUBST([CPPFLAGS]) +m4trace:configure.in:253: -1- AC_SUBST([CPP]) +m4trace:configure.in:253: -1- AC_SUBST([EGREP]) +m4trace:configure.in:253: -1- AC_DEFINE_TRACE_LITERAL([STDC_HEADERS]) +m4trace:configure.in:253: -1- AH_OUTPUT([STDC_HEADERS], [/* Define to 1 if you have the ANSI C header files. */ +#undef STDC_HEADERS]) +m4trace:configure.in:263: -1- AC_CHECK_HEADERS([wchar.h]) +m4trace:configure.in:263: -1- AH_OUTPUT([HAVE_WCHAR_H], [/* Define to 1 if you have the header file. */ +#undef HAVE_WCHAR_H]) +m4trace:configure.in:263: -1- AC_CHECK_HEADERS([sys/types.h sys/stat.h stdlib.h string.h memory.h strings.h \ + inttypes.h stdint.h unistd.h], [], [], [$ac_includes_default]) +m4trace:configure.in:263: -1- AH_OUTPUT([HAVE_SYS_TYPES_H], [/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_TYPES_H]) +m4trace:configure.in:263: -1- AH_OUTPUT([HAVE_SYS_STAT_H], [/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_STAT_H]) +m4trace:configure.in:263: -1- AH_OUTPUT([HAVE_STDLIB_H], [/* Define to 1 if you have the header file. */ +#undef HAVE_STDLIB_H]) +m4trace:configure.in:263: -1- AH_OUTPUT([HAVE_STRING_H], [/* Define to 1 if you have the header file. */ +#undef HAVE_STRING_H]) +m4trace:configure.in:263: -1- AH_OUTPUT([HAVE_MEMORY_H], [/* Define to 1 if you have the header file. */ +#undef HAVE_MEMORY_H]) +m4trace:configure.in:263: -1- AH_OUTPUT([HAVE_STRINGS_H], [/* Define to 1 if you have the header file. */ +#undef HAVE_STRINGS_H]) +m4trace:configure.in:263: -1- AH_OUTPUT([HAVE_INTTYPES_H], [/* Define to 1 if you have the header file. */ +#undef HAVE_INTTYPES_H]) +m4trace:configure.in:263: -1- AH_OUTPUT([HAVE_STDINT_H], [/* Define to 1 if you have the header file. */ +#undef HAVE_STDINT_H]) +m4trace:configure.in:263: -1- AH_OUTPUT([HAVE_UNISTD_H], [/* Define to 1 if you have the header file. */ +#undef HAVE_UNISTD_H]) +m4trace:configure.in:270: -1- AC_SUBST([HAVE_WCHAR_H_DEFINE]) +m4trace:configure.in:274: -1- AC_CHECK_HEADERS([sys/filio.h]) +m4trace:configure.in:274: -1- AH_OUTPUT([HAVE_SYS_FILIO_H], [/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_FILIO_H]) +m4trace:configure.in:280: -1- AC_SUBST([HAVE_SYS_FILIO_H_DEFINE]) +m4trace:configure.in:284: -1- AC_CHECK_HEADERS([sys/ioctl.h]) +m4trace:configure.in:284: -1- AH_OUTPUT([HAVE_SYS_IOCTL_H], [/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_IOCTL_H]) +m4trace:configure.in:290: -1- AC_SUBST([HAVE_SYS_IOCTL_H_DEFINE]) +m4trace:configure.in:295: -1- AC_CHECK_HEADERS([stdarg.h], [], [ +AC_MSG_ERROR(stdarg.h is required to build this library) +]) +m4trace:configure.in:295: -1- AH_OUTPUT([HAVE_STDARG_H], [/* Define to 1 if you have the header file. */ +#undef HAVE_STDARG_H]) +m4trace:configure.in:303: -1- AC_TYPE_SIZE_T +m4trace:configure.in:303: -1- AC_DEFINE_TRACE_LITERAL([size_t]) +m4trace:configure.in:303: -1- AH_OUTPUT([size_t], [/* Define to `unsigned\' if does not define. */ +#undef size_t]) +m4trace:configure.in:311: -1- _m4_warn([obsolete], [The macro `AC_TRY_COMPILE' is obsolete. +You should run autoupdate.], [autoconf/general.m4:2180: AC_TRY_COMPILE is expanded from... +configure.in:311: the top level]) +m4trace:configure.in:318: -1- AC_SUBST([VA_LIST_IS_ARRAY_DEFINE]) +m4trace:configure.in:323: -1- _m4_warn([obsolete], [The macro `AC_TRY_COMPILE' is obsolete. +You should run autoupdate.], [autoconf/general.m4:2180: AC_TRY_COMPILE is expanded from... +configure.in:323: the top level]) +m4trace:configure.in:330: -1- AC_SUBST([ATTR_UNUSED]) +m4trace:configure.in:342: -1- AC_CHECK_FUNCS([wcsncmp]) +m4trace:configure.in:342: -1- AH_OUTPUT([HAVE_WCSNCMP], [/* Define to 1 if you have the `wcsncmp\' function. */ +#undef HAVE_WCSNCMP]) +m4trace:configure.in:345: -1- AC_CHECK_FUNCS([setgroups]) +m4trace:configure.in:345: -1- AH_OUTPUT([HAVE_SETGROUPS], [/* Define to 1 if you have the `setgroups\' function. */ +#undef HAVE_SETGROUPS]) +m4trace:configure.in:347: -1- AC_CHECK_FUNCS([asprintf]) +m4trace:configure.in:347: -1- AH_OUTPUT([HAVE_ASPRINTF], [/* Define to 1 if you have the `asprintf\' function. */ +#undef HAVE_ASPRINTF]) +m4trace:configure.in:349: -1- AC_CHECK_FUNCS([setenv]) +m4trace:configure.in:349: -1- AH_OUTPUT([HAVE_SETENV], [/* Define to 1 if you have the `setenv\' function. */ +#undef HAVE_SETENV]) +m4trace:configure.in:359: -1- AC_SUBST([DIRECTORY_SEPARATOR]) +m4trace:configure.in:373: -1- AC_SUBST([ENABLE_ABYSS_THREADS]) +m4trace:configure.in:389: -1- AC_SUBST([WININET_CONFIG], [$ac_cv_path_WININET_CONFIG]) +m4trace:configure.in:426: -1- AC_SUBST([WININET_CFLAGS]) +m4trace:configure.in:431: -1- AC_SUBST([WININET_LDADD]) +m4trace:configure.in:445: -1- AC_SUBST([WININET_LIBDIR]) +m4trace:configure.in:447: -1- AC_SUBST([WININET_RPATH]) +m4trace:configure.in:449: -1- AC_SUBST([WININET_WL_RPATH]) +m4trace:configure.in:465: -1- AC_SUBST([LIBWWW_CONFIG], [$ac_cv_path_LIBWWW_CONFIG]) +m4trace:configure.in:502: -1- AC_SUBST([LIBWWW_LDADD]) +m4trace:configure.in:516: -1- AC_SUBST([LIBWWW_LIBDIR]) +m4trace:configure.in:524: -1- AC_SUBST([LIBWWW_RPATH]) +m4trace:configure.in:527: -1- AC_SUBST([LIBWWW_WL_RPATH]) +m4trace:configure.in:540: -1- AC_SUBST([CURL_CONFIG], [$ac_cv_path_CURL_CONFIG]) +m4trace:configure.in:558: -1- AC_SUBST([CURL_LDADD]) +m4trace:configure.in:568: -1- AC_SUBST([CURL_LIBDIR]) +m4trace:configure.in:570: -1- AC_SUBST([CURL_RPATH]) +m4trace:configure.in:572: -1- AC_SUBST([CURL_WL_RPATH]) +m4trace:configure.in:595: -1- AC_SUBST([HAVE_LIBWWW_SSL_DEFINE]) +m4trace:configure.in:605: -1- AC_SUBST([have_xml2_config]) +m4trace:configure.in:611: -1- AC_SUBST([ENABLE_LIBXML2_BACKEND]) +m4trace:configure.in:617: -1- AC_SUBST([C_COMPILER_GNU]) +m4trace:configure.in:619: -1- AC_SUBST([CXX_COMPILER_GNU]) +m4trace:configure.in:623: -1- AC_SUBST([CC_WARN_FLAGS]) +m4trace:configure.in:625: -1- AC_SUBST([CPP_WARN_FLAGS]) +m4trace:configure.in:629: -1- AC_SUBST([BUILDDIR]) +m4trace:configure.in:634: -1- AC_PROG_RANLIB +m4trace:configure.in:634: -1- AC_SUBST([RANLIB]) +m4trace:configure.in:634: -1- AC_SUBST([ac_ct_RANLIB]) +m4trace:configure.in:634: -1- _m4_warn([obsolete], [The macro `ac_cv_prog_gcc' is obsolete. +You should run autoupdate.], [autoconf/c.m4:440: ac_cv_prog_gcc is expanded from... +aclocal.m4:419: AC_PROG_LD is expanded from... +configure.in:634: AC_PROG_LD is required by... +aclocal.m4:242: AC_LIBTOOL_SETUP is expanded from... +configure.in:634: AC_LIBTOOL_SETUP is required by... +aclocal.m4:158: AC_PROG_LIBTOOL is expanded from... +aclocal.m4:535: AM_PROG_LIBTOOL is expanded from... +configure.in:634: the top level]) +m4trace:configure.in:634: -1- AC_PROG_LN_S +m4trace:configure.in:634: -1- AC_SUBST([LN_S], [$as_ln_s]) +m4trace:configure.in:634: -1- _m4_warn([obsolete], [The macro `ac_cv_prog_gcc' is obsolete. +You should run autoupdate.], [autoconf/c.m4:440: ac_cv_prog_gcc is expanded from... +aclocal.m4:242: AC_LIBTOOL_SETUP is expanded from... +configure.in:634: AC_LIBTOOL_SETUP is required by... +aclocal.m4:158: AC_PROG_LIBTOOL is expanded from... +aclocal.m4:535: AM_PROG_LIBTOOL is expanded from... +configure.in:634: the top level]) +m4trace:configure.in:634: -1- _m4_warn([obsolete], [The macro `AC_TRY_LINK' is obsolete. +You should run autoupdate.], [autoconf/general.m4:2223: AC_TRY_LINK is expanded from... +autoconf/general.m4:1799: AC_CACHE_VAL is expanded from... +autoconf/general.m4:1808: AC_CACHE_CHECK is expanded from... +aclocal.m4:242: AC_LIBTOOL_SETUP is expanded from... +configure.in:634: AC_LIBTOOL_SETUP is required by... +aclocal.m4:158: AC_PROG_LIBTOOL is expanded from... +aclocal.m4:535: AM_PROG_LIBTOOL is expanded from... +configure.in:634: the top level]) +m4trace:configure.in:634: -1- AC_SUBST([LIBTOOL]) +m4trace:configure.in:648: -1- AC_CONFIG_FILES([xmlrpc-c-config \ + xmlrpc-c-config.test \ + Makefile.config \ + xmlrpc_config.h \ + ]) +m4trace:configure.in:648: -1- _m4_warn([obsolete], [AC_OUTPUT should be used without arguments. +You should run autoupdate.], []) +m4trace:configure.in:648: -1- AC_SUBST([LIB@&t@OBJS], [$ac_libobjs]) +m4trace:configure.in:648: -1- AC_SUBST([LTLIBOBJS], [$ac_ltlibobjs]) diff --git a/conf/abyss_root/conf/abyss.conf b/conf/abyss_root/conf/abyss.conf new file mode 100644 index 0000000..f9c09f2 --- /dev/null +++ b/conf/abyss_root/conf/abyss.conf @@ -0,0 +1,56 @@ +# ABYSS Web Server configuration file +# (C) Moez Mahfoudh - 2000 + +# Cases in option names are ignored, +# that means that PORT=port=PoRT=.. + +# When writing paths, do not worry about / or \ use. +# ABYSS will substitute / with \ on Win32 systems. + +# Options which are system specific (such as User) are +# ignored on systems which do not handle them. + +# The Port option tells the server on which TCP port to listen. +# default is 80 +Port 8080 + +# The name or #number of the user to run the server as if it is +# launched as root (UNIX specific) +User nobody + +# The Server Root (UNIX systems style) +ServerRoot conf/abyss_root + +# The Server Root (Win32 systems style) +# ServerRoot G:\XML\xmlrpc-c-0.9.5\conf\abyss_root + +# The Path option specifies the web files path. +Path htdocs + +# The Default option contains the name of the files the server should +# look for when only a path is given (e.g. http://myserver/info/). +Default index.html index.htm INDEX.HTM INDEX.HTML + +# The KeepAlive option is used to set the maximum number of requests +# served using the same persistent connection. +KeepAlive 10 + +# The TimeOut option tells the server how much seconds to wait for +# an idle connection before closing it. +TimeOut 10 + +# The MimeTypes option specifies the location of the file +# containing the mapping of MIME types and files extensions +MimeTypes conf/mime.types + +# The path of the log file +LogFile log/access.log + +# The file where the pid of the server is logged (UNIX specific) +PidFile log/abyss.pid + +# If AdvertiseServer if set to no, then no server field would be +# appended to the responses. This is the way to make the server +# identity unknown to some malicious people which can profit from +# well known security holes in the software to crash it. +AdvertiseServer yes diff --git a/conf/abyss_root/conf/mime.types b/conf/abyss_root/conf/mime.types new file mode 100644 index 0000000..d53db0f --- /dev/null +++ b/conf/abyss_root/conf/mime.types @@ -0,0 +1,276 @@ +# This is a comment. I love comments. + +# This file controls what Internet media types are sent to the client for +# given file extension(s). Sending the correct media type to the client +# is important so they know how to handle the content of the file. +# Extra types can either be added here or by using an AddType directive +# in your config files. For more information about Internet media types, +# please read RFC 2045, 2046, 2047, 2048, and 2077. The Internet media type +# registry is at . + +# MIME type Extension +application/EDI-Consent +application/EDI-X12 +application/EDIFACT +application/activemessage +application/andrew-inset ez +application/applefile +application/atomicmail +application/cals-1840 +application/commonground +application/cybercash +application/dca-rft +application/dec-dx +application/eshop +application/hyperstudio +application/iges +application/mac-binhex40 hqx +application/mac-compactpro cpt +application/macwriteii +application/marc +application/mathematica +application/msword doc +application/news-message-id +application/news-transmission +application/octet-stream bin dms lha lzh exe class +application/oda oda +application/pdf pdf +application/pgp-encrypted +application/pgp-keys +application/pgp-signature +application/pkcs10 +application/pkcs7-mime +application/pkcs7-signature +application/postscript ai eps ps +application/prs.alvestrand.titrax-sheet +application/prs.cww +application/prs.nprend +application/remote-printing +application/riscos +application/rtf rtf +application/set-payment +application/set-payment-initiation +application/set-registration +application/set-registration-initiation +application/sgml +application/sgml-open-catalog +application/slate +application/smil smi smil +application/vemmi +application/vnd.3M.Post-it-Notes +application/vnd.FloGraphIt +application/vnd.acucobol +application/vnd.anser-web-certificate-issue-initiation +application/vnd.anser-web-funds-transfer-initiation +application/vnd.audiograph +application/vnd.businessobjects +application/vnd.claymore +application/vnd.comsocaller +application/vnd.dna +application/vnd.dxr +application/vnd.ecdis-update +application/vnd.ecowin.chart +application/vnd.ecowin.filerequest +application/vnd.ecowin.fileupdate +application/vnd.ecowin.series +application/vnd.ecowin.seriesrequest +application/vnd.ecowin.seriesupdate +application/vnd.enliven +application/vnd.epson.salt +application/vnd.fdf +application/vnd.ffsns +application/vnd.framemaker +application/vnd.fujitsu.oasys +application/vnd.fujitsu.oasys2 +application/vnd.fujitsu.oasys3 +application/vnd.fujitsu.oasysgp +application/vnd.fujitsu.oasysprs +application/vnd.fujixerox.docuworks +application/vnd.hp-HPGL +application/vnd.hp-PCL +application/vnd.hp-PCLXL +application/vnd.hp-hps +application/vnd.ibm.MiniPay +application/vnd.ibm.modcap +application/vnd.intercon.formnet +application/vnd.intertrust.digibox +application/vnd.intertrust.nncp +application/vnd.is-xpr +application/vnd.japannet-directory-service +application/vnd.japannet-jpnstore-wakeup +application/vnd.japannet-payment-wakeup +application/vnd.japannet-registration +application/vnd.japannet-registration-wakeup +application/vnd.japannet-setstore-wakeup +application/vnd.japannet-verification +application/vnd.japannet-verification-wakeup +application/vnd.koan +application/vnd.lotus-1-2-3 +application/vnd.lotus-approach +application/vnd.lotus-freelance +application/vnd.lotus-organizer +application/vnd.lotus-screencam +application/vnd.lotus-wordpro +application/vnd.meridian-slingshot +application/vnd.mif mif +application/vnd.minisoft-hp3000-save +application/vnd.mitsubishi.misty-guard.trustweb +application/vnd.ms-artgalry +application/vnd.ms-asf +application/vnd.ms-excel xls +application/vnd.ms-powerpoint ppt +application/vnd.ms-project +application/vnd.ms-tnef +application/vnd.ms-works +application/vnd.music-niff +application/vnd.musician +application/vnd.netfpx +application/vnd.noblenet-directory +application/vnd.noblenet-sealer +application/vnd.noblenet-web +application/vnd.novadigm.EDM +application/vnd.novadigm.EDX +application/vnd.novadigm.EXT +application/vnd.osa.netdeploy +application/vnd.powerbuilder6 +application/vnd.powerbuilder6-s +application/vnd.rapid +application/vnd.seemail +application/vnd.shana.informed.formtemplate +application/vnd.shana.informed.interchange +application/vnd.shana.informed.package +application/vnd.street-stream +application/vnd.svd +application/vnd.swiftview-ics +application/vnd.truedoc +application/vnd.visio +application/vnd.webturbo +application/vnd.wrq-hp3000-labelled +application/vnd.wt.stf +application/vnd.xara +application/vnd.yellowriver-custom-menu +application/wita +application/wordperfect5.1 +application/x-bcpio bcpio +application/x-cdlink vcd +application/x-chess-pgn pgn +application/x-compress +application/x-cpio cpio +application/x-csh csh +application/x-director dcr dir dxr +application/x-dvi dvi +application/x-futuresplash spl +application/x-gtar gtar +application/x-gzip +application/x-hdf hdf +application/x-javascript js +application/x-koan skp skd skt skm +application/x-latex latex +application/x-netcdf nc cdf +application/x-sh sh +application/x-shar shar +application/x-shockwave-flash swf +application/x-stuffit sit +application/x-sv4cpio sv4cpio +application/x-sv4crc sv4crc +application/x-tar tar +application/x-tcl tcl +application/x-tex tex +application/x-texinfo texinfo texi +application/x-troff t tr roff +application/x-troff-man man +application/x-troff-me me +application/x-troff-ms ms +application/x-ustar ustar +application/x-wais-source src +application/x400-bp +application/xml +application/zip zip +audio/32kadpcm +audio/basic au snd +audio/midi mid midi kar +audio/mpeg mpga mp2 mp3 +audio/vnd.qcelp +audio/x-aiff aif aiff aifc +audio/x-pn-realaudio ram rm +audio/x-pn-realaudio-plugin rpm +audio/x-realaudio ra +audio/x-wav wav +chemical/x-pdb pdb xyz +image/bmp bmp +image/cgm +image/g3fax +image/gif gif +image/ief ief +image/jpeg jpeg jpg jpe +image/naplps +image/png png +image/prs.btif +image/tiff tiff tif +image/vnd.dwg +image/vnd.dxf +image/vnd.fpx +image/vnd.net-fpx +image/vnd.svf +image/vnd.xiff +image/x-cmu-raster ras +image/x-portable-anymap pnm +image/x-portable-bitmap pbm +image/x-portable-graymap pgm +image/x-portable-pixmap ppm +image/x-rgb rgb +image/x-xbitmap xbm +image/x-xpixmap xpm +image/x-xwindowdump xwd +message/delivery-status +message/disposition-notification +message/external-body +message/http +message/news +message/partial +message/rfc822 +model/iges igs iges +model/mesh msh mesh silo +model/vnd.dwf +model/vrml wrl vrml +multipart/alternative +multipart/appledouble +multipart/byteranges +multipart/digest +multipart/encrypted +multipart/form-data +multipart/header-set +multipart/mixed +multipart/parallel +multipart/related +multipart/report +multipart/signed +multipart/voice-message +text/css css +text/directory +text/enriched +text/html html htm +text/plain asc txt +text/prs.lines.tag +text/rfc822-headers +text/richtext rtx +text/rtf rtf +text/sgml sgml sgm +text/tab-separated-values tsv +text/uri-list +text/vnd.abc +text/vnd.flatland.3dml +text/vnd.fmi.flexstor +text/vnd.in3d.3dml +text/vnd.in3d.spot +text/vnd.latex-z +text/x-setext etx +text/xml xml +video/mpeg mpeg mpg mpe +video/quicktime qt mov +video/vnd.motorola.video +video/vnd.motorola.videop +video/vnd.vivo +video/x-msvideo avi +video/x-sgi-movie movie +x-conference/x-cooltalk ice diff --git a/conf/abyss_root/htdocs/index.htm b/conf/abyss_root/htdocs/index.htm new file mode 100644 index 0000000..f0369a5 --- /dev/null +++ b/conf/abyss_root/htdocs/index.htm @@ -0,0 +1,21 @@ + + +ABYSS is working !!! + + +

Congratulations, ABYSS is working !!!

+
+

+ABYSS Web Server is working correctly on your system. You should now change this +page with yours. +
+Please include in your web pages (at least the first), the 'Powered by ABYSS' +banner to promote the use of ABYSS. +

+
+

+

+Copyright © 2000 Moez Mahfoudh. All rights reserved. + +

+ diff --git a/conf/abyss_root/htdocs/pwrabyss.gif b/conf/abyss_root/htdocs/pwrabyss.gif new file mode 100644 index 0000000000000000000000000000000000000000..9a4a3a3c1fa78ddc71f1251b7bf236931158e6d3 GIT binary patch literal 2198 zcmeH}`&Sb70>Hn3DZUa#6P+d`m{?n~t{KeCG!cl*;cL03D853=oHk$8LBV{X;y{hW zMF~q&Or5l{xuK@16=^!so3U~hYE!&M<7TDz?%aRj{nMz+f|dk zLZMJ9fl{gL?FGHPy+cD_XlO{S25PlhqX8O?Mymx{tyZT4I-O3h2YS8UXaq*1abp8) z{LSA6{vQT*{#C$VEdcmBID7|1>5%qu;YhDz!yT6gN)YaQ{(%vc3|63avu9E}OYT;q zgUVf~U9u6OXZSTgCvH%11xOebjdXfc*Y3?)oEdp7Gq>KAci)9AWIb%62)&l#`;)9H zT}{TM5NXhOB?&(~7xs1YV=>HQX1<2iN4LXK!QNA>l43|)@40MC-(|XRKR4FiJ6si6 zNpc@{5pZQsZzBEF&6dmqBWAEz!?RPl^C331`nvRMkGENDA~;C@-9Sj;Uq)Nq+c}-E z5@NeMydvUN9}6lbL};tT4Jq2IGOn&0FpKU(i-XxwuE;sAxOe|2Cs#6wv{xh|>~3lk z6axJG*G+yY{bA^zuD2n>o68zMELQuVc1=A$qv9{>!*ASu`(+dCqACCJI87u^?#~=4 z>~=f%piriXaw`NJxW&ty#^PzB+!i!JIIvu3yC?|4oA#KEpIz^|NQ! zMh^ZS`XR}1iM|=0E2MQ~z8EhgV05uucjXr3Y0T3w4&74Z6JQ+@^=Ck~crY6m>zsTL zW&(wyA=duw*#Jc3^R#7=$r?`LHe08O6WcxOall5Fii-_6k@NW`##>4(&5VI~#MMRS z>YzIWvReB2a>Goc+u@72`bP8Mh*G={0FtamCuA|c&QL@*7l;Pv=0%1g`FibHdsth^ zzr-!kNmpcvNoK=S14UaQmTlCR@n0}HDOIw@YWOh@bTj$#WJ0oRo!xfD>(hEg=s?u* z)=RR&El8MahZIKkY)qb`bPP_Wbv&-S_VJOY2^IL8e%Z#aazE-j1&Je+5u2%~=IBS8 zuY|%gy1w}|T_5^p^bn&8wFHmlIF(rf6Sp(qr3(8LsCuwU%K)eWQoyFevK{o);Tsah zedEcg=OxY<0mMQVJNddA7k_@1;y#*Kq|Di(>l(03srzE0cHh3tOY09NS>#K_dt#2? z?ccXhY zH9jvjcBhl!COiA!j?<@eW<}9ejNcrm5l|CC@K#4Ag!jqXysZA@+CuZy_O->fAFD{= z8F6<2F!dHd<}f|&@0NcuF28$q;WcoEA`-&_#lLL7{(kk|z<0-gZpcx$yqJvM_Q%d*9v6oG4`*DdjXo2(l zP^e?vuNk;!w<$Asu&`xuqUrWl5s&er##H(+$&tkTW;vSBN*u$c^c=Cye}nZZYxDMn zH_*3v*In-z+h_WoVo|ahcwI7jRt@R1N?`=8-CBxT2ZBN?neW!xR29=h6<|{ugt41z zF?&cA46oWF@w0gBLJhS^3I{tFofT+;IzNWfOLrIE(~|`9ZJh!2>Tmm*&0`@>Z)I?5Gyb z!VuDOS3Ud8lRt)VhopnMJRH-bPxvK}Kg%1(UX*#D^6+*?@}89)OLsVj81B0;#VIX{ zDI2~q%}oeSDXGhR{*FWhhQ0}*ieo5sg>?8=&t&k literal 0 HcmV?d00001 diff --git a/config.guess b/config.guess new file mode 100755 index 0000000..dd1688b --- /dev/null +++ b/config.guess @@ -0,0 +1,1459 @@ +#! /bin/sh +# Attempt to guess a canonical system name. +# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, +# 2000, 2001, 2002, 2003 Free Software Foundation, Inc. + +timestamp='2004-06-11' + +# 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, 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 . +# Please send patches to . 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 ." + +version="\ +GNU config.guess ($timestamp) + +Originally written by Per Bothner. +Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001 +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 0 ;; + --version | -v ) + echo "$version" ; exit 0 ;; + --help | --h* | -h ) + echo "$usage"; exit 0 ;; + -- ) # 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 -q "$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 ;' + +# 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 0 ;; + amd64:OpenBSD:*:*) + echo x86_64-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + amiga:OpenBSD:*:*) + echo m68k-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + arc:OpenBSD:*:*) + echo mipsel-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + cats:OpenBSD:*:*) + echo arm-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + hp300:OpenBSD:*:*) + echo m68k-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + luna88k:OpenBSD:*:*) + echo m88k-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + mac68k:OpenBSD:*:*) + echo m68k-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + macppc:OpenBSD:*:*) + echo powerpc-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + mvme68k:OpenBSD:*:*) + echo m68k-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + mvme88k:OpenBSD:*:*) + echo m88k-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + mvmeppc:OpenBSD:*:*) + echo powerpc-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + pmax:OpenBSD:*:*) + echo mipsel-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + sgi:OpenBSD:*:*) + echo mipseb-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + sun3:OpenBSD:*:*) + echo m68k-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + wgrisc:OpenBSD:*:*) + echo mipsel-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + *:OpenBSD:*:*) + echo ${UNAME_MACHINE}-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + *:ekkoBSD:*:*) + echo ${UNAME_MACHINE}-unknown-ekkobsd${UNAME_RELEASE} + exit 0 ;; + macppc:MirBSD:*:*) + echo powerppc-unknown-mirbsd${UNAME_RELEASE} + exit 0 ;; + *:MirBSD:*:*) + echo ${UNAME_MACHINE}-unknown-mirbsd${UNAME_RELEASE} + exit 0 ;; + 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 0 ;; + Alpha*:OpenVMS:*:*) + echo alpha-hp-vms + exit 0 ;; + 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 0 ;; + 21064:Windows_NT:50:3) + echo alpha-dec-winnt3.5 + exit 0 ;; + Amiga*:UNIX_System_V:4.0:*) + echo m68k-unknown-sysv4 + exit 0;; + *:[Aa]miga[Oo][Ss]:*:*) + echo ${UNAME_MACHINE}-unknown-amigaos + exit 0 ;; + *:[Mm]orph[Oo][Ss]:*:*) + echo ${UNAME_MACHINE}-unknown-morphos + exit 0 ;; + *:OS/390:*:*) + echo i370-ibm-openedition + exit 0 ;; + *:OS400:*:*) + echo powerpc-ibm-os400 + exit 0 ;; + arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*) + echo arm-acorn-riscix${UNAME_RELEASE} + exit 0;; + SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*) + echo hppa1.1-hitachi-hiuxmpp + exit 0;; + 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 0 ;; + NILE*:*:*:dcosx) + echo pyramid-pyramid-svr4 + exit 0 ;; + DRS?6000:unix:4.0:6*) + echo sparc-icl-nx6 + exit 0 ;; + DRS?6000:UNIX_SV:4.2*:7*) + case `/usr/bin/uname -p` in + sparc) echo sparc-icl-nx7 && exit 0 ;; + esac ;; + sun4H:SunOS:5.*:*) + echo sparc-hal-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit 0 ;; + sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*) + echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit 0 ;; + i86pc:SunOS:5.*:*) + echo i386-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit 0 ;; + 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 0 ;; + 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 0 ;; + sun3*:SunOS:*:*) + echo m68k-sun-sunos${UNAME_RELEASE} + exit 0 ;; + 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 0 ;; + aushp:SunOS:*:*) + echo sparc-auspex-sunos${UNAME_RELEASE} + exit 0 ;; + # 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 0 ;; + atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*) + echo m68k-atari-mint${UNAME_RELEASE} + exit 0 ;; + *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*) + echo m68k-atari-mint${UNAME_RELEASE} + exit 0 ;; + milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*) + echo m68k-milan-mint${UNAME_RELEASE} + exit 0 ;; + hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*) + echo m68k-hades-mint${UNAME_RELEASE} + exit 0 ;; + *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*) + echo m68k-unknown-mint${UNAME_RELEASE} + exit 0 ;; + m68k:machten:*:*) + echo m68k-apple-machten${UNAME_RELEASE} + exit 0 ;; + powerpc:machten:*:*) + echo powerpc-apple-machten${UNAME_RELEASE} + exit 0 ;; + RISC*:Mach:*:*) + echo mips-dec-mach_bsd4.3 + exit 0 ;; + RISC*:ULTRIX:*:*) + echo mips-dec-ultrix${UNAME_RELEASE} + exit 0 ;; + VAX*:ULTRIX*:*:*) + echo vax-dec-ultrix${UNAME_RELEASE} + exit 0 ;; + 2020:CLIX:*:* | 2430:CLIX:*:*) + echo clipper-intergraph-clix${UNAME_RELEASE} + exit 0 ;; + mips:*:*:UMIPS | mips:*:*:RISCos) + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c +#ifdef __cplusplus +#include /* 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 \ + && $dummy `echo "${UNAME_RELEASE}" | sed -n 's/\([0-9]*\).*/\1/p'` \ + && exit 0 + echo mips-mips-riscos${UNAME_RELEASE} + exit 0 ;; + Motorola:PowerMAX_OS:*:*) + echo powerpc-motorola-powermax + exit 0 ;; + Motorola:*:4.3:PL8-*) + echo powerpc-harris-powermax + exit 0 ;; + Night_Hawk:*:*:PowerMAX_OS | Synergy:PowerMAX_OS:*:*) + echo powerpc-harris-powermax + exit 0 ;; + Night_Hawk:Power_UNIX:*:*) + echo powerpc-harris-powerunix + exit 0 ;; + m88k:CX/UX:7*:*) + echo m88k-harris-cxux7 + exit 0 ;; + m88k:*:4*:R4*) + echo m88k-motorola-sysv4 + exit 0 ;; + m88k:*:3*:R3*) + echo m88k-motorola-sysv3 + exit 0 ;; + 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 0 ;; + M88*:DolphinOS:*:*) # DolphinOS (SVR3) + echo m88k-dolphin-sysv3 + exit 0 ;; + M88*:*:R3*:*) + # Delta 88k system running SVR3 + echo m88k-motorola-sysv3 + exit 0 ;; + XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3) + echo m88k-tektronix-sysv3 + exit 0 ;; + Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD) + echo m68k-tektronix-bsd + exit 0 ;; + *:IRIX*:*:*) + echo mips-sgi-irix`echo ${UNAME_RELEASE}|sed -e 's/-/_/g'` + exit 0 ;; + ????????: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 0 ;; # Note that: echo "'`uname -s`'" gives 'AIX ' + i*86:AIX:*:*) + echo i386-ibm-aix + exit 0 ;; + 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 0 ;; + *: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 + + main() + { + if (!__power_pc()) + exit(1); + puts("powerpc-ibm-aix3.2.5"); + exit(0); + } +EOF + $CC_FOR_BUILD -o $dummy $dummy.c && $dummy && exit 0 + echo rs6000-ibm-aix3.2.5 + 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 0 ;; + *: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 0 ;; + *:AIX:*:*) + echo rs6000-ibm-aix + exit 0 ;; + ibmrt:4.4BSD:*|romp-ibm:BSD:*) + echo romp-ibm-bsd4.4 + exit 0 ;; + ibmrt:*BSD:*|romp-ibm:BSD:*) # covers RT/PC BSD and + echo romp-ibm-bsd${UNAME_RELEASE} # 4.3 with uname added to + exit 0 ;; # report: romp-ibm BSD 4.3 + *:BOSX:*:*) + echo rs6000-bull-bosx + exit 0 ;; + DPX/2?00:B.O.S.:*:*) + echo m68k-bull-sysv3 + exit 0 ;; + 9000/[34]??:4.3bsd:1.*:*) + echo m68k-hp-bsd + exit 0 ;; + hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*) + echo m68k-hp-bsd4.4 + exit 0 ;; + 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 + #include + + 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 + # avoid double evaluation of $set_cc_for_build + test -n "$CC_FOR_BUILD" || eval $set_cc_for_build + if echo __LP64__ | (CCOPTS= $CC_FOR_BUILD -E -) | grep __LP64__ >/dev/null + then + HP_ARCH="hppa2.0w" + else + HP_ARCH="hppa64" + fi + fi + echo ${HP_ARCH}-hp-hpux${HPUX_REV} + exit 0 ;; + ia64:HP-UX:*:*) + HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` + echo ia64-hp-hpux${HPUX_REV} + exit 0 ;; + 3050*:HI-UX:*:*) + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + #include + 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 && $dummy && exit 0 + echo unknown-hitachi-hiuxwe2 + exit 0 ;; + 9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:* ) + echo hppa1.1-hp-bsd + exit 0 ;; + 9000/8??:4.3bsd:*:*) + echo hppa1.0-hp-bsd + exit 0 ;; + *9??*:MPE/iX:*:* | *3000*:MPE/iX:*:*) + echo hppa1.0-hp-mpeix + exit 0 ;; + hp7??:OSF1:*:* | hp8?[79]:OSF1:*:* ) + echo hppa1.1-hp-osf + exit 0 ;; + hp8??:OSF1:*:*) + echo hppa1.0-hp-osf + exit 0 ;; + i*86:OSF1:*:*) + if [ -x /usr/sbin/sysversion ] ; then + echo ${UNAME_MACHINE}-unknown-osf1mk + else + echo ${UNAME_MACHINE}-unknown-osf1 + fi + exit 0 ;; + parisc*:Lites*:*:*) + echo hppa1.1-hp-lites + exit 0 ;; + C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*) + echo c1-convex-bsd + exit 0 ;; + C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*) + if getsysinfo -f scalar_acc + then echo c32-convex-bsd + else echo c2-convex-bsd + fi + exit 0 ;; + C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*) + echo c34-convex-bsd + exit 0 ;; + C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*) + echo c38-convex-bsd + exit 0 ;; + C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*) + echo c4-convex-bsd + exit 0 ;; + CRAY*Y-MP:*:*:*) + echo ymp-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit 0 ;; + 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 0 ;; + CRAY*TS:*:*:*) + echo t90-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit 0 ;; + CRAY*T3E:*:*:*) + echo alphaev5-cray-unicosmk${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit 0 ;; + CRAY*SV1:*:*:*) + echo sv1-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit 0 ;; + *:UNICOS/mp:*:*) + echo nv1-cray-unicosmp${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit 0 ;; + 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 0 ;; + 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 0 ;; + i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*) + echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE} + exit 0 ;; + sparc*:BSD/OS:*:*) + echo sparc-unknown-bsdi${UNAME_RELEASE} + exit 0 ;; + *:BSD/OS:*:*) + echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE} + exit 0 ;; + *:FreeBSD:*:*) + # Determine whether the default compiler uses glibc. + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + #include + #if __GLIBC__ >= 2 + LIBC=gnu + #else + LIBC= + #endif +EOF + eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep ^LIBC=` + # GNU/KFreeBSD systems have a "k" prefix to indicate we are using + # FreeBSD's kernel, but not the complete OS. + case ${LIBC} in gnu) kernel_only='k' ;; esac + echo ${UNAME_MACHINE}-unknown-${kernel_only}freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`${LIBC:+-$LIBC} + exit 0 ;; + i*:CYGWIN*:*) + echo ${UNAME_MACHINE}-pc-cygwin + exit 0 ;; + i*:MINGW*:*) + echo ${UNAME_MACHINE}-pc-mingw32 + exit 0 ;; + i*:PW*:*) + echo ${UNAME_MACHINE}-pc-pw32 + exit 0 ;; + x86:Interix*:[34]*) + echo i586-pc-interix${UNAME_RELEASE}|sed -e 's/\..*//' + exit 0 ;; + [345]86:Windows_95:* | [345]86:Windows_98:* | [345]86:Windows_NT:*) + echo i${UNAME_MACHINE}-pc-mks + exit 0 ;; + 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 0 ;; + i*:UWIN*:*) + echo ${UNAME_MACHINE}-pc-uwin + exit 0 ;; + p*:CYGWIN*:*) + echo powerpcle-unknown-cygwin + exit 0 ;; + prep*:SunOS:5.*:*) + echo powerpcle-unknown-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit 0 ;; + *:GNU:*:*) + # the GNU system + echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-gnu`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'` + exit 0 ;; + *: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 0 ;; + i*86:Minix:*:*) + echo ${UNAME_MACHINE}-pc-minix + exit 0 ;; + arm*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit 0 ;; + cris:Linux:*:*) + echo cris-axis-linux-gnu + exit 0 ;; + ia64:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit 0 ;; + m32r*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit 0 ;; + m68*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit 0 ;; + 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 | grep ^CPU=` + test x"${CPU}" != x && echo "${CPU}-unknown-linux-gnu" && exit 0 + ;; + 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 | grep ^CPU=` + test x"${CPU}" != x && echo "${CPU}-unknown-linux-gnu" && exit 0 + ;; + ppc:Linux:*:*) + echo powerpc-unknown-linux-gnu + exit 0 ;; + ppc64:Linux:*:*) + echo powerpc64-unknown-linux-gnu + exit 0 ;; + 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 0 ;; + 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 0 ;; + parisc64:Linux:*:* | hppa64:Linux:*:*) + echo hppa64-unknown-linux-gnu + exit 0 ;; + s390:Linux:*:* | s390x:Linux:*:*) + echo ${UNAME_MACHINE}-ibm-linux + exit 0 ;; + sh64*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit 0 ;; + sh*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit 0 ;; + sparc:Linux:*:* | sparc64:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit 0 ;; + x86_64:Linux:*:*) + echo x86_64-unknown-linux-gnu + exit 0 ;; + 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 0 ;; + coff-i386) + echo "${UNAME_MACHINE}-pc-linux-gnucoff" + exit 0 ;; + "") + # 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 0 ;; + esac + # Determine whether the default compiler is a.out or elf + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + #include + #ifdef __ELF__ + # ifdef __GLIBC__ + # if __GLIBC__ >= 2 + LIBC=gnu + # else + LIBC=gnulibc1 + # endif + # else + LIBC=gnulibc1 + # endif + #else + #ifdef __INTEL_COMPILER + LIBC=gnu + #else + LIBC=gnuaout + #endif + #endif + #ifdef __dietlibc__ + LIBC=dietlibc + #endif +EOF + eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep ^LIBC=` + test x"${LIBC}" != x && echo "${UNAME_MACHINE}-pc-linux-${LIBC}" && exit 0 + test x"${TENTATIVE}" != x && echo "${TENTATIVE}" && exit 0 + ;; + 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 0 ;; + 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 0 ;; + 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 0 ;; + i*86:XTS-300:*:STOP) + echo ${UNAME_MACHINE}-unknown-stop + exit 0 ;; + i*86:atheos:*:*) + echo ${UNAME_MACHINE}-unknown-atheos + exit 0 ;; + i*86:syllable:*:*) + echo ${UNAME_MACHINE}-pc-syllable + exit 0 ;; + i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.0*:*) + echo i386-unknown-lynxos${UNAME_RELEASE} + exit 0 ;; + i*86:*DOS:*:*) + echo ${UNAME_MACHINE}-pc-msdosdjgpp + exit 0 ;; + 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 0 ;; + i*86:*:5:[78]*) + 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 0 ;; + i*86:*:3.2:*) + if test -f /usr/options/cb.name; then + UNAME_REL=`sed -n 's/.*Version //p' /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 0 ;; + 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 0 ;; + Intel:Mach:3*:*) + echo i386-pc-mach3 + exit 0 ;; + paragon:*:*:*) + echo i860-intel-osf1 + exit 0 ;; + 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 0 ;; + mini*:CTIX:SYS*5:*) + # "miniframe" + echo m68010-convergent-sysv + exit 0 ;; + mc68k:UNIX:SYSTEM5:3.51m) + echo m68k-convergent-sysv + exit 0 ;; + M680?0:D-NIX:5.3:*) + echo m68k-diab-dnix + exit 0 ;; + M68*:*:R3V[5678]*:*) + test -r /sysV68 && echo 'm68k-motorola-sysv' && exit 0 ;; + 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) + 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 0 + /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ + && echo i586-ncr-sysv4.3${OS_REL} && exit 0 ;; + 3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*) + /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ + && echo i486-ncr-sysv4 && exit 0 ;; + m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*) + echo m68k-unknown-lynxos${UNAME_RELEASE} + exit 0 ;; + mc68030:UNIX_System_V:4.*:*) + echo m68k-atari-sysv4 + exit 0 ;; + TSUNAMI:LynxOS:2.*:*) + echo sparc-unknown-lynxos${UNAME_RELEASE} + exit 0 ;; + rs6000:LynxOS:2.*:*) + echo rs6000-unknown-lynxos${UNAME_RELEASE} + exit 0 ;; + PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.0*:*) + echo powerpc-unknown-lynxos${UNAME_RELEASE} + exit 0 ;; + SM[BE]S:UNIX_SV:*:*) + echo mips-dde-sysv${UNAME_RELEASE} + exit 0 ;; + RM*:ReliantUNIX-*:*:*) + echo mips-sni-sysv4 + exit 0 ;; + RM*:SINIX-*:*:*) + echo mips-sni-sysv4 + exit 0 ;; + *: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 0 ;; + PENTIUM:*:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort + # says + echo i586-unisys-sysv4 + exit 0 ;; + *:UNIX_System_V:4*:FTX*) + # From Gerald Hewes . + # How about differentiating between stratus architectures? -djm + echo hppa1.1-stratus-sysv4 + exit 0 ;; + *:*:*:FTX*) + # From seanf@swdc.stratus.com. + echo i860-stratus-sysv4 + exit 0 ;; + *:VOS:*:*) + # From Paul.Green@stratus.com. + echo hppa1.1-stratus-vos + exit 0 ;; + mc68*:A/UX:*:*) + echo m68k-apple-aux${UNAME_RELEASE} + exit 0 ;; + news*:NEWS-OS:6*:*) + echo mips-sony-newsos6 + exit 0 ;; + 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 0 ;; + BeBox:BeOS:*:*) # BeOS running on hardware made by Be, PPC only. + echo powerpc-be-beos + exit 0 ;; + BeMac:BeOS:*:*) # BeOS running on Mac or Mac clone, PPC only. + echo powerpc-apple-beos + exit 0 ;; + BePC:BeOS:*:*) # BeOS running on Intel PC compatible. + echo i586-pc-beos + exit 0 ;; + SX-4:SUPER-UX:*:*) + echo sx4-nec-superux${UNAME_RELEASE} + exit 0 ;; + SX-5:SUPER-UX:*:*) + echo sx5-nec-superux${UNAME_RELEASE} + exit 0 ;; + SX-6:SUPER-UX:*:*) + echo sx6-nec-superux${UNAME_RELEASE} + exit 0 ;; + Power*:Rhapsody:*:*) + echo powerpc-apple-rhapsody${UNAME_RELEASE} + exit 0 ;; + *:Rhapsody:*:*) + echo ${UNAME_MACHINE}-apple-rhapsody${UNAME_RELEASE} + exit 0 ;; + *:Darwin:*:*) + case `uname -p` in + *86) UNAME_PROCESSOR=i686 ;; + powerpc) UNAME_PROCESSOR=powerpc ;; + esac + echo ${UNAME_PROCESSOR}-apple-darwin${UNAME_RELEASE} + exit 0 ;; + *: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 0 ;; + *:QNX:*:4*) + echo i386-pc-qnx + exit 0 ;; + NSR-?:NONSTOP_KERNEL:*:*) + echo nsr-tandem-nsk${UNAME_RELEASE} + exit 0 ;; + *:NonStop-UX:*:*) + echo mips-compaq-nonstopux + exit 0 ;; + BS2000:POSIX*:*:*) + echo bs2000-siemens-sysv + exit 0 ;; + DS/*:UNIX_System_V:*:*) + echo ${UNAME_MACHINE}-${UNAME_SYSTEM}-${UNAME_RELEASE} + exit 0 ;; + *: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 0 ;; + *:TOPS-10:*:*) + echo pdp10-unknown-tops10 + exit 0 ;; + *:TENEX:*:*) + echo pdp10-unknown-tenex + exit 0 ;; + KS10:TOPS-20:*:* | KL10:TOPS-20:*:* | TYPE4:TOPS-20:*:*) + echo pdp10-dec-tops20 + exit 0 ;; + XKL-1:TOPS-20:*:* | TYPE5:TOPS-20:*:*) + echo pdp10-xkl-tops20 + exit 0 ;; + *:TOPS-20:*:*) + echo pdp10-unknown-tops20 + exit 0 ;; + *:ITS:*:*) + echo pdp10-unknown-its + exit 0 ;; + SEI:*:*:SEIUX) + echo mips-sei-seiux${UNAME_RELEASE} + exit 0 ;; + *:DragonFly:*:*) + echo ${UNAME_MACHINE}-unknown-dragonfly`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` + exit 0 ;; +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 < +# include +#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 + 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"); 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 +# 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 && $dummy && exit 0 + +# Apollos put the system type in the environment. + +test -d /usr/apollo && { echo ${ISP}-apollo-${SYSTYPE}; exit 0; } + +# 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 0 ;; + c2*) + if getsysinfo -f scalar_acc + then echo c32-convex-bsd + else echo c2-convex-bsd + fi + exit 0 ;; + c34*) + echo c34-convex-bsd + exit 0 ;; + c38*) + echo c38-convex-bsd + exit 0 ;; + c4*) + echo c4-convex-bsd + exit 0 ;; + esac +fi + +cat >&2 < 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 index 0000000..ba33103 --- /dev/null +++ b/config.sub @@ -0,0 +1,1549 @@ +#! /bin/sh +# Configuration validation subroutine script. +# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, +# 2000, 2001, 2002, 2003 Free Software Foundation, Inc. + +timestamp='2004-03-12' + +# 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., 59 Temple Place - Suite 330, +# Boston, MA 02111-1307, 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 . 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 ." + +version="\ +GNU config.sub ($timestamp) + +Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001 +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 0 ;; + --version | -v ) + echo "$version" ; exit 0 ;; + --help | --h* | -h ) + echo "$usage"; exit 0 ;; + -- ) # 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 0;; + + * ) + 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-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) + 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 + ;; + -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/'` + ;; + -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 \ + | 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 | mcore \ + | mips | mipsbe | mipseb | mipsel | mipsle \ + | mips16 \ + | mips64 | mips64el \ + | mips64vr | mips64vrel \ + | mips64orion | mips64orionel \ + | mips64vr4100 | mips64vr4100el \ + | mips64vr4300 | mips64vr4300el \ + | mips64vr5000 | mips64vr5000el \ + | mipsisa32 | mipsisa32el \ + | mipsisa32r2 | mipsisa32r2el \ + | mipsisa64 | mipsisa64el \ + | mipsisa64r2 | mipsisa64r2el \ + | mipsisa64sb1 | mipsisa64sb1el \ + | mipsisa64sr71k | mipsisa64sr71kel \ + | mipstx39 | mipstx39el \ + | mn10200 | mn10300 \ + | msp430 \ + | ns16k | ns32k \ + | openrisc | or32 \ + | pdp10 | pdp11 | pj | pjl \ + | powerpc | powerpc64 | powerpc64le | powerpcle | ppcbe \ + | pyramid \ + | sh | sh[1234] | sh[23]e | sh[34]eb | shbe | shle | sh[1234]le | sh3ele \ + | sh64 | sh64le \ + | sparc | sparc64 | sparc86x | sparclet | sparclite | sparcv8 | sparcv9 | sparcv9b \ + | strongarm \ + | tahoe | thumb | tic4x | tic80 | tron \ + | v850 | v850e \ + | we32k \ + | x86 | xscale | xstormy16 | xtensa \ + | z8k) + 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) + ;; + + # 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-* \ + | bs2000-* \ + | c[123]* | c30-* | [cjt]90-* | c4x-* | c54x-* | c55x-* | c6x-* \ + | clipper-* | 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-* | mcore-* \ + | mips-* | mipsbe-* | mipseb-* | mipsel-* | mipsle-* \ + | mips16-* \ + | mips64-* | mips64el-* \ + | mips64vr-* | mips64vrel-* \ + | mips64orion-* | mips64orionel-* \ + | mips64vr4100-* | mips64vr4100el-* \ + | mips64vr4300-* | mips64vr4300el-* \ + | mips64vr5000-* | mips64vr5000el-* \ + | mipsisa32-* | mipsisa32el-* \ + | mipsisa32r2-* | mipsisa32r2el-* \ + | mipsisa64-* | mipsisa64el-* \ + | mipsisa64r2-* | mipsisa64r2el-* \ + | mipsisa64sb1-* | mipsisa64sb1el-* \ + | mipsisa64sr71k-* | mipsisa64sr71kel-* \ + | mipstx39-* | mipstx39el-* \ + | msp430-* \ + | none-* | np1-* | nv1-* | ns16k-* | ns32k-* \ + | orion-* \ + | pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \ + | powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* | ppcbe-* \ + | pyramid-* \ + | romp-* | rs6000-* \ + | sh-* | sh[1234]-* | sh[23]e-* | sh[34]eb-* | shbe-* \ + | shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \ + | sparc-* | sparc64-* | sparc86x-* | sparclet-* | sparclite-* \ + | sparcv8-* | sparcv9-* | sparcv9b-* | strongarm-* | sv1-* | sx?-* \ + | tahoe-* | thumb-* \ + | tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* \ + | tron-* \ + | v850-* | v850e-* | vax-* \ + | we32k-* \ + | x86-* | x86_64-* | xps100-* | xscale-* | xstormy16-* \ + | xtensa-* \ + | ymp-* \ + | z8k-*) + ;; + # 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 + ;; + cr16c) + basic_machine=cr16c-unknown + os=-elf + ;; + crds | unos) + basic_machine=m68k-crds + ;; + 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 + ;; + 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 + ;; + mmix*) + basic_machine=mmix-knuth + os=-mmixware + ;; + monitor) + basic_machine=m68k-rom68k + os=-coff + ;; + morphos) + basic_machine=powerpc-unknown + os=-morphos + ;; + msdos) + basic_machine=i386-pc + os=-msdos + ;; + 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 + ;; + nv1) + basic_machine=nv1-cray + os=-unicosmp + ;; + nsr-tandem) + basic_machine=nsr-tandem + ;; + op50n-* | op60c-*) + basic_machine=hppa1.1-oki + os=-proelf + ;; + or32 | or32-*) + basic_machine=or32-unknown + os=-coff + ;; + 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 + ;; + 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 + ;; + 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 + ;; + 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 + ;; + 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 + ;; + sh3 | sh4 | sh[34]eb | sh[1234]le | sh[23]ele) + basic_machine=sh-unknown + ;; + sh64) + basic_machine=sh64-unknown + ;; + sparc | sparcv8 | sparcv9 | sparcv9b) + 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* \ + | -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-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*) + # 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* \ + | -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 + ;; + -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 + ;; + *-ibm) + os=-aix + ;; + *-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 0 + +# 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 index 0000000..b83f07d --- /dev/null +++ b/configure @@ -0,0 +1,7573 @@ +#! /bin/sh +# Guess values for system-dependent variables and create Makefiles. +# Generated by GNU Autoconf 2.59. +# +# Copyright (C) 2003 Free Software Foundation, Inc. +# This configure script is free software; the Free Software Foundation +# gives unlimited permission to copy, distribute and modify it. +## --------------------- ## +## M4sh Initialization. ## +## --------------------- ## + +# Be Bourne compatible +if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then + emulate sh + NULLCMD=: + # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which + # is contrary to our usage. Disable this feature. + alias -g '${1+"$@"}'='"$@"' +elif test -n "${BASH_VERSION+set}" && (set -o posix) >/dev/null 2>&1; then + set -o posix +fi +DUALCASE=1; export DUALCASE # for MKS sh + +# Support unset when possible. +if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then + as_unset=unset +else + as_unset=false +fi + + +# Work around bugs in pre-3.0 UWIN ksh. +$as_unset ENV MAIL MAILPATH +PS1='$ ' +PS2='> ' +PS4='+ ' + +# NLS nuisances. +for as_var in \ + LANG LANGUAGE LC_ADDRESS LC_ALL LC_COLLATE LC_CTYPE LC_IDENTIFICATION \ + LC_MEASUREMENT LC_MESSAGES LC_MONETARY LC_NAME LC_NUMERIC LC_PAPER \ + LC_TELEPHONE LC_TIME +do + if (set +x; test -z "`(eval $as_var=C; export $as_var) 2>&1`"); then + eval $as_var=C; export $as_var + else + $as_unset $as_var + fi +done + +# Required to use basename. +if expr a : '\(a\)' >/dev/null 2>&1; then + as_expr=expr +else + as_expr=false +fi + +if (basename /) >/dev/null 2>&1 && test "X`basename / 2>&1`" = "X/"; then + as_basename=basename +else + as_basename=false +fi + + +# Name of the executable. +as_me=`$as_basename "$0" || +$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ + X"$0" : 'X\(//\)$' \| \ + X"$0" : 'X\(/\)$' \| \ + . : '\(.\)' 2>/dev/null || +echo X/"$0" | + sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/; q; } + /^X\/\(\/\/\)$/{ s//\1/; q; } + /^X\/\(\/\).*/{ s//\1/; q; } + s/.*/./; q'` + + +# PATH needs CR, and LINENO needs CR and PATH. +# Avoid depending upon Character Ranges. +as_cr_letters='abcdefghijklmnopqrstuvwxyz' +as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' +as_cr_Letters=$as_cr_letters$as_cr_LETTERS +as_cr_digits='0123456789' +as_cr_alnum=$as_cr_Letters$as_cr_digits + +# The user is always right. +if test "${PATH_SEPARATOR+set}" != set; then + echo "#! /bin/sh" >conf$$.sh + echo "exit 0" >>conf$$.sh + chmod +x conf$$.sh + if (PATH="/nonexistent;."; conf$$.sh) >/dev/null 2>&1; then + PATH_SEPARATOR=';' + else + PATH_SEPARATOR=: + fi + rm -f conf$$.sh +fi + + + as_lineno_1=$LINENO + as_lineno_2=$LINENO + as_lineno_3=`(expr $as_lineno_1 + 1) 2>/dev/null` + test "x$as_lineno_1" != "x$as_lineno_2" && + test "x$as_lineno_3" = "x$as_lineno_2" || { + # Find who we are. Look in the path if we contain no path at all + # relative or not. + case $0 in + *[\\/]* ) as_myself=$0 ;; + *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break +done + + ;; + esac + # We did not find ourselves, most probably we were run as `sh COMMAND' + # in which case we are not to be found in the path. + if test "x$as_myself" = x; then + as_myself=$0 + fi + if test ! -f "$as_myself"; then + { echo "$as_me: error: cannot find myself; rerun with an absolute path" >&2 + { (exit 1); exit 1; }; } + fi + case $CONFIG_SHELL in + '') + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for as_base in sh bash ksh sh5; do + case $as_dir in + /*) + if ("$as_dir/$as_base" -c ' + as_lineno_1=$LINENO + as_lineno_2=$LINENO + as_lineno_3=`(expr $as_lineno_1 + 1) 2>/dev/null` + test "x$as_lineno_1" != "x$as_lineno_2" && + test "x$as_lineno_3" = "x$as_lineno_2" ') 2>/dev/null; then + $as_unset BASH_ENV || test "${BASH_ENV+set}" != set || { BASH_ENV=; export BASH_ENV; } + $as_unset ENV || test "${ENV+set}" != set || { ENV=; export ENV; } + CONFIG_SHELL=$as_dir/$as_base + export CONFIG_SHELL + exec "$CONFIG_SHELL" "$0" ${1+"$@"} + fi;; + esac + done +done +;; + esac + + # Create $as_me.lineno as a copy of $as_myself, but with $LINENO + # uniformly replaced by the line number. The first 'sed' inserts a + # line-number line before each line; the second 'sed' does the real + # work. The second script uses 'N' to pair each line-number line + # with the numbered line, and appends trailing '-' during + # substitution so that $LINENO is not a special case at line end. + # (Raja R Harinath suggested sed '=', and Paul Eggert wrote the + # second 'sed' script. Blame Lee E. McMahon for sed's syntax. :-) + sed '=' <$as_myself | + sed ' + N + s,$,-, + : loop + s,^\(['$as_cr_digits']*\)\(.*\)[$]LINENO\([^'$as_cr_alnum'_]\),\1\2\1\3, + t loop + s,-$,, + s,^['$as_cr_digits']*\n,, + ' >$as_me.lineno && + chmod +x $as_me.lineno || + { echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2 + { (exit 1); exit 1; }; } + + # Don't try to exec as it changes $[0], causing all sort of problems + # (the dirname of $[0] is not the place where we might find the + # original and so on. Autoconf is especially sensible to this). + . ./$as_me.lineno + # Exit status is that of the last command. + exit +} + + +case `echo "testing\c"; echo 1,2,3`,`echo -n testing; echo 1,2,3` in + *c*,-n*) ECHO_N= ECHO_C=' +' ECHO_T=' ' ;; + *c*,* ) ECHO_N=-n ECHO_C= ECHO_T= ;; + *) ECHO_N= ECHO_C='\c' ECHO_T= ;; +esac + +if expr a : '\(a\)' >/dev/null 2>&1; then + as_expr=expr +else + as_expr=false +fi + +rm -f conf$$ conf$$.exe conf$$.file +echo >conf$$.file +if ln -s conf$$.file conf$$ 2>/dev/null; then + # We could just check for DJGPP; but this test a) works b) is more generic + # and c) will remain valid once DJGPP supports symlinks (DJGPP 2.04). + if test -f conf$$.exe; then + # Don't use ln at all; we don't have any links + as_ln_s='cp -p' + else + as_ln_s='ln -s' + fi +elif ln conf$$.file conf$$ 2>/dev/null; then + as_ln_s=ln +else + as_ln_s='cp -p' +fi +rm -f conf$$ conf$$.exe conf$$.file + +if mkdir -p . 2>/dev/null; then + as_mkdir_p=: +else + test -d ./-p && rmdir ./-p + as_mkdir_p=false +fi + +as_executable_p="test -f" + +# Sed expression to map a string onto a valid CPP name. +as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" + +# Sed expression to map a string onto a valid variable name. +as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" + + +# IFS +# We need space, tab and new line, in precisely that order. +as_nl=' +' +IFS=" $as_nl" + +# CDPATH. +$as_unset CDPATH + + +# Name of the host. +# hostname on some systems (SVR3.2, Linux) returns a bogus exit status, +# so uname gets run too. +ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q` + +exec 6>&1 + +# +# Initializations. +# +ac_default_prefix=/usr/local +ac_config_libobj_dir=. +cross_compiling=no +subdirs= +MFLAGS= +MAKEFLAGS= +SHELL=${CONFIG_SHELL-/bin/sh} + +# Maximum number of lines to put in a shell here document. +# This variable seems obsolete. It should probably be removed, and +# only ac_max_sed_lines should be used. +: ${ac_max_here_lines=38} + +# Identity of this package. +PACKAGE_NAME= +PACKAGE_TARNAME= +PACKAGE_VERSION= +PACKAGE_STRING= +PACKAGE_BUGREPORT= + +ac_unique_file="include/xmlrpc-c/base.h" +# Factoring default headers for most tests. +ac_includes_default="\ +#include +#if HAVE_SYS_TYPES_H +# include +#endif +#if HAVE_SYS_STAT_H +# include +#endif +#if STDC_HEADERS +# include +# include +#else +# if HAVE_STDLIB_H +# include +# endif +#endif +#if HAVE_STRING_H +# if !STDC_HEADERS && HAVE_MEMORY_H +# include +# endif +# include +#endif +#if HAVE_STRINGS_H +# include +#endif +#if HAVE_INTTYPES_H +# include +#else +# if HAVE_STDINT_H +# include +# endif +#endif +#if HAVE_UNISTD_H +# include +#endif" + +ac_subst_vars='SHELL PATH_SEPARATOR PACKAGE_NAME PACKAGE_TARNAME PACKAGE_VERSION PACKAGE_STRING PACKAGE_BUGREPORT exec_prefix prefix program_transform_name bindir sbindir libexecdir datadir sysconfdir sharedstatedir localstatedir libdir includedir oldincludedir infodir mandir build_alias host_alias target_alias DEFS ECHO_C ECHO_N ECHO_T LIBS INSTALL_PROGRAM INSTALL_SCRIPT INSTALL_DATA PACKAGE VERSION ACLOCAL AUTOCONF AUTOMAKE AUTOHEADER MAKEINFO SET_MAKE VERSION_INFO build build_cpu build_vendor build_os host host_cpu host_vendor host_os have_wininet_config MUST_BUILD_WININET_CLIENT have_curl_config MUST_BUILD_CURL_CLIENT have_libwww_config MUST_BUILD_LIBWWW_CLIENT LIBXMLRPC_CLIENT_LA CLIENTTEST XMLRPC_CLIENT_H XMLRPC_TRANSPORT_H SYNCH_CLIENT ASYNCH_CLIENT AUTH_CLIENT QUERY_MEERKAT ENABLE_ABYSS_SERVER ABYSS_SUBDIR LIBXMLRPC_ABYSS_SERVER_LA SERVERTEST VALIDATEE XMLRPC_ABYSS_H SERVER ENABLE_CGI_SERVER ENABLE_CPLUSPLUS LIBXMLRPC_CPP_A CPPTEST XMLRPCCPP_H XML_RPC_API2CPP_SUBDIR FEATURE_LIST CC CFLAGS LDFLAGS CPPFLAGS ac_ct_CC EXEEXT OBJEXT CXX CXXFLAGS ac_ct_CXX LSOCKET CPP EGREP HAVE_WCHAR_H_DEFINE HAVE_SYS_FILIO_H_DEFINE HAVE_SYS_IOCTL_H_DEFINE VA_LIST_IS_ARRAY_DEFINE ATTR_UNUSED DIRECTORY_SEPARATOR ENABLE_ABYSS_THREADS WININET_CONFIG WININET_CFLAGS WININET_LDADD WININET_LIBDIR WININET_RPATH WININET_WL_RPATH LIBWWW_CONFIG LIBWWW_LDADD LIBWWW_LIBDIR LIBWWW_RPATH LIBWWW_WL_RPATH CURL_CONFIG CURL_LDADD CURL_LIBDIR CURL_RPATH CURL_WL_RPATH HAVE_LIBWWW_SSL_DEFINE have_xml2_config ENABLE_LIBXML2_BACKEND C_COMPILER_GNU CXX_COMPILER_GNU CC_WARN_FLAGS CPP_WARN_FLAGS BUILDDIR RANLIB ac_ct_RANLIB LN_S LIBTOOL LIBOBJS LTLIBOBJS' +ac_subst_files='' + +# Initialize some variables set by options. +ac_init_help= +ac_init_version=false +# The variables have the same names as the options, with +# dashes changed to underlines. +cache_file=/dev/null +exec_prefix=NONE +no_create= +no_recursion= +prefix=NONE +program_prefix=NONE +program_suffix=NONE +program_transform_name=s,x,x, +silent= +site= +srcdir= +verbose= +x_includes=NONE +x_libraries=NONE + +# Installation directory options. +# These are left unexpanded so users can "make install exec_prefix=/foo" +# and all the variables that are supposed to be based on exec_prefix +# by default will actually change. +# Use braces instead of parens because sh, perl, etc. also accept them. +bindir='${exec_prefix}/bin' +sbindir='${exec_prefix}/sbin' +libexecdir='${exec_prefix}/libexec' +datadir='${prefix}/share' +sysconfdir='${prefix}/etc' +sharedstatedir='${prefix}/com' +localstatedir='${prefix}/var' +libdir='${exec_prefix}/lib' +includedir='${prefix}/include' +oldincludedir='/usr/include' +infodir='${prefix}/info' +mandir='${prefix}/man' + +ac_prev= +for ac_option +do + # If the previous option needs an argument, assign it. + if test -n "$ac_prev"; then + eval "$ac_prev=\$ac_option" + ac_prev= + continue + fi + + ac_optarg=`expr "x$ac_option" : 'x[^=]*=\(.*\)'` + + # Accept the important Cygnus configure options, so we can diagnose typos. + + case $ac_option in + + -bindir | --bindir | --bindi | --bind | --bin | --bi) + ac_prev=bindir ;; + -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*) + bindir=$ac_optarg ;; + + -build | --build | --buil | --bui | --bu) + ac_prev=build_alias ;; + -build=* | --build=* | --buil=* | --bui=* | --bu=*) + build_alias=$ac_optarg ;; + + -cache-file | --cache-file | --cache-fil | --cache-fi \ + | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c) + ac_prev=cache_file ;; + -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \ + | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*) + cache_file=$ac_optarg ;; + + --config-cache | -C) + cache_file=config.cache ;; + + -datadir | --datadir | --datadi | --datad | --data | --dat | --da) + ac_prev=datadir ;; + -datadir=* | --datadir=* | --datadi=* | --datad=* | --data=* | --dat=* \ + | --da=*) + datadir=$ac_optarg ;; + + -disable-* | --disable-*) + ac_feature=`expr "x$ac_option" : 'x-*disable-\(.*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_feature" : ".*[^-_$as_cr_alnum]" >/dev/null && + { echo "$as_me: error: invalid feature name: $ac_feature" >&2 + { (exit 1); exit 1; }; } + ac_feature=`echo $ac_feature | sed 's/-/_/g'` + eval "enable_$ac_feature=no" ;; + + -enable-* | --enable-*) + ac_feature=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_feature" : ".*[^-_$as_cr_alnum]" >/dev/null && + { echo "$as_me: error: invalid feature name: $ac_feature" >&2 + { (exit 1); exit 1; }; } + ac_feature=`echo $ac_feature | sed 's/-/_/g'` + case $ac_option in + *=*) ac_optarg=`echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"`;; + *) ac_optarg=yes ;; + esac + eval "enable_$ac_feature='$ac_optarg'" ;; + + -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \ + | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \ + | --exec | --exe | --ex) + ac_prev=exec_prefix ;; + -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \ + | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \ + | --exec=* | --exe=* | --ex=*) + exec_prefix=$ac_optarg ;; + + -gas | --gas | --ga | --g) + # Obsolete; use --with-gas. + with_gas=yes ;; + + -help | --help | --hel | --he | -h) + ac_init_help=long ;; + -help=r* | --help=r* | --hel=r* | --he=r* | -hr*) + ac_init_help=recursive ;; + -help=s* | --help=s* | --hel=s* | --he=s* | -hs*) + ac_init_help=short ;; + + -host | --host | --hos | --ho) + ac_prev=host_alias ;; + -host=* | --host=* | --hos=* | --ho=*) + host_alias=$ac_optarg ;; + + -includedir | --includedir | --includedi | --included | --include \ + | --includ | --inclu | --incl | --inc) + ac_prev=includedir ;; + -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \ + | --includ=* | --inclu=* | --incl=* | --inc=*) + includedir=$ac_optarg ;; + + -infodir | --infodir | --infodi | --infod | --info | --inf) + ac_prev=infodir ;; + -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*) + infodir=$ac_optarg ;; + + -libdir | --libdir | --libdi | --libd) + ac_prev=libdir ;; + -libdir=* | --libdir=* | --libdi=* | --libd=*) + libdir=$ac_optarg ;; + + -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \ + | --libexe | --libex | --libe) + ac_prev=libexecdir ;; + -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \ + | --libexe=* | --libex=* | --libe=*) + libexecdir=$ac_optarg ;; + + -localstatedir | --localstatedir | --localstatedi | --localstated \ + | --localstate | --localstat | --localsta | --localst \ + | --locals | --local | --loca | --loc | --lo) + ac_prev=localstatedir ;; + -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \ + | --localstate=* | --localstat=* | --localsta=* | --localst=* \ + | --locals=* | --local=* | --loca=* | --loc=* | --lo=*) + localstatedir=$ac_optarg ;; + + -mandir | --mandir | --mandi | --mand | --man | --ma | --m) + ac_prev=mandir ;; + -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*) + mandir=$ac_optarg ;; + + -nfp | --nfp | --nf) + # Obsolete; use --without-fp. + with_fp=no ;; + + -no-create | --no-create | --no-creat | --no-crea | --no-cre \ + | --no-cr | --no-c | -n) + no_create=yes ;; + + -no-recursion | --no-recursion | --no-recursio | --no-recursi \ + | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) + no_recursion=yes ;; + + -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \ + | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \ + | --oldin | --oldi | --old | --ol | --o) + ac_prev=oldincludedir ;; + -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \ + | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \ + | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*) + oldincludedir=$ac_optarg ;; + + -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) + ac_prev=prefix ;; + -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*) + prefix=$ac_optarg ;; + + -program-prefix | --program-prefix | --program-prefi | --program-pref \ + | --program-pre | --program-pr | --program-p) + ac_prev=program_prefix ;; + -program-prefix=* | --program-prefix=* | --program-prefi=* \ + | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*) + program_prefix=$ac_optarg ;; + + -program-suffix | --program-suffix | --program-suffi | --program-suff \ + | --program-suf | --program-su | --program-s) + ac_prev=program_suffix ;; + -program-suffix=* | --program-suffix=* | --program-suffi=* \ + | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*) + program_suffix=$ac_optarg ;; + + -program-transform-name | --program-transform-name \ + | --program-transform-nam | --program-transform-na \ + | --program-transform-n | --program-transform- \ + | --program-transform | --program-transfor \ + | --program-transfo | --program-transf \ + | --program-trans | --program-tran \ + | --progr-tra | --program-tr | --program-t) + ac_prev=program_transform_name ;; + -program-transform-name=* | --program-transform-name=* \ + | --program-transform-nam=* | --program-transform-na=* \ + | --program-transform-n=* | --program-transform-=* \ + | --program-transform=* | --program-transfor=* \ + | --program-transfo=* | --program-transf=* \ + | --program-trans=* | --program-tran=* \ + | --progr-tra=* | --program-tr=* | --program-t=*) + program_transform_name=$ac_optarg ;; + + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil) + silent=yes ;; + + -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) + ac_prev=sbindir ;; + -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ + | --sbi=* | --sb=*) + sbindir=$ac_optarg ;; + + -sharedstatedir | --sharedstatedir | --sharedstatedi \ + | --sharedstated | --sharedstate | --sharedstat | --sharedsta \ + | --sharedst | --shareds | --shared | --share | --shar \ + | --sha | --sh) + ac_prev=sharedstatedir ;; + -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \ + | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \ + | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \ + | --sha=* | --sh=*) + sharedstatedir=$ac_optarg ;; + + -site | --site | --sit) + ac_prev=site ;; + -site=* | --site=* | --sit=*) + site=$ac_optarg ;; + + -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) + ac_prev=srcdir ;; + -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) + srcdir=$ac_optarg ;; + + -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \ + | --syscon | --sysco | --sysc | --sys | --sy) + ac_prev=sysconfdir ;; + -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \ + | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*) + sysconfdir=$ac_optarg ;; + + -target | --target | --targe | --targ | --tar | --ta | --t) + ac_prev=target_alias ;; + -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*) + target_alias=$ac_optarg ;; + + -v | -verbose | --verbose | --verbos | --verbo | --verb) + verbose=yes ;; + + -version | --version | --versio | --versi | --vers | -V) + ac_init_version=: ;; + + -with-* | --with-*) + ac_package=`expr "x$ac_option" : 'x-*with-\([^=]*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_package" : ".*[^-_$as_cr_alnum]" >/dev/null && + { echo "$as_me: error: invalid package name: $ac_package" >&2 + { (exit 1); exit 1; }; } + ac_package=`echo $ac_package| sed 's/-/_/g'` + case $ac_option in + *=*) ac_optarg=`echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"`;; + *) ac_optarg=yes ;; + esac + eval "with_$ac_package='$ac_optarg'" ;; + + -without-* | --without-*) + ac_package=`expr "x$ac_option" : 'x-*without-\(.*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_package" : ".*[^-_$as_cr_alnum]" >/dev/null && + { echo "$as_me: error: invalid package name: $ac_package" >&2 + { (exit 1); exit 1; }; } + ac_package=`echo $ac_package | sed 's/-/_/g'` + eval "with_$ac_package=no" ;; + + --x) + # Obsolete; use --with-x. + with_x=yes ;; + + -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \ + | --x-incl | --x-inc | --x-in | --x-i) + ac_prev=x_includes ;; + -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \ + | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*) + x_includes=$ac_optarg ;; + + -x-libraries | --x-libraries | --x-librarie | --x-librari \ + | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l) + ac_prev=x_libraries ;; + -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \ + | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*) + x_libraries=$ac_optarg ;; + + -*) { echo "$as_me: error: unrecognized option: $ac_option +Try \`$0 --help' for more information." >&2 + { (exit 1); exit 1; }; } + ;; + + *=*) + ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='` + # Reject names that are not valid shell variable names. + expr "x$ac_envvar" : ".*[^_$as_cr_alnum]" >/dev/null && + { echo "$as_me: error: invalid variable name: $ac_envvar" >&2 + { (exit 1); exit 1; }; } + ac_optarg=`echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` + eval "$ac_envvar='$ac_optarg'" + export $ac_envvar ;; + + *) + # FIXME: should be removed in autoconf 3.0. + echo "$as_me: WARNING: you should use --build, --host, --target" >&2 + expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null && + echo "$as_me: WARNING: invalid host type: $ac_option" >&2 + : ${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option} + ;; + + esac +done + +if test -n "$ac_prev"; then + ac_option=--`echo $ac_prev | sed 's/_/-/g'` + { echo "$as_me: error: missing argument to $ac_option" >&2 + { (exit 1); exit 1; }; } +fi + +# Be sure to have absolute paths. +for ac_var in exec_prefix prefix +do + eval ac_val=$`echo $ac_var` + case $ac_val in + [\\/$]* | ?:[\\/]* | NONE | '' ) ;; + *) { echo "$as_me: error: expected an absolute directory name for --$ac_var: $ac_val" >&2 + { (exit 1); exit 1; }; };; + esac +done + +# Be sure to have absolute paths. +for ac_var in bindir sbindir libexecdir datadir sysconfdir sharedstatedir \ + localstatedir libdir includedir oldincludedir infodir mandir +do + eval ac_val=$`echo $ac_var` + case $ac_val in + [\\/$]* | ?:[\\/]* ) ;; + *) { echo "$as_me: error: expected an absolute directory name for --$ac_var: $ac_val" >&2 + { (exit 1); exit 1; }; };; + esac +done + +# There might be people who depend on the old broken behavior: `$host' +# used to hold the argument of --host etc. +# FIXME: To remove some day. +build=$build_alias +host=$host_alias +target=$target_alias + +# FIXME: To remove some day. +if test "x$host_alias" != x; then + if test "x$build_alias" = x; then + cross_compiling=maybe + echo "$as_me: WARNING: If you wanted to set the --build type, don't use --host. + If a cross compiler is detected then cross compile mode will be used." >&2 + elif test "x$build_alias" != "x$host_alias"; then + cross_compiling=yes + fi +fi + +ac_tool_prefix= +test -n "$host_alias" && ac_tool_prefix=$host_alias- + +test "$silent" = yes && exec 6>/dev/null + + +# Find the source files, if location was not specified. +if test -z "$srcdir"; then + ac_srcdir_defaulted=yes + # Try the directory containing this script, then its parent. + ac_confdir=`(dirname "$0") 2>/dev/null || +$as_expr X"$0" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$0" : 'X\(//\)[^/]' \| \ + X"$0" : 'X\(//\)$' \| \ + X"$0" : 'X\(/\)' \| \ + . : '\(.\)' 2>/dev/null || +echo X"$0" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; } + /^X\(\/\/\)[^/].*/{ s//\1/; q; } + /^X\(\/\/\)$/{ s//\1/; q; } + /^X\(\/\).*/{ s//\1/; q; } + s/.*/./; q'` + srcdir=$ac_confdir + if test ! -r $srcdir/$ac_unique_file; then + srcdir=.. + fi +else + ac_srcdir_defaulted=no +fi +if test ! -r $srcdir/$ac_unique_file; then + if test "$ac_srcdir_defaulted" = yes; then + { echo "$as_me: error: cannot find sources ($ac_unique_file) in $ac_confdir or .." >&2 + { (exit 1); exit 1; }; } + else + { echo "$as_me: error: cannot find sources ($ac_unique_file) in $srcdir" >&2 + { (exit 1); exit 1; }; } + fi +fi +(cd $srcdir && test -r ./$ac_unique_file) 2>/dev/null || + { echo "$as_me: error: sources are in $srcdir, but \`cd $srcdir' does not work" >&2 + { (exit 1); exit 1; }; } +srcdir=`echo "$srcdir" | sed 's%\([^\\/]\)[\\/]*$%\1%'` +ac_env_build_alias_set=${build_alias+set} +ac_env_build_alias_value=$build_alias +ac_cv_env_build_alias_set=${build_alias+set} +ac_cv_env_build_alias_value=$build_alias +ac_env_host_alias_set=${host_alias+set} +ac_env_host_alias_value=$host_alias +ac_cv_env_host_alias_set=${host_alias+set} +ac_cv_env_host_alias_value=$host_alias +ac_env_target_alias_set=${target_alias+set} +ac_env_target_alias_value=$target_alias +ac_cv_env_target_alias_set=${target_alias+set} +ac_cv_env_target_alias_value=$target_alias +ac_env_CC_set=${CC+set} +ac_env_CC_value=$CC +ac_cv_env_CC_set=${CC+set} +ac_cv_env_CC_value=$CC +ac_env_CFLAGS_set=${CFLAGS+set} +ac_env_CFLAGS_value=$CFLAGS +ac_cv_env_CFLAGS_set=${CFLAGS+set} +ac_cv_env_CFLAGS_value=$CFLAGS +ac_env_LDFLAGS_set=${LDFLAGS+set} +ac_env_LDFLAGS_value=$LDFLAGS +ac_cv_env_LDFLAGS_set=${LDFLAGS+set} +ac_cv_env_LDFLAGS_value=$LDFLAGS +ac_env_CPPFLAGS_set=${CPPFLAGS+set} +ac_env_CPPFLAGS_value=$CPPFLAGS +ac_cv_env_CPPFLAGS_set=${CPPFLAGS+set} +ac_cv_env_CPPFLAGS_value=$CPPFLAGS +ac_env_CXX_set=${CXX+set} +ac_env_CXX_value=$CXX +ac_cv_env_CXX_set=${CXX+set} +ac_cv_env_CXX_value=$CXX +ac_env_CXXFLAGS_set=${CXXFLAGS+set} +ac_env_CXXFLAGS_value=$CXXFLAGS +ac_cv_env_CXXFLAGS_set=${CXXFLAGS+set} +ac_cv_env_CXXFLAGS_value=$CXXFLAGS +ac_env_CPP_set=${CPP+set} +ac_env_CPP_value=$CPP +ac_cv_env_CPP_set=${CPP+set} +ac_cv_env_CPP_value=$CPP + +# +# Report the --help message. +# +if test "$ac_init_help" = "long"; then + # Omit some internal or obsolete options to make the list less imposing. + # This message is too long to be a string in the A/UX 3.1 sh. + cat <<_ACEOF +\`configure' configures this package to adapt to many kinds of systems. + +Usage: $0 [OPTION]... [VAR=VALUE]... + +To assign environment variables (e.g., CC, CFLAGS...), specify them as +VAR=VALUE. See below for descriptions of some of the useful variables. + +Defaults for the options are specified in brackets. + +Configuration: + -h, --help display this help and exit + --help=short display options specific to this package + --help=recursive display the short help of all the included packages + -V, --version display version information and exit + -q, --quiet, --silent do not print \`checking...' messages + --cache-file=FILE cache test results in FILE [disabled] + -C, --config-cache alias for \`--cache-file=config.cache' + -n, --no-create do not create output files + --srcdir=DIR find the sources in DIR [configure dir or \`..'] + +_ACEOF + + cat <<_ACEOF +Installation directories: + --prefix=PREFIX install architecture-independent files in PREFIX + [$ac_default_prefix] + --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX + [PREFIX] + +By default, \`make install' will install all the files in +\`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify +an installation prefix other than \`$ac_default_prefix' using \`--prefix', +for instance \`--prefix=\$HOME'. + +For better control, use the options below. + +Fine tuning of the installation directories: + --bindir=DIR user executables [EPREFIX/bin] + --sbindir=DIR system admin executables [EPREFIX/sbin] + --libexecdir=DIR program executables [EPREFIX/libexec] + --datadir=DIR read-only architecture-independent data [PREFIX/share] + --sysconfdir=DIR read-only single-machine data [PREFIX/etc] + --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com] + --localstatedir=DIR modifiable single-machine data [PREFIX/var] + --libdir=DIR object code libraries [EPREFIX/lib] + --includedir=DIR C header files [PREFIX/include] + --oldincludedir=DIR C header files for non-gcc [/usr/include] + --infodir=DIR info documentation [PREFIX/info] + --mandir=DIR man documentation [PREFIX/man] +_ACEOF + + cat <<\_ACEOF + +Program names: + --program-prefix=PREFIX prepend PREFIX to installed program names + --program-suffix=SUFFIX append SUFFIX to installed program names + --program-transform-name=PROGRAM run sed PROGRAM on installed program names + +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 + + cat <<\_ACEOF + +Optional Features: + --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no) + --enable-FEATURE[=ARG] include FEATURE [ARG=yes] + --disable-wininet-client Don't build the Wininet client transport + --disable-curl-client Don't build the Curl client transport + --disable-libwww-client Don't build the Libwww client transport + --disable-abyss-server Don't build the Abyss server module + --disable-cgi-server Don't build the CGI server module + --disable-cplusplus Don't build the C++ wrapper classes or tools + --disable-abyss-threads Use fork in Abyss instead of pthreads + --enable-libxml2-backend Use libxml2 instead of built-in expat + --enable-shared=PKGS build shared libraries default=yes + --enable-static=PKGS build static libraries default=yes + --enable-fast-install=PKGS optimize for fast installation default=yes + --disable-libtool-lock avoid locking (might break parallel builds) + +Optional Packages: + --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] + --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no) + --with-libwww-ssl Include libwww SSL capability. + + --with-gnu-ld assume the C compiler uses GNU ld default=no + +Some influential environment variables: + CC C compiler command + CFLAGS C compiler flags + LDFLAGS linker flags, e.g. -L if you have libraries in a + nonstandard directory + CPPFLAGS C/C++ preprocessor flags, e.g. -I if you have + headers in a nonstandard directory + CXX C++ compiler command + CXXFLAGS C++ compiler flags + CPP C preprocessor + +Use these variables to override the choices made by `configure' or to help +it to find libraries and programs with nonstandard names/locations. + +_ACEOF +fi + +if test "$ac_init_help" = "recursive"; then + # If there are subdirs, report their specific --help. + ac_popdir=`pwd` + for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue + test -d $ac_dir || continue + ac_builddir=. + +if test "$ac_dir" != .; then + ac_dir_suffix=/`echo "$ac_dir" | sed 's,^\.[\\/],,'` + # A "../" for each directory in $ac_dir_suffix. + ac_top_builddir=`echo "$ac_dir_suffix" | sed 's,/[^\\/]*,../,g'` +else + ac_dir_suffix= ac_top_builddir= +fi + +case $srcdir in + .) # No --srcdir option. We are building in place. + ac_srcdir=. + if test -z "$ac_top_builddir"; then + ac_top_srcdir=. + else + ac_top_srcdir=`echo $ac_top_builddir | sed 's,/$,,'` + fi ;; + [\\/]* | ?:[\\/]* ) # Absolute path. + ac_srcdir=$srcdir$ac_dir_suffix; + ac_top_srcdir=$srcdir ;; + *) # Relative path. + ac_srcdir=$ac_top_builddir$srcdir$ac_dir_suffix + ac_top_srcdir=$ac_top_builddir$srcdir ;; +esac + +# Do not use `cd foo && pwd` to compute absolute paths, because +# the directories may not exist. +case `pwd` in +.) ac_abs_builddir="$ac_dir";; +*) + case "$ac_dir" in + .) ac_abs_builddir=`pwd`;; + [\\/]* | ?:[\\/]* ) ac_abs_builddir="$ac_dir";; + *) ac_abs_builddir=`pwd`/"$ac_dir";; + esac;; +esac +case $ac_abs_builddir in +.) ac_abs_top_builddir=${ac_top_builddir}.;; +*) + case ${ac_top_builddir}. in + .) ac_abs_top_builddir=$ac_abs_builddir;; + [\\/]* | ?:[\\/]* ) ac_abs_top_builddir=${ac_top_builddir}.;; + *) ac_abs_top_builddir=$ac_abs_builddir/${ac_top_builddir}.;; + esac;; +esac +case $ac_abs_builddir in +.) ac_abs_srcdir=$ac_srcdir;; +*) + case $ac_srcdir in + .) ac_abs_srcdir=$ac_abs_builddir;; + [\\/]* | ?:[\\/]* ) ac_abs_srcdir=$ac_srcdir;; + *) ac_abs_srcdir=$ac_abs_builddir/$ac_srcdir;; + esac;; +esac +case $ac_abs_builddir in +.) ac_abs_top_srcdir=$ac_top_srcdir;; +*) + case $ac_top_srcdir in + .) ac_abs_top_srcdir=$ac_abs_builddir;; + [\\/]* | ?:[\\/]* ) ac_abs_top_srcdir=$ac_top_srcdir;; + *) ac_abs_top_srcdir=$ac_abs_builddir/$ac_top_srcdir;; + esac;; +esac + + cd $ac_dir + # Check for guested configure; otherwise get Cygnus style configure. + if test -f $ac_srcdir/configure.gnu; then + echo + $SHELL $ac_srcdir/configure.gnu --help=recursive + elif test -f $ac_srcdir/configure; then + echo + $SHELL $ac_srcdir/configure --help=recursive + elif test -f $ac_srcdir/configure.ac || + test -f $ac_srcdir/configure.in; then + echo + $ac_configure --help + else + echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2 + fi + cd $ac_popdir + done +fi + +test -n "$ac_init_help" && exit 0 +if $ac_init_version; then + cat <<\_ACEOF + +Copyright (C) 2003 Free Software Foundation, Inc. +This configure script is free software; the Free Software Foundation +gives unlimited permission to copy, distribute and modify it. +_ACEOF + exit 0 +fi +exec 5>config.log +cat >&5 <<_ACEOF +This file contains any messages produced by compilers while +running configure, to aid debugging if configure makes a mistake. + +It was created by $as_me, which was +generated by GNU Autoconf 2.59. Invocation command line was + + $ $0 $@ + +_ACEOF +{ +cat <<_ASUNAME +## --------- ## +## Platform. ## +## --------- ## + +hostname = `(hostname || uname -n) 2>/dev/null | sed 1q` +uname -m = `(uname -m) 2>/dev/null || echo unknown` +uname -r = `(uname -r) 2>/dev/null || echo unknown` +uname -s = `(uname -s) 2>/dev/null || echo unknown` +uname -v = `(uname -v) 2>/dev/null || echo unknown` + +/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown` +/bin/uname -X = `(/bin/uname -X) 2>/dev/null || echo unknown` + +/bin/arch = `(/bin/arch) 2>/dev/null || echo unknown` +/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null || echo unknown` +/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown` +hostinfo = `(hostinfo) 2>/dev/null || echo unknown` +/bin/machine = `(/bin/machine) 2>/dev/null || echo unknown` +/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null || echo unknown` +/bin/universe = `(/bin/universe) 2>/dev/null || echo unknown` + +_ASUNAME + +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + echo "PATH: $as_dir" +done + +} >&5 + +cat >&5 <<_ACEOF + + +## ----------- ## +## Core tests. ## +## ----------- ## + +_ACEOF + + +# Keep a trace of the command line. +# Strip out --no-create and --no-recursion so they do not pile up. +# Strip out --silent because we don't want to record it for future runs. +# Also quote any args containing shell meta-characters. +# Make two passes to allow for proper duplicate-argument suppression. +ac_configure_args= +ac_configure_args0= +ac_configure_args1= +ac_sep= +ac_must_keep_next=false +for ac_pass in 1 2 +do + for ac_arg + do + case $ac_arg in + -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;; + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil) + continue ;; + *" "*|*" "*|*[\[\]\~\#\$\^\&\*\(\)\{\}\\\|\;\<\>\?\"\']*) + ac_arg=`echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; + esac + case $ac_pass in + 1) ac_configure_args0="$ac_configure_args0 '$ac_arg'" ;; + 2) + ac_configure_args1="$ac_configure_args1 '$ac_arg'" + if test $ac_must_keep_next = true; then + ac_must_keep_next=false # Got value, back to normal. + else + case $ac_arg in + *=* | --config-cache | -C | -disable-* | --disable-* \ + | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \ + | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \ + | -with-* | --with-* | -without-* | --without-* | --x) + case "$ac_configure_args0 " in + "$ac_configure_args1"*" '$ac_arg' "* ) continue ;; + esac + ;; + -* ) ac_must_keep_next=true ;; + esac + fi + ac_configure_args="$ac_configure_args$ac_sep'$ac_arg'" + # Get rid of the leading space. + ac_sep=" " + ;; + esac + done +done +$as_unset ac_configure_args0 || test "${ac_configure_args0+set}" != set || { ac_configure_args0=; export ac_configure_args0; } +$as_unset ac_configure_args1 || test "${ac_configure_args1+set}" != set || { ac_configure_args1=; export ac_configure_args1; } + +# When interrupted or exit'd, cleanup temporary files, and complete +# config.log. We remove comments because anyway the quotes in there +# would cause problems or look ugly. +# WARNING: Be sure not to use single quotes in there, as some shells, +# such as our DU 5.0 friend, will then `close' the trap. +trap 'exit_status=$? + # Save into config.log some information that might help in debugging. + { + echo + + cat <<\_ASBOX +## ---------------- ## +## Cache variables. ## +## ---------------- ## +_ASBOX + echo + # The following way of writing the cache mishandles newlines in values, +{ + (set) 2>&1 | + case `(ac_space='"'"' '"'"'; set | grep ac_space) 2>&1` in + *ac_space=\ *) + sed -n \ + "s/'"'"'/'"'"'\\\\'"'"''"'"'/g; + s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='"'"'\\2'"'"'/p" + ;; + *) + sed -n \ + "s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1=\\2/p" + ;; + esac; +} + echo + + cat <<\_ASBOX +## ----------------- ## +## Output variables. ## +## ----------------- ## +_ASBOX + echo + for ac_var in $ac_subst_vars + do + eval ac_val=$`echo $ac_var` + echo "$ac_var='"'"'$ac_val'"'"'" + done | sort + echo + + if test -n "$ac_subst_files"; then + cat <<\_ASBOX +## ------------- ## +## Output files. ## +## ------------- ## +_ASBOX + echo + for ac_var in $ac_subst_files + do + eval ac_val=$`echo $ac_var` + echo "$ac_var='"'"'$ac_val'"'"'" + done | sort + echo + fi + + if test -s confdefs.h; then + cat <<\_ASBOX +## ----------- ## +## confdefs.h. ## +## ----------- ## +_ASBOX + echo + sed "/^$/d" confdefs.h | sort + echo + fi + test "$ac_signal" != 0 && + echo "$as_me: caught signal $ac_signal" + echo "$as_me: exit $exit_status" + } >&5 + rm -f core *.core && + rm -rf conftest* confdefs* conf$$* $ac_clean_files && + exit $exit_status + ' 0 +for ac_signal in 1 2 13 15; do + trap 'ac_signal='$ac_signal'; { (exit 1); exit 1; }' $ac_signal +done +ac_signal=0 + +# confdefs.h avoids OS command line length limits that DEFS can exceed. +rm -rf conftest* confdefs.h +# AIX cpp loses on an empty file, so make sure it contains at least a newline. +echo >confdefs.h + +# Predefined preprocessor variables. + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_NAME "$PACKAGE_NAME" +_ACEOF + + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_TARNAME "$PACKAGE_TARNAME" +_ACEOF + + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_VERSION "$PACKAGE_VERSION" +_ACEOF + + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_STRING "$PACKAGE_STRING" +_ACEOF + + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT" +_ACEOF + + +# Let the site file select an alternate cache file if it wants to. +# Prefer explicitly selected file to automatically selected ones. +if test -z "$CONFIG_SITE"; then + if test "x$prefix" != xNONE; then + CONFIG_SITE="$prefix/share/config.site $prefix/etc/config.site" + else + CONFIG_SITE="$ac_default_prefix/share/config.site $ac_default_prefix/etc/config.site" + fi +fi +for ac_site_file in $CONFIG_SITE; do + if test -r "$ac_site_file"; then + { echo "$as_me:$LINENO: loading site script $ac_site_file" >&5 +echo "$as_me: loading site script $ac_site_file" >&6;} + sed 's/^/| /' "$ac_site_file" >&5 + . "$ac_site_file" + fi +done + +if test -r "$cache_file"; then + # Some versions of bash will fail to source /dev/null (special + # files actually), so we avoid doing that. + if test -f "$cache_file"; then + { echo "$as_me:$LINENO: loading cache $cache_file" >&5 +echo "$as_me: loading cache $cache_file" >&6;} + case $cache_file in + [\\/]* | ?:[\\/]* ) . $cache_file;; + *) . ./$cache_file;; + esac + fi +else + { echo "$as_me:$LINENO: creating cache $cache_file" >&5 +echo "$as_me: creating cache $cache_file" >&6;} + >$cache_file +fi + +# Check that the precious variables saved in the cache have kept the same +# value. +ac_cache_corrupted=false +for ac_var in `(set) 2>&1 | + sed -n 's/^ac_env_\([a-zA-Z_0-9]*\)_set=.*/\1/p'`; do + eval ac_old_set=\$ac_cv_env_${ac_var}_set + eval ac_new_set=\$ac_env_${ac_var}_set + eval ac_old_val="\$ac_cv_env_${ac_var}_value" + eval ac_new_val="\$ac_env_${ac_var}_value" + case $ac_old_set,$ac_new_set in + set,) + { echo "$as_me:$LINENO: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5 +echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;} + ac_cache_corrupted=: ;; + ,set) + { echo "$as_me:$LINENO: error: \`$ac_var' was not set in the previous run" >&5 +echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;} + ac_cache_corrupted=: ;; + ,);; + *) + if test "x$ac_old_val" != "x$ac_new_val"; then + { echo "$as_me:$LINENO: error: \`$ac_var' has changed since the previous run:" >&5 +echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;} + { echo "$as_me:$LINENO: former value: $ac_old_val" >&5 +echo "$as_me: former value: $ac_old_val" >&2;} + { echo "$as_me:$LINENO: current value: $ac_new_val" >&5 +echo "$as_me: current value: $ac_new_val" >&2;} + ac_cache_corrupted=: + fi;; + esac + # Pass precious variables to config.status. + if test "$ac_new_set" = set; then + case $ac_new_val in + *" "*|*" "*|*[\[\]\~\#\$\^\&\*\(\)\{\}\\\|\;\<\>\?\"\']*) + ac_arg=$ac_var=`echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;; + *) ac_arg=$ac_var=$ac_new_val ;; + esac + case " $ac_configure_args " in + *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy. + *) ac_configure_args="$ac_configure_args '$ac_arg'" ;; + esac + fi +done +if $ac_cache_corrupted; then + { echo "$as_me:$LINENO: error: changes in the environment can compromise the build" >&5 +echo "$as_me: error: changes in the environment can compromise the build" >&2;} + { { echo "$as_me:$LINENO: error: run \`make distclean' and/or \`rm $cache_file' and start over" >&5 +echo "$as_me: error: run \`make distclean' and/or \`rm $cache_file' and start over" >&2;} + { (exit 1); exit 1; }; } +fi + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + + + + + + + + + + + + + + + + + + + + ac_config_headers="$ac_config_headers xmlrpc_amconfig.h" + + ac_config_commands="$ac_config_commands default-1" + + + +ac_aux_dir= +for ac_dir in $srcdir $srcdir/.. $srcdir/../..; do + if test -f $ac_dir/install-sh; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/install-sh -c" + break + elif test -f $ac_dir/install.sh; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/install.sh -c" + break + elif test -f $ac_dir/shtool; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/shtool install -c" + break + fi +done +if test -z "$ac_aux_dir"; then + { { echo "$as_me:$LINENO: error: cannot find install-sh or install.sh in $srcdir $srcdir/.. $srcdir/../.." >&5 +echo "$as_me: error: cannot find install-sh or install.sh in $srcdir $srcdir/.. $srcdir/../.." >&2;} + { (exit 1); exit 1; }; } +fi +ac_config_guess="$SHELL $ac_aux_dir/config.guess" +ac_config_sub="$SHELL $ac_aux_dir/config.sub" +ac_configure="$SHELL $ac_aux_dir/configure" # This should be Cygnus configure. + +# Find a good install program. We prefer a C program (faster), +# so one script is as good as another. But avoid the broken or +# incompatible versions: +# SysV /etc/install, /usr/sbin/install +# SunOS /usr/etc/install +# IRIX /sbin/install +# AIX /bin/install +# AmigaOS /C/install, which installs bootblocks on floppy discs +# AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag +# AFS /usr/afsws/bin/install, which mishandles nonexistent args +# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff" +# OS/2's system install, which has a completely different semantic +# ./install, which can be erroneously created by make from ./install.sh. +echo "$as_me:$LINENO: checking for a BSD-compatible install" >&5 +echo $ECHO_N "checking for a BSD-compatible install... $ECHO_C" >&6 +if test -z "$INSTALL"; then +if test "${ac_cv_path_install+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + # Account for people who put trailing slashes in PATH elements. +case $as_dir/ in + ./ | .// | /cC/* | \ + /etc/* | /usr/sbin/* | /usr/etc/* | /sbin/* | /usr/afsws/bin/* | \ + ?:\\/os2\\/install\\/* | ?:\\/OS2\\/INSTALL\\/* | \ + /usr/ucb/* ) ;; + *) + # OSF1 and SCO ODT 3.0 have their own names for install. + # Don't use installbsd from OSF since it installs stuff as root + # by default. + for ac_prog in ginstall scoinst install; do + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_prog$ac_exec_ext"; then + if test $ac_prog = install && + grep dspmsg "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then + # AIX install. It has an incompatible calling convention. + : + elif test $ac_prog = install && + grep pwplus "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then + # program-specific install script used by HP pwplus--don't use. + : + else + ac_cv_path_install="$as_dir/$ac_prog$ac_exec_ext -c" + break 3 + fi + fi + done + done + ;; +esac +done + + +fi + if test "${ac_cv_path_install+set}" = set; then + INSTALL=$ac_cv_path_install + else + # As a last resort, use the slow shell script. We don't cache a + # path for INSTALL within a source directory, because that will + # break other packages using the cache if that directory is + # removed, or if the path is relative. + INSTALL=$ac_install_sh + fi +fi +echo "$as_me:$LINENO: result: $INSTALL" >&5 +echo "${ECHO_T}$INSTALL" >&6 + +# Use test -z because SunOS4 sh mishandles braces in ${var-val}. +# It thinks the first close brace ends the variable substitution. +test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}' + +test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL}' + +test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644' + +echo "$as_me:$LINENO: checking whether build environment is sane" >&5 +echo $ECHO_N "checking whether build environment is sane... $ECHO_C" >&6 +# Just in case +sleep 1 +echo timestamp > conftestfile +# Do `set' in a subshell so we don't clobber the current shell's +# arguments. Must try -L first in case configure is actually a +# symlink; some systems play weird games with the mod time of symlinks +# (eg FreeBSD returns the mod time of the symlink's containing +# directory). +if ( + set X `ls -Lt $srcdir/configure conftestfile 2> /dev/null` + if test "$*" = "X"; then + # -L didn't work. + set X `ls -t $srcdir/configure conftestfile` + fi + if test "$*" != "X $srcdir/configure conftestfile" \ + && test "$*" != "X conftestfile $srcdir/configure"; then + + # If neither matched, then we have a broken ls. This can happen + # if, for instance, CONFIG_SHELL is bash and it inherits a + # broken ls alias from the environment. This has actually + # happened. Such a system could not be considered "sane". + { { echo "$as_me:$LINENO: error: ls -t appears to fail. Make sure there is not a broken +alias in your environment" >&5 +echo "$as_me: error: ls -t appears to fail. Make sure there is not a broken +alias in your environment" >&2;} + { (exit 1); exit 1; }; } + fi + + test "$2" = conftestfile + ) +then + # Ok. + : +else + { { echo "$as_me:$LINENO: error: newly created file is older than distributed files! +Check your system clock" >&5 +echo "$as_me: error: newly created file is older than distributed files! +Check your system clock" >&2;} + { (exit 1); exit 1; }; } +fi +rm -f conftest* +echo "$as_me:$LINENO: result: yes" >&5 +echo "${ECHO_T}yes" >&6 +test "$program_prefix" != NONE && + program_transform_name="s,^,$program_prefix,;$program_transform_name" +# Use a double $ so make ignores it. +test "$program_suffix" != NONE && + program_transform_name="s,\$,$program_suffix,;$program_transform_name" +# Double any \ or $. echo might interpret backslashes. +# By default was `s,x,x', remove it if useless. +cat <<\_ACEOF >conftest.sed +s/[\\$]/&&/g;s/;s,x,x,$// +_ACEOF +program_transform_name=`echo $program_transform_name | sed -f conftest.sed` +rm conftest.sed + +echo "$as_me:$LINENO: checking whether ${MAKE-make} sets \$(MAKE)" >&5 +echo $ECHO_N "checking whether ${MAKE-make} sets \$(MAKE)... $ECHO_C" >&6 +set dummy ${MAKE-make}; ac_make=`echo "$2" | sed 'y,:./+-,___p_,'` +if eval "test \"\${ac_cv_prog_make_${ac_make}_set+set}\" = set"; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.make <<\_ACEOF +all: + @echo 'ac_maketemp="$(MAKE)"' +_ACEOF +# GNU make sometimes prints "make[1]: Entering...", which would confuse us. +eval `${MAKE-make} -f conftest.make 2>/dev/null | grep temp=` +if test -n "$ac_maketemp"; then + eval ac_cv_prog_make_${ac_make}_set=yes +else + eval ac_cv_prog_make_${ac_make}_set=no +fi +rm -f conftest.make +fi +if eval "test \"`echo '$ac_cv_prog_make_'${ac_make}_set`\" = yes"; then + echo "$as_me:$LINENO: result: yes" >&5 +echo "${ECHO_T}yes" >&6 + SET_MAKE= +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 + SET_MAKE="MAKE=${MAKE-make}" +fi + + +PACKAGE=xmlrpc-c + +VERSION=1.06.32 + +if test "`cd $srcdir && pwd`" != "`pwd`" && test -f $srcdir/config.status; then + { { echo "$as_me:$LINENO: error: source directory already configured; run \"make distclean\" there first" >&5 +echo "$as_me: error: source directory already configured; run \"make distclean\" there first" >&2;} + { (exit 1); exit 1; }; } +fi + +cat >>confdefs.h <<_ACEOF +#define PACKAGE "$PACKAGE" +_ACEOF + + +cat >>confdefs.h <<_ACEOF +#define VERSION "$VERSION" +_ACEOF + + + +missing_dir=`cd $ac_aux_dir && pwd` +echo "$as_me:$LINENO: checking for working aclocal" >&5 +echo $ECHO_N "checking for working aclocal... $ECHO_C" >&6 +# Run test in a subshell; some versions of sh will print an error if +# an executable is not found, even if stderr is redirected. +# Redirect stdin to placate older versions of autoconf. Sigh. +if (aclocal --version) < /dev/null > /dev/null 2>&1; then + ACLOCAL=aclocal + echo "$as_me:$LINENO: result: found" >&5 +echo "${ECHO_T}found" >&6 +else + ACLOCAL="$missing_dir/missing aclocal" + echo "$as_me:$LINENO: result: missing" >&5 +echo "${ECHO_T}missing" >&6 +fi + +echo "$as_me:$LINENO: checking for working autoconf" >&5 +echo $ECHO_N "checking for working autoconf... $ECHO_C" >&6 +# Run test in a subshell; some versions of sh will print an error if +# an executable is not found, even if stderr is redirected. +# Redirect stdin to placate older versions of autoconf. Sigh. +if (autoconf --version) < /dev/null > /dev/null 2>&1; then + AUTOCONF=autoconf + echo "$as_me:$LINENO: result: found" >&5 +echo "${ECHO_T}found" >&6 +else + AUTOCONF="$missing_dir/missing autoconf" + echo "$as_me:$LINENO: result: missing" >&5 +echo "${ECHO_T}missing" >&6 +fi + +echo "$as_me:$LINENO: checking for working automake" >&5 +echo $ECHO_N "checking for working automake... $ECHO_C" >&6 +# Run test in a subshell; some versions of sh will print an error if +# an executable is not found, even if stderr is redirected. +# Redirect stdin to placate older versions of autoconf. Sigh. +if (automake --version) < /dev/null > /dev/null 2>&1; then + AUTOMAKE=automake + echo "$as_me:$LINENO: result: found" >&5 +echo "${ECHO_T}found" >&6 +else + AUTOMAKE="$missing_dir/missing automake" + echo "$as_me:$LINENO: result: missing" >&5 +echo "${ECHO_T}missing" >&6 +fi + +echo "$as_me:$LINENO: checking for working autoheader" >&5 +echo $ECHO_N "checking for working autoheader... $ECHO_C" >&6 +# Run test in a subshell; some versions of sh will print an error if +# an executable is not found, even if stderr is redirected. +# Redirect stdin to placate older versions of autoconf. Sigh. +if (autoheader --version) < /dev/null > /dev/null 2>&1; then + AUTOHEADER=autoheader + echo "$as_me:$LINENO: result: found" >&5 +echo "${ECHO_T}found" >&6 +else + AUTOHEADER="$missing_dir/missing autoheader" + echo "$as_me:$LINENO: result: missing" >&5 +echo "${ECHO_T}missing" >&6 +fi + +echo "$as_me:$LINENO: checking for working makeinfo" >&5 +echo $ECHO_N "checking for working makeinfo... $ECHO_C" >&6 +# Run test in a subshell; some versions of sh will print an error if +# an executable is not found, even if stderr is redirected. +# Redirect stdin to placate older versions of autoconf. Sigh. +if (makeinfo --version) < /dev/null > /dev/null 2>&1; then + MAKEINFO=makeinfo + echo "$as_me:$LINENO: result: found" >&5 +echo "${ECHO_T}found" >&6 +else + MAKEINFO="$missing_dir/missing makeinfo" + echo "$as_me:$LINENO: result: missing" >&5 +echo "${ECHO_T}missing" >&6 +fi + + + +VERSION_INFO="-version-info 7:0:6" + + +# Make sure we can run config.sub. +$ac_config_sub sun4 >/dev/null 2>&1 || + { { echo "$as_me:$LINENO: error: cannot run $ac_config_sub" >&5 +echo "$as_me: error: cannot run $ac_config_sub" >&2;} + { (exit 1); exit 1; }; } + +echo "$as_me:$LINENO: checking build system type" >&5 +echo $ECHO_N "checking build system type... $ECHO_C" >&6 +if test "${ac_cv_build+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_cv_build_alias=$build_alias +test -z "$ac_cv_build_alias" && + ac_cv_build_alias=`$ac_config_guess` +test -z "$ac_cv_build_alias" && + { { echo "$as_me:$LINENO: error: cannot guess build type; you must specify one" >&5 +echo "$as_me: error: cannot guess build type; you must specify one" >&2;} + { (exit 1); exit 1; }; } +ac_cv_build=`$ac_config_sub $ac_cv_build_alias` || + { { echo "$as_me:$LINENO: error: $ac_config_sub $ac_cv_build_alias failed" >&5 +echo "$as_me: error: $ac_config_sub $ac_cv_build_alias failed" >&2;} + { (exit 1); exit 1; }; } + +fi +echo "$as_me:$LINENO: result: $ac_cv_build" >&5 +echo "${ECHO_T}$ac_cv_build" >&6 +build=$ac_cv_build +build_cpu=`echo $ac_cv_build | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\1/'` +build_vendor=`echo $ac_cv_build | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\2/'` +build_os=`echo $ac_cv_build | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\3/'` + + +echo "$as_me:$LINENO: checking host system type" >&5 +echo $ECHO_N "checking host system type... $ECHO_C" >&6 +if test "${ac_cv_host+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_cv_host_alias=$host_alias +test -z "$ac_cv_host_alias" && + ac_cv_host_alias=$ac_cv_build_alias +ac_cv_host=`$ac_config_sub $ac_cv_host_alias` || + { { echo "$as_me:$LINENO: error: $ac_config_sub $ac_cv_host_alias failed" >&5 +echo "$as_me: error: $ac_config_sub $ac_cv_host_alias failed" >&2;} + { (exit 1); exit 1; }; } + +fi +echo "$as_me:$LINENO: result: $ac_cv_host" >&5 +echo "${ECHO_T}$ac_cv_host" >&6 +host=$ac_cv_host +host_cpu=`echo $ac_cv_host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\1/'` +host_vendor=`echo $ac_cv_host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\2/'` +host_os=`echo $ac_cv_host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\3/'` + + + +test -z "$target" && target=NONE + + +FEATURE_LIST= + +# Check whether --enable-wininet-client or --disable-wininet-client was given. +if test "${enable_wininet_client+set}" = set; then + enableval="$enable_wininet_client" + +else + enable_wininet_client=maybe +fi; + +if test $enable_wininet_client = maybe; then + # Extract the first word of "wininet-config", so it can be a program name with args. +set dummy wininet-config; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_have_wininet_config+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$have_wininet_config"; then + ac_cv_prog_have_wininet_config="$have_wininet_config" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_have_wininet_config="yes" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + + test -z "$ac_cv_prog_have_wininet_config" && ac_cv_prog_have_wininet_config="no" +fi +fi +have_wininet_config=$ac_cv_prog_have_wininet_config +if test -n "$have_wininet_config"; then + echo "$as_me:$LINENO: result: $have_wininet_config" >&5 +echo "${ECHO_T}$have_wininet_config" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + + if test $have_wininet_config = no; then + { echo "$as_me:$LINENO: You don't appear to have Wininet installed (no working wininet-config in your command search path), so we will not build the Wininet client XML transport" >&5 +echo "$as_me: You don't appear to have Wininet installed (no working wininet-config in your command search path), so we will not build the Wininet client XML transport" >&6;} + MUST_BUILD_WININET_CLIENT=no + else + MUST_BUILD_WININET_CLIENT=yes + fi +else + MUST_BUILD_WININET_CLIENT=$enable_wininet_client +fi + +echo "$as_me:$LINENO: checking whether to build Wininet client XML transport module" >&5 +echo $ECHO_N "checking whether to build Wininet client XML transport module... $ECHO_C" >&6 +echo "$as_me:$LINENO: result: $MUST_BUILD_WININET_CLIENT" >&5 +echo "${ECHO_T}$MUST_BUILD_WININET_CLIENT" >&6 + + + +# Check whether --enable-curl-client or --disable-curl-client was given. +if test "${enable_curl_client+set}" = set; then + enableval="$enable_curl_client" + +else + enable_curl_client=maybe +fi; + +if test $enable_curl_client = maybe; then + # Extract the first word of "curl-config", so it can be a program name with args. +set dummy curl-config; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_have_curl_config+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$have_curl_config"; then + ac_cv_prog_have_curl_config="$have_curl_config" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_have_curl_config="yes" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + + test -z "$ac_cv_prog_have_curl_config" && ac_cv_prog_have_curl_config="no" +fi +fi +have_curl_config=$ac_cv_prog_have_curl_config +if test -n "$have_curl_config"; then + echo "$as_me:$LINENO: result: $have_curl_config" >&5 +echo "${ECHO_T}$have_curl_config" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + + if test $have_curl_config = no; then + { echo "$as_me:$LINENO: You don't appear to have Curl installed (no working curl-config in your command search path), so we will not build the Curl client XML transport" >&5 +echo "$as_me: You don't appear to have Curl installed (no working curl-config in your command search path), so we will not build the Curl client XML transport" >&6;} + MUST_BUILD_CURL_CLIENT=no + else + MUST_BUILD_CURL_CLIENT=yes + fi +else + MUST_BUILD_CURL_CLIENT=$enable_curl_client +fi + +echo "$as_me:$LINENO: checking whether to build Curl client XML transport module" >&5 +echo $ECHO_N "checking whether to build Curl client XML transport module... $ECHO_C" >&6 +echo "$as_me:$LINENO: result: $MUST_BUILD_CURL_CLIENT" >&5 +echo "${ECHO_T}$MUST_BUILD_CURL_CLIENT" >&6 + + + +# Check whether --enable-libwww-client or --disable-libwww-client was given. +if test "${enable_libwww_client+set}" = set; then + enableval="$enable_libwww_client" + +else + enable_libwww_client=maybe +fi; + +if test $enable_libwww_client = maybe; then + # Extract the first word of "libwww-config", so it can be a program name with args. +set dummy libwww-config; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_have_libwww_config+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$have_libwww_config"; then + ac_cv_prog_have_libwww_config="$have_libwww_config" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_have_libwww_config="yes" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + + test -z "$ac_cv_prog_have_libwww_config" && ac_cv_prog_have_libwww_config="no" +fi +fi +have_libwww_config=$ac_cv_prog_have_libwww_config +if test -n "$have_libwww_config"; then + echo "$as_me:$LINENO: result: $have_libwww_config" >&5 +echo "${ECHO_T}$have_libwww_config" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + + if test $have_libwww_config = no; then + { echo "$as_me:$LINENO: You don't appear to have Libwww installed (no working libwww-config in your command search path), so we will not build the Libwww client XML transport" >&5 +echo "$as_me: You don't appear to have Libwww installed (no working libwww-config in your command search path), so we will not build the Libwww client XML transport" >&6;} + MUST_BUILD_LIBWWW_CLIENT=no + else + MUST_BUILD_LIBWWW_CLIENT=yes + fi +else + MUST_BUILD_LIBWWW_CLIENT=$enable_libwww_client +fi + +echo "$as_me:$LINENO: checking whether to build Libwww client XML transport module" >&5 +echo $ECHO_N "checking whether to build Libwww client XML transport module... $ECHO_C" >&6 +echo "$as_me:$LINENO: result: $MUST_BUILD_LIBWWW_CLIENT" >&5 +echo "${ECHO_T}$MUST_BUILD_LIBWWW_CLIENT" >&6 + + + +if test "$MUST_BUILD_WININET_CLIENT $MUST_BUILD_CURL_CLIENT $MUST_BUILD_LIBWWW_CLIENT" = "no no no"; then + { echo "$as_me:$LINENO: We are not building any client XML transport, therefore we will not build the client library at all." >&5 +echo "$as_me: We are not building any client XML transport, therefore we will not build the client library at all." >&6;} +fi + + + +LIBXMLRPC_CLIENT_LA=libxmlrpc_client.la + +CLIENTTEST=clienttest + +XMLRPC_CLIENT_H=xmlrpc_client.h + +XMLRPC_TRANSPORT_H=xmlrpc_transport.h + +SYNCH_CLIENT=synch_client + +ASYNCH_CLIENT=asynch_client + +AUTH_CLIENT=auth_client + +QUERY_MEERKAT=query-meerkat + + +if test $MUST_BUILD_WININET_CLIENT = yes; then + FEATURE_LIST="wininet-client $FEATURE_LIST" +fi +if test $MUST_BUILD_CURL_CLIENT = yes; then + FEATURE_LIST="curl-client $FEATURE_LIST" +fi +if test $MUST_BUILD_LIBWWW_CLIENT = yes; then + FEATURE_LIST="libwww-client $FEATURE_LIST" +fi + +echo "$as_me:$LINENO: checking whether to build Abyss server module" >&5 +echo $ECHO_N "checking whether to build Abyss server module... $ECHO_C" >&6 +# Check whether --enable-abyss-server or --disable-abyss-server was given. +if test "${enable_abyss_server+set}" = set; then + enableval="$enable_abyss_server" + +else + enable_abyss_server=yes +fi; +echo "$as_me:$LINENO: result: $enable_abyss_server" >&5 +echo "${ECHO_T}$enable_abyss_server" >&6 +ENABLE_ABYSS_SERVER=$enable_abyss_server + + +ABYSS_SUBDIR= +LIBXMLRPC_ABYSS_SERVER_LA= +SERVERTEST= +VALIDATEE= +XMLRPC_ABYSS_H= +SERVER= +if test x"$enable_abyss_server" != xno; then + FEATURE_LIST="abyss-server $FEATURE_LIST" + ABYSS_SUBDIR=abyss + LIBXMLRPC_ABYSS_SERVER_LA=libxmlrpc_abyss_server.la + SERVERTEST=servertest + VALIDATEE=validatee + XMLRPC_ABYSS_H=xmlrpc_abyss.h + SERVER=server +fi + + + + + + + +echo "$as_me:$LINENO: checking whether to build CGI server module" >&5 +echo $ECHO_N "checking whether to build CGI server module... $ECHO_C" >&6 +# Check whether --enable-cgi-server or --disable-cgi-server was given. +if test "${enable_cgi_server+set}" = set; then + enableval="$enable_cgi_server" + +else + enable_cgi_server=yes +fi; +echo "$as_me:$LINENO: result: $enable_cgi_server" >&5 +echo "${ECHO_T}$enable_cgi_server" >&6 +ENABLE_CGI_SERVER=$enable_cgi_server + + +echo "$as_me:$LINENO: checking whether to build C++ wrappers and tools" >&5 +echo $ECHO_N "checking whether to build C++ wrappers and tools... $ECHO_C" >&6 +# Check whether --enable-cplusplus or --disable-cplusplus was given. +if test "${enable_cplusplus+set}" = set; then + enableval="$enable_cplusplus" + +else + enable_cplusplus=yes +fi; +echo "$as_me:$LINENO: result: $enable_cplusplus" >&5 +echo "${ECHO_T}$enable_cplusplus" >&6 +ENABLE_CPLUSPLUS=$enable_cplusplus + + +LIBXMLRPC_CPP_A= +CPPTEST= +XMLRPCCPP_H= +XML_RPC_API2CPP_SUBDIR= +MEERKAT_APP_LIST= +INTEROP_CLIENT_SUBDIR= +if test x"$enable_cplusplus" != xno; then + FEATURE_LIST="c++ $FEATURE_LIST" + LIBXMLRPC_CPP_A=libxmlrpc_cpp.a + CPPTEST=cpptest + XMLRPCCPP_H=XmlRpcCpp.h + + if test $MUST_BUILD_LIBWWW_CLIENT = yes; then + XML_RPC_API2CPP_SUBDIR=xml-rpc-api2cpp + elif test $MUST_BUILD_CURL_CLIENT = yes; then + XML_RPC_API2CPP_SUBDIR=xml-rpc-api2cpp + fi +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 +if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args. +set dummy ${ac_tool_prefix}gcc; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_CC+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_CC="${ac_tool_prefix}gcc" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + echo "$as_me:$LINENO: result: $CC" >&5 +echo "${ECHO_T}$CC" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + +fi +if test -z "$ac_cv_prog_CC"; then + ac_ct_CC=$CC + # Extract the first word of "gcc", so it can be a program name with args. +set dummy gcc; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_ac_ct_CC+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$ac_ct_CC"; then + ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_CC="gcc" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + +fi +fi +ac_ct_CC=$ac_cv_prog_ac_ct_CC +if test -n "$ac_ct_CC"; then + echo "$as_me:$LINENO: result: $ac_ct_CC" >&5 +echo "${ECHO_T}$ac_ct_CC" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + + CC=$ac_ct_CC +else + CC="$ac_cv_prog_CC" +fi + +if test -z "$CC"; then + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args. +set dummy ${ac_tool_prefix}cc; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_CC+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_CC="${ac_tool_prefix}cc" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + echo "$as_me:$LINENO: result: $CC" >&5 +echo "${ECHO_T}$CC" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + +fi +if test -z "$ac_cv_prog_CC"; then + ac_ct_CC=$CC + # Extract the first word of "cc", so it can be a program name with args. +set dummy cc; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_ac_ct_CC+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$ac_ct_CC"; then + ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_CC="cc" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + +fi +fi +ac_ct_CC=$ac_cv_prog_ac_ct_CC +if test -n "$ac_ct_CC"; then + echo "$as_me:$LINENO: result: $ac_ct_CC" >&5 +echo "${ECHO_T}$ac_ct_CC" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + + CC=$ac_ct_CC +else + CC="$ac_cv_prog_CC" +fi + +fi +if test -z "$CC"; then + # Extract the first word of "cc", so it can be a program name with args. +set dummy cc; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_CC+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else + ac_prog_rejected=no +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then + ac_prog_rejected=yes + continue + fi + ac_cv_prog_CC="cc" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + +if test $ac_prog_rejected = yes; then + # We found a bogon in the path, so make sure we never use it. + set dummy $ac_cv_prog_CC + shift + if test $# != 0; then + # We chose a different compiler from the bogus one. + # However, it has the same basename, so the bogon will be chosen + # first if we set CC to just the basename; use the full file name. + shift + ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@" + fi +fi +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + echo "$as_me:$LINENO: result: $CC" >&5 +echo "${ECHO_T}$CC" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + +fi +if test -z "$CC"; then + if test -n "$ac_tool_prefix"; then + for ac_prog in cl + do + # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. +set dummy $ac_tool_prefix$ac_prog; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_CC+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_CC="$ac_tool_prefix$ac_prog" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + echo "$as_me:$LINENO: result: $CC" >&5 +echo "${ECHO_T}$CC" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + + test -n "$CC" && break + done +fi +if test -z "$CC"; then + ac_ct_CC=$CC + for ac_prog in cl +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_ac_ct_CC+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$ac_ct_CC"; then + ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_CC="$ac_prog" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + +fi +fi +ac_ct_CC=$ac_cv_prog_ac_ct_CC +if test -n "$ac_ct_CC"; then + echo "$as_me:$LINENO: result: $ac_ct_CC" >&5 +echo "${ECHO_T}$ac_ct_CC" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + + test -n "$ac_ct_CC" && break +done + + CC=$ac_ct_CC +fi + +fi + + +test -z "$CC" && { { echo "$as_me:$LINENO: error: no acceptable C compiler found in \$PATH +See \`config.log' for more details." >&5 +echo "$as_me: error: no acceptable C compiler found in \$PATH +See \`config.log' for more details." >&2;} + { (exit 1); exit 1; }; } + +# Provide some information about the compiler. +echo "$as_me:$LINENO:" \ + "checking for C compiler version" >&5 +ac_compiler=`set X $ac_compile; echo $2` +{ (eval echo "$as_me:$LINENO: \"$ac_compiler --version &5\"") >&5 + (eval $ac_compiler --version &5) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } +{ (eval echo "$as_me:$LINENO: \"$ac_compiler -v &5\"") >&5 + (eval $ac_compiler -v &5) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } +{ (eval echo "$as_me:$LINENO: \"$ac_compiler -V &5\"") >&5 + (eval $ac_compiler -V &5) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } + +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +ac_clean_files_save=$ac_clean_files +ac_clean_files="$ac_clean_files a.out a.exe b.out" +# Try to create an executable without -o first, disregard a.out. +# It will help us diagnose broken compilers, and finding out an intuition +# of exeext. +echo "$as_me:$LINENO: checking for C compiler default output file name" >&5 +echo $ECHO_N "checking for C compiler default output file name... $ECHO_C" >&6 +ac_link_default=`echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'` +if { (eval echo "$as_me:$LINENO: \"$ac_link_default\"") >&5 + (eval $ac_link_default) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; then + # Find the output, starting from the most likely. This scheme is +# not robust to junk in `.', hence go to wildcards (a.*) only as a last +# resort. + +# Be careful to initialize this variable, since it used to be cached. +# Otherwise an old cache value of `no' led to `EXEEXT = no' in a Makefile. +ac_cv_exeext= +# b.out is created by i960 compilers. +for ac_file in a_out.exe a.exe conftest.exe a.out conftest a.* conftest.* b.out +do + test -f "$ac_file" || continue + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.o | *.obj ) + ;; + conftest.$ac_ext ) + # This is the source file. + ;; + [ab].out ) + # We found the default executable, but exeext='' is most + # certainly right. + break;; + *.* ) + ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` + # FIXME: I believe we export ac_cv_exeext for Libtool, + # but it would be cool to find out if it's true. Does anybody + # maintain Libtool? --akim. + export ac_cv_exeext + break;; + * ) + break;; + esac +done +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +{ { echo "$as_me:$LINENO: error: C compiler cannot create executables +See \`config.log' for more details." >&5 +echo "$as_me: error: C compiler cannot create executables +See \`config.log' for more details." >&2;} + { (exit 77); exit 77; }; } +fi + +ac_exeext=$ac_cv_exeext +echo "$as_me:$LINENO: result: $ac_file" >&5 +echo "${ECHO_T}$ac_file" >&6 + +# Check the compiler produces executables we can run. If not, either +# the compiler is broken, or we cross compile. +echo "$as_me:$LINENO: checking whether the C compiler works" >&5 +echo $ECHO_N "checking whether the C compiler works... $ECHO_C" >&6 +# FIXME: These cross compiler hacks should be removed for Autoconf 3.0 +# If not cross compiling, check that we can run a simple program. +if test "$cross_compiling" != yes; then + if { ac_try='./$ac_file' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + cross_compiling=no + else + if test "$cross_compiling" = maybe; then + cross_compiling=yes + else + { { echo "$as_me:$LINENO: error: cannot run C compiled programs. +If you meant to cross compile, use \`--host'. +See \`config.log' for more details." >&5 +echo "$as_me: error: cannot run C compiled programs. +If you meant to cross compile, use \`--host'. +See \`config.log' for more details." >&2;} + { (exit 1); exit 1; }; } + fi + fi +fi +echo "$as_me:$LINENO: result: yes" >&5 +echo "${ECHO_T}yes" >&6 + +rm -f a.out a.exe conftest$ac_cv_exeext b.out +ac_clean_files=$ac_clean_files_save +# Check the compiler produces executables we can run. If not, either +# the compiler is broken, or we cross compile. +echo "$as_me:$LINENO: checking whether we are cross compiling" >&5 +echo $ECHO_N "checking whether we are cross compiling... $ECHO_C" >&6 +echo "$as_me:$LINENO: result: $cross_compiling" >&5 +echo "${ECHO_T}$cross_compiling" >&6 + +echo "$as_me:$LINENO: checking for suffix of executables" >&5 +echo $ECHO_N "checking for suffix of executables... $ECHO_C" >&6 +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; then + # If both `conftest.exe' and `conftest' are `present' (well, observable) +# catch `conftest.exe'. For instance with Cygwin, `ls conftest' will +# work properly (i.e., refer to `conftest.exe'), while it won't with +# `rm'. +for ac_file in conftest.exe conftest conftest.*; do + test -f "$ac_file" || continue + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.o | *.obj ) ;; + *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` + export ac_cv_exeext + break;; + * ) break;; + esac +done +else + { { echo "$as_me:$LINENO: error: cannot compute suffix of executables: cannot compile and link +See \`config.log' for more details." >&5 +echo "$as_me: error: cannot compute suffix of executables: cannot compile and link +See \`config.log' for more details." >&2;} + { (exit 1); exit 1; }; } +fi + +rm -f conftest$ac_cv_exeext +echo "$as_me:$LINENO: result: $ac_cv_exeext" >&5 +echo "${ECHO_T}$ac_cv_exeext" >&6 + +rm -f conftest.$ac_ext +EXEEXT=$ac_cv_exeext +ac_exeext=$EXEEXT +echo "$as_me:$LINENO: checking for suffix of object files" >&5 +echo $ECHO_N "checking for suffix of object files... $ECHO_C" >&6 +if test "${ac_cv_objext+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.o conftest.obj +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; then + for ac_file in `(ls conftest.o conftest.obj; ls conftest.*) 2>/dev/null`; do + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg ) ;; + *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'` + break;; + esac +done +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +{ { echo "$as_me:$LINENO: error: cannot compute suffix of object files: cannot compile +See \`config.log' for more details." >&5 +echo "$as_me: error: cannot compute suffix of object files: cannot compile +See \`config.log' for more details." >&2;} + { (exit 1); exit 1; }; } +fi + +rm -f conftest.$ac_cv_objext conftest.$ac_ext +fi +echo "$as_me:$LINENO: result: $ac_cv_objext" >&5 +echo "${ECHO_T}$ac_cv_objext" >&6 +OBJEXT=$ac_cv_objext +ac_objext=$OBJEXT +echo "$as_me:$LINENO: checking whether we are using the GNU C compiler" >&5 +echo $ECHO_N "checking whether we are using the GNU C compiler... $ECHO_C" >&6 +if test "${ac_cv_c_compiler_gnu+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ +#ifndef __GNUC__ + choke me +#endif + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_compiler_gnu=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_compiler_gnu=no +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +ac_cv_c_compiler_gnu=$ac_compiler_gnu + +fi +echo "$as_me:$LINENO: result: $ac_cv_c_compiler_gnu" >&5 +echo "${ECHO_T}$ac_cv_c_compiler_gnu" >&6 +GCC=`test $ac_compiler_gnu = yes && echo yes` +ac_test_CFLAGS=${CFLAGS+set} +ac_save_CFLAGS=$CFLAGS +CFLAGS="-g" +echo "$as_me:$LINENO: checking whether $CC accepts -g" >&5 +echo $ECHO_N "checking whether $CC accepts -g... $ECHO_C" >&6 +if test "${ac_cv_prog_cc_g+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_prog_cc_g=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_cv_prog_cc_g=no +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +fi +echo "$as_me:$LINENO: result: $ac_cv_prog_cc_g" >&5 +echo "${ECHO_T}$ac_cv_prog_cc_g" >&6 +if test "$ac_test_CFLAGS" = set; then + CFLAGS=$ac_save_CFLAGS +elif test $ac_cv_prog_cc_g = yes; then + if test "$GCC" = yes; then + CFLAGS="-g -O2" + else + CFLAGS="-g" + fi +else + if test "$GCC" = yes; then + CFLAGS="-O2" + else + CFLAGS= + fi +fi +echo "$as_me:$LINENO: checking for $CC option to accept ANSI C" >&5 +echo $ECHO_N "checking for $CC option to accept ANSI C... $ECHO_C" >&6 +if test "${ac_cv_prog_cc_stdc+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_cv_prog_cc_stdc=no +ac_save_CC=$CC +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +#include +#include +#include +/* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */ +struct buf { int x; }; +FILE * (*rcsopen) (struct buf *, struct stat *, int); +static char *e (p, i) + char **p; + int i; +{ + return p[i]; +} +static char *f (char * (*g) (char **, int), char **p, ...) +{ + char *s; + va_list v; + va_start (v,p); + s = g (p, va_arg (v,int)); + va_end (v); + return s; +} + +/* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has + function prototypes and stuff, but not '\xHH' hex character constants. + These don't provoke an error unfortunately, instead are silently treated + as 'x'. The following induces an error, until -std1 is added to get + proper ANSI mode. Curiously '\x00'!='x' always comes out true, for an + array size at least. It's necessary to write '\x00'==0 to get something + that's true only with -std1. */ +int osf4_cc_array ['\x00' == 0 ? 1 : -1]; + +int test (int i, double x); +struct s1 {int (*f) (int a);}; +struct s2 {int (*f) (double a);}; +int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int); +int argc; +char **argv; +int +main () +{ +return f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1]; + ; + return 0; +} +_ACEOF +# Don't try gcc -ansi; that turns off useful extensions and +# breaks some systems' header files. +# AIX -qlanglvl=ansi +# Ultrix and OSF/1 -std1 +# HP-UX 10.20 and later -Ae +# HP-UX older versions -Aa -D_HPUX_SOURCE +# SVR4 -Xc -D__EXTENSIONS__ +for ac_arg in "" -qlanglvl=ansi -std1 -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__" +do + CC="$ac_save_CC $ac_arg" + rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_prog_cc_stdc=$ac_arg +break +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +fi +rm -f conftest.err conftest.$ac_objext +done +rm -f conftest.$ac_ext conftest.$ac_objext +CC=$ac_save_CC + +fi + +case "x$ac_cv_prog_cc_stdc" in + x|xno) + echo "$as_me:$LINENO: result: none needed" >&5 +echo "${ECHO_T}none needed" >&6 ;; + *) + echo "$as_me:$LINENO: result: $ac_cv_prog_cc_stdc" >&5 +echo "${ECHO_T}$ac_cv_prog_cc_stdc" >&6 + CC="$CC $ac_cv_prog_cc_stdc" ;; +esac + +# Some people use a C++ compiler to compile C. Since we use `exit', +# in C++ we need to declare it. In case someone uses the same compiler +# for both compiling C and C++ we need to have the C++ compiler decide +# the declaration of exit, since it's the most demanding environment. +cat >conftest.$ac_ext <<_ACEOF +#ifndef __cplusplus + choke me +#endif +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + for ac_declaration in \ + '' \ + 'extern "C" void std::exit (int) throw (); using std::exit;' \ + 'extern "C" void std::exit (int); using std::exit;' \ + 'extern "C" void exit (int) throw ();' \ + 'extern "C" void exit (int);' \ + 'void exit (int);' +do + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_declaration +#include +int +main () +{ +exit (42); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + : +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +continue +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_declaration +int +main () +{ +exit (42); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + break +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +done +rm -f conftest* +if test -n "$ac_declaration"; then + echo '#ifdef __cplusplus' >>confdefs.h + echo $ac_declaration >>confdefs.h + echo '#endif' >>confdefs.h +fi + +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + +if test x"$enable_cplusplus" != xno; then + ac_ext=cc +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu +if test -n "$ac_tool_prefix"; then + for ac_prog in $CCC g++ c++ gpp aCC CC cxx cc++ cl FCC KCC RCC xlC_r xlC + do + # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. +set dummy $ac_tool_prefix$ac_prog; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_CXX+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$CXX"; then + ac_cv_prog_CXX="$CXX" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_CXX="$ac_tool_prefix$ac_prog" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + +fi +fi +CXX=$ac_cv_prog_CXX +if test -n "$CXX"; then + echo "$as_me:$LINENO: result: $CXX" >&5 +echo "${ECHO_T}$CXX" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + + test -n "$CXX" && break + done +fi +if test -z "$CXX"; then + ac_ct_CXX=$CXX + for ac_prog in $CCC g++ c++ gpp aCC CC cxx cc++ cl FCC KCC RCC xlC_r xlC +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_ac_ct_CXX+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$ac_ct_CXX"; then + ac_cv_prog_ac_ct_CXX="$ac_ct_CXX" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_CXX="$ac_prog" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + +fi +fi +ac_ct_CXX=$ac_cv_prog_ac_ct_CXX +if test -n "$ac_ct_CXX"; then + echo "$as_me:$LINENO: result: $ac_ct_CXX" >&5 +echo "${ECHO_T}$ac_ct_CXX" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + + test -n "$ac_ct_CXX" && break +done +test -n "$ac_ct_CXX" || ac_ct_CXX="g++" + + CXX=$ac_ct_CXX +fi + + +# Provide some information about the compiler. +echo "$as_me:$LINENO:" \ + "checking for C++ compiler version" >&5 +ac_compiler=`set X $ac_compile; echo $2` +{ (eval echo "$as_me:$LINENO: \"$ac_compiler --version &5\"") >&5 + (eval $ac_compiler --version &5) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } +{ (eval echo "$as_me:$LINENO: \"$ac_compiler -v &5\"") >&5 + (eval $ac_compiler -v &5) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } +{ (eval echo "$as_me:$LINENO: \"$ac_compiler -V &5\"") >&5 + (eval $ac_compiler -V &5) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } + +echo "$as_me:$LINENO: checking whether we are using the GNU C++ compiler" >&5 +echo $ECHO_N "checking whether we are using the GNU C++ compiler... $ECHO_C" >&6 +if test "${ac_cv_cxx_compiler_gnu+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ +#ifndef __GNUC__ + choke me +#endif + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_cxx_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_compiler_gnu=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_compiler_gnu=no +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +ac_cv_cxx_compiler_gnu=$ac_compiler_gnu + +fi +echo "$as_me:$LINENO: result: $ac_cv_cxx_compiler_gnu" >&5 +echo "${ECHO_T}$ac_cv_cxx_compiler_gnu" >&6 +GXX=`test $ac_compiler_gnu = yes && echo yes` +ac_test_CXXFLAGS=${CXXFLAGS+set} +ac_save_CXXFLAGS=$CXXFLAGS +CXXFLAGS="-g" +echo "$as_me:$LINENO: checking whether $CXX accepts -g" >&5 +echo $ECHO_N "checking whether $CXX accepts -g... $ECHO_C" >&6 +if test "${ac_cv_prog_cxx_g+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_cxx_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_prog_cxx_g=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_cv_prog_cxx_g=no +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +fi +echo "$as_me:$LINENO: result: $ac_cv_prog_cxx_g" >&5 +echo "${ECHO_T}$ac_cv_prog_cxx_g" >&6 +if test "$ac_test_CXXFLAGS" = set; then + CXXFLAGS=$ac_save_CXXFLAGS +elif test $ac_cv_prog_cxx_g = yes; then + if test "$GXX" = yes; then + CXXFLAGS="-g -O2" + else + CXXFLAGS="-g" + fi +else + if test "$GXX" = yes; then + CXXFLAGS="-O2" + else + CXXFLAGS= + fi +fi +for ac_declaration in \ + '' \ + 'extern "C" void std::exit (int) throw (); using std::exit;' \ + 'extern "C" void std::exit (int); using std::exit;' \ + 'extern "C" void exit (int) throw ();' \ + 'extern "C" void exit (int);' \ + 'void exit (int);' +do + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_declaration +#include +int +main () +{ +exit (42); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_cxx_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + : +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +continue +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_declaration +int +main () +{ +exit (42); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_cxx_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + break +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +done +rm -f conftest* +if test -n "$ac_declaration"; then + echo '#ifdef __cplusplus' >>confdefs.h + echo $ac_declaration >>confdefs.h + echo '#endif' >>confdefs.h +fi + +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 + +fi + + + +# Code by albert chin to check for various +# oddball networking libraries. Solaris and some other operating systems +# hide their networking code in various places. (Yes, this links too many +# of our libraries against -lsocket, but a finer-grained mechanism would +# require too much testing.) +echo "$as_me:$LINENO: checking for socket" >&5 +echo $ECHO_N "checking for socket... $ECHO_C" >&6 +if test "${ac_cv_func_socket+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +/* Define socket to an innocuous variant, in case declares socket. + For example, HP-UX 11i declares gettimeofday. */ +#define socket innocuous_socket + +/* System header to define __stub macros and hopefully few prototypes, + which can conflict with char socket (); below. + Prefer to if __STDC__ is defined, since + exists even on freestanding compilers. */ + +#ifdef __STDC__ +# include +#else +# include +#endif + +#undef socket + +/* Override any gcc2 internal prototype to avoid an error. */ +#ifdef __cplusplus +extern "C" +{ +#endif +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char socket (); +/* 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_socket) || defined (__stub___socket) +choke me +#else +char (*f) () = socket; +#endif +#ifdef __cplusplus +} +#endif + +int +main () +{ +return f != socket; + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_func_socket=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_cv_func_socket=no +fi +rm -f conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +fi +echo "$as_me:$LINENO: result: $ac_cv_func_socket" >&5 +echo "${ECHO_T}$ac_cv_func_socket" >&6 +if test $ac_cv_func_socket = yes; then + : +else + +echo "$as_me:$LINENO: checking for socket in -lsocket" >&5 +echo $ECHO_N "checking for socket in -lsocket... $ECHO_C" >&6 +if test "${ac_cv_lib_socket_socket+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lsocket $LIBS" + +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +/* Override any gcc2 internal prototype to avoid an error. */ +#ifdef __cplusplus +extern "C" +#endif +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char socket (); +int +main () +{ +socket (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_lib_socket_socket=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_cv_lib_socket_socket=no +fi +rm -f conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +echo "$as_me:$LINENO: result: $ac_cv_lib_socket_socket" >&5 +echo "${ECHO_T}$ac_cv_lib_socket_socket" >&6 +if test $ac_cv_lib_socket_socket = yes; then + cat >>confdefs.h <<_ACEOF +#define HAVE_LIBSOCKET 1 +_ACEOF + + LIBS="-lsocket $LIBS" + +fi + +fi + + +# Above sets LIBS, which is not all that useful because we don't want +# to include every library in every link. It also sets +# ac_cv_lib_socket_socket, which we use to pass more specific information +# to the configuration files. + +if test x"$ac_cv_lib_socket_socket" = xyes; then + LSOCKET=-lsocket +else + LSOCKET= +fi + + +# For some reason, we don't seem to need this on Solaris. If you do +# need it, go ahead and try it. +# AC_CHECK_FUNC(gethostent, , AC_CHECK_LIB(nsl, gethostent)) + + + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu +echo "$as_me:$LINENO: checking how to run the C preprocessor" >&5 +echo $ECHO_N "checking how to run the C preprocessor... $ECHO_C" >&6 +# On Suns, sometimes $CPP names a directory. +if test -n "$CPP" && test -d "$CPP"; then + CPP= +fi +if test -z "$CPP"; then + if test "${ac_cv_prog_CPP+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + # Double quotes because CPP needs to be expanded + for CPP in "$CC -E" "$CC -E -traditional-cpp" "/lib/cpp" + do + ac_preproc_ok=false +for ac_c_preproc_warn_flag in '' yes +do + # Use a header file that comes with gcc, so configuring glibc + # with a fresh cross-compiler works. + # Prefer to if __STDC__ is defined, since + # 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 +#else +# include +#endif + Syntax error +_ACEOF +if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 + (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null; then + if test -s conftest.err; then + ac_cpp_err=$ac_c_preproc_warn_flag + ac_cpp_err=$ac_cpp_err$ac_c_werror_flag + else + ac_cpp_err= + fi +else + ac_cpp_err=yes +fi +if test -z "$ac_cpp_err"; then + : +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + # Broken: fails on valid input. +continue +fi +rm -f conftest.err conftest.$ac_ext + + # OK, works on sane cases. Now check whether non-existent headers + # can be detected and how. + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +_ACEOF +if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 + (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null; then + if test -s conftest.err; then + ac_cpp_err=$ac_c_preproc_warn_flag + ac_cpp_err=$ac_cpp_err$ac_c_werror_flag + else + ac_cpp_err= + fi +else + ac_cpp_err=yes +fi +if test -z "$ac_cpp_err"; then + # Broken: success on invalid input. +continue +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + # Passes both tests. +ac_preproc_ok=: +break +fi +rm -f conftest.err conftest.$ac_ext + +done +# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. +rm -f conftest.err conftest.$ac_ext +if $ac_preproc_ok; then + break +fi + + done + ac_cv_prog_CPP=$CPP + +fi + CPP=$ac_cv_prog_CPP +else + ac_cv_prog_CPP=$CPP +fi +echo "$as_me:$LINENO: result: $CPP" >&5 +echo "${ECHO_T}$CPP" >&6 +ac_preproc_ok=false +for ac_c_preproc_warn_flag in '' yes +do + # Use a header file that comes with gcc, so configuring glibc + # with a fresh cross-compiler works. + # Prefer to if __STDC__ is defined, since + # 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 +#else +# include +#endif + Syntax error +_ACEOF +if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 + (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null; then + if test -s conftest.err; then + ac_cpp_err=$ac_c_preproc_warn_flag + ac_cpp_err=$ac_cpp_err$ac_c_werror_flag + else + ac_cpp_err= + fi +else + ac_cpp_err=yes +fi +if test -z "$ac_cpp_err"; then + : +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + # Broken: fails on valid input. +continue +fi +rm -f conftest.err conftest.$ac_ext + + # OK, works on sane cases. Now check whether non-existent headers + # can be detected and how. + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +_ACEOF +if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 + (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null; then + if test -s conftest.err; then + ac_cpp_err=$ac_c_preproc_warn_flag + ac_cpp_err=$ac_cpp_err$ac_c_werror_flag + else + ac_cpp_err= + fi +else + ac_cpp_err=yes +fi +if test -z "$ac_cpp_err"; then + # Broken: success on invalid input. +continue +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + # Passes both tests. +ac_preproc_ok=: +break +fi +rm -f conftest.err conftest.$ac_ext + +done +# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. +rm -f conftest.err conftest.$ac_ext +if $ac_preproc_ok; then + : +else + { { echo "$as_me:$LINENO: error: C preprocessor \"$CPP\" fails sanity check +See \`config.log' for more details." >&5 +echo "$as_me: error: C preprocessor \"$CPP\" fails sanity check +See \`config.log' for more details." >&2;} + { (exit 1); exit 1; }; } +fi + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +echo "$as_me:$LINENO: checking for egrep" >&5 +echo $ECHO_N "checking for egrep... $ECHO_C" >&6 +if test "${ac_cv_prog_egrep+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if echo a | (grep -E '(a|b)') >/dev/null 2>&1 + then ac_cv_prog_egrep='grep -E' + else ac_cv_prog_egrep='egrep' + fi +fi +echo "$as_me:$LINENO: result: $ac_cv_prog_egrep" >&5 +echo "${ECHO_T}$ac_cv_prog_egrep" >&6 + EGREP=$ac_cv_prog_egrep + + +echo "$as_me:$LINENO: checking for ANSI C header files" >&5 +echo $ECHO_N "checking for ANSI C header files... $ECHO_C" >&6 +if test "${ac_cv_header_stdc+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +#include +#include +#include + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_header_stdc=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_cv_header_stdc=no +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext + +if test $ac_cv_header_stdc = yes; then + # SunOS 4.x string.h does not declare mem*, contrary to ANSI. + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include + +_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 + +_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 +#if ((' ' & 0x0FF) == 0x020) +# define ISLOWER(c) ('a' <= (c) && (c) <= 'z') +# define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c)) +#else +# define ISLOWER(c) \ + (('a' <= (c) && (c) <= 'i') \ + || ('j' <= (c) && (c) <= 'r') \ + || ('s' <= (c) && (c) <= 'z')) +# define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c)) +#endif + +#define XOR(e, f) (((e) && !(f)) || (!(e) && (f))) +int +main () +{ + int i; + for (i = 0; i < 256; i++) + if (XOR (islower (i), ISLOWER (i)) + || toupper (i) != TOUPPER (i)) + exit(2); + exit (0); +} +_ACEOF +rm -f conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { ac_try='./conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + : +else + echo "$as_me: program exited with status $ac_status" >&5 +echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +( exit $ac_status ) +ac_cv_header_stdc=no +fi +rm -f core *.core gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext +fi +fi +fi +echo "$as_me:$LINENO: result: $ac_cv_header_stdc" >&5 +echo "${ECHO_T}$ac_cv_header_stdc" >&6 +if test $ac_cv_header_stdc = yes; then + +cat >>confdefs.h <<\_ACEOF +#define STDC_HEADERS 1 +_ACEOF + +fi + + + +# On IRIX 5.3, sys/types and inttypes.h are conflicting. + + + + + + + + + +for ac_header in sys/types.h sys/stat.h stdlib.h string.h memory.h strings.h \ + inttypes.h stdint.h unistd.h +do +as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh` +echo "$as_me:$LINENO: checking for $ac_header" >&5 +echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6 +if eval "test \"\${$as_ac_Header+set}\" = set"; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default + +#include <$ac_header> +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + eval "$as_ac_Header=yes" +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +eval "$as_ac_Header=no" +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +fi +echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5 +echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6 +if test `eval echo '${'$as_ac_Header'}'` = yes; then + cat >>confdefs.h <<_ACEOF +#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1 +_ACEOF + +fi + +done + + + +for ac_header in wchar.h +do +as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh` +if eval "test \"\${$as_ac_Header+set}\" = set"; then + echo "$as_me:$LINENO: checking for $ac_header" >&5 +echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6 +if eval "test \"\${$as_ac_Header+set}\" = set"; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +fi +echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5 +echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6 +else + # Is the header compilable? +echo "$as_me:$LINENO: checking $ac_header usability" >&5 +echo $ECHO_N "checking $ac_header usability... $ECHO_C" >&6 +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +#include <$ac_header> +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_header_compiler=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_header_compiler=no +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +echo "$as_me:$LINENO: result: $ac_header_compiler" >&5 +echo "${ECHO_T}$ac_header_compiler" >&6 + +# Is the header present? +echo "$as_me:$LINENO: checking $ac_header presence" >&5 +echo $ECHO_N "checking $ac_header presence... $ECHO_C" >&6 +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include <$ac_header> +_ACEOF +if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 + (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null; then + if test -s conftest.err; then + ac_cpp_err=$ac_c_preproc_warn_flag + ac_cpp_err=$ac_cpp_err$ac_c_werror_flag + else + ac_cpp_err= + fi +else + ac_cpp_err=yes +fi +if test -z "$ac_cpp_err"; then + ac_header_preproc=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_header_preproc=no +fi +rm -f conftest.err conftest.$ac_ext +echo "$as_me:$LINENO: result: $ac_header_preproc" >&5 +echo "${ECHO_T}$ac_header_preproc" >&6 + +# So? What about this header? +case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in + yes:no: ) + { echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5 +echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5 +echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;} + ac_header_preproc=yes + ;; + no:yes:* ) + { echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5 +echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: check for missing prerequisite headers?" >&5 +echo "$as_me: WARNING: $ac_header: check for missing prerequisite headers?" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5 +echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&5 +echo "$as_me: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5 +echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5 +echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;} + ( + cat <<\_ASBOX +## ------------------------------------------ ## +## Report this to the AC_PACKAGE_NAME lists. ## +## ------------------------------------------ ## +_ASBOX + ) | + sed "s/^/$as_me: WARNING: /" >&2 + ;; +esac +echo "$as_me:$LINENO: checking for $ac_header" >&5 +echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6 +if eval "test \"\${$as_ac_Header+set}\" = set"; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + eval "$as_ac_Header=\$ac_header_preproc" +fi +echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5 +echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6 + +fi +if test `eval echo '${'$as_ac_Header'}'` = yes; then + cat >>confdefs.h <<_ACEOF +#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1 +_ACEOF + +fi + +done + + +if test x"$ac_cv_header_wchar_h" = xyes; then + HAVE_WCHAR_H_DEFINE=1 +else + HAVE_WCHAR_H_DEFINE=0 +fi + + +# Needed by Abyss on Solaris: + + +for ac_header in sys/filio.h +do +as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh` +if eval "test \"\${$as_ac_Header+set}\" = set"; then + echo "$as_me:$LINENO: checking for $ac_header" >&5 +echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6 +if eval "test \"\${$as_ac_Header+set}\" = set"; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +fi +echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5 +echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6 +else + # Is the header compilable? +echo "$as_me:$LINENO: checking $ac_header usability" >&5 +echo $ECHO_N "checking $ac_header usability... $ECHO_C" >&6 +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +#include <$ac_header> +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_header_compiler=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_header_compiler=no +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +echo "$as_me:$LINENO: result: $ac_header_compiler" >&5 +echo "${ECHO_T}$ac_header_compiler" >&6 + +# Is the header present? +echo "$as_me:$LINENO: checking $ac_header presence" >&5 +echo $ECHO_N "checking $ac_header presence... $ECHO_C" >&6 +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include <$ac_header> +_ACEOF +if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 + (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null; then + if test -s conftest.err; then + ac_cpp_err=$ac_c_preproc_warn_flag + ac_cpp_err=$ac_cpp_err$ac_c_werror_flag + else + ac_cpp_err= + fi +else + ac_cpp_err=yes +fi +if test -z "$ac_cpp_err"; then + ac_header_preproc=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_header_preproc=no +fi +rm -f conftest.err conftest.$ac_ext +echo "$as_me:$LINENO: result: $ac_header_preproc" >&5 +echo "${ECHO_T}$ac_header_preproc" >&6 + +# So? What about this header? +case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in + yes:no: ) + { echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5 +echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5 +echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;} + ac_header_preproc=yes + ;; + no:yes:* ) + { echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5 +echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: check for missing prerequisite headers?" >&5 +echo "$as_me: WARNING: $ac_header: check for missing prerequisite headers?" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5 +echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&5 +echo "$as_me: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5 +echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5 +echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;} + ( + cat <<\_ASBOX +## ------------------------------------------ ## +## Report this to the AC_PACKAGE_NAME lists. ## +## ------------------------------------------ ## +_ASBOX + ) | + sed "s/^/$as_me: WARNING: /" >&2 + ;; +esac +echo "$as_me:$LINENO: checking for $ac_header" >&5 +echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6 +if eval "test \"\${$as_ac_Header+set}\" = set"; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + eval "$as_ac_Header=\$ac_header_preproc" +fi +echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5 +echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6 + +fi +if test `eval echo '${'$as_ac_Header'}'` = yes; then + cat >>confdefs.h <<_ACEOF +#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1 +_ACEOF + +fi + +done + +if test x"$ac_cv_header_sys_filio_h" = xyes; then + HAVE_SYS_FILIO_H_DEFINE=1 +else + HAVE_SYS_FILIO_H_DEFINE=0 +fi + + +# Needed by Abyss on Solaris: + + +for ac_header in sys/ioctl.h +do +as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh` +if eval "test \"\${$as_ac_Header+set}\" = set"; then + echo "$as_me:$LINENO: checking for $ac_header" >&5 +echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6 +if eval "test \"\${$as_ac_Header+set}\" = set"; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +fi +echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5 +echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6 +else + # Is the header compilable? +echo "$as_me:$LINENO: checking $ac_header usability" >&5 +echo $ECHO_N "checking $ac_header usability... $ECHO_C" >&6 +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +#include <$ac_header> +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_header_compiler=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_header_compiler=no +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +echo "$as_me:$LINENO: result: $ac_header_compiler" >&5 +echo "${ECHO_T}$ac_header_compiler" >&6 + +# Is the header present? +echo "$as_me:$LINENO: checking $ac_header presence" >&5 +echo $ECHO_N "checking $ac_header presence... $ECHO_C" >&6 +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include <$ac_header> +_ACEOF +if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 + (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null; then + if test -s conftest.err; then + ac_cpp_err=$ac_c_preproc_warn_flag + ac_cpp_err=$ac_cpp_err$ac_c_werror_flag + else + ac_cpp_err= + fi +else + ac_cpp_err=yes +fi +if test -z "$ac_cpp_err"; then + ac_header_preproc=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_header_preproc=no +fi +rm -f conftest.err conftest.$ac_ext +echo "$as_me:$LINENO: result: $ac_header_preproc" >&5 +echo "${ECHO_T}$ac_header_preproc" >&6 + +# So? What about this header? +case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in + yes:no: ) + { echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5 +echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5 +echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;} + ac_header_preproc=yes + ;; + no:yes:* ) + { echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5 +echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: check for missing prerequisite headers?" >&5 +echo "$as_me: WARNING: $ac_header: check for missing prerequisite headers?" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5 +echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&5 +echo "$as_me: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5 +echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5 +echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;} + ( + cat <<\_ASBOX +## ------------------------------------------ ## +## Report this to the AC_PACKAGE_NAME lists. ## +## ------------------------------------------ ## +_ASBOX + ) | + sed "s/^/$as_me: WARNING: /" >&2 + ;; +esac +echo "$as_me:$LINENO: checking for $ac_header" >&5 +echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6 +if eval "test \"\${$as_ac_Header+set}\" = set"; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + eval "$as_ac_Header=\$ac_header_preproc" +fi +echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5 +echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6 + +fi +if test `eval echo '${'$as_ac_Header'}'` = yes; then + cat >>confdefs.h <<_ACEOF +#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1 +_ACEOF + +fi + +done + +if test x"$ac_cv_header_sys_ioctl_h" = xyes; then + HAVE_SYS_IOCTL_H_DEFINE=1 +else + HAVE_SYS_IOCTL_H_DEFINE=0 +fi + + + + +for ac_header in stdarg.h +do +as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh` +if eval "test \"\${$as_ac_Header+set}\" = set"; then + echo "$as_me:$LINENO: checking for $ac_header" >&5 +echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6 +if eval "test \"\${$as_ac_Header+set}\" = set"; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +fi +echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5 +echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6 +else + # Is the header compilable? +echo "$as_me:$LINENO: checking $ac_header usability" >&5 +echo $ECHO_N "checking $ac_header usability... $ECHO_C" >&6 +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +#include <$ac_header> +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_header_compiler=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_header_compiler=no +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +echo "$as_me:$LINENO: result: $ac_header_compiler" >&5 +echo "${ECHO_T}$ac_header_compiler" >&6 + +# Is the header present? +echo "$as_me:$LINENO: checking $ac_header presence" >&5 +echo $ECHO_N "checking $ac_header presence... $ECHO_C" >&6 +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include <$ac_header> +_ACEOF +if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 + (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null; then + if test -s conftest.err; then + ac_cpp_err=$ac_c_preproc_warn_flag + ac_cpp_err=$ac_cpp_err$ac_c_werror_flag + else + ac_cpp_err= + fi +else + ac_cpp_err=yes +fi +if test -z "$ac_cpp_err"; then + ac_header_preproc=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_header_preproc=no +fi +rm -f conftest.err conftest.$ac_ext +echo "$as_me:$LINENO: result: $ac_header_preproc" >&5 +echo "${ECHO_T}$ac_header_preproc" >&6 + +# So? What about this header? +case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in + yes:no: ) + { echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5 +echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5 +echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;} + ac_header_preproc=yes + ;; + no:yes:* ) + { echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5 +echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: check for missing prerequisite headers?" >&5 +echo "$as_me: WARNING: $ac_header: check for missing prerequisite headers?" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5 +echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&5 +echo "$as_me: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5 +echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5 +echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;} + ( + cat <<\_ASBOX +## ------------------------------------------ ## +## Report this to the AC_PACKAGE_NAME lists. ## +## ------------------------------------------ ## +_ASBOX + ) | + sed "s/^/$as_me: WARNING: /" >&2 + ;; +esac +echo "$as_me:$LINENO: checking for $ac_header" >&5 +echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6 +if eval "test \"\${$as_ac_Header+set}\" = set"; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + eval "$as_ac_Header=\$ac_header_preproc" +fi +echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5 +echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6 + +fi +if test `eval echo '${'$as_ac_Header'}'` = yes; then + cat >>confdefs.h <<_ACEOF +#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1 +_ACEOF + +else + +{ { echo "$as_me:$LINENO: error: stdarg.h is required to build this library" >&5 +echo "$as_me: error: stdarg.h is required to build this library" >&2;} + { (exit 1); exit 1; }; } + +fi + +done + + + + +echo "$as_me:$LINENO: checking for size_t" >&5 +echo $ECHO_N "checking for size_t... $ECHO_C" >&6 +if test "${ac_cv_type_size_t+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +int +main () +{ +if ((size_t *) 0) + return 0; +if (sizeof (size_t)) + return 0; + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_type_size_t=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_cv_type_size_t=no +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +fi +echo "$as_me:$LINENO: result: $ac_cv_type_size_t" >&5 +echo "${ECHO_T}$ac_cv_type_size_t" >&6 +if test $ac_cv_type_size_t = yes; then + : +else + +cat >>confdefs.h <<_ACEOF +#define size_t unsigned +_ACEOF + +fi + + +va_list_is_array=no +echo "$as_me:$LINENO: checking whether va_list is an array" >&5 +echo $ECHO_N "checking whether va_list is an array... $ECHO_C" >&6 +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +#include + +int +main () +{ +va_list list1, list2; list1 = list2; + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + : +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +va_list_is_array=yes +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +echo "$as_me:$LINENO: result: $va_list_is_array" >&5 +echo "${ECHO_T}$va_list_is_array" >&6 +if test x"$va_list_is_array" = xyes; then + VA_LIST_IS_ARRAY_DEFINE=1 +else + VA_LIST_IS_ARRAY_DEFINE=0 +fi + + +echo "$as_me:$LINENO: checking whether compiler has __attribute__" >&5 +echo $ECHO_N "checking whether compiler has __attribute__... $ECHO_C" >&6 +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ +int x __attribute__((__unused__)); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + compiler_has_attribute=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +compiler_has_attribute=no +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +echo "$as_me:$LINENO: result: $compiler_has_attribute" >&5 +echo "${ECHO_T}$compiler_has_attribute" >&6 +if test x"$compiler_has_attribute" = xyes; then + ATTR_UNUSED="__attribute__((__unused__))" +else + ATTR_UNUSED= +fi + + + + +echo "$as_me:$LINENO: checking for vsnprintf" >&5 +echo $ECHO_N "checking for vsnprintf... $ECHO_C" >&6 +if test "${ac_cv_func_vsnprintf+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +/* Define vsnprintf to an innocuous variant, in case declares vsnprintf. + For example, HP-UX 11i declares gettimeofday. */ +#define vsnprintf innocuous_vsnprintf + +/* System header to define __stub macros and hopefully few prototypes, + which can conflict with char vsnprintf (); below. + Prefer to if __STDC__ is defined, since + exists even on freestanding compilers. */ + +#ifdef __STDC__ +# include +#else +# include +#endif + +#undef vsnprintf + +/* Override any gcc2 internal prototype to avoid an error. */ +#ifdef __cplusplus +extern "C" +{ +#endif +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char vsnprintf (); +/* 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_vsnprintf) || defined (__stub___vsnprintf) +choke me +#else +char (*f) () = vsnprintf; +#endif +#ifdef __cplusplus +} +#endif + +int +main () +{ +return f != vsnprintf; + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_func_vsnprintf=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_cv_func_vsnprintf=no +fi +rm -f conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +fi +echo "$as_me:$LINENO: result: $ac_cv_func_vsnprintf" >&5 +echo "${ECHO_T}$ac_cv_func_vsnprintf" >&6 +if test $ac_cv_func_vsnprintf = yes; then + : +else + +{ { echo "$as_me:$LINENO: error: your C library does not provide vsnprintf" >&5 +echo "$as_me: error: your C library does not provide vsnprintf" >&2;} + { (exit 1); exit 1; }; } + +fi + + + +for ac_func in wcsncmp +do +as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh` +echo "$as_me:$LINENO: checking for $ac_func" >&5 +echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6 +if eval "test \"\${$as_ac_var+set}\" = set"; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +/* Define $ac_func to an innocuous variant, in case declares $ac_func. + For example, HP-UX 11i 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 to if __STDC__ is defined, since + exists even on freestanding compilers. */ + +#ifdef __STDC__ +# include +#else +# include +#endif + +#undef $ac_func + +/* Override any gcc2 internal prototype to avoid an error. */ +#ifdef __cplusplus +extern "C" +{ +#endif +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char $ac_func (); +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined (__stub_$ac_func) || defined (__stub___$ac_func) +choke me +#else +char (*f) () = $ac_func; +#endif +#ifdef __cplusplus +} +#endif + +int +main () +{ +return f != $ac_func; + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + eval "$as_ac_var=yes" +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +eval "$as_ac_var=no" +fi +rm -f conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +fi +echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_var'}'`" >&5 +echo "${ECHO_T}`eval echo '${'$as_ac_var'}'`" >&6 +if test `eval echo '${'$as_ac_var'}'` = yes; then + cat >>confdefs.h <<_ACEOF +#define `echo "HAVE_$ac_func" | $as_tr_cpp` 1 +_ACEOF + +fi +done + + + +for ac_func in setgroups +do +as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh` +echo "$as_me:$LINENO: checking for $ac_func" >&5 +echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6 +if eval "test \"\${$as_ac_var+set}\" = set"; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +/* Define $ac_func to an innocuous variant, in case declares $ac_func. + For example, HP-UX 11i 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 to if __STDC__ is defined, since + exists even on freestanding compilers. */ + +#ifdef __STDC__ +# include +#else +# include +#endif + +#undef $ac_func + +/* Override any gcc2 internal prototype to avoid an error. */ +#ifdef __cplusplus +extern "C" +{ +#endif +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char $ac_func (); +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined (__stub_$ac_func) || defined (__stub___$ac_func) +choke me +#else +char (*f) () = $ac_func; +#endif +#ifdef __cplusplus +} +#endif + +int +main () +{ +return f != $ac_func; + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + eval "$as_ac_var=yes" +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +eval "$as_ac_var=no" +fi +rm -f conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +fi +echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_var'}'`" >&5 +echo "${ECHO_T}`eval echo '${'$as_ac_var'}'`" >&6 +if test `eval echo '${'$as_ac_var'}'` = yes; then + cat >>confdefs.h <<_ACEOF +#define `echo "HAVE_$ac_func" | $as_tr_cpp` 1 +_ACEOF + +fi +done + + + +for ac_func in asprintf +do +as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh` +echo "$as_me:$LINENO: checking for $ac_func" >&5 +echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6 +if eval "test \"\${$as_ac_var+set}\" = set"; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +/* Define $ac_func to an innocuous variant, in case declares $ac_func. + For example, HP-UX 11i 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 to if __STDC__ is defined, since + exists even on freestanding compilers. */ + +#ifdef __STDC__ +# include +#else +# include +#endif + +#undef $ac_func + +/* Override any gcc2 internal prototype to avoid an error. */ +#ifdef __cplusplus +extern "C" +{ +#endif +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char $ac_func (); +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined (__stub_$ac_func) || defined (__stub___$ac_func) +choke me +#else +char (*f) () = $ac_func; +#endif +#ifdef __cplusplus +} +#endif + +int +main () +{ +return f != $ac_func; + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + eval "$as_ac_var=yes" +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +eval "$as_ac_var=no" +fi +rm -f conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +fi +echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_var'}'`" >&5 +echo "${ECHO_T}`eval echo '${'$as_ac_var'}'`" >&6 +if test `eval echo '${'$as_ac_var'}'` = yes; then + cat >>confdefs.h <<_ACEOF +#define `echo "HAVE_$ac_func" | $as_tr_cpp` 1 +_ACEOF + +fi +done + + + +for ac_func in setenv +do +as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh` +echo "$as_me:$LINENO: checking for $ac_func" >&5 +echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6 +if eval "test \"\${$as_ac_var+set}\" = set"; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +/* Define $ac_func to an innocuous variant, in case declares $ac_func. + For example, HP-UX 11i 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 to if __STDC__ is defined, since + exists even on freestanding compilers. */ + +#ifdef __STDC__ +# include +#else +# include +#endif + +#undef $ac_func + +/* Override any gcc2 internal prototype to avoid an error. */ +#ifdef __cplusplus +extern "C" +{ +#endif +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char $ac_func (); +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined (__stub_$ac_func) || defined (__stub___$ac_func) +choke me +#else +char (*f) () = $ac_func; +#endif +#ifdef __cplusplus +} +#endif + +int +main () +{ +return f != $ac_func; + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + eval "$as_ac_var=yes" +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +eval "$as_ac_var=no" +fi +rm -f conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +fi +echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_var'}'`" >&5 +echo "${ECHO_T}`eval echo '${'$as_ac_var'}'`" >&6 +if test `eval echo '${'$as_ac_var'}'` = yes; then + cat >>confdefs.h <<_ACEOF +#define `echo "HAVE_$ac_func" | $as_tr_cpp` 1 +_ACEOF + +fi +done + + + + +DIRECTORY_SEPARATOR="/" + + + + +echo "$as_me:$LINENO: checking whether to use Abyss pthread function" >&5 +echo $ECHO_N "checking whether to use Abyss pthread function... $ECHO_C" >&6 +# Check whether --enable-abyss-threads or --disable-abyss-threads was given. +if test "${enable_abyss_threads+set}" = set; then + enableval="$enable_abyss_threads" + +else + enable_abyss_threads=yes +fi; +echo "$as_me:$LINENO: result: $enable_abyss_threads" >&5 +echo "${ECHO_T}$enable_abyss_threads" >&6 + +ENABLE_ABYSS_THREADS=$enable_abyss_threads + + +if test x"$enable_abyss_threads" != xno; then + CFLAGS="$CFLAGS -D_THREAD" +fi + + + +if test $MUST_BUILD_WININET_CLIENT = yes; then + + for ac_prog in wininet-xmlrpc-config wininet-config +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_path_WININET_CONFIG+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + case $WININET_CONFIG in + [\\/]* | ?:[\\/]*) + ac_cv_path_WININET_CONFIG="$WININET_CONFIG" # Let the user override the test with a path. + ;; + *) + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_path_WININET_CONFIG="$as_dir/$ac_word$ac_exec_ext" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + + ;; +esac +fi +WININET_CONFIG=$ac_cv_path_WININET_CONFIG + +if test -n "$WININET_CONFIG"; then + echo "$as_me:$LINENO: result: $WININET_CONFIG" >&5 +echo "${ECHO_T}$WININET_CONFIG" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + + test -n "$WININET_CONFIG" && break +done +test -n "$WININET_CONFIG" || WININET_CONFIG="no" + + if test "x$WININET_CONFIG" = "xno"; then + { { echo "$as_me:$LINENO: error: wininet lib not found; see './configure --help'" >&5 +echo "$as_me: error: wininet lib not found; see './configure --help'" >&2;} + { (exit 1); exit 1; }; } + fi + + echo "$as_me:$LINENO: checking for wininet version >= 1.0.0" >&5 +echo $ECHO_N "checking for wininet version >= 1.0.0... $ECHO_C" >&6 + W3VER=`$WININET_CONFIG --version` + WININET_MAJOR=\ +`echo $W3VER|sed 's/\([0-9]*\)\.\([0-9]*\)\.\([0-9]*\)/\1/'` + WININET_MINOR=\ +`echo $W3VER|sed 's/\([0-9]*\)\.\([0-9]*\)\.\([0-9]*\)/\2/'` + WININET_MICRO=\ +`echo $W3VER|sed 's/\([0-9]*\)\.\([0-9]*\)\.\([0-9]*\)/\3/'` + echo "$as_me:$LINENO: result: $WININET_MAJOR.$WININET_MINOR.$WININET_MICRO" >&5 +echo "${ECHO_T}$WININET_MAJOR.$WININET_MINOR.$WININET_MICRO" >&6 + + WININET_VERSION_OK=yes + if test $WININET_MAJOR -lt 1; then + WININET_VERSION_OK=no + else + if test $WININET_MAJOR -eq 1 -a $WININET_MINOR -lt 0; then + WININET_VERSION_OK=no + else + if test $WININET_MAJOR -eq 1 -a $WININET_MINOR -eq 0 \ + -a $WININET_MICRO -lt 0; then + WININET_VERSION_OK=no + fi + fi + fi + if test "x$WININET_VERSION_OK" = "xno"; then + { { echo "$as_me:$LINENO: error: wininet version >= 1.0.0 required" >&5 +echo "$as_me: error: wininet version >= 1.0.0 required" >&2;} + { (exit 1); exit 1; }; } + fi + + WININET_CFLAGS="`$WININET_CONFIG --cflags`" + + CFLAGS="$CFLAGS $WININET_CFLAGS" + + WININET_LDADD="`$WININET_CONFIG --libs`" + + + echo "$as_me:$LINENO: checking for wininet library directory" >&5 +echo $ECHO_N "checking for wininet library directory... $ECHO_C" >&6 + if $WININET_CONFIG --rpath-dir > /dev/null 2>&1; then + WININET_LIBDIR="`$WININET_CONFIG --rpath-dir`" + else + WININET_LIBDIR="`$WININET_CONFIG --prefix`/lib" + fi + echo "$as_me:$LINENO: result: $WININET_LIBDIR" >&5 +echo "${ECHO_T}$WININET_LIBDIR" >&6 + + WININET_RPATH="-rpath $WININET_LIBDIR" + + WININET_WL_RPATH="-Wl,--rpath -Wl,$WININET_LIBDIR" + + +fi # MUST_BUILD_WININET_CLIENT + + +if test $MUST_BUILD_LIBWWW_CLIENT = yes; then + + for ac_prog in libwww-xmlrpc-config libwww-config +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_path_LIBWWW_CONFIG+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + case $LIBWWW_CONFIG in + [\\/]* | ?:[\\/]*) + ac_cv_path_LIBWWW_CONFIG="$LIBWWW_CONFIG" # Let the user override the test with a path. + ;; + *) + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_path_LIBWWW_CONFIG="$as_dir/$ac_word$ac_exec_ext" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + + ;; +esac +fi +LIBWWW_CONFIG=$ac_cv_path_LIBWWW_CONFIG + +if test -n "$LIBWWW_CONFIG"; then + echo "$as_me:$LINENO: result: $LIBWWW_CONFIG" >&5 +echo "${ECHO_T}$LIBWWW_CONFIG" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + + test -n "$LIBWWW_CONFIG" && break +done +test -n "$LIBWWW_CONFIG" || LIBWWW_CONFIG="no" + + if test "x$LIBWWW_CONFIG" = "xno"; then + { { echo "$as_me:$LINENO: error: w3c-libwww not found; see './configure --help'" >&5 +echo "$as_me: error: w3c-libwww not found; see './configure --help'" >&2;} + { (exit 1); exit 1; }; } + fi + + echo "$as_me:$LINENO: checking for w3c-libwww version >= 5.2.8" >&5 +echo $ECHO_N "checking for w3c-libwww version >= 5.2.8... $ECHO_C" >&6 + W3VER=`$LIBWWW_CONFIG --version` + LIBWWW_MAJOR=\ +`echo $W3VER|sed 's/\([0-9]*\)\.\([0-9]*\)\.\([0-9]*\)/\1/'` + LIBWWW_MINOR=\ +`echo $W3VER|sed 's/\([0-9]*\)\.\([0-9]*\)\.\([0-9]*\)/\2/'` + LIBWWW_MICRO=\ +`echo $W3VER|sed 's/\([0-9]*\)\.\([0-9]*\)\.\([0-9]*\)/\3/'` + echo "$as_me:$LINENO: result: $LIBWWW_MAJOR.$LIBWWW_MINOR.$LIBWWW_MICRO" >&5 +echo "${ECHO_T}$LIBWWW_MAJOR.$LIBWWW_MINOR.$LIBWWW_MICRO" >&6 + + LIBWWW_VERSION_OK=yes + if test $LIBWWW_MAJOR -lt 5; then + LIBWWW_VERSION_OK=no + else + if test $LIBWWW_MAJOR -eq 5 -a $LIBWWW_MINOR -lt 2; then + LIBWWW_VERSION_OK=no + else + if test $LIBWWW_MAJOR -eq 5 -a $LIBWWW_MINOR -eq 2 \ + -a $LIBWWW_MICRO -lt 8; then + LIBWWW_VERSION_OK=no + fi + fi + fi + if test "x$LIBWWW_VERSION_OK" = "xno"; then + { { echo "$as_me:$LINENO: error: w3c-libwww version >= 5.2.8 required" >&5 +echo "$as_me: error: w3c-libwww version >= 5.2.8 required" >&2;} + { (exit 1); exit 1; }; } + fi + + LIBWWW_LDADD="`$LIBWWW_CONFIG --libs`" + + + echo "$as_me:$LINENO: checking for libwww library directory" >&5 +echo $ECHO_N "checking for libwww library directory... $ECHO_C" >&6 + if $LIBWWW_CONFIG --rpath-dir > /dev/null 2>&1; then + LIBWWW_LIBDIR="`$LIBWWW_CONFIG --rpath-dir`" + else + LIBWWW_LIBDIR="`$LIBWWW_CONFIG --prefix`/lib" + fi + echo "$as_me:$LINENO: result: $LIBWWW_LIBDIR" >&5 +echo "${ECHO_T}$LIBWWW_LIBDIR" >&6 + + + # Some ancient rpath stuff, now disabled. I turned this off because it + # breaks Debian (and Mandrake?) policy, and we don't use it anymore. + # If you have multiple copies of w3c-libwww lying around, you can turn + # it back on. + #LIBWWW_RPATH="-rpath $LIBWWW_LIBDIR" + LIBWWW_RPATH="" + + #LIBWWW_WL_RPATH="-Wl,--rpath -Wl,$LIBWWW_LIBDIR" + LIBWWW_WL_RPATH="" + + +fi # MUST_BUILD_LIBWWW_CLIENT + + + +if test $MUST_BUILD_CURL_CLIENT = yes; then + + for ac_prog in curl-xmlrpc-config curl-config +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_path_CURL_CONFIG+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + case $CURL_CONFIG in + [\\/]* | ?:[\\/]*) + ac_cv_path_CURL_CONFIG="$CURL_CONFIG" # Let the user override the test with a path. + ;; + *) + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_path_CURL_CONFIG="$as_dir/$ac_word$ac_exec_ext" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + + ;; +esac +fi +CURL_CONFIG=$ac_cv_path_CURL_CONFIG + +if test -n "$CURL_CONFIG"; then + echo "$as_me:$LINENO: result: $CURL_CONFIG" >&5 +echo "${ECHO_T}$CURL_CONFIG" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + + test -n "$CURL_CONFIG" && break +done +test -n "$CURL_CONFIG" || CURL_CONFIG="no" + + if test "x$CURL_CONFIG" = "xno"; then + { { echo "$as_me:$LINENO: error: cURL not found; see './configure --help'" >&5 +echo "$as_me: error: cURL not found; see './configure --help'" >&2;} + { (exit 1); exit 1; }; } + fi + + + CURL_LDADD=`$CURL_CONFIG --libs` + + + echo "$as_me:$LINENO: checking for curl library directory" >&5 +echo $ECHO_N "checking for curl library directory... $ECHO_C" >&6 + CURL_LIBDIR="`$CURL_CONFIG --prefix`/lib" + + echo "$as_me:$LINENO: result: $CURL_LIBDIR" >&5 +echo "${ECHO_T}$CURL_LIBDIR" >&6 + + CURL_RPATH="-rpath $CURL_LIBDIR" + + CURL_WL_RPATH="-Wl,--rpath -Wl,$CURL_LIBDIR" + + +fi # MUST_BUILD_CURL_CLIENT + + + + +# Check whether --with-libwww-ssl or --without-libwww-ssl was given. +if test "${with_libwww_ssl+set}" = set; then + withval="$with_libwww_ssl" + +fi; + +if test x"$enable_libwww_client" != xno; then + echo "$as_me:$LINENO: checking whether to use SSL with libwww" >&5 +echo $ECHO_N "checking whether to use SSL with libwww... $ECHO_C" >&6 + if test x"$with_libwww_ssl" = xyes; then + echo "$as_me:$LINENO: result: yes" >&5 +echo "${ECHO_T}yes" >&6 + HAVE_LIBWWW_SSL_DEFINE=1 + else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 + HAVE_LIBWWW_SSL_DEFINE=0 + fi +fi + + +# Check whether --enable-libxml2-backend or --disable-libxml2-backend was given. +if test "${enable_libxml2_backend+set}" = set; then + enableval="$enable_libxml2_backend" + +else + enable_libxml2_backend=no +fi; +echo "$as_me:$LINENO: checking whether to build the libxml2 backend" >&5 +echo $ECHO_N "checking whether to build the libxml2 backend... $ECHO_C" >&6 +echo "$as_me:$LINENO: result: $enable_libxml2_backend" >&5 +echo "${ECHO_T}$enable_libxml2_backend" >&6 + +if test $enable_libxml2_backend = yes; then + # Extract the first word of "xml2-config", so it can be a program name with args. +set dummy xml2-config; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_have_xml2_config+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$have_xml2_config"; then + ac_cv_prog_have_xml2_config="$have_xml2_config" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_have_xml2_config="yes" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + + test -z "$ac_cv_prog_have_xml2_config" && ac_cv_prog_have_xml2_config="no" +fi +fi +have_xml2_config=$ac_cv_prog_have_xml2_config +if test -n "$have_xml2_config"; then + echo "$as_me:$LINENO: result: $have_xml2_config" >&5 +echo "${ECHO_T}$have_xml2_config" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + + if test $have_xml2_config = no; then + { { echo "$as_me:$LINENO: error: You specified --enable-libxml2_backend, but don't appear to have libxml2 installed (no working xml2-config inyour command search path), so we cannot not build for libxml2" >&5 +echo "$as_me: error: You specified --enable-libxml2_backend, but don't appear to have libxml2 installed (no working xml2-config inyour command search path), so we cannot not build for libxml2" >&2;} + { (exit 1); exit 1; }; } + fi +fi +ENABLE_LIBXML2_BACKEND=$enable_libxml2_backend + + +C_COMPILER_GNU=$ac_cv_c_compiler_gnu + +CXX_COMPILER_GNU=$ac_cv_cxx_compiler_gnu + + +CC_WARN_FLAGS= + +CPP_WARN_FLAGS= + + + +BUILDDIR=`pwd` + + +# Check whether --enable-shared or --disable-shared was given. +if test "${enable_shared+set}" = set; then + enableval="$enable_shared" + p=${PACKAGE-default} +case "$enableval" in +yes) enable_shared=yes ;; +no) enable_shared=no ;; +*) + enable_shared=no + # Look at the argument we got. We use all the common list separators. + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}:," + for pkg in $enableval; do + if test "X$pkg" = "X$p"; then + enable_shared=yes + fi + done + IFS="$ac_save_ifs" + ;; +esac +else + enable_shared=yes +fi; +# Check whether --enable-static or --disable-static was given. +if test "${enable_static+set}" = set; then + enableval="$enable_static" + p=${PACKAGE-default} +case "$enableval" in +yes) enable_static=yes ;; +no) enable_static=no ;; +*) + enable_static=no + # Look at the argument we got. We use all the common list separators. + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}:," + for pkg in $enableval; do + if test "X$pkg" = "X$p"; then + enable_static=yes + fi + done + IFS="$ac_save_ifs" + ;; +esac +else + enable_static=yes +fi; +# Check whether --enable-fast-install or --disable-fast-install was given. +if test "${enable_fast_install+set}" = set; then + enableval="$enable_fast_install" + p=${PACKAGE-default} +case "$enableval" in +yes) enable_fast_install=yes ;; +no) enable_fast_install=no ;; +*) + enable_fast_install=no + # Look at the argument we got. We use all the common list separators. + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}:," + for pkg in $enableval; do + if test "X$pkg" = "X$p"; then + enable_fast_install=yes + fi + done + IFS="$ac_save_ifs" + ;; +esac +else + enable_fast_install=yes +fi; +if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}ranlib", so it can be a program name with args. +set dummy ${ac_tool_prefix}ranlib; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_RANLIB+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$RANLIB"; then + ac_cv_prog_RANLIB="$RANLIB" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_RANLIB="${ac_tool_prefix}ranlib" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + +fi +fi +RANLIB=$ac_cv_prog_RANLIB +if test -n "$RANLIB"; then + echo "$as_me:$LINENO: result: $RANLIB" >&5 +echo "${ECHO_T}$RANLIB" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + +fi +if test -z "$ac_cv_prog_RANLIB"; then + ac_ct_RANLIB=$RANLIB + # Extract the first word of "ranlib", so it can be a program name with args. +set dummy ranlib; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_ac_ct_RANLIB+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$ac_ct_RANLIB"; then + ac_cv_prog_ac_ct_RANLIB="$ac_ct_RANLIB" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_RANLIB="ranlib" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + + test -z "$ac_cv_prog_ac_ct_RANLIB" && ac_cv_prog_ac_ct_RANLIB=":" +fi +fi +ac_ct_RANLIB=$ac_cv_prog_ac_ct_RANLIB +if test -n "$ac_ct_RANLIB"; then + echo "$as_me:$LINENO: result: $ac_ct_RANLIB" >&5 +echo "${ECHO_T}$ac_ct_RANLIB" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + + RANLIB=$ac_ct_RANLIB +else + RANLIB="$ac_cv_prog_RANLIB" +fi + + +# Check whether --with-gnu-ld or --without-gnu-ld was given. +if test "${with_gnu_ld+set}" = set; then + withval="$with_gnu_ld" + test "$withval" = no || with_gnu_ld=yes +else + with_gnu_ld=no +fi; +ac_prog=ld +if test "$ac_cv_c_compiler_gnu" = yes; then + # Check if gcc -print-prog-name=ld gives a path. + echo "$as_me:$LINENO: checking for ld used by GCC" >&5 +echo $ECHO_N "checking for ld used by GCC... $ECHO_C" >&6 + ac_prog=`($CC -print-prog-name=ld) 2>&5` + case "$ac_prog" in + # Accept absolute paths. + [\\/]* | [A-Za-z]:[\\/]*) + re_direlt='/[^/][^/]*/\.\./' + # Canonicalize the path of ld + ac_prog=`echo $ac_prog| sed 's%\\\\%/%g'` + while echo $ac_prog | grep "$re_direlt" > /dev/null 2>&1; do + ac_prog=`echo $ac_prog| sed "s%$re_direlt%/%"` + done + test -z "$LD" && LD="$ac_prog" + ;; + "") + # If it fails, then pretend we aren't using GCC. + ac_prog=ld + ;; + *) + # If it is relative, then search for the first ld in PATH. + with_gnu_ld=unknown + ;; + esac +elif test "$with_gnu_ld" = yes; then + echo "$as_me:$LINENO: checking for GNU ld" >&5 +echo $ECHO_N "checking for GNU ld... $ECHO_C" >&6 +else + echo "$as_me:$LINENO: checking for non-GNU ld" >&5 +echo $ECHO_N "checking for non-GNU ld... $ECHO_C" >&6 +fi +if test "${ac_cv_path_LD+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -z "$LD"; then + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}${PATH_SEPARATOR-:}" + for ac_dir in $PATH; do + test -z "$ac_dir" && ac_dir=. + if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then + ac_cv_path_LD="$ac_dir/$ac_prog" + # Check to see if the program is GNU ld. I'd rather use --version, + # but apparently some GNU ld's only accept -v. + # Break only if it was the GNU/non-GNU ld that we prefer. + if "$ac_cv_path_LD" -v 2>&1 < /dev/null | egrep '(GNU|with BFD)' > /dev/null; then + test "$with_gnu_ld" != no && break + else + test "$with_gnu_ld" != yes && break + fi + fi + done + IFS="$ac_save_ifs" +else + ac_cv_path_LD="$LD" # Let the user override the test with a path. +fi +fi + +LD="$ac_cv_path_LD" +if test -n "$LD"; then + echo "$as_me:$LINENO: result: $LD" >&5 +echo "${ECHO_T}$LD" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi +test -z "$LD" && { { echo "$as_me:$LINENO: error: no acceptable ld found in \$PATH" >&5 +echo "$as_me: error: no acceptable ld found in \$PATH" >&2;} + { (exit 1); exit 1; }; } +echo "$as_me:$LINENO: checking if the linker ($LD) is GNU ld" >&5 +echo $ECHO_N "checking if the linker ($LD) is GNU ld... $ECHO_C" >&6 +if test "${ac_cv_prog_gnu_ld+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + # I'd rather use --version here, but apparently some GNU ld's only accept -v. +if $LD -v 2>&1 &5; then + ac_cv_prog_gnu_ld=yes +else + ac_cv_prog_gnu_ld=no +fi +fi +echo "$as_me:$LINENO: result: $ac_cv_prog_gnu_ld" >&5 +echo "${ECHO_T}$ac_cv_prog_gnu_ld" >&6 + + +echo "$as_me:$LINENO: checking for BSD-compatible nm" >&5 +echo $ECHO_N "checking for BSD-compatible nm... $ECHO_C" >&6 +if test "${ac_cv_path_NM+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$NM"; then + # Let the user override the test. + ac_cv_path_NM="$NM" +else + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}${PATH_SEPARATOR-:}" + for ac_dir in $PATH /usr/ccs/bin /usr/ucb /bin; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/nm || test -f $ac_dir/nm$ac_exeext ; then + # Check to see if the nm accepts a BSD-compat flag. + # Adding the `sed 1q' prevents false positives on HP-UX, which says: + # nm: unknown option "B" ignored + if ($ac_dir/nm -B /dev/null 2>&1 | sed '1q'; exit 0) | egrep /dev/null >/dev/null; then + ac_cv_path_NM="$ac_dir/nm -B" + break + elif ($ac_dir/nm -p /dev/null 2>&1 | sed '1q'; exit 0) | egrep /dev/null >/dev/null; then + ac_cv_path_NM="$ac_dir/nm -p" + break + else + ac_cv_path_NM=${ac_cv_path_NM="$ac_dir/nm"} # keep the first match, but + continue # so that we can try to find one that supports BSD flags + fi + fi + done + IFS="$ac_save_ifs" + test -z "$ac_cv_path_NM" && ac_cv_path_NM=nm +fi +fi + +NM="$ac_cv_path_NM" +echo "$as_me:$LINENO: result: $NM" >&5 +echo "${ECHO_T}$NM" >&6 + +echo "$as_me:$LINENO: checking whether ln -s works" >&5 +echo $ECHO_N "checking whether ln -s works... $ECHO_C" >&6 +LN_S=$as_ln_s +if test "$LN_S" = "ln -s"; then + echo "$as_me:$LINENO: result: yes" >&5 +echo "${ECHO_T}yes" >&6 +else + echo "$as_me:$LINENO: result: no, using $LN_S" >&5 +echo "${ECHO_T}no, using $LN_S" >&6 +fi + + +case "$target" in +NONE) lt_target="$host" ;; +*) lt_target="$target" ;; +esac + +# Check for any special flags to pass to ltconfig. +# +# the following will cause an existing older ltconfig to fail, so +# we ignore this at the expense of the cache file... Checking this +# will just take longer ... bummer! +#libtool_flags="--cache-file=$cache_file" +# +test "$enable_shared" = no && libtool_flags="$libtool_flags --disable-shared" +test "$enable_static" = no && libtool_flags="$libtool_flags --disable-static" +test "$enable_fast_install" = no && libtool_flags="$libtool_flags --disable-fast-install" +test "$ac_cv_c_compiler_gnu" = yes && libtool_flags="$libtool_flags --with-gcc" +test "$ac_cv_prog_gnu_ld" = yes && libtool_flags="$libtool_flags --with-gnu-ld" + + +# Check whether --enable-libtool-lock or --disable-libtool-lock was given. +if test "${enable_libtool_lock+set}" = set; then + enableval="$enable_libtool_lock" + +fi; +test "x$enable_libtool_lock" = xno && libtool_flags="$libtool_flags --disable-lock" +test x"$silent" = xyes && libtool_flags="$libtool_flags --silent" + +# Some flags need to be propagated to the compiler or linker for good +# libtool support. +case "$lt_target" in +*-*-irix6*) + # Find out which ABI we are using. + echo '#line 6049 "configure"' > conftest.$ac_ext + if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; then + case "`/usr/bin/file conftest.o`" in + *32-bit*) + LD="${LD-ld} -32" + ;; + *N32*) + LD="${LD-ld} -n32" + ;; + *64-bit*) + LD="${LD-ld} -64" + ;; + esac + fi + rm -rf conftest* + ;; + +*-*-sco3.2v5*) + # On SCO OpenServer 5, we need -belf to get full-featured binaries. + SAVE_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS -belf" + echo "$as_me:$LINENO: checking whether the C compiler needs -belf" >&5 +echo $ECHO_N "checking whether the C compiler needs -belf... $ECHO_C" >&6 +if test "${lt_cv_cc_needs_belf+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + lt_cv_cc_needs_belf=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +lt_cv_cc_needs_belf=no +fi +rm -f conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +fi +echo "$as_me:$LINENO: result: $lt_cv_cc_needs_belf" >&5 +echo "${ECHO_T}$lt_cv_cc_needs_belf" >&6 + if test x"$lt_cv_cc_needs_belf" != x"yes"; then + # this is probably gcc 2.8.0, egcs 1.0 or newer; no need for -belf + CFLAGS="$SAVE_CFLAGS" + fi + ;; + + +esac + + +# Save cache, so that ltconfig can load it +cat >confcache <<\_ACEOF +# This file is a shell script that caches the results of configure +# tests run on this system so they can be shared between configure +# scripts and configure runs, see configure's option --config-cache. +# It is not useful on other systems. If it contains results you don't +# want to keep, you may remove or edit it. +# +# config.status only pays attention to the cache file if you give it +# the --recheck option to rerun configure. +# +# `ac_cv_env_foo' variables (set or unset) will be overridden when +# loading this file, other *unset* `ac_cv_foo' will be assigned the +# following values. + +_ACEOF + +# The following way of writing the cache mishandles newlines in values, +# but we know of no workaround that is simple, portable, and efficient. +# So, don't put newlines in cache variables' values. +# Ultrix sh set writes to stderr and can't be redirected directly, +# and sets the high bit in the cache file unless we assign to the vars. +{ + (set) 2>&1 | + case `(ac_space=' '; set | grep ac_space) 2>&1` in + *ac_space=\ *) + # `set' does not quote correctly, so add quotes (double-quote + # substitution turns \\\\ into \\, and sed turns \\ into \). + sed -n \ + "s/'/'\\\\''/g; + s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p" + ;; + *) + # `set' quotes correctly as required by POSIX, so do not add quotes. + sed -n \ + "s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1=\\2/p" + ;; + esac; +} | + sed ' + t clear + : clear + s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/ + t end + /^ac_cv_env/!s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/ + : end' >>confcache +if diff $cache_file confcache >/dev/null 2>&1; then :; else + if test -w $cache_file; then + test "x$cache_file" != "x/dev/null" && echo "updating cache $cache_file" + cat confcache >$cache_file + else + echo "not updating unwritable cache $cache_file" + fi +fi +rm -f confcache + +# Actually configure libtool. ac_aux_dir is where install-sh is found. +CC="$CC" CFLAGS="$CFLAGS" CPPFLAGS="$CPPFLAGS" \ +LD="$LD" LDFLAGS="$LDFLAGS" LIBS="$LIBS" \ +LN_S="$LN_S" NM="$NM" RANLIB="$RANLIB" \ +DLLTOOL="$DLLTOOL" AS="$AS" OBJDUMP="$OBJDUMP" \ +${CONFIG_SHELL-/bin/sh} $ac_aux_dir/ltconfig --no-reexec \ +$libtool_flags --no-verify $ac_aux_dir/ltmain.sh $lt_target \ +|| { { echo "$as_me:$LINENO: error: libtool configure failed" >&5 +echo "$as_me: error: libtool configure failed" >&2;} + { (exit 1); exit 1; }; } + +# Reload cache, that may have been modified by ltconfig +if test -r "$cache_file"; then + # Some versions of bash will fail to source /dev/null (special + # files actually), so we avoid doing that. + if test -f "$cache_file"; then + { echo "$as_me:$LINENO: loading cache $cache_file" >&5 +echo "$as_me: loading cache $cache_file" >&6;} + case $cache_file in + [\\/]* | ?:[\\/]* ) . $cache_file;; + *) . ./$cache_file;; + esac + fi +else + { echo "$as_me:$LINENO: creating cache $cache_file" >&5 +echo "$as_me: creating cache $cache_file" >&6;} + >$cache_file +fi + + +# This can be used to rebuild libtool when needed +LIBTOOL_DEPS="$ac_aux_dir/ltconfig $ac_aux_dir/ltmain.sh" + +# Always use our own libtool. +LIBTOOL='$(SHELL) $(top_builddir)/libtool' + +# Redirect the config.log output again, so that the ltconfig log is not +# clobbered by the next message. +exec 5>>./config.log + + + + + + ac_config_files="$ac_config_files xmlrpc-c-config xmlrpc-c-config.test Makefile.config xmlrpc_config.h" +cat >confcache <<\_ACEOF +# This file is a shell script that caches the results of configure +# tests run on this system so they can be shared between configure +# scripts and configure runs, see configure's option --config-cache. +# It is not useful on other systems. If it contains results you don't +# want to keep, you may remove or edit it. +# +# config.status only pays attention to the cache file if you give it +# the --recheck option to rerun configure. +# +# `ac_cv_env_foo' variables (set or unset) will be overridden when +# loading this file, other *unset* `ac_cv_foo' will be assigned the +# following values. + +_ACEOF + +# The following way of writing the cache mishandles newlines in values, +# but we know of no workaround that is simple, portable, and efficient. +# So, don't put newlines in cache variables' values. +# Ultrix sh set writes to stderr and can't be redirected directly, +# and sets the high bit in the cache file unless we assign to the vars. +{ + (set) 2>&1 | + case `(ac_space=' '; set | grep ac_space) 2>&1` in + *ac_space=\ *) + # `set' does not quote correctly, so add quotes (double-quote + # substitution turns \\\\ into \\, and sed turns \\ into \). + sed -n \ + "s/'/'\\\\''/g; + s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p" + ;; + *) + # `set' quotes correctly as required by POSIX, so do not add quotes. + sed -n \ + "s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1=\\2/p" + ;; + esac; +} | + sed ' + t clear + : clear + s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/ + t end + /^ac_cv_env/!s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/ + : end' >>confcache +if diff $cache_file confcache >/dev/null 2>&1; then :; else + if test -w $cache_file; then + test "x$cache_file" != "x/dev/null" && echo "updating cache $cache_file" + cat confcache >$cache_file + else + echo "not updating unwritable cache $cache_file" + fi +fi +rm -f confcache + +test "x$prefix" = xNONE && prefix=$ac_default_prefix +# Let make expand exec_prefix. +test "x$exec_prefix" = xNONE && exec_prefix='${prefix}' + +# VPATH may cause trouble with some makes, so we remove $(srcdir), +# ${srcdir} and @srcdir@ from VPATH if srcdir is ".", strip leading and +# trailing colons and then remove the whole line if VPATH becomes empty +# (actually we leave an empty line to preserve line numbers). +if test "x$srcdir" = x.; then + ac_vpsub='/^[ ]*VPATH[ ]*=/{ +s/:*\$(srcdir):*/:/; +s/:*\${srcdir}:*/:/; +s/:*@srcdir@:*/:/; +s/^\([^=]*=[ ]*\):*/\1/; +s/:*$//; +s/^[^=]*=[ ]*$//; +}' +fi + +DEFS=-DHAVE_CONFIG_H + +ac_libobjs= +ac_ltlibobjs= +for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue + # 1. Remove the extension, and $U if already installed. + ac_i=`echo "$ac_i" | + sed 's/\$U\././;s/\.o$//;s/\.obj$//'` + # 2. Add them. + ac_libobjs="$ac_libobjs $ac_i\$U.$ac_objext" + ac_ltlibobjs="$ac_ltlibobjs $ac_i"'$U.lo' +done +LIBOBJS=$ac_libobjs + +LTLIBOBJS=$ac_ltlibobjs + + + +: ${CONFIG_STATUS=./config.status} +ac_clean_files_save=$ac_clean_files +ac_clean_files="$ac_clean_files $CONFIG_STATUS" +{ echo "$as_me:$LINENO: creating $CONFIG_STATUS" >&5 +echo "$as_me: creating $CONFIG_STATUS" >&6;} +cat >$CONFIG_STATUS <<_ACEOF +#! $SHELL +# Generated by $as_me. +# Run this file to recreate the current configuration. +# Compiler output produced by configure, useful for debugging +# configure, is in config.log if it exists. + +debug=false +ac_cs_recheck=false +ac_cs_silent=false +SHELL=\${CONFIG_SHELL-$SHELL} +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF +## --------------------- ## +## M4sh Initialization. ## +## --------------------- ## + +# Be Bourne compatible +if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then + emulate sh + NULLCMD=: + # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which + # is contrary to our usage. Disable this feature. + alias -g '${1+"$@"}'='"$@"' +elif test -n "${BASH_VERSION+set}" && (set -o posix) >/dev/null 2>&1; then + set -o posix +fi +DUALCASE=1; export DUALCASE # for MKS sh + +# Support unset when possible. +if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then + as_unset=unset +else + as_unset=false +fi + + +# Work around bugs in pre-3.0 UWIN ksh. +$as_unset ENV MAIL MAILPATH +PS1='$ ' +PS2='> ' +PS4='+ ' + +# NLS nuisances. +for as_var in \ + LANG LANGUAGE LC_ADDRESS LC_ALL LC_COLLATE LC_CTYPE LC_IDENTIFICATION \ + LC_MEASUREMENT LC_MESSAGES LC_MONETARY LC_NAME LC_NUMERIC LC_PAPER \ + LC_TELEPHONE LC_TIME +do + if (set +x; test -z "`(eval $as_var=C; export $as_var) 2>&1`"); then + eval $as_var=C; export $as_var + else + $as_unset $as_var + fi +done + +# Required to use basename. +if expr a : '\(a\)' >/dev/null 2>&1; then + as_expr=expr +else + as_expr=false +fi + +if (basename /) >/dev/null 2>&1 && test "X`basename / 2>&1`" = "X/"; then + as_basename=basename +else + as_basename=false +fi + + +# Name of the executable. +as_me=`$as_basename "$0" || +$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ + X"$0" : 'X\(//\)$' \| \ + X"$0" : 'X\(/\)$' \| \ + . : '\(.\)' 2>/dev/null || +echo X/"$0" | + sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/; q; } + /^X\/\(\/\/\)$/{ s//\1/; q; } + /^X\/\(\/\).*/{ s//\1/; q; } + s/.*/./; q'` + + +# PATH needs CR, and LINENO needs CR and PATH. +# Avoid depending upon Character Ranges. +as_cr_letters='abcdefghijklmnopqrstuvwxyz' +as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' +as_cr_Letters=$as_cr_letters$as_cr_LETTERS +as_cr_digits='0123456789' +as_cr_alnum=$as_cr_Letters$as_cr_digits + +# The user is always right. +if test "${PATH_SEPARATOR+set}" != set; then + echo "#! /bin/sh" >conf$$.sh + echo "exit 0" >>conf$$.sh + chmod +x conf$$.sh + if (PATH="/nonexistent;."; conf$$.sh) >/dev/null 2>&1; then + PATH_SEPARATOR=';' + else + PATH_SEPARATOR=: + fi + rm -f conf$$.sh +fi + + + as_lineno_1=$LINENO + as_lineno_2=$LINENO + as_lineno_3=`(expr $as_lineno_1 + 1) 2>/dev/null` + test "x$as_lineno_1" != "x$as_lineno_2" && + test "x$as_lineno_3" = "x$as_lineno_2" || { + # Find who we are. Look in the path if we contain no path at all + # relative or not. + case $0 in + *[\\/]* ) as_myself=$0 ;; + *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break +done + + ;; + esac + # We did not find ourselves, most probably we were run as `sh COMMAND' + # in which case we are not to be found in the path. + if test "x$as_myself" = x; then + as_myself=$0 + fi + if test ! -f "$as_myself"; then + { { echo "$as_me:$LINENO: error: cannot find myself; rerun with an absolute path" >&5 +echo "$as_me: error: cannot find myself; rerun with an absolute path" >&2;} + { (exit 1); exit 1; }; } + fi + case $CONFIG_SHELL in + '') + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for as_base in sh bash ksh sh5; do + case $as_dir in + /*) + if ("$as_dir/$as_base" -c ' + as_lineno_1=$LINENO + as_lineno_2=$LINENO + as_lineno_3=`(expr $as_lineno_1 + 1) 2>/dev/null` + test "x$as_lineno_1" != "x$as_lineno_2" && + test "x$as_lineno_3" = "x$as_lineno_2" ') 2>/dev/null; then + $as_unset BASH_ENV || test "${BASH_ENV+set}" != set || { BASH_ENV=; export BASH_ENV; } + $as_unset ENV || test "${ENV+set}" != set || { ENV=; export ENV; } + CONFIG_SHELL=$as_dir/$as_base + export CONFIG_SHELL + exec "$CONFIG_SHELL" "$0" ${1+"$@"} + fi;; + esac + done +done +;; + esac + + # Create $as_me.lineno as a copy of $as_myself, but with $LINENO + # uniformly replaced by the line number. The first 'sed' inserts a + # line-number line before each line; the second 'sed' does the real + # work. The second script uses 'N' to pair each line-number line + # with the numbered line, and appends trailing '-' during + # substitution so that $LINENO is not a special case at line end. + # (Raja R Harinath suggested sed '=', and Paul Eggert wrote the + # second 'sed' script. Blame Lee E. McMahon for sed's syntax. :-) + sed '=' <$as_myself | + sed ' + N + s,$,-, + : loop + s,^\(['$as_cr_digits']*\)\(.*\)[$]LINENO\([^'$as_cr_alnum'_]\),\1\2\1\3, + t loop + s,-$,, + s,^['$as_cr_digits']*\n,, + ' >$as_me.lineno && + chmod +x $as_me.lineno || + { { echo "$as_me:$LINENO: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&5 +echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2;} + { (exit 1); exit 1; }; } + + # Don't try to exec as it changes $[0], causing all sort of problems + # (the dirname of $[0] is not the place where we might find the + # original and so on. Autoconf is especially sensible to this). + . ./$as_me.lineno + # Exit status is that of the last command. + exit +} + + +case `echo "testing\c"; echo 1,2,3`,`echo -n testing; echo 1,2,3` in + *c*,-n*) ECHO_N= ECHO_C=' +' ECHO_T=' ' ;; + *c*,* ) ECHO_N=-n ECHO_C= ECHO_T= ;; + *) ECHO_N= ECHO_C='\c' ECHO_T= ;; +esac + +if expr a : '\(a\)' >/dev/null 2>&1; then + as_expr=expr +else + as_expr=false +fi + +rm -f conf$$ conf$$.exe conf$$.file +echo >conf$$.file +if ln -s conf$$.file conf$$ 2>/dev/null; then + # We could just check for DJGPP; but this test a) works b) is more generic + # and c) will remain valid once DJGPP supports symlinks (DJGPP 2.04). + if test -f conf$$.exe; then + # Don't use ln at all; we don't have any links + as_ln_s='cp -p' + else + as_ln_s='ln -s' + fi +elif ln conf$$.file conf$$ 2>/dev/null; then + as_ln_s=ln +else + as_ln_s='cp -p' +fi +rm -f conf$$ conf$$.exe conf$$.file + +if mkdir -p . 2>/dev/null; then + as_mkdir_p=: +else + test -d ./-p && rmdir ./-p + as_mkdir_p=false +fi + +as_executable_p="test -f" + +# Sed expression to map a string onto a valid CPP name. +as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" + +# Sed expression to map a string onto a valid variable name. +as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" + + +# IFS +# We need space, tab and new line, in precisely that order. +as_nl=' +' +IFS=" $as_nl" + +# CDPATH. +$as_unset CDPATH + +exec 6>&1 + +# Open the log real soon, to keep \$[0] and so on meaningful, and to +# report actual input values of CONFIG_FILES etc. instead of their +# values after options handling. Logging --version etc. is OK. +exec 5>>config.log +{ + echo + sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX +## Running $as_me. ## +_ASBOX +} >&5 +cat >&5 <<_CSEOF + +This file was extended by $as_me, which was +generated by GNU Autoconf 2.59. Invocation command line was + + CONFIG_FILES = $CONFIG_FILES + CONFIG_HEADERS = $CONFIG_HEADERS + CONFIG_LINKS = $CONFIG_LINKS + CONFIG_COMMANDS = $CONFIG_COMMANDS + $ $0 $@ + +_CSEOF +echo "on `(hostname || uname -n) 2>/dev/null | sed 1q`" >&5 +echo >&5 +_ACEOF + +# Files that config.status was made for. +if test -n "$ac_config_files"; then + echo "config_files=\"$ac_config_files\"" >>$CONFIG_STATUS +fi + +if test -n "$ac_config_headers"; then + echo "config_headers=\"$ac_config_headers\"" >>$CONFIG_STATUS +fi + +if test -n "$ac_config_links"; then + echo "config_links=\"$ac_config_links\"" >>$CONFIG_STATUS +fi + +if test -n "$ac_config_commands"; then + echo "config_commands=\"$ac_config_commands\"" >>$CONFIG_STATUS +fi + +cat >>$CONFIG_STATUS <<\_ACEOF + +ac_cs_usage="\ +\`$as_me' instantiates files from templates according to the +current configuration. + +Usage: $0 [OPTIONS] [FILE]... + + -h, --help print this help, then exit + -V, --version print version number, then exit + -q, --quiet do not print progress messages + -d, --debug don't remove temporary files + --recheck update $as_me by reconfiguring in the same conditions + --file=FILE[:TEMPLATE] + instantiate the configuration file FILE + --header=FILE[:TEMPLATE] + instantiate the configuration header FILE + +Configuration files: +$config_files + +Configuration headers: +$config_headers + +Configuration commands: +$config_commands + +Report bugs to ." +_ACEOF + +cat >>$CONFIG_STATUS <<_ACEOF +ac_cs_version="\\ +config.status +configured by $0, generated by GNU Autoconf 2.59, + with options \\"`echo "$ac_configure_args" | sed 's/[\\""\`\$]/\\\\&/g'`\\" + +Copyright (C) 2003 Free Software Foundation, Inc. +This config.status script is free software; the Free Software Foundation +gives unlimited permission to copy, distribute and modify it." +srcdir=$srcdir +INSTALL="$INSTALL" +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF +# If no file are specified by the user, then we need to provide default +# value. By we need to know if files were specified by the user. +ac_need_defaults=: +while test $# != 0 +do + case $1 in + --*=*) + ac_option=`expr "x$1" : 'x\([^=]*\)='` + ac_optarg=`expr "x$1" : 'x[^=]*=\(.*\)'` + ac_shift=: + ;; + -*) + ac_option=$1 + ac_optarg=$2 + ac_shift=shift + ;; + *) # This is not an option, so the user has probably given explicit + # arguments. + ac_option=$1 + ac_need_defaults=false;; + esac + + case $ac_option in + # Handling of the options. +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF + -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) + ac_cs_recheck=: ;; + --version | --vers* | -V ) + echo "$ac_cs_version"; exit 0 ;; + --he | --h) + # Conflict between --help and --header + { { echo "$as_me:$LINENO: error: ambiguous option: $1 +Try \`$0 --help' for more information." >&5 +echo "$as_me: error: ambiguous option: $1 +Try \`$0 --help' for more information." >&2;} + { (exit 1); exit 1; }; };; + --help | --hel | -h ) + echo "$ac_cs_usage"; exit 0 ;; + --debug | --d* | -d ) + debug=: ;; + --file | --fil | --fi | --f ) + $ac_shift + CONFIG_FILES="$CONFIG_FILES $ac_optarg" + ac_need_defaults=false;; + --header | --heade | --head | --hea ) + $ac_shift + CONFIG_HEADERS="$CONFIG_HEADERS $ac_optarg" + ac_need_defaults=false;; + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil | --si | --s) + ac_cs_silent=: ;; + + # This is an error. + -*) { { echo "$as_me:$LINENO: error: unrecognized option: $1 +Try \`$0 --help' for more information." >&5 +echo "$as_me: error: unrecognized option: $1 +Try \`$0 --help' for more information." >&2;} + { (exit 1); exit 1; }; } ;; + + *) ac_config_targets="$ac_config_targets $1" ;; + + esac + shift +done + +ac_configure_extra_args= + +if $ac_cs_silent; then + exec 6>/dev/null + ac_configure_extra_args="$ac_configure_extra_args --silent" +fi + +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF +if \$ac_cs_recheck; then + echo "running $SHELL $0 " $ac_configure_args \$ac_configure_extra_args " --no-create --no-recursion" >&6 + exec $SHELL $0 $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion +fi + +_ACEOF + +cat >>$CONFIG_STATUS <<_ACEOF +# +# INIT-COMMANDS section. +# + + + +_ACEOF + + + +cat >>$CONFIG_STATUS <<\_ACEOF +for ac_config_target in $ac_config_targets +do + case "$ac_config_target" in + # Handling of arguments. + "xmlrpc-c-config" ) CONFIG_FILES="$CONFIG_FILES xmlrpc-c-config" ;; + "xmlrpc-c-config.test" ) CONFIG_FILES="$CONFIG_FILES xmlrpc-c-config.test" ;; + "Makefile.config" ) CONFIG_FILES="$CONFIG_FILES Makefile.config" ;; + "xmlrpc_config.h" ) CONFIG_FILES="$CONFIG_FILES xmlrpc_config.h" ;; + "default-1" ) CONFIG_COMMANDS="$CONFIG_COMMANDS default-1" ;; + "xmlrpc_amconfig.h" ) CONFIG_HEADERS="$CONFIG_HEADERS xmlrpc_amconfig.h" ;; + *) { { echo "$as_me:$LINENO: error: invalid argument: $ac_config_target" >&5 +echo "$as_me: error: invalid argument: $ac_config_target" >&2;} + { (exit 1); exit 1; }; };; + esac +done + +# If the user did not use the arguments to specify the items to instantiate, +# then the envvar interface is used. Set only those that are not. +# We use the long form for the default assignment because of an extremely +# bizarre bug on SunOS 4.1.3. +if $ac_need_defaults; then + test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files + test "${CONFIG_HEADERS+set}" = set || CONFIG_HEADERS=$config_headers + test "${CONFIG_COMMANDS+set}" = set || CONFIG_COMMANDS=$config_commands +fi + +# Have a temporary directory for convenience. Make it in the build tree +# simply because there is no reason to put it here, and in addition, +# creating and moving files from /tmp can sometimes cause problems. +# Create a temporary directory, and hook for its removal unless debugging. +$debug || +{ + trap 'exit_status=$?; rm -rf $tmp && exit $exit_status' 0 + trap '{ (exit 1); exit 1; }' 1 2 13 15 +} + +# Create a (secure) tmp directory for tmp files. + +{ + tmp=`(umask 077 && mktemp -d -q "./confstatXXXXXX") 2>/dev/null` && + test -n "$tmp" && test -d "$tmp" +} || +{ + tmp=./confstat$$-$RANDOM + (umask 077 && mkdir $tmp) +} || +{ + echo "$me: cannot create a temporary directory in ." >&2 + { (exit 1); exit 1; } +} + +_ACEOF + +cat >>$CONFIG_STATUS <<_ACEOF + +# +# CONFIG_FILES section. +# + +# No need to generate the scripts if there are no CONFIG_FILES. +# This happens for instance when ./config.status config.h +if test -n "\$CONFIG_FILES"; then + # Protect against being on the right side of a sed subst in config.status. + sed 's/,@/@@/; s/@,/@@/; s/,;t t\$/@;t t/; /@;t t\$/s/[\\\\&,]/\\\\&/g; + s/@@/,@/; s/@@/@,/; s/@;t t\$/,;t t/' >\$tmp/subs.sed <<\\CEOF +s,@SHELL@,$SHELL,;t t +s,@PATH_SEPARATOR@,$PATH_SEPARATOR,;t t +s,@PACKAGE_NAME@,$PACKAGE_NAME,;t t +s,@PACKAGE_TARNAME@,$PACKAGE_TARNAME,;t t +s,@PACKAGE_VERSION@,$PACKAGE_VERSION,;t t +s,@PACKAGE_STRING@,$PACKAGE_STRING,;t t +s,@PACKAGE_BUGREPORT@,$PACKAGE_BUGREPORT,;t t +s,@exec_prefix@,$exec_prefix,;t t +s,@prefix@,$prefix,;t t +s,@program_transform_name@,$program_transform_name,;t t +s,@bindir@,$bindir,;t t +s,@sbindir@,$sbindir,;t t +s,@libexecdir@,$libexecdir,;t t +s,@datadir@,$datadir,;t t +s,@sysconfdir@,$sysconfdir,;t t +s,@sharedstatedir@,$sharedstatedir,;t t +s,@localstatedir@,$localstatedir,;t t +s,@libdir@,$libdir,;t t +s,@includedir@,$includedir,;t t +s,@oldincludedir@,$oldincludedir,;t t +s,@infodir@,$infodir,;t t +s,@mandir@,$mandir,;t t +s,@build_alias@,$build_alias,;t t +s,@host_alias@,$host_alias,;t t +s,@target_alias@,$target_alias,;t t +s,@DEFS@,$DEFS,;t t +s,@ECHO_C@,$ECHO_C,;t t +s,@ECHO_N@,$ECHO_N,;t t +s,@ECHO_T@,$ECHO_T,;t t +s,@LIBS@,$LIBS,;t t +s,@INSTALL_PROGRAM@,$INSTALL_PROGRAM,;t t +s,@INSTALL_SCRIPT@,$INSTALL_SCRIPT,;t t +s,@INSTALL_DATA@,$INSTALL_DATA,;t t +s,@PACKAGE@,$PACKAGE,;t t +s,@VERSION@,$VERSION,;t t +s,@ACLOCAL@,$ACLOCAL,;t t +s,@AUTOCONF@,$AUTOCONF,;t t +s,@AUTOMAKE@,$AUTOMAKE,;t t +s,@AUTOHEADER@,$AUTOHEADER,;t t +s,@MAKEINFO@,$MAKEINFO,;t t +s,@SET_MAKE@,$SET_MAKE,;t t +s,@VERSION_INFO@,$VERSION_INFO,;t t +s,@build@,$build,;t t +s,@build_cpu@,$build_cpu,;t t +s,@build_vendor@,$build_vendor,;t t +s,@build_os@,$build_os,;t t +s,@host@,$host,;t t +s,@host_cpu@,$host_cpu,;t t +s,@host_vendor@,$host_vendor,;t t +s,@host_os@,$host_os,;t t +s,@have_wininet_config@,$have_wininet_config,;t t +s,@MUST_BUILD_WININET_CLIENT@,$MUST_BUILD_WININET_CLIENT,;t t +s,@have_curl_config@,$have_curl_config,;t t +s,@MUST_BUILD_CURL_CLIENT@,$MUST_BUILD_CURL_CLIENT,;t t +s,@have_libwww_config@,$have_libwww_config,;t t +s,@MUST_BUILD_LIBWWW_CLIENT@,$MUST_BUILD_LIBWWW_CLIENT,;t t +s,@LIBXMLRPC_CLIENT_LA@,$LIBXMLRPC_CLIENT_LA,;t t +s,@CLIENTTEST@,$CLIENTTEST,;t t +s,@XMLRPC_CLIENT_H@,$XMLRPC_CLIENT_H,;t t +s,@XMLRPC_TRANSPORT_H@,$XMLRPC_TRANSPORT_H,;t t +s,@SYNCH_CLIENT@,$SYNCH_CLIENT,;t t +s,@ASYNCH_CLIENT@,$ASYNCH_CLIENT,;t t +s,@AUTH_CLIENT@,$AUTH_CLIENT,;t t +s,@QUERY_MEERKAT@,$QUERY_MEERKAT,;t t +s,@ENABLE_ABYSS_SERVER@,$ENABLE_ABYSS_SERVER,;t t +s,@ABYSS_SUBDIR@,$ABYSS_SUBDIR,;t t +s,@LIBXMLRPC_ABYSS_SERVER_LA@,$LIBXMLRPC_ABYSS_SERVER_LA,;t t +s,@SERVERTEST@,$SERVERTEST,;t t +s,@VALIDATEE@,$VALIDATEE,;t t +s,@XMLRPC_ABYSS_H@,$XMLRPC_ABYSS_H,;t t +s,@SERVER@,$SERVER,;t t +s,@ENABLE_CGI_SERVER@,$ENABLE_CGI_SERVER,;t t +s,@ENABLE_CPLUSPLUS@,$ENABLE_CPLUSPLUS,;t t +s,@LIBXMLRPC_CPP_A@,$LIBXMLRPC_CPP_A,;t t +s,@CPPTEST@,$CPPTEST,;t t +s,@XMLRPCCPP_H@,$XMLRPCCPP_H,;t t +s,@XML_RPC_API2CPP_SUBDIR@,$XML_RPC_API2CPP_SUBDIR,;t t +s,@FEATURE_LIST@,$FEATURE_LIST,;t t +s,@CC@,$CC,;t t +s,@CFLAGS@,$CFLAGS,;t t +s,@LDFLAGS@,$LDFLAGS,;t t +s,@CPPFLAGS@,$CPPFLAGS,;t t +s,@ac_ct_CC@,$ac_ct_CC,;t t +s,@EXEEXT@,$EXEEXT,;t t +s,@OBJEXT@,$OBJEXT,;t t +s,@CXX@,$CXX,;t t +s,@CXXFLAGS@,$CXXFLAGS,;t t +s,@ac_ct_CXX@,$ac_ct_CXX,;t t +s,@LSOCKET@,$LSOCKET,;t t +s,@CPP@,$CPP,;t t +s,@EGREP@,$EGREP,;t t +s,@HAVE_WCHAR_H_DEFINE@,$HAVE_WCHAR_H_DEFINE,;t t +s,@HAVE_SYS_FILIO_H_DEFINE@,$HAVE_SYS_FILIO_H_DEFINE,;t t +s,@HAVE_SYS_IOCTL_H_DEFINE@,$HAVE_SYS_IOCTL_H_DEFINE,;t t +s,@VA_LIST_IS_ARRAY_DEFINE@,$VA_LIST_IS_ARRAY_DEFINE,;t t +s,@ATTR_UNUSED@,$ATTR_UNUSED,;t t +s,@DIRECTORY_SEPARATOR@,$DIRECTORY_SEPARATOR,;t t +s,@ENABLE_ABYSS_THREADS@,$ENABLE_ABYSS_THREADS,;t t +s,@WININET_CONFIG@,$WININET_CONFIG,;t t +s,@WININET_CFLAGS@,$WININET_CFLAGS,;t t +s,@WININET_LDADD@,$WININET_LDADD,;t t +s,@WININET_LIBDIR@,$WININET_LIBDIR,;t t +s,@WININET_RPATH@,$WININET_RPATH,;t t +s,@WININET_WL_RPATH@,$WININET_WL_RPATH,;t t +s,@LIBWWW_CONFIG@,$LIBWWW_CONFIG,;t t +s,@LIBWWW_LDADD@,$LIBWWW_LDADD,;t t +s,@LIBWWW_LIBDIR@,$LIBWWW_LIBDIR,;t t +s,@LIBWWW_RPATH@,$LIBWWW_RPATH,;t t +s,@LIBWWW_WL_RPATH@,$LIBWWW_WL_RPATH,;t t +s,@CURL_CONFIG@,$CURL_CONFIG,;t t +s,@CURL_LDADD@,$CURL_LDADD,;t t +s,@CURL_LIBDIR@,$CURL_LIBDIR,;t t +s,@CURL_RPATH@,$CURL_RPATH,;t t +s,@CURL_WL_RPATH@,$CURL_WL_RPATH,;t t +s,@HAVE_LIBWWW_SSL_DEFINE@,$HAVE_LIBWWW_SSL_DEFINE,;t t +s,@have_xml2_config@,$have_xml2_config,;t t +s,@ENABLE_LIBXML2_BACKEND@,$ENABLE_LIBXML2_BACKEND,;t t +s,@C_COMPILER_GNU@,$C_COMPILER_GNU,;t t +s,@CXX_COMPILER_GNU@,$CXX_COMPILER_GNU,;t t +s,@CC_WARN_FLAGS@,$CC_WARN_FLAGS,;t t +s,@CPP_WARN_FLAGS@,$CPP_WARN_FLAGS,;t t +s,@BUILDDIR@,$BUILDDIR,;t t +s,@RANLIB@,$RANLIB,;t t +s,@ac_ct_RANLIB@,$ac_ct_RANLIB,;t t +s,@LN_S@,$LN_S,;t t +s,@LIBTOOL@,$LIBTOOL,;t t +s,@LIBOBJS@,$LIBOBJS,;t t +s,@LTLIBOBJS@,$LTLIBOBJS,;t t +CEOF + +_ACEOF + + cat >>$CONFIG_STATUS <<\_ACEOF + # Split the substitutions into bite-sized pieces for seds with + # small command number limits, like on Digital OSF/1 and HP-UX. + ac_max_sed_lines=48 + ac_sed_frag=1 # Number of current file. + ac_beg=1 # First line for current file. + ac_end=$ac_max_sed_lines # Line after last line for current file. + ac_more_lines=: + ac_sed_cmds= + while $ac_more_lines; do + if test $ac_beg -gt 1; then + sed "1,${ac_beg}d; ${ac_end}q" $tmp/subs.sed >$tmp/subs.frag + else + sed "${ac_end}q" $tmp/subs.sed >$tmp/subs.frag + fi + if test ! -s $tmp/subs.frag; then + ac_more_lines=false + else + # The purpose of the label and of the branching condition is to + # speed up the sed processing (if there are no `@' at all, there + # is no need to browse any of the substitutions). + # These are the two extra sed commands mentioned above. + (echo ':t + /@[a-zA-Z_][a-zA-Z_0-9]*@/!b' && cat $tmp/subs.frag) >$tmp/subs-$ac_sed_frag.sed + if test -z "$ac_sed_cmds"; then + ac_sed_cmds="sed -f $tmp/subs-$ac_sed_frag.sed" + else + ac_sed_cmds="$ac_sed_cmds | sed -f $tmp/subs-$ac_sed_frag.sed" + fi + ac_sed_frag=`expr $ac_sed_frag + 1` + ac_beg=$ac_end + ac_end=`expr $ac_end + $ac_max_sed_lines` + fi + done + if test -z "$ac_sed_cmds"; then + ac_sed_cmds=cat + fi +fi # test -n "$CONFIG_FILES" + +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF +for ac_file in : $CONFIG_FILES; do test "x$ac_file" = x: && continue + # Support "outfile[:infile[:infile...]]", defaulting infile="outfile.in". + case $ac_file in + - | *:- | *:-:* ) # input from stdin + cat >$tmp/stdin + ac_file_in=`echo "$ac_file" | sed 's,[^:]*:,,'` + ac_file=`echo "$ac_file" | sed 's,:.*,,'` ;; + *:* ) ac_file_in=`echo "$ac_file" | sed 's,[^:]*:,,'` + ac_file=`echo "$ac_file" | sed 's,:.*,,'` ;; + * ) ac_file_in=$ac_file.in ;; + esac + + # Compute @srcdir@, @top_srcdir@, and @INSTALL@ for subdirectories. + ac_dir=`(dirname "$ac_file") 2>/dev/null || +$as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$ac_file" : 'X\(//\)[^/]' \| \ + X"$ac_file" : 'X\(//\)$' \| \ + X"$ac_file" : 'X\(/\)' \| \ + . : '\(.\)' 2>/dev/null || +echo X"$ac_file" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; } + /^X\(\/\/\)[^/].*/{ s//\1/; q; } + /^X\(\/\/\)$/{ s//\1/; q; } + /^X\(\/\).*/{ s//\1/; q; } + s/.*/./; q'` + { if $as_mkdir_p; then + mkdir -p "$ac_dir" + else + as_dir="$ac_dir" + as_dirs= + while test ! -d "$as_dir"; do + as_dirs="$as_dir $as_dirs" + as_dir=`(dirname "$as_dir") 2>/dev/null || +$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$as_dir" : 'X\(//\)[^/]' \| \ + X"$as_dir" : 'X\(//\)$' \| \ + X"$as_dir" : 'X\(/\)' \| \ + . : '\(.\)' 2>/dev/null || +echo X"$as_dir" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; } + /^X\(\/\/\)[^/].*/{ s//\1/; q; } + /^X\(\/\/\)$/{ s//\1/; q; } + /^X\(\/\).*/{ s//\1/; q; } + s/.*/./; q'` + done + test ! -n "$as_dirs" || mkdir $as_dirs + fi || { { echo "$as_me:$LINENO: error: cannot create directory \"$ac_dir\"" >&5 +echo "$as_me: error: cannot create directory \"$ac_dir\"" >&2;} + { (exit 1); exit 1; }; }; } + + ac_builddir=. + +if test "$ac_dir" != .; then + ac_dir_suffix=/`echo "$ac_dir" | sed 's,^\.[\\/],,'` + # A "../" for each directory in $ac_dir_suffix. + ac_top_builddir=`echo "$ac_dir_suffix" | sed 's,/[^\\/]*,../,g'` +else + ac_dir_suffix= ac_top_builddir= +fi + +case $srcdir in + .) # No --srcdir option. We are building in place. + ac_srcdir=. + if test -z "$ac_top_builddir"; then + ac_top_srcdir=. + else + ac_top_srcdir=`echo $ac_top_builddir | sed 's,/$,,'` + fi ;; + [\\/]* | ?:[\\/]* ) # Absolute path. + ac_srcdir=$srcdir$ac_dir_suffix; + ac_top_srcdir=$srcdir ;; + *) # Relative path. + ac_srcdir=$ac_top_builddir$srcdir$ac_dir_suffix + ac_top_srcdir=$ac_top_builddir$srcdir ;; +esac + +# Do not use `cd foo && pwd` to compute absolute paths, because +# the directories may not exist. +case `pwd` in +.) ac_abs_builddir="$ac_dir";; +*) + case "$ac_dir" in + .) ac_abs_builddir=`pwd`;; + [\\/]* | ?:[\\/]* ) ac_abs_builddir="$ac_dir";; + *) ac_abs_builddir=`pwd`/"$ac_dir";; + esac;; +esac +case $ac_abs_builddir in +.) ac_abs_top_builddir=${ac_top_builddir}.;; +*) + case ${ac_top_builddir}. in + .) ac_abs_top_builddir=$ac_abs_builddir;; + [\\/]* | ?:[\\/]* ) ac_abs_top_builddir=${ac_top_builddir}.;; + *) ac_abs_top_builddir=$ac_abs_builddir/${ac_top_builddir}.;; + esac;; +esac +case $ac_abs_builddir in +.) ac_abs_srcdir=$ac_srcdir;; +*) + case $ac_srcdir in + .) ac_abs_srcdir=$ac_abs_builddir;; + [\\/]* | ?:[\\/]* ) ac_abs_srcdir=$ac_srcdir;; + *) ac_abs_srcdir=$ac_abs_builddir/$ac_srcdir;; + esac;; +esac +case $ac_abs_builddir in +.) ac_abs_top_srcdir=$ac_top_srcdir;; +*) + case $ac_top_srcdir in + .) ac_abs_top_srcdir=$ac_abs_builddir;; + [\\/]* | ?:[\\/]* ) ac_abs_top_srcdir=$ac_top_srcdir;; + *) ac_abs_top_srcdir=$ac_abs_builddir/$ac_top_srcdir;; + esac;; +esac + + + case $INSTALL in + [\\/$]* | ?:[\\/]* ) ac_INSTALL=$INSTALL ;; + *) ac_INSTALL=$ac_top_builddir$INSTALL ;; + esac + + if test x"$ac_file" != x-; then + { echo "$as_me:$LINENO: creating $ac_file" >&5 +echo "$as_me: creating $ac_file" >&6;} + rm -f "$ac_file" + fi + # Let's still pretend it is `configure' which instantiates (i.e., don't + # use $as_me), people would be surprised to read: + # /* config.h. Generated by config.status. */ + if test x"$ac_file" = x-; then + configure_input= + else + configure_input="$ac_file. " + fi + configure_input=$configure_input"Generated from `echo $ac_file_in | + sed 's,.*/,,'` by configure." + + # First look for the input files in the build tree, otherwise in the + # src tree. + ac_file_inputs=`IFS=: + for f in $ac_file_in; do + case $f in + -) echo $tmp/stdin ;; + [\\/$]*) + # Absolute (can't be DOS-style, as IFS=:) + test -f "$f" || { { echo "$as_me:$LINENO: error: cannot find input file: $f" >&5 +echo "$as_me: error: cannot find input file: $f" >&2;} + { (exit 1); exit 1; }; } + echo "$f";; + *) # Relative + if test -f "$f"; then + # Build tree + echo "$f" + elif test -f "$srcdir/$f"; then + # Source tree + echo "$srcdir/$f" + else + # /dev/null tree + { { echo "$as_me:$LINENO: error: cannot find input file: $f" >&5 +echo "$as_me: error: cannot find input file: $f" >&2;} + { (exit 1); exit 1; }; } + fi;; + esac + done` || { (exit 1); exit 1; } +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF + sed "$ac_vpsub +$extrasub +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF +:t +/@[a-zA-Z_][a-zA-Z_0-9]*@/!b +s,@configure_input@,$configure_input,;t t +s,@srcdir@,$ac_srcdir,;t t +s,@abs_srcdir@,$ac_abs_srcdir,;t t +s,@top_srcdir@,$ac_top_srcdir,;t t +s,@abs_top_srcdir@,$ac_abs_top_srcdir,;t t +s,@builddir@,$ac_builddir,;t t +s,@abs_builddir@,$ac_abs_builddir,;t t +s,@top_builddir@,$ac_top_builddir,;t t +s,@abs_top_builddir@,$ac_abs_top_builddir,;t t +s,@INSTALL@,$ac_INSTALL,;t t +" $ac_file_inputs | (eval "$ac_sed_cmds") >$tmp/out + rm -f $tmp/stdin + if test x"$ac_file" != x-; then + mv $tmp/out $ac_file + else + cat $tmp/out + rm -f $tmp/out + fi + +done +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF + +# +# CONFIG_HEADER section. +# + +# These sed commands are passed to sed as "A NAME B NAME C VALUE D", where +# NAME is the cpp macro being defined and VALUE is the value it is being given. +# +# ac_d sets the value in "#define NAME VALUE" lines. +ac_dA='s,^\([ ]*\)#\([ ]*define[ ][ ]*\)' +ac_dB='[ ].*$,\1#\2' +ac_dC=' ' +ac_dD=',;t' +# ac_u turns "#undef NAME" without trailing blanks into "#define NAME VALUE". +ac_uA='s,^\([ ]*\)#\([ ]*\)undef\([ ][ ]*\)' +ac_uB='$,\1#\2define\3' +ac_uC=' ' +ac_uD=',;t' + +for ac_file in : $CONFIG_HEADERS; do test "x$ac_file" = x: && continue + # Support "outfile[:infile[:infile...]]", defaulting infile="outfile.in". + case $ac_file in + - | *:- | *:-:* ) # input from stdin + cat >$tmp/stdin + ac_file_in=`echo "$ac_file" | sed 's,[^:]*:,,'` + ac_file=`echo "$ac_file" | sed 's,:.*,,'` ;; + *:* ) ac_file_in=`echo "$ac_file" | sed 's,[^:]*:,,'` + ac_file=`echo "$ac_file" | sed 's,:.*,,'` ;; + * ) ac_file_in=$ac_file.in ;; + esac + + test x"$ac_file" != x- && { echo "$as_me:$LINENO: creating $ac_file" >&5 +echo "$as_me: creating $ac_file" >&6;} + + # First look for the input files in the build tree, otherwise in the + # src tree. + ac_file_inputs=`IFS=: + for f in $ac_file_in; do + case $f in + -) echo $tmp/stdin ;; + [\\/$]*) + # Absolute (can't be DOS-style, as IFS=:) + test -f "$f" || { { echo "$as_me:$LINENO: error: cannot find input file: $f" >&5 +echo "$as_me: error: cannot find input file: $f" >&2;} + { (exit 1); exit 1; }; } + # Do quote $f, to prevent DOS paths from being IFS'd. + echo "$f";; + *) # Relative + if test -f "$f"; then + # Build tree + echo "$f" + elif test -f "$srcdir/$f"; then + # Source tree + echo "$srcdir/$f" + else + # /dev/null tree + { { echo "$as_me:$LINENO: error: cannot find input file: $f" >&5 +echo "$as_me: error: cannot find input file: $f" >&2;} + { (exit 1); exit 1; }; } + fi;; + esac + done` || { (exit 1); exit 1; } + # Remove the trailing spaces. + sed 's/[ ]*$//' $ac_file_inputs >$tmp/in + +_ACEOF + +# Transform confdefs.h into two sed scripts, `conftest.defines' and +# `conftest.undefs', that substitutes the proper values into +# config.h.in to produce config.h. The first handles `#define' +# templates, and the second `#undef' templates. +# And first: Protect against being on the right side of a sed subst in +# config.status. Protect against being in an unquoted here document +# in config.status. +rm -f conftest.defines conftest.undefs +# Using a here document instead of a string reduces the quoting nightmare. +# Putting comments in sed scripts is not portable. +# +# `end' is used to avoid that the second main sed command (meant for +# 0-ary CPP macros) applies to n-ary macro definitions. +# See the Autoconf documentation for `clear'. +cat >confdef2sed.sed <<\_ACEOF +s/[\\&,]/\\&/g +s,[\\$`],\\&,g +t clear +: clear +s,^[ ]*#[ ]*define[ ][ ]*\([^ (][^ (]*\)\(([^)]*)\)[ ]*\(.*\)$,${ac_dA}\1${ac_dB}\1\2${ac_dC}\3${ac_dD},gp +t end +s,^[ ]*#[ ]*define[ ][ ]*\([^ ][^ ]*\)[ ]*\(.*\)$,${ac_dA}\1${ac_dB}\1${ac_dC}\2${ac_dD},gp +: end +_ACEOF +# If some macros were called several times there might be several times +# the same #defines, which is useless. Nevertheless, we may not want to +# sort them, since we want the *last* AC-DEFINE to be honored. +uniq confdefs.h | sed -n -f confdef2sed.sed >conftest.defines +sed 's/ac_d/ac_u/g' conftest.defines >conftest.undefs +rm -f confdef2sed.sed + +# This sed command replaces #undef with comments. This is necessary, for +# example, in the case of _POSIX_SOURCE, which is predefined and required +# on some systems where configure will not decide to define it. +cat >>conftest.undefs <<\_ACEOF +s,^[ ]*#[ ]*undef[ ][ ]*[a-zA-Z_][a-zA-Z_0-9]*,/* & */, +_ACEOF + +# Break up conftest.defines because some shells have a limit on the size +# of here documents, and old seds have small limits too (100 cmds). +echo ' # Handle all the #define templates only if necessary.' >>$CONFIG_STATUS +echo ' if grep "^[ ]*#[ ]*define" $tmp/in >/dev/null; then' >>$CONFIG_STATUS +echo ' # If there are no defines, we may have an empty if/fi' >>$CONFIG_STATUS +echo ' :' >>$CONFIG_STATUS +rm -f conftest.tail +while grep . conftest.defines >/dev/null +do + # Write a limited-size here document to $tmp/defines.sed. + echo ' cat >$tmp/defines.sed <>$CONFIG_STATUS + # Speed up: don't consider the non `#define' lines. + echo '/^[ ]*#[ ]*define/!b' >>$CONFIG_STATUS + # Work around the forget-to-reset-the-flag bug. + echo 't clr' >>$CONFIG_STATUS + echo ': clr' >>$CONFIG_STATUS + sed ${ac_max_here_lines}q conftest.defines >>$CONFIG_STATUS + echo 'CEOF + sed -f $tmp/defines.sed $tmp/in >$tmp/out + rm -f $tmp/in + mv $tmp/out $tmp/in +' >>$CONFIG_STATUS + sed 1,${ac_max_here_lines}d conftest.defines >conftest.tail + rm -f conftest.defines + mv conftest.tail conftest.defines +done +rm -f conftest.defines +echo ' fi # grep' >>$CONFIG_STATUS +echo >>$CONFIG_STATUS + +# Break up conftest.undefs because some shells have a limit on the size +# of here documents, and old seds have small limits too (100 cmds). +echo ' # Handle all the #undef templates' >>$CONFIG_STATUS +rm -f conftest.tail +while grep . conftest.undefs >/dev/null +do + # Write a limited-size here document to $tmp/undefs.sed. + echo ' cat >$tmp/undefs.sed <>$CONFIG_STATUS + # Speed up: don't consider the non `#undef' + echo '/^[ ]*#[ ]*undef/!b' >>$CONFIG_STATUS + # Work around the forget-to-reset-the-flag bug. + echo 't clr' >>$CONFIG_STATUS + echo ': clr' >>$CONFIG_STATUS + sed ${ac_max_here_lines}q conftest.undefs >>$CONFIG_STATUS + echo 'CEOF + sed -f $tmp/undefs.sed $tmp/in >$tmp/out + rm -f $tmp/in + mv $tmp/out $tmp/in +' >>$CONFIG_STATUS + sed 1,${ac_max_here_lines}d conftest.undefs >conftest.tail + rm -f conftest.undefs + mv conftest.tail conftest.undefs +done +rm -f conftest.undefs + +cat >>$CONFIG_STATUS <<\_ACEOF + # Let's still pretend it is `configure' which instantiates (i.e., don't + # use $as_me), people would be surprised to read: + # /* config.h. Generated by config.status. */ + if test x"$ac_file" = x-; then + echo "/* Generated by configure. */" >$tmp/config.h + else + echo "/* $ac_file. Generated by configure. */" >$tmp/config.h + fi + cat $tmp/in >>$tmp/config.h + rm -f $tmp/in + if test x"$ac_file" != x-; then + if diff $ac_file $tmp/config.h >/dev/null 2>&1; then + { echo "$as_me:$LINENO: $ac_file is unchanged" >&5 +echo "$as_me: $ac_file is unchanged" >&6;} + else + ac_dir=`(dirname "$ac_file") 2>/dev/null || +$as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$ac_file" : 'X\(//\)[^/]' \| \ + X"$ac_file" : 'X\(//\)$' \| \ + X"$ac_file" : 'X\(/\)' \| \ + . : '\(.\)' 2>/dev/null || +echo X"$ac_file" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; } + /^X\(\/\/\)[^/].*/{ s//\1/; q; } + /^X\(\/\/\)$/{ s//\1/; q; } + /^X\(\/\).*/{ s//\1/; q; } + s/.*/./; q'` + { if $as_mkdir_p; then + mkdir -p "$ac_dir" + else + as_dir="$ac_dir" + as_dirs= + while test ! -d "$as_dir"; do + as_dirs="$as_dir $as_dirs" + as_dir=`(dirname "$as_dir") 2>/dev/null || +$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$as_dir" : 'X\(//\)[^/]' \| \ + X"$as_dir" : 'X\(//\)$' \| \ + X"$as_dir" : 'X\(/\)' \| \ + . : '\(.\)' 2>/dev/null || +echo X"$as_dir" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; } + /^X\(\/\/\)[^/].*/{ s//\1/; q; } + /^X\(\/\/\)$/{ s//\1/; q; } + /^X\(\/\).*/{ s//\1/; q; } + s/.*/./; q'` + done + test ! -n "$as_dirs" || mkdir $as_dirs + fi || { { echo "$as_me:$LINENO: error: cannot create directory \"$ac_dir\"" >&5 +echo "$as_me: error: cannot create directory \"$ac_dir\"" >&2;} + { (exit 1); exit 1; }; }; } + + rm -f $ac_file + mv $tmp/config.h $ac_file + fi + else + cat $tmp/config.h + rm -f $tmp/config.h + fi +done +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF + +# +# CONFIG_COMMANDS section. +# +for ac_file in : $CONFIG_COMMANDS; do test "x$ac_file" = x: && continue + ac_dest=`echo "$ac_file" | sed 's,:.*,,'` + ac_source=`echo "$ac_file" | sed 's,[^:]*:,,'` + ac_dir=`(dirname "$ac_dest") 2>/dev/null || +$as_expr X"$ac_dest" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$ac_dest" : 'X\(//\)[^/]' \| \ + X"$ac_dest" : 'X\(//\)$' \| \ + X"$ac_dest" : 'X\(/\)' \| \ + . : '\(.\)' 2>/dev/null || +echo X"$ac_dest" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; } + /^X\(\/\/\)[^/].*/{ s//\1/; q; } + /^X\(\/\/\)$/{ s//\1/; q; } + /^X\(\/\).*/{ s//\1/; q; } + s/.*/./; q'` + { if $as_mkdir_p; then + mkdir -p "$ac_dir" + else + as_dir="$ac_dir" + as_dirs= + while test ! -d "$as_dir"; do + as_dirs="$as_dir $as_dirs" + as_dir=`(dirname "$as_dir") 2>/dev/null || +$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$as_dir" : 'X\(//\)[^/]' \| \ + X"$as_dir" : 'X\(//\)$' \| \ + X"$as_dir" : 'X\(/\)' \| \ + . : '\(.\)' 2>/dev/null || +echo X"$as_dir" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; } + /^X\(\/\/\)[^/].*/{ s//\1/; q; } + /^X\(\/\/\)$/{ s//\1/; q; } + /^X\(\/\).*/{ s//\1/; q; } + s/.*/./; q'` + done + test ! -n "$as_dirs" || mkdir $as_dirs + fi || { { echo "$as_me:$LINENO: error: cannot create directory \"$ac_dir\"" >&5 +echo "$as_me: error: cannot create directory \"$ac_dir\"" >&2;} + { (exit 1); exit 1; }; }; } + + ac_builddir=. + +if test "$ac_dir" != .; then + ac_dir_suffix=/`echo "$ac_dir" | sed 's,^\.[\\/],,'` + # A "../" for each directory in $ac_dir_suffix. + ac_top_builddir=`echo "$ac_dir_suffix" | sed 's,/[^\\/]*,../,g'` +else + ac_dir_suffix= ac_top_builddir= +fi + +case $srcdir in + .) # No --srcdir option. We are building in place. + ac_srcdir=. + if test -z "$ac_top_builddir"; then + ac_top_srcdir=. + else + ac_top_srcdir=`echo $ac_top_builddir | sed 's,/$,,'` + fi ;; + [\\/]* | ?:[\\/]* ) # Absolute path. + ac_srcdir=$srcdir$ac_dir_suffix; + ac_top_srcdir=$srcdir ;; + *) # Relative path. + ac_srcdir=$ac_top_builddir$srcdir$ac_dir_suffix + ac_top_srcdir=$ac_top_builddir$srcdir ;; +esac + +# Do not use `cd foo && pwd` to compute absolute paths, because +# the directories may not exist. +case `pwd` in +.) ac_abs_builddir="$ac_dir";; +*) + case "$ac_dir" in + .) ac_abs_builddir=`pwd`;; + [\\/]* | ?:[\\/]* ) ac_abs_builddir="$ac_dir";; + *) ac_abs_builddir=`pwd`/"$ac_dir";; + esac;; +esac +case $ac_abs_builddir in +.) ac_abs_top_builddir=${ac_top_builddir}.;; +*) + case ${ac_top_builddir}. in + .) ac_abs_top_builddir=$ac_abs_builddir;; + [\\/]* | ?:[\\/]* ) ac_abs_top_builddir=${ac_top_builddir}.;; + *) ac_abs_top_builddir=$ac_abs_builddir/${ac_top_builddir}.;; + esac;; +esac +case $ac_abs_builddir in +.) ac_abs_srcdir=$ac_srcdir;; +*) + case $ac_srcdir in + .) ac_abs_srcdir=$ac_abs_builddir;; + [\\/]* | ?:[\\/]* ) ac_abs_srcdir=$ac_srcdir;; + *) ac_abs_srcdir=$ac_abs_builddir/$ac_srcdir;; + esac;; +esac +case $ac_abs_builddir in +.) ac_abs_top_srcdir=$ac_top_srcdir;; +*) + case $ac_top_srcdir in + .) ac_abs_top_srcdir=$ac_abs_builddir;; + [\\/]* | ?:[\\/]* ) ac_abs_top_srcdir=$ac_top_srcdir;; + *) ac_abs_top_srcdir=$ac_abs_builddir/$ac_top_srcdir;; + esac;; +esac + + + { echo "$as_me:$LINENO: executing $ac_dest commands" >&5 +echo "$as_me: executing $ac_dest commands" >&6;} + case $ac_dest in + default-1 ) test -z "$CONFIG_HEADERS" || echo timestamp > stamp-h ;; + esac +done +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF + +{ (exit 0); exit 0; } +_ACEOF +chmod +x $CONFIG_STATUS +ac_clean_files=$ac_clean_files_save + + +# configure is writing to config.log, and then calls config.status. +# config.status does its own redirection, appending to config.log. +# Unfortunately, on DOS this fails, as config.log is still kept open +# by configure, so config.status won't be able to write to it; its +# output is simply discarded. So we exec the FD to /dev/null, +# effectively closing config.log, so it can be properly (re)opened and +# appended to by config.status. When coming back to configure, we +# need to make the FD available again. +if test "$no_create" != yes; then + ac_cs_success=: + ac_config_status_args= + test "$silent" = yes && + ac_config_status_args="$ac_config_status_args --quiet" + exec 5>/dev/null + $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false + exec 5>>config.log + # Use ||, not &&, to avoid exiting from the if with $? = 1, which + # would make configure fail if this is the last instruction. + $ac_cs_success || { (exit 1); exit 1; } +fi + +chmod +x xmlrpc-c-config +chmod +x xmlrpc-c-config.test diff --git a/configure.in b/configure.in new file mode 100644 index 0000000..092a2d7 --- /dev/null +++ b/configure.in @@ -0,0 +1,650 @@ +dnl Process this file with autoconf to produce a configure script. + +AC_INIT(include/xmlrpc-c/base.h) +AM_CONFIG_HEADER(xmlrpc_amconfig.h) + +dnl ======================================================================= +dnl Define PACKAGE, VERSION, @PACKAGE@, @VERSION@ +dnl ======================================================================= + +dnl Increment the package version for each release. +AM_INIT_AUTOMAKE(xmlrpc-c, 1.06.32) + +dnl This version number needs to be changed in several *different* tricky +dnl ways for each release. Please read the libtool documentation very +dnl closely before touching this or making a release! +VERSION_INFO="-version-info 7:0:6" +AC_SUBST(VERSION_INFO) + +dnl Define @build@, @build_cpu@, @build_vendor@, @build_os, +dnl @host, @host_cpu@, @host_vender, and @host_os@ substitutions. +dnl "host" means the target system -- the one for which we are building. +dnl "build" means the system that will do the building. +AC_CANONICAL_HOST + +dnl We need this to compensate for an incompatibility between autoconf +dnl and our libtool. autoconf generates an invalid ltconfig command +dnl otherwise. +test -z "$target" && target=NONE + +dnl ======================================================================= +dnl Decide What To Build +dnl ======================================================================= + +FEATURE_LIST= + +AC_ARG_ENABLE(wininet-client, + [ --disable-wininet-client Don't build the Wininet client transport], , +enable_wininet_client=maybe) + +if test $enable_wininet_client = maybe; then + AC_CHECK_PROG(have_wininet_config, wininet-config, yes, no) + if test $have_wininet_config = no; then + AC_MSG_NOTICE([You don't appear to have Wininet installed (no working wininet-config in your command search path), so we will not build the Wininet client XML transport]) + MUST_BUILD_WININET_CLIENT=no + else + MUST_BUILD_WININET_CLIENT=yes + fi +else + MUST_BUILD_WININET_CLIENT=$enable_wininet_client +fi + +AC_MSG_CHECKING(whether to build Wininet client XML transport module) +AC_MSG_RESULT($MUST_BUILD_WININET_CLIENT) +AC_SUBST(MUST_BUILD_WININET_CLIENT) + + +AC_ARG_ENABLE(curl-client, + [ --disable-curl-client Don't build the Curl client transport], , +enable_curl_client=maybe) + +if test $enable_curl_client = maybe; then + AC_CHECK_PROG(have_curl_config, curl-config, yes, no) + if test $have_curl_config = no; then + AC_MSG_NOTICE([You don't appear to have Curl installed (no working curl-config in your command search path), so we will not build the Curl client XML transport]) + MUST_BUILD_CURL_CLIENT=no + else + MUST_BUILD_CURL_CLIENT=yes + fi +else + MUST_BUILD_CURL_CLIENT=$enable_curl_client +fi + +AC_MSG_CHECKING(whether to build Curl client XML transport module) +AC_MSG_RESULT($MUST_BUILD_CURL_CLIENT) +AC_SUBST(MUST_BUILD_CURL_CLIENT) + + +AC_ARG_ENABLE(libwww-client, + [ --disable-libwww-client Don't build the Libwww client transport], , +enable_libwww_client=maybe) + +if test $enable_libwww_client = maybe; then + AC_CHECK_PROG(have_libwww_config, libwww-config, yes, no) + if test $have_libwww_config = no; then + AC_MSG_NOTICE([You don't appear to have Libwww installed (no working libwww-config in your command search path), so we will not build the Libwww client XML transport]) + MUST_BUILD_LIBWWW_CLIENT=no + else + MUST_BUILD_LIBWWW_CLIENT=yes + fi +else + MUST_BUILD_LIBWWW_CLIENT=$enable_libwww_client +fi + +AC_MSG_CHECKING(whether to build Libwww client XML transport module) +AC_MSG_RESULT($MUST_BUILD_LIBWWW_CLIENT) +AC_SUBST(MUST_BUILD_LIBWWW_CLIENT) + + +if test "$MUST_BUILD_WININET_CLIENT $MUST_BUILD_CURL_CLIENT $MUST_BUILD_LIBWWW_CLIENT" = "no no no"; then + AC_MSG_NOTICE([We are not building any client XML transport, therefore we will not build the client library at all.]) +fi + + +dnl Set up the appropriate Makefile substitutions. + +LIBXMLRPC_CLIENT_LA=libxmlrpc_client.la +AC_SUBST(LIBXMLRPC_CLIENT_LA) +CLIENTTEST=clienttest +AC_SUBST(CLIENTTEST) +XMLRPC_CLIENT_H=xmlrpc_client.h +AC_SUBST(XMLRPC_CLIENT_H) +XMLRPC_TRANSPORT_H=xmlrpc_transport.h +AC_SUBST(XMLRPC_TRANSPORT_H) +SYNCH_CLIENT=synch_client +AC_SUBST(SYNCH_CLIENT) +ASYNCH_CLIENT=asynch_client +AC_SUBST(ASYNCH_CLIENT) +AUTH_CLIENT=auth_client +AC_SUBST(AUTH_CLIENT) +QUERY_MEERKAT=query-meerkat +AC_SUBST(QUERY_MEERKAT) + +if test $MUST_BUILD_WININET_CLIENT = yes; then + FEATURE_LIST="wininet-client $FEATURE_LIST" +fi +if test $MUST_BUILD_CURL_CLIENT = yes; then + FEATURE_LIST="curl-client $FEATURE_LIST" +fi +if test $MUST_BUILD_LIBWWW_CLIENT = yes; then + FEATURE_LIST="libwww-client $FEATURE_LIST" +fi + +dnl Check to see if we should build our Abyss server module. +AC_MSG_CHECKING(whether to build Abyss server module) +AC_ARG_ENABLE(abyss-server, + [ --disable-abyss-server Don't build the Abyss server module], , +enable_abyss_server=yes) +AC_MSG_RESULT($enable_abyss_server) +ENABLE_ABYSS_SERVER=$enable_abyss_server +AC_SUBST(ENABLE_ABYSS_SERVER) + +dnl Set up the appropriate Makefile substitutions. +ABYSS_SUBDIR= +LIBXMLRPC_ABYSS_SERVER_LA= +SERVERTEST= +VALIDATEE= +XMLRPC_ABYSS_H= +SERVER= +if test x"$enable_abyss_server" != xno; then + FEATURE_LIST="abyss-server $FEATURE_LIST" + ABYSS_SUBDIR=abyss + LIBXMLRPC_ABYSS_SERVER_LA=libxmlrpc_abyss_server.la + SERVERTEST=servertest + VALIDATEE=validatee + XMLRPC_ABYSS_H=xmlrpc_abyss.h + SERVER=server +fi +AC_SUBST(ABYSS_SUBDIR) +AC_SUBST(LIBXMLRPC_ABYSS_SERVER_LA) +AC_SUBST(SERVERTEST) +AC_SUBST(VALIDATEE) +AC_SUBST(XMLRPC_ABYSS_H) +AC_SUBST(SERVER) + +dnl Check to see if we should build our CGI server module. +AC_MSG_CHECKING(whether to build CGI server module) +AC_ARG_ENABLE(cgi-server, + [ --disable-cgi-server Don't build the CGI server module], , +enable_cgi_server=yes) +AC_MSG_RESULT($enable_cgi_server) +ENABLE_CGI_SERVER=$enable_cgi_server +AC_SUBST(ENABLE_CGI_SERVER) + +dnl Check to see if we should build our C++ stuff. +AC_MSG_CHECKING(whether to build C++ wrappers and tools) +AC_ARG_ENABLE(cplusplus, + [ --disable-cplusplus Don't build the C++ wrapper classes or tools], , +enable_cplusplus=yes) +AC_MSG_RESULT($enable_cplusplus) +ENABLE_CPLUSPLUS=$enable_cplusplus +AC_SUBST(ENABLE_CPLUSPLUS) + +dnl Set up the appropriate Makefile substitutions. +LIBXMLRPC_CPP_A= +CPPTEST= +XMLRPCCPP_H= +XML_RPC_API2CPP_SUBDIR= +MEERKAT_APP_LIST= +INTEROP_CLIENT_SUBDIR= +if test x"$enable_cplusplus" != xno; then + FEATURE_LIST="c++ $FEATURE_LIST" + LIBXMLRPC_CPP_A=libxmlrpc_cpp.a + CPPTEST=cpptest + XMLRPCCPP_H=XmlRpcCpp.h + + if test $MUST_BUILD_LIBWWW_CLIENT = yes; then + XML_RPC_API2CPP_SUBDIR=xml-rpc-api2cpp + elif test $MUST_BUILD_CURL_CLIENT = yes; then + XML_RPC_API2CPP_SUBDIR=xml-rpc-api2cpp + fi +fi +AC_SUBST(LIBXMLRPC_CPP_A) +AC_SUBST(CPPTEST) +AC_SUBST(XMLRPCCPP_H) +AC_SUBST(XML_RPC_API2CPP_SUBDIR) + + +AC_SUBST(FEATURE_LIST) + + +dnl ======================================================================= +dnl Checks for programs. +dnl ======================================================================= + +AC_PROG_CC +if test x"$enable_cplusplus" != xno; then + AC_PROG_CXX +fi + + +dnl ======================================================================= +dnl Checks for libraries. +dnl ======================================================================= + +# Code by albert chin to check for various +# oddball networking libraries. Solaris and some other operating systems +# hide their networking code in various places. (Yes, this links too many +# of our libraries against -lsocket, but a finer-grained mechanism would +# require too much testing.) +AC_CHECK_FUNC(socket, , AC_CHECK_LIB(socket, socket)) + +# Above sets LIBS, which is not all that useful because we don't want +# to include every library in every link. It also sets +# ac_cv_lib_socket_socket, which we use to pass more specific information +# to the configuration files. + +if test x"$ac_cv_lib_socket_socket" = xyes; then + LSOCKET=-lsocket +else + LSOCKET= +fi +AC_SUBST(LSOCKET) + +# For some reason, we don't seem to need this on Solaris. If you do +# need it, go ahead and try it. +# AC_CHECK_FUNC(gethostent, , AC_CHECK_LIB(nsl, gethostent)) + + +dnl ======================================================================= +dnl Checks for header files. +dnl ======================================================================= + +AC_STDC_HEADERS + +dnl We don't use AM_CONFIG_HEADER to define HAVE_WCHAR_H, etc. because +dnl the following is more straightforward and easier to understand, +dnl especially for a newcomer. Furthermore, AM_CONFIG_HEADER represents +dnl false as undefined, whereas our scheme represents it as 0. undefined +dnl is a poor choice because it often means just that you neglected to +dnl choose a value for some reason. + +dnl defines ac_cv_header_wchar_h, etc: +AC_CHECK_HEADERS(wchar.h) + +if test x"$ac_cv_header_wchar_h" = xyes; then + HAVE_WCHAR_H_DEFINE=1 +else + HAVE_WCHAR_H_DEFINE=0 +fi +AC_SUBST(HAVE_WCHAR_H_DEFINE) + +# Needed by Abyss on Solaris: + +AC_CHECK_HEADERS(sys/filio.h) +if test x"$ac_cv_header_sys_filio_h" = xyes; then + HAVE_SYS_FILIO_H_DEFINE=1 +else + HAVE_SYS_FILIO_H_DEFINE=0 +fi +AC_SUBST(HAVE_SYS_FILIO_H_DEFINE) + +# Needed by Abyss on Solaris: + +AC_CHECK_HEADERS(sys/ioctl.h) +if test x"$ac_cv_header_sys_ioctl_h" = xyes; then + HAVE_SYS_IOCTL_H_DEFINE=1 +else + HAVE_SYS_IOCTL_H_DEFINE=0 +fi +AC_SUBST(HAVE_SYS_IOCTL_H_DEFINE) + + +AC_CHECK_HEADERS(stdarg.h, , [ +AC_MSG_ERROR(stdarg.h is required to build this library) +]) + + +dnl ======================================================================= +dnl Checks for typedefs, structures, and compiler characteristics. +dnl ======================================================================= + +dnl AC_C_BIGENDIAN +AC_TYPE_SIZE_T + +dnl This check is borrowed from Python 1.5.2. +va_list_is_array=no +AC_MSG_CHECKING(whether va_list is an array) +AC_TRY_COMPILE([ +#include +], [va_list list1, list2; list1 = list2;], , +va_list_is_array=yes) +AC_MSG_RESULT($va_list_is_array) +if test x"$va_list_is_array" = xyes; then + VA_LIST_IS_ARRAY_DEFINE=1 +else + VA_LIST_IS_ARRAY_DEFINE=0 +fi +AC_SUBST(VA_LIST_IS_ARRAY_DEFINE) + +AC_MSG_CHECKING(whether compiler has __attribute__) +AC_TRY_COMPILE(, [int x __attribute__((__unused__));], +compiler_has_attribute=yes, +compiler_has_attribute=no) +AC_MSG_RESULT($compiler_has_attribute) +if test x"$compiler_has_attribute" = xyes; then + ATTR_UNUSED="__attribute__((__unused__))" +else + ATTR_UNUSED= +fi +AC_SUBST(ATTR_UNUSED) + + +dnl ======================================================================= +dnl Checks for library functions. +dnl ======================================================================= + +AC_CHECK_FUNC(vsnprintf, , [ +AC_MSG_ERROR(your C library does not provide vsnprintf) +]) + +dnl Unicode function needed by test suites. +AC_CHECK_FUNCS(wcsncmp) + +dnl CygWin looks like Unix, but doesn't provide setgroups. +AC_CHECK_FUNCS(setgroups) + +AC_CHECK_FUNCS(asprintf) + +AC_CHECK_FUNCS(setenv) + + +dnl ======================================================================= +dnl Checks for operating system features. +dnl ======================================================================= + +dnl Non-Unix systems will need to set up their platform configuration file +dnl by hand. +DIRECTORY_SEPARATOR="/" +AC_SUBST(DIRECTORY_SEPARATOR) + + +dnl ======================================================================= +dnl ABYSS Configuration +dnl ======================================================================= + +AC_MSG_CHECKING(whether to use Abyss pthread function) +AC_ARG_ENABLE(abyss-threads, + [ --disable-abyss-threads Use fork in Abyss instead of pthreads], , + enable_abyss_threads=yes) +AC_MSG_RESULT($enable_abyss_threads) + +ENABLE_ABYSS_THREADS=$enable_abyss_threads +AC_SUBST(ENABLE_ABYSS_THREADS) + +if test x"$enable_abyss_threads" != xno; then + CFLAGS="$CFLAGS -D_THREAD" +fi + + +dnl ======================================================================= +dnl Finding wininet stubs +dnl ======================================================================= +dnl If you implement the parts of wininet.h the wininet_transport uses, +dnl you will need to configure this way.. + +if test $MUST_BUILD_WININET_CLIENT = yes; then + + dnl You can control which of these gets chosen by fooling around with PATH. + AC_PATH_PROGS(WININET_CONFIG, wininet-xmlrpc-config wininet-config, no) + if test "x$WININET_CONFIG" = "xno"; then + AC_MSG_ERROR(wininet lib not found; see './configure --help') + fi + + dnl Get our wininet version. + dnl Adapted from a macro which called gtk-config. + AC_MSG_CHECKING(for wininet version >= 1.0.0) + W3VER=`$WININET_CONFIG --version` + WININET_MAJOR=\ +`echo $W3VER|sed 's/\([[0-9]]*\)\.\([[0-9]]*\)\.\([[0-9]]*\)/\1/'` + WININET_MINOR=\ +`echo $W3VER|sed 's/\([[0-9]]*\)\.\([[0-9]]*\)\.\([[0-9]]*\)/\2/'` + WININET_MICRO=\ +`echo $W3VER|sed 's/\([[0-9]]*\)\.\([[0-9]]*\)\.\([[0-9]]*\)/\3/'` + AC_MSG_RESULT($WININET_MAJOR.$WININET_MINOR.$WININET_MICRO) + + dnl Check to make sure our version is OK. + WININET_VERSION_OK=yes + if test $WININET_MAJOR -lt 1; then + WININET_VERSION_OK=no + else + if test $WININET_MAJOR -eq 1 -a $WININET_MINOR -lt 0; then + WININET_VERSION_OK=no + else + if test $WININET_MAJOR -eq 1 -a $WININET_MINOR -eq 0 \ + -a $WININET_MICRO -lt 0; then + WININET_VERSION_OK=no + fi + fi + fi + if test "x$WININET_VERSION_OK" = "xno"; then + AC_MSG_ERROR(wininet version >= 1.0.0 required) + fi + + dnl Get the necessary CFLAGS, and merge them into our master list. + WININET_CFLAGS="`$WININET_CONFIG --cflags`" + AC_SUBST(WININET_CFLAGS) + CFLAGS="$CFLAGS $WININET_CFLAGS" + + dnl Get the huge list of libraries we need to link against. + WININET_LDADD="`$WININET_CONFIG --libs`" + AC_SUBST(WININET_LDADD) + + dnl Oh, such massive brain damage! Because there may be another copy + dnl of libwww in the default dynamic loader search path, we need to + dnl adjust the search patch manually. Just gag me with a backquote, OK? + AC_MSG_CHECKING(for wininet library directory) + if $WININET_CONFIG --rpath-dir > /dev/null 2>&1; then + dnl Yay! We're using our smart version of wininet. + WININET_LIBDIR="`$WININET_CONFIG --rpath-dir`" + else + dnl Yawn. We're using the regular boring version. + WININET_LIBDIR="`$WININET_CONFIG --prefix`/lib" + fi + AC_MSG_RESULT($WININET_LIBDIR) + AC_SUBST(WININET_LIBDIR) + WININET_RPATH="-rpath $WININET_LIBDIR" + AC_SUBST(WININET_RPATH) + WININET_WL_RPATH="-Wl,--rpath -Wl,$WININET_LIBDIR" + AC_SUBST(WININET_WL_RPATH) + +fi # MUST_BUILD_WININET_CLIENT + +dnl ======================================================================= +dnl Finding w3c-libwww +dnl ======================================================================= +dnl Once upon a time, we used a patched copy of libwww that needed to +dnl co-exist with the system copy of libwww. We have some vestigal function +dnl for keeping track of libwww's rpath, although this is no longer really +dnl necessary. + +if test $MUST_BUILD_LIBWWW_CLIENT = yes; then + + dnl First of all, locate the semi-broken libwww config program. + dnl You can control which of these gets chosen by fooling around with PATH. + AC_PATH_PROGS(LIBWWW_CONFIG, libwww-xmlrpc-config libwww-config, no) + if test "x$LIBWWW_CONFIG" = "xno"; then + AC_MSG_ERROR(w3c-libwww not found; see './configure --help') + fi + + dnl Get our libwww version. + dnl Adapted from a macro which called gtk-config. + AC_MSG_CHECKING(for w3c-libwww version >= 5.2.8) + W3VER=`$LIBWWW_CONFIG --version` + LIBWWW_MAJOR=\ +`echo $W3VER|sed 's/\([[0-9]]*\)\.\([[0-9]]*\)\.\([[0-9]]*\)/\1/'` + LIBWWW_MINOR=\ +`echo $W3VER|sed 's/\([[0-9]]*\)\.\([[0-9]]*\)\.\([[0-9]]*\)/\2/'` + LIBWWW_MICRO=\ +`echo $W3VER|sed 's/\([[0-9]]*\)\.\([[0-9]]*\)\.\([[0-9]]*\)/\3/'` + AC_MSG_RESULT($LIBWWW_MAJOR.$LIBWWW_MINOR.$LIBWWW_MICRO) + + dnl Check to make sure our version is OK. + LIBWWW_VERSION_OK=yes + if test $LIBWWW_MAJOR -lt 5; then + LIBWWW_VERSION_OK=no + else + if test $LIBWWW_MAJOR -eq 5 -a $LIBWWW_MINOR -lt 2; then + LIBWWW_VERSION_OK=no + else + if test $LIBWWW_MAJOR -eq 5 -a $LIBWWW_MINOR -eq 2 \ + -a $LIBWWW_MICRO -lt 8; then + LIBWWW_VERSION_OK=no + fi + fi + fi + if test "x$LIBWWW_VERSION_OK" = "xno"; then + AC_MSG_ERROR(w3c-libwww version >= 5.2.8 required) + fi + + dnl Get the huge list of libraries we need to link against. + LIBWWW_LDADD="`$LIBWWW_CONFIG --libs`" + AC_SUBST(LIBWWW_LDADD) + + dnl Oh, such massive brain damage! Because there may be another copy + dnl of libwww in the default dynamic loader search path, we need to + dnl adjust the search patch manually. Just gag me with a backquote, OK? + AC_MSG_CHECKING(for libwww library directory) + if $LIBWWW_CONFIG --rpath-dir > /dev/null 2>&1; then + dnl Yay! We're using our smart version of libwww. + LIBWWW_LIBDIR="`$LIBWWW_CONFIG --rpath-dir`" + else + dnl Yawn. We're using the regular boring version. + LIBWWW_LIBDIR="`$LIBWWW_CONFIG --prefix`/lib" + fi + AC_MSG_RESULT($LIBWWW_LIBDIR) + AC_SUBST(LIBWWW_LIBDIR) + + # Some ancient rpath stuff, now disabled. I turned this off because it + # breaks Debian (and Mandrake?) policy, and we don't use it anymore. + # If you have multiple copies of w3c-libwww lying around, you can turn + # it back on. + #LIBWWW_RPATH="-rpath $LIBWWW_LIBDIR" + LIBWWW_RPATH="" + AC_SUBST(LIBWWW_RPATH) + #LIBWWW_WL_RPATH="-Wl,--rpath -Wl,$LIBWWW_LIBDIR" + LIBWWW_WL_RPATH="" + AC_SUBST(LIBWWW_WL_RPATH) + +fi # MUST_BUILD_LIBWWW_CLIENT + + +dnl ======================================================================= +dnl Finding cURL +dnl ======================================================================= + +if test $MUST_BUILD_CURL_CLIENT = yes; then + + dnl First of all, locate the curl config program. + dnl You can control which of these gets chosen by fooling around with PATH. + AC_PATH_PROGS(CURL_CONFIG, curl-xmlrpc-config curl-config, no) + if test "x$CURL_CONFIG" = "xno"; then + AC_MSG_ERROR(cURL not found; see './configure --help') + fi + + dnl There used to be code here to check the Curl version and make sure + dnl it is at least 7.8. But there were bugs both in the code and in + dnl curl (curl-config --vernum, at least in older versios of Curl, + dnl omits the leading zero). So it didn't work. Plus, checking version + dnl numbers isn't a good idea. Better to check for feature presence. + dnl So we don't do any check now. If we find out there's a problem with + dnl older Curls, we will revisit that. + + dnl Get the huge list of libraries we need to link against. + dnl MRB-20010516-For some reason, curl-config + dnl does not list itself '-lcurl'. 2004.12.12. It seems to do so + dnl now. + CURL_LDADD=`$CURL_CONFIG --libs` + AC_SUBST(CURL_LDADD) + + dnl Oh, such massive brain damage! Because there may be another copy + dnl of curl in the default dynamic loader search path, we need to + dnl adjust the search patch manually. Just gag me with a backquote, OK? + AC_MSG_CHECKING(for curl library directory) + dnl Yawn. We're using the regular boring version. + CURL_LIBDIR="`$CURL_CONFIG --prefix`/lib" + + AC_MSG_RESULT($CURL_LIBDIR) + AC_SUBST(CURL_LIBDIR) + CURL_RPATH="-rpath $CURL_LIBDIR" + AC_SUBST(CURL_RPATH) + CURL_WL_RPATH="-Wl,--rpath -Wl,$CURL_LIBDIR" + AC_SUBST(CURL_WL_RPATH) + +fi # MUST_BUILD_CURL_CLIENT + + +dnl ======================================================================= +dnl Checks for build options. +dnl ======================================================================= + +AC_ARG_WITH(libwww-ssl, + [ --with-libwww-ssl Include libwww SSL capability.] + ) + +if test x"$enable_libwww_client" != xno; then + AC_MSG_CHECKING(whether to use SSL with libwww) + if test x"$with_libwww_ssl" = xyes; then + AC_MSG_RESULT(yes) + HAVE_LIBWWW_SSL_DEFINE=1 + else + AC_MSG_RESULT(no) + HAVE_LIBWWW_SSL_DEFINE=0 + fi +fi +AC_SUBST(HAVE_LIBWWW_SSL_DEFINE) + +dnl Check to see if we should build the libxml2 backend. +AC_ARG_ENABLE(libxml2-backend, + [ --enable-libxml2-backend Use libxml2 instead of built-in expat], , +enable_libxml2_backend=no) +AC_MSG_CHECKING(whether to build the libxml2 backend) +AC_MSG_RESULT($enable_libxml2_backend) + +if test $enable_libxml2_backend = yes; then + AC_CHECK_PROG(have_xml2_config, xml2-config, yes, no) + if test $have_xml2_config = no; then + AC_MSG_ERROR([You specified --enable-libxml2_backend, but don't appear to have libxml2 installed (no working xml2-config inyour command search path), so we cannot not build for libxml2]) + fi +fi +ENABLE_LIBXML2_BACKEND=$enable_libxml2_backend +AC_SUBST(ENABLE_LIBXML2_BACKEND) + +dnl ======================================================================= +dnl Compiler information +dnl ======================================================================= +C_COMPILER_GNU=$ac_cv_c_compiler_gnu +AC_SUBST(C_COMPILER_GNU) +CXX_COMPILER_GNU=$ac_cv_cxx_compiler_gnu +AC_SUBST(CXX_COMPILER_GNU) + +dnl obsolete variables, need to be removed from Makefile.in: +CC_WARN_FLAGS= +AC_SUBST(CC_WARN_FLAGS) +CPP_WARN_FLAGS= +AC_SUBST(CPP_WARN_FLAGS) + + +BUILDDIR=`pwd` +AC_SUBST(BUILDDIR) + +dnl ======================================================================= +dnl Libtool +dnl ======================================================================= +AM_PROG_LIBTOOL + + +dnl ======================================================================= +dnl Output our results. +dnl ======================================================================= + +dnl Note that AM_CONFIG_HEADER at the top of this file outputs another +dnl result: xmlrpc_amconfig.h . + +AC_OUTPUT(xmlrpc-c-config \ + xmlrpc-c-config.test \ + Makefile.config \ + xmlrpc_config.h \ + ) +chmod +x xmlrpc-c-config +chmod +x xmlrpc-c-config.test diff --git a/doc/COPYING b/doc/COPYING new file mode 100644 index 0000000..1d83762 --- /dev/null +++ b/doc/COPYING @@ -0,0 +1,143 @@ +The copyright owners of this package license the public to copy it +(and do other things with it which are controlled by copyright law) +under a few simple conditions. + +Each source files describes the copyright license for that particular +file. This file summarizes the licenses for your convenience. + +All the code written specifically for Xmlrpc-c, which is most +of the code, and the aggregation, is licensed under the +XML-RPC FOR C/C++ license shown below. + +Some of the code was written for another purpose and copied into +Xmlrpc-c. Its copyright owners license the code under a different +license: + +The Expat Licence applies to the contents of the directory lib/expat, +the ABYSS Web Server License applies to the contents of the directory +lib/abyss and parts of the file src/xmlrpc_abyss.c. + +The Python 1.5.2 license applies to parts of the file +src/xmlrpc_base64.c. + +And as for the tools/ directory, you'll have to examine the licenses +on your own. + +These same licenses have been offered throughout Xmlrpc-c's history. + + + XML-RPC For C/C++ License + ------------------------- + +Copyright (C) 2001 by First Peer, Inc. All rights reserved. +Copyright (C) 2001 by Eric Kidd. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. +3. The name of the author may not be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +SUCH DAMAGE. + + + Expat License + ------------- + +Copyright (c) 1998, 1999, 2000 Thai Open Source Software Center Ltd + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + + ABYSS Web Server License + ------------------------ + +Copyright (C) 2000 by Moez Mahfoudh . All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. +3. The name of the author may not be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +SUCH DAMAGE. + + + + Python 1.5.2 License + -------------------- + +Copyright 1991, 1992, 1993, 1994 by Stichting Mathematisch Centrum, +Amsterdam, The Netherlands. + + All Rights Reserved + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +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 names of Stichting Mathematisch +Centrum or CWI or Corporation for National Research Initiatives or +CNRI not be used in advertising or publicity pertaining to +distribution of the software without specific, written prior +permission. + +While CWI is the initial source for this software, a modified version +is made available by the Corporation for National Research Initiatives +(CNRI) at the Internet address ftp://ftp.python.org. + +STICHTING MATHEMATISCH CENTRUM AND CNRI DISCLAIM ALL WARRANTIES WITH +REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH +CENTRUM OR CNRI BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL +DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR +PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER +TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR +PERFORMANCE OF THIS SOFTWARE. diff --git a/doc/CREDITS b/doc/CREDITS new file mode 100644 index 0000000..050113a --- /dev/null +++ b/doc/CREDITS @@ -0,0 +1,19 @@ +Funding for the project that created the original Xmlrpc-c was +provided in part by the good folks at First Peer, Inc., producers of +P2P applications. + +Eric Kidd developed the original Xmlrpc-c in 2000 and maintained it up +through June 2001. + +Bryan Henderson took over as maintainer in October 2004. + +Xmlrpc-c contains (and relies on for some server functions) a derivation +of the Abyss web server by Moez Mahfoudh. + +Xmlrpc-c contains (and relies on) a derivation of the Expat XML +parser, written by James Clark. + +The base64 code was derived from what Jack Jansen developed for Python. + +For more history, including credits for more minor contributions, see +the HISTORY file. diff --git a/doc/DEVELOPING b/doc/DEVELOPING new file mode 100644 index 0000000..d5c53b0 --- /dev/null +++ b/doc/DEVELOPING @@ -0,0 +1,82 @@ +Here are some notes to help you develop code for Xmlrpc-c. I include +as "developing" debugging to figure out why Xmlrpc-c doesn't work for +you. + +CODE LIBRARY +------------ + +The master Xmlrpc-c source code tree is the CVS repository on +Sourceforge. Anybody can read it; only the maintainer can commit to +it. If you're not the maintainer, simply use a 'cvs diff' command in +your CVS working directory to create a patch file that embodies your +changes and email that to the maintainer. He can easily apply that +patch to his own CVS working directory and then commit the changes. + + +MAKE VARIABLES +-------------- + +You can pass make variable values to GNU Make to change the build. +There are two common ways to do this: + + 1) Like this: + + $ make MYVAR=myvalue + + 2) Via an environment variable, like this: + + $ MYVAR=myvalue make + + or + + $ export MYVAR=myvalue + $ make + +See GNU Make and shell documentation for details. + +In Xmlrpc-c make files, there are two make variables that add +arbitrary options to every compile command: CADD and CFLAGS_PERSONAL. + +They both do the same thing. CADD is meant to be set on an individual +make command, whereas CFLAGS_PERSONAL is meant to be a long-lived +environment variable. CFLAGS_PERSONAL is for flags you like on all +your compiles, but maybe others don't. + +One of my favorite CADD settings is CADD=--save-temps. To the GNU +Compiler, --save-temps means to create, in addition to the object +code, a file containing the intermediate preprocessed C code and a +file containing the intermediate assembler source code. I can use +that to debug certain things. + +The Xmlrpc-c build uses -g by default with Gcc, so you don't need to +use CADD to get debugging symbols in your object code. + + +There's also LADD for linker options. + + +CODE STYLE +---------- + +The maintainer is pretty particular about coding style, but doesn't +require anyone to submit code in any particular style. He changes +what he thinks isn't maintainable enough as submitted. You could do +him a big favor, though, and reduce the chance of him introducing bugs +into your code, but trying to copy the style you see in existing code. +The major theme is high level programming -- closer to English prose +and further from machine instructions. + +Probably the most important thing is not to use tabs. Tabs are +actually quite common in Unix C programming, but apart from tradition, +they are a bad idea. They don't look the same to everyone. A person +must suffer an additional configuration step -- setting up tab stops +in order to see the code the right way. Spaces, on the other hand, +look the same to everyone. Very old editors made it easier to compose +with tabs than with spaces, but with modern ones, there is no +difference. + +The maintainer tries to catch all tabs in code submitted to him and +convert them to spaces, but this often leaves the code incorrectly +indented. Better to give him code that already has the right number +of spaces explicitly. + diff --git a/doc/HISTORY b/doc/HISTORY new file mode 100644 index 0000000..ada3e0f --- /dev/null +++ b/doc/HISTORY @@ -0,0 +1,61 @@ +For a release-by-release change history, see +. + +XML-RPC For C/C++ was created by Eric Kidd in 2000, when XML-RPC was +new and vital. Its development was funded in significant part by +First Peer, Inc. Eric released the package in January 2001 and set up +an extensive project to maintain it. The project used virtually every +feature on Sourceforge, had about 8 official developers, and +distributed code in various formats. There were mailing lists, +trackers, CVS branches, RPMs, and a full PHP-based web site, just to +name a few features of the project. + +Then everything ground to a halt in June 2001, with the disappearance +of Eric. We don't know what happened to him, but Google searches in +late 2004 indicated he dropped off the face of the web at that time. +While people continued to use Xmlrpc-c, and some developed fixes and +enhancements and posted them to the Sourceforge trackers, the release +remained frozen at 0.9.10. The web site also became frozen in time. + +In the years that followed the great freeze, XML-RPC became +marginalized by more sophisticated alternatives such as SOAP. XML-RPC +consequently became rather stable and interest in Xmlrpc-c levelled +off. + +This dark age of Xmlrpc-c lasted until November 2004, when Bryan Henderson +set out to find an RPC mechanism to use in one of his projects. Bryan +found XML-RPC and then Xmlrpc-c. He decided that the two were almost right +for his needs, but he needed some small extensions. + +On finding out that the project was orphaned, Bryan decided to take it +over. Bryan became the Sourceforge project administrator through +Sourceforge's abandonned project process, then gathered the patches +that had been submitted over the years and made a come-back release +called 1.0. + +Bryan then proceeded to add a lot of features in subsequent releases +about every two months. Most of it was code Bryan wrote himself, but +significant parts were contributed by others, as you can see in the +detailed history below. Among the larger enhancements was a new +C++ interface; the old one was a fairly weak wrapper around the +C interface and required the user to manage memory and access the +underlying C structures; the new one used pure C++ principles with +automatic memory management. + +Bryan also wrote a complete user's manual. Surprisingly, in spite of +the wide array of features the project had, documentation wasn't one +of them. There was only a smattering of information available on how +to use the package. + +One significant change Bryan made to the project was to strip it down +considerably. In order to concentrate the small amount of time Bryan +had available for Xmlrpc-c development on actual code and +documentation, Bryan had to greatly reduce the amount of bureaucracy +involved in administering the project and making releases, and reduce +the set of skills required to do it. Bryan made static make files +(for GNU Make) to replace the two extra build stages that originally +generated make files. Bryan moved away from Libtool and toward simple +compiling and linking. Bryan eliminated all pre-built distributions; +each of his releases consisted of a single source code tarball, and +that tarball was not signed. Bryan removed some redundant sources of +information from the package and the web site. diff --git a/doc/INSTALL b/doc/INSTALL new file mode 100644 index 0000000..7b15e94 --- /dev/null +++ b/doc/INSTALL @@ -0,0 +1,129 @@ +These are instructions for building Xmlrpc-c from source and installing +it on a system. + +See the README file for information on prerequisites (things you need to +have installed before you can build). + + +Essentially, it's just the conventional + + $ ./configure + $ make + $ make install + +You can also do + + $ make check + +to run a battery of tests before you install. But note that it's as common +for the tests to fail because the tests are broken as because the product +is broken, so consider the results carefully. + +To see it work, run a simple server like this: + + $ examples/xmlrpc_sample_add_server 8080 + +Then run a client that does an RPC to this server: + + $ examples/xmlrpc_sample_add_client + +(I don't mean to imply that the above are consecutive shell commands; +They can't be, because the server program runs indefinitely). + +Also try other sample servers and clients, described in examples/README. + + +You may want to pass a '--prefix' argument to 'configure'. See +'./configure --help' for details. + +You may also want to disable client XML transports that you won't be +using. In particular, the Libwww transport can be inconvenient, because +it typically uses about 20 shared libraries. Any XML-RPC client +program that uses Xmlrpc-c, whether or not the program uses any of the +libwww facilities, must attach all those libraries, and that can take +a significant amount of time. + +See './configure --help' for the options that disable certain transports. + + +COMMON PROBLEMS +--------------- + +Improper -config files +---------------------- + +The most common problem building Xmlrpc-c is one of improperly installed +prerequisite libraries, namely Libwww and Curl. These libraries are +designed to be installed along with a -config program (libwww-config +and curl-config) that tells builders of dependent packages (such as +Xmlrpc-c) how to use them. When the -config program is wrong, you get +Xmlrpc-c build failures with messages about undefined references. + +The exact nature of the problems with -config programs can be quite +involved, especially since there is no guarantee that a -config +program can do what's required of it in every situation. But I'll +explain the basic problem. For simplicity, I'll talk specifically +about Curl, but the principles apply to any library that has a -config +program. + +The point of curl-config is to describe how Curl is installed on your +particular system. You have choices of where to install the various parts +and what prerequisites to build into them, and curl-config is how you +communicate those choices to the Xmlrpc-c make files. + +Curl's builder automatically creates a curl-config program for you, +but you should not think of it as part of Curl. It's really a +configuration file -- something that tells how your particular system +is put together. The Curl builder is not smart enough to know exactly +what to put in curl-config; it just builds one that works for most +people. The local system administrator is actually responsible for +the contents of curl-config. + +One rather complex way in which the curl-config that the Curl builder +builds can be wrong is that it often indicates that to link to the +Curl library, you need a "-L /usr/lib" option (or something like that +-- an option that adds to the linker's search path a directory that is +already in it). This is usually unnecessary because the directory is +already in the search path, and often breaks things because it puts +the directory too early in the search path. If your curl-config says to +link with -L /usr/lib, you should normally edit it to remove that. + +As an example of how -L /usr/lib breaks things, here is a problem that +is often reported: The user has Xmlrpc-c installed on his system, but +wants to build a new one to replace it, or to use for a particular +project instead of the system version. But the build of the new +version fails with undefined references to symbol "xmlrpc_foo". +xmlrpc_foo is a new symbol - it was added to Xmlrpc-c in a recent +release. The version of Xmlrpc-c installed on the system is too old +to have it. The make file obviously specifies the path to the current +libraries that the user just built in the link library search order, +but the link is picking up the old system version instead. Why? +Because the link options say to search /usr/lib _before_ the local +build directory. And it does that because curl-config erroneously +says that you need a -L /usr/lib link option to find the Curl library. + +64 Bit Linux -fPIC +------------------ + +The GNU link-editor produces this error message when building the C++ +libraries for certain 64 bit machines: + + relocation R_X86_64_32 against `a local symbol' can not be used when + making a shared object; recompile with -fPIC + +Xmlrpc-c 1.06 C++ libraries are not designed for these platforms. +(Releases starting with 1.07 are). + +You can work around this by adding a setting of the CADD make variable +to your make command: + + make CADD=-fPIC + + +WINDOWS +------- + +All of the above is essentially for Unix-type operating systems. To +build and use Xmlrpc-c on Windows, see the file +Windows/ReadMeWin32.txt. + diff --git a/doc/SECURITY b/doc/SECURITY new file mode 100644 index 0000000..c3566c2 --- /dev/null +++ b/doc/SECURITY @@ -0,0 +1,50 @@ +Security Advisories +=================== + +The Xmlrpc-c maintainer will normally post security advisories related +to xmlrpc-c to the xmlrpc-c-announce mailing list. You can subscribe +to this using the web: + + http://xmlrpc-c.sourceforge.net/lists.php + +You will also find a list of all known bugs including those with +security ramifications, in the release notes on Sourceforge. To see +the release notes for a release, go to the file download page and +click on the release name. The list is current only for the most +current release -- i.e. we stop adding to the list for release N after +we release N+1. + + +XML-RPC Security +================ + +There are some security issues inherent in XML-RPC: + + 1) XML-RPC messages are not encrypted at the XML-RPC level. This + means that unless you encrypt them at some lower level, someone + with sufficient access to the network can see them with standard + packet-sniffing and network administration tools. + + This is especially dangerous because XML-RPC is a stateless protocol. + If you include reusable authentication tokens in an XML-RPC call, they + can probably be sniffed and used by attackers. + + You can solve this problem by using SSL under HTTP. This is possible + with Xmlrpc-c, but it's nontrivial to set up and the Xmlrpc-c + documentation doesn't tell you how. + + 2) There are no permission restrictions and no authentication built + into Xmlrpc-c by default -- any client can call any method on any + visible server and neither can know for sure to whom it is talking. + + If you need permission and authentication, you either have to put + it above the XML-RPC layer or below. For a server, above means in + the method code you supply and register with the Xmlrpc-c server + facilities; below means something like a firewall that lets clients + only from a certain IP address connect to your server. + + 3) XML-RPC is a complex protocol based on complex data structures. + Layers and layers of potentially buggy code gets run between the + time network data is received, and the time it is understood; and + conversely between the time data is conceived and the time it + gets sent. diff --git a/doc/TESTING b/doc/TESTING new file mode 100644 index 0000000..50d785d --- /dev/null +++ b/doc/TESTING @@ -0,0 +1,96 @@ +In general, we want to run as many automated test tools on the +Xmlrpc-c libraries as possible. Before releasing a new release, +please run as many of these tests as possible. + + +Included Test Suites +-------------------- + +The 'test' program tests core functions. These are functions that +don't involve HTTP communications. So obviously, it doesn't do any +end-to-end client/server tests. + +The program is in src/test/test. You have to build that explicitly (with +src/test/ as your current directory, do a 'make'); a top level 'make all' +doesn't build it. (Reason: it's a tricky build, and we don't a user's +build to fail just because of this program that a user doesn't need). + +src/cpp/cpptest is similar for the C++ libraries. + +Note: Before Release 1.03, 'test' was called 'rpctest' and both it +and 'cpptest' were in the src/ directory and were built by 'make all'. + + +Memory Leaks +------------ + +(Linux only?) Install Owen Taylor's 'memprof' utility. This program +includes a malloc debugger and a conservative garbage collector. To run it, +type: + + memprof test + +This should report any memory leaks which occur while the test suites are +running. + + +Electric Fence +-------------- + +(Most Unix platforms.) Install Bruce Perens' Electric Fence library, and +read the man pages carefully. Link 'test' against '-lefence', and run it +with the following sets of environment variables: + + 1) (Default environment.) + Test for heap block overruns. + + 2) EF_PROTECT_BELOW=1 + Test for heap block underruns. + + 3) EF_PROTECT_FREE=1 + Test for doubly-freed memory and illegal accesses to freed memory. + + 4) EF_ALIGNMENT=0 + Test for very small block overruns. This is an important test, but + it may not work on some platforms. Please see the efence manpage for + more information. + +(After each run, unset the environment variables from the previous run.) + +Using a Bourne shell (such as bash) you can run all these tests as follows: + + test + EF_PROTECT_BELOW=1 test + EF_PROTECT_FREE=1 test + EF_ALIGNMENT=0 test + +Alternatively, if you have a copy of Purify installed, please run that. + + +End-to-End Tests +---------------- + +To test Abyss and the client XML transports, use the example +programs examples/sample_add_server and examples/sample_add_client: + + $ export XMLRPC_TRACE_XML=1 + $ examples/sample_add_server 8080& + $ examples/sample_add_client + +Note that we use XMLRPC_TRACE_XML so we can see the XML flying by on +both sides of the connection. + +Note that the Port 8080 is hardcoded in sample_add_client. + +Note that sample_add_client uses only the default XML transport. + + +You can do more extensive client testing with the 'xmlrpc' program +(tools/xmlrpc/xmlrpc). + + +Tips +---- + +To debug Abyss without threads, don't pass -D_UNIX or -D_WIN32. The server +will run in a single-threaded mode. diff --git a/doc/TODO b/doc/TODO new file mode 100644 index 0000000..514b4a4 --- /dev/null +++ b/doc/TODO @@ -0,0 +1,71 @@ +Here are some changes we'd like to see to Xmlrpc-c. While it's unlikely +anyone will ever do them, the list is at least useful as an indication of +what direction the maintainer wants the package to take, and that should +be useful to anyone proposing changes of any kind. + + +FUNCTIONAL CHANGES +------------------ + +Make xmlrpc_server_abyss() catch a SIGTERM and terminate cleanly. + +Make a system.shutdown XML-RPC method to send SIGTERM to its server. +Don't know what kind of security. + +Provide an interface for Abyss servers where the user accepts the TCP +connection and passes to Xmlrpc-c the open socket. This would be +useful for inetd servers, among others. For the C++ interface, this +should be a new constructor option to create a server with no socket +and a doRpc() method that has a connected socket as parameter. + +Put details in the manual for the xmlrpc-c/server_abyss.hpp interface: +libxmlrpc_server_abyss++.html. + +Implement pluggable XML transports on the server side like on the +client side. + +Create a non-XML non-HTTP efficient transport, client and server. +The tools/binmode-rpc-kit/ directory might be useful. Consider XDR. + +Make clients and servers reentrant (this requires getting or making +reentrant HTTP libraries). + +Change the argument order of asynchronous response callbacks to be +more consistent with the xmlrpc_client_call_asynch function. Also +take a look at the server method callback. + +Make an optional destructor function for XMLRPC_TYPE_C_PTR. + +Return XMLRPC_LIMIT_EXCEEDED_ERROR when nesting limits are exceeded. +This will break binary and source API compatibility in a very minor +way. + +Make a Perl interface to Xmlrpc-c libraries. This would be better than the +existing Perl RPC::XML modules because the latter are Perl all the way down +to the sockets and are thus very slow. + +Don't use xmlrpc_value for things that aren't part of an XML-RPC call or +response. It's confusing. In particular, we use an xmlrpc_value +array to pass the parameters of an RPC to xmlrpc_client_call(), and it +should instead be a normal C array plus count, or variable argument list. + +Don't use XML-RPC fault codes internally. It's confusing. Plus, there's +no need for fault codes at all. Just use the string descriptions. + + +IMPLEMENTATION CHANGES +---------------------- + +Replace dynamically created make files with static ones based on GNU make. + +Use function pointers to access cleanup code in xmlrpc_DECREF? + +Or even better: Should we create some kind of class-like system to declare +XML-RPC types, with a per-type dispatch table? + +Fix abstract XML parser API to access children via functions named +xml_element_child(env,elem,index) and xml_element_child_count(env,elem). +Clean up corresponding client code. + +Make the C++ server implementation less based on the C functions. + diff --git a/doc/configure_doc b/doc/configure_doc new file mode 100644 index 0000000..953a904 --- /dev/null +++ b/doc/configure_doc @@ -0,0 +1,189 @@ +Xmlrpc-c's 'configure' program is a GNU Autoconf configurator -- i.e. +it is created by GNU Autoconf. This is the standard configurator you +find throughout the open source software world. Here are the instructions +for 'configure' from GNU Autoconf; in most packages, you find these in +a file called INSTALL. + + +Basic Installation +================== + + These are generic installation instructions. + + 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: + + 1. `cd' to the directory containing the package's source code and type + `./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. + + 2. Type `make' to compile the package. + + 3. Optionally, type `make check' to run any self-tests that come with + the package. + + 4. Type `make install' to install the programs and any data files and + documentation. + + 5. 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. Using +a Bourne-compatible shell, you can do that on the command line like +this: + CC=c89 CFLAGS=-O2 LIBS=-lposix ./configure + +Or on systems that have the `env' program, you can do it like this: + env CPPFLAGS=-I/usr/local/include LDFLAGS=-s ./configure + +Compiling For Multiple Architectures +==================================== + + You can compile the package for more than one kind of computer at the +same time, by placing the object files for each architecture in their +own directory. To do this, you must use a version of `make' that +supports the `VPATH' variable, such as GNU `make'. `cd' to the +directory where you want the object files and executables to go and run +the `configure' script. `configure' automatically checks for the +source code in the directory that `configure' is in and in `..'. + + If you have to use a `make' that does not supports the `VPATH' +variable, you have to compile the package for one architecture at a time +in the source code directory. After you have installed the package for +one architecture, use `make distclean' before reconfiguring for another +architecture. + +Installation Names +================== + + By default, `make install' will install the package's files in +`/usr/local/bin', `/usr/local/man', etc. You can specify an +installation prefix other than `/usr/local' by giving `configure' the +option `--prefix=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. diff --git a/examples/.cvsignore b/examples/.cvsignore new file mode 100644 index 0000000..5835a25 --- /dev/null +++ b/examples/.cvsignore @@ -0,0 +1,13 @@ +gen_sample_add_xml +meerkat-app-list +query-meerkat +synch_client +xmlrpc_asynch_client +auth_client +xmlrpc_inetd_server +xmlrpc_loop_server +xmlrpc_sample_add_client +xmlrpc_sample_add_server +xmlrpc_server_validatee +xmlrpc_socket_server +*.cgi diff --git a/examples/Makefile b/examples/Makefile new file mode 100644 index 0000000..7eb8e96 --- /dev/null +++ b/examples/Makefile @@ -0,0 +1,141 @@ +# Since the programs in this directories are examples for the user, this +# make file should be as ordinary as possible. It should not rely heavily +# on included make files or configuration parameters. It should not use +# libtool. Also, we don't try to build or rebuild the libraries on which +# these programs depend. + + +ifeq ($(SRCDIR)x,x) +SRCDIR = $(CURDIR)/.. +BUILDDIR = $(SRCDIR) +endif + +default: all + +include $(BUILDDIR)/Makefile.config + +CFLAGS = $(CFLAGS_COMMON) $(CFLAGS_PERSONAL) $(CADD) +LDFLAGS = $(LADD) + +# If this were a real application, working from an installed copy of +# Xmlrpc-c, XMLRPC_C_CONFIG would just be 'xmlrpc-c-config'. It would be +# found in the user's PATH. +XMLRPC_C_CONFIG = $(BUILDDIR)/xmlrpc-c-config.test + +CLIENTPROGS = \ + auth_client \ + query-meerkat \ + synch_client \ + xmlrpc_sample_add_client \ + xmlrpc_asynch_client \ + +SERVERPROGS_CGI = \ + xmlrpc_sample_add_server.cgi + +SERVERPROGS_ABYSS = \ + xmlrpc_inetd_server \ + xmlrpc_socket_server \ + xmlrpc_loop_server \ + xmlrpc_sample_add_server \ + xmlrpc_server_validatee \ + +# Build up PROGS: +PROGS = + +ifeq ($(ENABLE_ABYSS_SERVER),yes) + PROGS += $(SERVERPROGS_ABYSS) +endif + +PROGS += gen_sample_add_xml + +ifeq ($(MUST_BUILD_CLIENT),yes) + PROGS += $(CLIENTPROGS) +endif + +ifeq ($(ENABLE_CGI_SERVER),yes) + PROGS += $(SERVERPROGS_CGI) +endif + +INCLUDES = $(shell $(XMLRPC_C_CONFIG) client abyss-server --cflags) + +LDADD_CLIENT = \ + $(shell $(XMLRPC_C_CONFIG) client --ldadd) + +LDADD_SERVER_ABYSS = \ + $(shell $(XMLRPC_C_CONFIG) abyss-server --ldadd) + +LDADD_SERVER_CGI = \ + $(shell $(XMLRPC_C_CONFIG) cgi-server --ldadd) + +LDADD_BASE = \ + $(shell $(XMLRPC_C_CONFIG) --ldadd) + +all: $(PROGS) + +ifeq ($(ENABLE_CPLUSPLUS),yes) + all: cpp/all +endif + +.PHONY: cpp/all +cpp/all: + $(MAKE) -C $(dir $@) $(notdir $@) + +$(CLIENTPROGS):%:%.o + $(CCLD) -o $@ $(LDFLAGS) $^ $(LDADD_CLIENT) + +$(SERVERPROGS_CGI):%.cgi:%_cgi.o + $(CCLD) -o $@ $(LDFLAGS) $^ $(LDADD_SERVER_CGI) + +$(SERVERPROGS_ABYSS):%:%.o + $(CCLD) -o $@ $(LDFLAGS) $^ $(LDADD_SERVER_ABYSS) + +gen_sample_add_xml:%:%.o + $(CCLD) -o $@ $(LDFLAGS) $^ $(LDADD_BASE) + +%.o:%.c + $(CC) -c $(INCLUDES) $(CFLAGS) $< + +*.c: config.h xmlrpc_amconfig.h + +config.h: + $(LN_S) $(BUILDDIR)/xmlrpc_config.h $@ +xmlrpc_amconfig.h: + $(LN_S) $(BUILDDIR)/$@ . + +include $(SRCDIR)/Makefile.common + +.PHONY: clean +clean: clean-common + rm -f $(PROGS) config.h xmlrpc_amconfig.h + $(MAKE) -C cpp clean + +.PHONY: distclean +distclean: clean + +BINDIR=$(DESTDIR)$(bindir) + +FILENAME_GENERATOR = "echo $$p|sed 's/$(EXEEXT)$$//'|sed '$(transform)'|sed 's/$$/$(EXEEXT)/'" + +INSTCMD = "$(LIBTOOL) --mode=install $(INSTALL_PROGRAM) $$p \ + $(BINDIR)/`$(FILENAME_GENERATOR)`" + +.PHONY: install +install: $(PROGS) + @$(NORMAL_INSTALL) + $(MKINSTALLDIRS) $(BINDIR) + @list='$(bin_PROGRAMS)'; for p in $$list; do \ + if test -f $$p; then \ + echo "$(INSTCMD)"; $(INSTCMD); \ + else :; \ + fi; \ + done + +.PHONY: check +check: + +.PHONY: dep depend +dep depend: +# We don't do dependencies in this directory, because it's supposed to be +# an example of what a program outside this package would do, so we can't +# go weaving it into the rest of the package. Ergo, a developer must +# carefully clean and remake examples as he updates other parts of the tree. diff --git a/examples/README b/examples/README new file mode 100644 index 0000000..46b02b4 --- /dev/null +++ b/examples/README @@ -0,0 +1,34 @@ +This directory contains working examples of uses of XML-RPC-c. There +are XML-RPC servers and XML-RPC clients that use the Xmlrpc-c libraries. + +The simplest example is the 'query-meerkat' program, which contacts an +XML-RPC server that O'Reilly operates on the Internet called Meerkat. +Meerkat provides an RPC that returns a list of new articles that match +a specified search pattern. Run 'query-meerkat' like this example: + + $ ./query-meerkat Linux + +This responds with a list of new articles that contain the work "Linux", +according to O'reilly's Meerkat service. + + +The simplest server program is 'xmlrpc_sample_add_server'. This +implements a single XML-RPC method called 'sample.add'. All it does is +add two numbers and return the sum. You can run such a server like +this: + + $ ./xmlrpc_sample_add_server 8080 + +The server this runs is based on the Abyss HTTP server. file. The +argument tell it to listen on TCP Port 8080 for RPCs. It puts log +information in /tmp, so be sure to look there. + +A client program that goes along with this server is +'xmlrpc_sample_add_client'. All this client does is make an XML-RPC +request to Port 8080 of 'localhost' to add the numbers 5 and 7 and +print the result on Standard Output. + +You can run such a client like this: + + $ ./xmlrpc_sample_add_client + diff --git a/examples/auth_client.c b/examples/auth_client.c new file mode 100644 index 0000000..dd6a2b4 --- /dev/null +++ b/examples/auth_client.c @@ -0,0 +1,80 @@ +/* A demonstration of using HTTP basic authentication with XML-RPC. +** +** In general, you shouldn't write XML-RPC servers which require basic +** authenticaion. (Few XML-RPC clients are capable of it, and it's not part of +** any standard.) Instead, you should pass any authentication information +** as a regular XML-RPC parameter (or look into using SSL). +** +** But certain XML-RPC servers, including Zope, rely heavily on HTTP +** basic authentication. Here's how to talk to them. */ + +#include +#include + +#include +#include + +#include "config.h" /* information about this build environment */ + +#define NAME "XML-RPC C Auth Client" +#define VERSION "1.0" +#define SERVER_URL "http://localhost:8080/RPC2" + +static void die_if_fault_occurred (xmlrpc_env *env) +{ + if (env->fault_occurred) { + fprintf(stderr, "XML-RPC Fault: %s (%d)\n", + env->fault_string, env->fault_code); + exit(1); + } +} + +int +main(int const argc, + const char ** const argv ATTR_UNUSED) { + + xmlrpc_env env; + xmlrpc_server_info * server; + xmlrpc_value * result; + xmlrpc_int sum; + + if (argc-1 > 0) { + fprintf(stderr, "There are no arguments. You specified %d", argc-1); + exit(1); + } + + /* Start up our XML-RPC client library. */ + xmlrpc_client_init(XMLRPC_CLIENT_NO_FLAGS, NAME, VERSION); + xmlrpc_env_init(&env); + + /* Make a new object to represent our XML-RPC server. */ + server = xmlrpc_server_info_new(&env, SERVER_URL); + die_if_fault_occurred(&env); + + /* Set up our authentication information. */ + xmlrpc_server_info_set_basic_auth(&env, server, "jrandom", "secret"); + die_if_fault_occurred(&env); + + result = + xmlrpc_client_call_server( + &env, server, "sample.add", "(ii)", + (xmlrpc_int32) 5, (xmlrpc_int32) 7); + die_if_fault_occurred(&env); + + /* Dispose of our server object. */ + xmlrpc_server_info_free(server); + + /* Get the authentication information and print it out. */ + xmlrpc_read_int(&env, result, &sum); + die_if_fault_occurred(&env); + printf("The sum is %d\n", sum); + + /* Dispose of our result value. */ + xmlrpc_DECREF(result); + + /* Shut down our XML-RPC client library. */ + xmlrpc_env_clean(&env); + xmlrpc_client_cleanup(); + + return 0; +} diff --git a/examples/cpp/.cvsignore b/examples/cpp/.cvsignore new file mode 100644 index 0000000..99bb114 --- /dev/null +++ b/examples/cpp/.cvsignore @@ -0,0 +1,6 @@ +meerkat-app-list +xmlrpc_inetd_server +xmlrpc_loop_server +xmlrpc_sample_add_server +xmlrpc_sample_add_client +sample_add_client_complex diff --git a/examples/cpp/Makefile b/examples/cpp/Makefile new file mode 100644 index 0000000..8d59247 --- /dev/null +++ b/examples/cpp/Makefile @@ -0,0 +1,98 @@ +# Since the programs in this directories are examples for the user, this +# make file should be as ordinary as possible. It should not rely heavily +# on included make files or configuration parameters. It should not use +# libtool. Also, we don't try to build or rebuild the libraries on which +# these programs depend. + + +ifeq ($(SRCDIR)x,x) +SRCDIR = $(CURDIR)/../.. +BUILDDIR = ../.. +endif + +default: all + +include $(BUILDDIR)/Makefile.config + +CXXFLAGS = $(CXXFLAGS_COMMON) $(CFLAGS_PERSONAL) $(CADD) +LDFLAGS = $(LADD) + +# If this were a real application, working from an installed copy of +# Xmlrpc-c, XMLRPC_C_CONFIG would just be 'xmlrpc-c-config'. It would be +# found in the user's PATH. +XMLRPC_C_CONFIG = $(BUILDDIR)/xmlrpc-c-config.test + + +SERVERPROGS_ABYSS = \ + xmlrpc_inetd_server \ + xmlrpc_loop_server \ + xmlrpc_sample_add_server \ + +LEGACY_CLIENTPROGS = \ + meerkat-app-list + +CLIENTPROGS = \ + xmlrpc_sample_add_client \ + sample_add_client_complex \ + +# Build up PROGS: +PROGS = + +ifeq ($(ENABLE_ABYSS_SERVER),yes) + PROGS += $(SERVERPROGS_ABYSS) +endif + +ifeq ($(MUST_BUILD_CLIENT),yes) + PROGS += $(CLIENTPROGS) $(LEGACY_CLIENTPROGS) +endif + +INCLUDES = $(shell $(XMLRPC_C_CONFIG) c++2 client abyss-server --cflags) + +LDADD_SERVER_ABYSS = \ + $(shell $(XMLRPC_C_CONFIG) c++2 abyss-server --ldadd) + +LDADD_CLIENT = \ + $(shell $(XMLRPC_C_CONFIG) c++2 client --ldadd) + +LDADD_BASE = \ + $(shell $(XMLRPC_C_CONFIG) c++2 --ldadd) + +LDADD_LEGACY_CLIENT = \ + $(shell $(XMLRPC_C_CONFIG) c++ client --ldadd) + +all: $(PROGS) + +$(SERVERPROGS_ABYSS):%:%.o + $(CXXLD) -o $@ $(LDFLAGS) $^ $(LDADD_SERVER_ABYSS) + +$(LEGACY_CLIENTPROGS):%:%.o + $(CXXLD) -o $@ $(LDFLAGS) $^ $(LDADD_LEGACY_CLIENT) + +$(CLIENTPROGS):%:%.o + $(CXXLD) -o $@ $(LDFLAGS) $^ $(LDADD_CLIENT) + +%.o:%.cpp + $(CXX) -c $(INCLUDES) $(CXXFLAGS) $< + +*.c: config.h xmlrpc_amconfig.h + +config.h: + $(LN_S) $(BUILDDIR)/xmlrpc_config.h $@ +xmlrpc_amconfig.h: + $(LN_S) $(BUILDDIR)/$@ . + +include $(SRCDIR)/Makefile.common + +.PHONY: clean +clean: clean-common + rm -f $(PROGS) config.h xmlrpc_amconfig.h + +.PHONY: distclean +distclean: clean + +.PHONY: dep depend +dep depend: +# We don't do dependencies in this directory, because it's supposed to be +# an example of what a program outside this package would do, so we can't +# go weaving it into the rest of the package. Ergo, a developer must +# carefully clean and remake examples as he updates other parts of the tree. diff --git a/examples/cpp/meerkat-app-list.cpp b/examples/cpp/meerkat-app-list.cpp new file mode 100644 index 0000000..69f0f8d --- /dev/null +++ b/examples/cpp/meerkat-app-list.cpp @@ -0,0 +1,106 @@ +// List recently-released Linux applications. (Written in C++.) +// For more details about O'Reilly's excellent Meerkat news service, see: +// http://www.oreillynet.com/pub/a/rss/2000/11/14/meerkat_xmlrpc.html */ + +#include +#include +#include + +using namespace std; + +#include + +#define NAME "XML-RPC C++ Meerkat Query Demo" +#define VERSION "0.1" +#define MEERKAT_URL "http://www.oreillynet.com/meerkat/xml-rpc/server.php" +#define SOFTWARE_LINUX (6) + +static void +list_apps(unsigned int const hours) { + + // Build our time_period parameter. + ostringstream time_period_stream; + time_period_stream << hours << "HOUR"; + string const time_period(time_period_stream.str()); + + // Assemble our meerkat query recipe. + XmlRpcValue recipe = XmlRpcValue::makeStruct(); + recipe.structSetValue("category", XmlRpcValue::makeInt(SOFTWARE_LINUX)); + recipe.structSetValue("time_period", XmlRpcValue::makeString(time_period)); + recipe.structSetValue("descriptions", XmlRpcValue::makeInt(76)); + + // Build our parameter array. + XmlRpcValue param_array(XmlRpcValue::makeArray()); + param_array.arrayAppendItem(recipe); + + // Create a client pointing to Meerkat. + XmlRpcClient meerkat(MEERKAT_URL); + + // Perform the query. + XmlRpcValue const apps(meerkat.call("meerkat.getItems", param_array)); + + // Print our results. + size_t const app_count(apps.arraySize()); + bool first; + size_t i; + for (i = 0, first=false; i < app_count; ++i, first = false) { + XmlRpcValue const app(apps.arrayGetItem(i)); + + // Get some information about our application. + string const title(app.structGetValue("title").getString()); + string const link(app.structGetValue("link").getString()); + string const description( + app.structGetValue("description").getString()); + + // Print a separator line if necessary. + if (!first) + cout << endl; + + // Print this application entry. + if (description.size() > 0) + cout << title << endl << description << endl << link << endl; + else + cout << title << endl << description << endl << link << endl; + } +} + + + +int +main(int argc, char **argv) { + int retval; + unsigned int hours; + + // Parse our command-line arguments. + if (argc == 1) { + hours = 25; + } else if (argc == 2) { + hours = atoi(argv[1]); + } + if (hours == 0) { + cerr << "Hours must be positive" << endl; + exit(1); + } + if (hours > 49) { + cerr << "It's not nice to ask for > 49 hours at once." << endl; + exit(1); + } + + // Start up our client library. + XmlRpcClient::Initialize(NAME, VERSION); + + // Call our implementation, and watch out for faults. + try { + list_apps(hours); + retval = 0; + } catch (XmlRpcFault& fault) { + cerr << argv[0] << ": XML-RPC fault #" << fault.getFaultCode() + << ": " << fault.getFaultString() << endl; + retval = 1; + } + + // Shut down our client library. + XmlRpcClient::Terminate(); + + return retval; +} diff --git a/examples/cpp/sample_add_client_complex.cpp b/examples/cpp/sample_add_client_complex.cpp new file mode 100644 index 0000000..41cef39 --- /dev/null +++ b/examples/cpp/sample_add_client_complex.cpp @@ -0,0 +1,71 @@ +/*============================================================================= + sample_add_client_complex.cpp +=============================================================================== + This is an example of an XML-RPC client that uses XML-RPC for C/C++ + (Xmlrpc-c). + + In particular, it uses the complex lower-level interface that gives you + lots of flexibility but requires lots of code. Also see + xmlrpc_sample_add_server, which does the same thing as this program, + but with much simpler code because it uses a simpler facility of + Xmlrpc-c. + + This program actually gains nothing from using the more difficult + facility. It is for demonstration purposes. +=============================================================================*/ + +#include +#include +#include +#include +#include +#include +#include + +using namespace std; + +int +main(int argc, char **) { + + if (argc-1 > 0) { + cerr << "This program has no arguments" << endl; + exit(1); + } + + try { + xmlrpc_c::clientXmlTransport_curl myTransport( + xmlrpc_c::clientXmlTransport_curl::constrOpt() + .no_ssl_verifyhost(true) + .user_agent("sample_add/1.0")); + + xmlrpc_c::client_xml myClient(&myTransport); + + string const methodName("sample.add"); + + xmlrpc_c::paramList sampleAddParms; + sampleAddParms.add(xmlrpc_c::value_int(5)); + sampleAddParms.add(xmlrpc_c::value_int(7)); + + xmlrpc_c::rpcPtr myRpcP(methodName, sampleAddParms); + + string const serverUrl("http://localhost:8080/RPC2"); + + xmlrpc_c::carriageParm_curl0 myCarriageParm(serverUrl); + + myRpcP->call(&myClient, &myCarriageParm); + + assert(myRpcP->isFinished()); + + int const sum(xmlrpc_c::value_int(myRpcP->getResult())); + // Assume the method returned an integer; throws error if not + + cout << "Result of RPC (sum of 5 and 7): " << sum << endl; + + } catch (girerr::error const error) { + cerr << "Client threw error: " << error.what() << endl; + } catch (...) { + cerr << "Client threw unexpected error." << endl; + } + + return 0; +} diff --git a/examples/cpp/xmlrpc_inetd_server.cpp b/examples/cpp/xmlrpc_inetd_server.cpp new file mode 100644 index 0000000..fd97424 --- /dev/null +++ b/examples/cpp/xmlrpc_inetd_server.cpp @@ -0,0 +1,65 @@ +/* A simple standalone XML-RPC server based on Abyss that contains a + simple one-thread request processing loop. + + xmlrpc_sample_add_server.cpp is a server that does the same thing, but + does it by running a full Abyss daemon in the background, so it has + less control over how the requests are served. +*/ + +#ifndef WIN32 +#include +#endif +#include + +#include +#include +#include + +using namespace std; + +class sampleAddMethod : public xmlrpc_c::method { +public: + sampleAddMethod() { + // signature and help strings are documentation -- the client + // can query this information with a system.methodSignature and + // system.methodHelp RPC. + this->_signature = "ii"; // method's arguments are two integers + this->_help = "This method adds two integers together"; + } + void + execute(xmlrpc_c::paramList const& paramList, + xmlrpc_c::value * const retvalP) { + + int const addend(paramList.getInt(0)); + int const adder(paramList.getInt(1)); + + paramList.verifyEnd(2); + + *retvalP = xmlrpc_c::value_int(addend + adder); + } +}; + + + +int +main(int const, + const char ** const) { + + xmlrpc_c::registry myRegistry; + + xmlrpc_c::methodPtr const sampleAddMethodP(new sampleAddMethod); + + myRegistry.addMethod("sample.add", sampleAddMethodP); + + xmlrpc_c::serverAbyss myAbyssServer( + myRegistry, + 8080, // TCP port on which to listen + "/tmp/xmlrpc_log" // Log file + ); + + myAbyssServer.runConn(STDIN_FILENO); + /* This reads the HTTP POST request from Standard Input and + executes the indicated RPC. + */ + return 0; +} diff --git a/examples/cpp/xmlrpc_loop_server.cpp b/examples/cpp/xmlrpc_loop_server.cpp new file mode 100644 index 0000000..6cc4293 --- /dev/null +++ b/examples/cpp/xmlrpc_loop_server.cpp @@ -0,0 +1,68 @@ +/* A simple standalone XML-RPC server based on Abyss that contains a + simple one-thread request processing loop. + + xmlrpc_sample_add_server.cpp is a server that does the same thing, but + does it by running a full Abyss daemon in the background, so it has + less control over how the requests are served. +*/ + +#include +#include + +#include +#include +#include + +using namespace std; + +class sampleAddMethod : public xmlrpc_c::method { +public: + sampleAddMethod() { + // signature and help strings are documentation -- the client + // can query this information with a system.methodSignature and + // system.methodHelp RPC. + this->_signature = "i:ii"; // method's arguments are two integers + this->_help = "This method adds two integers together"; + } + void + execute(xmlrpc_c::paramList const& paramList, + xmlrpc_c::value * const retvalP) { + + int const addend(paramList.getInt(0)); + int const adder(paramList.getInt(1)); + + paramList.verifyEnd(2); + + *retvalP = xmlrpc_c::value_int(addend + adder); + } +}; + + + +int +main(int const, + const char ** const) { + + xmlrpc_c::registry myRegistry; + + xmlrpc_c::methodPtr const sampleAddMethodP(new sampleAddMethod); + + myRegistry.addMethod("sample.add", sampleAddMethodP); + + xmlrpc_c::serverAbyss myAbyssServer( + myRegistry, + 8080, // TCP port on which to listen + "/tmp/xmlrpc_log" // Log file + ); + + while (true) { + cout << "Waiting for next RPC..." << endl; + + myAbyssServer.runOnce(); + /* This waits for the next connection, accepts it, reads the + HTTP POST request, executes the indicated RPC, and closes + the connection. + */ + } + return 0; +} diff --git a/examples/cpp/xmlrpc_sample_add_client.cpp b/examples/cpp/xmlrpc_sample_add_client.cpp new file mode 100644 index 0000000..00699b1 --- /dev/null +++ b/examples/cpp/xmlrpc_sample_add_client.cpp @@ -0,0 +1,39 @@ +#include +#include +#include +#include +#include +#include + +using namespace std; + +int +main(int argc, char **) { + + if (argc-1 > 0) { + cerr << "This program has no arguments" << endl; + exit(1); + } + + try { + string const serverUrl("http://localhost:8080/RPC2"); + string const methodName("sample.add"); + + xmlrpc_c::clientSimple myClient; + xmlrpc_c::value result; + + myClient.call(serverUrl, methodName, "ii", &result, 5, 7); + + int const sum = xmlrpc_c::value_int(result); + // Assume the method returned an integer; throws error if not + + cout << "Result of RPC (sum of 5 and 7): " << sum << endl; + + } catch (girerr::error const error) { + cerr << "Client threw error: " << error.what() << endl; + } catch (...) { + cerr << "Client threw unexpected error." << endl; + } + + return 0; +} diff --git a/examples/cpp/xmlrpc_sample_add_server.cpp b/examples/cpp/xmlrpc_sample_add_server.cpp new file mode 100644 index 0000000..9658f6d --- /dev/null +++ b/examples/cpp/xmlrpc_sample_add_server.cpp @@ -0,0 +1,60 @@ +#include +#include +#include + +#include +#include +#include + +using namespace std; + +class sampleAddMethod : public xmlrpc_c::method { +public: + sampleAddMethod() { + // signature and help strings are documentation -- the client + // can query this information with a system.methodSignature and + // system.methodHelp RPC. + this->_signature = "i:ii"; + // method's result and two arguments are integers + this->_help = "This method adds two integers together"; + } + void + execute(xmlrpc_c::paramList const& paramList, + xmlrpc_c::value * const retvalP) { + + int const addend(paramList.getInt(0)); + int const adder(paramList.getInt(1)); + + paramList.verifyEnd(2); + + *retvalP = xmlrpc_c::value_int(addend + adder); + } +}; + + + +int +main(int const, + const char ** const) { + + try { + xmlrpc_c::registry myRegistry; + + xmlrpc_c::methodPtr const sampleAddMethodP(new sampleAddMethod); + + myRegistry.addMethod("sample.add", sampleAddMethodP); + + xmlrpc_c::serverAbyss myAbyssServer( + myRegistry, + 8080, // TCP port on which to listen + "/tmp/xmlrpc_log" // Log file + ); + + myAbyssServer.run(); + // xmlrpc_c::serverAbyss.run() never returns + assert(false); + } catch (exception const& e) { + cerr << "Something failed. " << e.what() << endl; + } + return 0; +} diff --git a/examples/gen_sample_add_xml.c b/examples/gen_sample_add_xml.c new file mode 100644 index 0000000..724f814 --- /dev/null +++ b/examples/gen_sample_add_xml.c @@ -0,0 +1,73 @@ +/* This program generates on Standard Output the XML for an XML-RPC + call suitable for the xmlrpc_sample_add_server program. + + This is the same XML that the xmlrpc_sample_add_client program sends. + + Use this either as an example of how to use the Xmlrpc-c XML-generating + functions or to generate XML that you can use to test an XML-RPC + server. +*/ + +#include +#include + +#include + +#include "config.h" + +static void +die_if_fault_occurred (xmlrpc_env *env) { + if (env->fault_occurred) { + fprintf(stderr, "XML-RPC Fault: %s (%d)\n", + env->fault_string, env->fault_code); + exit(1); + } +} + + + +int +main(int const argc, + const char ** const argv ATTR_UNUSED) { + + char * const methodName = "sample.add"; + + xmlrpc_env env; + xmlrpc_value * params; + xmlrpc_mem_block * xmlmemblockP; + + if (argc-1 > 0) { + fprintf(stderr, "This program has no arguments\n"); + exit(1); + } + + /* Initialize our error-handling environment. */ + xmlrpc_env_init(&env); + + params = xmlrpc_build_value(&env, "(ii)", + (xmlrpc_int32) 5, (xmlrpc_int32) 7); + + die_if_fault_occurred(&env); + + xmlmemblockP = XMLRPC_MEMBLOCK_NEW(char, &env, 0); + + xmlrpc_serialize_call(&env, xmlmemblockP, methodName, params); + + die_if_fault_occurred(&env); + + fwrite(XMLRPC_MEMBLOCK_CONTENTS(char, xmlmemblockP), + sizeof(char), + XMLRPC_MEMBLOCK_SIZE(char, xmlmemblockP), + stdout); + + XMLRPC_MEMBLOCK_FREE(char, xmlmemblockP); + + /* Dispose of our parameter array. */ + xmlrpc_DECREF(params); + + /* Clean up our error-handling environment. */ + xmlrpc_env_clean(&env); + + return 0; +} + diff --git a/examples/query-meerkat.c b/examples/query-meerkat.c new file mode 100644 index 0000000..e566654 --- /dev/null +++ b/examples/query-meerkat.c @@ -0,0 +1,156 @@ +/* A simple news-searcher, written in C to demonstrate how to use the + xmplrpc-c client library. + + This program connects to an XMLRPC server that O'Reilly runs on the + Internet, gets some information, and displays it on Standard Output. + + Note that that server is not in any way designed specifically for xmlrpc-c. + It simply implements the XMLRPC protocol, and works with any client that + implements XMLRPC. + + The service that the aforementioned server provides is that it gives you + a list of news articles that match a certain regular expression. You give + that regular expression an argument to this client program. + + For more details about O'Reilly's excellent Meerkat news service, see: + http://www.oreillynet.com/pub/a/rss/2000/11/14/meerkat_xmlrpc.html +*/ + +#include +#include +#include + +#include +#include + +#include "config.h" /* information about this build environment */ + +#define NAME "XML-RPC C Meerkat Query Demo" +#define VERSION "1.0" +#define MEERKAT_URL "http://www.oreillynet.com/meerkat/xml-rpc/server.php" + +struct cmdline { + const char * searchArg; + int hours; +}; + + +static void +parseCommandLine(int const argc, + const char ** const argv, + struct cmdline * const cmdlineP) { + + if (argc-1 < 1) { + fprintf(stderr, "Need at least one argument: " + "A mysql regular expression " + "search pattern. Try 'query-meerkat Linux'\n"); + exit(1); + } else { + cmdlineP->searchArg = argv[1]; + + if (argc-1 < 2) { + cmdlineP->hours = 24; + } else { + cmdlineP->hours = atoi(argv[2]); + if (cmdlineP->hours > 49) { + fprintf(stderr, "It's not nice to ask for > 49 hours " + "at once.\n"); + exit(1); + } + if (argc-1 > 2) { + fprintf(stderr, "There are at most 2 arguments: " + "search pattern " + "and number of hours."); + exit(1); + } + } + } +} + + + +static void +die_if_fault_occurred(xmlrpc_env * const env) { + /* We're a command-line utility, so we abort if an error occurs. */ + if (env->fault_occurred) { + fprintf(stderr, "XML-RPC Fault #%d: %s\n", + env->fault_code, env->fault_string); + exit(1); + } +} + + + +/* Hey! We fit in one function. */ +int +main(int const argc, + const char** const argv) { + + struct cmdline cmdline; + char time_period[16]; + xmlrpc_env env; + xmlrpc_value *stories, *story; + size_t size, i; + int first; + + parseCommandLine(argc, argv, &cmdline); + + snprintf(time_period, sizeof(time_period), "%dHOUR", cmdline.hours); + + xmlrpc_env_init(&env); + + /* Set up our client. */ + xmlrpc_client_init2(&env, XMLRPC_CLIENT_NO_FLAGS, NAME, VERSION, NULL, 0); + + die_if_fault_occurred(&env); + + /* Ask Meerkat to look for matching stories. */ + stories = xmlrpc_client_call(&env, MEERKAT_URL, + "meerkat.getItems", "({s:s,s:i,s:s})", + "search", cmdline.searchArg, + "descriptions", (xmlrpc_int32) 76, + "time_period", time_period); + die_if_fault_occurred(&env); + + /* Loop over the stories. */ + size = xmlrpc_array_size(&env, stories); + die_if_fault_occurred(&env); + first = 1; + for (i = 0; i < size; i++) { + const char * title; + const char * link; + const char * description; + + /* Extract the useful information from our story. */ + story = xmlrpc_array_get_item(&env, stories, i); + die_if_fault_occurred(&env); + xmlrpc_decompose_value(&env, story, "{s:s,s:s,s:s,*}", + "title", &title, + "link", &link, + "description", &description); + die_if_fault_occurred(&env); + + /* Print a separator line if necessary. */ + if (first) + first = 0; + else + printf("\n"); + + /* Print the story. */ + if (strlen(description) > 0) { + printf("%s\n%s\n%s\n", title, description, link); + } else { + printf("%s\n%s\n", title, link); + } + free((char*)title); + free((char*)link); + free((char*)description); + } + + /* Shut down our client. */ + xmlrpc_DECREF(stories); + xmlrpc_env_clean(&env); + xmlrpc_client_cleanup(); + + return 0; +} diff --git a/examples/synch_client.c b/examples/synch_client.c new file mode 100644 index 0000000..bf6889a --- /dev/null +++ b/examples/synch_client.c @@ -0,0 +1,66 @@ +/* A simple synchronous XML-RPC client written in C. */ + +#include +#include + +#include +#include + +#include "config.h" /* information about this build environment */ + +#define NAME "XML-RPC C Test Client synch_client" +#define VERSION "1.0" + +static void die_if_fault_occurred (xmlrpc_env *env) +{ + if (env->fault_occurred) { + fprintf(stderr, "XML-RPC Fault: %s (%d)\n", + env->fault_string, env->fault_code); + exit(1); + } +} + + + +int +main(int const argc, + const char ** const argv ATTR_UNUSED) { + + xmlrpc_env env; + xmlrpc_value * resultP; + const char * state_name; + + if (argc-1 > 0) { + fprintf(stderr, "No arguments"); + exit(0); + } + + /* Start up our XML-RPC client library. */ + xmlrpc_client_init(XMLRPC_CLIENT_NO_FLAGS, NAME, VERSION); + + /* Initialize our error-handling environment. */ + xmlrpc_env_init(&env); + + /* Call the famous server at UserLand. */ + resultP = xmlrpc_client_call(&env, "http://betty.userland.com/RPC2", + "examples.getStateName", + "(i)", (xmlrpc_int32) 41); + die_if_fault_occurred(&env); + + /* Get our state name and print it out. */ + xmlrpc_read_string(&env, resultP, &state_name); + die_if_fault_occurred(&env); + printf("%s\n", state_name); + free((char*)state_name); + + /* Dispose of our result value. */ + xmlrpc_DECREF(resultP); + + /* Clean up our error-handling environment. */ + xmlrpc_env_clean(&env); + + /* Shutdown our XML-RPC client library. */ + xmlrpc_client_cleanup(); + + return 0; +} diff --git a/examples/xmlrpc_asynch_client.c b/examples/xmlrpc_asynch_client.c new file mode 100644 index 0000000..ae812e1 --- /dev/null +++ b/examples/xmlrpc_asynch_client.c @@ -0,0 +1,122 @@ +/* A simple asynchronous XML-RPC client written in C, as an example of + Xmlrpc-c asynchronous RPC facilities. This is the same as the + simpler synchronous client xmlprc_sample_add_client.c, except that + it adds 3 different pairs of numbers with the summation RPCs going on + simultaneously. + + Use this with xmlrpc_sample_add_server. Note that that server + intentionally takes extra time to add 1 to anything, so you can see + our 5+1 RPC finish after our 5+0 and 5+2 RPCs. +*/ + +#include +#include + +#include +#include + +#include "config.h" /* information about this build environment */ + +#define NAME "Xmlrpc-c Asynchronous Test Client" +#define VERSION "1.0" + +static void +die_if_fault_occurred (xmlrpc_env * const envP) { + if (envP->fault_occurred) { + fprintf(stderr, "Something failed. %s (XML-RPC fault code %d)\n", + envP->fault_string, envP->fault_code); + exit(1); + } +} + + + +static void +handle_sample_add_response(const char * const server_url, + const char * const method_name, + xmlrpc_value * const param_array, + void * const user_data ATTR_UNUSED, + xmlrpc_env * const faultP, + xmlrpc_value * const resultP) { + + xmlrpc_env env; + xmlrpc_int addend, adder; + + /* Initialize our error environment variable */ + xmlrpc_env_init(&env); + + /* Our first four arguments provide helpful context. Let's grab the + addends from our parameter array. + */ + xmlrpc_decompose_value(&env, param_array, "(ii)", &addend, &adder); + die_if_fault_occurred(&env); + + printf("RPC with method '%s' at URL '%s' to add %d and %d " + "has completed\n", method_name, server_url, addend, adder); + + if (faultP->fault_occurred) + printf("The RPC failed. %s", faultP->fault_string); + else { + xmlrpc_int sum; + + xmlrpc_read_int(&env, resultP, &sum); + die_if_fault_occurred(&env); + + printf("The sum is %d\n", sum); + } +} + + + +int +main(int const argc, + const char ** const argv ATTR_UNUSED) { + + char * const serverUrl = "http://localhost:8080/RPC2"; + char * const methodName = "sample.add"; + + xmlrpc_env env; + xmlrpc_client * clientP; + xmlrpc_int adder; + + if (argc-1 > 0) { + fprintf(stderr, "This program has no arguments\n"); + exit(1); + } + + /* Initialize our error environment variable */ + xmlrpc_env_init(&env); + + /* Required before any use of Xmlrpc-c client library: */ + xmlrpc_client_setup_global_const(&env); + die_if_fault_occurred(&env); + + xmlrpc_client_create(&env, XMLRPC_CLIENT_NO_FLAGS, NAME, VERSION, NULL, 0, + &clientP); + die_if_fault_occurred(&env); + + for (adder = 0; adder < 3; ++adder) { + printf("Making XMLRPC call to server url '%s' method '%s' " + "to request the sum " + "of 5 and %d...\n", serverUrl, methodName, adder); + + /* request the remote procedure call */ + xmlrpc_client_start_rpcf(&env, clientP, serverUrl, methodName, + handle_sample_add_response, NULL, + "(ii)", (xmlrpc_int32) 5, adder); + die_if_fault_occurred(&env); + } + + printf("RPCs all requested. Waiting for & handling responses...\n"); + + /* Wait for all RPCs to be done. With some transports, this is also + what causes them to go. + */ + xmlrpc_client_event_loop_finish(clientP); + + printf("All RPCs finished.\n"); + + xmlrpc_client_destroy(clientP); + + return 0; +} diff --git a/examples/xmlrpc_inetd_server.c b/examples/xmlrpc_inetd_server.c new file mode 100644 index 0000000..fd7b7df --- /dev/null +++ b/examples/xmlrpc_inetd_server.c @@ -0,0 +1,106 @@ +/* A simple standalone XML-RPC server based on Abyss that processes a + single RPC from an existing TCP connection on Standard Input. + + A typical example of where this would be useful is with an Inetd + "super server." + + xmlrpc_sample_add_server.c is a server that does the same thing, + but you give it a TCP port number and it listens for TCP connecitons + and processes RPCs ad infinitum. +*/ + +#include +#include +#include +#ifndef WIN32 +#include +#endif + +#include +#include +#include +#include + +#include "config.h" /* information about this build environment */ + + +static void +setupSignalHandlers(void) { + + /* In UNIX, when you try to write to a socket that has been closed + from the other end, your write fails, but you also get a SIGPIPE + signal. That signal will kill you before you even have a chance + to see the write fail unless you catch, block, or ignore it. + If a client should connect to us and then disconnect before we've + sent our response, we see this socket-closed behavior. We + obviously don't want to die just because a client didn't complete + an RPC, so we ignore SIGPIPE. + */ + struct sigaction mysigaction; + + sigemptyset(&mysigaction.sa_mask); + mysigaction.sa_flags = 0; + mysigaction.sa_handler = SIG_IGN; + sigaction(SIGPIPE, &mysigaction, NULL); +} + + + +static xmlrpc_value * +sample_add(xmlrpc_env * const envP, + xmlrpc_value * const paramArrayP, + void * const userData ATTR_UNUSED) { + + xmlrpc_int x, y, z; + + /* Parse our argument array. */ + xmlrpc_decompose_value(envP, paramArrayP, "(ii)", &x, &y); + if (envP->fault_occurred) + return NULL; + + /* Add our two numbers. */ + z = x + y; + + /* Return our result. */ + return xmlrpc_build_value(envP, "i", z); +} + + + +int +main(int const argc, + const char ** const argv) { + + TServer abyssServer; + xmlrpc_registry * registryP; + xmlrpc_env env; + + if (argc-1 != 0) { + fprintf(stderr, "There are no arguments. You must supply a " + "bound socket on which to listen for client connections " + "as Standard Input\n"); + if (argv) {} /* silence unused parameter warning */ + exit(1); + } + xmlrpc_env_init(&env); + + registryP = xmlrpc_registry_new(&env); + + xmlrpc_registry_add_method( + &env, registryP, NULL, "sample.add", &sample_add, NULL); + + ServerCreateNoAccept(&abyssServer, "XmlRpcServer", NULL, NULL); + + xmlrpc_server_abyss_set_handlers(&abyssServer, registryP); + + setupSignalHandlers(); + + ServerRunConn(&abyssServer, STDIN_FILENO); + /* This reads the HTTP POST request from Standard Input and + executes the indicated RPC. + */ + + ServerFree(&abyssServer); + + return 0; +} diff --git a/examples/xmlrpc_loop_server.c b/examples/xmlrpc_loop_server.c new file mode 100644 index 0000000..239d59b --- /dev/null +++ b/examples/xmlrpc_loop_server.c @@ -0,0 +1,134 @@ +/* A simple standalone XML-RPC server based on Abyss that contains a + simple one-thread request processing loop. + + xmlrpc_sample_add_server.c is a server that does the same thing, but + does it by running a full Abyss daemon in the background, so it has + less control over how the requests are served. +*/ + +#include +#include +#include +#include +#include +#include +#include + +#include "config.h" /* information about this build environment */ + + +static void +setupSignalHandlers(void) { + + /* In UNIX, when you try to write to a socket that has been closed + from the other end, your write fails, but you also get a SIGPIPE + signal. That signal will kill you before you even have a chance + to see the write fail unless you catch, block, or ignore it. + If a client should connect to us and then disconnect before we've + sent our response, we see this socket-closed behavior. We + obviously don't want to die just because a client didn't complete + an RPC, so we ignore SIGPIPE. + */ + struct sigaction mysigaction; + + sigemptyset(&mysigaction.sa_mask); + mysigaction.sa_flags = 0; + mysigaction.sa_handler = SIG_IGN; + sigaction(SIGPIPE, &mysigaction, NULL); +} + + + +static xmlrpc_value * +sample_add(xmlrpc_env * const envP, + xmlrpc_value * const paramArrayP, + void * const userData ATTR_UNUSED) { + + xmlrpc_int x, y, z; + + /* Parse our argument array. */ + xmlrpc_decompose_value(envP, paramArrayP, "(ii)", &x, &y); + if (envP->fault_occurred) + return NULL; + + /* Add our two numbers. */ + z = x + y; + + /* Return our result. */ + return xmlrpc_build_value(envP, "i", z); +} + + + +static xmlrpc_server_shutdown_fn requestShutdown; + +static void +requestShutdown(xmlrpc_env * const envP, + void * const context, + const char * const comment) { + + /* You make this run by executing the system method + 'system.shutdown'. This function is registered in the method + registry as the thing to call for that. + */ + int * const terminationRequestedP = context; + + xmlrpc_env_init(envP); + + fprintf(stderr, "Termination requested: %s\n", comment); + + *terminationRequestedP = 1; +} + + + +int +main(int const argc, + const char ** const argv) { + + TServer abyssServer; + xmlrpc_registry * registryP; + xmlrpc_env env; + int terminationRequested; /* A boolean value */ + + if (argc-1 != 1) { + fprintf(stderr, "You must specify 1 argument: The TCP port number " + "on which to listen for XML-RPC calls. " + "You specified %d.\n", argc-1); + exit(1); + } + + xmlrpc_env_init(&env); + + registryP = xmlrpc_registry_new(&env); + + xmlrpc_registry_add_method( + &env, registryP, NULL, "sample.add", &sample_add, NULL); + + xmlrpc_registry_set_shutdown(registryP, + &requestShutdown, &terminationRequested); + + ServerCreate(&abyssServer, "XmlRpcServer", atoi(argv[1]), NULL, NULL); + + xmlrpc_server_abyss_set_handlers(&abyssServer, registryP); + + ServerInit(&abyssServer); + + setupSignalHandlers(); + + terminationRequested = 0; + + while (!terminationRequested) { + printf("Waiting for next RPC...\n"); + + ServerRunOnce(&abyssServer); + /* This waits for the next connection, accepts it, reads the + HTTP POST request, executes the indicated RPC, and closes + the connection. + */ + } + + ServerFree(&abyssServer); + + return 0; +} diff --git a/examples/xmlrpc_sample_add_client.c b/examples/xmlrpc_sample_add_client.c new file mode 100644 index 0000000..100d8fc --- /dev/null +++ b/examples/xmlrpc_sample_add_client.c @@ -0,0 +1,76 @@ +/* A simple synchronous XML-RPC client written in C, as an example of + an Xmlrpc-c client. This invokes the sample.add procedure that the + Xmlrpc-c example server.c server provides. I.e. it adds to numbers + together, the hard way. +*/ + +#include +#include + +#include +#include + +#include "config.h" /* information about this build environment */ + +#define NAME "Xmlrpc-c Test Client" +#define VERSION "1.0" + +static void +die_if_fault_occurred (xmlrpc_env *env) { + if (env->fault_occurred) { + fprintf(stderr, "XML-RPC Fault: %s (%d)\n", + env->fault_string, env->fault_code); + exit(1); + } +} + + + +int +main(int const argc, + const char ** const argv ATTR_UNUSED) { + + xmlrpc_env env; + xmlrpc_value *result; + xmlrpc_int32 sum; + char * const serverUrl = "http://localhost:8080/RPC2"; + char * const methodName = "sample.add"; + + if (argc-1 > 0) { + fprintf(stderr, "This program has no arguments\n"); + exit(1); + } + + /* Initialize our error-handling environment. */ + xmlrpc_env_init(&env); + + /* Start up our XML-RPC client library. */ + xmlrpc_client_init2(&env, XMLRPC_CLIENT_NO_FLAGS, NAME, VERSION, NULL, 0); + die_if_fault_occurred(&env); + + printf("Making XMLRPC call to server url '%s' method '%s' " + "to request the sum " + "of 5 and 7...\n", serverUrl, methodName); + + /* Make the remote procedure call */ + result = xmlrpc_client_call(&env, serverUrl, methodName, + "(ii)", (xmlrpc_int32) 5, (xmlrpc_int32) 7); + die_if_fault_occurred(&env); + + /* Get our sum and print it out. */ + xmlrpc_read_int(&env, result, &sum); + die_if_fault_occurred(&env); + printf("The sum is %d\n", sum); + + /* Dispose of our result value. */ + xmlrpc_DECREF(result); + + /* Clean up our error-handling environment. */ + xmlrpc_env_clean(&env); + + /* Shutdown our XML-RPC client library. */ + xmlrpc_client_cleanup(); + + return 0; +} + diff --git a/examples/xmlrpc_sample_add_server.c b/examples/xmlrpc_sample_add_server.c new file mode 100644 index 0000000..3dde122 --- /dev/null +++ b/examples/xmlrpc_sample_add_server.c @@ -0,0 +1,80 @@ +/* A simple standalone XML-RPC server written in C. */ + +#include +#include +#ifndef WIN32 +#include +#endif + +#include +#include +#include + +#include "config.h" /* information about this build environment */ + +static xmlrpc_value * +sample_add(xmlrpc_env * const env, + xmlrpc_value * const param_array, + void * const user_data ATTR_UNUSED) { + + xmlrpc_int32 x, y, z; + + /* Parse our argument array. */ + xmlrpc_decompose_value(env, param_array, "(ii)", &x, &y); + if (env->fault_occurred) + return NULL; + + /* Add our two numbers. */ + z = x + y; + + /* Sometimes, make it look hard (so client can see what it's like + to do an RPC that takes a while). + */ + if (y == 1) + sleep(2); + + /* Return our result. */ + return xmlrpc_build_value(env, "i", z); +} + + + +int +main(int const argc, + const char ** const argv) { + + xmlrpc_server_abyss_parms serverparm; + xmlrpc_registry * registryP; + xmlrpc_env env; + + if (argc-1 != 1) { + fprintf(stderr, "You must specify 1 argument: The TCP port " + "number on which the server will accept connections " + "for RPCs. You specified %d arguments.\n", argc-1); + exit(1); + } + + xmlrpc_env_init(&env); + + registryP = xmlrpc_registry_new(&env); + + xmlrpc_registry_add_method( + &env, registryP, NULL, "sample.add", &sample_add, NULL); + + /* In the modern form of the Abyss API, we supply parameters in memory + like a normal API. We select the modern form by setting + config_file_name to NULL: + */ + serverparm.config_file_name = NULL; + serverparm.registryP = registryP; + serverparm.port_number = atoi(argv[1]); + serverparm.log_file_name = "/tmp/xmlrpc_log"; + + printf("Running XML-RPC server...\n"); + + xmlrpc_server_abyss(&env, &serverparm, XMLRPC_APSIZE(log_file_name)); + + /* xmlrpc_server_abyss() never returns */ + + return 0; +} diff --git a/examples/xmlrpc_sample_add_server_cgi.c b/examples/xmlrpc_sample_add_server_cgi.c new file mode 100644 index 0000000..18374a1 --- /dev/null +++ b/examples/xmlrpc_sample_add_server_cgi.c @@ -0,0 +1,57 @@ +/* A simple standalone XML-RPC server written in C. */ + +#include +#include + +#include +#include +#include + +#include "config.h" /* information about this build environment */ + +static xmlrpc_value * +sample_add(xmlrpc_env * const env, + xmlrpc_value * const param_array, + void * const user_data ATTR_UNUSED) { + + xmlrpc_int32 x, y, z; + + /* Parse our argument array. */ + xmlrpc_decompose_value(env, param_array, "(ii)", &x, &y); + if (env->fault_occurred) + return NULL; + + /* Add our two numbers. */ + z = x + y; + + /* Return our result. */ + return xmlrpc_build_value(env, "i", z); +} + + + +int +main(int const argc, + const char ** const argv) { + + xmlrpc_registry * registryP; + xmlrpc_env env; + + if (argc-1 > 0 && argv==argv) { + fprintf(stderr, "There are no arguments to a CGI script\n"); + exit(1); + } + + xmlrpc_env_init(&env); + + registryP = xmlrpc_registry_new(&env); + + xmlrpc_registry_add_method( + &env, registryP, NULL, "sample.add", &sample_add, NULL); + + xmlrpc_server_cgi_process_call(registryP); + + xmlrpc_registry_free(registryP); + + return 0; +} diff --git a/examples/xmlrpc_sample_add_server_w32httpsys.c b/examples/xmlrpc_sample_add_server_w32httpsys.c new file mode 100644 index 0000000..f794f19 --- /dev/null +++ b/examples/xmlrpc_sample_add_server_w32httpsys.c @@ -0,0 +1,190 @@ +/* Copyright (C) 2005 by Steven A. Bone, sbone@pobox.com. All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +** ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +** OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +** HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +** LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +** OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +** SUCH DAMAGE. */ + +/* COMPILATION NOTE: + Note that the Platform SDK headers and + link libraries for Windows XP SP2 or newer are required to compile + xmlrpc-c for this module. If you are not using this server, it is + safe to exclude the xmlrpc_server_w32httpsys.c file from the xmlrpc + project and these dependencies will not be required. You can get the + latest platform SDK at + http://www.microsoft.com/msdownload/platformsdk/sdkupdate/ + Be sure after installation to choose the program to "register the PSDK + directories with Visual Studio" so the newer headers are found. +*/ + +#include +#include +#include +#include +#include + + +/* SECURITY NOTE: Using HTTP Authorization + +The current implementation of HTTP Authorization in the win32httpsys +server only uses basic Authorization. This means the userid and password +is sent in clear-text over the network (Technically, it is Base64 encoded, +but this is essentially clear text). This method is not secure, as it +can be captured and decoded. The use of HTTP Basic Authorization with SSL +is considered much more secure. See the note below for configuring SSL +support. +*/ + + +/* +HOWTO: Configure SSL for the XMLRPC-C Server + +To use SSL you need an SSL certificate. For testing purposes, +it is possible to create a self-signed SSL certificate. To do so, +you must download the IIS 6.0 Resource Kit tools. The current +URL to get the download link is http://support.microsoft.com/kb/840671 +We will be using the SelfSSL version 1.0 from this toolkit for +this example. The other tool you will need is httpcfg.exe, which +can be compiled from the sources in the Windows XP SP2 (or newer) Platform SDK, +or downloaded as part of the Windows XP SP2 Support Tools at the following URL: +http://www.microsoft.com/downloads/details.aspx?FamilyID=49ae8576-9bb9-4126-9761-ba8011fabf38&displaylang=en +The last assumption is that this procedure is being done on the machine that is +hosting the XMLRPC-C server application. + +1) Make sure that IIS is installed, and you are running at least Windows XP SP2 +or Windows Server 2003. WARNING: This process will replace any existing IIS SSL +certificates currently installed. + +2) In a command prompt, navigate to the directory of the +IIS Support Tools where the selfssl program exists (usually +C:\Program Files\IIS Resources\SelfSSL). Assuming (as we are for this example) +that we are going to run on port 8443, use the following command line (see the +documentation for all the flags): + +selfssl /T /V:365 /P:8443 + +3) In the Control Panel, Administrative tools, run the Internet Information Services +program. Drill down to the Default Web Site. Right-click it and choose Properties. +On the "Web Site" tab, you will notice that the SSL port is now set to 8443. Change +it back to 443. On the Directory Security tab, pick "View Certificate". In the +"Details" tab, select the "Thumbprint" line. The edit box below the listbox will +display a series of hex numbers. Copy these to the clipboard and paste into notepad. +OK yourself out of the IIS program. + +4) Remove all the spaces in the hex string so you are left with a string with no spaces. +This is your SSL Thumbprint hash which you will need in the next step. + +5) At your command prompt, navigate to the support tools directory (or the location +where you built httpcfg.exe) - usually C:\Program Files\Support Tools. Run the following +command line, replacing both the brackets and text with your thumbprint hash from step 4 above: + +httpcfg.exe set ssl -i 0.0.0.0:8443 -h -g "{2bb50d9c-7f6a-4d6f-873d-5aee7fb43290}" -c "MY" -t "" -n "" + +6) You can check the setup by performing a "httpcfg.exe query ssl" if you wish. + +7) Modify the example server code below to use SSL. Set the xmlrpc_server_httpsys_parms.useSSL +to '1' and the xmlrpc_server_httpsys_parms.portNum to be '8443'. You can test the server by using +IE to browse to the URL https://127.0.0.1:8443/rpc2. An error 405 (Resource not allowed) is the +expected result if everything is working properly. + +NOTE: Testing clients with a 'test' or not real SSL certificate involves changing some of the default +code in the client samples, as by default the transports will fail if there are any issues with the +certificate. The WinInet transport as of 1.2 has a transport-specific setting to allow +invalid SSL certificates. See the libxmlrpc_client.html documentation for more details. + +NOTE: Failure to follow all the steps listed above correctly will result in no application +errors, event log messages, or HTTP.SYS log messages indicating failure or the cause. If +anyone can provide information on debugging SSL certificate issues in HTTP.SYS, please +submit to us! +*/ + + +static xmlrpc_value * +sample_add(xmlrpc_env * const env, + xmlrpc_value * const param_array, + void * const user_data ) { + + xmlrpc_int32 x, y, z; + + /* Parse our argument array. */ + xmlrpc_decompose_value(env, param_array, "(ii)", &x, &y); + if (env->fault_occurred) + return NULL; + + /* Add our two numbers. */ + z = x + y; + + /* Return our result. */ + return xmlrpc_build_value(env, "i", z); +} + +static void handleAuthorization( + xmlrpc_env * envP, + char * userid, + char * password) +{ + if (strcmp(userid,"jrandom")==0 && strcmp(password,"secret")==0) + return; + + xmlrpc_env_set_fault( envP, XMLRPC_REQUEST_REFUSED_ERROR, + "Username and/or password do not match."); +} + +int __cdecl wmain( int argc, wchar_t * argv[]) +{ + xmlrpc_server_httpsys_parms serverparm; + xmlrpc_registry * registryP; + xmlrpc_env env; + + xmlrpc_env_init(&env); + + registryP = xmlrpc_registry_new(&env); + + xmlrpc_registry_add_method( + &env, registryP, NULL, "sample.add", &sample_add, NULL); + + wprintf(L"Starting XML-RPC server...\n"); + + //Sets the port number we are listening on + serverparm.portNum=8080; + + //if this is set, we will use the authorization function + serverparm.authfn=NULL; + //serverparm.authfn=&handleAuthorization; + + //set the logging level and log file + serverparm.logLevel=2; + serverparm.logFile="C:\\httpsysserverlog.txt"; + + //set the use of SSL + serverparm.useSSL=0; + + serverparm.registryP = registryP; + + xmlrpc_server_httpsys(&env, &serverparm, XMLRPC_HSSIZE(authfn)); + + wprintf(L"Stopping XML-RPC server...\n"); + + xmlrpc_registry_free(registryP); + xmlrpc_env_clean(&env); + + return 0; +} diff --git a/examples/xmlrpc_server_validatee.c b/examples/xmlrpc_server_validatee.c new file mode 100644 index 0000000..6d55e5f --- /dev/null +++ b/examples/xmlrpc_server_validatee.c @@ -0,0 +1,402 @@ +/* Copyright (C) 2001 by First Peer, Inc. All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +** ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +** OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +** HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +** LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +** OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +** SUCH DAMAGE. */ + + +/*============================================================================ + xmlrpc_server_validatee +============================================================================== + + This program runs an XMLRPC server, using the Xmlrpc-c libraries. + + The server implements the methods that the Userland Validator1 test suite + invokes, which are supposed to exercise a broad range of XMLRPC server + function. + + Coments here used to say you could get information about Validator1 + from , but as of 2004.09.25, there's nothing + there (there's a web server, but it is not configured to serve that + particular URL). + +============================================================================*/ + +#include +#include +#include + +#include +#include +#include + +#include "config.h" /* information about this build environment */ + +#define RETURN_IF_FAULT(env) \ + do { \ + if ((env)->fault_occurred) \ + return NULL; \ + } while (0) + + +/*========================================================================= +** validator1.arrayOfStructsTest +**========================================================================= +*/ + +static xmlrpc_value * +array_of_structs(xmlrpc_env * const envP, + xmlrpc_value * const param_array, + void * const user_data ATTR_UNUSED) { + + xmlrpc_value * array; + xmlrpc_value * retval; + + xmlrpc_decompose_value(envP, param_array, "(A)", &array); + if (envP->fault_occurred) + retval = NULL; + else { + /* Add up all the struct elements named "curly". */ + size_t size; + size = xmlrpc_array_size(envP, array); + if (envP->fault_occurred) + retval = NULL; + else { + unsigned int sum; + unsigned int i; + sum = 0; + for (i = 0; i < size && !envP->fault_occurred; ++i) { + xmlrpc_value * strct; + strct = xmlrpc_array_get_item(envP, array, i); + if (!envP->fault_occurred) { + xmlrpc_int32 curly; + xmlrpc_decompose_value(envP, strct, "{s:i,*}", + "curly", &curly); + if (!envP->fault_occurred) + sum += curly; + } + } + xmlrpc_DECREF(array); + if (envP->fault_occurred) + retval = NULL; + else + retval = xmlrpc_build_value(envP, "i", sum); + } + } + return retval; +} + + +/*========================================================================= +** validator1.countTheEntities +**========================================================================= +*/ + +static xmlrpc_value * +count_entities(xmlrpc_env * const env, + xmlrpc_value * const param_array, + void * const user_data ATTR_UNUSED) { + const char *str; + size_t len, i; + xmlrpc_int32 left, right, amp, apos, quote; + + xmlrpc_decompose_value(env, param_array, "(s#)", &str, &len); + RETURN_IF_FAULT(env); + + left = right = amp = apos = quote = 0; + for (i = 0; i < len; i++) { + switch (str[i]) { + case '<': left++; break; + case '>': right++; break; + case '&': amp++; break; + case '\'': apos++; break; + case '\"': quote++; break; + default: break; + } + } + free((void*)str); + + return xmlrpc_build_value(env, "{s:i,s:i,s:i,s:i,s:i}", + "ctLeftAngleBrackets", left, + "ctRightAngleBrackets", right, + "ctAmpersands", amp, + "ctApostrophes", apos, + "ctQuotes", quote); +} + + + +/*========================================================================= +** validator1.easyStructTest +**========================================================================= +*/ + +static xmlrpc_value * +easy_struct(xmlrpc_env * const env, + xmlrpc_value * const param_array, + void * const user_data ATTR_UNUSED) { + + xmlrpc_int32 larry, moe, curly; + + /* Parse our argument array and get the stooges. */ + xmlrpc_decompose_value(env, param_array, "({s:i,s:i,s:i,*})", + "larry", &larry, + "moe", &moe, + "curly", &curly); + RETURN_IF_FAULT(env); + + /* Return our result. */ + return xmlrpc_build_value(env, "i", larry + moe + curly); +} + + +/*========================================================================= +** validator1.echoStructTest +**========================================================================= +*/ + +static xmlrpc_value * +echo_struct(xmlrpc_env * const env, + xmlrpc_value * const param_array, + void * const user_data ATTR_UNUSED) { + xmlrpc_value *s; + + /* Parse our argument array. */ + xmlrpc_decompose_value(env, param_array, "(S)", &s); + RETURN_IF_FAULT(env); + + return s; /* We transfer our reference on 's' to Caller */ +} + + +/*========================================================================= +** validator1.manyTypesTest +**========================================================================= +*/ + +static xmlrpc_value * +many_types(xmlrpc_env * const env ATTR_UNUSED, + xmlrpc_value * const param_array, + void * const user_data ATTR_UNUSED) { + + /* Create another reference to our argument array and return it as is. */ + xmlrpc_INCREF(param_array); + return param_array; +} + + +/*========================================================================= +** validator1.moderateSizeArrayCheck +**========================================================================= +*/ + +static void +concatenate(xmlrpc_env * const envP, + const char * const str1, + size_t const str1_len, + const char * const str2, + size_t const str2_len, + xmlrpc_value ** const resultP) { + + /* Concatenate the two strings. */ + + char * buffer; + + buffer = (char*) malloc(str1_len + str2_len); + if (!buffer) { + xmlrpc_env_set_fault(envP, 1, + "Couldn't allocate concatenated string"); + } else { + memcpy(buffer, str1, str1_len); + memcpy(&buffer[str1_len], str2, str2_len); + *resultP = xmlrpc_build_value(envP, "s#", + buffer, str1_len + str2_len); + free(buffer); + } +} + + + +static xmlrpc_value * +moderate_array(xmlrpc_env * const envP, + xmlrpc_value * const param_array, + void * const user_data ATTR_UNUSED) { + + xmlrpc_value * retval; + xmlrpc_value * arrayP; + + /* Parse our argument array. */ + xmlrpc_decompose_value(envP, param_array, "(A)", &arrayP); + if (!envP->fault_occurred) { + int const size = xmlrpc_array_size(envP, arrayP); + if (!envP->fault_occurred) { + /* Get our first string. */ + xmlrpc_value * const firstItemP = + xmlrpc_array_get_item(envP, arrayP, 0); + if (!envP->fault_occurred) { + const char * str1; + size_t str1_len; + xmlrpc_read_string_lp(envP, firstItemP, &str1_len, &str1); + if (!envP->fault_occurred) { + /* Get our last string. */ + xmlrpc_value * const lastItemP = + xmlrpc_array_get_item(envP, arrayP, size - 1); + if (!envP->fault_occurred) { + const char * str2; + size_t str2_len; + xmlrpc_read_string_lp(envP, lastItemP, + &str2_len, &str2); + if (!envP->fault_occurred) { + concatenate(envP, str1, str1_len, str2, str2_len, + &retval); + free((char*)str2); + } + } + free((char*)str1); + } + } + } + xmlrpc_DECREF(arrayP); + } + return retval; +} + + +/*========================================================================= +** validator1.nestedStructTest +**========================================================================= +*/ + +static xmlrpc_value * +nested_struct(xmlrpc_env * const envP, + xmlrpc_value * const param_array, + void * const user_data ATTR_UNUSED) { + + xmlrpc_value * yearsP; + xmlrpc_value * retval; + + /* Parse our argument array. */ + xmlrpc_decompose_value(envP, param_array, "(S)", &yearsP); + if (envP->fault_occurred) + retval = NULL; + else { + /* Get values of larry, moe and curly for 2000-04-01. */ + xmlrpc_int32 larry, moe, curly; + xmlrpc_decompose_value(envP, yearsP, + "{s:{s:{s:{s:i,s:i,s:i,*},*},*},*}", + "2000", "04", "01", + "larry", &larry, + "moe", &moe, + "curly", &curly); + if (envP->fault_occurred) + retval = NULL; + else + retval = xmlrpc_build_value(envP, "i", larry + moe + curly); + + xmlrpc_DECREF(yearsP); + } + return retval; +} + + +/*========================================================================= +** validator1.simpleStructReturnTest +**========================================================================= +*/ + +static xmlrpc_value * +struct_return(xmlrpc_env * const env, + xmlrpc_value * const param_array, + void * const user_data ATTR_UNUSED) { + + xmlrpc_int32 i; + + xmlrpc_decompose_value(env, param_array, "(i)", &i); + RETURN_IF_FAULT(env); + + return xmlrpc_build_value(env, "{s:i,s:i,s:i}", + "times10", (xmlrpc_int32) i * 10, + "times100", (xmlrpc_int32) i * 100, + "times1000", (xmlrpc_int32) i * 1000); +} + + +/*========================================================================= +** main +**========================================================================= +*/ + +int main(int const argc, + const char ** const argv) { + + xmlrpc_server_abyss_parms serverparm; + xmlrpc_registry * registryP; + xmlrpc_env env; + + if (argc-1 != 1) { + fprintf(stderr, "You must specify 1 argument: The TCP port " + "number on which the server will accept connections " + "for RPCs. You specified %d arguments.\n", argc-1); + exit(1); + } + + xmlrpc_env_init(&env); + + registryP = xmlrpc_registry_new(&env); + + xmlrpc_registry_add_method( + &env, registryP, NULL, "validator1.arrayOfStructsTest", + &array_of_structs, NULL); + xmlrpc_registry_add_method( + &env, registryP, NULL, "validator1.countTheEntities", + &count_entities, NULL); + xmlrpc_registry_add_method( + &env, registryP, NULL, "validator1.easyStructTest", + &easy_struct, NULL); + xmlrpc_registry_add_method( + &env, registryP, NULL, "validator1.echoStructTest", + &echo_struct, NULL); + xmlrpc_registry_add_method( + &env, registryP, NULL, "validator1.manyTypesTest", + &many_types, NULL); + xmlrpc_registry_add_method( + &env, registryP, NULL, "validator1.moderateSizeArrayCheck", + &moderate_array, NULL); + xmlrpc_registry_add_method( + &env, registryP, NULL, "validator1.nestedStructTest", + &nested_struct, NULL); + xmlrpc_registry_add_method( + &env, registryP, NULL, "validator1.simpleStructReturnTest", + &struct_return, NULL); + + serverparm.config_file_name = NULL; + serverparm.registryP = registryP; + serverparm.port_number = atoi(argv[1]); + serverparm.log_file_name = NULL; + + printf("Running XML-RPC server...\n"); + + xmlrpc_server_abyss(&env, &serverparm, XMLRPC_APSIZE(log_file_name)); + + /* This never gets executed. */ + return 0; +} diff --git a/examples/xmlrpc_socket_server.c b/examples/xmlrpc_socket_server.c new file mode 100644 index 0000000..b20ce15 --- /dev/null +++ b/examples/xmlrpc_socket_server.c @@ -0,0 +1,91 @@ +/* A simple standalone XML-RPC server written in C as an example of use of + the Xmlrpc-c libraries. + + This example expects an already bound socket on Standard Input, ready to + be listened on for client connections. Also see xmlrpc_sample_add_server, + which is the same thing, except you tell it a TCP port number and it + creates the socket itself. + */ + +#include +#include +#ifndef WIN32 +#include +#endif + +#include +#include +#include + +#include "config.h" /* information about this build environment */ + +static xmlrpc_value * +sample_add(xmlrpc_env * const env, + xmlrpc_value * const param_array, + void * const user_data ATTR_UNUSED) { + + xmlrpc_int32 x, y, z; + + /* Parse our argument array. */ + xmlrpc_decompose_value(env, param_array, "(ii)", &x, &y); + if (env->fault_occurred) + return NULL; + + /* Add our two numbers. */ + z = x + y; + + /* Sometimes, make it look hard (so client can see what it's like + to do an RPC that takes a while). + */ + if (y == 1) + sleep(2); + + /* Return our result. */ + return xmlrpc_build_value(env, "i", z); +} + + + +int +main(int const argc, + const char ** const argv) { + + xmlrpc_server_abyss_parms serverparm; + xmlrpc_registry * registryP; + xmlrpc_env env; + + if (argc-1 != 0) { + fprintf(stderr, "There are no arguments. You must supply a " + "bound socket on which to listen for client connections " + "as Standard Input\n"); + if (argv) {} /* silence unused parameter warning */ + exit(1); + } + + xmlrpc_env_init(&env); + + registryP = xmlrpc_registry_new(&env); + + xmlrpc_registry_add_method( + &env, registryP, NULL, "sample.add", &sample_add, NULL); + + /* In the modern form of the Abyss API, we supply parameters in memory + like a normal API. We select the modern form by setting + config_file_name to NULL: + */ + serverparm.config_file_name = NULL; + serverparm.registryP = registryP; + serverparm.log_file_name = "/tmp/xmlrpc_log"; + serverparm.keepalive_timeout = 0; + serverparm.keepalive_max_conn = 0; + serverparm.timeout = 0; + serverparm.dont_advertise = FALSE; + serverparm.socket_bound = TRUE; + serverparm.socket_handle = STDIN_FILENO; + + printf("Running XML-RPC server...\n"); + + xmlrpc_server_abyss(&env, &serverparm, XMLRPC_APSIZE(socket_handle)); + + return 0; +} diff --git a/include/Makefile b/include/Makefile new file mode 100644 index 0000000..6c76478 --- /dev/null +++ b/include/Makefile @@ -0,0 +1,79 @@ +ifeq ($(SRCDIR)x,x) +SRCDIR = $(CURDIR)/.. +endif +SUBDIR = src +BUILDDIR = $(SRCDIR) +VPATH = .:$(SRCDIR) + +include $(BUILDDIR)/Makefile.config + +default: all + +all: xmlrpc-c/config.h + +xmlrpc-c/config.h: + echo "#define XMLRPC_HAVE_WCHAR $(HAVE_WCHAR_H_DEFINE)" >$@ + + +HEADERS_TO_INSTALL = \ + xmlrpc-c/config.h \ + xmlrpc-c/util.h \ + xmlrpc-c/base.h \ + xmlrpc-c/abyss.h \ + xmlrpc-c/server.h \ + xmlrpc-c/server_abyss.h \ + xmlrpc-c/server_w32httpsys.h \ + xmlrpc-c/oldxmlrpc.h \ + +ifeq ($(ENABLE_CPLUSPLUS),yes) + HEADERS_TO_INSTALL += \ + xmlrpc-c/oldcppwrapper.hpp \ + xmlrpc-c/girerr.hpp \ + xmlrpc-c/girmem.hpp \ + xmlrpc-c/base.hpp \ + xmlrpc-c/timeout.hpp \ + xmlrpc-c/xml.hpp \ + xmlrpc-c/registry.hpp \ + xmlrpc-c/server_abyss.hpp \ + +endif + +HEADERINST_PREFIX = /xmlrpc-c + +ifeq ($(MUST_BUILD_CLIENT),yes) + HEADERS_TO_INSTALL += \ + xmlrpc-c/client.h \ + xmlrpc-c/transport.h \ + xmlrpc-c/client_global.h \ + + ifeq ($(ENABLE_CPLUSPLUS),yes) + HEADERS_TO_INSTALL += \ + xmlrpc-c/client.hpp \ + xmlrpc-c/client_transport.hpp \ + xmlrpc-c/client_simple.hpp \ + + endif +endif +ifeq ($(ENABLE_CGI_SERVER),yes) + HEADERS_TO_INSTALL += xmlrpc-c/server_cgi.h +endif + +default: all + +all: + +.PHONY: install +install: install-common + +.PHONY: clean distclean dep +clean: +distclean: + rm -f xmlrpc-c/config.h + +.PHONY: check +check: + +.PHONY: dep +dep: + +include $(SRCDIR)/Makefile.common diff --git a/include/xmlrpc-c/.cvsignore b/include/xmlrpc-c/.cvsignore new file mode 100644 index 0000000..0e56cf2 --- /dev/null +++ b/include/xmlrpc-c/.cvsignore @@ -0,0 +1 @@ +config.h diff --git a/include/xmlrpc-c/abyss.h b/include/xmlrpc-c/abyss.h new file mode 100644 index 0000000..d9aeb9a --- /dev/null +++ b/include/xmlrpc-c/abyss.h @@ -0,0 +1,527 @@ +/***************************************************************************** + abyss.h +****************************************************************************** + + This file is the interface header for the Abyss HTTP server component of + XML-RPC For C/C++ (Xmlrpc-c). + + The Abyss component of Xmlrpc-c is based on the independently developed + and distributed Abyss web server package from 2001. + + Copyright information is at the end of the file. +****************************************************************************/ + +#ifndef _ABYSS_H_ +#define _ABYSS_H_ + + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +#ifdef WIN32 +#include "xmlrpc_config.h" +#else +#include +#endif + +/**************************************************************************** + STUFF FOR THE OUTER CONTROL PROGRAM TO USE +****************************************************************************/ + +typedef int abyss_bool; + +/********************************************************************* +** MIMEType +*********************************************************************/ + +typedef struct MIMEType MIMEType; + +MIMEType * +MIMETypeCreate(void); + +void +MIMETypeDestroy(MIMEType * const MIMETypeP); + +void +MIMETypeInit(void); + +void +MIMETypeTerm(void); + +abyss_bool +MIMETypeAdd2(MIMEType * const MIMETypeP, + const char * const type, + const char * const ext); + +abyss_bool +MIMETypeAdd(const char * const type, + const char * const ext); + + +enum abyss_foreback {ABYSS_FOREGROUND, ABYSS_BACKGROUND}; + + +typedef struct _TSocket TSocket; + +/* TOsSocket is the type of a conventional socket offered by our OS. + This is for backward compatibility; everyone should use TSocket + sockets today. +*/ +#ifdef WIN32 +void +SocketWinCreate(TSocket ** const socketPP); + +void +SocketWinCreateWinsock(SOCKET const winsock, + TSocket ** const socketPP); + +typedef SOCKET TOsSocket; + +#else /* WIN32 */ + +void +SocketUnixCreate(TSocket ** const socketPP); + +void +SocketUnixCreateFd(int const fd, + TSocket ** const socketPP); + +typedef int TOsSocket; +#endif /* WIN32 */ + +void +SocketDestroy(TSocket * const socketP); + + +typedef struct { + /* Before Xmlrpc-c 1.04, the internal server representation, + struct _TServer, was exposed to users and was the only way to + set certain parameters of the server. Now, use the (new) + ServerSet...() functions. Use the HAVE_ macros to determine + which method you have to use. + */ + struct _TServer * srvP; +} TServer; + +typedef struct _TSession TSession; + +abyss_bool +ServerCreate(TServer * const serverP, + const char * const name, + uint16_t const port, + const char * const filespath, + const char * const logfilename); + +abyss_bool +ServerCreateSocket(TServer * const serverP, + const char * const name, + TOsSocket const socketFd, + const char * const filespath, + const char * const logfilename); + +#define HAVE_SERVER_CREATE_SOCKET_2 +void +ServerCreateSocket2(TServer * const serverP, + TSocket * const socketP, + const char ** const errorP); + +abyss_bool +ServerCreateNoAccept(TServer * const serverP, + const char * const name, + const char * const filespath, + const char * const logfilename); + +void +ServerFree(TServer * const serverP); + +void +ServerSetName(TServer * const serverP, + const char * const name); + +void +ServerSetFilesPath(TServer * const serverP, + const char * const filesPath); + +void +ServerSetLogFileName(TServer * const serverP, + const char * const logFileName); + +#define HAVE_SERVER_SET_KEEPALIVE_TIMEOUT 1 +void +ServerSetKeepaliveTimeout(TServer * const serverP, + uint32_t const keepaliveTimeout); + +#define HAVE_SERVER_SET_KEEPALIVE_MAX_CONN 1 +void +ServerSetKeepaliveMaxConn(TServer * const serverP, + uint32_t const keepaliveMaxConn); + +#define HAVE_SERVER_SET_TIMEOUT 1 +void +ServerSetTimeout(TServer * const serverP, + uint32_t const timeout); + +#define HAVE_SERVER_SET_ADVERTISE 1 +void +ServerSetAdvertise(TServer * const serverP, + abyss_bool const advertise); + +#define HAVE_SERVER_SET_MIME_TYPE 1 +void +ServerSetMimeType(TServer * const serverP, + MIMEType * const MIMETypeP); + +void +ServerInit(TServer * const serverP); + +void +ServerRun(TServer * const serverP); + +void +ServerRunOnce(TServer * const serverP); + +/* ServerRunOnce2() is obsolete. See user's guide. */ +void +ServerRunOnce2(TServer * const serverP, + enum abyss_foreback const foregroundBackground); + +void +ServerRunConn(TServer * const serverP, + TOsSocket const connectedSocket); + +#define HAVE_SERVER_RUN_CONN_2 +void +ServerRunConn2(TServer * const serverP, + TSocket * const connectedSocketP, + const char ** const errorP); + +void +ServerDaemonize(TServer * const serverP); + +void +ServerTerminate(TServer * const serverP); + +void +ServerResetTerminate(TServer * const serverP); + +void +ServerUseSigchld(TServer * const serverP); + +#ifndef WIN32 +void +ServerHandleSigchld(pid_t const pid); +#endif + +typedef abyss_bool (*URIHandler) (TSession *); /* deprecated */ + +struct URIHandler2; + +typedef void (*initHandlerFn)(struct URIHandler2 *, + abyss_bool *); + +typedef void (*termHandlerFn)(void *); + +typedef void (*handleReq2Fn)(struct URIHandler2 *, + TSession *, + abyss_bool *); + +typedef struct URIHandler2 { + initHandlerFn init; + termHandlerFn term; + handleReq2Fn handleReq2; + URIHandler handleReq1; /* deprecated */ + void * userdata; +} URIHandler2; + +void +ServerAddHandler2(TServer * const srvP, + URIHandler2 * const handlerP, + abyss_bool * const successP); + +abyss_bool +ServerAddHandler(TServer * const srvP, + URIHandler const handler); + +void +ServerDefaultHandler(TServer * const srvP, + URIHandler const handler); + +/* This is inappropriately named; it was a mistake. But then, so is + having this function at all. The config file is inappropriate for + an API. +*/ +abyss_bool +ConfReadServerFile(const char * const filename, + TServer * const srvP); + +void +LogWrite(TServer * const srvP, + const char * const c); + +/**************************************************************************** + STUFF FOR URI HANDLERS TO USE +****************************************************************************/ + +typedef enum { + m_unknown, m_get, m_put, m_head, m_post, m_delete, m_trace, m_options +} TMethod; + +typedef struct { + TMethod method; + const char * uri; + /* This is NOT the URI. It is the pathname part of the URI. + We really should fix that and put the pathname in another + member. + */ + const char * query; + /* The query part of the URI (stuff after '?') */ + const char * host; + /* NOT the value of the host: header. Rather, the name of the + target host (could be part of the host: value). No port number. + */ + const char * from; + const char * useragent; + const char * referer; + const char * requestline; + const char * user; + unsigned short port; + abyss_bool keepalive; +} TRequestInfo; + +abyss_bool +SessionRefillBuffer(TSession * const sessionP); + +size_t +SessionReadDataAvail(TSession * const sessionP); + +void +SessionGetReadData(TSession * const sessionP, + size_t const max, + const char ** const outStartP, + size_t * const outLenP); + +void +SessionGetRequestInfo(TSession * const sessionP, + const TRequestInfo ** const requestInfoPP); + +char * +RequestHeaderValue(TSession * const sessionP, + char * const name); + +abyss_bool +ResponseAddField(TSession * const sessionP, + const char * const name, + const char * const value); + +void +ResponseWriteStart(TSession * const sessionP); + +/* For backward compatibility: */ +#define ResponseWrite ResponseWriteStart + +abyss_bool +ResponseWriteBody(TSession * const sessionP, + const char * const data, + uint32_t const len); + +abyss_bool +ResponseWriteEnd(TSession * const sessionP); + +abyss_bool +ResponseChunked(TSession * const sessionP); + +uint16_t +ResponseStatusFromErrno(int const errnoArg); + +void +ResponseStatus(TSession * const sessionP, + uint16_t const code); + +void +ResponseStatusErrno(TSession * const sessionP); + +abyss_bool +ResponseContentType(TSession * const serverP, + const char * const type); + +abyss_bool +ResponseContentLength(TSession * const sessionP, + uint64_t const len); + +void +ResponseError(TSession * const sessionP); + +const char * +MIMETypeFromExt(const char * const ext); + +const char * +MIMETypeFromExt2(MIMEType * const MIMETypeP, + const char * const ext); + +const char * +MIMETypeFromFileName2(MIMEType * const MIMETypeP, + const char * const fileName); + +const char * +MIMETypeFromFileName(const char * const fileName); + +const char * +MIMETypeGuessFromFile2(MIMEType * const MIMETypeP, + const char * const fileName); + +const char * +MIMETypeGuessFromFile(const char * const filename); + + +/**************************************************************************** + STUFF THAT PROBABLY DOESN'T BELONG IN THIS FILE BECAUSE IT IS INTERNAL + + Some day, we sort this out. +****************************************************************************/ + + +#define CR '\r' +#define LF '\n' +#define CRLF "\r\n" + +/********************************************************************* +** Paths and so on... +*********************************************************************/ + +#ifdef WIN32 +#define DEFAULT_ROOT "c:\\abyss" +#define DEFAULT_DOCS DEFAULT_ROOT"\\htdocs" +#define DEFAULT_CONF_FILE DEFAULT_ROOT"\\conf\\abyss.conf" +#define DEFAULT_LOG_FILE DEFAULT_ROOT"\\log\\abyss.log" +#else +#ifdef __rtems__ +#define DEFAULT_ROOT "/abyss" +#else +#define DEFAULT_ROOT "/usr/local/abyss" +#endif +#define DEFAULT_DOCS DEFAULT_ROOT"/htdocs" +#define DEFAULT_CONF_FILE DEFAULT_ROOT"/conf/abyss.conf" +#define DEFAULT_LOG_FILE DEFAULT_ROOT"/log/abyss.log" +#endif + +/********************************************************************* +** Maximum number of simultaneous connections +*********************************************************************/ + +#define MAX_CONN 16 + +/********************************************************************* +** General purpose definitions +*********************************************************************/ + +#ifndef NULL +#define NULL ((void *)0) +#endif /* NULL */ + +#ifndef TRUE +#define TRUE 1 +#endif /* TRUE */ + +#ifndef FALSE +#define FALSE 0 +#endif /* FALSE */ + +/********************************************************************* +** Buffer +*********************************************************************/ + +typedef struct +{ + void *data; + uint32_t size; + uint32_t staticid; +} TBuffer; + +abyss_bool BufferAlloc(TBuffer *buf,uint32_t memsize); +abyss_bool BufferRealloc(TBuffer *buf,uint32_t memsize); +void BufferFree(TBuffer *buf); + + +/********************************************************************* +** String +*********************************************************************/ + +typedef struct +{ + TBuffer buffer; + uint32_t size; +} TString; + +abyss_bool StringAlloc(TString *s); +abyss_bool StringConcat(TString *s,char *s2); +abyss_bool StringBlockConcat(TString *s,char *s2,char **ref); +void StringFree(TString *s); +char *StringData(TString *s); + + +/********************************************************************* +** Range +*********************************************************************/ + +abyss_bool +RangeDecode(char *str, + uint64_t filesize, + uint64_t *start, + uint64_t *end); + +abyss_bool DateInit(void); + +/********************************************************************* +** Base64 +*********************************************************************/ + +void Base64Encode(char *s,char *d); + +/********************************************************************* +** Session +*********************************************************************/ + +abyss_bool SessionLog(TSession *s); + + +#ifdef __cplusplus +} + + +#endif + +/***************************************************************************** +** Here is the copyright notice from the Abyss web server project file from +** which this file is derived. +** +** Copyright (C) 2000 by Moez Mahfoudh . +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +** ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +** OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +** HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +** LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +** OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +** SUCH DAMAGE. +** +******************************************************************************/ +#endif /* _ABYSS_H_ */ diff --git a/include/xmlrpc-c/base.h b/include/xmlrpc-c/base.h new file mode 100644 index 0000000..45f18ef --- /dev/null +++ b/include/xmlrpc-c/base.h @@ -0,0 +1,616 @@ +/* Copyright and license information is at the end of the file */ + +#ifndef XMLRPC_H_INCLUDED +#define XMLRPC_H_INCLUDED + +#include +#include +#include +#include +#include /* Defines XMLRPC_HAVE_WCHAR */ + +#if XMLRPC_HAVE_WCHAR +#include +#endif + +#ifdef __cplusplus +extern "C" { +#endif + + +/*========================================================================= +** Typedefs +**========================================================================= +** We define names for these types, because they may change from platform +** to platform. +*/ + +typedef signed int xmlrpc_int; + /* An integer of the type defined by XML-RPC ; i.e. 32 bit */ +typedef signed int xmlrpc_int32; + /* An integer of the type defined by XML-RPC ; i.e. 32 bit */ +typedef int xmlrpc_bool; + /* A boolean (of the type defined by XML-RPC , but there's + really only one kind) + */ +typedef double xmlrpc_double; + /* A double precision floating point number as defined by + XML-RPC . But the C "double" type is universally the same, + so it's probably clearer just to use that. This typedef is here + for mathematical completeness. + */ + +#ifdef _WIN32 +typedef SOCKET xmlrpc_socket; +#else +typedef int xmlrpc_socket; +#endif + +#define XMLRPC_INT32_MAX (2147483647) +#define XMLRPC_INT32_MIN (-XMLRPC_INT32_MAX - 1) + + + +/*========================================================================= +** xmlrpc_value +**========================================================================= +** An XML-RPC value (of any type). +*/ + +typedef enum { + XMLRPC_TYPE_INT = 0, + XMLRPC_TYPE_BOOL = 1, + XMLRPC_TYPE_DOUBLE = 2, + XMLRPC_TYPE_DATETIME = 3, + XMLRPC_TYPE_STRING = 4, + XMLRPC_TYPE_BASE64 = 5, + XMLRPC_TYPE_ARRAY = 6, + XMLRPC_TYPE_STRUCT = 7, + XMLRPC_TYPE_C_PTR = 8, + XMLRPC_TYPE_NIL = 9, + XMLRPC_TYPE_DEAD = 0xDEAD +} xmlrpc_type; + +/* These are *always* allocated on the heap. No exceptions. */ +typedef struct _xmlrpc_value xmlrpc_value; + +void +xmlrpc_abort_if_array_bad(xmlrpc_value * const arrayP); + +#define XMLRPC_ASSERT_ARRAY_OK(val) \ + xmlrpc_abort_if_array_bad(val) + +/* Increment the reference count of an xmlrpc_value. */ +extern void xmlrpc_INCREF (xmlrpc_value* value); + +/* Decrement the reference count of an xmlrpc_value. If there +** are no more references, free it. */ +extern void xmlrpc_DECREF (xmlrpc_value* value); + +/* Get the type of an XML-RPC value. */ +extern xmlrpc_type xmlrpc_value_type (xmlrpc_value* value); + +xmlrpc_value * +xmlrpc_int_new(xmlrpc_env * const envP, + int const intValue); + +void +xmlrpc_read_int(xmlrpc_env * const envP, + const xmlrpc_value * const valueP, + int * const intValueP); + +xmlrpc_value * +xmlrpc_bool_new(xmlrpc_env * const envP, + xmlrpc_bool const boolValue); + +void +xmlrpc_read_bool(xmlrpc_env * const envP, + const xmlrpc_value * const valueP, + xmlrpc_bool * const boolValueP); + +xmlrpc_value * +xmlrpc_double_new(xmlrpc_env * const envP, + double const doubleValue); + +void +xmlrpc_read_double(xmlrpc_env * const envP, + const xmlrpc_value * const valueP, + xmlrpc_double * const doubleValueP); + +xmlrpc_value * +xmlrpc_datetime_new_str(xmlrpc_env * const envP, + const char * const value); + +xmlrpc_value * +xmlrpc_datetime_new_sec(xmlrpc_env * const envP, + time_t const value); + +void +xmlrpc_read_datetime_str(xmlrpc_env * const envP, + const xmlrpc_value * const valueP, + const char ** const stringValueP); + +void +xmlrpc_read_datetime_sec(xmlrpc_env * const envP, + const xmlrpc_value * const valueP, + time_t * const timeValueP); + +xmlrpc_value * +xmlrpc_string_new(xmlrpc_env * const envP, + const char * const stringValue); + +xmlrpc_value * +xmlrpc_string_new_lp(xmlrpc_env * const envP, + size_t const length, + const char * const stringValue); + +void +xmlrpc_read_string(xmlrpc_env * const envP, + const xmlrpc_value * const valueP, + const char ** const stringValueP); + + +void +xmlrpc_read_string_lp(xmlrpc_env * const envP, + const xmlrpc_value * const valueP, + size_t * const lengthP, + const char ** const stringValueP); + +#if XMLRPC_HAVE_WCHAR +xmlrpc_value * +xmlrpc_string_w_new(xmlrpc_env * const envP, + const wchar_t * const stringValue); + +xmlrpc_value * +xmlrpc_string_w_new_lp(xmlrpc_env * const envP, + size_t const length, + const wchar_t * const stringValue); + +void +xmlrpc_read_string_w(xmlrpc_env * const envP, + xmlrpc_value * const valueP, + const wchar_t ** const stringValueP); + +void +xmlrpc_read_string_w_lp(xmlrpc_env * const envP, + xmlrpc_value * const valueP, + size_t * const lengthP, + const wchar_t ** const stringValueP); + +#endif /* XMLRPC_HAVE_WCHAR */ + +xmlrpc_value * +xmlrpc_base64_new(xmlrpc_env * const envP, + size_t const length, + const unsigned char * const value); + +void +xmlrpc_read_base64(xmlrpc_env * const envP, + const xmlrpc_value * const valueP, + size_t * const lengthP, + const unsigned char ** const bytestringValueP); + +void +xmlrpc_read_base64_size(xmlrpc_env * const envP, + const xmlrpc_value * const valueP, + size_t * const lengthP); + +xmlrpc_value * +xmlrpc_array_new(xmlrpc_env * const envP); + +/* Return the number of elements in an XML-RPC array. +** Sets XMLRPC_TYPE_ERROR if 'array' is not an array. */ +int +xmlrpc_array_size(xmlrpc_env * const env, + const xmlrpc_value * const array); + +/* Append an item to an XML-RPC array. +** Sets XMLRPC_TYPE_ERROR if 'array' is not an array. */ +extern void +xmlrpc_array_append_item (xmlrpc_env * envP, + xmlrpc_value * arrayP, + xmlrpc_value * valueP); + +void +xmlrpc_array_read_item(xmlrpc_env * const envP, + const xmlrpc_value * const arrayP, + unsigned int const index, + xmlrpc_value ** const valuePP); + +/* Deprecated. Use xmlrpc_array_read_item() instead. + + Get an item from an XML-RPC array. + Does not increment the reference count of the returned value. + Sets XMLRPC_TYPE_ERROR if 'array' is not an array. + Sets XMLRPC_INDEX_ERROR if 'index' is out of bounds. +*/ +xmlrpc_value * +xmlrpc_array_get_item(xmlrpc_env * const envP, + const xmlrpc_value * const arrayP, + int const index); + +/* Not implemented--we don't need it yet. +extern +int xmlrpc_array_set_item (xmlrpc_env* env, +xmlrpc_value* array, +int index, + xmlrpc_value* value); +*/ + +void +xmlrpc_read_nil(xmlrpc_env * const envP, + xmlrpc_value * const valueP); + + +void +xmlrpc_read_cptr(xmlrpc_env * const envP, + const xmlrpc_value * const valueP, + void ** const ptrValueP); + +xmlrpc_value * +xmlrpc_struct_new(xmlrpc_env * env); + +/* Return the number of key/value pairs in a struct. +** Sets XMLRPC_TYPE_ERROR if 'strct' is not a struct. */ +int +xmlrpc_struct_size (xmlrpc_env * env, + xmlrpc_value * strct); + +/* Returns true iff 'strct' contains 'key'. +** Sets XMLRPC_TYPE_ERROR if 'strct' is not a struct. */ +int +xmlrpc_struct_has_key(xmlrpc_env * const envP, + xmlrpc_value * const strctP, + const char * const key); + +/* The same as the above, but the key may contain zero bytes. + Deprecated. xmlrpc_struct_get_value_v() is more general, and this + case is not common enough to warrant a shortcut. +*/ +int +xmlrpc_struct_has_key_n(xmlrpc_env * const envP, + xmlrpc_value * const strctP, + const char * const key, + size_t const key_len); + +#if 0 +/* Not implemented yet, but needed for completeness. */ +int +xmlrpc_struct_has_key_v(xmlrpc_env * env, + xmlrpc_value * strct, + xmlrpc_value * const keyval); +#endif + + +void +xmlrpc_struct_find_value(xmlrpc_env * const envP, + xmlrpc_value * const structP, + const char * const key, + xmlrpc_value ** const valuePP); + + +void +xmlrpc_struct_find_value_v(xmlrpc_env * const envP, + xmlrpc_value * const structP, + xmlrpc_value * const keyP, + xmlrpc_value ** const valuePP); + +void +xmlrpc_struct_read_value_v(xmlrpc_env * const envP, + xmlrpc_value * const structP, + xmlrpc_value * const keyP, + xmlrpc_value ** const valuePP); + +void +xmlrpc_struct_read_value(xmlrpc_env * const envP, + xmlrpc_value * const strctP, + const char * const key, + xmlrpc_value ** const valuePP); + +/* The "get_value" functions are deprecated. Use the "find_value" + and "read_value" functions instead. +*/ +xmlrpc_value * +xmlrpc_struct_get_value(xmlrpc_env * const envP, + xmlrpc_value * const strctP, + const char * const key); + +/* The same as above, but the key may contain zero bytes. + Deprecated. xmlrpc_struct_get_value_v() is more general, and this + case is not common enough to warrant a shortcut. +*/ +xmlrpc_value * +xmlrpc_struct_get_value_n(xmlrpc_env * const envP, + xmlrpc_value * const strctP, + const char * const key, + size_t const key_len); + +/* Set the value associated with 'key' in 'strct' to 'value'. + Sets XMLRPC_TYPE_ERROR if 'strct' is not a struct. +*/ +void +xmlrpc_struct_set_value(xmlrpc_env * const env, + xmlrpc_value * const strct, + const char * const key, + xmlrpc_value * const value); + +/* The same as above, but the key may contain zero bytes. Deprecated. + The general way to set a structure value is xmlrpc_struct_set_value_v(), + and this case is not common enough to deserve a shortcut. +*/ +void +xmlrpc_struct_set_value_n(xmlrpc_env * const env, + xmlrpc_value * const strct, + const char * const key, + size_t const key_len, + xmlrpc_value * const value); + +/* The same as above, but the key must be an XML-RPC string. +** Fails with XMLRPC_TYPE_ERROR if 'keyval' is not a string. */ +void +xmlrpc_struct_set_value_v(xmlrpc_env * const env, + xmlrpc_value * const strct, + xmlrpc_value * const keyval, + xmlrpc_value * const value); + +/* Given a zero-based index, return the matching key and value. This +** is normally used in conjunction with xmlrpc_struct_size. +** Fails with XMLRPC_TYPE_ERROR if 'struct' is not a struct. +** Fails with XMLRPC_INDEX_ERROR if 'index' is out of bounds. */ + +void +xmlrpc_struct_read_member(xmlrpc_env * const envP, + xmlrpc_value * const structP, + unsigned int const index, + xmlrpc_value ** const keyvalP, + xmlrpc_value ** const valueP); + +/* The same as above, but does not increment the reference count of the + two values it returns, and return NULL for both if it fails, and + takes a signed integer for the index (but fails if it is negative). + + Deprecated. Use xmlrpc_struct_read_member() instead. +*/ +void +xmlrpc_struct_get_key_and_value(xmlrpc_env * env, + xmlrpc_value * strct, + int index, + xmlrpc_value ** out_keyval, + xmlrpc_value ** out_value); + +xmlrpc_value * +xmlrpc_cptr_new(xmlrpc_env * const envP, + void * const value); + +xmlrpc_value * +xmlrpc_nil_new(xmlrpc_env * const envP); + + +/* Build an xmlrpc_value from a format string. */ + +xmlrpc_value * +xmlrpc_build_value(xmlrpc_env * const env, + const char * const format, + ...); + +/* The same as the above, but using a va_list and more general */ +void +xmlrpc_build_value_va(xmlrpc_env * const env, + const char * const format, + va_list args, + xmlrpc_value ** const valPP, + const char ** const tailP); + +void +xmlrpc_decompose_value(xmlrpc_env * const envP, + xmlrpc_value * const value, + const char * const format, + ...); + +void +xmlrpc_decompose_value_va(xmlrpc_env * const envP, + xmlrpc_value * const value, + const char * const format, + va_list args); + +/* xmlrpc_parse_value... is the same as xmlrpc_decompose_value... except + that it doesn't do proper memory management -- it returns xmlrpc_value's + without incrementing the reference count and returns pointers to data + inside an xmlrpc_value structure. + + These are deprecated. Use xmlrpc_decompose_value... instead. +*/ +void +xmlrpc_parse_value(xmlrpc_env * const envP, + xmlrpc_value * const value, + const char * const format, + ...); + +/* The same as the above, but using a va_list. */ +void +xmlrpc_parse_value_va(xmlrpc_env * const envP, + xmlrpc_value * const value, + const char * const format, + va_list args); + +/*========================================================================= +** Encoding XML +**=======================================================================*/ + +/* Serialize an XML value without any XML header. This is primarily used +** for testing purposes. */ +void +xmlrpc_serialize_value(xmlrpc_env * env, + xmlrpc_mem_block * output, + xmlrpc_value * value); + +/* Serialize a list of parameters without any XML header. This is +** primarily used for testing purposes. */ +void +xmlrpc_serialize_params(xmlrpc_env * env, + xmlrpc_mem_block * output, + xmlrpc_value * param_array); + +/* Serialize an XML-RPC call. */ +void +xmlrpc_serialize_call (xmlrpc_env * const env, + xmlrpc_mem_block * const output, + const char * const method_name, + xmlrpc_value * const param_array); + +/* Serialize an XML-RPC return value. */ +extern void +xmlrpc_serialize_response(xmlrpc_env * env, + xmlrpc_mem_block * output, + xmlrpc_value * value); + +/* Serialize an XML-RPC fault (as specified by 'fault'). */ +extern void +xmlrpc_serialize_fault(xmlrpc_env * env, + xmlrpc_mem_block * output, + xmlrpc_env * fault); + + +/*========================================================================= +** Decoding XML +**=======================================================================*/ + +/* Parse an XML-RPC call. If an error occurs, set a fault and set +** the output variables to NULL. +** The caller is responsible for calling free(*out_method_name) and +** xmlrpc_DECREF(*out_param_array). */ +void +xmlrpc_parse_call(xmlrpc_env * const envP, + const char * const xml_data, + size_t const xml_len, + const char ** const out_method_name, + xmlrpc_value ** const out_param_array); + +void +xmlrpc_parse_response2(xmlrpc_env * const envP, + const char * const xmlData, + size_t const xmlDataLen, + xmlrpc_value ** const resultPP, + int * const faultCodeP, + const char ** const faultStringP); + + +/* xmlrpc_parse_response() is for backward compatibility */ + +xmlrpc_value * +xmlrpc_parse_response(xmlrpc_env * const envP, + const char * const xmlData, + size_t const xmlDataLen); + + +/*========================================================================= +** XML-RPC Base64 Utilities +**========================================================================= +** Here are some lightweight utilities which can be used to encode and +** decode Base64 data. These are exported mainly for testing purposes. +*/ + +/* This routine inserts newlines every 76 characters, as required by the +** Base64 specification. */ +xmlrpc_mem_block * +xmlrpc_base64_encode(xmlrpc_env * env, + unsigned char * bin_data, + size_t bin_len); + +/* This routine encodes everything in one line. This is needed for HTTP +** authentication and similar tasks. */ +xmlrpc_mem_block * +xmlrpc_base64_encode_without_newlines(xmlrpc_env * env, + unsigned char * bin_data, + size_t bin_len); + +/* This decodes Base64 data with or without newlines. */ +extern xmlrpc_mem_block * +xmlrpc_base64_decode(xmlrpc_env * const envP, + const char * const ascii_data, + size_t const ascii_len); + + +/*========================================================================= +** UTF-8 Encoding and Decoding +**========================================================================= +** We need a correct, reliable and secure UTF-8 decoder. This decoder +** raises a fault if it encounters invalid UTF-8. +** +** Note that ANSI C does not precisely define the representation used +** by wchar_t--it may be UCS-2, UTF-16, UCS-4, or something from outer +** space. If your platform does something especially bizarre, you may +** need to reimplement these routines. +*/ + +/* Ensure that a string contains valid, legally-encoded UTF-8 data. + (Incorrectly-encoded UTF-8 strings are often used to bypass security + checks.) +*/ +void +xmlrpc_validate_utf8 (xmlrpc_env * const env, + const char * const utf8_data, + size_t const utf8_len); + +/* Decode a UTF-8 string. */ +xmlrpc_mem_block * +xmlrpc_utf8_to_wcs(xmlrpc_env * const envP, + const char * const utf8_data, + size_t const utf8_len); + +/* Encode a UTF-8 string. */ + +#if XMLRPC_HAVE_WCHAR +xmlrpc_mem_block * +xmlrpc_wcs_to_utf8(xmlrpc_env * env, + wchar_t * wcs_data, + size_t wcs_len); +#endif + +/*========================================================================= +** Authorization Cookie Handling +**========================================================================= +** Routines to get and set values for authorizing via authorization +** cookies. Both the client and server use HTTP_COOKIE_AUTH to store +** the representation of the authorization value, which is actually +** just a base64 hash of username:password. (This entire method is +** a cookie replacement of basic authentication.) +**/ + +extern void xmlrpc_authcookie_set(xmlrpc_env * env, + const char * username, + const char * password); + +char *xmlrpc_authcookie(void); + +#ifdef __cplusplus +} +#endif + +/* Copyright (C) 2001 by First Peer, Inc. All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +** ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +** OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +** HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +** LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +** OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +** SUCH DAMAGE. */ + +#endif + diff --git a/include/xmlrpc-c/base.hpp b/include/xmlrpc-c/base.hpp new file mode 100644 index 0000000..c3dac8b --- /dev/null +++ b/include/xmlrpc-c/base.hpp @@ -0,0 +1,312 @@ +#ifndef XMLRPC_BASE_HPP_INCLUDED +#define XMLRPC_BASE_HPP_INCLUDED + +#include +#include +#include +#include +#include +#include + +#include + +namespace xmlrpc_c { + + +class value { + // This is a handle. You don't want to create a pointer to this; + // it is in fact a pointer itself. +public: + value(); + // This creates a placeholder. It can't be used for anything, but + // holds memory. instantiate() can turn it into a real object. + + value(xmlrpc_c::value const &value); // copy constructor + + ~value(); + + enum type_t { + TYPE_INT = 0, + TYPE_BOOLEAN = 1, + TYPE_DOUBLE = 2, + TYPE_DATETIME = 3, + TYPE_STRING = 4, + TYPE_BYTESTRING = 5, + TYPE_ARRAY = 6, + TYPE_STRUCT = 7, + TYPE_C_PTR = 8, + TYPE_NIL = 9, + TYPE_DEAD = 0xDEAD + }; + + type_t type() const; + + xmlrpc_c::value& + operator=(xmlrpc_c::value const&); + + // The following are not meant to be public to users, but just to + // other Xmlrpc-c library modules. If we ever go to a pure C++ + // implementation, not based on C xmlrpc_value objects, this shouldn't + // be necessary. + + void + appendToCArray(xmlrpc_value * const arrayP) const; + + void + addToCStruct(xmlrpc_value * const structP, + std::string const key) const; + + xmlrpc_value * + cValue() const; + + value(xmlrpc_value * const valueP); + + void + instantiate(xmlrpc_value * const valueP); + // Work only on a placeholder object created by the no-argument + // constructor. + + xmlrpc_value * cValueP; + // NULL means this is merely a placeholder object. +}; + + + +class value_int : public value { +public: + value_int(int const cvalue); + + value_int(xmlrpc_c::value const baseValue); + + operator int() const; +}; + + + +class value_boolean : public value { +public: + value_boolean(bool const cvalue); + + value_boolean(xmlrpc_c::value const baseValue); + + operator bool() const; +}; + + + +class value_string : public value { +public: + value_string(std::string const& cvalue); + + value_string(xmlrpc_c::value const baseValue); + + operator std::string() const; +}; + + + +class value_double : public value { +public: + value_double(double const cvalue); + + value_double(xmlrpc_c::value const baseValue); + + operator double() const; +}; + + + +class value_datetime : public value { +public: + value_datetime(std::string const cvalue); + value_datetime(time_t const cvalue); + value_datetime(struct timeval const& cvalue); + value_datetime(struct timespec const& cvalue); + + value_datetime(xmlrpc_c::value const baseValue); + + operator time_t() const; +}; + + + +class value_bytestring : public value { +public: + value_bytestring(std::vector const& cvalue); + + value_bytestring(xmlrpc_c::value const baseValue); + + // You can't cast to a vector because the compiler can't tell which + // constructor to use (complains about ambiguity). So we have this: + std::vector + vectorUcharValue() const; + + size_t + length() const; +}; + + + +class value_nil : public value { +public: + value_nil(); + + value_nil(xmlrpc_c::value const baseValue); +}; + + + +class value_struct : public value { +public: + value_struct(std::map const& cvalue); + + value_struct(xmlrpc_c::value const baseValue); + + operator std::map() const; +}; + + + +class value_array : public value { +public: + value_array(std::vector const& cvalue); + + value_array(xmlrpc_c::value const baseValue); + + std::vector + vectorValueValue() const; + + size_t + size() const; +}; + + + +class fault { +/*---------------------------------------------------------------------------- + This is an XML-RPC fault. + + This object is not intended to be used to represent a fault in the + execution of XML-RPC client/server software -- just a fault in an + XML-RPC RPC as described by the XML-RPC spec. + + There is no way to represent "no fault" with this object. The object is + meaningful only in the context of some fault. +-----------------------------------------------------------------------------*/ +public: + enum code_t { + CODE_UNSPECIFIED = 0, + CODE_INTERNAL = -500, + CODE_TYPE = -501, + CODE_INDEX = -502, + CODE_PARSE = -503, + CODE_NETWORK = -504, + CODE_TIMEOUT = -505, + CODE_NO_SUCH_METHOD = -506, + CODE_REQUEST_REFUSED = -507, + CODE_INTROSPECTION_DISABLED = -508, + CODE_LIMIT_EXCEEDED = -509, + CODE_INVALID_UTF8 = -510 + }; + + fault(); + + fault(std::string const _faultString, + xmlrpc_c::fault::code_t const _faultCode + = xmlrpc_c::fault::CODE_UNSPECIFIED + ); + + xmlrpc_c::fault::code_t getCode() const; + + std::string getDescription() const; + +private: + bool valid; + xmlrpc_c::fault::code_t code; + std::string description; +}; + +class rpcOutcome { +/*---------------------------------------------------------------------------- + The outcome of a validly executed RPC -- either an XML-RPC fault + or an XML-RPC value of the result. +-----------------------------------------------------------------------------*/ +public: + rpcOutcome(); + rpcOutcome(xmlrpc_c::value const result); + rpcOutcome(xmlrpc_c::fault const fault); + bool succeeded() const; + xmlrpc_c::fault getFault() const; + xmlrpc_c::value getResult() const; +private: + bool valid; + // This is false in a placeholder variable -- i.e. an object you + // create with the no-argument constructor, which is waiting to be + // assigned a value. When false, nothing below is valid. + bool _succeeded; + xmlrpc_c::value result; // valid if 'succeeded' + xmlrpc_c::fault fault; // valid if not 'succeeded' +}; + +class paramList { +/*---------------------------------------------------------------------------- + A parameter list of an XML-RPC call. +-----------------------------------------------------------------------------*/ +public: + paramList(unsigned int const paramCount = 0); + + void + add(xmlrpc_c::value const param); + + unsigned int + size() const; + + xmlrpc_c::value operator[](unsigned int const subscript) const; + + int + getInt(unsigned int const paramNumber, + int const minimum = INT_MIN, + int const maximum = INT_MAX) const; + + bool + getBoolean(unsigned int const paramNumber) const; + + double + getDouble(unsigned int const paramNumber, + double const minimum = -DBL_MAX, + double const maximum = DBL_MAX) const; + + enum timeConstraint {TC_ANY, TC_NO_PAST, TC_NO_FUTURE}; + + time_t + getDatetime_sec(unsigned int const paramNumber, + timeConstraint const constraint + = paramList::TC_ANY) const; + + std::string + getString(unsigned int const paramNumber) const; + + std::vector + getBytestring(unsigned int const paramNumber) const; + + std::vector + getArray(unsigned int const paramNumber, + unsigned int const minSize = 0, + unsigned int const maxSize = UINT_MAX) const; + + std::map + getStruct(unsigned int const paramNumber) const; + + void + getNil(unsigned int const paramNumber) const; + + void + verifyEnd(unsigned int const paramNumber) const; + +private: + std::vector paramVector; +}; + +} // namespace + +#endif diff --git a/include/xmlrpc-c/base64.hpp b/include/xmlrpc-c/base64.hpp new file mode 100644 index 0000000..a884225 --- /dev/null +++ b/include/xmlrpc-c/base64.hpp @@ -0,0 +1,25 @@ +#ifndef XMLRPC_BASE64_HPP_INCLUDED +#define XMLRPC_BASE64_HPP_INCLUDED + +#include +#include + +namespace xmlrpc_c { + + +enum newlineCtl {NEWLINE_NO, NEWLINE_YES}; + +std::string +base64FromBytes( + std::vector const& bytes, + xmlrpc_c::newlineCtl const newlineCtl = xmlrpc_c::NEWLINE_YES); + + + +std::vector +bytesFromBase64(std::string const& base64); + + +} // namespace + +#endif diff --git a/include/xmlrpc-c/base_int.h b/include/xmlrpc-c/base_int.h new file mode 100644 index 0000000..cd5ef3e --- /dev/null +++ b/include/xmlrpc-c/base_int.h @@ -0,0 +1,176 @@ +/*============================================================================ + base_int.h +============================================================================== + This header file defines the interface between modules inside + xmlrpc-c. + + Use this in addition to xmlrpc.h, which defines the external + interface. + + Copyright information is at the end of the file. +============================================================================*/ + + +#ifndef XMLRPC_C_BASE_INT_H_INCLUDED +#define XMLRPC_C_BASE_INT_H_INCLUDED + +#include "xmlrpc_config.h" +#include "bool.h" + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + + +struct _xmlrpc_value { + xmlrpc_type _type; + int _refcount; + + /* Certain data types store their data directly in the xmlrpc_value. */ + union { + xmlrpc_int32 i; + xmlrpc_bool b; + double d; + /* time_t t */ + void *c_ptr; + } _value; + + /* Other data types use a memory block. + + For a string, this is the characters of the string in UTF-8, plus + a NUL added to the end. + */ + xmlrpc_mem_block _block; + + xmlrpc_mem_block *_wcs_block; + /* This is a copy of the string value in _block, but in UTF-16 + instead of UTF-8. This member is not always present. If NULL, + it is not present. + + We keep this copy for convenience. The value is totally + redundant with _block. + + This member is always NULL when the data type is not string. + + This member is always NULL on a system that does not have + Unicode wchar functions. + */ +}; + +#define XMLRPC_ASSERT_VALUE_OK(val) \ + XMLRPC_ASSERT((val) != NULL && (val)->_type != XMLRPC_TYPE_DEAD) + +/* A handy type-checking routine. */ +#define XMLRPC_TYPE_CHECK(env,v,t) \ + do \ + if ((v)->_type != (t)) \ + XMLRPC_FAIL(env, XMLRPC_TYPE_ERROR, "Expected " #t); \ + while (0) + + +typedef struct { + unsigned char key_hash; + xmlrpc_value *key; + xmlrpc_value *value; +} _struct_member; + + +void +xmlrpc_createXmlrpcValue(xmlrpc_env * const envP, + xmlrpc_value ** const valPP); + +const char * +xmlrpc_typeName(xmlrpc_type const type); + +void +xmlrpc_traceXml(const char * const label, + const char * const xml, + unsigned int const xmlLength); + +void +xmlrpc_destroyStruct(xmlrpc_value * const structP); + +void +xmlrpc_destroyArrayContents(xmlrpc_value * const arrayP); + +/*---------------------------------------------------------------------------- + The following are for use by the legacy xmlrpc_parse_value(). They don't + do proper memory management, so they aren't appropriate for general use, + but there are old users that do xmlrpc_parse_value() and compensate for + the memory management, so we have to continue to offer this style of + memory management. + + In particular, the functions that return xmlrpc_values don't increment + the reference count, and the functions that return strings don't allocate + new memory for them. +-----------------------------------------------------------------------------*/ + +void +xmlrpc_read_datetime_str_old(xmlrpc_env * const envP, + const xmlrpc_value * const valueP, + const char ** const stringValueP); + +void +xmlrpc_read_string_old(xmlrpc_env * const envP, + const xmlrpc_value * const valueP, + const char ** const stringValueP); + +void +xmlrpc_read_string_lp_old(xmlrpc_env * const envP, + const xmlrpc_value * const valueP, + size_t * const lengthP, + const char ** const stringValueP); + +#if XMLRPC_HAVE_WCHAR +void +xmlrpc_read_string_w_old(xmlrpc_env * const envP, + xmlrpc_value * const valueP, + const wchar_t ** const stringValueP); + +void +xmlrpc_read_string_w_lp_old(xmlrpc_env * const envP, + xmlrpc_value * const valueP, + size_t * const lengthP, + const wchar_t ** const stringValueP); +#endif + +void +xmlrpc_read_base64_old(xmlrpc_env * const envP, + const xmlrpc_value * const valueP, + size_t * const lengthP, + const unsigned char ** const byteStringValueP); + + +/* Copyright (C) 2001 by First Peer, Inc. All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +** ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +** OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +** HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +** LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +** OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +** SUCH DAMAGE. */ + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/include/xmlrpc-c/client.h b/include/xmlrpc-c/client.h new file mode 100644 index 0000000..6e08ea1 --- /dev/null +++ b/include/xmlrpc-c/client.h @@ -0,0 +1,246 @@ +/*============================================================================ + xmlrpc_client.h +============================================================================== + This header file defines the interface between xmlrpc.c and its users, + related to clients. + + Copyright information is at the end of the file. +============================================================================*/ + +#ifndef XMLRPC_CLIENT_H_INCLUDED +#define XMLRPC_CLIENT_H_INCLUDED + +#include + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +struct xmlrpc_client; +#ifndef __cplusplus +typedef struct xmlrpc_client xmlrpc_client; +#endif + +struct xmlrpc_xportparms; + /* This is a "base class". The struct is never complete; you're + supposed to cast between struct xmlrpc_xportparms * and + "struct xmlrpc_..._xportparms *" in order to use it. + */ + +enum xmlrpc_sslversion { + XMLRPC_SSLVERSION_DEFAULT, + XMLRPC_SSLVERSION_TLSv1, + XMLRPC_SSLVERSION_SSLv2, + XMLRPC_SSLVERSION_SSLv3 +}; + +struct xmlrpc_curl_xportparms { + /* This is designed so that zero values are always the defaults. */ + const char * network_interface; + xmlrpc_bool no_ssl_verifypeer; + xmlrpc_bool no_ssl_verifyhost; + const char * user_agent; + const char * ssl_cert; + const char * sslcerttype; + const char * sslcertpasswd; + const char * sslkey; + const char * sslkeytype; + const char * sslkeypasswd; + const char * sslengine; + xmlrpc_bool sslengine_default; + enum xmlrpc_sslversion sslversion; + const char * cainfo; + const char * capath; + const char * randomfile; + const char * egdsocket; + const char * ssl_cipher_list; +}; + + +#define XMLRPC_CXPSIZE(mbrname) \ + XMLRPC_STRUCTSIZE(struct xmlrpc_curl_xportparms, mbrname) + +/* XMLRPC_CXPSIZE(xyz) is analogous to XMLRPC_CPSIZE, below */ + +struct xmlrpc_wininet_xportparms { + int allowInvalidSSLCerts; +}; + +#define XMLRPC_WXPSIZE(mbrname) \ + XMLRPC_STRUCTSIZE(struct xmlrpc_wininet_xportparms, mbrname) + +/* XMLRPC_WXPSIZE(xyz) is analogous to XMLRPC_CPSIZE, below */ + +struct xmlrpc_clientparms { + const char * transport; + struct xmlrpc_xportparms * transportparmsP; + /* Cast a "struct ..._xportparms *" to fit here */ + size_t transportparm_size; +}; + +#define XMLRPC_CPSIZE(mbrname) \ + XMLRPC_STRUCTSIZE(struct xmlrpc_clientparms, mbrname) + +/* XMLRPC_CPSIZE(xyz) is the minimum size a struct xmlrpc_clientparms + must be to include the 'xyz' member. This is essential to forward and + backward compatbility, as new members will be added to the end of the + struct in future releases. This is how the callee knows whether or + not the caller is new enough to have supplied a certain parameter. +*/ + +const char * +xmlrpc_client_get_default_transport(xmlrpc_env * const env); + +/* A callback function to handle the response to an asynchronous call. +** If 'fault->fault_occurred' is true, then response will be NULL. All +** arguments except 'user_data' will be deallocated internally; please do +** not free any of them yourself. +** WARNING: param_array may (or may not) be NULL if fault->fault_occurred +** is true, and you set up the call using xmlrpc_client_call_asynch. +** WARNING: If asynchronous calls are still pending when the library is +** shut down, your handler may (or may not) be called with a fault. */ +typedef void (*xmlrpc_response_handler) (const char *server_url, + const char *method_name, + xmlrpc_value *param_array, + void *user_data, + xmlrpc_env *fault, + xmlrpc_value *result); + + +/*========================================================================= +** xmlrpc_server_info +**========================================================================= +** We normally refer to servers by URL. But sometimes we need to do extra +** setup for particular servers. In that case, we can create an +** xmlrpc_server_info object, configure it in various ways, and call the +** remote server. +** +** (This interface is also designed to discourage further multiplication +** of xmlrpc_client_call APIs. We have enough of those already. Please +** add future options and flags using xmlrpc_server_info.) +*/ + +typedef struct _xmlrpc_server_info xmlrpc_server_info; + +/* Create a new server info record, pointing to the specified server. */ +xmlrpc_server_info * +xmlrpc_server_info_new(xmlrpc_env * const env, + const char * const server_url); + +/* Create a new server info record, with a copy of the old server. */ +extern xmlrpc_server_info * +xmlrpc_server_info_copy(xmlrpc_env *env, xmlrpc_server_info *src_server); + +/* Delete a server info record. */ +extern void +xmlrpc_server_info_free (xmlrpc_server_info *server); + +void +xmlrpc_server_info_set_basic_auth(xmlrpc_env * const envP, + xmlrpc_server_info * const serverP, + const char * const username, + const char * const password); + + +void +xmlrpc_client_setup_global_const(xmlrpc_env * const envP); + +void +xmlrpc_client_teardown_global_const(void); + +void +xmlrpc_client_create(xmlrpc_env * const envP, + int const flags, + const char * const appname, + const char * const appversion, + const struct xmlrpc_clientparms * const clientparmsP, + unsigned int const parmSize, + xmlrpc_client ** const clientPP); + +void +xmlrpc_client_destroy(xmlrpc_client * const clientP); + +void +xmlrpc_client_transport_call2( + xmlrpc_env * const envP, + xmlrpc_client * const clientP, + const xmlrpc_server_info * const serverP, + xmlrpc_mem_block * const callXmlP, + xmlrpc_mem_block ** const respXmlPP); + +void +xmlrpc_client_call2(xmlrpc_env * const envP, + struct xmlrpc_client * const clientP, + const xmlrpc_server_info * const serverInfoP, + const char * const methodName, + xmlrpc_value * const paramArrayP, + xmlrpc_value ** const resultPP); + +void +xmlrpc_client_call2f(xmlrpc_env * const envP, + xmlrpc_client * const clientP, + const char * const serverUrl, + const char * const methodName, + xmlrpc_value ** const resultPP, + const char * const format, + ...); + +void +xmlrpc_client_event_loop_finish(xmlrpc_client * const clientP); + +void +xmlrpc_client_event_loop_finish_timeout(xmlrpc_client * const clientP, + unsigned long const milliseconds); + +void +xmlrpc_client_start_rpc(xmlrpc_env * const envP, + struct xmlrpc_client * const clientP, + xmlrpc_server_info * const serverInfoP, + const char * const methodName, + xmlrpc_value * const argP, + xmlrpc_response_handler responseHandler, + void * const userData); + +void +xmlrpc_client_start_rpcf(xmlrpc_env * const envP, + xmlrpc_client * const clientP, + const char * const serverUrl, + const char * const methodName, + xmlrpc_response_handler callback, + void * const userData, + const char * const format, + ...); + +#include + +/* Copyright (C) 2001 by First Peer, Inc. All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +** ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +** OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +** HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +** LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +** OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +** SUCH DAMAGE. */ + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* _XMLRPC_CLIENT_H_ */ diff --git a/include/xmlrpc-c/client.hpp b/include/xmlrpc-c/client.hpp new file mode 100644 index 0000000..846ad9b --- /dev/null +++ b/include/xmlrpc-c/client.hpp @@ -0,0 +1,283 @@ +#ifndef CLIENT_HPP_INCLUDED +#define CLIENT_HPP_INCLUDED + +#include +#include +#include + +#include +#include +#include +#include +#include + +namespace xmlrpc_c { + +class clientTransactionPtr; + +class clientTransaction : public girmem::autoObject { + + friend class clientTransactionPtr; + +public: + virtual void + finish(xmlrpc_c::rpcOutcome const& outcome) = 0; + + virtual void + finishErr(girerr::error const& error) = 0; + +protected: + clientTransaction(); +}; + +class clientTransactionPtr : public girmem::autoObjectPtr { + +public: + clientTransactionPtr(); + + virtual ~clientTransactionPtr(); + + virtual xmlrpc_c::clientTransaction * + operator->() const; +}; + +class clientPtr; + +class client : public girmem::autoObject { +/*---------------------------------------------------------------------------- + A generic client -- a means of performing an RPC. This is so generic + that it can be used for clients that are not XML-RPC. + + This is a base class. Derived classes define things such as that + XML and HTTP get used to perform the RPC. +-----------------------------------------------------------------------------*/ + friend class clientTransactionPtr; + +public: + virtual ~client(); + + virtual void + call(xmlrpc_c::carriageParm * const carriageParmP, + std::string const& methodName, + xmlrpc_c::paramList const& paramList, + xmlrpc_c::rpcOutcome * const outcomeP) = 0; + + virtual void + start(xmlrpc_c::carriageParm * const carriageParmP, + std::string const& methodName, + xmlrpc_c::paramList const& paramList, + xmlrpc_c::clientTransactionPtr const& tranP); +}; + +class clientPtr : public girmem::autoObjectPtr { +public: + clientPtr(); + + explicit clientPtr(xmlrpc_c::client * const clientP); + + xmlrpc_c::client * + operator->() const; + + xmlrpc_c::client * + get() const; +}; + +class serverAccessor : public girmem::autoObject { + +public: + serverAccessor(xmlrpc_c::clientPtr const clientP, + xmlrpc_c::carriageParmPtr const carriageParmP); + + void + call(std::string const& methodName, + xmlrpc_c::paramList const& paramList, + xmlrpc_c::rpcOutcome * const outcomeP) const; + +private: + xmlrpc_c::clientPtr const clientP; + xmlrpc_c::carriageParmPtr const carriageParmP; +}; + +class serverAccessorPtr : public girmem::autoObjectPtr { +public: + serverAccessorPtr(); + + explicit + serverAccessorPtr(xmlrpc_c::serverAccessor * const serverAccessorP); + + xmlrpc_c::serverAccessor * + operator->() const; + + xmlrpc_c::serverAccessor * + get() const; +}; + +class connection { +/*---------------------------------------------------------------------------- + A nexus of a particular client and a particular server, along with + carriage parameters for performing RPCs between the two. + + This is a minor convenience for client programs that always talk to + the same server the same way. + + Use this as a parameter to rpc.call(). +-----------------------------------------------------------------------------*/ +public: + connection(xmlrpc_c::client * const clientP, + xmlrpc_c::carriageParm * const carriageParmP); + + ~connection(); + + xmlrpc_c::client * clientP; + xmlrpc_c::carriageParm * carriageParmP; +}; + +class client_xml : public xmlrpc_c::client { +/*---------------------------------------------------------------------------- + A client that uses XML-RPC XML in the RPC. This class does not define + how the XML gets transported, though (i.e. does not require HTTP). +-----------------------------------------------------------------------------*/ +public: + client_xml(xmlrpc_c::clientXmlTransport * const transportP); + + client_xml(xmlrpc_c::clientXmlTransportPtr const transportP); + + void + call(carriageParm * const carriageParmP, + std::string const& methodName, + xmlrpc_c::paramList const& paramList, + xmlrpc_c::rpcOutcome * const outcomeP); + + void + start(xmlrpc_c::carriageParm * const carriageParmP, + std::string const& methodName, + xmlrpc_c::paramList const& paramList, + xmlrpc_c::clientTransactionPtr const& tranP); + + void + finishAsync(xmlrpc_c::timeout const timeout); + +private: + /* We have both kinds of pointers to give the user flexibility -- we + have constructors that take both. But the simple pointer + 'transportP' is valid in both cases. + */ + xmlrpc_c::clientXmlTransport * transportP; + xmlrpc_c::clientXmlTransportPtr transportPtr; +}; + +class xmlTransaction_client : public xmlrpc_c::xmlTransaction { + +public: + xmlTransaction_client(xmlrpc_c::clientTransactionPtr const& tranP); + + void + finish(std::string const& responseXml) const; + + void + finishErr(girerr::error const& error) const; +private: + xmlrpc_c::clientTransactionPtr const tranP; +}; + +class xmlTransaction_clientPtr : public xmlTransactionPtr { +public: + xmlTransaction_clientPtr(); + + xmlTransaction_clientPtr(xmlrpc_c::clientTransactionPtr const& tranP); + + xmlrpc_c::xmlTransaction_client * + operator->() const; +}; + +class rpcPtr; + +class rpc : public clientTransaction { +/*---------------------------------------------------------------------------- + An RPC. An RPC consists of method name, parameters, and result. It + does not specify in any way how the method name and parameters get + turned into a result. It does not presume XML or HTTP. + + You don't create an object of this class directly. All references to + an rpc object should be by an rpcPtr object. Create a new RPC by + creating a new rpcPtr. Accordingly, our constructors and destructors + are protected, but available to our friend class rpcPtr. + + In order to do asynchronous RPCs, you normally have to create a derived + class that defines a useful notifyComplete(). If you do that, you'll + want to make sure the derived class objects get accessed only via rpcPtrs + as well. +-----------------------------------------------------------------------------*/ + friend class xmlrpc_c::rpcPtr; + +public: + void + call(xmlrpc_c::client * const clientP, + xmlrpc_c::carriageParm * const carriageParmP); + + void + call(xmlrpc_c::connection const& connection); + + void + start(xmlrpc_c::client * const clientP, + xmlrpc_c::carriageParm * const carriageParmP); + + void + start(xmlrpc_c::connection const& connection); + + void + finish(xmlrpc_c::rpcOutcome const& outcome); + + void + finishErr(girerr::error const& error); + + virtual void + notifyComplete(); + + bool + isFinished() const; + + bool + isSuccessful() const; + + xmlrpc_c::value + getResult() const; + + xmlrpc_c::fault + getFault() const; + + rpc(std::string const methodName, + xmlrpc_c::paramList const& paramList); + + virtual ~rpc(); + +private: + enum state { + STATE_UNFINISHED, // RPC is running or not started yet + STATE_ERROR, // We couldn't execute the RPC + STATE_FAILED, // RPC executed successfully, but failed per XML-RPC + STATE_SUCCEEDED // RPC is done, no exception + }; + enum state state; + girerr::error * errorP; // Defined only in STATE_ERROR + xmlrpc_c::rpcOutcome outcome; + // Defined only in STATE_FAILED and STATE_SUCCEEDED + std::string methodName; + xmlrpc_c::paramList paramList; +}; + +class rpcPtr : public clientTransactionPtr { +public: + rpcPtr(); + + explicit rpcPtr(xmlrpc_c::rpc * const rpcP); + + rpcPtr(std::string const methodName, + xmlrpc_c::paramList const& paramList); + + xmlrpc_c::rpc * + operator->() const; +}; + +} // namespace +#endif diff --git a/include/xmlrpc-c/client_global.h b/include/xmlrpc-c/client_global.h new file mode 100644 index 0000000..23b4e85 --- /dev/null +++ b/include/xmlrpc-c/client_global.h @@ -0,0 +1,141 @@ +#ifndef CLIENT_GLOBAL_H_INCLUDED +#define CLIENT_GLOBAL_H_INCLUDED + +/*========================================================================= +** Initialization and Shutdown +**========================================================================= +** These routines initialize and terminate the XML-RPC client. If you're +** already using libwww on your own, you can pass +** XMLRPC_CLIENT_SKIP_LIBWWW_INIT to avoid initializing it twice. +*/ + +#define XMLRPC_CLIENT_NO_FLAGS (0) +#define XMLRPC_CLIENT_SKIP_LIBWWW_INIT (1) + +extern void +xmlrpc_client_init(int const flags, + const char * const appname, + const char * const appversion); + +void +xmlrpc_client_init2(xmlrpc_env * const env, + int const flags, + const char * const appname, + const char * const appversion, + const struct xmlrpc_clientparms * const clientparms, + unsigned int const parm_size); + +extern void +xmlrpc_client_cleanup(void); + +/*========================================================================= +** xmlrpc_client_call +**========================================================================= +** A synchronous XML-RPC client. Do not attempt to call any of these +** functions from inside an asynchronous callback! +*/ + +xmlrpc_value * +xmlrpc_client_call(xmlrpc_env * const envP, + const char * const server_url, + const char * const method_name, + const char * const format, + ...); + +xmlrpc_value * +xmlrpc_client_call_params(xmlrpc_env * const envP, + const char * const serverUrl, + const char * const methodName, + xmlrpc_value * const paramArrayP); + +xmlrpc_value * +xmlrpc_client_call_server(xmlrpc_env * const envP, + const xmlrpc_server_info * const server, + const char * const method_name, + const char * const format, + ...); + +xmlrpc_value * +xmlrpc_client_call_server_params( + xmlrpc_env * const envP, + const xmlrpc_server_info * const serverP, + const char * const method_name, + xmlrpc_value * const paramArrayP); + +void +xmlrpc_client_transport_call( + xmlrpc_env * const envP, + void * const reserved, /* for client handle */ + const xmlrpc_server_info * const serverP, + xmlrpc_mem_block * const callXmlP, + xmlrpc_mem_block ** const respXmlPP); + + +/*========================================================================= +** xmlrpc_client_call_asynch +**========================================================================= +** An asynchronous XML-RPC client. +*/ + +/* Make an asynchronous XML-RPC call. We make internal copies of all +** arguments except user_data, so you can deallocate them safely as soon +** as you return. Errors will be passed to the callback. You will need +** to run the event loop somehow; see below. +** WARNING: If an error occurs while building the argument, the +** response handler will be called with a NULL param_array. */ +void +xmlrpc_client_call_asynch(const char * const server_url, + const char * const method_name, + xmlrpc_response_handler callback, + void * const user_data, + const char * const format, + ...); + +/* As above, but use an xmlrpc_server_info object. The server object can be +** safely destroyed as soon as this function returns. */ +void +xmlrpc_client_call_server_asynch(xmlrpc_server_info * const server, + const char * const method_name, + xmlrpc_response_handler callback, + void * const user_data, + const char * const format, + ...); + +/* As above, but the parameter list is supplied as an xmlrpc_value +** containing an array. +*/ +void +xmlrpc_client_call_asynch_params(const char * const server_url, + const char * const method_name, + xmlrpc_response_handler callback, + void * const user_data, + xmlrpc_value * const paramArrayP); + +/* As above, but use an xmlrpc_server_info object. The server object can be +** safely destroyed as soon as this function returns. */ +void +xmlrpc_client_call_server_asynch_params( + xmlrpc_server_info * const server, + const char * const method_name, + xmlrpc_response_handler callback, + void * const user_data, + xmlrpc_value * const paramArrayP); + +/*========================================================================= +** Event Loop Interface +**========================================================================= +** These functions can be used to run the XML-RPC event loop. If you +** don't like these, you can also run the libwww event loop directly. +*/ + +/* Finish all outstanding asynchronous calls. Alternatively, the loop +** will exit if someone calls xmlrpc_client_event_loop_end. */ +extern void +xmlrpc_client_event_loop_finish_asynch(void); + + +/* Finish all outstanding asynchronous calls. */ +extern void +xmlrpc_client_event_loop_finish_asynch_timeout(unsigned long milliseconds); + +#endif diff --git a/include/xmlrpc-c/client_int.h b/include/xmlrpc-c/client_int.h new file mode 100644 index 0000000..a7ef2bc --- /dev/null +++ b/include/xmlrpc-c/client_int.h @@ -0,0 +1,102 @@ +/*============================================================================ + xmlrpc_client_int.h +============================================================================== + This header file defines the interface between client modules inside + xmlrpc-c. + + Use this in addition to xmlrpc_client.h, which defines the external + interface. + + Copyright information is at the end of the file. +============================================================================*/ + + +#ifndef XMLRPC_CLIENT_INT_H_INCLUDED +#define XMLRPC_CLIENT_INT_H_INCLUDED + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +struct _xmlrpc_server_info { + char *_server_url; + char *_http_basic_auth; +}; + +/* Create a new server info record, with a copy of the old server. */ +extern xmlrpc_server_info * +xmlrpc_server_info_copy(xmlrpc_env *env, xmlrpc_server_info *aserver); + + +/*========================================================================= +** Transport Implementation functions. +**========================================================================= +*/ +#include "xmlrpc-c/transport.h" + +/* The generalized event loop. This uses the above flags. For more details, +** see the wrapper functions below. If you're not using the timeout, the +** 'milliseconds' parameter will be ignored. +** Note that ANY event loop call will return immediately if there are +** no outstanding XML-RPC calls. */ +extern void +xmlrpc_client_event_loop_run_general (int flags, xmlrpc_timeout milliseconds); + +/* Run the event loop forever. The loop will exit if someone calls +** xmlrpc_client_event_loop_end. */ +extern void +xmlrpc_client_event_loop_run (void); + +/* Run the event loop forever. The loop will exit if someone calls +** xmlrpc_client_event_loop_end or the timeout expires. +** (Note that ANY event loop call will return immediately if there are +** no outstanding XML-RPC calls.) */ +extern void +xmlrpc_client_event_loop_run_timeout (xmlrpc_timeout milliseconds); + +/* End the running event loop immediately. This can also be accomplished +** by calling the corresponding function in libwww. +** (Note that ANY event loop call will return immediately if there are +** no outstanding XML-RPC calls.) */ +extern void +xmlrpc_client_event_loop_end (void); + + +/* Return true if there are uncompleted asynchronous calls. +** The exact value of this during a response callback is undefined. */ +extern int +xmlrpc_client_asynch_calls_are_unfinished (void); + +/* Copyright (C) 2001 by First Peer, Inc. All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +** ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +** OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +** HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +** LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +** OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +** SUCH DAMAGE. */ + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif + + + diff --git a/include/xmlrpc-c/client_simple.hpp b/include/xmlrpc-c/client_simple.hpp new file mode 100644 index 0000000..52e6c2b --- /dev/null +++ b/include/xmlrpc-c/client_simple.hpp @@ -0,0 +1,44 @@ +#ifndef CLIENT_SIMPLE_HPP_INCLUDED +#define CLIENT_SIMPLE_HPP_INCLUDED + +#include + +#include +#include + +namespace xmlrpc_c { + + +class clientSimple { + +public: + clientSimple(); + + void + call(std::string const serverUrl, + std::string const methodName, + xmlrpc_c::value * const resultP); + + void + call(std::string const serverUrl, + std::string const methodName, + std::string const format, + xmlrpc_c::value * const resultP, + ...); + + void + call(std::string const serverUrl, + std::string const methodName, + xmlrpc_c::paramList const& paramList, + xmlrpc_c::value * const resultP); + +private: + xmlrpc_c::clientPtr clientP; +}; + +} // namespace +#endif + + + + diff --git a/include/xmlrpc-c/client_transport.hpp b/include/xmlrpc-c/client_transport.hpp new file mode 100644 index 0000000..f16cac0 --- /dev/null +++ b/include/xmlrpc-c/client_transport.hpp @@ -0,0 +1,342 @@ +#ifndef CLIENT_TRANSPORT_HPP_INCLUDED +#define CLIENT_TRANSPORT_HPP_INCLUDED + +#include +#include +#include +#include +#include +#include +#include + +namespace xmlrpc_c { + +class carriageParmPtr; + +class carriageParm : public girmem::autoObject { +/*---------------------------------------------------------------------------- + The parameter to a client for an individual RPC. It tells specifics + of how to carry the call to the server and the response back. For + example, it may identify the server. It may identify communication + protocols to use. It may indicate permission and accounting + information. + + This is a base class; the carriage parameter is specific to the + class of client. For example, an HTTP-based client would have a + URL and HTTP basic authentication info as parameter. +-----------------------------------------------------------------------------*/ +protected: + virtual ~carriageParm(); + carriageParm(); +}; + +class carriageParmPtr : public girmem::autoObjectPtr { + +public: + carriageParmPtr(); + + explicit carriageParmPtr(xmlrpc_c::carriageParm * const carriageParmP); + + xmlrpc_c::carriageParm * + operator->() const; + + xmlrpc_c::carriageParm * + get() const; +}; + +class carriageParm_http0 : public xmlrpc_c::carriageParm { + +public: + carriageParm_http0(std::string const serverUrl); + + ~carriageParm_http0(); + + void + setBasicAuth(std::string const userid, + std::string const password); + + xmlrpc_server_info * c_serverInfoP; + +protected: + // Only a derived class is allowed to create an object with no + // server URL, and the derived class is expected to follow it up + // with an instantiate() to establish the server URL. + + carriageParm_http0(); + + void + instantiate(std::string const serverUrl); +}; + +class carriageParm_http0Ptr : public xmlrpc_c::carriageParmPtr { + +public: + carriageParm_http0Ptr(); + carriageParm_http0Ptr(xmlrpc_c::carriageParm_http0 * const carriageParmP); + + xmlrpc_c::carriageParm_http0 * + operator->() const; +}; + +class carriageParm_curl0 : public xmlrpc_c::carriageParm_http0 { + +public: + carriageParm_curl0(std::string const serverUrl); + +}; + +class carriageParm_curl0Ptr : public xmlrpc_c::carriageParm_http0Ptr { + +public: + carriageParm_curl0Ptr(); + carriageParm_curl0Ptr(xmlrpc_c::carriageParm_curl0 * const carriageParmP); + + xmlrpc_c::carriageParm_curl0 * + operator->() const; +}; + +class carriageParm_libwww0 : public xmlrpc_c::carriageParm_http0 { + +public: + carriageParm_libwww0(std::string const serverUrl); + +}; + +class carriageParm_libwww0Ptr : public xmlrpc_c::carriageParm_http0Ptr { + +public: + carriageParm_libwww0Ptr(); + carriageParm_libwww0Ptr(xmlrpc_c::carriageParm_libwww0 * const); + + xmlrpc_c::carriageParm_libwww0 * + operator->() const; +}; + +class carriageParm_wininet0 : public xmlrpc_c::carriageParm_http0 { + +public: + carriageParm_wininet0(std::string const serverUrl); + +}; + +class carriageParm_wininet0Ptr : public xmlrpc_c::carriageParm_http0Ptr { + +public: + carriageParm_wininet0Ptr(); + carriageParm_wininet0Ptr(xmlrpc_c::carriageParm_wininet0 * const); + + xmlrpc_c::carriageParm_wininet0 * + operator->() const; +}; + +//---------------------------------------------------------------------------- + +class xmlTransactionPtr; + +class xmlTransaction : public girmem::autoObject { + + friend class xmlTransactionPtr; + +public: + virtual void + finish(std::string const& responseXml) const; + + virtual void + finishErr(girerr::error const& error) const; + +protected: + xmlTransaction(); +}; + +class xmlTransactionPtr : public girmem::autoObjectPtr { +public: + xmlTransactionPtr(); + + xmlrpc_c::xmlTransaction * + operator->() const; +}; + +//---------------------------------------------------------------------------- + +class clientXmlTransport : public girmem::autoObject { +/*---------------------------------------------------------------------------- + An object which transports XML to and from an XML-RPC server for an + XML-RPC client. + + This is a base class. Derived classes define methods to perform the + transportation in particular ways. +-----------------------------------------------------------------------------*/ +public: + virtual ~clientXmlTransport(); + + virtual void + call(xmlrpc_c::carriageParm * const carriageParmP, + std::string const& callXml, + std::string * const responseXmlP) = 0; + + virtual void + start(xmlrpc_c::carriageParm * const carriageParmP, + std::string const& callXml, + xmlrpc_c::xmlTransactionPtr const& xmlTranP); + + virtual void + finishAsync(xmlrpc_c::timeout const timeout); + + static void + asyncComplete( + struct xmlrpc_call_info * const callInfoP, + xmlrpc_mem_block * const responseXmlMP, + xmlrpc_env const transportEnv); +}; + +class clientXmlTransportPtr : public girmem::autoObjectPtr { + +public: + clientXmlTransportPtr(); + + clientXmlTransportPtr(xmlrpc_c::clientXmlTransport * const transportP); + + xmlrpc_c::clientXmlTransport * + operator->() const; + + xmlrpc_c::clientXmlTransport * + get() const; +}; + +class clientXmlTransport_http : public xmlrpc_c::clientXmlTransport { +/*---------------------------------------------------------------------------- + A base class for client XML transports that use the simple, classic + C HTTP transports. +-----------------------------------------------------------------------------*/ +public: + virtual ~clientXmlTransport_http(); + + void + call(xmlrpc_c::carriageParm * const carriageParmP, + std::string const& callXml, + std::string * const responseXmlP); + + void + start(xmlrpc_c::carriageParm * const carriageParmP, + std::string const& callXml, + xmlrpc_c::xmlTransactionPtr const& xmlTranP); + + virtual void + finishAsync(xmlrpc_c::timeout const timeout); + + static std::vector + availableTypes(); + + static clientXmlTransportPtr + create(); + +protected: + clientXmlTransport_http() {} // ensure no one can create + struct xmlrpc_client_transport * c_transportP; + const struct xmlrpc_client_transport_ops * c_transportOpsP; +}; + + +class clientXmlTransport_curl : public xmlrpc_c::clientXmlTransport_http { + +public: + class constrOpt { + public: + constrOpt(); + + constrOpt & network_interface (std::string const& arg); + constrOpt & no_ssl_verifypeer (bool const& arg); + constrOpt & no_ssl_verifyhost (bool const& arg); + constrOpt & user_agent (std::string const& arg); + constrOpt & ssl_cert (std::string const& arg); + constrOpt & sslcerttype (std::string const& arg); + constrOpt & sslcertpasswd (std::string const& arg); + constrOpt & sslkey (std::string const& arg); + constrOpt & sslkeytype (std::string const& arg); + constrOpt & sslkeypasswd (std::string const& arg); + constrOpt & sslengine (std::string const& arg); + constrOpt & sslengine_default (bool const& arg); + constrOpt & sslversion (xmlrpc_sslversion const& arg); + constrOpt & cainfo (std::string const& arg); + constrOpt & capath (std::string const& arg); + constrOpt & randomfile (std::string const& arg); + constrOpt & egdsocket (std::string const& arg); + constrOpt & ssl_cipher_list (std::string const& arg); + + struct { + std::string network_interface; + bool no_ssl_verifypeer; + bool no_ssl_verifyhost; + std::string user_agent; + std::string ssl_cert; + std::string sslcerttype; + std::string sslcertpasswd; + std::string sslkey; + std::string sslkeytype; + std::string sslkeypasswd; + std::string sslengine; + bool sslengine_default; + xmlrpc_sslversion sslversion; + std::string cainfo; + std::string capath; + std::string randomfile; + std::string egdsocket; + std::string ssl_cipher_list; + } value; + struct { + bool network_interface; + bool no_ssl_verifypeer; + bool no_ssl_verifyhost; + bool user_agent; + bool ssl_cert; + bool sslcerttype; + bool sslcertpasswd; + bool sslkey; + bool sslkeytype; + bool sslkeypasswd; + bool sslengine; + bool sslengine_default; + bool sslversion; + bool cainfo; + bool capath; + bool randomfile; + bool egdsocket; + bool ssl_cipher_list; + } present; + }; + + clientXmlTransport_curl(constrOpt const& opt); + + clientXmlTransport_curl(std::string const networkInterface = "", + bool const noSslVerifyPeer = false, + bool const noSslVerifyHost = false, + std::string const userAgent = ""); + + ~clientXmlTransport_curl(); + +private: + void + initialize(constrOpt const& opt); +}; + +class clientXmlTransport_libwww : public xmlrpc_c::clientXmlTransport_http { + +public: + clientXmlTransport_libwww(std::string const appname = "", + std::string const appversion = ""); + + ~clientXmlTransport_libwww(); +}; + +class clientXmlTransport_wininet : public xmlrpc_c::clientXmlTransport_http { + +public: + clientXmlTransport_wininet(bool const allowInvalidSslCerts = false); + + ~clientXmlTransport_wininet(); +}; + + + +} // namespace +#endif diff --git a/include/xmlrpc-c/girerr.hpp b/include/xmlrpc-c/girerr.hpp new file mode 100644 index 0000000..1008722 --- /dev/null +++ b/include/xmlrpc-c/girerr.hpp @@ -0,0 +1,31 @@ +#ifndef GIRERR_HPP_INCLUDED +#define GIRERR_HPP_INCLUDED + +#include +#include + +#define HAVE_GIRERR_ERROR + +namespace girerr { + +class error : public std::exception { +public: + error(std::string const& what_arg) : _what(what_arg) {} + + ~error() throw() {} + + virtual const char * + what() const throw() { return this->_what.c_str(); }; + +private: + std::string _what; +}; + +// throwf() always throws a girerr::error . + +void +throwf(const char * const format, ...); + +} // namespace + +#endif diff --git a/include/xmlrpc-c/girmem.hpp b/include/xmlrpc-c/girmem.hpp new file mode 100644 index 0000000..0113046 --- /dev/null +++ b/include/xmlrpc-c/girmem.hpp @@ -0,0 +1,74 @@ +#ifndef GIRMEM_HPP_INCLUDED +#define GIRMEM_HPP_INCLUDED + + +/* The following pthread crap mirrors what is in pthreadx.h, which is + what girmem.cpp uses to declare the lock interface. We can't simply + include pthreadx.h here, because it's an internal Xmlrpc-c header file, + and this is an external one. + + This is a stopgap measure until we do something cleaner, such as expose + pthreadx.h as an external interface (class girlock, maybe?) or create + a lock class with virtual methods. + + The problem we're solving is that class autoObject contains + a pthread_mutex_t member, and on Windows, there's no such type. +*/ + +#ifndef WIN32 +# include + typedef pthread_mutex_t girmem_lock; +#else + typedef CRITICAL_SECTION girmem_lock; +#endif + +namespace girmem { + +class autoObjectPtr; + +class autoObject { + friend class autoObjectPtr; + +public: + void incref(); + void decref(bool * const unreferencedP); + +protected: + autoObject(); + virtual ~autoObject(); + +private: + girmem_lock refcountLock; + unsigned int refcount; +}; + +class autoObjectPtr { +public: + autoObjectPtr(); + autoObjectPtr(girmem::autoObject * objectP); + autoObjectPtr(girmem::autoObjectPtr const& autoObjectPtr); + + ~autoObjectPtr(); + + void + point(girmem::autoObject * const objectP); + + void + unpoint(); + + autoObjectPtr + operator=(girmem::autoObjectPtr const& objectPtr); + + girmem::autoObject * + operator->() const; + + girmem::autoObject * + get() const; + +protected: + girmem::autoObject * objectP; +}; + +} // namespace + +#endif diff --git a/include/xmlrpc-c/oldcppwrapper.hpp b/include/xmlrpc-c/oldcppwrapper.hpp new file mode 100644 index 0000000..22bc9c5 --- /dev/null +++ b/include/xmlrpc-c/oldcppwrapper.hpp @@ -0,0 +1,419 @@ +// -*- C++ -*- <-- an Emacs control + +// Copyright information is at the bottom of the file. + +//========================================================================= +// XML-RPC C++ API +//========================================================================= + + +#ifndef XMLRPCCPP_H_INCLUDED +#define XMLRPCCPP_H_INCLUDED + +// There used to be a "using namespace std" here and some confusing old +// comments about it having something to do with what header file you +// include to get string functions. +// +// "using namespace std" was under "#if defined(__GNUC__) && (__GNUC__ >= 3)" +// until December 2003, and then unconditional until Release 1.1 (March 2005). +// Older GNU Compilers apparently imply namespace std, so they don't need it. +// +// But "using namespace std" is a bad idea. This is an interface header +// file, and we don't want to suck all of namespace std into the user's +// namespace just because he's using Xmlrpc-c. So we took it out. +// We refer to std names like std::string. +// -Bryan 2005.03.12. + + +#include +#include +#include +#include +#include + + +//========================================================================= +// XmlRpcFault +//========================================================================= +// A C++ exception class representing an XML-RPC fault. + +class XmlRpcFault { + +private: + xmlrpc_env mFault; + + XmlRpcFault& operator= (XmlRpcFault const& f) + { if (true || f.getFaultCode()) abort(); return (XmlRpcFault&) f; } + +public: + XmlRpcFault (const XmlRpcFault &fault); + XmlRpcFault (const int faultCode, const std::string faultString); + XmlRpcFault (const xmlrpc_env *env); + ~XmlRpcFault (void); + + int getFaultCode (void) const; + std::string getFaultString (void) const; + xmlrpc_env *getFaultEnv (void); +}; + +inline int XmlRpcFault::getFaultCode (void) const { + return mFault.fault_code; +} + +inline xmlrpc_env *XmlRpcFault::getFaultEnv (void) { + return &mFault; +} + + +//========================================================================= +// XmlRpcEnv +//========================================================================= +// This class can be used to wrap xmlrpc_env object. Use it as follows: +// +// XmlRpcEnv env; +// xmlrpc_parse_value(env, v, "(i)", &i); +// env.throwIfFaultOccurred(); + +class XmlRpcEnv { + +private: + xmlrpc_env mEnv; + + void throwMe (void) const; + XmlRpcEnv& operator= (XmlRpcEnv const& e) + { if (true || e.faultOccurred()) abort(); return (XmlRpcEnv&) e;} + +public: + XmlRpcEnv (const XmlRpcEnv &env); + XmlRpcEnv (void) { xmlrpc_env_init(&mEnv); } + ~XmlRpcEnv (void) { xmlrpc_env_clean(&mEnv); } + + bool faultOccurred (void) const { return mEnv.fault_occurred; }; + bool hasFaultOccurred (void) const { return faultOccurred(); }; + /* hasFaultOccurred() is for backward compatibility. + faultOccurred() is a superior name for this. + */ + std::string getFaultString() const { return mEnv.fault_string; }; + XmlRpcFault getFault (void) const; + + void throwIfFaultOccurred (void) const; + + operator xmlrpc_env * (void) { return &mEnv; } +}; + +inline void XmlRpcEnv::throwIfFaultOccurred (void) const { + if (faultOccurred()) + throwMe(); +} + + +//========================================================================= +// XmlRpcValue +//========================================================================= +// An object in this class is an XML-RPC value. +// +// We have a complex structure to allow C code mixed in with C++ code +// which uses this class to refer to the same XML-RPC value object. +// This is especially important because there aren't proper C++ facilities +// for much of Xmlrpc-c; you have to use the C facilities even if you'd +// rather use proper C++. +// +// The XmlRpcValue object internally represents the value as an +// xmlrpc_value. It holds one reference to the xmlrpc_value. Users +// of XmlRpcValue never see that xmlrpc_value, but C code can. the +// C code might create the xmlrpc_value and then bind it to an XmlRpcValue, +// or it might get the xmlrpc_value handle from the XmlRpcValue. Finally, +// C code can simply use the XmlRpcValue where an xmlrpc_value handle is +// required and it gets converted automatically. +// +// So reference counting for the xmlrpc_value is quite a nightmare. + +class XmlRpcValue { + +private: + xmlrpc_value *mValue; + +public: + enum ReferenceBehavior { + MAKE_REFERENCE, + CONSUME_REFERENCE + }; + + typedef xmlrpc_int32 int32; + + XmlRpcValue (void); + XmlRpcValue (xmlrpc_value *value, + ReferenceBehavior behavior = MAKE_REFERENCE); + XmlRpcValue (const XmlRpcValue& value); + ~XmlRpcValue (void); + + XmlRpcValue& operator= (const XmlRpcValue& value); + + // Accessing the value's type (think of this as lightweight RTTI). + xmlrpc_type getType(void) const; + + // We don't supply an automatic conversion operator--you need to say + // whether you want to make or borrow this object's reference. + // XXX - Is it really OK for these to be const? + xmlrpc_value *makeReference (void) const; + xmlrpc_value *borrowReference (void) const; + + // Some static "constructor" functions. + static XmlRpcValue makeInt (const XmlRpcValue::int32 i); + static XmlRpcValue makeBool (const bool b); + static XmlRpcValue makeDouble (const double d); + static XmlRpcValue makeDateTime (const std::string& dateTime); + static XmlRpcValue makeString (const std::string& str); + static XmlRpcValue makeString (const char *const str); + static XmlRpcValue makeString (const char *const str, size_t len); + static XmlRpcValue makeArray (void); + static XmlRpcValue makeStruct (void); + static XmlRpcValue makeBase64 (const unsigned char *const data, + size_t len); + /* + // An interface to xmlrpc_build_value. + static XmlRpcValue buildValue (const char *const format, ...); + */ + + // Some functions to get the underlying data. + // These will throw an XmlRpcFault if the data is the wrong type. + XmlRpcValue::int32 getInt (void) const; + bool getBool (void) const; + double getDouble (void) const; + std::string getRawDateTime (void) const; + std::string getString (void) const; + XmlRpcValue getArray (void) const; + XmlRpcValue getStruct (void) const; + + // This returns an internal pointer which will become invalid when + // all references to the underlying value are destroyed. + void getBase64 (const unsigned char *& out_data, + size_t& out_len) const; + + /* + // An interface to xmlrpc_parse_value. + void parseValue (const char *const format, ...); + */ + + // Array functions. These will throw an XmlRpcFault if the value + // isn't an array. + size_t arraySize (void) const; + void arrayAppendItem (const XmlRpcValue& value); + XmlRpcValue arrayGetItem (int index) const; + + // Struct functions. These will throw an XmlRpcFault if the value + // isn't a struct. + size_t structSize (void) const; + bool structHasKey (const std::string& key) const; + XmlRpcValue structGetValue (const std::string& key) const; + void structSetValue (const std::string& key, + const XmlRpcValue& value); + void structGetKeyAndValue (const int index, + std::string& out_key, + XmlRpcValue& out_value) const; +}; + +inline XmlRpcValue::XmlRpcValue (xmlrpc_value *value, + ReferenceBehavior behavior) +{ + mValue = value; + + if (behavior == MAKE_REFERENCE) + xmlrpc_INCREF(value); +} + +inline XmlRpcValue::XmlRpcValue (const XmlRpcValue& value) { + mValue = value.mValue; + xmlrpc_INCREF(mValue); +} + +inline XmlRpcValue::~XmlRpcValue (void) { + xmlrpc_DECREF(mValue); +} + +inline XmlRpcValue& XmlRpcValue::operator= (const XmlRpcValue& value) { + // Must increment before we decrement, in case of assignment to self. + xmlrpc_INCREF(value.mValue); + xmlrpc_DECREF(mValue); + mValue = value.mValue; + return *this; +} + +inline xmlrpc_type XmlRpcValue::getType (void) const { + return xmlrpc_value_type(mValue); +} + +inline xmlrpc_value *XmlRpcValue::makeReference (void) const { + xmlrpc_INCREF(mValue); + return mValue; +} + +inline xmlrpc_value *XmlRpcValue::borrowReference (void) const { + return mValue; +} + + +//========================================================================= +// XmlRpcClient +//========================================================================= + +class XmlRpcClient { + +private: + std::string mServerUrl; + +public: + static void Initialize (std::string appname, std::string appversion); + static void Terminate (void); + + XmlRpcClient (const std::string& server_url) : mServerUrl(server_url) {} + ~XmlRpcClient (void) {} + + XmlRpcClient (const XmlRpcClient& client); + XmlRpcClient& operator= (const XmlRpcClient& client); + + XmlRpcValue call (std::string method_name, XmlRpcValue param_array); + void call_asynch (std::string method_name, + XmlRpcValue param_array, + xmlrpc_response_handler callback, + void* user_data); + void event_loop_asynch (unsigned long milliseconds); +}; + +inline void XmlRpcClient::call_asynch(std::string method_name, + XmlRpcValue param_array, + xmlrpc_response_handler callback, + void* user_data) +{ + xmlrpc_client_call_asynch_params( + mServerUrl.c_str(), + method_name.c_str(), + callback, + user_data, + param_array.borrowReference()); +} + +inline void XmlRpcClient::event_loop_asynch(unsigned long milliseconds) +{ + xmlrpc_client_event_loop_finish_asynch_timeout(milliseconds); +} + + +//========================================================================= +// XmlRpcClient Methods +//========================================================================= +// These are inline for now, so we don't need to screw with linker issues +// and build a separate client library. + +inline XmlRpcClient::XmlRpcClient (const XmlRpcClient& client) + : mServerUrl(client.mServerUrl) +{ +} + +inline XmlRpcClient& XmlRpcClient::operator= (const XmlRpcClient& client) { + if (this != &client) + mServerUrl = client.mServerUrl; + return *this; +} + +inline void XmlRpcClient::Initialize (std::string appname, + std::string appversion) { + xmlrpc_client_init(XMLRPC_CLIENT_NO_FLAGS, + appname.c_str(), + appversion.c_str()); +} + +inline void XmlRpcClient::Terminate (void) { + xmlrpc_client_cleanup(); +} + +inline XmlRpcValue XmlRpcClient::call (std::string method_name, + XmlRpcValue param_array) +{ + XmlRpcEnv env; + xmlrpc_value *result = + xmlrpc_client_call_params(env, + mServerUrl.c_str(), + method_name.c_str(), + param_array.borrowReference()); + env.throwIfFaultOccurred(); + return XmlRpcValue(result, XmlRpcValue::CONSUME_REFERENCE); +} + +//========================================================================= +// XmlRpcGenSrv +//========================================================================= + +class XmlRpcGenSrv { + +private: + + xmlrpc_registry* mRegistry; + + xmlrpc_mem_block* alloc (XmlRpcEnv& env, const std::string& body) const; + +public: + + XmlRpcGenSrv (int flags); + ~XmlRpcGenSrv (void); + + xmlrpc_registry* getRegistry (void) const; + + XmlRpcGenSrv& addMethod (const std::string& name, + xmlrpc_method method, + void *data); + XmlRpcGenSrv& addMethod (const std::string& name, + xmlrpc_method method, + void* data, + const std::string& signature, + const std::string& help); + + std::string handle (const std::string& body) const; +}; + +inline XmlRpcGenSrv::XmlRpcGenSrv (int) { + + XmlRpcEnv env; + + mRegistry = xmlrpc_registry_new (env); + env.throwIfFaultOccurred(); +} + +inline XmlRpcGenSrv::~XmlRpcGenSrv (void) { + + xmlrpc_registry_free (mRegistry); +} + +inline xmlrpc_registry* XmlRpcGenSrv::getRegistry () const { + + return mRegistry; +} + + +// Copyright (C) 2001 by Eric Kidd. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// 3. The name of the author may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +// OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +// OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +// SUCH DAMAGE. + + +#endif /* _XMLRPCCPP_H_ */ diff --git a/include/xmlrpc-c/oldxmlrpc.h b/include/xmlrpc-c/oldxmlrpc.h new file mode 100644 index 0000000..2a5d3bf --- /dev/null +++ b/include/xmlrpc-c/oldxmlrpc.h @@ -0,0 +1,2 @@ +#include +#include diff --git a/include/xmlrpc-c/registry.hpp b/include/xmlrpc-c/registry.hpp new file mode 100644 index 0000000..1f12f1a --- /dev/null +++ b/include/xmlrpc-c/registry.hpp @@ -0,0 +1,175 @@ +#ifndef REGISTRY_HPP_INCLUDED +#define REGISTRY_HPP_INCLUDED + +#include +#include +#include + +#include +#include +#include + +namespace xmlrpc_c { + + +class method : public girmem::autoObject { +/*---------------------------------------------------------------------------- + An XML-RPC method. + + This base class is abstract. You can't create an object in it. + Define a useful method with this as a base class, with an + execute() method. +-----------------------------------------------------------------------------*/ +public: + method(); + + virtual ~method(); + + virtual void + execute(xmlrpc_c::paramList const& paramList, + xmlrpc_c::value * const resultP) = 0; + + std::string signature() const { return _signature; }; + std::string help() const { return _help; }; + +protected: + std::string _signature; + std::string _help; +}; + +/* Example of a specific method class: + + class sample_add : public xmlrpc_c::method { + public: + sample_add() { + this->_signature = "ii"; + this->_help = "This method adds two integers together"; + } + void + execute(xmlrpc_c::param_list const paramList, + const xmlrpc_c::value * const retvalP) { + + int const addend(paramList.getInt(0)); + int const adder(paramList.getInt(1)); + + *retvalP = xmlrpc_c::value(addend, adder); + } + }; + + + Example of creating such a method: + + methodPtr const sampleAddMethodP(new sample_add); + + You pass around, copy, etc. the handle sampleAddMethodP and when + the last copy of the handle is gone, the sample_add object itself + gets deleted. + +*/ + + +class methodPtr : public girmem::autoObjectPtr { + +public: + methodPtr(xmlrpc_c::method * const methodP); + + xmlrpc_c::method * + operator->() const; +}; + +class defaultMethod : public girmem::autoObject { + +public: + virtual ~defaultMethod(); + + virtual void + execute(std::string const& methodName, + xmlrpc_c::paramList const& paramList, + xmlrpc_c::value * const resultP) = 0; +}; + +class defaultMethodPtr : public girmem::autoObjectPtr { + +public: + defaultMethodPtr(); + + defaultMethodPtr(xmlrpc_c::defaultMethod * const methodP); + + xmlrpc_c::defaultMethod * + operator->() const; + + xmlrpc_c::defaultMethod * + get() const; +}; + +class registry : public girmem::autoObject { +/*---------------------------------------------------------------------------- + An Xmlrpc-c server method registry. An Xmlrpc-c server transport + (e.g. an HTTP server) uses this object to process an incoming + Xmlrpc-c call. +-----------------------------------------------------------------------------*/ + +public: + + registry(); + ~registry(); + + void + addMethod(std::string const name, + xmlrpc_c::methodPtr const methodP); + + void + setDefaultMethod(xmlrpc_c::defaultMethodPtr const methodP); + + void + disableIntrospection(); + + void + processCall(std::string const& body, + std::string * const responseP) const; + + xmlrpc_registry * + c_registry() const; + /* This is meant to be private except to other objects in the + Xmlrpc-c library. + */ + +private: + + xmlrpc_registry * c_registryP; + /* Pointer to the C registry object we use to implement this + object. + */ + + std::list methodList; + /* This is a list of all the method objects (actually, pointers + to them). But since the real registry is the C registry object, + all this list is for is to maintain references to the objects + to which the C registry points so that they continue to exist. + */ + xmlrpc_c::defaultMethodPtr defaultMethodP; + /* The real identifier of the default method is the C registry + object; this member exists only to maintain a reference to the + object to which the C registry points so that it will continue + to exist. + */ +}; + + +class registryPtr : public girmem::autoObjectPtr { + +public: + registryPtr(); + + registryPtr(xmlrpc_c::registry * const registryP); + + xmlrpc_c::registry * + operator->() const; + + xmlrpc_c::registry * + get() const; +}; + +} // namespace + +#endif diff --git a/include/xmlrpc-c/server.h b/include/xmlrpc-c/server.h new file mode 100644 index 0000000..adb2aaa --- /dev/null +++ b/include/xmlrpc-c/server.h @@ -0,0 +1,122 @@ +/* Copyright and license information is at the end of the file */ + +#ifndef XMLRPC_SERVER_H_INCLUDED +#define XMLRPC_SERVER_H_INCLUDED + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct _xmlrpc_registry xmlrpc_registry; + +typedef void +(*xmlrpc_preinvoke_method)(xmlrpc_env * const envP, + const char * const methodName, + xmlrpc_value * const paramArrayP, + void * const userData); + +typedef xmlrpc_value * +(*xmlrpc_method)(xmlrpc_env * const envP, + xmlrpc_value * const paramArrayP, + void * const userData); + +typedef xmlrpc_value * +(*xmlrpc_default_method)(xmlrpc_env * const envP, + const char * const host, + const char * const methodName, + xmlrpc_value * const paramArrayP, + void * const userData); + +xmlrpc_registry * +xmlrpc_registry_new(xmlrpc_env * const envP); + +void +xmlrpc_registry_free(xmlrpc_registry * const registryP); + +void +xmlrpc_registry_disable_introspection(xmlrpc_registry * const registryP); + +void +xmlrpc_registry_add_method(xmlrpc_env * const envP, + xmlrpc_registry * const registryP, + const char * const host, + const char * const methodName, + xmlrpc_method const method, + void * const userData); + +void +xmlrpc_registry_add_method_w_doc(xmlrpc_env * const envP, + xmlrpc_registry * const registryP, + const char * const host, + const char * const methodName, + xmlrpc_method const method, + void * const userData, + const char * const signature, + const char * const help); + +void +xmlrpc_registry_set_default_method(xmlrpc_env * const envP, + xmlrpc_registry * const registryP, + xmlrpc_default_method const handler, + void * const userData); + +void +xmlrpc_registry_set_preinvoke_method(xmlrpc_env * const envP, + xmlrpc_registry * const registryP, + xmlrpc_preinvoke_method const method, + void * const userData); + + +typedef void xmlrpc_server_shutdown_fn(xmlrpc_env *, void *, const char *); + /* A function that shuts down a server that uses a registry. + Second argument is context specific to that function; third + argument is a comment to describe the shutdown. + */ + +void +xmlrpc_registry_set_shutdown(xmlrpc_registry * const registryP, + xmlrpc_server_shutdown_fn * const shutdownFn, + void * const context); + +/*---------------------------------------------------------------------------- + Lower interface -- services to be used by an HTTP request handler +-----------------------------------------------------------------------------*/ + +xmlrpc_mem_block * +xmlrpc_registry_process_call(xmlrpc_env * const envP, + xmlrpc_registry * const registryP, + const char * const host, + const char * const xmlData, + size_t const xmlLen); + +#ifdef __cplusplus +} +#endif + +/* Copyright (C) 2001 by First Peer, Inc. All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +** ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +** OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +** HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +** LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +** OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +** SUCH DAMAGE. */ +#endif diff --git a/include/xmlrpc-c/server_abyss.h b/include/xmlrpc-c/server_abyss.h new file mode 100644 index 0000000..4882a20 --- /dev/null +++ b/include/xmlrpc-c/server_abyss.h @@ -0,0 +1,211 @@ +/* Copyright and license information is at the end of the file */ + +#ifndef XMLRPC_SERVER_ABYSS_H_INCLUDED +#define XMLRPC_SERVER_ABYSS_H_INCLUDED + +#include "xmlrpc-c/abyss.h" +#include "xmlrpc-c/server.h" + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/*========================================================================= +** XML-RPC Server (based on Abyss) +**========================================================================= +** A simple XML-RPC server based on the Abyss web server. If errors +** occur during server setup, the server will exit. In general, if you +** want to use this API, you'll need to be familiar with Abyss. +** +** There are two ways to use Abyss: +** 1) You can use the handy wrapper functions. +** 2) You can set up Abyss yourself, and install the appropriate +** handlers manually. +*/ + +#define XMLRPC_SERVER_ABYSS_NO_FLAGS (0) + + + + +/*========================================================================= +** Basic Abyss Server Functions +**=======================================================================*/ + +typedef void ((*runfirstFn)(void *)); + +typedef struct { + const char * config_file_name; + /* NULL to use preferred proper API-level interface */ + + xmlrpc_registry * registryP; + + /* runfirstFn and runfirst_arg are meaningless when + config_file_name is NULL + */ + runfirstFn runfirst; + void * runfirst_arg; + + unsigned int port_number; + const char * log_file_name; + unsigned int keepalive_timeout; + unsigned int keepalive_max_conn; + unsigned int timeout; + xmlrpc_bool dont_advertise; + xmlrpc_bool socket_bound; + xmlrpc_socket socket_handle; + const char * uri_path; + xmlrpc_bool chunk_response; +} xmlrpc_server_abyss_parms; + + +#define XMLRPC_APSIZE(MBRNAME) \ + XMLRPC_STRUCTSIZE(xmlrpc_server_abyss_parms, MBRNAME) + +/* XMLRPC_APSIZE(xyz) is the minimum size a struct xmlrpc_server_abyss_parms + must be to include the 'xyz' member. This is essential to forward and + backward compatibility, as new members will be added to the end of the + struct in future releases. This is how the callee knows whether or + not the caller is new enough to have supplied a certain parameter. +*/ + +void +xmlrpc_server_abyss(xmlrpc_env * const envP, + const xmlrpc_server_abyss_parms * const parms, + unsigned int const parm_size); + +void +xmlrpc_server_abyss_set_handlers2(TServer * const srvP, + const char * const filename, + xmlrpc_registry * const registryP); + +void +xmlrpc_server_abyss_set_handlers(TServer * const serverP, + xmlrpc_registry * const registryP); + +void +xmlrpc_server_abyss_set_handler(xmlrpc_env * const envP, + TServer * const serverP, + const char * const filename, + xmlrpc_registry * const registryP); + +/*========================================================================= +** Handy Abyss Extensions +**=======================================================================*/ + +/* These are functions that have nothing to do with Xmlrpc-c, but provide + convenient Abyss services beyond those provided by the Abyss library. +*/ + +/* Start an Abyss webserver running (previously created and +** initialized). Under Unix, this routine will attempt to do a +** detaching fork, drop root privileges (if any) and create a pid +** file. Under Windows, this routine merely starts the server. This +** routine never returns. +** +** Once you call this routine, it is illegal to modify the server any +** more, including changing any method registry. +*/ +void +xmlrpc_server_abyss_run(void); + +/* Same as xmlrpc_server_abyss_run(), except you get to specify a "runfirst" +** function. The server runs this just before executing the actual server +** function, after any daemonizing. NULL for 'runfirst' means no runfirst +** function. 'runfirstArg' is the argument the server passes to the runfirst +** function. +**/ +void +xmlrpc_server_abyss_run_first(void (runfirst(void *)), + void * const runfirstArg); + +/*========================================================================= +** Method Registry +**========================================================================= + These functions are for the built-in xmlrpc_server_abyss registry. + It's usually simpler to skip all this and use the regular method + registry services (from xmlrpc_server.h) to build a registry and + pass it to xmlrpc_server_abyss. +*/ + +/* Call this function to create a new Abyss webserver with the default +** options and the built-in method registry. If you've already +** initialized Abyss using Abyss functions, you can instead call +** xmlrpc_server_abyss_init_registry() to make it an Xmlrpc-c server. +** Or use a regular method registry and call +** xmlrpc_server_abyss_set_handlers(). +**/ +void +xmlrpc_server_abyss_init(int const flags, + const char * const config_file); + +/* This is called automatically by xmlrpc_server_abyss_init. */ +void xmlrpc_server_abyss_init_registry (void); + +/* Fetch the internal registry, if you happen to need it. + If you're using this, you really shouldn't be using the built-in + registry at all. It exists today only for backward compatibilty. +*/ +extern xmlrpc_registry * +xmlrpc_server_abyss_registry (void); + +/* A quick & easy shorthand for adding a method. Depending on +** how you've configured your copy of Abyss, it's probably not safe to +** call this method after calling xmlrpc_server_abyss_run. */ +void xmlrpc_server_abyss_add_method (char *method_name, + xmlrpc_method method, + void *user_data); + +/* As above, but provide documentation (see xmlrpc_registry_add_method_w_doc +** for more information). You should really use this one. */ +extern void +xmlrpc_server_abyss_add_method_w_doc (char *method_name, + xmlrpc_method method, + void *user_data, + char *signature, + char *help); + +/*========================================================================= +** Content Handlers +**=======================================================================*/ +/* Abyss contents handlers xmlrpc_server_abyss_rpc2_handler() + and xmlrpc_server_abyss_default_handler() were available in older + Xmlrpc-c, but starting with Release 1.01, they are not. Instead, + call xmlrpc_server_abyss_set_handlers() to install them. + + Alternatively, you can write your own handlers that do the same thing. + It's not hard, and if you're writing low enough level Abyss code that + you can't use xmlrpc_server_abyss_set_handlers(), you probably want to + anyway. +*/ + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +/* Copyright (C) 2001 by First Peer, Inc. All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +** ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +** OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +** HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +** LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +** OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +** SUCH DAMAGE. */ + +#endif diff --git a/include/xmlrpc-c/server_abyss.hpp b/include/xmlrpc-c/server_abyss.hpp new file mode 100644 index 0000000..e420ad3 --- /dev/null +++ b/include/xmlrpc-c/server_abyss.hpp @@ -0,0 +1,117 @@ +#ifndef SERVER_ABYSS_HPP_INCLUDED +#define SERVER_ABYSS_HPP_INCLUDED + +#include "xmlrpc-c/base.hpp" +#include "abyss.h" + +namespace xmlrpc_c { + +class serverAbyss { + +public: + class constrOpt { + public: + constrOpt(); + + constrOpt & registryPtr (xmlrpc_c::registryPtr const& arg); + constrOpt & registryP (const xmlrpc_c::registry * const& arg); + constrOpt & socketFd (xmlrpc_socket const& arg); + constrOpt & portNumber (uint const& arg); + constrOpt & logFileName (std::string const& arg); + constrOpt & keepaliveTimeout (uint const& arg); + constrOpt & keepaliveMaxConn (uint const& arg); + constrOpt & timeout (uint const& arg); + constrOpt & dontAdvertise (bool const& arg); + constrOpt & uriPath (std::string const& arg); + constrOpt & chunkResponse (bool const& arg); + + struct value { + xmlrpc_c::registryPtr registryPtr; + const xmlrpc_c::registry * registryP; + xmlrpc_socket socketFd; + uint portNumber; + std::string logFileName; + uint keepaliveTimeout; + uint keepaliveMaxConn; + uint timeout; + bool dontAdvertise; + std::string uriPath; + bool chunkResponse; + } value; + struct { + bool registryPtr; + bool registryP; + bool socketFd; + bool portNumber; + bool logFileName; + bool keepaliveTimeout; + bool keepaliveMaxConn; + bool timeout; + bool dontAdvertise; + bool uriPath; + bool chunkResponse; + } present; + }; + + serverAbyss(constrOpt const& opt); + + serverAbyss( + xmlrpc_c::registry const& registry, + unsigned int const portNumber = 8080, + std::string const& logFileName = "", + unsigned int const keepaliveTimeout = 0, + unsigned int const keepaliveMaxConn = 0, + unsigned int const timeout = 0, + bool const dontAdvertise = false, + bool const socketBound = false, + xmlrpc_socket const socketFd = 0 + ); + ~serverAbyss(); + + void + run(); + + void + runOnce(); + + void + runConn(int const socketFd); + +private: + // The user has the choice of supplying the registry by plain pointer + // (and managing the object's existence himself) or by autoObjectPtr + // (with automatic management). 'registryPtr' exists here only to + // maintain a reference count in the case that the user supplied an + // autoObjectPtr. The object doesn't reference the C++ registry + // object except during construction, because the C registry is the + // real registry. + xmlrpc_c::registryPtr registryPtr; + + TServer cServer; + + void + setAdditionalServerParms(constrOpt const& opt); + + void + initialize(constrOpt const& opt); +}; + + +void +server_abyss_set_handlers(TServer * const srvP, + xmlrpc_c::registry const& registry, + std::string const& uriPath = "/RPC2"); + +void +server_abyss_set_handlers(TServer * const srvP, + const xmlrpc_c::registry * const registryP, + std::string const& uriPath = "/RPC2"); + +void +server_abyss_set_handlers(TServer * const srvP, + xmlrpc_c::registryPtr const registryPtr, + std::string const& uriPath = "/RPC2"); + +} // namespace + +#endif diff --git a/include/xmlrpc-c/server_cgi.h b/include/xmlrpc-c/server_cgi.h new file mode 100644 index 0000000..ad926aa --- /dev/null +++ b/include/xmlrpc-c/server_cgi.h @@ -0,0 +1,49 @@ +/* Interface header file for libxmlrpc_server_cgi. + + By Bryan Henderson, 05.04.27. Contributed to the public domain. +*/ + +#ifndef XMLRPC_CGI_H_INCLUDED +#define XMLRPC_CGI_H_INCLUDED + +#include + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + +void +xmlrpc_server_cgi_process_call(xmlrpc_registry * const registryP); + +#define XMLRPC_CGI_NO_FLAGS (0) + +extern void +xmlrpc_cgi_init (int flags); + +extern xmlrpc_registry * +xmlrpc_cgi_registry (void); + +void +xmlrpc_cgi_add_method(const char * const method_name, + xmlrpc_method const method, + void * const user_data); + +void +xmlrpc_cgi_add_method_w_doc(const char * const method_name, + xmlrpc_method const method, + void * const user_data, + const char * const signature, + const char * const help); +extern void +xmlrpc_cgi_process_call (void); + +extern void +xmlrpc_cgi_cleanup (void); + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif diff --git a/include/xmlrpc-c/server_w32httpsys.h b/include/xmlrpc-c/server_w32httpsys.h new file mode 100644 index 0000000..085f6e3 --- /dev/null +++ b/include/xmlrpc-c/server_w32httpsys.h @@ -0,0 +1,95 @@ +/* Copyright (C) 2005 by Steven A. Bone, sbone@pobox.com. All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +** ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +** OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +** HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +** LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +** OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +** SUCH DAMAGE. */ + +/* COMPILATION NOTE: + Note that the Platform SDK headers and + link libraries for Windows XP SP2 or newer are required to compile + xmlrpc-c for this module. If you are not using this server, it is + safe to exclude the xmlrpc_server_w32httpsys.c file from the xmlrpc + project and these dependencies will not be required. You can get the + latest platform SDK at + http://www.microsoft.com/msdownload/platformsdk/sdkupdate/ + Be sure after installation to choose the program to "register the PSDK + directories with Visual Studio" so the newer headers are found. +*/ + +#ifndef _XMLRPC_SERVER_HTTPSYS_H_ +#define _XMLRPC_SERVER_HTTPSYS_H_ 1 + +#include "transport_config.h" + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/*========================================================================= +** XML-RPC Server (based on HTTP.SYS) +**========================================================================= +** A simple XML-RPC server based on the "built-in" Windows web server, +** HTTP.SYS. This is provided by Microsoft in Windows XP SP2 and +** Windows Server 2003. If errors occur during server setup, the server +** will exit. In general, if you want to use this API, you do not really +** need to be familiar with the HTTP.SYS API. +*/ + +typedef void (*authorization_function)( + xmlrpc_env * envP, + char * userid, + char * password); + +typedef struct { + xmlrpc_registry * registryP; + unsigned int portNum; + unsigned int useSSL; + /* useSSL, 0 = no SSL, 1 = use SSL */ + unsigned int logLevel; + /* logLevel, 0 = none, 1 = file, 2 = file+OutputDebugString() */ + const char * logFile; + /* logFile, NULL or filename */ + authorization_function authfn; +} xmlrpc_server_httpsys_parms; + +#define XMLRPC_HSSIZE(MBRNAME) \ + XMLRPC_STRUCTSIZE(xmlrpc_server_httpsys_parms, MBRNAME) + +/* XMLRPC_HSSIZE(xyz) is the minimum size a struct xmlrpc_server_httpsys_parms + must be to include the 'xyz' member. This is essential for forward and + backward compatbility, as new members will be added to the end of the + struct in future releases. This is how the callee knows whether or + not the caller is new enough to have supplied a certain parameter. +*/ + +void +xmlrpc_server_httpsys( + xmlrpc_env * const envP, + const xmlrpc_server_httpsys_parms * const parmsP, + unsigned int const parm_size + ); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif \ No newline at end of file diff --git a/include/xmlrpc-c/sleep_int.h b/include/xmlrpc-c/sleep_int.h new file mode 100644 index 0000000..be18e8f --- /dev/null +++ b/include/xmlrpc-c/sleep_int.h @@ -0,0 +1,7 @@ +#ifndef SLEEP_INT_H_INCLUDED +#define SLEEP_INT_H_INCLUDED + +void +xmlrpc_millisecond_sleep(unsigned int const milliseconds); + +#endif diff --git a/include/xmlrpc-c/string_int.h b/include/xmlrpc-c/string_int.h new file mode 100644 index 0000000..f1bfb7b --- /dev/null +++ b/include/xmlrpc-c/string_int.h @@ -0,0 +1,60 @@ +#ifndef XMLRPC_C_STRING_INT_H_INCLUDED +#define XMLRPC_C_STRING_INT_H_INCLUDED + + +#include +#include + +#include "xmlrpc-c/base_int.h" + +#ifdef __cplusplus +extern "C" { +#endif + +extern const char * const xmlrpc_strsol; + +void +xmlrpc_vasprintf(const char ** const retvalP, + const char * const fmt, + va_list varargs); + +void GNU_PRINTF_ATTR(2,3) +xmlrpc_asprintf(const char ** const retvalP, const char * const fmt, ...); + +void +xmlrpc_strfree(const char * const string); + +static __inline__ bool +xmlrpc_streq(const char * const a, + const char * const b) { + return (strcmp(a, b) == 0); +} + +static __inline__ bool +xmlrpc_strcaseeq(const char * const a, + const char * const b) { + return (strcasecmp(a, b) == 0); +} + +static __inline__ bool +xmlrpc_strneq(const char * const a, + const char * const b, + size_t const len) { + return (strncmp(a, b, len) == 0); +} + +const char * +xmlrpc_makePrintable(const char * const input); + +const char * +xmlrpc_makePrintable_lp(const char * const input, + size_t const inputLength); + +const char * +xmlrpc_makePrintableChar(char const input); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/include/xmlrpc-c/timeout.hpp b/include/xmlrpc-c/timeout.hpp new file mode 100644 index 0000000..5638300 --- /dev/null +++ b/include/xmlrpc-c/timeout.hpp @@ -0,0 +1,20 @@ +#ifndef XMLRPC_TIMEOUT_H_INCLUDED +#define XMLRPC_TIMEOUT_H_INCLUDED + +namespace xmlrpc_c { + +struct timeout { + + timeout() : finite(false) {} + + timeout(unsigned int const duration) : + finite(true), duration(duration) {} + + bool finite; + unsigned int duration; +}; + + +} // namespace + +#endif diff --git a/include/xmlrpc-c/transport.h b/include/xmlrpc-c/transport.h new file mode 100644 index 0000000..b6ca0d2 --- /dev/null +++ b/include/xmlrpc-c/transport.h @@ -0,0 +1,81 @@ +/* Copyright information is at the end of the file */ +#ifndef XMLRPC_TRANSPORT_H_INCLUDED +#define XMLRPC_TRANSPORT_H_INCLUDED + +#ifdef __cplusplus +extern "C" { +#endif + +#include "xmlrpc-c/base.h" + +struct xmlrpc_call_info; + +struct xmlrpc_client_transport; + +/*========================================================================= +** Transport function type declarations. +**========================================================================= +*/ +typedef void (*xmlrpc_transport_setup)(xmlrpc_env * const envP); + +typedef void (*xmlrpc_transport_teardown)(void); + +typedef void (*xmlrpc_transport_create)( + xmlrpc_env * const envP, + int const flags, + const char * const appname, + const char * const appversion, + const struct xmlrpc_xportparms * const transportparmsP, + size_t const transportparm_size, + struct xmlrpc_client_transport ** const handlePP); + +typedef void (*xmlrpc_transport_destroy)( + struct xmlrpc_client_transport * const clientTransportP); + +typedef void (*xmlrpc_transport_asynch_complete)( + struct xmlrpc_call_info * const callInfoP, + xmlrpc_mem_block * const responseXmlP, + xmlrpc_env const env); + +typedef void (*xmlrpc_transport_send_request)( + xmlrpc_env * const envP, + struct xmlrpc_client_transport * const clientTransportP, + const xmlrpc_server_info * const serverP, + xmlrpc_mem_block * const xmlP, + xmlrpc_transport_asynch_complete complete, + struct xmlrpc_call_info * const callInfoP); + +typedef void (*xmlrpc_transport_call)( + xmlrpc_env * const envP, + struct xmlrpc_client_transport * const clientTransportP, + const xmlrpc_server_info * const serverP, + xmlrpc_mem_block * const xmlP, + xmlrpc_mem_block ** const responsePP); + +typedef enum {timeout_no, timeout_yes} xmlrpc_timeoutType; + +typedef unsigned long xmlrpc_timeout; + /* A timeout in milliseconds. */ + +typedef void (*xmlrpc_transport_finish_asynch)( + struct xmlrpc_client_transport * const clientTransportP, + xmlrpc_timeoutType const timeoutType, + xmlrpc_timeout const timeout); + + +struct xmlrpc_client_transport_ops { + + xmlrpc_transport_setup setup_global_const; + xmlrpc_transport_teardown teardown_global_const; + xmlrpc_transport_create create; + xmlrpc_transport_destroy destroy; + xmlrpc_transport_send_request send_request; + xmlrpc_transport_call call; + xmlrpc_transport_finish_asynch finish_asynch; +}; + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/include/xmlrpc-c/util.h b/include/xmlrpc-c/util.h new file mode 100644 index 0000000..541e385 --- /dev/null +++ b/include/xmlrpc-c/util.h @@ -0,0 +1,313 @@ +/*============================================================================= + xmlrpc-c/util.h +=============================================================================== + + This is the interface to the libxmlrpc_util library, which contains + utility routines that have nothing to do with XML-RPC. The library + exists because other Xmlrpc-c libraries use the utilities. + + By Bryan Henderson, San Jose, CA 05.09.21. + + Contributed to the public domain by its author. +=============================================================================*/ + +#ifndef XMLRPC_C_UTIL_H_INCLUDED +#define XMLRPC_C_UTIL_H_INCLUDED + +#include + +#ifdef __cplusplus +extern "C" { +#endif + + +/* GNU_PRINTF_ATTR lets the GNU compiler check printf-type + calls to be sure the arguments match the format string, thus preventing + runtime segmentation faults and incorrect messages. +*/ +#ifdef __GNUC__ +#define GNU_PRINTF_ATTR(a,b) __attribute__ ((format (printf, a, b))) +#else +#define GNU_PRINTF_ATTR(a,b) +#endif + + +/*========================================================================= +** C struct size computations +**=======================================================================*/ + +/* Use XMLRPC_STRUCT_MEMBER_SIZE() to determine how big a structure is + up to and including a specified member. E.g. if you have + struct mystruct {int red; int green; int blue};, then + XMLRPC_STRUCT_MEMBER_SIZE(mystruct, green) is (8). +*/ + +#define _XMLRPC_STRUCT_MEMBER_OFFSET(TYPE, MBRNAME) \ + ((unsigned long)(char*)&((TYPE *)0)->MBRNAME) +#define _XMLRPC_STRUCT_MEMBER_SIZE(TYPE, MBRNAME) \ + sizeof(((TYPE *)0)->MBRNAME) +#define XMLRPC_STRUCTSIZE(TYPE, MBRNAME) \ + (_XMLRPC_STRUCT_MEMBER_OFFSET(TYPE, MBRNAME) + \ + _XMLRPC_STRUCT_MEMBER_SIZE(TYPE, MBRNAME)) + +/*========================================================================= +** Assertions and Debugging +**========================================================================= +** Note that an assertion is _not_ a directive to check a condition and +** crash if it isn't true. It is an assertion that the condition _is_ +** true. This assertion helps people to read the code. The program +** may also check the assertion as it runs, and if it conflicts with reality, +** recognize that the program is incorrect and abort it. In practice, +** it does this checking when the program was compiled without the NDEBUG +** macro defined. +*/ + +#ifndef NDEBUG + +#define XMLRPC_ASSERT(cond) \ + do \ + if (!(cond)) \ + xmlrpc_assertion_failed(__FILE__, __LINE__); \ + while (0) + +#else +#define XMLRPC_ASSERT(cond) while (0) {} +#endif + +void +xmlrpc_assertion_failed(const char * const fileName, + int const lineNumber); + +/* Validate a pointer. */ +#define XMLRPC_ASSERT_PTR_OK(ptr) \ + XMLRPC_ASSERT((ptr) != NULL) + +/* We only call this if something truly drastic happens. */ +#define XMLRPC_FATAL_ERROR(msg) xmlrpc_fatal_error(__FILE__, __LINE__, (msg)) + +extern void xmlrpc_fatal_error (char* file, int line, char* msg); + + +/*========================================================================= +** xmlrpc_env +**========================================================================= +** XML-RPC represents runtime errors as elements. These contain +** and elements. +** +** Since we need as much thread-safety as possible, we borrow an idea from +** CORBA--we store exception information in an "environment" object. +** You'll pass this to many different functions, and it will get filled +** out appropriately. +** +** For example: +** +** xmlrpc_env env; +** +** xmlrpc_env_init(&env); +** +** xmlrpc_do_something(&env); +** if (env.fault_occurred) +** report_error_appropriately(); +** +** xmlrpc_env_clean(&env); +*/ + +#define XMLRPC_INTERNAL_ERROR (-500) +#define XMLRPC_TYPE_ERROR (-501) +#define XMLRPC_INDEX_ERROR (-502) +#define XMLRPC_PARSE_ERROR (-503) +#define XMLRPC_NETWORK_ERROR (-504) +#define XMLRPC_TIMEOUT_ERROR (-505) +#define XMLRPC_NO_SUCH_METHOD_ERROR (-506) +#define XMLRPC_REQUEST_REFUSED_ERROR (-507) +#define XMLRPC_INTROSPECTION_DISABLED_ERROR (-508) +#define XMLRPC_LIMIT_EXCEEDED_ERROR (-509) +#define XMLRPC_INVALID_UTF8_ERROR (-510) + +typedef struct _xmlrpc_env { + int fault_occurred; + int fault_code; + char * fault_string; +} xmlrpc_env; + +/* Initialize and destroy the contents of the provided xmlrpc_env object. +** These functions will never fail. */ +void xmlrpc_env_init (xmlrpc_env* env); +void xmlrpc_env_clean (xmlrpc_env* env); + +/* Fill out an xmlrpc_fault with the specified values, and set the +** fault_occurred flag. This function will make a private copy of 'string', +** so you retain responsibility for your copy. */ +void +xmlrpc_env_set_fault(xmlrpc_env * const env, + int const faultCode, + const char * const faultDescription); + +/* The same as the above, but using a printf-style format string. */ +void +xmlrpc_env_set_fault_formatted(xmlrpc_env * const envP, + int const code, + const char * const format, + ...) GNU_PRINTF_ATTR(3,4); + +/* This one infers XMLRPC_INTERNAL_ERROR and has a shorter name. + So a call takes up less source code space. +*/ +void +xmlrpc_faultf(xmlrpc_env * const envP, + const char * const format, + ...) GNU_PRINTF_ATTR(2,3); + +/* A simple debugging assertion. */ +#define XMLRPC_ASSERT_ENV_OK(envP) \ + XMLRPC_ASSERT((envP) != NULL && \ + (envP->fault_string == NULL) && \ + !(envP)->fault_occurred) + +/* This version must *not* interpret 'str' as a format string, to avoid +** several evil attacks. */ +#define XMLRPC_FAIL(env,code,str) \ + do { xmlrpc_env_set_fault((env),(code),(str)); goto cleanup; } while (0) + +#define XMLRPC_FAIL1(env,code,str,arg1) \ + do { \ + xmlrpc_env_set_fault_formatted((env),(code),(str),(arg1)); \ + goto cleanup; \ + } while (0) + +#define XMLRPC_FAIL2(env,code,str,arg1,arg2) \ + do { \ + xmlrpc_env_set_fault_formatted((env),(code),(str),(arg1),(arg2)); \ + goto cleanup; \ + } while (0) + +#define XMLRPC_FAIL3(env,code,str,arg1,arg2,arg3) \ + do { \ + xmlrpc_env_set_fault_formatted((env),(code), \ + (str),(arg1),(arg2),(arg3)); \ + goto cleanup; \ + } while (0) + +#define XMLRPC_FAIL_IF_NULL(ptr,env,code,str) \ + do { \ + if ((ptr) == NULL) \ + XMLRPC_FAIL((env),(code),(str)); \ + } while (0) + +#define XMLRPC_FAIL_IF_FAULT(env) \ + do { if ((env)->fault_occurred) goto cleanup; } while (0) + + +/*========================================================================= +** Resource Limits +**========================================================================= +** To discourage denial-of-service attacks, we provide several adjustable +** resource limits. These functions are *not* re-entrant. +*/ + +/* Limit IDs. There will be more of these as time goes on. */ +#define XMLRPC_NESTING_LIMIT_ID (0) +#define XMLRPC_XML_SIZE_LIMIT_ID (1) +#define XMLRPC_LAST_LIMIT_ID (XMLRPC_XML_SIZE_LIMIT_ID) + +/* By default, deserialized data may be no more than 64 levels deep. */ +#define XMLRPC_NESTING_LIMIT_DEFAULT (64) + +/* By default, XML data from the network may be no larger than 512K. +** Some client and server modules may fail to enforce this properly. */ +#define XMLRPC_XML_SIZE_LIMIT_DEFAULT (512*1024) + +/* Set a specific limit to the specified value. */ +extern void xmlrpc_limit_set (int limit_id, size_t value); + +/* Get the value of a specified limit. */ +extern size_t xmlrpc_limit_get (int limit_id); + + +/*========================================================================= +** xmlrpc_mem_block +**========================================================================= +** A resizable chunk of memory. This is mostly used internally, but it is +** also used by the public API in a few places. +** The struct fields are private! +*/ + +typedef struct _xmlrpc_mem_block { + size_t _size; + size_t _allocated; + void* _block; +} xmlrpc_mem_block; + +/* Allocate a new xmlrpc_mem_block. */ +xmlrpc_mem_block* xmlrpc_mem_block_new (xmlrpc_env* env, size_t size); + +/* Destroy an existing xmlrpc_mem_block, and everything it contains. */ +void xmlrpc_mem_block_free (xmlrpc_mem_block* block); + +/* Initialize the contents of the provided xmlrpc_mem_block. */ +void xmlrpc_mem_block_init + (xmlrpc_env* env, xmlrpc_mem_block* block, size_t size); + +/* Deallocate the contents of the provided xmlrpc_mem_block, but not the +** block itself. */ +void xmlrpc_mem_block_clean (xmlrpc_mem_block* block); + +/* Get the size and contents of the xmlrpc_mem_block. */ +size_t +xmlrpc_mem_block_size(const xmlrpc_mem_block * const block); + +void * +xmlrpc_mem_block_contents(const xmlrpc_mem_block * const block); + +/* Resize an xmlrpc_mem_block, preserving as much of the contents as +** possible. */ +void xmlrpc_mem_block_resize + (xmlrpc_env* env, xmlrpc_mem_block* block, size_t size); + +/* Append data to an existing xmlrpc_mem_block. */ +void xmlrpc_mem_block_append + (xmlrpc_env* env, xmlrpc_mem_block* block, const void *data, size_t len); + +#define XMLRPC_MEMBLOCK_NEW(type,env,size) \ + xmlrpc_mem_block_new((env), sizeof(type) * (size)) +#define XMLRPC_MEMBLOCK_FREE(type,block) \ + xmlrpc_mem_block_free(block) +#define XMLRPC_MEMBLOCK_INIT(type,env,block,size) \ + xmlrpc_mem_block_init((env), (block), sizeof(type) * (size)) +#define XMLRPC_MEMBLOCK_CLEAN(type,block) \ + xmlrpc_mem_block_clean(block) +#define XMLRPC_MEMBLOCK_SIZE(type,block) \ + (xmlrpc_mem_block_size(block) / sizeof(type)) +#define XMLRPC_MEMBLOCK_CONTENTS(type,block) \ + ((type*) xmlrpc_mem_block_contents(block)) +#define XMLRPC_MEMBLOCK_RESIZE(type,env,block,size) \ + xmlrpc_mem_block_resize(env, block, sizeof(type) * (size)) +#define XMLRPC_MEMBLOCK_APPEND(type,env,block,data,size) \ + xmlrpc_mem_block_append(env, block, data, sizeof(type) * (size)) + +/* Here are some backward compatibility definitions. These longer names + used to be the only ones and typed memory blocks were considered + special. +*/ +#define XMLRPC_TYPED_MEM_BLOCK_NEW(type,env,size) \ + XMLRPC_MEMBLOCK_NEW(type,env,size) +#define XMLRPC_TYPED_MEM_BLOCK_FREE(type,block) \ + XMLRPC_MEMBLOCK_FREE(type,block) +#define XMLRPC_TYPED_MEM_BLOCK_INIT(type,env,block,size) \ + XMLRPC_MEMBLOCK_INIT(type,env,block,size) +#define XMLRPC_TYPED_MEM_BLOCK_CLEAN(type,block) \ + XMLRPC_MEMBLOCK_CLEAN(type,block) +#define XMLRPC_TYPED_MEM_BLOCK_SIZE(type,block) \ + XMLRPC_MEMBLOCK_SIZE(type,block) +#define XMLRPC_TYPED_MEM_BLOCK_CONTENTS(type,block) \ + XMLRPC_MEMBLOCK_CONTENTS(type,block) +#define XMLRPC_TYPED_MEM_BLOCK_RESIZE(type,env,block,size) \ + XMLRPC_MEMBLOCK_RESIZE(type,env,block,size) +#define XMLRPC_TYPED_MEM_BLOCK_APPEND(type,env,block,data,size) \ + XMLRPC_MEMBLOCK_APPEND(type,env,block,data,size) + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/include/xmlrpc-c/util_int.h b/include/xmlrpc-c/util_int.h new file mode 100644 index 0000000..4ac3e14 --- /dev/null +++ b/include/xmlrpc-c/util_int.h @@ -0,0 +1,13 @@ +#ifndef XMLRPC_C_UTIL_INT_H_INCLUDED +#define XMLRPC_C_UTIL_INT_H_INCLUDED + +#include "util.h" + +#define MIN(a,b) ((a) < (b) ? (a) : (b)) +#define MAX(a,b) ((a) > (b) ? (a) : (b)) + +/* When we deallocate a pointer in a struct, we often replace it with +** this and throw in a few assertions here and there. */ +#define XMLRPC_BAD_POINTER ((void*) 0xDEADBEEF) + +#endif diff --git a/include/xmlrpc-c/xml.hpp b/include/xmlrpc-c/xml.hpp new file mode 100644 index 0000000..cb24f0f --- /dev/null +++ b/include/xmlrpc-c/xml.hpp @@ -0,0 +1,30 @@ +#ifndef XML_HPP_INCLUDED +#define XML_HPP_INCLUDED + +#include +#include + +namespace xmlrpc_c { +namespace xml { + +void +generateCall(std::string const& methodName, + xmlrpc_c::paramList const& paramList, + std::string * const callXmlP); + +void +parseSuccessfulResponse(std::string const& responseXml, + xmlrpc_c::value * const resultP); + +void +parseResponse(std::string const& responseXml, + xmlrpc_c::rpcOutcome * const outcomeP); + + +void +trace(std::string const& label, + std::string const& xml); + + +}} // namespace +#endif diff --git a/include/xmlrpc-c/xmlparser.h b/include/xmlrpc-c/xmlparser.h new file mode 100644 index 0000000..ad1361f --- /dev/null +++ b/include/xmlrpc-c/xmlparser.h @@ -0,0 +1,97 @@ +/* Copyright and license information is at the end of the file */ + +#ifndef XMLRPC_XMLPARSER_H_INCLUDED +#define XMLRPC_XMLPARSER_H_INCLUDED + +/*========================================================================= +** Abstract XML Parser Interface +**========================================================================= +** This file provides an abstract interface to the XML parser. For now, +** this interface is implemented by expat, but feel free to change it +** if necessary. +*/ + + +/*========================================================================= +** xml_element +**========================================================================= +** This data structure represents an XML element. We provide no more API +** than we'll need in xmlrpc_parse.c. +** +** The pointers returned by the various accessor methods belong to the +** xml_element structure. Do not free them, and do not use them after +** the xml_element has been destroyed. +*/ + +/* You'll need to finish defining struct _xml_element elsewhere. */ +typedef struct _xml_element xml_element; + +/* Destroy an xml_element. */ +void xml_element_free (xml_element *elem); + +/* Return a pointer to the element's name. Do not free this pointer! +** This pointer should point to standard ASCII or UTF-8 data. */ +const char * +xml_element_name(const xml_element * const elemP); + +/* Return the xml_element's CDATA. Do not free this pointer! +** This pointer should point to standard ASCII or UTF-8 data. +** The implementation is allowed to concatenate all the CDATA in the +** element regardless of child elements. Alternatively, if there are +** any child elements, the implementation is allowed to dispose +** of whitespace characters. +** The value returned by xml_element_cdata should be '\0'-terminated +** (although it may contain other '\0' characters internally). +** xml_element_cdata_size should not include the final '\0'. */ +size_t xml_element_cdata_size (xml_element *elem); +char *xml_element_cdata (xml_element *elem); + +/* Return the xml_element's child elements. Do not free this pointer! */ +size_t +xml_element_children_size(const xml_element * const elemP); + +xml_element ** +xml_element_children(const xml_element * const elemP); + + +/*========================================================================= +** xml_parse +**========================================================================= +** Parse a chunk of XML data and return the top-level element. If this +** routine fails, it will return NULL and set up the env appropriately. +** You are responsible for calling xml_element_free on the returned pointer. +*/ + +void +xml_parse(xmlrpc_env * const envP, + const char * const xmlData, + size_t const xmlDataLen, + xml_element ** const resultPP); + + +/* Copyright (C) 2001 by First Peer, Inc. All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +** ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +** OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +** HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +** LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +** OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +** SUCH DAMAGE. */ + +#endif diff --git a/install-sh b/install-sh new file mode 100755 index 0000000..e9de238 --- /dev/null +++ b/install-sh @@ -0,0 +1,251 @@ +#!/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 "install: no input file specified" + exit 1 +else + true +fi + +if [ x"$dir_arg" != x ]; then + dst=$src + src="" + + if [ -d $dst ]; then + instcmd=: + chmodcmd="" + else + instcmd=mkdir + 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 -o -d $src ] + then + true + else + echo "install: $src does not exist" + exit 1 + fi + + if [ x"$dst" = x ] + then + echo "install: no destination specified" + exit 1 + else + true + 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 + true + 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 + true + fi + + pathcomp="${pathcomp}/" +done +fi + +if [ x"$dir_arg" != x ] +then + $doit $instcmd $dst && + + if [ x"$chowncmd" != x ]; then $doit $chowncmd $dst; else true ; fi && + if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dst; else true ; fi && + if [ x"$stripcmd" != x ]; then $doit $stripcmd $dst; else true ; fi && + if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dst; else true ; 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 + true + fi + +# Make a temp file name in the proper directory. + + dsttmp=$dstdir/#inst.$$# + +# Move or copy the file name to the temp name + + $doit $instcmd $src $dsttmp && + + trap "rm -f ${dsttmp}" 0 && + +# 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 true;fi && + if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dsttmp; else true;fi && + if [ x"$stripcmd" != x ]; then $doit $stripcmd $dsttmp; else true;fi && + if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dsttmp; else true;fi && + +# Now rename the file to the real destination. + + $doit $rmcmd -f $dstdir/$dstfile && + $doit $mvcmd $dsttmp $dstdir/$dstfile + +fi && + + +exit 0 diff --git a/lib/Makefile b/lib/Makefile new file mode 100644 index 0000000..3826372 --- /dev/null +++ b/lib/Makefile @@ -0,0 +1,52 @@ +ifeq ($(SRCDIR)x,x) +SRCDIR = $(CURDIR)/.. +endif +SUBDIR = lib + +include $(SRCDIR)/Makefile.config + +# Build up SUBDIRS: +SUBDIRS = +SUBDIRS += util libutil +ifeq ($(ENABLE_ABYSS_SERVER),yes) + SUBDIRS += abyss +endif +ifeq ($(MUST_BUILD_WININET_CLIENT),yes) + SUBDIRS += wininet_transport +endif +ifeq ($(MUST_BUILD_CURL_CLIENT),yes) + SUBDIRS += curl_transport +endif +ifeq ($(MUST_BUILD_LIBWWW_CLIENT),yes) + SUBDIRS += libwww_transport +endif +ifneq ($(ENABLE_LIBXML2_BACKEND),yes) + SUBDIRS += expat +endif + +default: all + +.PHONY: all clean distclean tags distdir intall check dep + +all: $(SUBDIRS:%=%/all) + +clean: $(SUBDIRS:%=%/clean) clean-common + +distclean: $(SUBDIRS:%=%/distclean) distclean-common + +tags: $(SUBDIRS:%=%/tags) TAGS + +DISTFILES = + +distdir: distdir-common + +install: $(SUBDIRS:%=%/install) + +check: + +dep: $(SUBDIRS:%=%/dep) + +include $(SRCDIR)/Makefile.common + + + diff --git a/lib/Makefile.depend b/lib/Makefile.depend new file mode 100644 index 0000000..e69de29 diff --git a/lib/abyss/Makefile b/lib/abyss/Makefile new file mode 100644 index 0000000..b0c4325 --- /dev/null +++ b/lib/abyss/Makefile @@ -0,0 +1,38 @@ +ifeq ($(SRCDIR)x,x) +SRCDIR = $(CURDIR)/../.. +endif +SUBDIR = lib/abyss + +include $(SRCDIR)/Makefile.config + +SUBDIRS = src + +default: all + +.PHONY: all +all: $(SUBDIRS:%=%/all) + +.PHONY: clean +clean: $(SUBDIRS:%=%/clean) clean-common + +.PHONY: distclean +distclean: $(SUBDIRS:%=%/distclean) distclean-common + +.PHONY: tags +tags: $(SUBDIRS:%=%/tags) TAGS + +DISTFILES = + +.PHONY: distdir +distdir: distdir-common + +.PHONY: install +install: $(SUBDIRS:%=%/install) + +.PHONY: dep +dep: $(SUBDIRS:%=%/dep) + +include $(SRCDIR)/Makefile.common + + + diff --git a/lib/abyss/Makefile.depend b/lib/abyss/Makefile.depend new file mode 100644 index 0000000..e69de29 diff --git a/lib/abyss/README b/lib/abyss/README new file mode 100644 index 0000000..b1d6c80 --- /dev/null +++ b/lib/abyss/README @@ -0,0 +1,23 @@ +This directory contains the Abyss HTTP server component of XML-RPC For C/C++ +(Xmlrpc-c). + +This was derived from the independently developed and distributed +Abyss web server package in 2001. Since that time, work has stopped +on package except for a non-free derivative of it that the original +author has done. He uses the Abyss name for that. + +So this is now strictly a piece of Xmlrpc-c. Some day, we should change +the name to avoid confusion with the old code on which it was based and +the current non-free version. + +But for Xmlrpc-c, we don't want to enhance this much. That would +duplicate the vast amount of work that has gone into other HTTP (web) +servers such as Apache. If someone needs fancy HTTP service for +XML-RPC, he should use Apache. One can use Apache with Xmlrpc-c +either by using an Apache request handler plugin or by using a CGI +script. Abyss is just for very simple servers, where the complexity +of using (or even acquiring) Apache would not be warranted. + + +Everything besides what's in the src/ directory is just historical -- +it comes from the original Abyss in 2001. diff --git a/lib/abyss/change.log b/lib/abyss/change.log new file mode 100644 index 0000000..2d32d1a --- /dev/null +++ b/lib/abyss/change.log @@ -0,0 +1,34 @@ + Change log for the ABYSS Web Server + ----------------------------------- + +Version 0.3 (March 23,2000): +---------------------------- +* Handles conditional GET requests (by date) +* Conforms to all the MUSTs of the RFC2616 (newer version of the HTTP/1.1 protocol draft) +* New configuration options (such as pidfile for UNIX systems...) +* Handles HEAD and OPTIONS methods +* Many bug fixes +* Tested on Sun-OS 5.7 +* Second public release + +Version 0.2 beta (February 7,2000): +----------------------------------- +* Handles GET on static files +* Handles correctly range requests +* Conforms to 80% of the MUSTs of the RFC2068 (HTTP/1.1 protocol draft) +* Improved code portability (Win32 and UNIX platforms) +* Tested on Linux 2.2 and Win95/98 +* First public release + +Version 0.1 (January 2000): +--------------------------- +* Completely rewritten in C +* Speed improvement +* New memory allocation scheme (using pools) +* Never released + +Version 0.0 (January 2000): +--------------------------- +* Initial version +* Written in C++ +* Never released \ No newline at end of file diff --git a/lib/abyss/conf/abyss.conf b/lib/abyss/conf/abyss.conf new file mode 100644 index 0000000..c74c758 --- /dev/null +++ b/lib/abyss/conf/abyss.conf @@ -0,0 +1,56 @@ +# ABYSS Web Server configuration file +# (C) Moez Mahfoudh - 2000 + +# Cases in option names are ignored, +# that means that PORT=port=PoRT=.. + +# When writing paths, do not worry about / or \ use. +# ABYSS will substitute / with \ on Win32 systems. + +# Options which are system specific (such as User) are +# ignored on systems which do not handle them. + +# The Port option tells the server on which TCP port to listen. +# default is 80 +Port 8000 + +# The name or #number of the user to run the server as if it is +# launched as root (UNIX specific) +User nobody + +# The Server Root (UNIX systems style) +ServerRoot /home/mahfoudh/abyss + +# The Server Root (Win32 systems style) +# ServerRoot c:\abyss + +# The Path option specifies the web files path. +Path htdocs + +# The Default option contains the name of the files the server should +# look for when only a path is given (e.g. http://myserver/info/). +Default index.html index.htm INDEX.HTM INDEX.HTML + +# The KeepAlive option is used to set the maximum number of requests +# served using the same persistent connection. +KeepAlive 10 + +# The TimeOut option tells the server how much seconds to wait for +# an idle connection before closing it. +TimeOut 10 + +# The MimeTypes option specifies the location of the file +# containing the mapping of MIME types and files extensions +MimeTypes conf/mime.types + +# The path of the log file +LogFile log/access.log + +# The file where the pid of the server is logged (UNIX specific) +PidFile log/abyss.pid + +# If AdvertiseServer if set to no, then no server field would be +# appended to the responses. This is the way to make the server +# identity unknown to some malicious people which can profit from +# well known security holes in the software to crash it. +AdvertiseServer yes diff --git a/lib/abyss/conf/mime.types b/lib/abyss/conf/mime.types new file mode 100644 index 0000000..d53db0f --- /dev/null +++ b/lib/abyss/conf/mime.types @@ -0,0 +1,276 @@ +# This is a comment. I love comments. + +# This file controls what Internet media types are sent to the client for +# given file extension(s). Sending the correct media type to the client +# is important so they know how to handle the content of the file. +# Extra types can either be added here or by using an AddType directive +# in your config files. For more information about Internet media types, +# please read RFC 2045, 2046, 2047, 2048, and 2077. The Internet media type +# registry is at . + +# MIME type Extension +application/EDI-Consent +application/EDI-X12 +application/EDIFACT +application/activemessage +application/andrew-inset ez +application/applefile +application/atomicmail +application/cals-1840 +application/commonground +application/cybercash +application/dca-rft +application/dec-dx +application/eshop +application/hyperstudio +application/iges +application/mac-binhex40 hqx +application/mac-compactpro cpt +application/macwriteii +application/marc +application/mathematica +application/msword doc +application/news-message-id +application/news-transmission +application/octet-stream bin dms lha lzh exe class +application/oda oda +application/pdf pdf +application/pgp-encrypted +application/pgp-keys +application/pgp-signature +application/pkcs10 +application/pkcs7-mime +application/pkcs7-signature +application/postscript ai eps ps +application/prs.alvestrand.titrax-sheet +application/prs.cww +application/prs.nprend +application/remote-printing +application/riscos +application/rtf rtf +application/set-payment +application/set-payment-initiation +application/set-registration +application/set-registration-initiation +application/sgml +application/sgml-open-catalog +application/slate +application/smil smi smil +application/vemmi +application/vnd.3M.Post-it-Notes +application/vnd.FloGraphIt +application/vnd.acucobol +application/vnd.anser-web-certificate-issue-initiation +application/vnd.anser-web-funds-transfer-initiation +application/vnd.audiograph +application/vnd.businessobjects +application/vnd.claymore +application/vnd.comsocaller +application/vnd.dna +application/vnd.dxr +application/vnd.ecdis-update +application/vnd.ecowin.chart +application/vnd.ecowin.filerequest +application/vnd.ecowin.fileupdate +application/vnd.ecowin.series +application/vnd.ecowin.seriesrequest +application/vnd.ecowin.seriesupdate +application/vnd.enliven +application/vnd.epson.salt +application/vnd.fdf +application/vnd.ffsns +application/vnd.framemaker +application/vnd.fujitsu.oasys +application/vnd.fujitsu.oasys2 +application/vnd.fujitsu.oasys3 +application/vnd.fujitsu.oasysgp +application/vnd.fujitsu.oasysprs +application/vnd.fujixerox.docuworks +application/vnd.hp-HPGL +application/vnd.hp-PCL +application/vnd.hp-PCLXL +application/vnd.hp-hps +application/vnd.ibm.MiniPay +application/vnd.ibm.modcap +application/vnd.intercon.formnet +application/vnd.intertrust.digibox +application/vnd.intertrust.nncp +application/vnd.is-xpr +application/vnd.japannet-directory-service +application/vnd.japannet-jpnstore-wakeup +application/vnd.japannet-payment-wakeup +application/vnd.japannet-registration +application/vnd.japannet-registration-wakeup +application/vnd.japannet-setstore-wakeup +application/vnd.japannet-verification +application/vnd.japannet-verification-wakeup +application/vnd.koan +application/vnd.lotus-1-2-3 +application/vnd.lotus-approach +application/vnd.lotus-freelance +application/vnd.lotus-organizer +application/vnd.lotus-screencam +application/vnd.lotus-wordpro +application/vnd.meridian-slingshot +application/vnd.mif mif +application/vnd.minisoft-hp3000-save +application/vnd.mitsubishi.misty-guard.trustweb +application/vnd.ms-artgalry +application/vnd.ms-asf +application/vnd.ms-excel xls +application/vnd.ms-powerpoint ppt +application/vnd.ms-project +application/vnd.ms-tnef +application/vnd.ms-works +application/vnd.music-niff +application/vnd.musician +application/vnd.netfpx +application/vnd.noblenet-directory +application/vnd.noblenet-sealer +application/vnd.noblenet-web +application/vnd.novadigm.EDM +application/vnd.novadigm.EDX +application/vnd.novadigm.EXT +application/vnd.osa.netdeploy +application/vnd.powerbuilder6 +application/vnd.powerbuilder6-s +application/vnd.rapid +application/vnd.seemail +application/vnd.shana.informed.formtemplate +application/vnd.shana.informed.interchange +application/vnd.shana.informed.package +application/vnd.street-stream +application/vnd.svd +application/vnd.swiftview-ics +application/vnd.truedoc +application/vnd.visio +application/vnd.webturbo +application/vnd.wrq-hp3000-labelled +application/vnd.wt.stf +application/vnd.xara +application/vnd.yellowriver-custom-menu +application/wita +application/wordperfect5.1 +application/x-bcpio bcpio +application/x-cdlink vcd +application/x-chess-pgn pgn +application/x-compress +application/x-cpio cpio +application/x-csh csh +application/x-director dcr dir dxr +application/x-dvi dvi +application/x-futuresplash spl +application/x-gtar gtar +application/x-gzip +application/x-hdf hdf +application/x-javascript js +application/x-koan skp skd skt skm +application/x-latex latex +application/x-netcdf nc cdf +application/x-sh sh +application/x-shar shar +application/x-shockwave-flash swf +application/x-stuffit sit +application/x-sv4cpio sv4cpio +application/x-sv4crc sv4crc +application/x-tar tar +application/x-tcl tcl +application/x-tex tex +application/x-texinfo texinfo texi +application/x-troff t tr roff +application/x-troff-man man +application/x-troff-me me +application/x-troff-ms ms +application/x-ustar ustar +application/x-wais-source src +application/x400-bp +application/xml +application/zip zip +audio/32kadpcm +audio/basic au snd +audio/midi mid midi kar +audio/mpeg mpga mp2 mp3 +audio/vnd.qcelp +audio/x-aiff aif aiff aifc +audio/x-pn-realaudio ram rm +audio/x-pn-realaudio-plugin rpm +audio/x-realaudio ra +audio/x-wav wav +chemical/x-pdb pdb xyz +image/bmp bmp +image/cgm +image/g3fax +image/gif gif +image/ief ief +image/jpeg jpeg jpg jpe +image/naplps +image/png png +image/prs.btif +image/tiff tiff tif +image/vnd.dwg +image/vnd.dxf +image/vnd.fpx +image/vnd.net-fpx +image/vnd.svf +image/vnd.xiff +image/x-cmu-raster ras +image/x-portable-anymap pnm +image/x-portable-bitmap pbm +image/x-portable-graymap pgm +image/x-portable-pixmap ppm +image/x-rgb rgb +image/x-xbitmap xbm +image/x-xpixmap xpm +image/x-xwindowdump xwd +message/delivery-status +message/disposition-notification +message/external-body +message/http +message/news +message/partial +message/rfc822 +model/iges igs iges +model/mesh msh mesh silo +model/vnd.dwf +model/vrml wrl vrml +multipart/alternative +multipart/appledouble +multipart/byteranges +multipart/digest +multipart/encrypted +multipart/form-data +multipart/header-set +multipart/mixed +multipart/parallel +multipart/related +multipart/report +multipart/signed +multipart/voice-message +text/css css +text/directory +text/enriched +text/html html htm +text/plain asc txt +text/prs.lines.tag +text/rfc822-headers +text/richtext rtx +text/rtf rtf +text/sgml sgml sgm +text/tab-separated-values tsv +text/uri-list +text/vnd.abc +text/vnd.flatland.3dml +text/vnd.fmi.flexstor +text/vnd.in3d.3dml +text/vnd.in3d.spot +text/vnd.latex-z +text/x-setext etx +text/xml xml +video/mpeg mpeg mpg mpe +video/quicktime qt mov +video/vnd.motorola.video +video/vnd.motorola.videop +video/vnd.vivo +video/x-msvideo avi +video/x-sgi-movie movie +x-conference/x-cooltalk ice diff --git a/lib/abyss/htdocs/index.htm b/lib/abyss/htdocs/index.htm new file mode 100644 index 0000000..f0369a5 --- /dev/null +++ b/lib/abyss/htdocs/index.htm @@ -0,0 +1,21 @@ + + +ABYSS is working !!! + + +

Congratulations, ABYSS is working !!!

+
+

+ABYSS Web Server is working correctly on your system. You should now change this +page with yours. +
+Please include in your web pages (at least the first), the 'Powered by ABYSS' +banner to promote the use of ABYSS. +

+
+

+

+Copyright © 2000 Moez Mahfoudh. All rights reserved. + +

+ diff --git a/lib/abyss/htdocs/pwrabyss.gif b/lib/abyss/htdocs/pwrabyss.gif new file mode 100644 index 0000000000000000000000000000000000000000..9a4a3a3c1fa78ddc71f1251b7bf236931158e6d3 GIT binary patch literal 2198 zcmeH}`&Sb70>Hn3DZUa#6P+d`m{?n~t{KeCG!cl*;cL03D853=oHk$8LBV{X;y{hW zMF~q&Or5l{xuK@16=^!so3U~hYE!&M<7TDz?%aRj{nMz+f|dk zLZMJ9fl{gL?FGHPy+cD_XlO{S25PlhqX8O?Mymx{tyZT4I-O3h2YS8UXaq*1abp8) z{LSA6{vQT*{#C$VEdcmBID7|1>5%qu;YhDz!yT6gN)YaQ{(%vc3|63avu9E}OYT;q zgUVf~U9u6OXZSTgCvH%11xOebjdXfc*Y3?)oEdp7Gq>KAci)9AWIb%62)&l#`;)9H zT}{TM5NXhOB?&(~7xs1YV=>HQX1<2iN4LXK!QNA>l43|)@40MC-(|XRKR4FiJ6si6 zNpc@{5pZQsZzBEF&6dmqBWAEz!?RPl^C331`nvRMkGENDA~;C@-9Sj;Uq)Nq+c}-E z5@NeMydvUN9}6lbL};tT4Jq2IGOn&0FpKU(i-XxwuE;sAxOe|2Cs#6wv{xh|>~3lk z6axJG*G+yY{bA^zuD2n>o68zMELQuVc1=A$qv9{>!*ASu`(+dCqACCJI87u^?#~=4 z>~=f%piriXaw`NJxW&ty#^PzB+!i!JIIvu3yC?|4oA#KEpIz^|NQ! zMh^ZS`XR}1iM|=0E2MQ~z8EhgV05uucjXr3Y0T3w4&74Z6JQ+@^=Ck~crY6m>zsTL zW&(wyA=duw*#Jc3^R#7=$r?`LHe08O6WcxOall5Fii-_6k@NW`##>4(&5VI~#MMRS z>YzIWvReB2a>Goc+u@72`bP8Mh*G={0FtamCuA|c&QL@*7l;Pv=0%1g`FibHdsth^ zzr-!kNmpcvNoK=S14UaQmTlCR@n0}HDOIw@YWOh@bTj$#WJ0oRo!xfD>(hEg=s?u* z)=RR&El8MahZIKkY)qb`bPP_Wbv&-S_VJOY2^IL8e%Z#aazE-j1&Je+5u2%~=IBS8 zuY|%gy1w}|T_5^p^bn&8wFHmlIF(rf6Sp(qr3(8LsCuwU%K)eWQoyFevK{o);Tsah zedEcg=OxY<0mMQVJNddA7k_@1;y#*Kq|Di(>l(03srzE0cHh3tOY09NS>#K_dt#2? z?ccXhY zH9jvjcBhl!COiA!j?<@eW<}9ejNcrm5l|CC@K#4Ag!jqXysZA@+CuZy_O->fAFD{= z8F6<2F!dHd<}f|&@0NcuF28$q;WcoEA`-&_#lLL7{(kk|z<0-gZpcx$yqJvM_Q%d*9v6oG4`*DdjXo2(l zP^e?vuNk;!w<$Asu&`xuqUrWl5s&er##H(+$&tkTW;vSBN*u$c^c=Cye}nZZYxDMn zH_*3v*In-z+h_WoVo|ahcwI7jRt@R1N?`=8-CBxT2ZBN?neW!xR29=h6<|{ugt41z zF?&cA46oWF@w0gBLJhS^3I{tFofT+;IzNWfOLrIE(~|`9ZJh!2>Tmm*&0`@>Z)I?5Gyb z!VuDOS3Ud8lRt)VhopnMJRH-bPxvK}Kg%1(UX*#D^6+*?@}89)OLsVj81B0;#VIX{ zDI2~q%}oeSDXGhR{*FWhhQ0}*ieo5sg>?8=&t&k literal 0 HcmV?d00001 diff --git a/lib/abyss/license.txt b/lib/abyss/license.txt new file mode 100644 index 0000000..1ee9c9f --- /dev/null +++ b/lib/abyss/license.txt @@ -0,0 +1,27 @@ + ABYSS Web Server License + ------------------------ + +Copyright (C) 2000 by Moez Mahfoudh . All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. +3. The name of the author may not be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +SUCH DAMAGE. diff --git a/lib/abyss/patch_notes.txt b/lib/abyss/patch_notes.txt new file mode 100644 index 0000000..8ca4f77 --- /dev/null +++ b/lib/abyss/patch_notes.txt @@ -0,0 +1,114 @@ +Notes about the Abyss Patch -- By: Rosimildo da Silva, Jan 31, 2001. +------------------------------------------------------------------- + +This file contains some notes about the changes made to the +Abyss source tree. The changes were required to fix a few +bugs, and port the base code to compile under CygWin, +and Borland C++ free compiler. The free compiler for +Win32 from Borland can be downloaded from here: + + http://www.borland.com/bcppbuilder/freecompiler/ + + +What is new: + + + Package should compile out of the box under CygWin + + + Added makefiles and changes to use Borland C++ compiler +under WIN32 as well as VC++ 6.0 + + + Fix Abyss.dsp to use the proper thread safe libraries, +and updated to VC++ 6.0 + + + Fixed thread leaks ( handles ) + + + +Applying the patch to Abyss-0.3.tar.gz +-------------------------------------- + + + get archive from here: + http://abyss.linuxave.net/abyss-0.3.tar.gz +WARNING: this site seems to be dead for the last two months. + + + cd /work ( any dir ) + tar xzvf abyss-0.3.tar.gz + cd abyss + patch -p1 + ( BCC_PATH=d:\bcb5 ) + + make -f makefile.bcc32 + + c) VC++ 6.0 + cd abyss\src + msdev Abyss.dsp + ( Or just open the workspace with Visual Studio, and you know + the drill ). +NOTE: Under Cygwin, after I apply the patch, Visual Studio was unable to +recognize the workspace. ??? + + +List of changes done to the ABYSS http server: ( ChangesLog ) +---------------------------------------------- + + + changed _WIN32 to ABYSS_WIN32. THis solve the problem that the +macro _WIN32 is defined under CygWin. CygWin has a unix like +api ( _UNIX ), so the macro _UNIX should be defined then. +Under CygWin we would have _UNIX and _WIN32 defined at the same +time. + + + + Theead API -- Added two extra functions: ThreadExit() and +ThreadClose(). These allows the resources of the threads to be +released when the thread has complete its duty serving the +request. + + + Added extra flag to TConn structure to make possible the +management of the worker threads by the server. + + + + Changed allocation of TConn array from stack to heap. This +would cause problems on certain system ( specially embedded systems ), +where the stack sizes arr not that large. + + + Changed ServerRun to free thread resources when the connection +for the thread is closed. + + + Changed main.c to make the sginal registration conforming with +the usage of the _FORK option. + + + Change ThreadCreate to be able to specify the "stack size" of the +worker's threads ( pthread ). Defined lable for it. + + + + Added flag _NO_USERS to disable check for users and groups. +This is useful for embedded systems where no users are available. + + + Updated VC++ workspace to version 6.0 + + + + Changed the creation of the thread under WIN32 to use a RTL +function ( _beginthreadex ), as recommend by MS, instead of using +the naked WIN32 API. + +-- +Rosimildo da Silva rdasilva@connectel.com +ConnectTel, Inc. Austin, TX -- USA +Phone : 512-338-1111 Fax : 512-918-0449 +Company Page: http://www.connecttel.com +Home Page: http://members.nbci.com/rosimildo/ diff --git a/lib/abyss/readme.txt b/lib/abyss/readme.txt new file mode 100644 index 0000000..c42ca1f --- /dev/null +++ b/lib/abyss/readme.txt @@ -0,0 +1,160 @@ + + + ABYSS Web Server + ------------------ + + +About: +------ + +ABYSS aims to be a fully HTTP/1.1 compliant web server. Its main design +goals are speed, low resource usage and portability. ABYSS works on most +UNIX based systems and on Win32 systems (Win95/98/2000/NT). + +Copyright: +---------- + +Copyright (C) 2000 Moez Mahfoudh. All rights reserved. + +Status: +------- + +ABYSS is still in development stage. Actual version is 0.3. Many features +are not implemented yet but the server core works well and seems to be +stable. It is fully reliable for serving static files on medium load sites. +In fact, primary benchmarks show that ABYSS is 70% as fast as Apache when +using the fork system. This rate jumps to 130% when using threads. +On UNIX platforms, some problems occurred because of the use of the Pthreads +library. This will be corrected in the future versions. That's why only the +fork system is usable under UNIX. This lowers performances but guarantees +stability. +CGI/1.1 support is still absent from the current version but will be +included in the near future. + +Change Log: +----------- + + * Version 0.3 (March 23,2000): + o Handles conditional GET requests (by date) + o Conforms to all the MUSTs of the RFC2616 (newer version of the + HTTP/1.1 protocol draft) + o New configuration options (such as pidfile for UNIX systems...) + o Handles HEAD and OPTIONS methods + o Many bug fixes + o Tested on Sun-OS 5.7 + o Second public release + + * Version 0.2 beta (February 7,2000): + o Handles GET on static files + o Handles correctly range requests + o Conforms to 80% of the MUSTs of the RFC2068 (HTTP/1.1 protocol + draft) + o Improved code portability (Win32 and UNIX platforms) + o Tested on Linux 2.2 and Win95/98 + o First public release + + * Version 0.1 (January 2000): + o Completely rewritten in C + o Speed improvement + o New memory allocation scheme (using pools) + o Never released + + * Version 0.0 (January 2000): + o Initial version + o Written in C++ + o Never released + +Downloading: +------------ + + * Version 0.3 (current version): + o UNIX package (source) abyss-0.3.tar.gz. + o Win32 package is not available but you can extract source files + from the UNIX package and compile them on Windows without any + modification. (Sorry for this inconvenience: I have no Windows + machine now to compile the program and to test it. If someone can + do that, please email me the zipped package and I'll add it here). + + * Version 0.2 beta: + o UNIX package (source) abyss-0.2b.tar.gz. + o Win32 package (source+binary) abyss-0.2b.zip. + +Installation: +------------- + + * For UNIX systems: + o Untar/Ungzip the distribution package with a command like tar xvfz + abyss-x.y.tar.gz + o Edit the Makefile src/Makefile to meet your system requirements. + o Go to directory src and execute make. + o The server binary is generated and stored in the bin directory. + o Edit the conf/abyss.conf to reflect your system configuration (At + least change the paths). + o Goto to the bin directory and start the server by typing ./abyss + -c ../conf/abyss.conf + + * For Win32 systems: + o Unzip the distribution package. + o An executable file is already present in the bin directory. + o If you wish to recompile the server, open the src/abyss.dsw file + with Microsoft Visual C++ 5.0 or higher and rebuild the project. + o Edit the conf/abyss.conf to reflect your system configuration (At + least change the paths). + o Goto to the bin directory and start the server by typing ./abyss + -c ../conf/abyss.conf + +Configuration: +-------------- + +Edit the conf/abyss.conf file and change the values of the available +options. + +Bugs: +----- + +Please email bug reports to mmoez@bigfoot.com + +To do: +------ + + * CGI/1.1 support + * Web based configuration/administration + * Speed improvement + * File caching system + * Throttling + * PUT method handling + * ... + +License: +-------- + +ABYSS Web Server is licensed under a modified BSD type license: + + Copyright (C) 2000 Moez Mahfoudh. All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + * Redistributions of source code must retain the above + copyright notice, this list of conditions and the following + disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials + provided with the distribution. + * The name of the author may not be used to endorse or promote + products derived from this software without specific prior + written permission. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS + OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/lib/abyss/src/Abyss.dsp b/lib/abyss/src/Abyss.dsp new file mode 100644 index 0000000..dad1e38 --- /dev/null +++ b/lib/abyss/src/Abyss.dsp @@ -0,0 +1,134 @@ +# Microsoft Developer Studio Project File - Name="Abyss" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + +CFG=Abyss - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "Abyss.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "Abyss.mak" CFG="Abyss - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "Abyss - Win32 Release" (based on "Win32 (x86) Console Application") +!MESSAGE "Abyss - Win32 Debug" (based on "Win32 (x86) Console Application") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "Abyss - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "../bin" +# PROP Intermediate_Dir "objs" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /MT /W3 /GX /O2 /I "../include" /I "../../../.." /I "../../.." /I "../../../include" /I "../../../lib/util/include" /D "NDEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D "ABYSS_WIN32" /YX /FD /c +# ADD BASE RSC /l 0x40c /d "NDEBUG" +# ADD RSC /l 0x40c /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 +# ADD LINK32 kernel32.lib user32.lib wsock32.lib ..\..\xmlrpc.lib /nologo /subsystem:console /machine:I386 + +!ELSEIF "$(CFG)" == "Abyss - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "../bin" +# PROP Intermediate_Dir "objs" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /I "../../../.." /I "../../.." /I "../../../include" /I "../../../lib/util/include" /D "_DEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D "ABYSS_WIN32" /YX /FD /c +# ADD BASE RSC /l 0x40c /d "_DEBUG" +# ADD RSC /l 0x40c /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept +# ADD LINK32 kernel32.lib user32.lib wsock32.lib ..\..\xmlrpcD.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept + +!ENDIF + +# Begin Target + +# Name "Abyss - Win32 Release" +# Name "Abyss - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "c" +# Begin Source File + +SOURCE=.\conf.c +# End Source File +# Begin Source File + +SOURCE=.\conn.c +# End Source File +# Begin Source File + +SOURCE=.\data.c +# End Source File +# Begin Source File + +SOURCE=.\file.c +# End Source File +# Begin Source File + +SOURCE=.\http.c +# End Source File +# Begin Source File + +SOURCE=.\main.c +# End Source File +# Begin Source File + +SOURCE=.\server.c +# End Source File +# Begin Source File + +SOURCE=.\socket.c +# End Source File +# Begin Source File + +SOURCE=.\trace.c +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h" +# Begin Source File + +SOURCE=.\abyss.h +# End Source File +# End Group +# End Target +# End Project diff --git a/lib/abyss/src/Abyss.dsw b/lib/abyss/src/Abyss.dsw new file mode 100644 index 0000000..4e27c99 --- /dev/null +++ b/lib/abyss/src/Abyss.dsw @@ -0,0 +1,29 @@ +Microsoft Developer Studio Workspace File, Format Version 6.00 +# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! + +############################################################################### + +Project: "Abyss"=.\Abyss.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Global: + +Package=<5> +{{{ +}}} + +Package=<3> +{{{ +}}} + +############################################################################### + diff --git a/lib/abyss/src/Makefile b/lib/abyss/src/Makefile new file mode 100644 index 0000000..b8b4db3 --- /dev/null +++ b/lib/abyss/src/Makefile @@ -0,0 +1,73 @@ +ifeq ($(SRCDIR)x,x) +SRCDIR = $(CURDIR)/../../.. +endif +SUBDIR = lib/abyss/src + +include $(SRCDIR)/Makefile.config + +CFLAGS = $(CFLAGS_COMMON) +CFLAGS += -D_UNIX +ifeq ($(ENABLE_ABYSS_THREADS),yes) + THREAD_MODULE = thread_pthread +else + THREAD_MODULE = thread_fork +endif +CFLAGS += $(CFLAGS_PERSONAL) $(CADD) +LIBLDFLAGS = $(LDFLAGS_VERSINFO) -rpath $(LIBINST_DIR) +LIBLDFLAGS += $(LADD) + +INCLUDES = -I$(SRCDIR) -I$(SRCDIR)/include -I$(SRCDIR)/lib/util/include + +LTLIBRARIES_TO_INSTALL = libxmlrpc_abyss.la + +default: all + +.PHONY: all +all: libxmlrpc_abyss.la + + +ABYSS_OBJS = \ + conf.lo \ + conn.lo \ + data.lo \ + date.lo \ + file.lo \ + http.lo \ + response.lo \ + server.lo \ + session.lo \ + socket.lo \ + socket_unix.lo \ + token.lo \ + $(THREAD_MODULE).lo \ + trace.lo \ + + +libxmlrpc_abyss.la: $(ABYSS_OBJS) + $(LIBTOOL) --mode=link $(CCLD) -o $@ $(LIBLDFLAGS) $^ + +$(ABYSS_OBJS):%.lo:%.c + $(LIBTOOL) --mode=compile $(CC) -c $(INCLUDES) \ + $(CFLAGS) $< + +.PHONY: clean +clean: clean-common + +.PHONY: distclean +distclean: clean distclean-common + +.PHONY: tags +tags: TAGS + +.PHONY: distdir +distdir: + +.PHONY: install +install: install-common + +.PHONY: dep +dep: dep-common + +include $(SRCDIR)/Makefile.common + +include Makefile.depend diff --git a/lib/abyss/src/Makefile.depend b/lib/abyss/src/Makefile.depend new file mode 100644 index 0000000..e69de29 diff --git a/lib/abyss/src/abyss_info.h b/lib/abyss/src/abyss_info.h new file mode 100644 index 0000000..1d3db45 --- /dev/null +++ b/lib/abyss/src/abyss_info.h @@ -0,0 +1,20 @@ +#ifndef ABYSS_INFO_H_INCLUDED +#define ABYSS_INFO_H_INCLUDED + +#define SERVER_VERSION "1.06" + +#define SERVER_HVERSION "XMLRPC_ABYSS/1.06" + +#define SERVER_HTML_INFO \ + "


" \ + "ABYSS Web Server for XML-RPC For C/C++ " \ + "version "SERVER_VERSION"
" \ + "

" + +#define SERVER_PLAIN_INFO \ + CRLF "----------------------------------------" \ + "----------------------------------------" \ + CRLF "ABYSS Web Server for XML-RPC For C/C++ " \ + "version "SERVER_VERSION CRLF"See xmlrpc-c.sourceforge.net" + +#endif diff --git a/lib/abyss/src/conf.c b/lib/abyss/src/conf.c new file mode 100644 index 0000000..84d7c97 --- /dev/null +++ b/lib/abyss/src/conf.c @@ -0,0 +1,379 @@ +/****************************************************************************** +** +** conf.c +** +** This file is part of the ABYSS Web server project. +** +** Copyright (C) 2000 by Moez Mahfoudh . +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +** ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +** OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +** HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +** LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +** OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +** SUCH DAMAGE. +** +******************************************************************************/ + +#include +#include +#include + +#if defined(WIN32) && !defined(__BORLANDC__) +#include +#endif + +#ifdef _UNIX +#include +#endif + +#include "xmlrpc_config.h" +#include "xmlrpc-c/string_int.h" +#include "xmlrpc-c/abyss.h" +#include "trace.h" +#include "server.h" +#include "http.h" + +/********************************************************************* +** Configuration Files Parsing Functions +*********************************************************************/ + + + +static abyss_bool +ConfReadLine(TFile *f,char *buffer,uint32_t len) { + abyss_bool r=TRUE; + char c,*p,*z=buffer; + + while ((--len)>0) + { + if (FileRead(f,buffer,1)<1) + { + if (z==buffer) + r=FALSE; + break; + }; + + if ((*buffer==CR) || (*buffer==LF) ) + break; + + buffer++; + }; + + if (len==0) + while (FileRead(f,&c,1)==1) + if ((c==CR) || (c==LF)) + break; + + *buffer='\0'; + + /* Discard comments */ + p=strchr(z,'#'); + if (p) + *p='\0'; + + return r; +} + +static abyss_bool +ConfNextToken(char **p) { + while (1) + switch (**p) + { + case '\t': + case ' ': + (*p)++; + break; + case '\0': + return FALSE; + default: + return TRUE; + }; +} + +static char * +ConfGetToken(char **p) { + char *p0=*p; + + while (1) + switch (**p) + { + case '\t': + case ' ': + case CR: + case LF: + case '\0': + if (p0==*p) + return NULL; + + if (**p) + { + **p='\0'; + (*p)++; + }; + return p0; + + default: + (*p)++; + }; +} + +static abyss_bool +ConfReadInt(const char * const p, + int32_t * const n, + int32_t const min, + int32_t const max) { +/*---------------------------------------------------------------------------- + Convert string 'p' to integer *n. + + If it isn't a valid integer or is not with the bounds [min, max], + return FALSE. Otherwise, return TRUE. +-----------------------------------------------------------------------------*/ + char * e; + + *n = strtol(p, &e, 10); + + if (min != max) + return ((e != p) && (*n >= min) && (*n <= max)); + else + return (e != p); +} + + + +static abyss_bool +ConfReadBool(char *p, abyss_bool *b) { + if (strcasecmp(p,"yes")==0) + { + *b=TRUE; + return TRUE; + }; + + if (strcasecmp(p,"no")==0) + { + *b=FALSE; + return TRUE; + }; + + return FALSE; +} + +/********************************************************************* +** MIME Types File +*********************************************************************/ + +static void +readMIMETypesFile(const char * const filename, + MIMEType ** const MIMETypePP) { + + abyss_bool success; + MIMEType * MIMETypeP; + + MIMETypeP = MIMETypeCreate(); + if (MIMETypeP) { + TFile file; + abyss_bool fileOpened; + + fileOpened = FileOpen(&file, filename, O_RDONLY); + if (fileOpened) { + char z[512]; + while (ConfReadLine(&file, z, 512)) { + char * p; + p = &z[0]; + + if (ConfNextToken(&p)) { + const char * mimetype = ConfGetToken(&p); + if (mimetype) { + while (ConfNextToken(&p)) { + const char * const ext = ConfGetToken(&p); + if (ext) + MIMETypeAdd2(MIMETypeP, mimetype, ext); + else + break; + } + } + } + } + FileClose(&file); + success = TRUE; + } else + success = FALSE; + if (!success) + MIMETypeDestroy(MIMETypeP); + } else + success = FALSE; + + if (success) + *MIMETypePP = MIMETypeP; + else + *MIMETypePP = NULL; +} + +/********************************************************************* +** Server Configuration File +*********************************************************************/ + +static void +chdirx(const char * const newdir, + abyss_bool * const successP) { + +#if defined(WIN32) && !defined(__BORLANDC__) + *successP = _chdir(newdir) == 0; +#else + *successP = chdir(newdir) == 0; +#endif +} + + + +static void +parseUser(const char * const p, + struct _TServer * const srvP) { +#ifdef _UNIX + if (p[0] == '#') { + int32_t n; + + if (!ConfReadInt(&p[1], &n, 0, 0)) + TraceExit("Bad user number '%s'", p); + else + srvP->uid = n; + } else { + struct passwd * pwd; + + if (!(pwd = getpwnam(p))) + TraceExit("Unknown user '%s'", p); + + srvP->uid = pwd->pw_uid; + if ((int)srvP->gid==(-1)) + srvP->gid = pwd->pw_gid; + }; +#else + TraceMsg("User option ignored"); +#endif /* _UNIX */ +} + + + +static void +parsePidfile(const char * const p, + struct _TServer * const srvP) { +#ifdef _UNIX + if (!FileOpenCreate(&srvP->pidfile, p, O_TRUNC | O_WRONLY)) { + srvP->pidfile = -1; + TraceMsg("Bad PidFile value '%s'", p); + }; +#else + TraceMsg("PidFile option ignored"); +#endif /* _UNIX */ +} + + + +abyss_bool +ConfReadServerFile(const char * const filename, + TServer * const serverP) { + + struct _TServer * const srvP = serverP->srvP; + + TFile f; + char z[512]; + char * p; + unsigned int lineNum; + TFileStat fs; + + if (!FileOpen(&f, filename, O_RDONLY)) + return FALSE; + + lineNum = 0; + + while (ConfReadLine(&f, z, 512)) { + ++lineNum; + p = z; + + if (ConfNextToken(&p)) { + const char * const option = ConfGetToken(&p); + if (option) { + ConfNextToken(&p); + + if (strcasecmp(option, "port") == 0) { + int32_t n; + if (ConfReadInt(p, &n, 1, 65535)) + srvP->port = n; + else + TraceExit("Invalid port '%s'", p); + } else if (strcasecmp(option, "serverroot") == 0) { + abyss_bool success; + chdirx(p, &success); + if (!success) + TraceExit("Invalid server root '%s'",p); + } else if (strcasecmp(option, "path") == 0) { + if (FileStat(p, &fs)) + if (fs.st_mode & S_IFDIR) { + xmlrpc_strfree(srvP->filespath); + srvP->filespath = strdup(p); + continue; + } + TraceExit("Invalid path '%s'", p); + } else if (strcasecmp(option, "default") == 0) { + const char * filename; + + while ((filename = ConfGetToken(&p))) { + ListAdd(&srvP->defaultfilenames, strdup(filename)); + if (!ConfNextToken(&p)) + break; + } + } else if (strcasecmp(option, "keepalive") == 0) { + int32_t n; + if (ConfReadInt(p, &n, 1, 65535)) + srvP->keepalivemaxconn = n; + else + TraceExit("Invalid KeepAlive value '%s'", p); + } else if (strcasecmp(option, "timeout") == 0) { + int32_t n; + if (ConfReadInt(p, &n, 1, 3600)) { + srvP->keepalivetimeout = n; + /* Must see what to do with that */ + srvP->timeout = n; + } else + TraceExit("Invalid TimeOut value '%s'", p); + } else if (strcasecmp(option, "mimetypes") == 0) { + readMIMETypesFile(p, &srvP->mimeTypeP); + if (!srvP->mimeTypeP) + TraceExit("Can't read MIME Types file '%s'", p); + } else if (strcasecmp(option,"logfile") == 0) { + srvP->logfilename = strdup(p); + } else if (strcasecmp(option,"user") == 0) { + parseUser(p, srvP); + } else if (strcasecmp(option, "pidfile")==0) { + parsePidfile(p, srvP); + } else if (strcasecmp(option, "advertiseserver") == 0) { + if (!ConfReadBool(p, &srvP->advertise)) + TraceExit("Invalid boolean value " + "for AdvertiseServer option"); + } else + TraceExit("Invalid option '%s' at line %u", + option, lineNum); + } + } + } + + FileClose(&f); + return TRUE; +} diff --git a/lib/abyss/src/conn.c b/lib/abyss/src/conn.c new file mode 100644 index 0000000..ab86fd3 --- /dev/null +++ b/lib/abyss/src/conn.c @@ -0,0 +1,637 @@ +/* Copyright information is at the end of the file. */ + +#include +#include +#include +#include +#include +#include + +#include "mallocvar.h" +#include "xmlrpc-c/util_int.h" +#include "xmlrpc-c/string_int.h" +#include "xmlrpc-c/sleep_int.h" +#include "xmlrpc-c/abyss.h" +#include "socket.h" +#include "server.h" +#include "thread.h" + +#include "conn.h" + +/********************************************************************* +** Conn +*********************************************************************/ + +static TThreadProc connJob; + +static void +connJob(void * const userHandle) { +/*---------------------------------------------------------------------------- + This is the root function for a thread that processes a connection + (performs HTTP transactions). +-----------------------------------------------------------------------------*/ + TConn * const connectionP = userHandle; + + (connectionP->job)(connectionP); + + connectionP->finished = TRUE; + /* Note that if we are running in a forked process, setting + connectionP->finished has no effect, because it's just our own + copy of *connectionP. In this case, Parent must update his own + copy based on a SIGCHLD signal that the OS will generate right + after we exit. + */ + + ThreadExit(0); +} + + + +static void +connDone(TConn * const connectionP) { + + /* In the forked case, this is designed to run in the parent + process after the child has terminated. + */ + connectionP->finished = TRUE; + + if (connectionP->done) + connectionP->done(connectionP); +} + + + +static TThreadDoneFn threadDone; + +static void +threadDone(void * const userHandle) { + + TConn * const connectionP = userHandle; + + connDone(connectionP); +} + + + +static void +makeThread(TConn * const connectionP, + enum abyss_foreback const foregroundBackground, + abyss_bool const useSigchld, + const char ** const errorP) { + + switch (foregroundBackground) { + case ABYSS_FOREGROUND: + connectionP->hasOwnThread = FALSE; + *errorP = NULL; + break; + case ABYSS_BACKGROUND: { + const char * error; + connectionP->hasOwnThread = TRUE; + ThreadCreate(&connectionP->threadP, connectionP, + &connJob, &threadDone, useSigchld, + &error); + if (error) { + xmlrpc_asprintf(errorP, "Unable to create thread to " + "process connection. %s", error); + xmlrpc_strfree(error); + } else + *errorP = NULL; + } break; + } /* switch */ +} + + + +void +ConnCreate(TConn ** const connectionPP, + TServer * const serverP, + TSocket * const connectedSocketP, + TThreadProc * const job, + TThreadDoneFn * const done, + enum abyss_foreback const foregroundBackground, + abyss_bool const useSigchld, + const char ** const errorP) { +/*---------------------------------------------------------------------------- + Create an HTTP connection. + + A connection carries one or more HTTP transactions (request/response). + + 'connectedSocketP' transports the requests and responses. + + The connection handles those HTTP requests. + + The connection handles the requests primarily by running the + function 'job' once. Some connections can do that autonomously, as + soon as the connection is created. Others don't until Caller + subsequently calls ConnProcess. Some connections complete the + processing before ConnProcess return, while others may run the + connection asynchronously to the creator, in the background, via a + TThread thread. 'foregroundBackground' determines which. + + 'job' calls methods of the connection to get requests and send + responses. + + Some time after the HTTP transactions are all done, 'done' gets + called in some context. +-----------------------------------------------------------------------------*/ + TConn * connectionP; + + MALLOCVAR(connectionP); + + if (connectionP == NULL) + xmlrpc_asprintf(errorP, "Unable to allocate memory for a connection " + "descriptor."); + else { + abyss_bool success; + uint16_t peerPortNumber; + + connectionP->server = serverP; + connectionP->socketP = connectedSocketP; + connectionP->buffersize = 0; + connectionP->bufferpos = 0; + connectionP->finished = FALSE; + connectionP->job = job; + connectionP->done = done; + connectionP->inbytes = 0; + connectionP->outbytes = 0; + connectionP->trace = getenv("ABYSS_TRACE_CONN"); + + SocketGetPeerName(connectedSocketP, + &connectionP->peerip, &peerPortNumber, &success); + + if (success) + makeThread(connectionP, foregroundBackground, useSigchld, errorP); + else + xmlrpc_asprintf(errorP, "Failed to get peer name from socket."); + } + *connectionPP = connectionP; +} + + + +abyss_bool +ConnProcess(TConn * const connectionP) { +/*---------------------------------------------------------------------------- + Drive the main processing of a connection -- run the connection's + "job" function, which should read HTTP requests from the connection + and send HTTP responses. + + If we succeed, we guarantee the connection's "done" function will get + called some time after all processing is complete. It might be before + we return or some time after. If we fail, we guarantee the "done" + function will not be called. +-----------------------------------------------------------------------------*/ + abyss_bool retval; + + if (connectionP->hasOwnThread) { + /* There's a background thread to handle this connection. Set + it running. + */ + retval = ThreadRun(connectionP->threadP); + } else { + /* No background thread. We just handle it here while Caller waits. */ + (connectionP->job)(connectionP); + connDone(connectionP); + retval = TRUE; + } + return retval; +} + + + +void +ConnWaitAndRelease(TConn * const connectionP) { + if (connectionP->hasOwnThread) + ThreadWaitAndRelease(connectionP->threadP); + + free(connectionP); +} + + + +abyss_bool +ConnKill(TConn * connectionP) { + connectionP->finished = TRUE; + return ThreadKill(connectionP->threadP); +} + + + +void +ConnReadInit(TConn * const connectionP) { + if (connectionP->buffersize>connectionP->bufferpos) { + connectionP->buffersize -= connectionP->bufferpos; + memmove(connectionP->buffer, + connectionP->buffer+connectionP->bufferpos, + connectionP->buffersize); + connectionP->bufferpos = 0; + } else + connectionP->buffersize=connectionP->bufferpos = 0; + + connectionP->inbytes=connectionP->outbytes = 0; +} + + + +static void +traceBuffer(const char * const label, + const char * const buffer, + unsigned int const size) { + + unsigned int nonPrintableCount; + unsigned int i; + + nonPrintableCount = 0; /* Initial value */ + + for (i = 0; i < size; ++i) { + if (!isprint(buffer[i]) && buffer[i] != '\n' && buffer[i] != '\r') + ++nonPrintableCount; + } + if (nonPrintableCount > 0) + fprintf(stderr, "%s contains %u nonprintable characters.\n", + label, nonPrintableCount); + + fprintf(stderr, "%s:\n", label); + fprintf(stderr, "%.*s\n", (int)size, buffer); +} + + + +static void +traceSocketRead(TConn * const connectionP, + unsigned int const size) { + + if (connectionP->trace) + traceBuffer("READ FROM SOCKET", + connectionP->buffer + connectionP->buffersize, size); +} + + + +static void +traceSocketWrite(TConn * const connectionP, + const char * const buffer, + unsigned int const size, + abyss_bool const failed) { + + if (connectionP->trace) { + const char * const label = + failed ? "FAILED TO WRITE TO SOCKET" : "WROTE TO SOCKET"; + traceBuffer(label, buffer, size); + } +} + + + +static uint32_t +bufferSpace(TConn * const connectionP) { + + return BUFFER_SIZE - connectionP->buffersize; +} + + + +abyss_bool +ConnRead(TConn * const connectionP, + uint32_t const timeout) { +/*---------------------------------------------------------------------------- + Read some stuff on connection *connectionP from the socket. + + Don't wait more than 'timeout' seconds for data to arrive. Fail if + nothing arrives within that time. +-----------------------------------------------------------------------------*/ + time_t const deadline = time(NULL) + timeout; + + abyss_bool cantGetData; + abyss_bool gotData; + + cantGetData = FALSE; + gotData = FALSE; + + while (!gotData && !cantGetData) { + int const timeLeft = deadline - time(NULL); + + if (timeLeft <= 0) + cantGetData = TRUE; + else { + int rc; + + rc = SocketWait(connectionP->socketP, TRUE, FALSE, + timeLeft * 1000); + + if (rc != 1) + cantGetData = TRUE; + else { + uint32_t bytesAvail; + + bytesAvail = SocketAvailableReadBytes(connectionP->socketP); + + if (bytesAvail <= 0) + cantGetData = TRUE; + else { + uint32_t const bytesToRead = + MIN(bytesAvail, bufferSpace(connectionP)-1); + + uint32_t bytesRead; + + bytesRead = SocketRead( + connectionP->socketP, + connectionP->buffer + connectionP->buffersize, + bytesToRead); + if (bytesRead > 0) { + traceSocketRead(connectionP, bytesRead); + connectionP->inbytes += bytesRead; + connectionP->buffersize += bytesRead; + connectionP->buffer[connectionP->buffersize] = '\0'; + gotData = TRUE; + } + } + } + } + } + if (gotData) + return TRUE; + else + return FALSE; +} + + + +abyss_bool +ConnWrite(TConn * const connectionP, + const void * const buffer, + uint32_t const size) { + + abyss_bool failed; + + SocketWrite(connectionP->socketP, buffer, size, &failed); + + traceSocketWrite(connectionP, buffer, size, failed); + + if (!failed) + connectionP->outbytes += size; + + return !failed; +} + + + +abyss_bool +ConnWriteFromFile(TConn * const connectionP, + TFile * const fileP, + uint64_t const start, + uint64_t const last, + void * const buffer, + uint32_t const buffersize, + uint32_t const rate) { +/*---------------------------------------------------------------------------- + Write the contents of the file stream *fileP, from offset 'start' + up through 'last', to the HTTP connection *connectionP. + + Meter the reading so as not to read more than 'rate' bytes per second. + + Use the 'bufferSize' bytes at 'buffer' as an internal buffer for this. +-----------------------------------------------------------------------------*/ + abyss_bool retval; + uint32_t waittime; + abyss_bool success; + uint32_t readChunkSize; + + if (rate > 0) { + readChunkSize = MIN(buffersize, rate); /* One second's worth */ + waittime = (1000 * buffersize) / rate; + } else { + readChunkSize = buffersize; + waittime = 0; + } + + success = FileSeek(fileP, start, SEEK_SET); + if (!success) + retval = FALSE; + else { + uint64_t const totalBytesToRead = last - start + 1; + uint64_t bytesread; + + bytesread = 0; /* initial value */ + + while (bytesread < totalBytesToRead) { + uint64_t const bytesLeft = totalBytesToRead - bytesread; + uint64_t const bytesToRead = MIN(readChunkSize, bytesLeft); + + uint64_t bytesReadThisTime; + + bytesReadThisTime = FileRead(fileP, buffer, bytesToRead); + bytesread += bytesReadThisTime; + + if (bytesReadThisTime > 0) + ConnWrite(connectionP, buffer, bytesReadThisTime); + else + break; + + if (waittime > 0) + xmlrpc_millisecond_sleep(waittime); + } + retval = (bytesread >= totalBytesToRead); + } + return retval; +} + + + +static void +processHeaderLine(char * const start, + const char * const headerStart, + TConn * const connectionP, + time_t const deadline, + abyss_bool * const gotHeaderP, + char ** const nextP, + abyss_bool * const errorP) { +/*---------------------------------------------------------------------------- + If there's enough data in the buffer, process a line of HTTP + header. + + It is part of a header that starts at 'headerStart' and has been + previously processed up to the line starting at 'start'. The data + in the buffer is terminated by a NUL. + + Return as *nextP the location of the next header line to process + (same as 'start' if we didn't find a line to process). + + WE MODIFY THE DATA. +-----------------------------------------------------------------------------*/ + abyss_bool gotHeader; + char * lfPos; + char * p; + + p = start; + + gotHeader = FALSE; /* initial assumption */ + + lfPos = strchr(p, LF); + if (lfPos) { + if ((*p != LF) && (*p != CR)) { + /* We're looking at a non-empty line */ + if (*(lfPos+1) == '\0') { + /* There's nothing in the buffer after the line, so we + don't know if there's a continuation line coming. + Must read more. + */ + int const timeLeft = deadline - time(NULL); + + *errorP = !ConnRead(connectionP, timeLeft); + } + if (!*errorP) { + p = lfPos; /* Point to LF */ + + /* If the next line starts with whitespace, it's a + continuation line, so blank out the line + delimiter (LF or CRLF) so as to join the next + line with this one. + */ + if ((*(p+1) == ' ') || (*(p+1) == '\t')) { + if (p > headerStart && *(p-1) == CR) + *(p-1) = ' '; + *p++ = ' '; + } else + gotHeader = TRUE; + } + } else { + /* We're looking at an empty line (i.e. what marks the + end of the header) + */ + p = lfPos; /* Point to LF */ + gotHeader = TRUE; + } + } + + if (gotHeader) { + /* 'p' points to the final LF */ + + /* Replace the LF or the CR in CRLF with NUL, so as to terminate + the string at 'headerStart' that is the full header. + */ + if (p > headerStart && *(p-1) == CR) + *(p-1) = '\0'; /* NUL out CR in CRLF */ + else + *p = '\0'; /* NUL out LF */ + + ++p; /* Point to next line in buffer */ + } + *gotHeaderP = gotHeader; + *nextP = p; +} + + + +abyss_bool +ConnReadHeader(TConn * const connectionP, + char ** const headerP) { +/*---------------------------------------------------------------------------- + Read an HTTP header on connection *connectionP. + + An HTTP header is basically a line, except that if a line starts + with white space, it's a continuation of the previous line. A line + is delimited by either LF or CRLF. + + In the course of reading, we read at least one character past the + line delimiter at the end of the header; we may read much more. We + leave everything after the header (and its line delimiter) in the + internal buffer, with the buffer pointer pointing to it. + + We use stuff already in the internal buffer (perhaps left by a + previous call to this subroutine) before reading any more from from + the socket. + + Return as *headerP the header value. This is in the connection's + internal buffer. This contains no line delimiters. +-----------------------------------------------------------------------------*/ + uint32_t const deadline = time(NULL) + connectionP->server->srvP->timeout; + + abyss_bool retval; + char * p; + char * headerStart; + abyss_bool error; + abyss_bool gotHeader; + + p = connectionP->buffer + connectionP->bufferpos; + headerStart = p; + + gotHeader = FALSE; + error = FALSE; + + while (!gotHeader && !error) { + int const timeLeft = deadline - time(NULL); + + if (timeLeft <= 0) + error = TRUE; + else { + if (p >= connectionP->buffer + connectionP->buffersize + || !strchr(p, LF)) + /* There is no line yet in the buffer. + Need more data from the socket to chew on + */ + error = !ConnRead(connectionP, timeLeft); + + if (!error) { + assert(connectionP->buffer + connectionP->buffersize > p); + processHeaderLine(p, headerStart, connectionP, deadline, + &gotHeader, &p, &error); + } + } + } + if (gotHeader) { + /* We've consumed this part of the buffer (but be careful -- + you can't reuse that part of the buffer because the string + we're returning is in it! + */ + connectionP->bufferpos += p - headerStart; + *headerP = headerStart; + retval = TRUE; + } else + retval = FALSE; + + return retval; +} + + + +TServer * +ConnServer(TConn * const connectionP) { + return connectionP->server; +} + + + +/******************************************************************************* +** +** conn.c +** +** This file is part of the ABYSS Web server project. +** +** Copyright (C) 2000 by Moez Mahfoudh . +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +** ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +** OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +** HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +** LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +** OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +** SUCH DAMAGE. +** +******************************************************************************/ diff --git a/lib/abyss/src/conn.h b/lib/abyss/src/conn.h new file mode 100644 index 0000000..662b748 --- /dev/null +++ b/lib/abyss/src/conn.h @@ -0,0 +1,98 @@ +#ifndef CONN_H_INCLUDED +#define CONN_H_INCLUDED + +#include "xmlrpc-c/abyss.h" +#include "socket.h" +#include "file.h" + +#define BUFFER_SIZE 4096 + +struct _TConn { + struct _TConn * nextOutstandingP; + /* Link to the next connection in the list of outstanding + connections + */ + TServer * server; + uint32_t buffersize; + /* Index into the connection buffer (buffer[], below) where + the next byte read on the connection will go. + */ + uint32_t bufferpos; + /* Index into the connection buffer (buffer[], below) where + the next byte to be delivered to the user is. + */ + uint32_t inbytes,outbytes; + TSocket * socketP; + TIPAddr peerip; + abyss_bool hasOwnThread; + TThread * threadP; + abyss_bool finished; + /* We have done all the processing there is to do on this + connection, other than possibly notifying someone that we're + done. One thing this signifies is that any thread or process + that the connection spawned is dead or will be dead soon, so + one could reasonably wait for it to be dead, e.g. with + pthread_join(). Note that one can scan a bunch of processes + for 'finished' status, but sometimes can't scan a bunch of + threads for liveness. + */ + const char * trace; + TThreadProc * job; + TThreadDoneFn * done; + char buffer[BUFFER_SIZE]; +}; + +typedef struct _TConn TConn; + +TConn * ConnAlloc(void); + +void ConnFree(TConn * const connectionP); + +void +ConnCreate(TConn ** const connectionPP, + TServer * const serverP, + TSocket * const connectedSocketP, + TThreadProc * const job, + TThreadDoneFn * const done, + enum abyss_foreback const foregroundBackground, + abyss_bool const useSigchld, + const char ** const errorP); + +abyss_bool +ConnProcess(TConn * const connectionP); + +abyss_bool +ConnKill(TConn * const connectionP); + +void +ConnWaitAndRelease(TConn * const connectionP); + +abyss_bool +ConnWrite(TConn * const connectionP, + const void * const buffer, + uint32_t const size); + +abyss_bool +ConnRead(TConn * const c, + uint32_t const timems); + +void +ConnReadInit(TConn * const connectionP); + +abyss_bool +ConnReadHeader(TConn * const connectionP, + char ** const headerP); + +abyss_bool +ConnWriteFromFile(TConn * const connectionP, + TFile * const file, + uint64_t const start, + uint64_t const end, + void * const buffer, + uint32_t const buffersize, + uint32_t const rate); + +TServer * +ConnServer(TConn * const connectionP); + +#endif diff --git a/lib/abyss/src/data.c b/lib/abyss/src/data.c new file mode 100644 index 0000000..03f4c3f --- /dev/null +++ b/lib/abyss/src/data.c @@ -0,0 +1,640 @@ +/****************************************************************************** +** +** list.c +** +** This file is part of the ABYSS Web server project. +** +** Copyright (C) 2000 by Moez Mahfoudh . +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +** ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +** OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +** HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +** LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +** OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +** SUCH DAMAGE. +** +*******************************************************************************/ + +#include +#include +#include + +#include "mallocvar.h" +#include "xmlrpc-c/util_int.h" +#include "xmlrpc-c/string_int.h" + +#include "xmlrpc-c/abyss.h" + +#include "token.h" + +#include "data.h" + +/********************************************************************* +** List +*********************************************************************/ + +void ListInit(TList *sl) +{ + sl->item=NULL; + sl->size=sl->maxsize=0; + sl->autofree=FALSE; +} + +void ListInitAutoFree(TList *sl) +{ + sl->item=NULL; + sl->size=sl->maxsize=0; + sl->autofree=TRUE; +} + + + +void +ListFree(TList * const sl) { + + if (sl->item) { + if (sl->autofree) { + unsigned int i; + for (i = sl->size; i > 0; --i) + free(sl->item[i-1]); + + } + free(sl->item); + } + sl->item = NULL; + sl->size = 0; + sl->maxsize = 0; +} + + + +void +ListFreeItems(TList * const sl) { + + if (sl->item) { + unsigned int i; + for (i = sl->size; i > 0; --i) + free(sl->item[i-1]); + } +} + + + +abyss_bool +ListAdd(TList * const sl, + void * const str) { +/*---------------------------------------------------------------------------- + Add an item to the end of the list. +-----------------------------------------------------------------------------*/ + abyss_bool success; + + if (sl->size >= sl->maxsize) { + uint16_t newSize = sl->maxsize + 16; + void **newitem; + + newitem = realloc(sl->item, newSize * sizeof(void *)); + if (newitem) { + sl->item = newitem; + sl->maxsize = newSize; + } + } + + if (sl->size >= sl->maxsize) + success = FALSE; + else { + success = TRUE; + sl->item[sl->size++] = str; + } + return success; +} + + + +void +ListRemove(TList * const sl) { +/*---------------------------------------------------------------------------- + Remove the last item from the list. +-----------------------------------------------------------------------------*/ + + assert(sl->size > 0); + + --sl->size; +} + + + +abyss_bool +ListAddFromString(TList * const list, + const char * const stringArg) { + + abyss_bool retval; + + if (!stringArg) + retval = TRUE; + else { + char * buffer; + + buffer = strdup(stringArg); + if (!buffer) + retval = FALSE; + else { + abyss_bool endOfString; + abyss_bool error; + char * c; + + for (c = &buffer[0], endOfString = FALSE, error = FALSE; + !endOfString && !error; + ) { + const char * t; + NextToken((const char **)&c); + + while (*c == ',') + ++c; + + t = GetToken(&c); + if (!t) + endOfString = TRUE; + else { + char * p; + + for (p = c - 2; *p == ','; --p) + *p = '\0'; + + if (t[0] != '\0') { + abyss_bool added; + added = ListAdd(list, (void*)t); + + if (!added) + error = TRUE; + } + } + } + retval = !error; + xmlrpc_strfree(buffer); + } + } + return retval; +} + + + +abyss_bool +ListFindString(TList * const sl, + const char * const str, + uint16_t * const indexP) +{ + uint16_t i; + + if (sl->item && str) + for (i=0;isize;i++) + if (strcmp(str,(char *)(sl->item[i]))==0) + { + *indexP=i; + return TRUE; + }; + + return FALSE; +} + +/********************************************************************* +** Buffer +*********************************************************************/ + +abyss_bool BufferAlloc(TBuffer *buf,uint32_t memsize) +{ + /* ************** Implement the static buffers ***/ + buf->staticid=0; + buf->data=(void *)malloc(memsize); + if (buf->data) + { + buf->size=memsize; + return TRUE; + } + else + { + buf->size=0; + return FALSE; + }; +} + +void BufferFree(TBuffer *buf) +{ + if (buf->staticid) + { + /* ************** Implement the static buffers ***/ + } + else + free(buf->data); + + buf->size=0; + buf->staticid=0; +} + +abyss_bool BufferRealloc(TBuffer *buf,uint32_t memsize) +{ + if (buf->staticid) + { + TBuffer b; + + if (memsize<=buf->size) + return TRUE; + + if (BufferAlloc(&b,memsize)) + { + memcpy(b.data,buf->data,buf->size); + BufferFree(buf); + *buf=b; + return TRUE; + } + } + else + { + void *d; + + d=realloc(buf->data,memsize); + if (d) + { + buf->data=d; + buf->size=memsize; + return TRUE; + } + } + + return FALSE; +} + + +/********************************************************************* +** String +*********************************************************************/ + +abyss_bool StringAlloc(TString *s) +{ + s->size=0; + if (BufferAlloc(&(s->buffer),256)) + { + *(char *)(s->buffer.data)='\0'; + return TRUE; + } + else + return FALSE; +} + +abyss_bool StringConcat(TString *s,char *s2) +{ + uint32_t len=strlen(s2); + + if (len+s->size+1>s->buffer.size) + if (!BufferRealloc(&(s->buffer),((len+s->size+1+256)/256)*256)) + return FALSE; + + strcat((char *)(s->buffer.data),s2); + s->size+=len; + return TRUE; +} + +abyss_bool StringBlockConcat(TString *s,char *s2,char **ref) +{ + uint32_t len=strlen(s2)+1; + + if (len+s->size>s->buffer.size) + if (!BufferRealloc(&(s->buffer),((len+s->size+1+256)/256)*256)) + return FALSE; + + *ref=(char *)(s->buffer.data)+s->size; + memcpy(*ref,s2,len); + s->size+=len; + return TRUE; +} + +void StringFree(TString *s) +{ + s->size=0; + BufferFree(&(s->buffer)); +} + +char *StringData(TString *s) +{ + return (char *)(s->buffer.data); +} + +/********************************************************************* +** Hash +*********************************************************************/ + +static uint16_t +Hash16(const char * const start) { + + const char * s; + + uint16_t i; + + s = start; + i = 0; + + while(*s) + i = i * 37 + *s++; + + return i; +} + +/********************************************************************* +** Table +*********************************************************************/ + +void TableInit(TTable *t) +{ + t->item=NULL; + t->size=t->maxsize=0; +} + +void TableFree(TTable *t) +{ + uint16_t i; + + if (t->item) + { + if (t->size) + for (i=t->size;i>0;i--) + { + free(t->item[i-1].name); + free(t->item[i-1].value); + }; + + free(t->item); + } + + TableInit(t); +} + + + +abyss_bool +TableFindIndex(TTable * const t, + const char * const name, + uint16_t * const index) { + + uint16_t i,hash=Hash16(name); + + if ((t->item) && (t->size>0) && (*indexsize)) + { + for (i=*index;isize;i++) + if (hash==t->item[i].hash) + if (strcmp(t->item[i].name,name)==0) + { + *index=i; + return TRUE; + }; + }; + + return FALSE; +} + + + +abyss_bool +TableAddReplace(TTable * const t, + const char * const name, + const char * const value) { + + uint16_t i=0; + + if (TableFindIndex(t,name,&i)) + { + free(t->item[i].value); + if (value) + t->item[i].value=strdup(value); + else + { + free(t->item[i].name); + if (--t->size>0) + t->item[i]=t->item[t->size]; + }; + + return TRUE; + } + else + return TableAdd(t,name,value); +} + + + +abyss_bool +TableAdd(TTable * const t, + const char * const name, + const char * const value) { + + if (t->size>=t->maxsize) { + TTableItem *newitem; + + t->maxsize+=16; + + newitem=(TTableItem *)realloc(t->item,(t->maxsize)*sizeof(TTableItem)); + if (newitem) + t->item=newitem; + else { + t->maxsize-=16; + return FALSE; + } + } + + t->item[t->size].name=strdup(name); + t->item[t->size].value=strdup(value); + t->item[t->size].hash=Hash16(name); + + ++t->size; + + return TRUE; +} + + + +char * +TableFind(TTable * const t, + const char * const name) { + + uint16_t i=0; + + if (TableFindIndex(t,name,&i)) + return t->item[i].value; + else + return NULL; +} + +/********************************************************************* +** Pool +*********************************************************************/ + +static TPoolZone * +PoolZoneAlloc(uint32_t const zonesize) { + + TPoolZone * poolZoneP; + + MALLOCARRAY(poolZoneP, zonesize); + if (poolZoneP) { + poolZoneP->pos = &poolZoneP->data[0]; + poolZoneP->maxpos = poolZoneP->pos + zonesize; + poolZoneP->next = NULL; + poolZoneP->prev = NULL; + } + return poolZoneP; +} + + + +static void +PoolZoneFree(TPoolZone * const poolZoneP) { + + free(poolZoneP); +} + + + +abyss_bool +PoolCreate(TPool * const poolP, + uint32_t const zonesize) { + + abyss_bool success; + abyss_bool mutexCreated; + + poolP->zonesize = zonesize; + + mutexCreated = MutexCreate(&poolP->mutex); + if (mutexCreated) { + TPoolZone * const firstZoneP = PoolZoneAlloc(zonesize); + + if (firstZoneP != NULL) { + poolP->firstzone = firstZoneP; + poolP->currentzone = firstZoneP; + success = TRUE; + } else + success = FALSE; + if (!success) + MutexFree(&poolP->mutex); + } else + success = FALSE; + + return success; +} + + + +void * +PoolAlloc(TPool * const poolP, + uint32_t const size) { +/*---------------------------------------------------------------------------- + Allocate a block of size 'size' from pool 'poolP'. +-----------------------------------------------------------------------------*/ + void * retval; + + if (size == 0) + retval = NULL; + else { + abyss_bool gotMutexLock; + + gotMutexLock = MutexLock(&poolP->mutex); + if (!gotMutexLock) + retval = NULL; + else { + TPoolZone * const curPoolZoneP = poolP->currentzone; + + if (curPoolZoneP->pos + size < curPoolZoneP->maxpos) { + retval = curPoolZoneP->pos; + curPoolZoneP->pos += size; + } else { + uint32_t const zonesize = MAX(size, poolP->zonesize); + + TPoolZone * const newPoolZoneP = PoolZoneAlloc(zonesize); + if (newPoolZoneP) { + newPoolZoneP->prev = curPoolZoneP; + newPoolZoneP->next = curPoolZoneP->next; + curPoolZoneP->next = newPoolZoneP; + poolP->currentzone = newPoolZoneP; + retval= newPoolZoneP->data; + newPoolZoneP->pos = newPoolZoneP->data + size; + } else + retval = NULL; + } + MutexUnlock(&poolP->mutex); + } + } + return retval; +} + + + +void +PoolReturn(TPool * const poolP, + void * const blockP) { +/*---------------------------------------------------------------------------- + Return the block at 'blockP' to the pool 'poolP'. WE ASSUME THAT IS + THE MOST RECENTLY ALLOCATED AND NOT RETURNED BLOCK IN THE POOL. +-----------------------------------------------------------------------------*/ + TPoolZone * const curPoolZoneP = poolP->currentzone; + + assert((char*)curPoolZoneP->data < (char*)blockP && + (char*)blockP < (char*)curPoolZoneP->pos); + + curPoolZoneP->pos = blockP; + + if (curPoolZoneP->pos == curPoolZoneP->data) { + /* That emptied out the current zone. Free it and make the previous + zone current. + */ + + assert(curPoolZoneP->prev); /* entry condition */ + + curPoolZoneP->prev->next = NULL; + + PoolZoneFree(curPoolZoneP); + } +} + + + +void +PoolFree(TPool * const poolP) { + + TPoolZone * poolZoneP; + TPoolZone * nextPoolZoneP; + + for (poolZoneP = poolP->firstzone; poolZoneP; poolZoneP = nextPoolZoneP) { + nextPoolZoneP = poolZoneP->next; + free(poolZoneP); + } +} + + + +const char * +PoolStrdup(TPool * const poolP, + const char * const origString) { + + char * newString; + + if (origString == NULL) + newString = NULL; + else { + newString = PoolAlloc(poolP, strlen(origString) + 1); + if (newString != NULL) + strcpy(newString, origString); + } + return newString; +} diff --git a/lib/abyss/src/data.h b/lib/abyss/src/data.h new file mode 100644 index 0000000..c990d99 --- /dev/null +++ b/lib/abyss/src/data.h @@ -0,0 +1,124 @@ +#ifndef DATA_H_INCLUDED +#define DATA_H_INCLUDED + +#include "thread.h" + +/********************************************************************* +** List +*********************************************************************/ + +typedef struct { + void **item; + uint16_t size; + uint16_t maxsize; + abyss_bool autofree; +} TList; + +void +ListInit(TList * const listP); + +void +ListInitAutoFree(TList * const listP); + +void +ListFree(TList * const listP); + +void +ListFreeItems(TList * const listP); + +abyss_bool +ListAdd(TList * const listP, + void * const str); + +void +ListRemove(TList * const listP); + +abyss_bool +ListAddFromString(TList * const listP, + const char * const c); + +abyss_bool +ListFindString(TList * const listP, + const char * const str, + uint16_t * const indexP); + + +typedef struct +{ + char *name,*value; + uint16_t hash; +} TTableItem; + +typedef struct +{ + TTableItem *item; + uint16_t size,maxsize; +} TTable; + +void +TableInit(TTable * const t); + +void +TableFree(TTable * const t); + +abyss_bool +TableAdd(TTable * const t, + const char * const name, + const char * const value); + +abyss_bool +TableAddReplace(TTable * const t, + const char * const name, + const char * const value); + +abyss_bool +TableFindIndex(TTable * const t, + const char * const name, + uint16_t * const index); + +char * +TableFind(TTable * const t, + const char * const name); + + +/********************************************************************* +** Pool +*********************************************************************/ + +typedef struct _TPoolZone { + char * pos; + char * maxpos; + struct _TPoolZone * next; + struct _TPoolZone * prev; +/* char data[0]; Some compilers don't accept this */ + char data[1]; +} TPoolZone; + +typedef struct { + TPoolZone * firstzone; + TPoolZone * currentzone; + uint32_t zonesize; + TMutex mutex; +} TPool; + +abyss_bool +PoolCreate(TPool * const poolP, + uint32_t const zonesize); + +void +PoolFree(TPool * const poolP); + +void * +PoolAlloc(TPool * const poolP, + uint32_t const size); + +void +PoolReturn(TPool * const poolP, + void * const blockP); + +const char * +PoolStrdup(TPool * const poolP, + const char * const origString); + + +#endif diff --git a/lib/abyss/src/date.c b/lib/abyss/src/date.c new file mode 100644 index 0000000..91c9fa7 --- /dev/null +++ b/lib/abyss/src/date.c @@ -0,0 +1,192 @@ +#include +#include +#include +#include +#include + + +#include +#include "date.h" + +/********************************************************************* +** Date +*********************************************************************/ + +static char *_DateDay[7]= +{ + "Sun","Mon","Tue","Wed","Thu","Fri","Sat" +}; + +static char *_DateMonth[12]= +{ + "Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec" +}; + +static int32_t _DateTimeBias=0; +static char _DateTimeBiasStr[6]=""; + +abyss_bool DateToString(TDate *tm,char *s) +{ + if (mktime(tm)==(time_t)(-1)) + { + *s='\0'; + return FALSE; + }; + + sprintf(s,"%s, %02d %s %04d %02d:%02d:%02d GMT",_DateDay[tm->tm_wday],tm->tm_mday, + _DateMonth[tm->tm_mon],tm->tm_year+1900,tm->tm_hour,tm->tm_min,tm->tm_sec); + + return TRUE; +} + + + +abyss_bool +DateToLogString(TDate * const tmP, + char * const s) { + time_t t; + + t = mktime(tmP); + if (t != (time_t)(-1)) { + TDate d; + abyss_bool success; + success = DateFromLocal(&d, t); + if (success) { + sprintf(s, "%02d/%s/%04d:%02d:%02d:%02d %s", + d.tm_mday, _DateMonth[d.tm_mon], + d.tm_year+1900, d.tm_hour, d.tm_min, d.tm_sec, + _DateTimeBiasStr); + return TRUE; + } + } + *s = '\0'; + return FALSE; +} + + + +abyss_bool +DateDecode(const char * const dateString, + TDate * const tmP) { + + int rc; + const char * s; + uint32_t n; + + s = &dateString[0]; + + /* Ignore spaces, day name and spaces */ + while ((*s==' ') || (*s=='\t')) + ++s; + + while ((*s!=' ') && (*s!='\t')) + ++s; + + while ((*s==' ') || (*s=='\t')) + ++s; + + /* try to recognize the date format */ + rc = sscanf(s, "%*s %d %d:%d:%d %d%*s", &tmP->tm_mday, &tmP->tm_hour, + &tmP->tm_min, &tmP->tm_sec, &tmP->tm_year); + if (rc != 5) { + int rc; + rc = sscanf(s, "%d %n%*s %d %d:%d:%d GMT%*s", + &tmP->tm_mday,&n,&tmP->tm_year, + &tmP->tm_hour, &tmP->tm_min, &tmP->tm_sec); + if (rc != 5) { + int rc; + rc = sscanf(s, "%d-%n%*[A-Za-z]-%d %d:%d:%d GMT%*s", + &tmP->tm_mday, &n, &tmP->tm_year, + &tmP->tm_hour, &tmP->tm_min, &tmP->tm_sec); + if (rc != 5) + return FALSE; + } + } + /* s points now to the month string */ + s += n; + for (n = 0; n < 12; ++n) { + char * p; + + p =_DateMonth[n]; + + if (tolower(*p++) == tolower(*s)) + if (*p++ == tolower(s[1])) + if (*p == tolower(s[2])) + break; + } + + if (n == 12) + return FALSE; + + tmP->tm_mon = n; + + /* finish the work */ + if (tmP->tm_year > 1900) + tmP->tm_year -= 1900; + else { + if (tmP->tm_year < 70) + tmP->tm_year += 100; + } + tmP->tm_isdst = 0; + + return (mktime(tmP) != (time_t)(-1)); +} + + + +int32_t DateCompare(TDate *d1,TDate *d2) +{ + int32_t x; + + if ((x=d1->tm_year-d2->tm_year)==0) + if ((x=d1->tm_mon-d2->tm_mon)==0) + if ((x=d1->tm_mday-d2->tm_mday)==0) + if ((x=d1->tm_hour-d2->tm_hour)==0) + if ((x=d1->tm_min-d2->tm_min)==0) + x=d1->tm_sec-d2->tm_sec; + + return x; +} + + + +abyss_bool +DateFromGMT(TDate *d,time_t t) { + TDate *dx; + + dx=gmtime(&t); + if (dx) { + *d=*dx; + return TRUE; + }; + + return FALSE; +} + +abyss_bool DateFromLocal(TDate *d,time_t t) +{ + return DateFromGMT(d,t+_DateTimeBias*2); +} + + + +abyss_bool +DateInit() { + time_t t; + TDate gmt,local,*d; + + time(&t); + if (DateFromGMT(&gmt,t)) { + d=localtime(&t); + if (d) { + local=*d; + _DateTimeBias = + (local.tm_sec-gmt.tm_sec)+(local.tm_min-gmt.tm_min)*60 + +(local.tm_hour-gmt.tm_hour)*3600; + sprintf(_DateTimeBiasStr, "%+03d%02d", + _DateTimeBias/3600,(abs(_DateTimeBias) % 3600)/60); + return TRUE; + }; + } + return FALSE; +} diff --git a/lib/abyss/src/date.h b/lib/abyss/src/date.h new file mode 100644 index 0000000..4f407c0 --- /dev/null +++ b/lib/abyss/src/date.h @@ -0,0 +1,34 @@ +#ifndef DATE_H_INCLUDED +#define DATE_H_INCLUDED + +#include + +#include "xmlrpc-c/abyss.h" + +typedef struct tm TDate; + +abyss_bool +DateToString(TDate * const tmP, + char * const s); + +abyss_bool +DateToLogString(TDate * const tmP, + char * const s); + +abyss_bool +DateDecode(const char * const dateString, + TDate * const tmP); + +int32_t +DateCompare(TDate * const d1, + TDate * const d2); + +abyss_bool +DateFromGMT(TDate * const d, + time_t const t); + +abyss_bool +DateFromLocal(TDate * const d, + time_t const t); + +#endif diff --git a/lib/abyss/src/file.c b/lib/abyss/src/file.c new file mode 100644 index 0000000..355bbc2 --- /dev/null +++ b/lib/abyss/src/file.c @@ -0,0 +1,244 @@ +/****************************************************************************** +** +** file.c +** +** This file is part of the ABYSS Web server project. +** +** Copyright (C) 2000 by Moez Mahfoudh . +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +** ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +** OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +** HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +** LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +** OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +** SUCH DAMAGE. +** +******************************************************************************/ + +#include + +#ifdef WIN32 +#include +#endif + +#ifndef WIN32 +#include +#include +#endif + +#include "xmlrpc-c/abyss.h" +#include "file.h" + +/********************************************************************* +** File +*********************************************************************/ + +abyss_bool FileOpen(TFile *f, const char *name,uint32_t attrib) +{ +#if defined( WIN32 ) && !defined( __BORLANDC__ ) + return ((*f=_open(name,attrib))!=(-1)); +#else + return ((*f=open(name,attrib))!=(-1)); +#endif +} + +abyss_bool FileOpenCreate(TFile *f, const char *name, uint32_t attrib) +{ +#if defined( WIN32 ) && !defined( __BORLANDC__ ) + return ((*f=_open(name,attrib | O_CREAT,_S_IWRITE | _S_IREAD))!=(-1)); +#else + return ((*f=open(name,attrib | O_CREAT,S_IWRITE | S_IREAD))!=(-1)); +#endif +} + +abyss_bool +FileWrite(TFile * const f, + const void * const buffer, + uint32_t const len) { +#if defined( WIN32 ) && !defined( __BORLANDC__ ) + return (_write(*f,buffer,len)==(int32_t)len); +#else + return (write(*f,buffer,len)==(int32_t)len); +#endif +} + +int32_t FileRead(TFile *f, void *buffer, uint32_t len) +{ +#if defined( WIN32 ) && !defined( __BORLANDC__ ) + return (_read(*f,buffer,len)); +#else + return (read(*f,buffer,len)); +#endif +} + +abyss_bool FileSeek(TFile *f, uint64_t pos, uint32_t attrib) +{ +#if defined( WIN32 ) && !defined( __BORLANDC__ ) + return (_lseek(*f,pos,attrib)!=(-1)); +#else + return (lseek(*f,pos,attrib)!=(-1)); +#endif +} + +uint64_t FileSize(TFile *f) +{ +#if defined( WIN32 ) && !defined( __BORLANDC__ ) + return (_filelength(*f)); +#else + struct stat fs; + + fstat(*f,&fs); + return (fs.st_size); +#endif +} + +abyss_bool FileClose(TFile *f) +{ +#if defined( WIN32 ) && !defined( __BORLANDC__ ) + return (_close(*f)!=(-1)); +#else + return (close(*f)!=(-1)); +#endif +} + + + +abyss_bool +FileStat(const char * const filename, + TFileStat * const filestat) { +#if defined( WIN32 ) && !defined( __BORLANDC__ ) + return (_stati64(filename,filestat)!=(-1)); +#else + return (stat(filename,filestat)!=(-1)); +#endif +} + + + +abyss_bool +FileFindFirst(TFileFind * const filefind, + const char * const path, + TFileInfo * const fileinfo) { +#ifdef WIN32 + abyss_bool ret; + char *p=path+strlen(path); + + *p='\\'; + *(p+1)='*'; + *(p+2)='\0'; +#ifndef __BORLANDC__ + ret=(((*filefind)=_findfirst(path,fileinfo))!=(-1)); +#else + *filefind = FindFirstFile( path, &fileinfo->data ); + ret = *filefind != NULL; + if( ret ) + { + LARGE_INTEGER li; + li.LowPart = fileinfo->data.nFileSizeLow; + li.HighPart = fileinfo->data.nFileSizeHigh; + strcpy( fileinfo->name, fileinfo->data.cFileName ); + fileinfo->attrib = fileinfo->data.dwFileAttributes; + fileinfo->size = li.QuadPart; + fileinfo->time_write = fileinfo->data.ftLastWriteTime.dwLowDateTime; + } +#endif + *p='\0'; + return ret; +#else /* WIN32 */ + strncpy(filefind->path,path,NAME_MAX); + filefind->path[NAME_MAX]='\0'; + filefind->handle=opendir(path); + if (filefind->handle) + return FileFindNext(filefind,fileinfo); + + return FALSE; +#endif /* WIN32 */ +} + + + +abyss_bool FileFindNext(TFileFind *filefind,TFileInfo *fileinfo) +{ +#ifdef WIN32 + +#ifndef __BORLANDC__ + return (_findnext(*filefind,fileinfo)!=(-1)); +#else + abyss_bool ret = FindNextFile( *filefind, &fileinfo->data ); + if( ret ) + { + LARGE_INTEGER li; + li.LowPart = fileinfo->data.nFileSizeLow; + li.HighPart = fileinfo->data.nFileSizeHigh; + strcpy( fileinfo->name, fileinfo->data.cFileName ); + fileinfo->attrib = fileinfo->data.dwFileAttributes; + fileinfo->size = li.QuadPart; + fileinfo->time_write = fileinfo->data.ftLastWriteTime.dwLowDateTime; + } + return ret; +#endif + +#else /* WIN32 */ + struct dirent *de; + /****** Must be changed ***/ + char z[NAME_MAX+1]; + + de=readdir(filefind->handle); + if (de) + { + struct stat fs; + + strcpy(fileinfo->name,de->d_name); + strcpy(z,filefind->path); + strncat(z,"/",NAME_MAX); + strncat(z,fileinfo->name,NAME_MAX); + z[NAME_MAX]='\0'; + + stat(z,&fs); + + if (fs.st_mode & S_IFDIR) + fileinfo->attrib=A_SUBDIR; + else + fileinfo->attrib=0; + + fileinfo->size=fs.st_size; + fileinfo->time_write=fs.st_mtime; + + return TRUE; + }; + + return FALSE; +#endif /* WIN32 */ +} + +void FileFindClose(TFileFind *filefind) +{ +#ifdef WIN32 + +#ifndef __BORLANDC__ + _findclose(*filefind); +#else + FindClose( *filefind ); +#endif + +#else /* WIN32 */ + closedir(filefind->handle); +#endif /* WIN32 */ +} diff --git a/lib/abyss/src/file.h b/lib/abyss/src/file.h new file mode 100644 index 0000000..c7cefbd --- /dev/null +++ b/lib/abyss/src/file.h @@ -0,0 +1,130 @@ +#ifndef FILE_H_INCLUDED +#define FILE_H_INCLUDED + +#include +#include +#include +#include + +#include "xmlrpc-c/abyss.h" + +#ifndef NAME_MAX +#define NAME_MAX 1024 +#endif + +#ifdef WIN32 +#ifndef __BORLANDC__ +#define O_APPEND _O_APPEND +#define O_CREAT _O_CREAT +#define O_EXCL _O_EXCL +#define O_RDONLY _O_RDONLY +#define O_RDWR _O_RDWR +#define O_TRUNC _O_TRUNC +#define O_WRONLY _O_WRONLY +#define O_TEXT _O_TEXT +#define O_BINARY _O_BINARY +#endif + +#define A_HIDDEN _A_HIDDEN +#define A_NORMAL _A_NORMAL +#define A_RDONLY _A_RDONLY +#define A_SUBDIR _A_SUBDIR +#else +#define A_SUBDIR 1 +#define O_BINARY 0 +#define O_TEXT 0 +#endif /* WIN32 */ + +#ifdef WIN32 + +#ifndef __BORLANDC__ +typedef struct _stati64 TFileStat; +typedef struct _finddata_t TFileInfo; +typedef long TFileFind; + +#else /* WIN32 */ + +typedef struct stat TFileStat; +typedef struct finddata_t { + char name[NAME_MAX+1]; + int attrib; + uint64_t size; + time_t time_write; + WIN32_FIND_DATA data; +} TFileInfo; + +typedef HANDLE TFileFind; + +#endif /* WIN32 */ + +#else + +#include +#include + +typedef struct stat TFileStat; + +typedef struct finddata_t { + char name[NAME_MAX+1]; + int attrib; + uint64_t size; + time_t time_write; +} TFileInfo; + +typedef struct { + char path[NAME_MAX+1]; + DIR *handle; +} TFileFind; + +#endif + +typedef int TFile; + +abyss_bool +FileOpen(TFile * const f, + const char * const name, + uint32_t const attrib); + +abyss_bool +FileOpenCreate(TFile * const f, + const char * const name, + uint32_t const attrib); + +abyss_bool +FileClose(TFile * const f); + +abyss_bool +FileWrite(TFile * const f, + const void * const buffer, + uint32_t const len); + +int32_t +FileRead(TFile * const f, + void * const buffer, + uint32_t const len); + +abyss_bool +FileSeek(TFile * const f, + uint64_t const pos, + uint32_t const attrib); + +uint64_t +FileSize(TFile * const f); + +abyss_bool +FileStat(const char * const filename, + TFileStat * const filestat); + +abyss_bool +FileFindFirst(TFileFind * const filefind, + const char * const path, + TFileInfo * const fileinfo); + +abyss_bool +FileFindNext(TFileFind * const filefind, + TFileInfo * const fileinfo); + +void +FileFindClose(TFileFind * const filefind); + +#endif diff --git a/lib/abyss/src/http.c b/lib/abyss/src/http.c new file mode 100644 index 0000000..bbd9a0e --- /dev/null +++ b/lib/abyss/src/http.c @@ -0,0 +1,857 @@ +/* Copyright information is at the end of the file */ + +#include +#include +#include +#include +#include +#include +#include + +#include "xmlrpc_config.h" +#include "mallocvar.h" +#include "xmlrpc-c/string_int.h" +#include "xmlrpc-c/abyss.h" + +#include "server.h" +#include "session.h" +#include "conn.h" +#include "token.h" +#include "date.h" +#include "data.h" +#include "abyss_info.h" + +#include "http.h" + +/********************************************************************* +** Request Parser +*********************************************************************/ + +/********************************************************************* +** Request +*********************************************************************/ + +static void +initRequestInfo(TRequestInfo * const requestInfoP, + httpVersion const httpVersion, + const char * const requestLine, + TMethod const httpMethod, + const char * const host, + unsigned int const port, + const char * const path, + const char * const query) { +/*---------------------------------------------------------------------------- + Set up the request info structure. For information that is + controlled by headers, use the defaults -- I.e. the value that + applies if the request contains no applicable header. +-----------------------------------------------------------------------------*/ + requestInfoP->requestline = requestLine; + requestInfoP->method = httpMethod; + requestInfoP->host = host; + requestInfoP->port = port; + requestInfoP->uri = path; + requestInfoP->query = query; + requestInfoP->from = NULL; + requestInfoP->useragent = NULL; + requestInfoP->referer = NULL; + requestInfoP->user = NULL; + + if (httpVersion.major > 1 || + (httpVersion.major == 1 && httpVersion.minor >= 1)) + requestInfoP->keepalive = TRUE; + else + requestInfoP->keepalive = FALSE; +} + + + +static void +freeRequestInfo(TRequestInfo * const requestInfoP) { + + if (requestInfoP->requestline) + xmlrpc_strfree(requestInfoP->requestline); + + if (requestInfoP->user) + xmlrpc_strfree(requestInfoP->user); +} + + + +void +RequestInit(TSession * const sessionP, + TConn * const connectionP) { + + time_t nowtime; + + sessionP->validRequest = false; /* Don't have valid request yet */ + + time(&nowtime); + sessionP->date = *gmtime(&nowtime); + + sessionP->conn = connectionP; + + sessionP->responseStarted = FALSE; + + sessionP->chunkedwrite = FALSE; + sessionP->chunkedwritemode = FALSE; + + sessionP->continueRequired = FALSE; + + ListInit(&sessionP->cookies); + ListInit(&sessionP->ranges); + TableInit(&sessionP->request_headers); + TableInit(&sessionP->response_headers); + + sessionP->status = 0; /* No status from handler yet */ + + StringAlloc(&(sessionP->header)); +} + + + +void +RequestFree(TSession * const sessionP) { + + if (sessionP->validRequest) + freeRequestInfo(&sessionP->request_info); + + ListFree(&sessionP->cookies); + ListFree(&sessionP->ranges); + TableFree(&sessionP->request_headers); + TableFree(&sessionP->response_headers); + StringFree(&(sessionP->header)); +} + + + +static void +readRequestLine(TSession * const sessionP, + char ** const requestLineP, + uint16_t * const httpErrorCodeP) { + + *httpErrorCodeP = 0; + + /* Ignore CRLFs in the beginning of the request (RFC2068-P30) */ + do { + abyss_bool success; + success = ConnReadHeader(sessionP->conn, requestLineP); + if (!success) + *httpErrorCodeP = 408; /* Request Timeout */ + } while (!*httpErrorCodeP && (*requestLineP)[0] == '\0'); +} + + + +static void +unescapeUri(char * const uri, + abyss_bool * const errorP) { + + char * x; + char * y; + + x = y = uri; + + *errorP = FALSE; + + while (*x && !*errorP) { + switch (*x) { + case '%': { + char c; + ++x; + c = tolower(*x++); + if ((c >= '0') && (c <= '9')) + c -= '0'; + else if ((c >= 'a') && (c <= 'f')) + c -= 'a' - 10; + else + *errorP = TRUE; + + if (!*errorP) { + char d; + d = tolower(*x++); + if ((d >= '0') && (d <= '9')) + d -= '0'; + else if ((d >= 'a') && (d <= 'f')) + d -= 'a' - 10; + else + *errorP = TRUE; + + if (!*errorP) + *y++ = ((c << 4) | d); + } + } break; + + default: + *y++ = *x++; + break; + } + } + *y = '\0'; +} + + + +static void +parseHostPort(char * const hostport, + const char ** const hostP, + unsigned short * const portP, + uint16_t * const httpErrorCodeP) { + + char * colonPos; + + colonPos = strchr(hostport, ':'); + if (colonPos) { + const char * p; + uint32_t port; + + *colonPos = '\0'; /* Split hostport at the colon */ + + *hostP = hostport; + + for (p = colonPos + 1, port = 0; + isdigit(*p) && port < 65535; + (port = port * 10 + (*p - '0')), ++p); + + *portP = port; + + if (*p || port == 0) + *httpErrorCodeP = 400; /* Bad Request */ + else + *httpErrorCodeP = 0; + } else { + *hostP = hostport; + *portP = 80; + *httpErrorCodeP = 0; + } +} + + + +static void +parseRequestUri(char * const requestUri, + const char ** const hostP, + const char ** const pathP, + const char ** const queryP, + unsigned short * const portP, + uint16_t * const httpErrorCodeP) { +/*---------------------------------------------------------------------------- + Parse the request URI (in the request line + "GET http://www.myserver.com/myfile?parm HTTP/1.1", + "http://www.myserver.com/myfile?parm" is the request URI). + + This destroys *requestUri and returns pointers into *requestUri! + + This is extremely ugly. We need to redo it with dynamically allocated + storage. We should return individual malloc'ed strings. +-----------------------------------------------------------------------------*/ + abyss_bool error; + + unescapeUri(requestUri, &error); + + if (error) + *httpErrorCodeP = 400; /* Bad Request */ + else { + char * requestUriNoQuery; + /* The request URI with any query (the stuff marked by a question + mark at the end of a request URI) chopped off. + */ + { + /* Split requestUri at the question mark */ + char * const qmark = strchr(requestUri, '?'); + + if (qmark) { + *qmark = '\0'; + *queryP = qmark + 1; + } else + *queryP = NULL; + } + + requestUriNoQuery = requestUri; + + if (requestUriNoQuery[0] == '/') { + *hostP = NULL; + *pathP = requestUriNoQuery; + *portP = 80; + } else { + if (!xmlrpc_strneq(requestUriNoQuery, "http://", 7)) + *httpErrorCodeP = 400; /* Bad Request */ + else { + char * const hostportpath = &requestUriNoQuery[7]; + char * const slashPos = strchr(hostportpath, '/'); + char * hostport; + + if (slashPos) { + char * p; + *pathP = slashPos; + + /* Nul-terminate the host name. To make space for + it, slide the whole name back one character. + This moves it into the space now occupied by + the end of "http://", which we don't need. + */ + for (p = hostportpath; *p != '/'; ++p) + *(p-1) = *p; + *(p-1) = '\0'; + + hostport = hostportpath - 1; + *httpErrorCodeP = 0; + } else { + *pathP = "*"; + hostport = hostportpath; + *httpErrorCodeP = 0; + } + if (!*httpErrorCodeP) + parseHostPort(hostport, hostP, portP, httpErrorCodeP); + } + } + } +} + + + +static void +parseRequestLine(char * const requestLine, + TMethod * const httpMethodP, + httpVersion * const httpVersionP, + const char ** const hostP, + unsigned short * const portP, + const char ** const pathP, + const char ** const queryP, + abyss_bool * const moreLinesP, + uint16_t * const httpErrorCodeP) { +/*---------------------------------------------------------------------------- + Modifies *header1 and returns pointers to its storage! +-----------------------------------------------------------------------------*/ + const char * httpMethodName; + char * p; + + p = requestLine; + + /* Jump over spaces */ + NextToken((const char **)&p); + + httpMethodName = GetToken(&p); + if (!httpMethodName) + *httpErrorCodeP = 400; /* Bad Request */ + else { + char * requestUri; + + if (xmlrpc_streq(httpMethodName, "GET")) + *httpMethodP = m_get; + else if (xmlrpc_streq(httpMethodName, "PUT")) + *httpMethodP = m_put; + else if (xmlrpc_streq(httpMethodName, "OPTIONS")) + *httpMethodP = m_options; + else if (xmlrpc_streq(httpMethodName, "DELETE")) + *httpMethodP = m_delete; + else if (xmlrpc_streq(httpMethodName, "POST")) + *httpMethodP = m_post; + else if (xmlrpc_streq(httpMethodName, "TRACE")) + *httpMethodP = m_trace; + else if (xmlrpc_streq(httpMethodName, "HEAD")) + *httpMethodP = m_head; + else + *httpMethodP = m_unknown; + + /* URI and Query Decoding */ + NextToken((const char **)&p); + + + requestUri = GetToken(&p); + if (!requestUri) + *httpErrorCodeP = 400; /* Bad Request */ + else { + parseRequestUri(requestUri, hostP, pathP, queryP, portP, + httpErrorCodeP); + + if (!*httpErrorCodeP) { + const char * httpVersion; + + NextToken((const char **)&p); + + /* HTTP Version Decoding */ + + httpVersion = GetToken(&p); + if (httpVersion) { + uint32_t vmin, vmaj; + if (sscanf(httpVersion, "HTTP/%d.%d", &vmaj, &vmin) != 2) + *httpErrorCodeP = 400; /* Bad Request */ + else { + httpVersionP->major = vmaj; + httpVersionP->minor = vmin; + *httpErrorCodeP = 0; /* no error */ + } + *moreLinesP = TRUE; + } else { + /* There is no HTTP version, so this is a single + line request. + */ + *httpErrorCodeP = 0; /* no error */ + *moreLinesP = FALSE; + } + } + } + } +} + + + +static void +strtolower(char * const s) { + + char * t; + + t = &s[0]; + while (*t) { + *t = tolower(*t); + ++t; + } +} + + + +static void +getFieldNameToken(char ** const pP, + char ** const fieldNameP, + uint16_t * const httpErrorCodeP) { + + char * fieldName; + + NextToken((const char **)pP); + + fieldName = GetToken(pP); + if (!fieldName) + *httpErrorCodeP = 400; /* Bad Request */ + else { + if (fieldName[strlen(fieldName)-1] != ':') + /* Not a valid field name */ + *httpErrorCodeP = 400; /* Bad Request */ + else { + fieldName[strlen(fieldName)-1] = '\0'; /* remove trailing colon */ + + strtolower(fieldName); + + *httpErrorCodeP = 0; /* no error */ + *fieldNameP = fieldName; + } + } +} + + + +static void +processHeader(const char * const fieldName, + char * const fieldValue, + TSession * const sessionP, + uint16_t * const httpErrorCodeP) { +/*---------------------------------------------------------------------------- + We may modify *fieldValue, and we put pointers to *fieldValue and + *fieldName into *sessionP. + + We must fix this some day. *sessionP should point to individual + malloc'ed strings. +-----------------------------------------------------------------------------*/ + *httpErrorCodeP = 0; /* initial assumption */ + + if (xmlrpc_streq(fieldName, "connection")) { + if (xmlrpc_strcaseeq(fieldValue, "keep-alive")) + sessionP->request_info.keepalive = TRUE; + else + sessionP->request_info.keepalive = FALSE; + } else if (xmlrpc_streq(fieldName, "host")) + parseHostPort(fieldValue, &sessionP->request_info.host, + &sessionP->request_info.port, httpErrorCodeP); + else if (xmlrpc_streq(fieldName, "from")) + sessionP->request_info.from = fieldValue; + else if (xmlrpc_streq(fieldName, "user-agent")) + sessionP->request_info.useragent = fieldValue; + else if (xmlrpc_streq(fieldName, "referer")) + sessionP->request_info.referer = fieldValue; + else if (xmlrpc_streq(fieldName, "range")) { + if (xmlrpc_strneq(fieldValue, "bytes=", 6)) { + abyss_bool succeeded; + succeeded = ListAddFromString(&sessionP->ranges, &fieldValue[6]); + *httpErrorCodeP = succeeded ? 0 : 400; + } + } else if (xmlrpc_streq(fieldName, "cookies")) { + abyss_bool succeeded; + succeeded = ListAddFromString(&sessionP->cookies, fieldValue); + *httpErrorCodeP = succeeded ? 0 : 400; + } else if (xmlrpc_streq(fieldName, "expect")) { + if (xmlrpc_strcaseeq(fieldValue, "100-continue")) + sessionP->continueRequired = TRUE; + } +} + + + +abyss_bool +RequestRead(TSession * const sessionP) { + uint16_t httpErrorCode; /* zero for no error */ + char * requestLine; + + readRequestLine(sessionP, &requestLine, &httpErrorCode); + if (!httpErrorCode) { + TMethod httpMethod; + const char * host; + const char * path; + const char * query; + unsigned short port; + abyss_bool moreHeaders; + + parseRequestLine(requestLine, &httpMethod, &sessionP->version, + &host, &port, &path, &query, + &moreHeaders, &httpErrorCode); + + if (!httpErrorCode) + initRequestInfo(&sessionP->request_info, sessionP->version, + strdup(requestLine), + httpMethod, host, port, path, query); + + while (moreHeaders && !httpErrorCode) { + char * p; + abyss_bool succeeded; + succeeded = ConnReadHeader(sessionP->conn, &p); + if (!succeeded) + httpErrorCode = 408; /* Request Timeout */ + else { + if (!*p) + /* We have reached the empty line so all the request + was read. + */ + moreHeaders = FALSE; + else { + char * fieldName; + getFieldNameToken(&p, &fieldName, &httpErrorCode); + if (!httpErrorCode) { + char * fieldValue; + + NextToken((const char **)&p); + + fieldValue = p; + + TableAdd(&sessionP->request_headers, + fieldName, fieldValue); + + processHeader(fieldName, fieldValue, sessionP, + &httpErrorCode); + } + } + } + } + } + if (httpErrorCode) + ResponseStatus(sessionP, httpErrorCode); + else + sessionP->validRequest = true; + + return !httpErrorCode; +} + + + +char *RequestHeaderValue(TSession *r,char *name) +{ + return (TableFind(&r->request_headers,name)); +} + + + +abyss_bool +RequestValidURI(TSession * const sessionP) { + + if (!sessionP->request_info.uri) + return FALSE; + + if (xmlrpc_streq(sessionP->request_info.uri, "*")) + return (sessionP->request_info.method != m_options); + + if (strchr(sessionP->request_info.uri, '*')) + return FALSE; + + return TRUE; +} + + + +abyss_bool +RequestValidURIPath(TSession * const sessionP) { + + uint32_t i; + const char * p; + + p = sessionP->request_info.uri; + + i = 0; + + if (*p == '/') { + i = 1; + while (*p) + if (*(p++) == '/') { + if (*p == '/') + break; + else if ((strncmp(p,"./",2) == 0) || (strcmp(p, ".") == 0)) + ++p; + else if ((strncmp(p, "../", 2) == 0) || + (strcmp(p, "..") == 0)) { + p += 2; + --i; + if (i == 0) + break; + } + /* Prevent accessing hidden files (starting with .) */ + else if (*p == '.') + return FALSE; + else + if (*p) + ++i; + } + } + return (*p == 0 && i > 0); +} + + + +abyss_bool +RequestAuth(TSession *r,char *credential,char *user,char *pass) { + + char *p,*x; + char z[80],t[80]; + + p=RequestHeaderValue(r,"authorization"); + if (p) { + NextToken((const char **)&p); + x=GetToken(&p); + if (x) { + if (strcasecmp(x,"basic")==0) { + NextToken((const char **)&p); + sprintf(z,"%s:%s",user,pass); + Base64Encode(z,t); + + if (strcmp(p,t)==0) { + r->request_info.user=strdup(user); + return TRUE; + }; + }; + } + }; + + sprintf(z,"Basic realm=\"%s\"",credential); + ResponseAddField(r,"WWW-Authenticate",z); + ResponseStatus(r,401); + return FALSE; +} + + + +/********************************************************************* +** Range +*********************************************************************/ + +abyss_bool RangeDecode(char *str,uint64_t filesize,uint64_t *start,uint64_t *end) +{ + char *ss; + + *start=0; + *end=filesize-1; + + if (*str=='-') + { + *start=filesize-strtol(str+1,&ss,10); + return ((ss!=str) && (!*ss)); + }; + + *start=strtol(str,&ss,10); + + if ((ss==str) || (*ss!='-')) + return FALSE; + + str=ss+1; + + if (!*str) + return TRUE; + + *end=strtol(str,&ss,10); + + if ((ss==str) || (*ss) || (*end<*start)) + return FALSE; + + return TRUE; +} + +/********************************************************************* +** HTTP +*********************************************************************/ + +const char * +HTTPReasonByStatus(uint16_t const code) { + + struct _HTTPReasons { + uint16_t status; + const char * reason; + }; + + static struct _HTTPReasons const reasons[] = { + { 100,"Continue" }, + { 101,"Switching Protocols" }, + { 200,"OK" }, + { 201,"Created" }, + { 202,"Accepted" }, + { 203,"Non-Authoritative Information" }, + { 204,"No Content" }, + { 205,"Reset Content" }, + { 206,"Partial Content" }, + { 300,"Multiple Choices" }, + { 301,"Moved Permanently" }, + { 302,"Moved Temporarily" }, + { 303,"See Other" }, + { 304,"Not Modified" }, + { 305,"Use Proxy" }, + { 400,"Bad Request" }, + { 401,"Unauthorized" }, + { 402,"Payment Required" }, + { 403,"Forbidden" }, + { 404,"Not Found" }, + { 405,"Method Not Allowed" }, + { 406,"Not Acceptable" }, + { 407,"Proxy Authentication Required" }, + { 408,"Request Timeout" }, + { 409,"Conflict" }, + { 410,"Gone" }, + { 411,"Length Required" }, + { 412,"Precondition Failed" }, + { 413,"Request Entity Too Large" }, + { 414,"Request-URI Too Long" }, + { 415,"Unsupported Media Type" }, + { 500,"Internal Server Error" }, + { 501,"Not Implemented" }, + { 502,"Bad Gateway" }, + { 503,"Service Unavailable" }, + { 504,"Gateway Timeout" }, + { 505,"HTTP Version Not Supported" }, + { 000, NULL } + }; + const struct _HTTPReasons * reasonP; + + reasonP = &reasons[0]; + + while (reasonP->status <= code) + if (reasonP->status == code) + return reasonP->reason; + else + ++reasonP; + + return "No Reason"; +} + + + +int32_t +HTTPRead(TSession * const s ATTR_UNUSED, + const char * const buffer ATTR_UNUSED, + uint32_t const len ATTR_UNUSED) { + + return 0; +} + + + +abyss_bool +HTTPWriteBodyChunk(TSession * const sessionP, + const char * const buffer, + uint32_t const len) { + + abyss_bool succeeded; + + if (sessionP->chunkedwrite && sessionP->chunkedwritemode) { + char chunkHeader[16]; + + sprintf(chunkHeader, "%x\r\n", len); + + succeeded = + ConnWrite(sessionP->conn, chunkHeader, strlen(chunkHeader)); + if (succeeded) { + succeeded = ConnWrite(sessionP->conn, buffer, len); + if (succeeded) + succeeded = ConnWrite(sessionP->conn, "\r\n", 2); + } + } else + succeeded = ConnWrite(sessionP->conn, buffer, len); + + return succeeded; +} + + + +abyss_bool +HTTPWriteEndChunk(TSession * const sessionP) { + + abyss_bool retval; + + if (sessionP->chunkedwritemode && sessionP->chunkedwrite) { + /* May be one day trailer dumping will be added */ + sessionP->chunkedwritemode = FALSE; + retval = ConnWrite(sessionP->conn, "0\r\n\r\n", 5); + } else + retval = TRUE; + + return retval; +} + + + +abyss_bool +HTTPKeepalive(TSession * const sessionP) { +/*---------------------------------------------------------------------------- + Return value: the connection should be kept alive after the session + *sessionP is over. +-----------------------------------------------------------------------------*/ + return (sessionP->request_info.keepalive && + !sessionP->serverDeniesKeepalive && + sessionP->status < 400); +} + + + +abyss_bool +HTTPWriteContinue(TSession * const sessionP) { + + char const continueStatus[] = "HTTP/1.1 100 continue\r\n\r\n"; + /* This is a status line plus an end-of-headers empty line */ + + return ConnWrite(sessionP->conn, continueStatus, strlen(continueStatus)); +} + + + +/****************************************************************************** +** +** http.c +** +** Copyright (C) 2000 by Moez Mahfoudh . +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +** ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +** OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +** HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +** LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +** OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +** SUCH DAMAGE. +** +******************************************************************************/ diff --git a/lib/abyss/src/http.h b/lib/abyss/src/http.h new file mode 100644 index 0000000..2c6d6a4 --- /dev/null +++ b/lib/abyss/src/http.h @@ -0,0 +1,46 @@ +#ifndef HTTP_H_INCLUDED +#define HTTP_H_INCLUDED + +#include "conn.h" + +/********************************************************************* +** Request +*********************************************************************/ + +abyss_bool RequestValidURI(TSession *r); +abyss_bool RequestValidURIPath(TSession *r); +abyss_bool RequestUnescapeURI(TSession *r); + +abyss_bool RequestRead(TSession *r); +void RequestInit(TSession *r,TConn *c); +void RequestFree(TSession *r); + +abyss_bool RequestAuth(TSession *r,char *credential,char *user,char *pass); + +/********************************************************************* +** HTTP +*********************************************************************/ + +const char * +HTTPReasonByStatus(uint16_t const code); + +int32_t +HTTPRead(TSession * const sessionP, + const char * const buffer, + uint32_t const len); + +abyss_bool +HTTPWriteBodyChunk(TSession * const sessionP, + const char * const buffer, + uint32_t const len); + +abyss_bool +HTTPWriteEndChunk(TSession * const sessionP); + +abyss_bool +HTTPKeepalive(TSession * const sessionP); + +abyss_bool +HTTPWriteContinue(TSession * const sessionP); + +#endif diff --git a/lib/abyss/src/main.c b/lib/abyss/src/main.c new file mode 100644 index 0000000..93bf966 --- /dev/null +++ b/lib/abyss/src/main.c @@ -0,0 +1,243 @@ +/****************************************************************************** +** +** main.c +** +** This file is part of the ABYSS Web server project. +** +** Copyright (C) 2000 by Moez Mahfoudh . +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +** ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +** OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +** HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +** LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +** OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +** SUCH DAMAGE. +** +******************************************************************************/ + +#include +#include +#include +#include + +#ifdef WIN32 +#include +#endif /* WIN32 */ + +#ifdef _UNIX +#include +#include +#endif + +#include "xmlrpc-c/abyss.h" + +void Answer(TSession *r, uint16_t statuscode, char *buffer) +{ + ResponseChunked(r); + + ResponseStatus(r,statuscode); + + ResponseContentType(r,"text/html"); + + ResponseWrite(r); + + HTTPWrite(r,"",12); + + HTTPWrite(r,buffer,strlen(buffer)); + + HTTPWrite(r,"",14); + + HTTPWriteEnd(r); +} + +abyss_bool HandleTime(TSession *r) +{ + char z[50]; + time_t ltime; + TDate date; + + if (strcmp(r->uri,"/time")!=0) + return FALSE; + + if (!RequestAuth(r,"Mot de passe","moez","hello")) + return TRUE; + + time( <ime ); + DateFromGMT(&date,ltime); + + + strcpy(z,"The time is "); + DateToString(&date,z+strlen(z)); + + Answer(r,200,z); + + return TRUE; +} + +abyss_bool HandleDump(TSession *r) +{ + char z[50]; + + if (strcmp(r->uri,"/name")!=0) + return FALSE; + + sprintf(z,"Server name is %s", (r->server)->name ); + Answer(r,200,z); + + return TRUE; +} + +abyss_bool HandleStatus(TSession *r) +{ + uint32_t status; + + if (sscanf(r->uri,"/status/%d",&status)<=0) + return FALSE; + + ResponseStatus(r,(uint16_t)status); + + return TRUE; +} + +abyss_bool HandleMIMEType(TSession *r) +{ + char *m; + + if (strncmp(r->uri,"/mime/",6)!=0) + return FALSE; + + m=MIMETypeFromExt(r->uri+6); + if (!m) + m="(none)"; + + Answer(r,200,m); + + return TRUE; +} + +#ifdef _UNIX +static void sigterm(int sig) +{ + TraceExit("Signal %d received. Exiting...\n",sig); +} + + + +static void +sigchld(int const signalClass) { + + abyss_bool childrenLeft; + abyss_bool error; + + childrenLeft = true; + error = false; + + /* Reap defunct children until there aren't any more. */ + while (childrenLeft && !error) { + int status; + pid_t rc; + rc = waitpid((pid_t) -1, &status, WNOHANG); + + if (rc == 0) + childrenLeft = false; + else if (rc < 0) { + /* because of ptrace */ + if (errno == EINTR) { + /* ptrace causes this */ + } else + error = true; + } else { + /* We reaped a child. */ + pid_t const pid = rc; + ThreadHandleSigchld(pid); + } + } +} +#endif _UNIX + + + +int main(int argc,char **argv) +{ + TServer srv; + char *p,*conffile=DEFAULT_CONF_FILE; + abyss_bool err=FALSE; + char *name=argv[0]; + + while (p=*(++argv)) + { + if ((*p=='-') && (*(p+1))) + if (*(p+2)=='\0') + switch (*(p+1)) + { + case 'c': + argv++; + if (*argv) + conffile=*argv; + else + err=TRUE; + break; + default: + err=TRUE; + } + else + err=TRUE; + else + err=TRUE; + }; + + if (err) + { + help(name); + exit(1); + }; + + DateInit(); + + MIMETypeInit(); + + ServerCreate(&srv,"HTTPServer",80,DEFAULT_DOCS,NULL); + + ConfReadServerFile(conffile,&srv); + + ServerAddHandler(&srv,HandleTime); + ServerAddHandler(&srv,HandleDump); + ServerAddHandler(&srv,HandleStatus); + ServerAddHandler(&srv,HandleMIMEType); + + ServerInit(&srv); + +#ifdef _UNIX + /* Catch various termination signals. */ + signal(SIGTERM,sigterm); + signal(SIGINT,sigterm); + signal(SIGHUP,sigterm); + signal(SIGUSR1,sigterm); + + /* Catch defunct children. */ + signal(SIGCHLD,sigchld); +#endif + + ServerDaemonize(srv); + + ServerRun(&srv); + + return 0; +} diff --git a/lib/abyss/src/response.c b/lib/abyss/src/response.c new file mode 100644 index 0000000..89fb69c --- /dev/null +++ b/lib/abyss/src/response.c @@ -0,0 +1,657 @@ +/*============================================================================= + response +=============================================================================== + This module contains callbacks from and services for a request handler. + + Copyright information is at the end of the file +=============================================================================*/ + +#include +#include +#include +#include +#include +#include +#include + +#include "xmlrpc_config.h" +#include "mallocvar.h" +#include "xmlrpc-c/string_int.h" +#include "xmlrpc-c/abyss.h" + +#include "server.h" +#include "session.h" +#include "conn.h" +#include "token.h" +#include "date.h" +#include "data.h" +#include "abyss_info.h" +#include "http.h" + + + +void +ResponseError(TSession * const sessionP) { + + const char * const reason = HTTPReasonByStatus(sessionP->status); + const char * errorDocument; + + ResponseAddField(sessionP, "Content-type", "text/html"); + + ResponseWriteStart(sessionP); + + xmlrpc_asprintf(&errorDocument, + "Error %d" + "

Error %d

%s

" SERVER_HTML_INFO + "", + sessionP->status, sessionP->status, reason); + + ConnWrite(sessionP->conn, errorDocument, strlen(errorDocument)); + + xmlrpc_strfree(errorDocument); +} + + + +abyss_bool +ResponseChunked(TSession * const sessionP) { + /* This is only a hope, things will be real only after a call of + ResponseWriteStart() + */ + assert(!sessionP->responseStarted); + + sessionP->chunkedwrite = + (sessionP->version.major > 1) || + (sessionP->version.major == 1 && (sessionP->version.minor >= 1)); + + sessionP->chunkedwritemode = TRUE; + + return TRUE; +} + + + +void +ResponseStatus(TSession * const sessionP, + uint16_t const code) { + + sessionP->status = code; +} + + + +uint16_t +ResponseStatusFromErrno(int const errnoArg) { + + uint16_t code; + + switch (errnoArg) { + case EACCES: + code=403; + break; + case ENOENT: + code=404; + break; + default: + code=500; + } + return code; +} + + + +void +ResponseStatusErrno(TSession * const sessionP) { + + ResponseStatus(sessionP, ResponseStatusFromErrno(errno)); +} + + + +abyss_bool +ResponseAddField(TSession * const sessionP, + const char * const name, + const char * const value) { + + return TableAdd(&sessionP->response_headers, name, value); +} + + + +static void +addDateHeader(TSession * const sessionP) { + + char dateValue[64]; + abyss_bool validDate; + + validDate = DateToString(&sessionP->date, dateValue); + + if (sessionP->status >= 200 && validDate) + ResponseAddField(sessionP, "Date", dateValue); +} + + + +void +ResponseWriteStart(TSession * const sessionP) { + + struct _TServer * const srvP = ConnServer(sessionP->conn)->srvP; + + unsigned int i; + + assert(!sessionP->responseStarted); + + if (sessionP->status == 0) { + // Handler hasn't set status. That's an error + sessionP->status = 500; + } + + sessionP->responseStarted = TRUE; + + { + const char * const reason = HTTPReasonByStatus(sessionP->status); + const char * line; + xmlrpc_asprintf(&line,"HTTP/1.1 %u %s\r\n", sessionP->status, reason); + ConnWrite(sessionP->conn, line, strlen(line)); + xmlrpc_strfree(line); + } + + if (HTTPKeepalive(sessionP)) { + const char * keepaliveValue; + + ResponseAddField(sessionP, "Connection", "Keep-Alive"); + + xmlrpc_asprintf(&keepaliveValue, "timeout=%u, max=%u", + srvP->keepalivetimeout, srvP->keepalivemaxconn); + + ResponseAddField(sessionP, "Keep-Alive", keepaliveValue); + + xmlrpc_strfree(keepaliveValue); + } else + ResponseAddField(sessionP, "Connection", "close"); + + if (sessionP->chunkedwrite && sessionP->chunkedwritemode) + ResponseAddField(sessionP, "Transfer-Encoding", "chunked"); + + addDateHeader(sessionP); + + /* Generation of the server field */ + if (srvP->advertise) + ResponseAddField(sessionP, "Server", SERVER_HVERSION); + + /* send all the fields */ + for (i = 0; i < sessionP->response_headers.size; ++i) { + TTableItem * const ti = &sessionP->response_headers.item[i]; + const char * line; + xmlrpc_asprintf(&line, "%s: %s\r\n", ti->name, ti->value); + ConnWrite(sessionP->conn, line, strlen(line)); + xmlrpc_strfree(line); + } + + ConnWrite(sessionP->conn, "\r\n", 2); +} + + + +abyss_bool +ResponseWriteBody(TSession * const sessionP, + const char * const data, + uint32_t const len) { + + return HTTPWriteBodyChunk(sessionP, data, len); +} + + + +abyss_bool +ResponseWriteEnd(TSession * const sessionP) { + + return HTTPWriteEndChunk(sessionP); +} + + + +abyss_bool +ResponseContentType(TSession * const serverP, + const char * const type) { + + return ResponseAddField(serverP, "Content-type", type); +} + + + +abyss_bool +ResponseContentLength(TSession * const sessionP, + uint64_t const len) { + char contentLengthValue[32]; + + sprintf(contentLengthValue, "%llu", len); + + return ResponseAddField(sessionP, "Content-length", contentLengthValue); +} + + +/********************************************************************* +** MIMEType +*********************************************************************/ + +struct MIMEType { + TList typeList; + TList extList; + TPool pool; +}; + + +static MIMEType * globalMimeTypeP = NULL; + + + +MIMEType * +MIMETypeCreate(void) { + + MIMEType * MIMETypeP; + + MALLOCVAR(MIMETypeP); + + if (MIMETypeP) { + ListInit(&MIMETypeP->typeList); + ListInit(&MIMETypeP->extList); + PoolCreate(&MIMETypeP->pool, 1024); + } + return MIMETypeP; +} + + + +void +MIMETypeDestroy(MIMEType * const MIMETypeP) { + + PoolFree(&MIMETypeP->pool); +} + + + +void +MIMETypeInit(void) { + + if (globalMimeTypeP != NULL) + abort(); + + globalMimeTypeP = MIMETypeCreate(); +} + + + +void +MIMETypeTerm(void) { + + if (globalMimeTypeP == NULL) + abort(); + + MIMETypeDestroy(globalMimeTypeP); + + globalMimeTypeP = NULL; +} + + + +static void +mimeTypeAdd(MIMEType * const MIMETypeP, + const char * const type, + const char * const ext, + abyss_bool * const successP) { + + uint16_t index; + void * mimeTypesItem; + abyss_bool typeIsInList; + + assert(MIMETypeP != NULL); + + typeIsInList = ListFindString(&MIMETypeP->typeList, type, &index); + if (typeIsInList) + mimeTypesItem = MIMETypeP->typeList.item[index]; + else + mimeTypesItem = (void*)PoolStrdup(&MIMETypeP->pool, type); + + if (mimeTypesItem) { + abyss_bool extIsInList; + extIsInList = ListFindString(&MIMETypeP->extList, ext, &index); + if (extIsInList) { + MIMETypeP->typeList.item[index] = mimeTypesItem; + *successP = TRUE; + } else { + void * extItem = (void*)PoolStrdup(&MIMETypeP->pool, ext); + if (extItem) { + abyss_bool addedToMimeTypes; + + addedToMimeTypes = + ListAdd(&MIMETypeP->typeList, mimeTypesItem); + if (addedToMimeTypes) { + abyss_bool addedToExt; + + addedToExt = ListAdd(&MIMETypeP->extList, extItem); + *successP = addedToExt; + if (!*successP) + ListRemove(&MIMETypeP->typeList); + } else + *successP = FALSE; + if (!*successP) + PoolReturn(&MIMETypeP->pool, extItem); + } else + *successP = FALSE; + } + } else + *successP = FALSE; +} + + + + +abyss_bool +MIMETypeAdd2(MIMEType * const MIMETypeArg, + const char * const type, + const char * const ext) { + + MIMEType * MIMETypeP = MIMETypeArg ? MIMETypeArg : globalMimeTypeP; + + abyss_bool success; + + if (MIMETypeP == NULL) + success = FALSE; + else + mimeTypeAdd(MIMETypeP, type, ext, &success); + + return success; +} + + + +abyss_bool +MIMETypeAdd(const char * const type, + const char * const ext) { + + return MIMETypeAdd2(globalMimeTypeP, type, ext); +} + + + +static const char * +mimeTypeFromExt(MIMEType * const MIMETypeP, + const char * const ext) { + + const char * retval; + uint16_t extindex; + abyss_bool extIsInList; + + assert(MIMETypeP != NULL); + + extIsInList = ListFindString(&MIMETypeP->extList, ext, &extindex); + if (!extIsInList) + retval = NULL; + else + retval = MIMETypeP->typeList.item[extindex]; + + return retval; +} + + + +const char * +MIMETypeFromExt2(MIMEType * const MIMETypeArg, + const char * const ext) { + + const char * retval; + + MIMEType * MIMETypeP = MIMETypeArg ? MIMETypeArg : globalMimeTypeP; + + if (MIMETypeP == NULL) + retval = NULL; + else + retval = mimeTypeFromExt(MIMETypeP, ext); + + return retval; +} + + + +const char * +MIMETypeFromExt(const char * const ext) { + + return MIMETypeFromExt2(globalMimeTypeP, ext); +} + + + +static void +findExtension(const char * const fileName, + const char ** const extP) { + + unsigned int extPos = 0; /* stifle unset variable warning */ + /* Running estimation of where in fileName[] the extension starts */ + abyss_bool extFound; + unsigned int i; + + /* We're looking for the last dot after the last slash */ + for (i = 0, extFound = FALSE; fileName[i]; ++i) { + char const c = fileName[i]; + + if (c == '.') { + extFound = TRUE; + extPos = i + 1; + } + if (c == '/') + extFound = FALSE; + } + + if (extFound) + *extP = &fileName[extPos]; + else + *extP = NULL; +} + + + +static const char * +mimeTypeFromFileName(MIMEType * const MIMETypeP, + const char * const fileName) { + + const char * retval; + const char * ext; + + assert(MIMETypeP != NULL); + + findExtension(fileName, &ext); + + if (ext) + retval = MIMETypeFromExt2(MIMETypeP, ext); + else + retval = "application/octet-stream"; + + return retval; +} + + + +const char * +MIMETypeFromFileName2(MIMEType * const MIMETypeArg, + const char * const fileName) { + + const char * retval; + + MIMEType * MIMETypeP = MIMETypeArg ? MIMETypeArg : globalMimeTypeP; + + if (MIMETypeP == NULL) + retval = NULL; + else + retval = mimeTypeFromFileName(MIMETypeP, fileName); + + return retval; +} + + + +const char * +MIMETypeFromFileName(const char * const fileName) { + + return MIMETypeFromFileName2(globalMimeTypeP, fileName); +} + + + +static abyss_bool +fileContainsText(const char * const fileName) { +/*---------------------------------------------------------------------------- + Return true iff we can read the contents of the file named 'fileName' + and see that it appears to be composed of plain text characters. +-----------------------------------------------------------------------------*/ + abyss_bool retval; + abyss_bool fileOpened; + TFile file; + + fileOpened = FileOpen(&file, fileName, O_BINARY | O_RDONLY); + if (fileOpened) { + char const ctlZ = 26; + unsigned char buffer[80]; + int32_t readRc; + unsigned int i; + + readRc = FileRead(&file, buffer, sizeof(buffer)); + + if (readRc >= 0) { + unsigned int bytesRead = readRc; + abyss_bool nonTextFound; + + nonTextFound = FALSE; /* initial value */ + + for (i = 0; i < bytesRead; ++i) { + char const c = buffer[i]; + if (c < ' ' && !isspace(c) && c != ctlZ) + nonTextFound = TRUE; + } + retval = !nonTextFound; + } else + retval = FALSE; + FileClose(&file); + } else + retval = FALSE; + + return retval; +} + + + +static const char * +mimeTypeGuessFromFile(MIMEType * const MIMETypeP, + const char * const fileName) { + + const char * retval; + const char * ext; + + findExtension(fileName, &ext); + + retval = NULL; + + if (ext && MIMETypeP) + retval = MIMETypeFromExt2(MIMETypeP, ext); + + if (!retval) { + if (fileContainsText(fileName)) + retval = "text/plain"; + else + retval = "application/octet-stream"; + } + return retval; +} + + + +const char * +MIMETypeGuessFromFile2(MIMEType * const MIMETypeArg, + const char * const fileName) { + + return mimeTypeGuessFromFile(MIMETypeArg ? MIMETypeArg : globalMimeTypeP, + fileName); +} + + + +const char * +MIMETypeGuessFromFile(const char * const fileName) { + + return mimeTypeGuessFromFile(globalMimeTypeP, fileName); +} + + + +/********************************************************************* +** Base64 +*********************************************************************/ + +void Base64Encode(char *s,char *d) +{ + /* Conversion table. */ + static char tbl[64] = { + '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','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','0','1','2','3', + '4','5','6','7','8','9','+','/' + }; + + uint32_t i,length=strlen(s); + char *p=d; + + /* Transform the 3x8 bits to 4x6 bits, as required by base64. */ + for (i = 0; i < length; i += 3) + { + *p++ = tbl[s[0] >> 2]; + *p++ = tbl[((s[0] & 3) << 4) + (s[1] >> 4)]; + *p++ = tbl[((s[1] & 0xf) << 2) + (s[2] >> 6)]; + *p++ = tbl[s[2] & 0x3f]; + s += 3; + } + + /* Pad the result if necessary... */ + if (i == length + 1) + *(p - 1) = '='; + else if (i == length + 2) + *(p - 1) = *(p - 2) = '='; + + /* ...and zero-terminate it. */ + *p = '\0'; +} + +/****************************************************************************** +** +** http.c +** +** Copyright (C) 2000 by Moez Mahfoudh . +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +** ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +** OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +** HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +** LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +** OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +** SUCH DAMAGE. +** +******************************************************************************/ diff --git a/lib/abyss/src/server.c b/lib/abyss/src/server.c new file mode 100644 index 0000000..8e5af56 --- /dev/null +++ b/lib/abyss/src/server.c @@ -0,0 +1,1794 @@ +/* Copyright information is at end of file */ +#include +#include +#include +#include +#include +#include +#ifdef WIN32 + #include +#else + #include + #include +#endif +#include + +#include "xmlrpc_config.h" +#include "mallocvar.h" +#include "xmlrpc-c/string_int.h" +#include "xmlrpc-c/sleep_int.h" + +#include "xmlrpc-c/abyss.h" +#include "trace.h" +#include "session.h" +#include "conn.h" +#include "socket.h" +#ifdef WIN32 + #include "socket_win.h" +#else + #include "socket_unix.h" +#endif +#include "http.h" +#include "date.h" +#include "abyss_info.h" + +#include "server.h" + + +void +ServerTerminate(TServer * const serverP) { + + struct _TServer * const srvP = serverP->srvP; + + srvP->terminationRequested = true; +} + + + +void +ServerResetTerminate(TServer * const serverP) { + + struct _TServer * const srvP = serverP->srvP; + + srvP->terminationRequested = false; +} + + + +typedef int (*TQSortProc)(const void *, const void *); + +static int +cmpfilenames(const TFileInfo **f1,const TFileInfo **f2) { + if (((*f1)->attrib & A_SUBDIR) && !((*f2)->attrib & A_SUBDIR)) + return (-1); + if (!((*f1)->attrib & A_SUBDIR) && ((*f2)->attrib & A_SUBDIR)) + return 1; + + return strcmp((*f1)->name,(*f2)->name); +} + +static int +cmpfiledates(const TFileInfo **f1,const TFileInfo **f2) { + if (((*f1)->attrib & A_SUBDIR) && !((*f2)->attrib & A_SUBDIR)) + return (-1); + if (!((*f1)->attrib & A_SUBDIR) && ((*f2)->attrib & A_SUBDIR)) + return 1; + + return ((*f1)->time_write-(*f2)->time_write); +} + + + +static void +determineSortType(const char * const query, + abyss_bool * const ascendingP, + uint16_t * const sortP, + abyss_bool * const textP, + const char ** const errorP) { + + *ascendingP = TRUE; + *sortP = 1; + *textP = FALSE; + *errorP = NULL; + + if (query) { + if (xmlrpc_streq(query, "plain")) + *textP = TRUE; + else if (xmlrpc_streq(query, "name-up")) { + *sortP = 1; + *ascendingP = TRUE; + } else if (xmlrpc_streq(query, "name-down")) { + *sortP = 1; + *ascendingP = FALSE; + } else if (xmlrpc_streq(query, "date-up")) { + *sortP = 2; + *ascendingP = TRUE; + } else if (xmlrpc_streq(query, "date-down")) { + *sortP = 2; + *ascendingP = FALSE; + } else { + xmlrpc_asprintf(errorP, "invalid query value '%s'", query); + } + } +} + + + +static void +generateListing(TList * const listP, + char * const z, + const char * const uri, + TPool * const poolP, + const char ** const errorP, + uint16_t * const responseStatusP) { + + TFileInfo fileinfo; + TFileFind findhandle; + + *errorP = NULL; + + if (!FileFindFirst(&findhandle, z, &fileinfo)) { + *responseStatusP = ResponseStatusFromErrno(errno); + xmlrpc_asprintf(errorP, "Can't read first entry in directory"); + } else { + ListInit(listP); + + do { + TFileInfo * fi; + /* Files whose names start with a dot are ignored */ + /* This includes implicitly the ./ and ../ */ + if (*fileinfo.name == '.') { + if (xmlrpc_streq(fileinfo.name, "..")) { + if (xmlrpc_streq(uri, "/")) + continue; + } else + continue; + } + fi = (TFileInfo *)PoolAlloc(poolP, sizeof(fileinfo)); + if (fi) { + abyss_bool success; + memcpy(fi, &fileinfo, sizeof(fileinfo)); + success = ListAdd(listP, fi); + if (!success) + xmlrpc_asprintf(errorP, "ListAdd() failed"); + } else + xmlrpc_asprintf(errorP, "PoolAlloc() failed."); + } while (!*errorP && FileFindNext(&findhandle, &fileinfo)); + + if (*errorP) { + *responseStatusP = 500; + ListFree(listP); + } + FileFindClose(&findhandle); + } +} + + + +static void +sendDirectoryDocument(TList * const listP, + abyss_bool const ascending, + uint16_t const sort, + abyss_bool const text, + const char * const uri, + MIMEType * const mimeTypeP, + TSession * const sessionP, + char * const z) { + + char *p,z1[26],z2[20],z3[9],u; + const char * z4; + int16_t i; + uint32_t k; + + if (text) { + sprintf(z, "Index of %s" CRLF, uri); + i = strlen(z)-2; + p = z + i + 2; + + while (i > 0) { + *(p++) = '-'; + --i; + } + + *p = '\0'; + strcat(z, CRLF CRLF + "Name Size " + "Date-Time Type" CRLF + "------------------------------------" + "--------------------------------------------"CRLF); + } else { + sprintf(z, "Index of %s" + "

Index of %s

",
+                uri, uri);
+        strcat(z, "Name                      Size      "
+               "Date-Time             Type
"CRLF); + } + + HTTPWriteBodyChunk(sessionP, z, strlen(z)); + + /* Sort the files */ + qsort(listP->item, listP->size, sizeof(void *), + (TQSortProc)(sort == 1 ? cmpfilenames : cmpfiledates)); + + /* Write the listing */ + if (ascending) + i = 0; + else + i = listP->size - 1; + + while ((i < listP->size) && (i >= 0)) { + TFileInfo * fi; + struct tm ftm; + + fi = listP->item[i]; + + if (ascending) + ++i; + else + --i; + + strcpy(z, fi->name); + + k = strlen(z); + + if (fi->attrib & A_SUBDIR) { + z[k++] = '/'; + z[k] = '\0'; + } + + if (k > 24) { + z[10] = '\0'; + strcpy(z1, z); + strcat(z1, "..."); + strcat(z1, z + k - 11); + k = 24; + p = z1 + 24; + } else { + strcpy(z1, z); + + ++k; + p = z1 + k; + while (k < 25) + z1[k++] = ' '; + + z1[25] = '\0'; + } + + ftm = *gmtime(&fi->time_write); + sprintf(z2, "%02u/%02u/%04u %02u:%02u:%02u",ftm.tm_mday,ftm.tm_mon+1, + ftm.tm_year+1900,ftm.tm_hour,ftm.tm_min,ftm.tm_sec); + + if (fi->attrib & A_SUBDIR) { + strcpy(z3, " -- "); + z4 = "Directory"; + } else { + if (fi->size < 9999) + u = 'b'; + else { + fi->size /= 1024; + if (fi->size < 9999) + u = 'K'; + else { + fi->size /= 1024; + if (fi->size < 9999) + u = 'M'; + else + u = 'G'; + } + } + + sprintf(z3, "%5llu %c", fi->size, u); + + if (xmlrpc_streq(fi->name, "..")) + z4 = ""; + else + z4 = MIMETypeFromFileName2(mimeTypeP, fi->name); + + if (!z4) + z4 = "Unknown"; + } + + if (text) + sprintf(z, "%s%s %s %s %s"CRLF, z1, p, z3, z2, z4); + else + sprintf(z, "%s%s %s %s %s"CRLF, + fi->name, fi->attrib & A_SUBDIR ? "/" : "", + z1, p, z3, z2, z4); + + HTTPWriteBodyChunk(sessionP, z, strlen(z)); + } + + /* Write the tail of the file */ + if (text) + strcpy(z, SERVER_PLAIN_INFO); + else + strcpy(z, "
" SERVER_HTML_INFO "" CRLF CRLF); + + HTTPWriteBodyChunk(sessionP, z, strlen(z)); +} + + + +static void +fileDate(TSession * const sessionP, + time_t const statFilemodTime, + TDate * const fileDateP) { + + abyss_bool haveDate; + TDate filemodDate; + + haveDate = DateFromLocal(&filemodDate, statFilemodTime); + + if (haveDate) { + if (DateCompare(&sessionP->date, &filemodDate) < 0) + *fileDateP = sessionP->date; + else + *fileDateP = filemodDate; + } else + *fileDateP = sessionP->date; +} + + + +static abyss_bool +ServerDirectoryHandler(TSession * const r, + char * const z, + time_t const fileModTime, + MIMEType * const mimeTypeP) { + + TList list; + abyss_bool text; + abyss_bool ascending; + uint16_t sort; /* 1=by name, 2=by date */ + TPool pool; + TDate date; + const char * error; + uint16_t responseStatus; + TDate dirdate; + const char * imsHdr; + + determineSortType(r->request_info.query, &ascending, &sort, &text, &error); + + if (error) { + ResponseStatus(r,400); + xmlrpc_strfree(error); + return TRUE; + } + + fileDate(r, fileModTime, &dirdate); + + imsHdr = RequestHeaderValue(r, "If-Modified-Since"); + if (imsHdr) { + if (DateDecode(imsHdr, &date)) { + if (DateCompare(&dirdate, &date) <= 0) { + ResponseStatus(r, 304); + ResponseWrite(r); + return TRUE; + } + } + } + + if (!PoolCreate(&pool, 1024)) { + ResponseStatus(r, 500); + return TRUE; + } + + generateListing(&list, z, r->request_info.uri, + &pool, &error, &responseStatus); + if (error) { + ResponseStatus(r, responseStatus); + xmlrpc_strfree(error); + PoolFree(&pool); + return TRUE; + } + + /* Send something to the user to show that we are still alive */ + ResponseStatus(r, 200); + ResponseContentType(r, (text ? "text/plain" : "text/html")); + + if (DateToString(&dirdate, z)) + ResponseAddField(r, "Last-Modified", z); + + ResponseChunked(r); + ResponseWrite(r); + + if (r->request_info.method!=m_head) + sendDirectoryDocument(&list, ascending, sort, text, + r->request_info.uri, mimeTypeP, r, z); + + HTTPWriteEndChunk(r); + + /* Free memory and exit */ + ListFree(&list); + PoolFree(&pool); + + return TRUE; +} + + + +#define BOUNDARY "##123456789###BOUNDARY" + +static void +sendBody(TSession * const sessionP, + TFile * const fileP, + uint64_t const filesize, + const char * const mediatype, + uint64_t const start0, + uint64_t const end0, + char * const z) { + + if (sessionP->ranges.size == 0) + ConnWriteFromFile(sessionP->conn, fileP, 0, filesize - 1, z, 4096, 0); + else if (sessionP->ranges.size == 1) + ConnWriteFromFile(sessionP->conn, fileP, start0, end0, z, 4096, 0); + else { + uint64_t i; + for (i = 0; i <= sessionP->ranges.size; ++i) { + ConnWrite(sessionP->conn,"--", 2); + ConnWrite(sessionP->conn, BOUNDARY, strlen(BOUNDARY)); + ConnWrite(sessionP->conn, CRLF, 2); + + if (i < sessionP->ranges.size) { + uint64_t start; + uint64_t end; + abyss_bool decoded; + + decoded = RangeDecode((char *)(sessionP->ranges.item[i]), + filesize, + &start, &end); + if (decoded) { + /* Entity header, not response header */ + sprintf(z, "Content-type: %s" CRLF + "Content-range: bytes %llu-%llu/%llu" CRLF + "Content-length: %llu" CRLF + CRLF, mediatype, start, end, + filesize, end-start+1); + + ConnWrite(sessionP->conn, z, strlen(z)); + + ConnWriteFromFile(sessionP->conn, fileP, start, end, z, + 4096, 0); + } + } + } + } +} + + + +static abyss_bool +ServerFileHandler(TSession * const r, + char * const z, + time_t const fileModTime, + MIMEType * const mimeTypeP) { + + const char * mediatype; + TFile file; + uint64_t filesize; + uint64_t start; + uint64_t end; + TDate date; + char * p; + TDate filedate; + + mediatype = MIMETypeGuessFromFile2(mimeTypeP, z); + + if (!FileOpen(&file,z,O_BINARY | O_RDONLY)) { + ResponseStatusErrno(r); + return TRUE; + } + + fileDate(r, fileModTime, &filedate); + + p = RequestHeaderValue(r, "if-modified-since"); + if (p) { + if (DateDecode(p,&date)) { + if (DateCompare(&filedate, &date) <= 0) { + ResponseStatus(r, 304); + ResponseWrite(r); + return TRUE; + } else + r->ranges.size = 0; + } + } + filesize = FileSize(&file); + + switch (r->ranges.size) { + case 0: + ResponseStatus(r, 200); + break; + + case 1: { + abyss_bool decoded; + decoded = RangeDecode((char *)(r->ranges.item[0]), filesize, + &start, &end); + if (!decoded) { + ListFree(&(r->ranges)); + ResponseStatus(r, 200); + break; + } + + sprintf(z, "bytes %llu-%llu/%llu", start, end, filesize); + + ResponseAddField(r, "Content-range", z); + ResponseContentLength(r, end - start + 1); + ResponseStatus(r, 206); + } break; + + default: + ResponseContentType(r, "multipart/ranges; boundary=" BOUNDARY); + ResponseStatus(r, 206); + break; + } + + if (r->ranges.size == 0) { + ResponseContentLength(r, filesize); + ResponseContentType(r, mediatype); + } + + if (DateToString(&filedate, z)) + ResponseAddField(r, "Last-Modified", z); + + ResponseWrite(r); + + if (r->request_info.method != m_head) + sendBody(r, &file, filesize, mediatype, start, end, z); + + FileClose(&file); + + return TRUE; +} + + + +static abyss_bool +ServerDefaultHandlerFunc(TSession * const sessionP) { + + struct _TServer * const srvP = ConnServer(sessionP->conn)->srvP; + + char *p; + char z[4096]; + TFileStat fs; + unsigned int i; + abyss_bool endingslash=FALSE; + + if (!RequestValidURIPath(sessionP)) { + ResponseStatus(sessionP, 400); + return TRUE; + } + + /* Must check for * (asterisk uri) in the future */ + if (sessionP->request_info.method == m_options) { + ResponseAddField(sessionP, "Allow", "GET, HEAD"); + ResponseContentLength(sessionP, 0); + ResponseStatus(sessionP, 200); + return TRUE; + } + + if ((sessionP->request_info.method != m_get) && + (sessionP->request_info.method != m_head)) { + ResponseAddField(sessionP, "Allow", "GET, HEAD"); + ResponseStatus(sessionP, 405); + return TRUE; + } + + strcpy(z, srvP->filespath); + strcat(z, sessionP->request_info.uri); + + p = z + strlen(z) - 1; + if (*p == '/') { + endingslash = TRUE; + *p = '\0'; + } + +#ifdef WIN32 + p = z; + while (*p) { + if ((*p) == '/') + *p= '\\'; + + ++p; + } +#endif /* WIN32 */ + + if (!FileStat(z, &fs)) { + ResponseStatusErrno(sessionP); + return TRUE; + } + + if (fs.st_mode & S_IFDIR) { + /* Redirect to the same directory but with the ending slash + ** to avoid problems with some browsers (IE for examples) when + ** they generate relative urls */ + if (!endingslash) { + strcpy(z, sessionP->request_info.uri); + p = z+strlen(z); + *p = '/'; + *(p+1) = '\0'; + ResponseAddField(sessionP, "Location", z); + ResponseStatus(sessionP, 302); + ResponseWrite(sessionP); + return TRUE; + } + + *p = DIRECTORY_SEPARATOR[0]; + ++p; + + i = srvP->defaultfilenames.size; + while (i-- > 0) { + *p = '\0'; + strcat(z, (srvP->defaultfilenames.item[i])); + if (FileStat(z, &fs)) { + if (!(fs.st_mode & S_IFDIR)) + return ServerFileHandler(sessionP, z, fs.st_mtime, + srvP->mimeTypeP); + } + } + + *(p-1) = '\0'; + + if (!FileStat(z, &fs)) { + ResponseStatusErrno(sessionP); + return TRUE; + } + return ServerDirectoryHandler(sessionP, z, fs.st_mtime, + srvP->mimeTypeP); + } else + return ServerFileHandler(sessionP, z, fs.st_mtime, + srvP->mimeTypeP); +} + + + +static void +initUnixStuff(struct _TServer * const srvP) { +#ifndef WIN32 + srvP->pidfile = srvP->uid = srvP->gid = -1; +#endif +} + + + +static abyss_bool +logOpen(struct _TServer * const srvP) { + + abyss_bool success; + + success = FileOpenCreate(&srvP->logfile, srvP->logfilename, + O_WRONLY | O_APPEND); + if (success) { + abyss_bool success; + success = MutexCreate(&srvP->logmutex); + if (success) + srvP->logfileisopen = TRUE; + else + TraceMsg("Can't create mutex for log file"); + + if (!success) + FileClose(&srvP->logfile); + } else + TraceMsg("Can't open log file '%s'", srvP->logfilename); + + return success; +} + + + +static void +logClose(struct _TServer * const srvP) { + + if (srvP->logfileisopen) { + FileClose(&srvP->logfile); + MutexFree(&srvP->logmutex); + srvP->logfileisopen = FALSE; + } +} + + + +static void +initSocketStuff(struct _TServer * const srvP, + abyss_bool const noAccept, + TSocket * const userSocketP, + uint16_t const port, + const char ** const errorP) { + + if (userSocketP) { + *errorP = NULL; + srvP->serverAcceptsConnections = TRUE; + srvP->socketBound = TRUE; + srvP->listenSocketP = userSocketP; + } else if (noAccept) { + *errorP = NULL; + srvP->serverAcceptsConnections = FALSE; + srvP->socketBound = FALSE; + } else { + *errorP = NULL; + srvP->serverAcceptsConnections = TRUE; + srvP->socketBound = FALSE; + srvP->port = port; + } + srvP->weCreatedListenSocket = FALSE; +} + + + +static void +createServer(struct _TServer ** const srvPP, + abyss_bool const noAccept, + TSocket * const userSocketP, + uint16_t const portNumber, + const char ** const errorP) { + + struct _TServer * srvP; + + MALLOCVAR(srvP); + + if (srvP == NULL) { + xmlrpc_asprintf(errorP, + "Unable to allocate space for server descriptor"); + } else { + srvP->terminationRequested = false; + + initSocketStuff(srvP, noAccept, userSocketP, portNumber, errorP); + + if (!*errorP) { + srvP->defaulthandler = ServerDefaultHandlerFunc; + + srvP->name = strdup("unnamed"); + srvP->filespath = strdup(DEFAULT_DOCS); + srvP->logfilename = NULL; + srvP->keepalivetimeout = 15; + srvP->keepalivemaxconn = 30; + srvP->timeout = 15; + srvP->advertise = TRUE; + srvP->mimeTypeP = NULL; + srvP->useSigchld = FALSE; + + initUnixStuff(srvP); + + ListInitAutoFree(&srvP->handlers); + ListInitAutoFree(&srvP->defaultfilenames); + + srvP->logfileisopen = FALSE; + + *errorP = NULL; + } + if (*errorP) + free(srvP); + } + *srvPP = srvP; +} + + + +static void +setNamePathLog(TServer * const serverP, + const char * const name, + const char * const filesPath, + const char * const logFileName) { +/*---------------------------------------------------------------------------- + This odd function exists to help with backward compatibility. + Today, we have the expandable model where you create a server with + default parameters, then use ServerSet... functions to choose + non-default parameters. But before, you specified these three + parameters right in the arguments of various create functions. +-----------------------------------------------------------------------------*/ + if (name) + ServerSetName(serverP, name); + if (filesPath) + ServerSetFilesPath(serverP, filesPath); + if (logFileName) + ServerSetLogFileName(serverP, logFileName); +} + + + +abyss_bool +ServerCreate(TServer * const serverP, + const char * const name, + uint16_t const portNumber, + const char * const filesPath, + const char * const logFileName) { + + abyss_bool const noAcceptFalse = FALSE; + + abyss_bool success; + const char * error; + + createServer(&serverP->srvP, noAcceptFalse, NULL, portNumber, &error); + + if (error) { + TraceMsg(error); + xmlrpc_strfree(error); + success = FALSE; + } else { + success = TRUE; + + setNamePathLog(serverP, name, filesPath, logFileName); + } + + return success; +} + + + +static void +createSocketFromOsSocket(TOsSocket const osSocket, + TSocket ** const socketPP) { + +#ifdef WIN32 + SocketWinCreateWinsock(osSocket, socketPP); +#else + SocketUnixCreateFd(osSocket, socketPP); +#endif +} + + + +abyss_bool +ServerCreateSocket(TServer * const serverP, + const char * const name, + TOsSocket const socketFd, + const char * const filesPath, + const char * const logFileName) { + + abyss_bool success; + TSocket * socketP; + + createSocketFromOsSocket(socketFd, &socketP); + + if (socketP) { + abyss_bool const noAcceptFalse = FALSE; + + const char * error; + + createServer(&serverP->srvP, noAcceptFalse, socketP, 0, &error); + + if (error) { + TraceMsg(error); + success = FALSE; + xmlrpc_strfree(error); + } else { + success = TRUE; + + setNamePathLog(serverP, name, filesPath, logFileName); + } + } else + success = FALSE; + + return success; +} + + + +abyss_bool +ServerCreateNoAccept(TServer * const serverP, + const char * const name, + const char * const filesPath, + const char * const logFileName) { + + abyss_bool const noAcceptTrue = TRUE; + + abyss_bool success; + const char * error; + + createServer(&serverP->srvP, noAcceptTrue, NULL, 0, &error); + + if (error) { + TraceMsg(error); + success = FALSE; + xmlrpc_strfree(error); + } else { + success = TRUE; + + setNamePathLog(serverP, name, filesPath, logFileName); + } + return success; +} + + + +void +ServerCreateSocket2(TServer * const serverP, + TSocket * const socketP, + const char ** const errorP) { + + abyss_bool const noAcceptFalse = FALSE; + + assert(socketP); + + createServer(&serverP->srvP, noAcceptFalse, socketP, 0, errorP); +} + + + +static void +terminateHandlers(TList * const handlersP) { +/*---------------------------------------------------------------------------- + Terminate all handlers in the list '*handlersP'. + + I.e. call each handler's terminate function. +-----------------------------------------------------------------------------*/ + if (handlersP->item) { + unsigned int i; + for (i = handlersP->size; i > 0; --i) { + URIHandler2 * const handlerP = handlersP->item[i-1]; + if (handlerP->term) + handlerP->term(handlerP->userdata); + } + } +} + + + +void +ServerFree(TServer * const serverP) { + + struct _TServer * const srvP = serverP->srvP; + + if (srvP->weCreatedListenSocket) + SocketDestroy(srvP->listenSocketP); + + xmlrpc_strfree(srvP->name); + + xmlrpc_strfree(srvP->filespath); + + ListFree(&srvP->defaultfilenames); + + terminateHandlers(&srvP->handlers); + + ListFree(&srvP->handlers); + + logClose(srvP); + + if (srvP->logfilename) + xmlrpc_strfree(srvP->logfilename); + + free(srvP); +} + + + +void +ServerSetName(TServer * const serverP, + const char * const name) { + + xmlrpc_strfree(serverP->srvP->name); + + serverP->srvP->name = strdup(name); +} + + + +void +ServerSetFilesPath(TServer * const serverP, + const char * const filesPath) { + + xmlrpc_strfree(serverP->srvP->filespath); + + serverP->srvP->filespath = strdup(filesPath); +} + + + +void +ServerSetLogFileName(TServer * const serverP, + const char * const logFileName) { + + struct _TServer * const srvP = serverP->srvP; + + if (srvP->logfilename) + xmlrpc_strfree(srvP->logfilename); + + srvP->logfilename = strdup(logFileName); +} + + + +void +ServerSetKeepaliveTimeout(TServer * const serverP, + uint32_t const keepaliveTimeout) { + + serverP->srvP->keepalivetimeout = keepaliveTimeout; +} + + + +void +ServerSetKeepaliveMaxConn(TServer * const serverP, + uint32_t const keepaliveMaxConn) { + + serverP->srvP->keepalivemaxconn = keepaliveMaxConn; +} + + + +void +ServerSetTimeout(TServer * const serverP, + uint32_t const timeout) { + + serverP->srvP->timeout = timeout; +} + + + +void +ServerSetAdvertise(TServer * const serverP, + abyss_bool const advertise) { + + serverP->srvP->advertise = advertise; +} + + + +void +ServerSetMimeType(TServer * const serverP, + MIMEType * const MIMETypeP) { + + serverP->srvP->mimeTypeP = MIMETypeP; +} + + + +static void +runUserHandler(TSession * const sessionP, + struct _TServer * const srvP) { + + abyss_bool handled; + int i; + + for (i = srvP->handlers.size-1, handled = FALSE; + i >= 0 && !handled; + --i) { + URIHandler2 * const handlerP = srvP->handlers.item[i]; + + if (handlerP->handleReq2) + handlerP->handleReq2(handlerP, sessionP, &handled); + else if (handlerP->handleReq1) + handled = handlerP->handleReq1(sessionP); + } + + if (!handled) + ((URIHandler)(srvP->defaulthandler))(sessionP); +} + + + +static void +processDataFromClient(TConn * const connectionP, + abyss_bool const lastReqOnConn, + abyss_bool * const keepAliveP) { + + TSession session; + + RequestInit(&session, connectionP); + + session.serverDeniesKeepalive = lastReqOnConn; + + RequestRead(&session); + if (session.status == 0) { + if (session.version.major >= 2) + ResponseStatus(&session, 505); + else if (!RequestValidURI(&session)) + ResponseStatus(&session, 400); + else + runUserHandler(&session, connectionP->server->srvP); + } + assert(session.status != 0); + + if (session.responseStarted) + HTTPWriteEndChunk(&session); + else + ResponseError(&session); + + *keepAliveP = HTTPKeepalive(&session); + + SessionLog(&session); + + RequestFree(&session); +} + + +static TThreadProc serverFunc; + +static void +serverFunc(void * const userHandle) { +/*---------------------------------------------------------------------------- + Do server stuff on one connection. At its simplest, this means do + one HTTP request. But with keepalive, it can be many requests. +-----------------------------------------------------------------------------*/ + TConn * const connectionP = userHandle; + struct _TServer * const srvP = connectionP->server->srvP; + + unsigned int requestCount; + /* Number of requests we've handled so far on this connection */ + abyss_bool connectionDone; + /* No more need for this HTTP connection */ + + requestCount = 0; + connectionDone = FALSE; + + while (!connectionDone) { + abyss_bool success; + + /* Wait to read until timeout */ + success = ConnRead(connectionP, srvP->keepalivetimeout); + + if (!success) + connectionDone = TRUE; + else { + abyss_bool const lastReqOnConn = + requestCount + 1 >= srvP->keepalivemaxconn; + + abyss_bool keepalive; + + processDataFromClient(connectionP, lastReqOnConn, &keepalive); + + ++requestCount; + + if (!keepalive) + connectionDone = TRUE; + + /**************** Must adjust the read buffer *****************/ + ConnReadInit(connectionP); + } + } +} + + + +static void +createAndBindSocket(struct _TServer * const srvP) { + + abyss_bool success; + + success = SocketInit(); + if (!success) + TraceMsg("Can't initialize TCP sockets"); + else { + TSocket * socketP; + + SocketUnixCreate(&socketP); + + if (!socketP) + TraceMsg("Can't create a socket"); + else { + abyss_bool success; + + success = SocketBind(socketP, NULL, srvP->port); + + if (!success) + TraceMsg("Failed to bind listening socket to port number %u", + srvP->port); + else { + srvP->weCreatedListenSocket = TRUE; + srvP->socketBound = TRUE; + srvP->listenSocketP = socketP; + } + if (!success) + SocketDestroy(socketP); + } + } +} + + + +void +ServerInit(TServer * const serverP) { +/*---------------------------------------------------------------------------- + Initialize a server to accept connections. + + Do not confuse this with creating the server -- ServerCreate(). + + Not necessary or valid with a server that doesn't accept connections (i.e. + user supplies the TCP connections). +-----------------------------------------------------------------------------*/ + struct _TServer * const srvP = serverP->srvP; + abyss_bool success; + + if (!srvP->serverAcceptsConnections) { + TraceMsg("ServerInit() is not valid on a server that doesn't " + "accept connections " + "(i.e. created with ServerCreateNoAccept)"); + success = FALSE; + } else { + if (!srvP->socketBound) + createAndBindSocket(srvP); + + if (srvP->socketBound) { + success = SocketListen(srvP->listenSocketP, MAX_CONN); + + if (!success) + TraceMsg("Failed to listen on bound socket."); + } else + success = FALSE; + } + if (!success) + exit(1); +} + + + +/* We don't do any locking on the outstanding connections list, so + we must make sure that only the master thread (the one that listens + for connections) ever accesses it. + + That's why when a thread completes, it places the connection in + "finished" status, but doesn't destroy the connection. +*/ + +typedef struct { + + TConn * firstP; + unsigned int count; + /* Redundant with 'firstP', for quick access */ +} outstandingConnList; + + + +static void +createOutstandingConnList(outstandingConnList ** const listPP) { + + outstandingConnList * listP; + + MALLOCVAR_NOFAIL(listP); + + listP->firstP = NULL; /* empty list */ + listP->count = 0; + + *listPP = listP; +} + + + +static void +destroyOutstandingConnList(outstandingConnList * const listP) { + + assert(listP->firstP == NULL); + assert(listP->count == 0); + + free(listP); +} + + + +static void +addToOutstandingConnList(outstandingConnList * const listP, + TConn * const connectionP) { + + connectionP->nextOutstandingP = listP->firstP; + + listP->firstP = connectionP; + + ++listP->count; +} + + + +static void +freeFinishedConns(outstandingConnList * const listP) { +/*---------------------------------------------------------------------------- + Garbage-collect the resources associated with connections that are + finished with their jobs. Thread resources, connection pool + descriptor, etc. +-----------------------------------------------------------------------------*/ + TConn ** pp; + + pp = &listP->firstP; + + while (*pp) { + TConn * const connectionP = (*pp); + + ThreadUpdateStatus(connectionP->threadP); + + if (connectionP->finished) { + /* Take it out of the list */ + *pp = connectionP->nextOutstandingP; + --listP->count; + + ConnWaitAndRelease(connectionP); + } else { + /* Move to next connection in list */ + pp = &connectionP->nextOutstandingP; + } + } +} + + + +static void +waitForConnectionFreed(outstandingConnList * const outstandingConnListP + ATTR_UNUSED) { +/*---------------------------------------------------------------------------- + Wait for a connection descriptor in 'connectionPool' to be probably + freed. +-----------------------------------------------------------------------------*/ + + /* TODO: We should do something more sophisticated here. For pthreads, + we can have a thread signal us by semaphore when it terminates. + For fork, we might be able to use the "done" handler argument + to ConnCreate() to get interrupted when the death of a child + signal happens. + */ + + xmlrpc_millisecond_sleep(2000); +} + + + +static void +waitForNoConnections(outstandingConnList * const outstandingConnListP) { + + while (outstandingConnListP->firstP) { + freeFinishedConns(outstandingConnListP); + + if (outstandingConnListP->firstP) + waitForConnectionFreed(outstandingConnListP); + } +} + + + +static void +waitForConnectionCapacity(outstandingConnList * const outstandingConnListP) { +/*---------------------------------------------------------------------------- + Wait until there are fewer than the maximum allowed connections in + progress. +-----------------------------------------------------------------------------*/ + while (outstandingConnListP->count >= MAX_CONN) { + freeFinishedConns(outstandingConnListP); + if (outstandingConnListP->firstP) + waitForConnectionFreed(outstandingConnListP); + } +} + + + +#ifndef WIN32 +void +ServerHandleSigchld(pid_t const pid) { + + ThreadHandleSigchld(pid); +} +#endif + + + +void +ServerUseSigchld(TServer * const serverP) { + + struct _TServer * const srvP = serverP->srvP; + + srvP->useSigchld = TRUE; +} + + + +TThreadDoneFn destroySocket; + +static void +destroyConnSocket(void * const userHandle) { +/*---------------------------------------------------------------------------- + This is a "connection done" function for the connection the server + serves. It gets called some time after the connection has done its + thing. Its job is to clean up stuff the server created for use by + the connection, but the server can't clean up because the + connection might be processed asynchronously in a background + thread. + + To wit, we destroy the connection's socket. +-----------------------------------------------------------------------------*/ + TConn * const connectionP = userHandle; + + SocketDestroy(connectionP->socketP); +} + + + +static void +serverRun2(TServer * const serverP) { + + struct _TServer * const srvP = serverP->srvP; + outstandingConnList * outstandingConnListP; + + createOutstandingConnList(&outstandingConnListP); + + while (!srvP->terminationRequested) { + TConn * connectionP; + + abyss_bool connected; + abyss_bool failed; + TSocket * connectedSocketP; + TIPAddr peerIpAddr; + + SocketAccept(srvP->listenSocketP, + &connected, &failed, + &connectedSocketP, &peerIpAddr); + + if (connected) { + const char * error; + + freeFinishedConns(outstandingConnListP); + + waitForConnectionCapacity(outstandingConnListP); + + ConnCreate(&connectionP, serverP, connectedSocketP, + &serverFunc, &destroyConnSocket, ABYSS_BACKGROUND, + srvP->useSigchld, + &error); + if (!error) { + addToOutstandingConnList(outstandingConnListP, connectionP); + ConnProcess(connectionP); + /* When connection is done (which could be later, courtesy + of a background thread), destroyConnSocket() will + destroy *connectedSocketP. + */ + } else { + xmlrpc_strfree(error); + SocketDestroy(connectedSocketP); + } + } else if (failed) + TraceMsg("Socket Error=%d", SocketError(srvP->listenSocketP)); + } + waitForNoConnections(outstandingConnListP); + + destroyOutstandingConnList(outstandingConnListP); +} + + + +void +ServerRun(TServer * const serverP) { + + struct _TServer * const srvP = serverP->srvP; + + if (!srvP->socketBound) + TraceMsg("This server is not set up to accept connections " + "on its own, so you can't use ServerRun(). " + "Try ServerRunConn() or ServerInit()"); + else + serverRun2(serverP); +} + + + +static void +serverRunConn(TServer * const serverP, + TSocket * const connectedSocketP) { +/*---------------------------------------------------------------------------- + Do the HTTP transaction on the TCP connection on the socket + 'connectedSocketP'. + (socket must be in connected state, with nothing having been read or + written on the connection yet). +-----------------------------------------------------------------------------*/ + struct _TServer * const srvP = serverP->srvP; + + TConn * connectionP; + const char * error; + + srvP->keepalivemaxconn = 1; + + ConnCreate(&connectionP, + serverP, connectedSocketP, + &serverFunc, NULL, ABYSS_FOREGROUND, srvP->useSigchld, + &error); + if (error) { + TraceMsg("Couldn't create HTTP connection out of " + "connected socket. %s", error); + xmlrpc_strfree(error); + } else { + ConnProcess(connectionP); + + ConnWaitAndRelease(connectionP); + } +} + + + +void +ServerRunConn2(TServer * const serverP, + TSocket * const connectedSocketP, + const char ** const errorP) { +/*---------------------------------------------------------------------------- + Do the HTTP transaction on the TCP connection on the socket + 'connectedOsSocket'. + (socket must be connected state, with nothing having been read or + written on the connection yet). +-----------------------------------------------------------------------------*/ + struct _TServer * const srvP = serverP->srvP; + + if (srvP->serverAcceptsConnections) + xmlrpc_asprintf(errorP, + "This server is configured to accept connections on " + "its own socket. " + "Try ServerRun() or ServerCreateNoAccept()."); + else { + serverRunConn(serverP, connectedSocketP); + *errorP = NULL; + } +} + + + +void +ServerRunConn(TServer * const serverP, + TOsSocket const connectedOsSocket) { + + TSocket * socketP; + createSocketFromOsSocket(connectedOsSocket, &socketP); + if (!socketP) + TraceExit("Unable to use supplied socket"); + else { + const char * error; + + ServerRunConn2(serverP, socketP, &error); + + if (error) { + TraceExit("Failed to run server on connection on file " + "descriptor %d. %s", connectedOsSocket, error); + xmlrpc_strfree(error); + } + SocketDestroy(socketP); + } +} + + + +void +ServerRunOnce(TServer * const serverP) { +/*---------------------------------------------------------------------------- + Accept a connection from the listening socket and do the HTTP + transaction that comes over it. + + If no connection is presently waiting on the listening socket, wait + for one. But return immediately if we receive a signal during the + wait. +-----------------------------------------------------------------------------*/ + struct _TServer * const srvP = serverP->srvP; + + if (!srvP->socketBound) + TraceMsg("This server is not set up to accept connections " + "on its own, so you can't use ServerRunOnce(). " + "Try ServerRunConn() or ServerInit()"); + else { + abyss_bool connected; + abyss_bool failed; + TSocket * connectedSocketP; + TIPAddr remoteAddr; + + srvP->keepalivemaxconn = 1; + + SocketAccept(srvP->listenSocketP, + &connected, &failed, + &connectedSocketP, &remoteAddr); + if (connected) { + serverRunConn(serverP, connectedSocketP); + SocketDestroy(connectedSocketP); + } else if (failed) + TraceMsg("Socket Error=%d", SocketError(srvP->listenSocketP)); + } +} + + + +void +ServerRunOnce2(TServer * const serverP, + enum abyss_foreback const foregroundBackground ATTR_UNUSED) { +/*---------------------------------------------------------------------------- + This is a backward compatibility interface to ServerRunOnce(). + + 'foregroundBackground' is meaningless. We always process the + connection in the foreground. The parameter exists because we once + thought we could do them in the background, but we really can't do + that in any clean way. If Caller wants background execution, he can + spin his own thread or process to call us. It makes much more sense + in Caller's context. +-----------------------------------------------------------------------------*/ + ServerRunOnce(serverP); +} + + + +static void +setGroups(void) { + +#ifdef HAVE_SETGROUPS + if (setgroups(0, NULL) == (-1)) + TraceExit("Failed to setup the group."); +#endif +} + + + +void +ServerDaemonize(TServer * const serverP) { +/*---------------------------------------------------------------------------- + Turn Caller into a daemon (i.e. fork a child, then exit; the child + returns to Caller). + + NOTE: It's ridiculous, but conventional, for us to do this. It's + ridiculous because the task of daemonizing is not something + particular to Abyss. It ought to be done by a higher level. In + fact, it should be done before the Abyss server program is even + execed. The user should run a "daemonize" program that creates a + daemon which execs the Abyss server program. +-----------------------------------------------------------------------------*/ + struct _TServer * const srvP = serverP->srvP; + +#ifndef _WIN32 + /* Become a daemon */ + switch (fork()) { + case 0: + break; + case -1: + TraceExit("Unable to become a daemon"); + default: + /* We are the parent */ + exit(0); + } + + setsid(); + + /* Change the current user if we are root */ + if (getuid()==0) { + if (srvP->uid == (uid_t)-1) + TraceExit("Can't run under root privileges. " + "Please add a User option in your " + "Abyss configuration file."); + + setGroups(); + + if (srvP->gid != (gid_t)-1) + if (setgid(srvP->gid)==(-1)) + TraceExit("Failed to change the group."); + + if (setuid(srvP->uid) == -1) + TraceExit("Failed to change the user."); + } + + if (srvP->pidfile != -1) { + char z[16]; + + sprintf(z, "%d", getpid()); + FileWrite(&srvP->pidfile, z, strlen(z)); + FileClose(&srvP->pidfile); + } +#endif /* _WIN32 */ +} + + + +void +ServerAddHandler2(TServer * const serverP, + URIHandler2 * const handlerArgP, + abyss_bool * const successP) { + + URIHandler2 * handlerP; + + MALLOCVAR(handlerP); + if (handlerP == NULL) + *successP = FALSE; + else { + *handlerP = *handlerArgP; + + if (handlerP->init == NULL) + *successP = TRUE; + else + handlerP->init(handlerP, successP); + + if (*successP) + *successP = ListAdd(&serverP->srvP->handlers, handlerP); + + if (!*successP) + free(handlerP); + } +} + + + +static URIHandler2 * +createHandler(URIHandler const function) { + + URIHandler2 * handlerP; + + MALLOCVAR(handlerP); + if (handlerP != NULL) { + handlerP->init = NULL; + handlerP->term = NULL; + handlerP->userdata = NULL; + handlerP->handleReq2 = NULL; + handlerP->handleReq1 = function; + } + return handlerP; +} + + + +abyss_bool +ServerAddHandler(TServer * const serverP, + URIHandler const function) { + + URIHandler2 * handlerP; + abyss_bool success; + + handlerP = createHandler(function); + + if (handlerP == NULL) + success = FALSE; + else { + success = ListAdd(&serverP->srvP->handlers, handlerP); + + if (!success) + free(handlerP); + } + return success; +} + + + +void +ServerDefaultHandler(TServer * const serverP, + URIHandler const handler) { + + serverP->srvP->defaulthandler = + handler ? handler : ServerDefaultHandlerFunc; +} + + + +void +LogWrite(TServer * const serverP, + const char * const msg) { + + struct _TServer * const srvP = serverP->srvP; + + if (!srvP->logfileisopen && srvP->logfilename) + logOpen(srvP); + + if (srvP->logfileisopen) { + abyss_bool success; + success = MutexLock(&srvP->logmutex); + if (success) { + const char * const lbr = "\n"; + FileWrite(&srvP->logfile, msg, strlen(msg)); + FileWrite(&srvP->logfile, lbr, strlen(lbr)); + + MutexUnlock(&srvP->logmutex); + } + } +} +/******************************************************************************* +** +** server.c +** +** This file is part of the ABYSS Web server project. +** +** Copyright (C) 2000 by Moez Mahfoudh . +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +** ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +** OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +** HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +** LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +** OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +** SUCH DAMAGE. +** +******************************************************************************/ diff --git a/lib/abyss/src/server.h b/lib/abyss/src/server.h new file mode 100644 index 0000000..db8bc79 --- /dev/null +++ b/lib/abyss/src/server.h @@ -0,0 +1,78 @@ +#ifndef SERVER_H_INCLUDED +#define SERVER_H_INCLUDED + +#include + +#include "xmlrpc-c/abyss.h" + +#include "file.h" +#include "data.h" + +typedef struct _Tsocket Tsocket; + +struct _TServer { + abyss_bool terminationRequested; + /* User wants this server to terminate as soon as possible, + in particular before accepting any more connections and without + waiting for any. + */ + abyss_bool socketBound; + /* The listening socket exists and is bound to a local address + (may already be listening as well) + */ + TSocket * listenSocketP; + /* Meaningful only when 'socketBound' is true: file descriptor of + the listening socket ("listening socket" means socket for listening, + not a socket that is listening right now). + */ + abyss_bool weCreatedListenSocket; + /* We created the listen socket (whose fd is 'listensock'), as + opposed to 1) User supplied it; or 2) there isn't one. + */ + const char * logfilename; + abyss_bool logfileisopen; + TFile logfile; + TMutex logmutex; + const char * name; + const char * filespath; + abyss_bool serverAcceptsConnections; + /* We listen for and accept TCP connections for HTTP transactions. + (The alternative is the user supplies a TCP-connected socket + for each transaction) + */ + uint16_t port; + /* Meaningful only when 'socketBound' is false: port number to which + we should bind the listening socket + */ + uint32_t keepalivetimeout; + uint32_t keepalivemaxconn; + uint32_t timeout; + /* Maximum time in seconds the server will wait to read a header + or a data chunk from the socket. + */ + TList handlers; + TList defaultfilenames; + void * defaulthandler; + abyss_bool advertise; + MIMEType * mimeTypeP; + /* NULL means to use the global MIMEType object */ + abyss_bool useSigchld; + /* Meaningless if not using forking for threads. + TRUE means user will call ServerHandleSigchld to indicate that + a SIGCHLD signal was received, and server shall use that as its + indication that a child has died. FALSE means server will not + be aware of SIGCHLD and will instead poll for existence of PIDs + to determine if a child has died. + */ +#ifndef WIN32 + uid_t uid; + gid_t gid; + TFile pidfile; +#endif +}; + + +void +ServerBackgroundProcessComplete(pid_t const pid); + +#endif diff --git a/lib/abyss/src/session.c b/lib/abyss/src/session.c new file mode 100644 index 0000000..093ea7a --- /dev/null +++ b/lib/abyss/src/session.c @@ -0,0 +1,137 @@ +#include +#include +#include +#include + +#include "xmlrpc-c/util_int.h" +#include "xmlrpc-c/string_int.h" +#include "xmlrpc-c/abyss.h" +#include "server.h" +#include "http.h" +#include "conn.h" + +#include "session.h" + + + +abyss_bool +SessionRefillBuffer(TSession * const sessionP) { +/*---------------------------------------------------------------------------- + Get the next chunk of HTTP request body from the connection into + the buffer. + + I.e. read data from the socket. +-----------------------------------------------------------------------------*/ + struct _TServer * const srvP = sessionP->conn->server->srvP; + abyss_bool failed; + + failed = FALSE; /* initial value */ + + /* Reset our read buffer & flush data from previous reads. */ + ConnReadInit(sessionP->conn); + + if (sessionP->continueRequired) + failed = !HTTPWriteContinue(sessionP); + + if (!failed) { + sessionP->continueRequired = FALSE; + + /* Read more network data into our buffer. If we encounter a + timeout, exit immediately. We're very forgiving about the + timeout here. We allow a full timeout per network read, which + would allow somebody to keep a connection alive nearly + indefinitely. But it's hard to do anything intelligent here + without very complicated code. + */ + failed = !ConnRead(sessionP->conn, srvP->timeout); + } + return !failed; +} + + + +size_t +SessionReadDataAvail(TSession * const sessionP) { + + return sessionP->conn->buffersize - sessionP->conn->bufferpos; + +} + + + +void +SessionGetReadData(TSession * const sessionP, + size_t const max, + const char ** const outStartP, + size_t * const outLenP) { +/*---------------------------------------------------------------------------- + Extract some HTTP request body which the server has read and + buffered for the session. Don't get or wait for any data that has + not yet arrived. Do not return more than 'max'. + + We return a pointer to the first byte as *outStartP, and the length in + bytes as *outLenP. The memory pointed to belongs to the session. +-----------------------------------------------------------------------------*/ + uint32_t const bufferPos = sessionP->conn->bufferpos; + + *outStartP = &sessionP->conn->buffer[bufferPos]; + + assert(bufferPos <= sessionP->conn->buffersize); + + *outLenP = MIN(max, sessionP->conn->buffersize - bufferPos); + + /* move pointer past the bytes we are returning */ + sessionP->conn->bufferpos += *outLenP; + + assert(sessionP->conn->bufferpos <= sessionP->conn->buffersize); +} + + + +void +SessionGetRequestInfo(TSession * const sessionP, + const TRequestInfo ** const requestInfoPP) { + + *requestInfoPP = &sessionP->request_info; +} + + + +abyss_bool +SessionLog(TSession * const sessionP) { + + abyss_bool retval; + + if (!sessionP->validRequest) + retval = FALSE; + else { + const char * const user = sessionP->request_info.user; + + const char * logline; + char date[30]; + + DateToLogString(&sessionP->date, date); + + xmlrpc_asprintf(&logline, "%d.%d.%d.%d - %s - [%s] \"%s\" %d %d", + IPB1(sessionP->conn->peerip), + IPB2(sessionP->conn->peerip), + IPB3(sessionP->conn->peerip), + IPB4(sessionP->conn->peerip), + user ? user : "", + date, + sessionP->request_info.requestline, + sessionP->status, + sessionP->conn->outbytes + ); + if (logline) { + LogWrite(sessionP->conn->server, logline); + + xmlrpc_strfree(logline); + } + retval = TRUE; + } + return retval; +} + + + diff --git a/lib/abyss/src/session.h b/lib/abyss/src/session.h new file mode 100644 index 0000000..43a5616 --- /dev/null +++ b/lib/abyss/src/session.h @@ -0,0 +1,60 @@ +#ifndef SESSION_H_INCLUDED +#define SESSION_H_INCLUDED + +#include "xmlrpc-c/abyss.h" +#include "date.h" +#include "data.h" + +typedef struct { + uint8_t major; + uint8_t minor; +} httpVersion; + +struct _TSession { + abyss_bool validRequest; + /* Client has sent, and server has recognized, a valid HTTP request. + This is false when the session is new. If and when the server + reads the request from the client and finds it to be valid HTTP, + it becomes true. + */ + TRequestInfo request_info; + uint32_t nbfileds; + TList cookies; + TList ranges; + + uint16_t status; + /* Response status from handler. Zero means handler has not + set it. + */ + TString header; + + abyss_bool serverDeniesKeepalive; + /* Server doesn't want keepalive for this session, regardless of + what happens in the session. E.g. because the connection has + already been kept alive long enough. + */ + abyss_bool responseStarted; + /* Handler has at least started the response (i.e. called + ResponseWrite()) + */ + + struct _TConn * conn; + + httpVersion version; + + TTable request_headers; + TTable response_headers; + + TDate date; + + abyss_bool chunkedwrite; + abyss_bool chunkedwritemode; + + abyss_bool continueRequired; + /* This client must receive 100 (continue) status before it will + send more of the body of the request. + */ +}; + + +#endif diff --git a/lib/abyss/src/socket.c b/lib/abyss/src/socket.c new file mode 100644 index 0000000..7868542 --- /dev/null +++ b/lib/abyss/src/socket.c @@ -0,0 +1,230 @@ +/*============================================================================ + socket.c +============================================================================== + Implementation of TSocket class: A generic socket over which one can + transport an HTTP stream or manage HTTP connections +============================================================================*/ + +#include +#include +#include +#include +#include +#include + +#include "mallocvar.h" +#include "xmlrpc-c/util_int.h" +#include "xmlrpc-c/abyss.h" +#include "xmlrpc-c/util_int.h" +#ifdef WIN32 + #include "socket_win.h" +#else + #include "socket_unix.h" +#endif +#include "socket.h" + + +#ifdef WIN32 + #include "socket_win.h" +#else + #include "socket_unix.h" +#endif + +#include "socket.h" + + +static void +socketOsInit(abyss_bool * const succeededP) { + +#ifdef WIN32 + SocketWinInit(succeededP); +#else + SocketUnixInit(succeededP); +#endif +} + + + +static void +socketOsTerm(void) { + +#ifdef WIN32 + SocketWinTerm(); +#else + SocketUnixTerm(); +#endif +} + + + +abyss_bool SocketTraceIsActive; + +abyss_bool +SocketInit(void) { + abyss_bool retval; + + socketOsInit(&retval); + + SocketTraceIsActive = (getenv("ABYSS_TRACE_SOCKET") != NULL); + if (SocketTraceIsActive) + fprintf(stderr, "Abyss socket layer will trace socket traffic " + "due to ABYSS_TRACE_SOCKET environment variable\n"); + + return retval; +} + + + +void +SocketTerm(void) { + + socketOsTerm(); +} + + + +/* SocketCreate() is not exported to the Abyss user. It is meant to + be used by an implementation-specific TSocket generator which is + exported to the Abyss user, e.g. SocketCreateUnix() in + socket_unix.c + + The TSocket generator functions are the _only_ user-accessible + functions that are particular to an implementation. +*/ + +static uint const socketSignature = 0x060609; + +void +SocketCreate(const struct TSocketVtbl * const vtblP, + void * const implP, + TSocket ** const socketPP) { + + TSocket * socketP; + + MALLOCVAR(socketP); + + if (socketP) { + socketP->implP = implP; + socketP->vtbl = *vtblP; + socketP->signature = socketSignature; + *socketPP = socketP; + } +} + + + +void +SocketDestroy(TSocket * const socketP) { + + assert(socketP->signature == socketSignature); + + socketP->vtbl.destroy(socketP); + + socketP->signature = 0; /* For debuggability */ + + free(socketP); +} + + + +void +SocketWrite(TSocket * const socketP, + const unsigned char * const buffer, + uint32_t const len, + abyss_bool * const failedP) { + + (*socketP->vtbl.write)(socketP, buffer, len, failedP ); +} + + + +uint32_t +SocketRead(TSocket * const socketP, + unsigned char * const buffer, + uint32_t const len) { + + return (*socketP->vtbl.read)(socketP, buffer, len); +} + + + +abyss_bool +SocketConnect(TSocket * const socketP, + TIPAddr * const addrP, + uint16_t const portNumber) { + + return (*socketP->vtbl.connect)(socketP, addrP, portNumber); +} + + + +abyss_bool +SocketBind(TSocket * const socketP, + TIPAddr * const addrP, + uint16_t const portNumber) { + + return (*socketP->vtbl.bind)(socketP, addrP, portNumber); +} + + + +abyss_bool +SocketListen(TSocket * const socketP, + uint32_t const backlog) { + + return (*socketP->vtbl.listen)(socketP, backlog); +} + + + +void +SocketAccept(TSocket * const listenSocketP, + abyss_bool * const connectedP, + abyss_bool * const failedP, + TSocket ** const acceptedSocketPP, + TIPAddr * const ipAddrP) { + + (*listenSocketP->vtbl.accept)(listenSocketP, + connectedP, + failedP, + acceptedSocketPP, + ipAddrP); +} + + + +uint32_t +SocketWait(TSocket * const socketP, + abyss_bool const rd, + abyss_bool const wr, + uint32_t const timems) { + + return (*socketP->vtbl.wait)(socketP, rd, wr, timems); +} + + + +uint32_t +SocketAvailableReadBytes(TSocket * const socketP) { + + return (*socketP->vtbl.availableReadBytes)(socketP); +} + + + +void +SocketGetPeerName(TSocket * const socketP, + TIPAddr * const ipAddrP, + uint16_t * const portNumberP, + abyss_bool * const successP) { + + (*socketP->vtbl.getPeerName)(socketP, ipAddrP, portNumberP, successP); +} + + + +uint32_t +SocketError(TSocket * const socketP) { + + return (*socketP->vtbl.error)(socketP); +} diff --git a/lib/abyss/src/socket.h b/lib/abyss/src/socket.h new file mode 100644 index 0000000..fd8c4b8 --- /dev/null +++ b/lib/abyss/src/socket.h @@ -0,0 +1,149 @@ +#ifndef SOCKET_H_INCLUDED +#define SOCKET_H_INCLUDED + +#include + +#include "xmlrpc-c/abyss.h" + +#include + +#define IPB1(x) (((unsigned char *)(&x))[0]) +#define IPB2(x) (((unsigned char *)(&x))[1]) +#define IPB3(x) (((unsigned char *)(&x))[2]) +#define IPB4(x) (((unsigned char *)(&x))[3]) + +typedef struct in_addr TIPAddr; + +typedef void SocketDestroyImpl(TSocket * const socketP); + +typedef void SocketWriteImpl(TSocket * const socketP, + const unsigned char * const buffer, + uint32_t const len, + abyss_bool * const failedP); + +typedef uint32_t SocketReadImpl(TSocket * const socketP, + char * const buffer, + uint32_t const len); + +typedef abyss_bool SocketConnectImpl(TSocket * const socketP, + TIPAddr * const addrP, + uint16_t const portNumber); + +typedef abyss_bool SocketBindImpl(TSocket * const socketP, + TIPAddr * const addrP, + uint16_t const portNumber); + +typedef abyss_bool SocketListenImpl(TSocket * const socketP, + uint32_t const backlog); + +typedef void SocketAcceptImpl(TSocket * const listenSocketP, + abyss_bool * const connectedP, + abyss_bool * const failedP, + TSocket ** const acceptedSocketPP, + TIPAddr * const ipAddrP); + +typedef uint32_t SocketErrorImpl(TSocket * const socketP); + +typedef uint32_t SocketWaitImpl(TSocket * const socketP, + abyss_bool const rd, + abyss_bool const wr, + uint32_t const timems); + +typedef uint32_t SocketAvailableReadBytesImpl(TSocket * const socketP); + +typedef void SocketGetPeerNameImpl(TSocket * const socketP, + TIPAddr * const ipAddrP, + uint16_t * const portNumberP, + abyss_bool * const successP); + +struct TSocketVtbl { + SocketDestroyImpl * destroy; + SocketWriteImpl * write; + SocketReadImpl * read; + SocketConnectImpl * connect; + SocketBindImpl * bind; + SocketListenImpl * listen; + SocketAcceptImpl * accept; + SocketErrorImpl * error; + SocketWaitImpl * wait; + SocketAvailableReadBytesImpl * availableReadBytes; + SocketGetPeerNameImpl * getPeerName; +}; + +struct _TSocket { + uint signature; + /* With both background and foreground use of sockets, and + background being both fork and pthread, it is very easy to + screw up socket lifetime and try to destroy twice. We use + this signature to help catch such bugs. + */ + void * implP; + struct TSocketVtbl vtbl; +}; + +#define TIME_INFINITE 0xffffffff + +extern abyss_bool SocketTraceIsActive; + +abyss_bool +SocketInit(void); + +void +SocketTerm(void); + +void +SocketCreate(const struct TSocketVtbl * const vtblP, + void * const implP, + TSocket ** const socketPP); + +void +SocketWrite(TSocket * const socketP, + const unsigned char * const buffer, + uint32_t const len, + abyss_bool * const failedP); + +uint32_t +SocketRead(TSocket * const socketP, + unsigned char * const buffer, + uint32_t const len); + +abyss_bool +SocketConnect(TSocket * const socketP, + TIPAddr * const addrP, + uint16_t const portNumber); + +abyss_bool +SocketBind(TSocket * const socketP, + TIPAddr * const addrP, + uint16_t const portNumber); + +abyss_bool +SocketListen(TSocket * const socketP, + uint32_t const backlog); + +void +SocketAccept(TSocket * const listenSocketP, + abyss_bool * const connectedP, + abyss_bool * const failedP, + TSocket ** const acceptedSocketP, + TIPAddr * const ipAddrP); + +uint32_t +SocketWait(TSocket * const socketP, + abyss_bool const rd, + abyss_bool const wr, + uint32_t const timems); + +uint32_t +SocketAvailableReadBytes(TSocket * const socketP); + +void +SocketGetPeerName(TSocket * const socketP, + TIPAddr * const ipAddrP, + uint16_t * const portNumberP, + abyss_bool * const successP); + +uint32_t +SocketError(TSocket * const socketP); + +#endif diff --git a/lib/abyss/src/socket_unix.c b/lib/abyss/src/socket_unix.c new file mode 100644 index 0000000..3f425c9 --- /dev/null +++ b/lib/abyss/src/socket_unix.c @@ -0,0 +1,501 @@ +/*============================================================================= + socket_unix.c +=============================================================================== + This is the implementation of TSocket for a standard Unix (POSIX) + stream socket -- what you create with a socket() C library call. +=============================================================================*/ + +#include "xmlrpc_config.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if HAVE_SYS_FILIO_H + #include +#endif +#if HAVE_SYS_IOCTL_H + #include +#endif + +#include "xmlrpc-c/util_int.h" +#include "mallocvar.h" +#include "trace.h" +#include "socket.h" +#include "xmlrpc-c/abyss.h" + +#include "socket_unix.h" + + + +struct socketUnix { +/*---------------------------------------------------------------------------- + The properties/state of a TSocket unique to a Unix TSocket. +-----------------------------------------------------------------------------*/ + int fd; + /* File descriptor of the POSIX socket (such as is created by + socket() in the C library) on which the TSocket is based. + */ + abyss_bool userSuppliedFd; + /* The file descriptor and associated POSIX socket belong to the + user; we did not create it. + */ +}; + + +void +SocketUnixInit(abyss_bool * const succeededP) { + + *succeededP = TRUE; +} + + + +void +SocketUnixTerm(void) { + +} + + + +static SocketDestroyImpl socketDestroy; +static SocketWriteImpl socketWrite; +static SocketReadImpl socketRead; +static SocketConnectImpl socketConnect; +static SocketBindImpl socketBind; +static SocketListenImpl socketListen; +static SocketAcceptImpl socketAccept; +static SocketErrorImpl socketError; +static SocketWaitImpl socketWait; +static SocketAvailableReadBytesImpl socketAvailableReadBytes; +static SocketGetPeerNameImpl socketGetPeerName; + + +static struct TSocketVtbl const vtbl = { + &socketDestroy, + &socketWrite, + &socketRead, + &socketConnect, + &socketBind, + &socketListen, + &socketAccept, + &socketError, + &socketWait, + &socketAvailableReadBytes, + &socketGetPeerName +}; + + + +void +SocketUnixCreate(TSocket ** const socketPP) { + + struct socketUnix * socketUnixP; + + MALLOCVAR(socketUnixP); + + if (socketUnixP) { + int rc; + rc = socket(AF_INET, SOCK_STREAM, 0); + if (rc < 0) + *socketPP = NULL; + else { + socketUnixP->fd = rc; + socketUnixP->userSuppliedFd = FALSE; + + { + int32_t n = 1; + int rc; + rc = setsockopt(socketUnixP->fd, SOL_SOCKET, SO_REUSEADDR, + (char*)&n, sizeof(n)); + if (rc < 0) + *socketPP = NULL; + else + SocketCreate(&vtbl, socketUnixP, socketPP); + } + if (!*socketPP) + close(socketUnixP->fd); + } + if (!*socketPP) + free(socketUnixP); + } else + *socketPP = NULL; +} + + + +void +SocketUnixCreateFd(int const fd, + TSocket ** const socketPP) { + + struct socketUnix * socketUnixP; + + MALLOCVAR(socketUnixP); + + if (socketUnixP) { + socketUnixP->fd = fd; + socketUnixP->userSuppliedFd = TRUE; + + SocketCreate(&vtbl, socketUnixP, socketPP); + + if (!*socketPP) + free(socketUnixP); + } else + *socketPP = NULL; +} + + + +static void +socketDestroy(TSocket * const socketP) { + + struct socketUnix * const socketUnixP = socketP->implP; + + if (!socketUnixP->userSuppliedFd) + close(socketUnixP->fd); + + free(socketUnixP); +} + + + +static void +socketWrite(TSocket * const socketP, + const unsigned char * const buffer, + uint32_t const len, + abyss_bool * const failedP) { + + struct socketUnix * const socketUnixP = socketP->implP; + + size_t bytesLeft; + abyss_bool error; + + assert(sizeof(size_t) >= sizeof(len)); + + for (bytesLeft = len, error = FALSE; + bytesLeft > 0 && !error; + ) { + size_t const maxSend = (size_t)(-1) >> 1; + + ssize_t rc; + + rc = send(socketUnixP->fd, &buffer[len-bytesLeft], + MIN(maxSend, bytesLeft), 0); + + if (SocketTraceIsActive) { + if (rc < 0) + fprintf(stderr, "Abyss socket: send() failed. errno=%d (%s)", + errno, strerror(errno)); + else if (rc == 0) + fprintf(stderr, "Abyss socket: send() failed. " + "Socket closed.\n"); + else + fprintf(stderr, "Abyss socket: sent %u bytes: '%.*s'\n", + rc, rc, &buffer[len-bytesLeft]); + } + if (rc <= 0) + /* 0 means connection closed; < 0 means severe error */ + error = TRUE; + else + bytesLeft -= rc; + } + *failedP = error; +} + + + +static uint32_t +socketRead(TSocket * const socketP, + char * const buffer, + uint32_t const len) { + + struct socketUnix * const socketUnixP = socketP->implP; + + int rc; + rc = recv(socketUnixP->fd, buffer, len, 0); + if (SocketTraceIsActive) { + if (rc < 0) + fprintf(stderr, "Abyss socket: recv() failed. errno=%d (%s)", + errno, strerror(errno)); + else + fprintf(stderr, "Abyss socket: read %u bytes: '%.*s'\n", + len, (int)len, buffer); + } + return rc; +} + + + +abyss_bool +socketConnect(TSocket * const socketP, + TIPAddr * const addrP, + uint16_t const portNumber) { + + struct socketUnix * const socketUnixP = socketP->implP; + + struct sockaddr_in name; + int rc; + + name.sin_family = AF_INET; + name.sin_port = htons(portNumber); + name.sin_addr = *addrP; + + rc = connect(socketUnixP->fd, (struct sockaddr *)&name, sizeof(name)); + + return rc != -1; +} + + + +abyss_bool +socketBind(TSocket * const socketP, + TIPAddr * const addrP, + uint16_t const portNumber) { + + struct socketUnix * const socketUnixP = socketP->implP; + + struct sockaddr_in name; + int rc; + + name.sin_family = AF_INET; + name.sin_port = htons(portNumber); + if (addrP) + name.sin_addr = *addrP; + else + name.sin_addr.s_addr = INADDR_ANY; + + rc = bind(socketUnixP->fd, (struct sockaddr *)&name, sizeof(name)); + + return (rc != -1); +} + + + +abyss_bool +socketListen(TSocket * const socketP, + uint32_t const backlog) { + + struct socketUnix * const socketUnixP = socketP->implP; + + int32_t const minus1 = -1; + + int rc; + + /* Disable the Nagle algorithm to make persistant connections faster */ + + setsockopt(socketUnixP->fd, IPPROTO_TCP,TCP_NODELAY, + &minus1, sizeof(minus1)); + + rc = listen(socketUnixP->fd, backlog); + + return (rc != -1); +} + + + +static void +socketAccept(TSocket * const listenSocketP, + abyss_bool * const connectedP, + abyss_bool * const failedP, + TSocket ** const acceptedSocketPP, + TIPAddr * const ipAddrP) { +/*---------------------------------------------------------------------------- + Accept a connection on the listening socket 'listenSocketP'. Return as + *acceptedSocketPP the socket for the accepted connection. + + If no connection is waiting on 'listenSocketP', wait until one is. + + If we receive a signal while waiting, return immediately. + + Return *connectedP true iff we accepted a connection. Return + *failedP true iff we were unable to accept a connection for some + reason other than that we were interrupted. Return both false if + our wait for a connection was interrupted by a signal. +-----------------------------------------------------------------------------*/ + struct socketUnix * const listenSocketUnixP = listenSocketP->implP; + + abyss_bool connected, failed, interrupted; + + connected = FALSE; + failed = FALSE; + interrupted = FALSE; + + while (!connected && !failed && !interrupted) { + struct sockaddr_in sa; + socklen_t size = sizeof(sa); + int rc; + rc = accept(listenSocketUnixP->fd, (struct sockaddr *)&sa, &size); + if (rc >= 0) { + int const acceptedFd = rc; + struct socketUnix * acceptedSocketUnixP; + + MALLOCVAR(acceptedSocketUnixP); + + if (acceptedSocketUnixP) { + acceptedSocketUnixP->fd = acceptedFd; + acceptedSocketUnixP->userSuppliedFd = FALSE; + + SocketCreate(&vtbl, acceptedSocketUnixP, acceptedSocketPP); + if (!*acceptedSocketPP) + failed = TRUE; + else { + connected = TRUE; + *ipAddrP = sa.sin_addr; + } + if (failed) + free(acceptedSocketUnixP); + } else + failed = TRUE; + if (failed) + close(acceptedFd); + } else if (errno == EINTR) + interrupted = TRUE; + else + failed = TRUE; + } + *failedP = failed; + *connectedP = connected; +} + + + +static uint32_t +socketWait(TSocket * const socketP, + abyss_bool const rd, + abyss_bool const wr, + uint32_t const timems) { + + struct socketUnix * const socketUnixP = socketP->implP; + + fd_set rfds, wfds; + struct timeval tv; + + if (SocketTraceIsActive) + fprintf(stderr, "Waiting %u milliseconds for %s %s of socket\n", + timems, rd ? "READ" : "", wr ? "WRITE" : ""); + + FD_ZERO(&rfds); + FD_ZERO(&wfds); + + if (rd) + FD_SET(socketUnixP->fd, &rfds); + + if (wr) + FD_SET(socketUnixP->fd, &wfds); + + tv.tv_sec = timems / 1000; + tv.tv_usec = timems % 1000; + + for (;;) { + int rc; + + rc = select(socketUnixP->fd + 1, &rfds, &wfds, NULL, + (timems == TIME_INFINITE ? NULL : &tv)); + + switch(rc) { + case 0: /* time out */ + return 0; + + case -1: /* socket error */ + if (errno == EINTR) + break; + + return 0; + + default: + if (FD_ISSET(socketUnixP->fd, &rfds)) + return 1; + if (FD_ISSET(socketUnixP->fd, &wfds)) + return 2; + return 0; + } + } +} + + + +static uint32_t +socketAvailableReadBytes(TSocket * const socketP) { + + struct socketUnix * const socketUnixP = socketP->implP; + + uint32_t x; + int rc; + + rc = ioctl(socketUnixP->fd, FIONREAD, &x); + + if (SocketTraceIsActive) { + if (rc == 0) + fprintf(stderr, "Socket has %u bytes available\n", x); + else + fprintf(stderr, "ioctl(FIONREAD) failed, errno=%d (%s)\n", + errno, strerror(errno)); + } + return rc == 0 ? x : 0; +} + + + +static void +socketGetPeerName(TSocket * const socketP, + TIPAddr * const ipAddrP, + uint16_t * const portNumberP, + abyss_bool * const successP) { + + struct socketUnix * const socketUnixP = socketP->implP; + + socklen_t addrlen; + int rc; + struct sockaddr sockAddr; + + addrlen = sizeof(sockAddr); + + rc = getpeername(socketUnixP->fd, &sockAddr, &addrlen); + + if (rc < 0) { + TraceMsg("getpeername() failed. errno=%d (%s)", + errno, strerror(errno)); + *successP = FALSE; + } else { + if (addrlen != sizeof(sockAddr)) { + TraceMsg("getpeername() returned a socket address of the wrong " + "size: %u. Expected %u", addrlen, sizeof(sockAddr)); + *successP = FALSE; + } else { + if (sockAddr.sa_family != AF_INET) { + TraceMsg("Socket does not use the Inet (IP) address " + "family. Instead it uses family %d", + sockAddr.sa_family); + *successP = FALSE; + } else { + struct sockaddr_in * const sockAddrInP = (struct sockaddr_in *) + &sockAddr; + + *ipAddrP = sockAddrInP->sin_addr; + *portNumberP = sockAddrInP->sin_port; + + *successP = TRUE; + } + } + } +} + + + +static uint32_t +socketError(TSocket * const socketP) { + + if (socketP){} /* defeat compiler warning */ + + return errno; +} diff --git a/lib/abyss/src/socket_unix.h b/lib/abyss/src/socket_unix.h new file mode 100644 index 0000000..845a4fc --- /dev/null +++ b/lib/abyss/src/socket_unix.h @@ -0,0 +1,10 @@ +#ifndef SOCKET_UNIX_H_INCLUDED +#define SOCKET_UNIX_H_INCLUDED + +void +SocketUnixInit(abyss_bool * const succeededP); + +void +SocketUnixTerm(void); + +#endif diff --git a/lib/abyss/src/socket_win.c b/lib/abyss/src/socket_win.c new file mode 100644 index 0000000..058c322 --- /dev/null +++ b/lib/abyss/src/socket_win.c @@ -0,0 +1,456 @@ +/*============================================================================= + socket_win.c +=============================================================================== + This is the implementation of TSocket for a Windows Winsock socket. +=============================================================================*/ + +#include "xmlrpc_config.h" + +#include +#include +#include +#include +#include + +#include "xmlrpc-c/util_int.h" +#include "mallocvar.h" +#include "trace.h" + +#include "socket.h" + + +struct socketWin { +/*---------------------------------------------------------------------------- + The properties/state of a TSocket unique to a Unix TSocket. +-----------------------------------------------------------------------------*/ + SOCKET fd; + abyss_bool userSuppliedWinsock; + /* 'socket' was supplied by the user; it belongs to him */ +}; + + + +void +SocketWinInit(abyss_bool * const succeededP) { + + WORD wVersionRequested; + WSADATA wsaData; + int err; + + wVersionRequested = MAKEWORD(2, 0); + + err = WSAStartup(wVersionRequested, &wsaData); + *succeededP = (err == 0); +} + + + +void +SocketWinTerm(void) { + + WSACleanup(); +} + + + +static SocketDestroyImpl socketDestroy; +static SocketWriteImpl socketWrite; +static SocketReadImpl socketRead; +static SocketConnectImpl socketConnect; +static SocketBindImpl socketBind; +static SocketListenImpl socketListen; +static SocketAcceptImpl socketAccept; +static SocketErrorImpl socketError; +static SocketWaitImpl socketWait; +static SocketAvailableReadBytesImpl socketAvailableReadBytes; +static SocketGetPeerNameImpl socketGetPeerName; + + +static struct TSocketVtbl const vtbl = { + &socketDestroy, + &socketWrite, + &socketRead, + &socketConnect, + &socketBind, + &socketListen, + &socketAccept, + &socketError, + &socketWait, + &socketAvailableReadBytes, + &socketGetPeerName +}; + + + +void +SocketWinCreate(TSocket ** const socketPP) { + + struct socketWin * socketWinP; + + MALLOCVAR(socketWinP); + + if (socketWinP) { + SOCKET rc; + rc = socket(AF_INET, SOCK_STREAM, 0); + if (rc < 0) + *socketPP = NULL; + else { + socketWinP->fd = rc; + socketWinP->userSuppliedWinsock = FALSE; + + { + int32_t n = 1; + int rc; + rc = setsockopt(socketWinP->fd, SOL_SOCKET, SO_REUSEADDR, + (char*)&n, sizeof(n)); + if (rc < 0) + *socketPP = NULL; + else + SocketCreate(&vtbl, socketWinP, socketPP); + } + if (!*socketPP) + closesocket(socketWinP->fd); + } + if (!*socketPP) + free(socketWinP); + } else + *socketPP = NULL; +} + + + +void +SocketWinCreateWinsock(SOCKET const winsock, + TSocket ** const socketPP) { + + struct socketWin * socketWinP; + + MALLOCVAR(socketWinP); + + if (socketWinP) { + socketWinP->fd = winsock; + socketWinP->userSuppliedWinsock = TRUE; + + SocketCreate(&vtbl, socketWinP, socketPP); + + if (!*socketPP) + free(socketWinP); + } else + *socketPP = NULL; +} + + + +void +socketDestroy(TSocket * const socketP) { + + struct socketWin * const socketWinP = socketP->implP; + + if (!socketWinP->userSuppliedWinsock) + closesocket(socketWinP->fd); + + free(socketWinP); +} + + + +void +socketWrite(TSocket * const socketP, + const unsigned char * const buffer, + uint32_t const len, + abyss_bool * const failedP) { + + struct socketWin * const socketWinP = socketP->implP; + + size_t bytesLeft; + abyss_bool error; + + assert(sizeof(size_t) >= sizeof(len)); + + for (bytesLeft = len, error = FALSE; + bytesLeft > 0 && !error; + ) { + size_t const maxSend = (size_t)(-1) >> 1; + + int rc; + + rc = send(socketWinP->fd, &buffer[len-bytesLeft], + MIN(maxSend, bytesLeft), 0); + + if (rc <= 0) + /* 0 means connection closed; < 0 means severe error */ + error = TRUE; + else + bytesLeft -= rc; + } + *failedP = error; +} + + + +uint32_t +socketRead(TSocket * const socketP, + char * const buffer, + uint32_t const len) { + + struct socketWin * const socketWinP = socketP->implP; + + int rc; + rc = recv(socketWinP->fd, buffer, len, 0); + return rc; +} + + + +abyss_bool +socketConnect(TSocket * const socketP, + TIPAddr * const addrP, + uint16_t const portNumber) { + + struct socketWin * const socketWinP = socketP->implP; + + struct sockaddr_in name; + int rc; + + name.sin_family = AF_INET; + name.sin_port = htons(portNumber); + name.sin_addr = *addrP; + + rc = connect(socketWinP->fd, (struct sockaddr *)&name, sizeof(name)); + + return rc != -1; +} + + + +abyss_bool +socketBind(TSocket * const socketP, + TIPAddr * const addrP, + uint16_t const portNumber) { + + struct socketWin * const socketWinP = socketP->implP; + + struct sockaddr_in name; + int rc; + + name.sin_family = AF_INET; + name.sin_port = htons(portNumber); + if (addrP) + name.sin_addr = *addrP; + else + name.sin_addr.s_addr = INADDR_ANY; + + rc = bind(socketWinP->fd, (struct sockaddr *)&name, sizeof(name)); + + return (rc != -1); +} + + + +abyss_bool +socketListen(TSocket * const socketP, + uint32_t const backlog) { + + struct socketWin * const socketWinP = socketP->implP; + + int32_t const minus1 = -1; + + int rc; + + /* Disable the Nagle algorithm to make persistant connections faster */ + + setsockopt(socketWinP->fd, IPPROTO_TCP,TCP_NODELAY, + (const char *)&minus1, sizeof(minus1)); + + rc = listen(socketWinP->fd, backlog); + + return (rc != -1); +} + + + +static void +socketAccept(TSocket * const listenSocketP, + abyss_bool * const connectedP, + abyss_bool * const failedP, + TSocket ** const acceptedSocketPP, + TIPAddr * const ipAddrP) { +/*---------------------------------------------------------------------------- + Accept a connection on the listening socket 'listenSocketP'. Return as + *acceptedSocketPP the socket for the accepted connection. + + If no connection is waiting on 'listenSocketP', wait until one is. + + If we receive a signal while waiting, return immediately. + + Return *connectedP true iff we accepted a connection. Return + *failedP true iff we were unable to accept a connection for some + reason other than that we were interrupted. Return both false if + our wait for a connection was interrupted by a signal. +-----------------------------------------------------------------------------*/ + struct socketWin * const listenSocketWinP = listenSocketP->implP; + + abyss_bool connected, failed, interrupted; + + connected = FALSE; + failed = FALSE; + interrupted = FALSE; + + while (!connected && !failed && !interrupted) { + struct sockaddr_in sa; + socklen_t size = sizeof(sa); + int rc; + rc = accept(listenSocketWinP->fd, (struct sockaddr *)&sa, &size); + if (rc >= 0) { + SOCKET const acceptedWinsock = rc; + struct socketWin * acceptedSocketWinP; + + MALLOCVAR(acceptedSocketWinP); + + if (acceptedSocketWinP) { + acceptedSocketWinP->fd = acceptedWinsock; + acceptedSocketWinP->userSuppliedWinsock = FALSE; + + SocketCreate(&vtbl, acceptedSocketWinP, acceptedSocketPP); + if (!*acceptedSocketPP) + failed = TRUE; + else { + connected = TRUE; + *ipAddrP = sa.sin_addr; + } + if (failed) + free(acceptedSocketWinP); + } else + failed = TRUE; + if (failed) + closesocket(acceptedWinsock); + } else if (socketError(NULL) == WSAEINTR) + interrupted = TRUE; + else + failed = TRUE; + } + *failedP = failed; + *connectedP = connected; +} + + + +static uint32_t +socketWait(TSocket * const socketP, + abyss_bool const rd, + abyss_bool const wr, + uint32_t const timems) { + + struct socketWin * const socketWinP = socketP->implP; + + fd_set rfds, wfds; + TIMEVAL tv; + + FD_ZERO(&rfds); + FD_ZERO(&wfds); + + if (rd) + FD_SET(socketWinP->fd, &rfds); + + if (wr) + FD_SET(socketWinP->fd, &wfds); + + tv.tv_sec = timems / 1000; + tv.tv_usec = timems % 1000; + + for (;;) { + int rc; + + rc = select(socketWinP->fd + 1, &rfds, &wfds, NULL, + (timems == TIME_INFINITE ? NULL : &tv)); + + switch(rc) { + case 0: /* time out */ + return 0; + + case -1: /* socket error */ + if (socketError(NULL) == WSAEINTR) + break; + + return 0; + + default: + if (FD_ISSET(socketWinP->fd, &rfds)) + return 1; + if (FD_ISSET(socketWinP->fd, &wfds)) + return 2; + return 0; + } + } +} + + + +static uint32_t +socketAvailableReadBytes(TSocket * const socketP) { + + struct socketWin * const socketWinP = socketP->implP; + + uint32_t x; + int rc; + + rc = ioctlsocket(socketWinP->fd, FIONREAD, &x); + + return rc == 0 ? x : 0; +} + + + +static void +socketGetPeerName(TSocket * const socketP, + TIPAddr * const ipAddrP, + uint16_t * const portNumberP, + abyss_bool * const successP) { + + struct socketWin * const socketWinP = socketP->implP; + + socklen_t addrlen; + int rc; + struct sockaddr sockAddr; + + addrlen = sizeof(sockAddr); + + rc = getpeername(socketWinP->fd, &sockAddr, &addrlen); + + if (rc < 0) { + TraceMsg("getpeername() failed. errno=%d (%s)", + errno, strerror(errno)); + *successP = FALSE; + } else { + if (addrlen != sizeof(sockAddr)) { + TraceMsg("getpeername() returned a socket address of the wrong " + "size: %u. Expected %u", addrlen, sizeof(sockAddr)); + *successP = FALSE; + } else { + if (sockAddr.sa_family != AF_INET) { + TraceMsg("Socket does not use the Inet (IP) address " + "family. Instead it uses family %d", + sockAddr.sa_family); + *successP = FALSE; + } else { + struct sockaddr_in * const sockAddrInP = (struct sockaddr_in *) + &sockAddr; + + *ipAddrP = sockAddrInP->sin_addr; + *portNumberP = sockAddrInP->sin_port; + + *successP = TRUE; + } + } + } +} + + + +static uint32_t +socketError(TSocket * const socketP) { + return (uint32_t)WSAGetLastError(); +} + + + diff --git a/lib/abyss/src/socket_win.h b/lib/abyss/src/socket_win.h new file mode 100644 index 0000000..f64f48d --- /dev/null +++ b/lib/abyss/src/socket_win.h @@ -0,0 +1,10 @@ +#ifndef SOCKET_WIN_H_INCLUDED +#define SOCKET_WIN_H_INCLUDED + +void +SocketWinInit(abyss_bool * const succeededP); + +void +SocketWinTerm(void); + +#endif diff --git a/lib/abyss/src/thread.h b/lib/abyss/src/thread.h new file mode 100644 index 0000000..dfef056 --- /dev/null +++ b/lib/abyss/src/thread.h @@ -0,0 +1,70 @@ +#ifndef THREAD_H_INCLUDED +#define THREAD_H_INCLUDED + +/********************************************************************* +** Thread +*********************************************************************/ + +typedef struct abyss_thread TThread; + +void +ThreadPoolInit(void); + +typedef void TThreadProc(void * const userHandleP); +typedef void TThreadDoneFn(void * const userHandleP); + +void +ThreadCreate(TThread ** const threadPP, + void * const userHandle, + TThreadProc * const func, + TThreadDoneFn * const threadDone, + abyss_bool const useSigchld, + const char ** const errorP); + +abyss_bool +ThreadRun(TThread * const threadP); + +abyss_bool +ThreadStop(TThread * const threadP); + +abyss_bool +ThreadKill(TThread * threadP); + +void +ThreadWaitAndRelease(TThread * const threadP); + +void +ThreadExit(int const retValue); + +void +ThreadRelease(TThread * const threadP); + +abyss_bool +ThreadForks(void); + +void +ThreadUpdateStatus(TThread * const threadP); + +#ifndef WIN32 +void +ThreadHandleSigchld(pid_t const pid); +#endif + +/********************************************************************* +** Mutex +*********************************************************************/ + +#ifdef WIN32 +typedef HANDLE TMutex; +#else +#include +typedef pthread_mutex_t TMutex; +#endif /* WIN32 */ + +abyss_bool MutexCreate(TMutex *m); +abyss_bool MutexLock(TMutex *m); +abyss_bool MutexUnlock(TMutex *m); +abyss_bool MutexTryLock(TMutex *m); +void MutexFree(TMutex *m); + +#endif diff --git a/lib/abyss/src/thread_fork.c b/lib/abyss/src/thread_fork.c new file mode 100644 index 0000000..b1727c7 --- /dev/null +++ b/lib/abyss/src/thread_fork.c @@ -0,0 +1,323 @@ +#include +#include +#include +#include +#include +#include +#include + +#include "xmlrpc_config.h" +#include "xmlrpc-c/string_int.h" +#include "xmlrpc-c/abyss.h" + +#include "mallocvar.h" +#include "thread.h" + + +static void +blockSignalClass(int const signalClass, + sigset_t * const oldBlockedSetP) { + + sigset_t newBlockedSet; + + sigemptyset(&newBlockedSet); + sigaddset(&newBlockedSet, signalClass); + + sigprocmask(SIG_BLOCK, &newBlockedSet, oldBlockedSetP); +} + + + +struct abyss_thread { + struct abyss_thread * nextInPoolP; + TThreadDoneFn * threadDone; + void * userHandle; + pid_t pid; + abyss_bool useSigchld; + /* This means that user is going to call ThreadHandleSigchld() + when it gets a death of a child signal for this process. If + false, he's going to leave us in the dark, so we'll have to + poll to know if the process is dead or not. + */ +}; + + +/* Because signals are global, we need this global variable in order for + the signal handler to figure out to what thread the signal belongs. +*/ + +/* We use a singly linked list. Every time we access it, we have to run + the whole chain. To make this scale up, we should replace it with + a doubly linked list and some kind of index by PID. + + But large scale systems probably aren't using fork threads anyway. +*/ + +static struct { + struct abyss_thread * firstP; +} ThreadPool; + + + +void +ThreadPoolInit(void) { + + ThreadPool.firstP = NULL; +} + + + +static struct abyss_thread * +findThread(pid_t const pid) { + + struct abyss_thread * p; + + for (p = ThreadPool.firstP; p && p->pid != pid; p = p->nextInPoolP); + + return p; +} + + + +static void +addToPool(struct abyss_thread * const threadP) { + + if (ThreadPool.firstP == NULL) + ThreadPool.firstP = threadP; + else { + struct abyss_thread * p; + + for (p = ThreadPool.firstP; p->nextInPoolP; p = p->nextInPoolP); + + /* p points to the last thread in the list */ + + p->nextInPoolP = threadP; + } +} + + + +static void +removeFromPool(struct abyss_thread * const threadP) { + + if (threadP == ThreadPool.firstP) + ThreadPool.firstP = threadP->nextInPoolP; + else { + struct abyss_thread * p; + + for (p = ThreadPool.firstP; + p && p->nextInPoolP != threadP; + p = p->nextInPoolP); + + if (p) + /* p points to thread right before the one we want to remove */ + p->nextInPoolP = threadP->nextInPoolP; + } +} + + + +void +ThreadHandleSigchld(pid_t const pid) { +/*---------------------------------------------------------------------------- + Handle a death of a child signal for process 'pid', which may be one + of our threads. +-----------------------------------------------------------------------------*/ + struct abyss_thread * const threadP = findThread(pid); + + if (threadP) { + if (threadP->threadDone) + threadP->threadDone(threadP->userHandle); + threadP->pid = 0; + } + /* Note that threadDone might free *threadP */ +} + + + +void +ThreadUpdateStatus(TThread * const threadP) { + + if (!threadP->useSigchld) { + if (threadP->pid) { + if (kill(threadP->pid, 0) != 0) { + if (threadP->threadDone) + threadP->threadDone(threadP->userHandle); + threadP->pid = 0; + } + } + } +} + + + +void +ThreadCreate(TThread ** const threadPP, + void * const userHandle, + TThreadProc * const func, + TThreadDoneFn * const threadDone, + abyss_bool const useSigchld, + const char ** const errorP) { + + TThread * threadP; + + MALLOCVAR(threadP); + if (threadP == NULL) + xmlrpc_asprintf(errorP, + "Can't allocate memory for thread descriptor."); + else { + sigset_t oldBlockedSet; + pid_t rc; + + threadP->nextInPoolP = NULL; + threadP->threadDone = threadDone; + threadP->userHandle = userHandle; + threadP->useSigchld = useSigchld; + threadP->pid = 0; + + /* We have to be sure we don't get the SIGCHLD for this child's + death until the child is properly registered in the thread pool + so that the handler will know who he is. + */ + blockSignalClass(SIGCHLD, &oldBlockedSet); + + rc = fork(); + + if (rc < 0) + xmlrpc_asprintf(errorP, "fork() failed, errno=%d (%s)", + errno, strerror(errno)); + else if (rc == 0) { + /* This is the child */ + (*func)(userHandle); + exit(0); + } else { + /* This is the parent */ + threadP->pid = rc; + + addToPool(threadP); + + sigprocmask(SIG_SETMASK, &oldBlockedSet, NULL); /* restore */ + + *errorP = NULL; + *threadPP = threadP; + } + if (*errorP) { + removeFromPool(threadP); + free(threadP); + } + } +} + + + +abyss_bool +ThreadRun(TThread * const threadP ATTR_UNUSED) { + return TRUE; +} + + + +abyss_bool +ThreadStop(TThread * const threadP ATTR_UNUSED) { + return TRUE; +} + + + +abyss_bool +ThreadKill(TThread * const threadP ATTR_UNUSED) { + return TRUE; +} + + + +void +ThreadWaitAndRelease(TThread * const threadP) { + + if (threadP->pid) { + int exitStatus; + + waitpid(threadP->pid, &exitStatus, 0); + + threadP->threadDone(threadP->userHandle); + + threadP->pid = 0; + } + ThreadRelease(threadP); +} + + + +void +ThreadExit(int const retValue) { + + /* Note that the OS will automatically send a SIGCHLD signal to + the parent process after we exit. The handler for that signal + will run threadDone in parent's context. Alternatively, if + the parent is set up for signals, the parent will eventually + poll for the existence of our PID and call threadDone when he + sees we've gone. + */ + + exit(retValue); +} + + + +void +ThreadRelease(TThread * const threadP) { + + removeFromPool(threadP); + free(threadP); +} + + + +abyss_bool +ThreadForks(void) { + + return TRUE; +} + + + +/********************************************************************* +** Mutex +*********************************************************************/ + +/* As two processes don't share memory, there is nothing to synchronize, + so locking is a no-op. +*/ + +abyss_bool +MutexCreate(TMutex * const mutexP ATTR_UNUSED) { + return TRUE; +} + + + +abyss_bool +MutexLock(TMutex * const mutexP ATTR_UNUSED) { + return TRUE; +} + + + +abyss_bool +MutexUnlock(TMutex * const mutexP ATTR_UNUSED) { + return TRUE; +} + + + +abyss_bool +MutexTryLock(TMutex * const mutexP ATTR_UNUSED) { + return TRUE; +} + + + +void +MutexFree(TMutex * const mutexP ATTR_UNUSED) { + +} diff --git a/lib/abyss/src/thread_pthread.c b/lib/abyss/src/thread_pthread.c new file mode 100644 index 0000000..69c62b1 --- /dev/null +++ b/lib/abyss/src/thread_pthread.c @@ -0,0 +1,221 @@ +#include +#include +#include +#include +#include + +#include "xmlrpc_config.h" + +#include "mallocvar.h" +#include "xmlrpc-c/string_int.h" + +#include "xmlrpc-c/abyss.h" + +#include "thread.h" + + + +struct abyss_thread { + pthread_t thread; + void * userHandle; + TThreadProc * func; + TThreadDoneFn * threadDone; +}; + +/* We used to have THREAD_STACK_SIZE = 16K, which was said to be the + minimum stack size on Win32. Scott Kolodzeski found in November + 2005 that this was insufficient for 64 bit Solaris -- we fail + when creating the first thread. So we changed to 128K. +*/ +#define THREAD_STACK_SIZE (128*1024L) + + +typedef void * (pthreadStartRoutine)(void *); + + + +static pthreadStartRoutine pthreadStart; + +static void * +pthreadStart(void * const arg) { + + struct abyss_thread * const threadP = arg; + abyss_bool const executeTrue = true; + + pthread_cleanup_push(threadP->threadDone, threadP->userHandle); + + threadP->func(threadP->userHandle); + + pthread_cleanup_pop(executeTrue); + + return NULL; +} + + + +void +ThreadCreate(TThread ** const threadPP, + void * const userHandle, + TThreadProc * const func, + TThreadDoneFn * const threadDone, + abyss_bool const useSigchld ATTR_UNUSED, + const char ** const errorP) { + + TThread * threadP; + + MALLOCVAR(threadP); + if (threadP == NULL) + xmlrpc_asprintf(errorP, + "Can't allocate memory for thread descriptor."); + else { + pthread_attr_t attr; + int rc; + + pthread_attr_init(&attr); + + pthread_attr_setstacksize(&attr, THREAD_STACK_SIZE); + + threadP->userHandle = userHandle; + threadP->func = func; + threadP->threadDone = threadDone; + + rc = pthread_create(&threadP->thread, &attr, + pthreadStart, threadP); + if (rc == 0) { + *errorP = NULL; + *threadPP = threadP; + } else + xmlrpc_asprintf( + errorP, "pthread_create() failed, errno = %d (%s)", + errno, strerror(errno)); + + pthread_attr_destroy(&attr); + + if (*errorP) + free(threadP); + } +} + + + +abyss_bool +ThreadRun(TThread * const threadP ATTR_UNUSED) { + return TRUE; +} + + + +abyss_bool +ThreadStop(TThread * const threadP ATTR_UNUSED) { + return TRUE; +} + + + +abyss_bool +ThreadKill(TThread * const threadP ATTR_UNUSED) { + + return (pthread_kill(threadP->thread, SIGTERM) == 0); +} + + + +void +ThreadWaitAndRelease(TThread * const threadP) { + + void * threadReturn; + + pthread_join(threadP->thread, &threadReturn); + + free(threadP); +} + + + +void +ThreadExit(int const retValue) { + + pthread_exit((void*)&retValue); + + /* Note that the above runs our cleanup routine (which we registered + with pthread_cleanup_push() before exiting. + */ +} + + + +void +ThreadRelease(TThread * const threadP) { + + pthread_detach(threadP->thread); + + free(threadP); +} + + + +abyss_bool +ThreadForks(void) { + + return FALSE; +} + + + +void +ThreadUpdateStatus(TThread * const threadP ATTR_UNUSED) { + + /* Threads keep their own statuses up to date, so there's nothing + to do here. + */ +} + + + +void +ThreadHandleSigchld(pid_t const pid ATTR_UNUSED) { + + /* Death of a child signals have nothing to do with pthreads */ +} + + + +/********************************************************************* +** Mutex +*********************************************************************/ + + + +abyss_bool +MutexCreate(TMutex * const mutexP) { + + return (pthread_mutex_init(mutexP, NULL) == 0); +} + + + +abyss_bool +MutexLock(TMutex * const mutexP) { + return (pthread_mutex_lock(mutexP) == 0); +} + + + +abyss_bool +MutexUnlock(TMutex * const mutexP) { + return (pthread_mutex_unlock(mutexP) == 0); +} + + + +abyss_bool +MutexTryLock(TMutex * const mutexP) { + return (pthread_mutex_trylock(mutexP) == 0); +} + + + +void +MutexFree(TMutex * const mutexP) { + pthread_mutex_destroy(mutexP); +} diff --git a/lib/abyss/src/thread_windows.c b/lib/abyss/src/thread_windows.c new file mode 100644 index 0000000..4a6868a --- /dev/null +++ b/lib/abyss/src/thread_windows.c @@ -0,0 +1,167 @@ +#include +#include + +#include "xmlrpc_config.h" + +#include "mallocvar.h" +#include "xmlrpc-c/string_int.h" + +#include "xmlrpc-c/abyss.h" + +#include "thread.h" + + + +struct abyss_thread { + HANDLE handle; + void * userHandle; + TThreadDoneFn * threadDone; +}; + +#define THREAD_STACK_SIZE (16*1024L) + + +typedef uint32_t (WINAPI WinThreadProc)(void *); + + +void +ThreadCreate(TThread ** const threadPP, + void * const userHandle, + TThreadProc * const func, + TThreadDoneFn * const threadDone, + abyss_bool const useSigchld, + const char ** const errorP) { + + DWORD z; + TThread * threadP; + + MALLOCVAR(threadP); + + if (threadP == NULL) + xmlrpc_asprintf(errorP, + "Can't allocate memory for thread descriptor."); + else { + threadP->userHandle = userHandle; + threadP->threadDone = threadDone; + threadP->handle = (HANDLE)_beginthreadex(NULL, THREAD_STACK_SIZE, func, + userHandle, + CREATE_SUSPENDED, &z); + if (threadP->handle == NULL) + xmlrpc_asprintf(errorP, "_beginthreadex() failed."); + else { + *errorP = NULL; + *threadPP = threadP; + } + if (*errorP) + free(threadP); + } +} + + + +abyss_bool +ThreadRun(TThread * const threadP) { + return (ResumeThread(threadP->handle) != 0xFFFFFFFF); +} + + + +abyss_bool +ThreadStop(TThread * const threadP) { + + return (SuspendThread(threadP->handle) != 0xFFFFFFFF); +} + + + +abyss_bool +ThreadKill(TThread * const threadP) { + return (TerminateThread(threadP->handle, 0) != 0); +} + + + +void +ThreadWaitAndRelease(TThread * const threadP) { + + ThreadRelease(threadP); + + if (threadP->threadDone) + threadP->threadDone(threadP->userHandle); + + free(threadP); +} + + + +void +ThreadExit(int const retValue) { + + _endthreadex(retValue); +} + + + +void +ThreadRelease(TThread * const threadP) { + + CloseHandle(threadP->handle); +} + + + +abyss_bool +ThreadForks(void) { + + return FALSE; +} + + + +void +ThreadUpdateStatus(TThread * const threadP ATTR_UNUSED) { + + /* Threads keep their own statuses up to date, so there's nothing + to do here. + */ +} + + + +abyss_bool +MutexCreate(TMutex * const mutexP) { + + *mutexP = CreateMutex(NULL, FALSE, NULL); + + return (*mutexP != NULL); +} + + + +abyss_bool +MutexLock(TMutex * const mutexP) { + + return (WaitForSingleObject(*mutexP, INFINITE) != WAIT_TIMEOUT); +} + + + +abyss_bool +MutexUnlock(TMutex * const mutexP) { + return ReleaseMutex(*mutexP); +} + + + +abyss_bool +MutexTryLock(TMutex * const mutexP) { + return (WaitForSingleObject(*mutexP, 0) != WAIT_TIMEOUT); +} + + + +void +MutexFree(TMutex * const mutexP) { + CloseHandle(*mutexP); +} + diff --git a/lib/abyss/src/token.c b/lib/abyss/src/token.c new file mode 100644 index 0000000..8616b95 --- /dev/null +++ b/lib/abyss/src/token.c @@ -0,0 +1,54 @@ +#include "xmlrpc-c/abyss.h" + +#include "token.h" + +void +NextToken(const char ** const pP) { + + abyss_bool gotToken; + + gotToken = FALSE; + + while (!gotToken) { + switch (**pP) { + case '\t': + case ' ': + ++(*pP); + break; + default: + gotToken = TRUE; + }; + } +} + + + +char * +GetToken(char ** const pP) { + + char * p0; + + p0 = *pP; + + while (1) { + switch (**pP) { + case '\t': + case ' ': + case CR: + case LF: + case '\0': + if (p0 == *pP) + return NULL; + + if (**pP) { + **pP = '\0'; + ++(*pP); + }; + return p0; + + default: + ++(*pP); + }; + } +} + diff --git a/lib/abyss/src/token.h b/lib/abyss/src/token.h new file mode 100644 index 0000000..a8458e4 --- /dev/null +++ b/lib/abyss/src/token.h @@ -0,0 +1,11 @@ +#ifndef ABYSS_TOKEN_H_INCLUDED +#define ABYSS_TOKEN_H_INCLUDED + +void +NextToken(const char ** const pP); + +char * +GetToken(char ** const pP); + + +#endif diff --git a/lib/abyss/src/trace.c b/lib/abyss/src/trace.c new file mode 100644 index 0000000..8079388 --- /dev/null +++ b/lib/abyss/src/trace.c @@ -0,0 +1,78 @@ +/****************************************************************************** +** +** trace.c +** +** This file is part of the ABYSS Web server project. +** +** Copyright (C) 2000 by Moez Mahfoudh . +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +** ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +** OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +** HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +** LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +** OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +** SUCH DAMAGE. +** +******************************************************************************/ + +#include +#include +#include + +#include "trace.h" + +/********************************************************************* +** Tracing functions +*********************************************************************/ + +static void +TraceVMsg(const char * const fmt, + va_list argptr) { + + vprintf(fmt,argptr); + + printf("\n"); +} + + + +void +TraceMsg(const char * const fmt, ...) { + + va_list argptr; + + va_start(argptr,fmt); + TraceVMsg(fmt,argptr); + va_end(argptr); +} + + + +void +TraceExit(const char * const fmt, ...) { + + va_list argptr; + + va_start(argptr,fmt); + TraceVMsg(fmt,argptr); + va_end(argptr); + + exit(1); +} diff --git a/lib/abyss/src/trace.h b/lib/abyss/src/trace.h new file mode 100644 index 0000000..849c0b3 --- /dev/null +++ b/lib/abyss/src/trace.h @@ -0,0 +1,11 @@ +#ifndef TRACE_H_INCLUDED +#define TRACE_H_INCLUDED + +void +TraceMsg(const char * const fmt, ...); + +void +TraceExit(const char * const fmt, ...); + +#endif + diff --git a/lib/abyss/version.txt b/lib/abyss/version.txt new file mode 100644 index 0000000..13874ba --- /dev/null +++ b/lib/abyss/version.txt @@ -0,0 +1 @@ +0.3 (03/23/2000) \ No newline at end of file diff --git a/lib/curl_transport/Makefile b/lib/curl_transport/Makefile new file mode 100644 index 0000000..7e0d421 --- /dev/null +++ b/lib/curl_transport/Makefile @@ -0,0 +1,51 @@ +ifeq ($(SRCDIR)x,x) +SRCDIR = $(CURDIR)/../.. +BUILDDIR = ../.. +endif + +include $(SRCDIR)/Makefile.config + +CURL_INCLUDES := $(shell curl-config --cflags) +# We expect that curl-config --cflags just gives us -I options, because +# we need just the -I options for 'make dep'. Plus, it's scary to think +# of what any other compiler flag would do to our compile. + +CFLAGS = $(CFLAGS_COMMON) $(CFLAGS_PERSONAL) $(CADD) +LDFLAGS = $(LADD) + +INCLUDES = -I$(SRCDIR) -I$(SRCDIR)/include -I$(SRCDIR)/lib/util/include \ + $(CURL_INCLUDES) + +default: all + +.PHONY: all +all: xmlrpc_curl_transport.lo + +.PHONY: clean +clean: clean-common + +.PHONY: distclean +distclean: clean distclean-common + +.PHONY: tags +tags: TAGS + +.PHONY: distdir +distdir: + +.PHONY: install +install: + +.PHONY: dep +dep: dep-common + +include $(SRCDIR)/Makefile.common + +include Makefile.depend + +xmlrpc_curl_transport.lo:%.lo:%.c + $(LIBTOOL) --mode=compile $(CC) -c $(INCLUDES) $(CFLAGS) $< + +# Need this dependency for those who don't use Makefile.depend. +# Without it, version.h doesn't get created. +xmlrpc_curl_transport.lo: version.h \ No newline at end of file diff --git a/lib/curl_transport/Makefile.depend b/lib/curl_transport/Makefile.depend new file mode 100644 index 0000000..e69de29 diff --git a/lib/curl_transport/xmlrpc_curl_transport.c b/lib/curl_transport/xmlrpc_curl_transport.c new file mode 100644 index 0000000..530fab5 --- /dev/null +++ b/lib/curl_transport/xmlrpc_curl_transport.c @@ -0,0 +1,1864 @@ +/*============================================================================= + xmlrpc_curl_transport +=============================================================================== + Curl-based client transport for Xmlrpc-c + + By Bryan Henderson 04.12.10. + + Contributed to the public domain by its author. +=============================================================================*/ + +/*---------------------------------------------------------------------------- + Curl global variables: + + Curl maintains some minor information in process-global variables. + One must call curl_global_init() to initialize them before calling + any other Curl library function. This is not state information -- + it is constants. They just aren't the kind of constants that the + library loader knows how to set, so there has to be this explicit + call to set them up. The matching function curl_global_cleanup() + returns resources these use (to wit, the constants live in + malloc'ed storage and curl_global_cleanup() frees the storage). + + So our setup_global_const transport operation calls + curl_global_init() and our teardown_global_const calls + curl_global_cleanup(). + + The Curl library is supposed to maintain a reference count for the + global constants so that multiple modules using the library and + independently calling curl_global_init() and curl_global_cleanup() + are not a problem. But today, it just keeps a flag "I have been + initialized" and the first call to curl_global_cleanup() destroys + the constants for everybody. Therefore, the user of the Xmlrpc-c + Curl client XML transport must make sure not to call + teardownGlobalConstants until everything else in his program is + done using the Curl library. + + Note that curl_global_init() is not threadsafe (with or without the + reference count), therefore our setup_global_const is not, and must + be called when no other thread in the process is running. + Typically, one calls it right at the beginning of the program. + + There are actually two other classes of global variables in the + Curl library, which we are ignoring: debug options and custom + memory allocator function identities. Our code never changes these + global variables from default. If something else in the user's + program does, User is responsible for making sure it doesn't + interfere with our use of the library. + + Note that when we say what the Curl library does, we're also + talking about various other libraries Curl uses internally, and in + fact much of what we're saying about global variables springs from + such subordinate libraries as OpenSSL and Winsock. +-----------------------------------------------------------------------------*/ + +#include +#include +#include +#include +#include + +#include "xmlrpc_config.h" + +#include "bool.h" +#include "girmath.h" +#include "mallocvar.h" +#include "linklist.h" +#include "girstring.h" +#include "pthreadx.h" + +#include "xmlrpc-c/base.h" +#include "xmlrpc-c/base_int.h" +#include "xmlrpc-c/string_int.h" +#include "xmlrpc-c/client.h" +#include "xmlrpc-c/client_int.h" +#include "xmlrpc-c/transport.h" +#include "version.h" + +#include +#include +#include +#include + +#if defined (WIN32) && defined(_DEBUG) +# include +# define new DEBUG_NEW +# define malloc(size) _malloc_dbg( size, _NORMAL_BLOCK, __FILE__, __LINE__) +# undef THIS_FILE + static char THIS_FILE[] = __FILE__; +#endif /*WIN32 && _DEBUG*/ + + + +struct curlSetup { + + /* This is all client transport properties that are implemented as + simple Curl session properties (i.e. the transport basically just + passes them through to Curl without looking at them). + + People occasionally want to replace all this with something where + the Xmlrpc-c user simply does the curl_easy_setopt() call and this + code need not know about all these options. Unfortunately, that's + a significant modularity violation. Either the Xmlrpc-c user + controls the Curl object or he doesn't. If he does, then he + shouldn't use libxmlrpc_client -- he should just copy some of this + code into his own program. If he doesn't, then he should never see + the Curl library. + + Speaking of modularity: the only reason this is a separate struct + is to make the code easier to manage. Ideally, the fact that these + particular properties of the transport are implemented by simple + Curl session setup would be known only at the lowest level code + that does that setup. + */ + + const char * networkInterface; + /* This identifies the network interface on the local side to + use for the session. It is an ASCIIZ string in the form + that the Curl recognizes for setting its CURLOPT_INTERFACE + option (also the --interface option of the Curl program). + E.g. "9.1.72.189" or "giraffe-data.com" or "eth0". + + It isn't necessarily valid, but it does have a terminating NUL. + + NULL means we have no preference. + */ + xmlrpc_bool sslVerifyPeer; + /* In an SSL connection, we should authenticate the server's SSL + certificate -- refuse to talk to him if it isn't authentic. + This is equivalent to Curl's CURLOPT_SSL_VERIFY_PEER option. + */ + xmlrpc_bool sslVerifyHost; + /* In an SSL connection, we should verify that the server's + certificate (independently of whether the certificate is + authentic) indicates the host name that is in the URL we + are using for the server. + */ + + const char * sslCert; + const char * sslCertType; + const char * sslCertPasswd; + const char * sslKey; + const char * sslKeyType; + const char * sslKeyPasswd; + const char * sslEngine; + bool sslEngineDefault; + unsigned int sslVersion; + const char * caInfo; + const char * caPath; + const char * randomFile; + const char * egdSocket; + const char * sslCipherList; +}; + + +/*============================================================================ + locks +============================================================================== + This is the beginnings of a lock abstraction that will allow this + transport to be used with locks other than pthread locks +============================================================================*/ + +struct lock { + pthread_mutex_t theLock; + void (*lock)(struct lock *); + void (*unlock)(struct lock *); + void (*destroy)(struct lock *); +}; + +typedef struct lock lock; + +static void +lock_pthread(struct lock * const lockP) { + pthread_mutex_lock(&lockP->theLock); +} + +static void +unlock_pthread(struct lock * const lockP) { + pthread_mutex_unlock(&lockP->theLock); +} + +static void +destroyLock_pthread(struct lock * const lockP) { + pthread_mutex_destroy(&lockP->theLock); + free(lockP); +} + + +static struct lock * +createLock_pthread(void) { + struct lock * lockP; + MALLOCVAR(lockP); + if (lockP) { + pthread_mutex_init(&lockP->theLock, NULL); + lockP->lock = &lock_pthread; + lockP->unlock = &unlock_pthread; + lockP->destroy = &destroyLock_pthread; + } + return lockP; +} + + + + +/*============================================================================= + curlMulti +=============================================================================*/ + +struct curlMulti { +/*---------------------------------------------------------------------------- + This is an extension to Curl's CURLM object. The extensions are: + + 1) It has a lock so multiple threads can use it simultaneously. + + 2) Its "select" file descriptor vectors are self-contained. CURLM + requires the user to maintain them separately. +-----------------------------------------------------------------------------*/ + CURLM * curlMultiP; + lock * lockP; + /* Hold this lock while accessing or using *curlMultiP. You're + using the multi manager whenever you're calling a Curl + library multi manager function. + */ + /* The following file descriptor sets are an integral part of the + CURLM object; Our curlMulti_fdset() routine binds them to the + CURLM object, and said object expects us to use them in a very + specific way, including doing a select() on them. It is very, + very messy. + */ + fd_set readFdSet; + fd_set writeFdSet; + fd_set exceptFdSet; +}; + + + +static struct curlMulti * +createCurlMulti(void) { + + struct curlMulti * retval; + struct curlMulti * curlMultiP; + + MALLOCVAR(curlMultiP); + + if (curlMultiP == NULL) + retval = NULL; + else { + curlMultiP->lockP = createLock_pthread(); + + if (curlMultiP->lockP == NULL) + retval = NULL; + else { + curlMultiP->curlMultiP = curl_multi_init(); + if (curlMultiP->curlMultiP == NULL) + retval = NULL; + else + retval = curlMultiP; + + if (retval == NULL) + curlMultiP->lockP->destroy(curlMultiP->lockP); + } + if (retval == NULL) + free(curlMultiP); + } + return retval; +} + + + +static void +destroyCurlMulti(struct curlMulti * const curlMultiP) { + + curl_multi_cleanup(curlMultiP->curlMultiP); + + curlMultiP->lockP->destroy(curlMultiP->lockP); + + free(curlMultiP); +} + + + +static void +curlMulti_perform(xmlrpc_env * const envP, + struct curlMulti * const curlMultiP, + bool * const immediateWorkToDoP, + int * const runningHandlesP) { + + CURLMcode rc; + + curlMultiP->lockP->lock(curlMultiP->lockP); + + rc = curl_multi_perform(curlMultiP->curlMultiP, runningHandlesP); + + curlMultiP->lockP->unlock(curlMultiP->lockP); + + if (rc == CURLM_CALL_MULTI_PERFORM) { + *immediateWorkToDoP = true; + } else { + *immediateWorkToDoP = false; + + if (rc != CURLM_OK) { + xmlrpc_faultf(envP, + "Impossible failure of curl_multi_perform() " + "with rc %d", rc); + } + } +} + + + +static void +curlMulti_addHandle(xmlrpc_env * const envP, + struct curlMulti * const curlMultiP, + CURL * const curlSessionP) { + + CURLMcode rc; + + curlMultiP->lockP->lock(curlMultiP->lockP); + + rc = curl_multi_add_handle(curlMultiP->curlMultiP, curlSessionP); + + curlMultiP->lockP->unlock(curlMultiP->lockP); + + if (rc != CURLM_OK) + xmlrpc_faultf(envP, "Could not add Curl session to the " + "curl multi manager. curl_multi_add_handle() " + "returns error code %d", rc); +} + + +static void +curlMulti_removeHandle(struct curlMulti * const curlMultiP, + CURL * const curlSessionP) { + + curlMultiP->lockP->lock(curlMultiP->lockP); + + curl_multi_remove_handle(curlMultiP->curlMultiP, curlSessionP); + + curlMultiP->lockP->unlock(curlMultiP->lockP); +} + + + +static void +curlMulti_getMessage(struct curlMulti * const curlMultiP, + bool * const endOfMessagesP, + CURLMsg * const curlMsgP) { +/*---------------------------------------------------------------------------- + Get the next message from the queue of things the Curl multi manager + wants to say to us. + + Return the message as *curlMsgP. + + Iff there are no messages in the queue, return *endOfMessagesP == true. +-----------------------------------------------------------------------------*/ + int remainingMsgCount; + CURLMsg * privateCurlMsgP; + /* Note that this is a pointer into the multi manager's memory, + so we have to use it under lock. + */ + + curlMultiP->lockP->lock(curlMultiP->lockP); + + privateCurlMsgP = curl_multi_info_read(curlMultiP->curlMultiP, + &remainingMsgCount); + + if (privateCurlMsgP == NULL) + *endOfMessagesP = true; + else { + *endOfMessagesP = false; + *curlMsgP = *privateCurlMsgP; + } + curlMultiP->lockP->unlock(curlMultiP->lockP); +} + + + +static void +curlMulti_fdset(xmlrpc_env * const envP, + struct curlMulti * const curlMultiP, + fd_set * const readFdSetP, + fd_set * const writeFdSetP, + fd_set * const exceptFdSetP, + int * const maxFdP) { +/*---------------------------------------------------------------------------- + Set the CURLM object's file descriptor sets to those in the + curlMulti object, update those file descriptor sets with the + current needs of the multi manager, and return the resulting values + of the file descriptor sets. + + This is a bizarre operation, but is necessary because of the nonmodular + way in which the Curl multi interface works with respect to waiting + for work with select(). +-----------------------------------------------------------------------------*/ + CURLMcode rc; + + curlMultiP->lockP->lock(curlMultiP->lockP); + + /* curl_multi_fdset() doesn't _set_ the fdsets. It adds to existing + ones (so you can easily do a select() on other fds and Curl + fds at the same time). So we have to clear first: + */ + FD_ZERO(&curlMultiP->readFdSet); + FD_ZERO(&curlMultiP->writeFdSet); + FD_ZERO(&curlMultiP->exceptFdSet); + + /* WARNING: curl_multi_fdset() doesn't just update the fdsets pointed + to by its arguments. It makes the CURLM object remember those + pointers and refer back to them later! In fact, curl_multi_perform + expects its caller to have done a select() on those masks. No, + really. The man page even admits it. + */ + + rc = curl_multi_fdset(curlMultiP->curlMultiP, + &curlMultiP->readFdSet, + &curlMultiP->writeFdSet, + &curlMultiP->exceptFdSet, + maxFdP); + + *readFdSetP = curlMultiP->readFdSet; + *writeFdSetP = curlMultiP->writeFdSet; + *exceptFdSetP = curlMultiP->exceptFdSet; + + curlMultiP->lockP->unlock(curlMultiP->lockP); + + if (rc != CURLM_OK) + xmlrpc_faultf(envP, "Impossible failure of curl_multi_fdset() " + "with rc %d", rc); +} + + + +static void +curlMulti_updateFdSet(struct curlMulti * const curlMultiP, + fd_set const readFdSet, + fd_set const writeFdSet, + fd_set const exceptFdSet) { +/*---------------------------------------------------------------------------- + curl_multi_perform() expects the file descriptor sets, which were bound + to the CURLM object via a prior curlMulti_fdset(), to contain the results + of a recent select(). This subroutine provides you a way to supply those. +-----------------------------------------------------------------------------*/ + curlMultiP->readFdSet = readFdSet; + curlMultiP->writeFdSet = writeFdSet; + curlMultiP->exceptFdSet = exceptFdSet; +} + + + +/*===========================================================================*/ + + +struct xmlrpc_client_transport { + struct curlMulti * curlMultiP; + /* The Curl multi manager that this transport uses to handle + multiple Curl sessions at the same time. + */ + CURL * syncCurlSessionP; + /* Handle for a Curl library session object that we use for + all synchronous RPCs. An async RPC has one of its own, + and consequently does not share things such as persistent + connections and cookies with any other RPC. + */ + lock * syncCurlSessionLockP; + /* Hold this lock while accessing or using *syncCurlSessionP. + You're using the session from the time you set any + attributes in it or start a transaction with it until any + transaction has finished and you've lost interest in any + attributes of the session. + */ + const char * userAgent; + /* Prefix for the User-Agent HTTP header, reflecting facilities + outside of Xmlrpc-c. The actual User-Agent header consists + of this prefix plus information about Xmlrpc-c. NULL means + none. + + This is constant. + */ + struct curlSetup curlSetupStuff; + /* This is constant */ +}; + +typedef struct { + /* This is all stuff that really ought to be in a Curl object, but + the Curl library is a little too simple for that. So we build + a layer on top of Curl, and define this "transaction," as an + object subordinate to a Curl "session." A Curl session has + zero or one transactions in progress. The Curl session + "private data" is a pointer to the CurlTransaction object for + the current transaction. + */ + CURL * curlSessionP; + /* Handle for the Curl session that hosts this transaction. + Note that only one transaction at a time can use a particular + Curl session, so this had better not be a session that some other + transaction is using simultaneously. + */ + struct curlMulti * curlMultiP; + /* The Curl multi manager which manages the above curl session, + if any. An asynchronous process uses a Curl multi manager + to manage the in-progress Curl sessions and thereby in-progress + RPCs. A synchronous process has no need of a Curl multi manager. + */ + struct rpc * rpcP; + /* The RPC which this transaction serves. (If this structure + were a true extension of the Curl library as described above, + this would be a void *, since the Curl library doesn't know what + an RPC is, but since we use it only for that, we might as well + use the specific type here). + */ + char curlError[CURL_ERROR_SIZE]; + /* Error message from Curl */ + struct curl_slist * headerList; + /* The HTTP headers for the transaction */ + const char * serverUrl; /* malloc'ed - belongs to this object */ +} curlTransaction; + + + +typedef struct rpc { + curlTransaction * curlTransactionP; + /* The object which does the HTTP transaction, with no knowledge + of XML-RPC or Xmlrpc-c. + */ + xmlrpc_mem_block * responseXmlP; + /* Where the response XML for this RPC should go or has gone. */ + xmlrpc_transport_asynch_complete complete; + /* Routine to call to complete the RPC after it is complete HTTP-wise. + NULL if none. + */ + struct xmlrpc_call_info * callInfoP; + /* User's identifier for this RPC */ +} rpc; + + +static int +timeDiffMillisec(struct timeval const minuend, + struct timeval const subtractor) { + + return (minuend.tv_sec - subtractor.tv_sec) * 1000 + + (minuend.tv_usec - subtractor.tv_usec + 500) / 1000; +} + + + +static bool +timeIsAfter(struct timeval const comparator, + struct timeval const comparand) { + + if (comparator.tv_sec > comparand.tv_sec) + return true; + else if (comparator.tv_sec < comparand.tv_sec) + return false; + else { + /* Seconds are equal */ + if (comparator.tv_usec > comparand.tv_usec) + return true; + else + return false; + } +} + + + +static void +addMilliseconds(struct timeval const addend, + unsigned int const adder, + struct timeval * const sumP) { + + unsigned int newRawUsec; + + newRawUsec = addend.tv_usec + adder * 1000; + + sumP->tv_sec = addend.tv_sec + newRawUsec / 1000000; + sumP->tv_usec = newRawUsec % 1000000; +} + + + +static void +lockSyncCurlSession(struct xmlrpc_client_transport * const transportP) { + transportP->syncCurlSessionLockP->lock(transportP->syncCurlSessionLockP); +} + + + +static void +unlockSyncCurlSession(struct xmlrpc_client_transport * const transportP) { + transportP->syncCurlSessionLockP->unlock(transportP->syncCurlSessionLockP); +} + + + +static size_t +collect(void * const ptr, + size_t const size, + size_t const nmemb, + FILE * const stream) { +/*---------------------------------------------------------------------------- + This is a Curl output function. Curl calls this to deliver the + HTTP response body. Curl thinks it's writing to a POSIX stream. +-----------------------------------------------------------------------------*/ + xmlrpc_mem_block * const responseXmlP = (xmlrpc_mem_block *) stream; + char * const buffer = ptr; + size_t const length = nmemb * size; + + size_t retval; + xmlrpc_env env; + + xmlrpc_env_init(&env); + xmlrpc_mem_block_append(&env, responseXmlP, buffer, length); + if (env.fault_occurred) + retval = (size_t)-1; + else + /* Really? Shouldn't it be like fread() and return 'nmemb'? */ + retval = length; + + return retval; +} + + + +static void +initWindowsStuff(xmlrpc_env * const envP ATTR_UNUSED) { + +#if defined (WIN32) + /* This is CRITICAL so that cURL-Win32 works properly! */ + + /* So this commenter says, but I wonder why. libcurl should do the + required WSAStartup() itself, and it looks to me like it does. + -Bryan 06.01.01 + */ + WORD wVersionRequested; + WSADATA wsaData; + int err; + wVersionRequested = MAKEWORD(1, 1); + + err = WSAStartup(wVersionRequested, &wsaData); + if (err) + xmlrpc_env_set_fault_formatted( + envP, XMLRPC_INTERNAL_ERROR, + "Winsock startup failed. WSAStartup returned rc %d", err); + else { + if (LOBYTE(wsaData.wVersion) != 1 || HIBYTE(wsaData.wVersion) != 1) { + /* Tell the user that we couldn't find a useable */ + /* winsock.dll. */ + xmlrpc_env_set_fault_formatted( + envP, XMLRPC_INTERNAL_ERROR, "Winsock reported that " + "it does not implement the requested version 1.1."); + } + if (envP->fault_occurred) + WSACleanup(); + } +#endif +} + + + +static void +termWindowsStuff(void) { + +#if defined (WIN32) + WSACleanup(); +#endif +} + + + +static void +getXportParms(xmlrpc_env * const envP ATTR_UNUSED, + const struct xmlrpc_curl_xportparms * const curlXportParmsP, + size_t const parmSize, + struct xmlrpc_client_transport * const transportP) { +/*---------------------------------------------------------------------------- + Get the parameters out of *curlXportParmsP and update *transportP + to reflect them. + + *curlXportParmsP is a 'parmSize' bytes long prefix of + struct xmlrpc_curl_xportparms. + + curlXportParmsP is something the user created. It's designed to be + friendly to the user, not to this program, and is encumbered by + lots of backward compatibility constraints. In particular, the + user may have coded and/or compiled it at a time that struct + xmlrpc_curl_xportparms was smaller than it is now! + + So that's why we don't simply attach a copy of *curlXportParmsP to + *transportP. + + To the extent that *curlXportParmsP is too small to contain a parameter, + we return the default value for that parameter. + + Special case: curlXportParmsP == NULL means there is no input at all. + In that case, we return default values for everything. +-----------------------------------------------------------------------------*/ + struct curlSetup * const curlSetupP = &transportP->curlSetupStuff; + + if (!curlXportParmsP || parmSize < XMLRPC_CXPSIZE(user_agent)) + transportP->userAgent = NULL; + else if (curlXportParmsP->user_agent == NULL) + transportP->userAgent = NULL; + else + transportP->userAgent = strdup(curlXportParmsP->user_agent); + + if (!curlXportParmsP || parmSize < XMLRPC_CXPSIZE(network_interface)) + curlSetupP->networkInterface = NULL; + else if (curlXportParmsP->network_interface == NULL) + curlSetupP->networkInterface = NULL; + else + curlSetupP->networkInterface = + strdup(curlXportParmsP->network_interface); + + if (!curlXportParmsP || parmSize < XMLRPC_CXPSIZE(no_ssl_verifypeer)) + curlSetupP->sslVerifyPeer = true; + else + curlSetupP->sslVerifyPeer = !curlXportParmsP->no_ssl_verifypeer; + + if (!curlXportParmsP || + parmSize < XMLRPC_CXPSIZE(no_ssl_verifyhost)) + curlSetupP->sslVerifyHost = true; + else + curlSetupP->sslVerifyHost = !curlXportParmsP->no_ssl_verifyhost; + + if (!curlXportParmsP || parmSize < XMLRPC_CXPSIZE(ssl_cert)) + curlSetupP->sslCert = NULL; + else if (curlXportParmsP->ssl_cert == NULL) + curlSetupP->sslCert = NULL; + else + curlSetupP->sslCert = strdup(curlXportParmsP->ssl_cert); + + if (!curlXportParmsP || parmSize < XMLRPC_CXPSIZE(sslcerttype)) + curlSetupP->sslCertType = NULL; + else if (curlXportParmsP->sslcerttype == NULL) + curlSetupP->sslCertType = NULL; + else + curlSetupP->sslCertType = strdup(curlXportParmsP->sslcerttype); + + if (!curlXportParmsP || parmSize < XMLRPC_CXPSIZE(sslcertpasswd)) + curlSetupP->sslCertPasswd = NULL; + else if (curlXportParmsP->sslcertpasswd == NULL) + curlSetupP->sslCertPasswd = NULL; + else + curlSetupP->sslCertPasswd = strdup(curlXportParmsP->sslcertpasswd); + + if (!curlXportParmsP || parmSize < XMLRPC_CXPSIZE(sslkey)) + curlSetupP->sslKey = NULL; + else if (curlXportParmsP->sslkey == NULL) + curlSetupP->sslKey = NULL; + else + curlSetupP->sslKey = strdup(curlXportParmsP->sslkey); + + if (!curlXportParmsP || parmSize < XMLRPC_CXPSIZE(sslkeytype)) + curlSetupP->sslKeyType = NULL; + else if (curlXportParmsP->sslkeytype == NULL) + curlSetupP->sslKeyType = NULL; + else + curlSetupP->sslKeyType = strdup(curlXportParmsP->sslkeytype); + + if (!curlXportParmsP || parmSize < XMLRPC_CXPSIZE(sslkeypasswd)) + curlSetupP->sslKeyPasswd = NULL; + else if (curlXportParmsP->sslkeypasswd == NULL) + curlSetupP->sslKeyPasswd = NULL; + else + curlSetupP->sslKeyPasswd = strdup(curlXportParmsP->sslkeypasswd); + + if (!curlXportParmsP || parmSize < XMLRPC_CXPSIZE(sslengine)) + curlSetupP->sslEngine = NULL; + else if (curlXportParmsP->sslengine == NULL) + curlSetupP->sslEngine = NULL; + else + curlSetupP->sslEngine = strdup(curlXportParmsP->sslengine); + + if (!curlXportParmsP || parmSize < XMLRPC_CXPSIZE(sslengine_default)) + curlSetupP->sslEngineDefault = false; + else + curlSetupP->sslEngineDefault = !!curlXportParmsP->sslengine_default; + + if (!curlXportParmsP || parmSize < XMLRPC_CXPSIZE(sslversion)) + curlSetupP->sslVersion = XMLRPC_SSLVERSION_DEFAULT; + else + curlSetupP->sslVersion = curlXportParmsP->sslversion; + + if (!curlXportParmsP || parmSize < XMLRPC_CXPSIZE(cainfo)) + curlSetupP->caInfo = NULL; + else if (curlXportParmsP->cainfo == NULL) + curlSetupP->caInfo = NULL; + else + curlSetupP->caInfo = strdup(curlXportParmsP->cainfo); + + if (!curlXportParmsP || parmSize < XMLRPC_CXPSIZE(capath)) + curlSetupP->caPath = NULL; + else if (curlXportParmsP->capath == NULL) + curlSetupP->caPath = NULL; + else + curlSetupP->caPath = strdup(curlXportParmsP->capath); + + if (!curlXportParmsP || parmSize < XMLRPC_CXPSIZE(randomfile)) + curlSetupP->randomFile = NULL; + else if (curlXportParmsP->randomfile == NULL) + curlSetupP->randomFile = NULL; + else + curlSetupP->randomFile = strdup(curlXportParmsP->randomfile); + + if (!curlXportParmsP || parmSize < XMLRPC_CXPSIZE(egdsocket)) + curlSetupP->egdSocket = NULL; + else if (curlXportParmsP->egdsocket == NULL) + curlSetupP->egdSocket = NULL; + else + curlSetupP->egdSocket = strdup(curlXportParmsP->egdsocket); + + if (!curlXportParmsP || parmSize < XMLRPC_CXPSIZE(ssl_cipher_list)) + curlSetupP->sslCipherList = NULL; + else if (curlXportParmsP->ssl_cipher_list == NULL) + curlSetupP->sslCipherList = NULL; + else + curlSetupP->sslCipherList = strdup(curlXportParmsP->ssl_cipher_list); + +} + + + +static void +freeXportParms(const struct xmlrpc_client_transport * const transportP) { + + const struct curlSetup * const curlSetupP = &transportP->curlSetupStuff; + + if (curlSetupP->sslCipherList) + xmlrpc_strfree(curlSetupP->sslCipherList); + if (curlSetupP->egdSocket) + xmlrpc_strfree(curlSetupP->egdSocket); + if (curlSetupP->randomFile) + xmlrpc_strfree(curlSetupP->randomFile); + if (curlSetupP->caPath) + xmlrpc_strfree(curlSetupP->caPath); + if (curlSetupP->caInfo) + xmlrpc_strfree(curlSetupP->caInfo); + if (curlSetupP->sslEngine) + xmlrpc_strfree(curlSetupP->sslEngine); + if (curlSetupP->sslKeyPasswd) + xmlrpc_strfree(curlSetupP->sslKeyPasswd); + if (curlSetupP->sslKeyType) + xmlrpc_strfree(curlSetupP->sslKeyType); + if (curlSetupP->sslKey) + xmlrpc_strfree(curlSetupP->sslKey); + if (curlSetupP->sslCertPasswd) + xmlrpc_strfree(curlSetupP->sslCertPasswd); + if (curlSetupP->sslCertType) + xmlrpc_strfree(curlSetupP->sslCertType); + if (curlSetupP->sslCert) + xmlrpc_strfree(curlSetupP->sslCert); + if (curlSetupP->networkInterface) + xmlrpc_strfree(curlSetupP->networkInterface); + if (transportP->userAgent) + xmlrpc_strfree(transportP->userAgent); +} + + + +static void +createSyncCurlSession(xmlrpc_env * const envP, + CURL ** const curlSessionPP) { +/*---------------------------------------------------------------------------- + Create a Curl session to be used for multiple serial transactions. + The Curl session we create is not complete -- it still has to be + further set up for each particular transaction. + + We can't set up anything here that changes from one transaction to the + next. + + We don't bother setting up anything that has to be set up for an + asynchronous transaction because code that is common between synchronous + and asynchronous transactions takes care of that anyway. + + That leaves things, such as cookies, that don't exist for + asynchronous transactions, and are common to multiple serial + synchronous transactions. +-----------------------------------------------------------------------------*/ + CURL * const curlSessionP = curl_easy_init(); + + if (curlSessionP == NULL) + xmlrpc_faultf(envP, "Could not create Curl session. " + "curl_easy_init() failed."); + else { + /* The following is a trick. CURLOPT_COOKIEFILE is the name + of the file containing the initial cookies for the Curl + session. But setting it is also what turns on the cookie + function itself, whereby the Curl library accepts and + stores cookies from the server and sends them back on + future requests. We don't have a file of initial cookies, but + we want to turn on cookie function, so we set the option to + something we know does not validly name a file. Curl will + ignore the error and just start up cookie function with no + initial cookies. + */ + curl_easy_setopt(curlSessionP, CURLOPT_COOKIEFILE, ""); + + *curlSessionPP = curlSessionP; + } +} + + + +static void +destroySyncCurlSession(CURL * const curlSessionP) { + + curl_easy_cleanup(curlSessionP); +} + + + +static void +makeSyncCurlSession(xmlrpc_env * const envP, + struct xmlrpc_client_transport * const transportP) { + + transportP->syncCurlSessionLockP = createLock_pthread(); + if (transportP->syncCurlSessionLockP == NULL) + xmlrpc_faultf(envP, "Unable to create lock for " + "synchronous Curl session."); + else { + createSyncCurlSession(envP, &transportP->syncCurlSessionP); + if (envP->fault_occurred) + transportP->syncCurlSessionLockP->destroy( + transportP->syncCurlSessionLockP); + } +} + + + +static void +unmakeSyncCurlSession(struct xmlrpc_client_transport * const transportP) { + + destroySyncCurlSession(transportP->syncCurlSessionP); + + transportP->syncCurlSessionLockP->destroy( + transportP->syncCurlSessionLockP); +} + + + +static void +assertConstantsMatch(void) { +/*---------------------------------------------------------------------------- + There are some constants that we define as part of the Xmlrpc-c + interface that are identical to constants in the Curl interface to + make curl option setting work. This function asserts such + formally. +-----------------------------------------------------------------------------*/ + assert(XMLRPC_SSLVERSION_DEFAULT == CURL_SSLVERSION_DEFAULT); + assert(XMLRPC_SSLVERSION_TLSv1 == CURL_SSLVERSION_TLSv1); + assert(XMLRPC_SSLVERSION_SSLv2 == CURL_SSLVERSION_SSLv2); + assert(XMLRPC_SSLVERSION_SSLv3 == CURL_SSLVERSION_SSLv3); +} + + + +static void +create(xmlrpc_env * const envP, + int const flags ATTR_UNUSED, + const char * const appname ATTR_UNUSED, + const char * const appversion ATTR_UNUSED, + const struct xmlrpc_xportparms * const transportparmsP, + size_t const parm_size, + struct xmlrpc_client_transport ** const handlePP) { +/*---------------------------------------------------------------------------- + This does the 'create' operation for a Curl client transport. +-----------------------------------------------------------------------------*/ + struct xmlrpc_curl_xportparms * const curlXportParmsP = + (struct xmlrpc_curl_xportparms *) transportparmsP; + + struct xmlrpc_client_transport * transportP; + + assertConstantsMatch(); + + MALLOCVAR(transportP); + if (transportP == NULL) + xmlrpc_faultf(envP, "Unable to allocate transport descriptor."); + else { + transportP->curlMultiP = createCurlMulti(); + + if (transportP->curlMultiP == NULL) + xmlrpc_faultf(envP, "Unable to create Curl multi manager"); + else { + getXportParms(envP, curlXportParmsP, parm_size, transportP); + + if (!envP->fault_occurred) { + makeSyncCurlSession(envP, transportP); + + if (envP->fault_occurred) + freeXportParms(transportP); + } + if (envP->fault_occurred) + destroyCurlMulti(transportP->curlMultiP); + } + if (envP->fault_occurred) + free(transportP); + } + *handlePP = transportP; +} + + + +static void +assertNoOutstandingCurlWork(struct curlMulti * const curlMultiP) { + + xmlrpc_env env; + bool immediateWorkToDo; + int runningHandles; + + xmlrpc_env_init(&env); + + curlMulti_perform(&env, curlMultiP, &immediateWorkToDo, &runningHandles); + + /* We know the above was a no-op, since we're asserting that there + is no outstanding work. + */ + XMLRPC_ASSERT(!env.fault_occurred); + XMLRPC_ASSERT(!immediateWorkToDo); + XMLRPC_ASSERT(runningHandles == 0); + xmlrpc_env_clean(&env); +} + + + +static void +destroy(struct xmlrpc_client_transport * const clientTransportP) { +/*---------------------------------------------------------------------------- + This does the 'destroy' operation for a Curl client transport. +-----------------------------------------------------------------------------*/ + XMLRPC_ASSERT(clientTransportP != NULL); + + assertNoOutstandingCurlWork(clientTransportP->curlMultiP); + /* We know this is true because a condition of destroying the + transport is that there be no outstanding RPCs. + */ + unmakeSyncCurlSession(clientTransportP); + + destroyCurlMulti(clientTransportP->curlMultiP); + + freeXportParms(clientTransportP); + + free(clientTransportP); +} + + + +static void +addHeader(xmlrpc_env * const envP, + struct curl_slist ** const headerListP, + const char * const headerText) { + + struct curl_slist * newHeaderList; + newHeaderList = curl_slist_append(*headerListP, headerText); + if (newHeaderList == NULL) + xmlrpc_faultf(envP, + "Could not add header '%s'. " + "curl_slist_append() failed.", headerText); + else + *headerListP = newHeaderList; +} + + + +static void +addContentTypeHeader(xmlrpc_env * const envP, + struct curl_slist ** const headerListP) { + + addHeader(envP, headerListP, "Content-Type: text/xml"); +} + + + +static void +addUserAgentHeader(xmlrpc_env * const envP, + struct curl_slist ** const headerListP, + const char * const userAgent) { + + if (userAgent) { + curl_version_info_data * const curlInfoP = + curl_version_info(CURLVERSION_NOW); + char curlVersion[32]; + const char * userAgentHeader; + + snprintf(curlVersion, sizeof(curlVersion), "%u.%u.%u", + (curlInfoP->version_num >> 16) && 0xff, + (curlInfoP->version_num >> 8) && 0xff, + (curlInfoP->version_num >> 0) && 0xff + ); + + xmlrpc_asprintf(&userAgentHeader, + "User-Agent: %s Xmlrpc-c/%s Curl/%s", + userAgent, XMLRPC_C_VERSION, curlVersion); + + if (userAgentHeader == xmlrpc_strsol) + xmlrpc_faultf(envP, "Couldn't allocate memory for " + "User-Agent header"); + else { + addHeader(envP, headerListP, userAgentHeader); + + xmlrpc_strfree(userAgentHeader); + } + } +} + + + +static void +addAuthorizationHeader(xmlrpc_env * const envP, + struct curl_slist ** const headerListP, + const char * const basicAuthInfo) { + + if (basicAuthInfo) { + const char * authorizationHeader; + + xmlrpc_asprintf(&authorizationHeader, "Authorization: %s", + basicAuthInfo); + + if (authorizationHeader == xmlrpc_strsol) + xmlrpc_faultf(envP, "Couldn't allocate memory for " + "Authorization header"); + else { + addHeader(envP, headerListP, authorizationHeader); + + xmlrpc_strfree(authorizationHeader); + } + } +} + + + +static void +createCurlHeaderList(xmlrpc_env * const envP, + const xmlrpc_server_info * const serverP, + const char * const userAgent, + struct curl_slist ** const headerListP) { + + struct curl_slist * headerList; + + headerList = NULL; /* initial value - empty list */ + + addContentTypeHeader(envP, &headerList); + if (!envP->fault_occurred) { + addUserAgentHeader(envP, &headerList, userAgent); + if (!envP->fault_occurred) { + addAuthorizationHeader(envP, &headerList, + serverP->_http_basic_auth); + } + } + if (envP->fault_occurred) + curl_slist_free_all(headerList); + else + *headerListP = headerList; +} + + + +static void +setupCurlSession(xmlrpc_env * const envP, + curlTransaction * const curlTransactionP, + xmlrpc_mem_block * const callXmlP, + xmlrpc_mem_block * const responseXmlP, + const struct curlSetup * const curlSetupP) { +/*---------------------------------------------------------------------------- + Set up the Curl session for the transaction *curlTransactionP so that + a subsequent curl_easy_perform() will perform said transaction. +-----------------------------------------------------------------------------*/ + CURL * const curlSessionP = curlTransactionP->curlSessionP; + + assertConstantsMatch(); + + curl_easy_setopt(curlSessionP, CURLOPT_POST, 1); + curl_easy_setopt(curlSessionP, CURLOPT_URL, curlTransactionP->serverUrl); + + XMLRPC_MEMBLOCK_APPEND(char, envP, callXmlP, "\0", 1); + if (!envP->fault_occurred) { + curl_easy_setopt(curlSessionP, CURLOPT_POSTFIELDS, + XMLRPC_MEMBLOCK_CONTENTS(char, callXmlP)); + + curl_easy_setopt(curlSessionP, CURLOPT_WRITEFUNCTION, collect); + curl_easy_setopt(curlSessionP, CURLOPT_FILE, responseXmlP); + curl_easy_setopt(curlSessionP, CURLOPT_HEADER, 0); + curl_easy_setopt(curlSessionP, CURLOPT_ERRORBUFFER, + curlTransactionP->curlError); + curl_easy_setopt(curlSessionP, CURLOPT_NOPROGRESS, 1); + + curl_easy_setopt(curlSessionP, CURLOPT_HTTPHEADER, + curlTransactionP->headerList); + + curl_easy_setopt(curlSessionP, CURLOPT_SSL_VERIFYPEER, + curlSetupP->sslVerifyPeer); + curl_easy_setopt(curlSessionP, CURLOPT_SSL_VERIFYHOST, + curlSetupP->sslVerifyHost ? 2 : 0); + + if (curlSetupP->networkInterface) + curl_easy_setopt(curlSessionP, CURLOPT_INTERFACE, + curlSetupP->networkInterface); + if (curlSetupP->sslCert) + curl_easy_setopt(curlSessionP, CURLOPT_SSLCERT, + curlSetupP->sslCert); + if (curlSetupP->sslCertType) + curl_easy_setopt(curlSessionP, CURLOPT_SSLCERTTYPE, + curlSetupP->sslCertType); + if (curlSetupP->sslCertPasswd) + curl_easy_setopt(curlSessionP, CURLOPT_SSLCERTPASSWD, + curlSetupP->sslCertPasswd); + if (curlSetupP->sslKey) + curl_easy_setopt(curlSessionP, CURLOPT_SSLKEY, + curlSetupP->sslKey); + if (curlSetupP->sslKeyType) + curl_easy_setopt(curlSessionP, CURLOPT_SSLKEYTYPE, + curlSetupP->sslKeyType); + if (curlSetupP->sslKeyPasswd) + curl_easy_setopt(curlSessionP, CURLOPT_SSLKEYPASSWD, + curlSetupP->sslKeyPasswd); + if (curlSetupP->sslEngine) + curl_easy_setopt(curlSessionP, CURLOPT_SSLENGINE, + curlSetupP->sslEngine); + if (curlSetupP->sslEngineDefault) + /* 3rd argument seems to be required by some Curl */ + curl_easy_setopt(curlSessionP, CURLOPT_SSLENGINE_DEFAULT, 1l); + if (curlSetupP->sslVersion != XMLRPC_SSLVERSION_DEFAULT) + curl_easy_setopt(curlSessionP, CURLOPT_SSLVERSION, + curlSetupP->sslVersion); + if (curlSetupP->caInfo) + curl_easy_setopt(curlSessionP, CURLOPT_CAINFO, + curlSetupP->caInfo); + if (curlSetupP->caPath) + curl_easy_setopt(curlSessionP, CURLOPT_CAPATH, + curlSetupP->caPath); + if (curlSetupP->randomFile) + curl_easy_setopt(curlSessionP, CURLOPT_RANDOM_FILE, + curlSetupP->randomFile); + if (curlSetupP->egdSocket) + curl_easy_setopt(curlSessionP, CURLOPT_EGDSOCKET, + curlSetupP->egdSocket); + if (curlSetupP->sslCipherList) + curl_easy_setopt(curlSessionP, CURLOPT_SSL_CIPHER_LIST, + curlSetupP->sslCipherList); + } +} + + + +static void +createCurlTransaction(xmlrpc_env * const envP, + CURL * const curlSessionP, + struct curlMulti * const curlMultiP, + const xmlrpc_server_info * const serverP, + xmlrpc_mem_block * const callXmlP, + xmlrpc_mem_block * const responseXmlP, + const char * const userAgent, + const struct curlSetup * const curlSetupStuffP, + rpc * const rpcP, + curlTransaction ** const curlTransactionPP) { + + curlTransaction * curlTransactionP; + + MALLOCVAR(curlTransactionP); + if (curlTransactionP == NULL) + xmlrpc_faultf(envP, "No memory to create Curl transaction."); + else { + curlTransactionP->curlSessionP = curlSessionP; + curlTransactionP->curlMultiP = curlMultiP; + curlTransactionP->rpcP = rpcP; + + curlTransactionP->serverUrl = strdup(serverP->_server_url); + if (curlTransactionP->serverUrl == NULL) + xmlrpc_faultf(envP, "Out of memory to store server URL."); + else { + createCurlHeaderList(envP, serverP, userAgent, + &curlTransactionP->headerList); + + if (!envP->fault_occurred) + setupCurlSession(envP, curlTransactionP, + callXmlP, responseXmlP, + curlSetupStuffP); + + if (envP->fault_occurred) + xmlrpc_strfree(curlTransactionP->serverUrl); + } + if (envP->fault_occurred) + free(curlTransactionP); + } + *curlTransactionPP = curlTransactionP; +} + + + +static void +destroyCurlTransaction(curlTransaction * const curlTransactionP) { + + curl_slist_free_all(curlTransactionP->headerList); + xmlrpc_strfree(curlTransactionP->serverUrl); + + free(curlTransactionP); +} + + + +static void +getCurlTransactionError(curlTransaction * const curlTransactionP, + xmlrpc_env * const envP) { + + CURLcode res; + long http_result; + + res = curl_easy_getinfo(curlTransactionP->curlSessionP, + CURLINFO_HTTP_CODE, &http_result); + + if (res != CURLE_OK) + xmlrpc_env_set_fault_formatted( + envP, XMLRPC_INTERNAL_ERROR, + "Curl performed the HTTP POST request, but was " + "unable to say what the HTTP result code was. " + "curl_easy_getinfo(CURLINFO_HTTP_CODE) says: %s", + curlTransactionP->curlError); + else { + if (http_result != 200) + xmlrpc_env_set_fault_formatted( + envP, XMLRPC_NETWORK_ERROR, "HTTP response: %ld", + http_result); + } +} + + + +static void +performCurlTransaction(xmlrpc_env * const envP, + curlTransaction * const curlTransactionP) { + + CURL * const curlSessionP = curlTransactionP->curlSessionP; + + CURLcode res; + + res = curl_easy_perform(curlSessionP); + + if (res != CURLE_OK) + xmlrpc_env_set_fault_formatted( + envP, XMLRPC_NETWORK_ERROR, "Curl failed to perform " + "HTTP POST request. curl_easy_perform() says: %s", + curlTransactionP->curlError); + else + getCurlTransactionError(curlTransactionP, envP); +} + + + +static void +createRpc(xmlrpc_env * const envP, + struct xmlrpc_client_transport * const clientTransportP, + CURL * const curlSessionP, + const xmlrpc_server_info * const serverP, + xmlrpc_mem_block * const callXmlP, + xmlrpc_mem_block * const responseXmlP, + xmlrpc_transport_asynch_complete complete, + struct xmlrpc_call_info * const callInfoP, + rpc ** const rpcPP) { + + rpc * rpcP; + + MALLOCVAR(rpcP); + if (rpcP == NULL) + xmlrpc_faultf(envP, "Couldn't allocate memory for rpc object"); + else { + rpcP->callInfoP = callInfoP; + rpcP->complete = complete; + rpcP->responseXmlP = responseXmlP; + + createCurlTransaction(envP, + curlSessionP, + clientTransportP->curlMultiP, + serverP, + callXmlP, responseXmlP, + clientTransportP->userAgent, + &clientTransportP->curlSetupStuff, + rpcP, + &rpcP->curlTransactionP); + if (!envP->fault_occurred) { + if (envP->fault_occurred) + destroyCurlTransaction(rpcP->curlTransactionP); + } + if (envP->fault_occurred) + free(rpcP); + } + *rpcPP = rpcP; +} + + + +static void +destroyRpc(rpc * const rpcP) { + + XMLRPC_ASSERT_PTR_OK(rpcP); + + destroyCurlTransaction(rpcP->curlTransactionP); + + free(rpcP); +} + + + +static void +performRpc(xmlrpc_env * const envP, + rpc * const rpcP) { + + performCurlTransaction(envP, rpcP->curlTransactionP); +} + + + +static void +startCurlTransaction(xmlrpc_env * const envP, + curlTransaction * const curlTransactionP) { + + /* A Curl session is serial -- it processes zero or one transaction + at a time. We use the "private" attribute of the Curl session to + indicate which transaction it is presently processing. This is + important when the transaction finishes, because libcurl will just + tell us that something finished on a particular session, not that + a particular transaction finished. + */ + curl_easy_setopt(curlTransactionP->curlSessionP, CURLOPT_PRIVATE, + curlTransactionP); + + curlMulti_addHandle(envP, + curlTransactionP->curlMultiP, + curlTransactionP->curlSessionP); +} + + + +static void +startRpc(xmlrpc_env * const envP, + rpc * const rpcP) { + + startCurlTransaction(envP, rpcP->curlTransactionP); +} + + + +static void +sendRequest(xmlrpc_env * const envP, + struct xmlrpc_client_transport * const clientTransportP, + const xmlrpc_server_info * const serverP, + xmlrpc_mem_block * const callXmlP, + xmlrpc_transport_asynch_complete complete, + struct xmlrpc_call_info * const callInfoP) { +/*---------------------------------------------------------------------------- + Initiate an XML-RPC rpc asynchronously. Don't wait for it to go to + the server. + + Unless we return failure, we arrange to have complete() called when + the rpc completes. + + This does the 'send_request' operation for a Curl client transport. +-----------------------------------------------------------------------------*/ + rpc * rpcP; + xmlrpc_mem_block * responseXmlP; + + responseXmlP = XMLRPC_MEMBLOCK_NEW(char, envP, 0); + if (!envP->fault_occurred) { + CURL * const curlSessionP = curl_easy_init(); + + if (curlSessionP == NULL) + xmlrpc_faultf(envP, "Could not create Curl session. " + "curl_easy_init() failed."); + else { + createRpc(envP, clientTransportP, curlSessionP, serverP, + callXmlP, responseXmlP, complete, callInfoP, + &rpcP); + + if (!envP->fault_occurred) { + startRpc(envP, rpcP); + + if (envP->fault_occurred) + destroyRpc(rpcP); + } + if (envP->fault_occurred) + curl_easy_cleanup(curlSessionP); + } + if (envP->fault_occurred) + XMLRPC_MEMBLOCK_FREE(char, responseXmlP); + } + /* If we're returning success, the user's eventual finish_asynch + call will destroy this RPC, Curl session, and response buffer + and remove the Curl session from the Curl multi manager. + (If we're returning failure, we didn't create any of those). + */ +} + + + +static void +finishCurlTransaction(xmlrpc_env * const envP ATTR_UNUSED, + CURL * const curlSessionP, + CURLcode const result) { +/*---------------------------------------------------------------------------- + Handle the event that a Curl transaction has completed on the Curl + session identified by 'curlSessionP'. + + Tell the requester of the RPC which this transaction serves the + results. + + Remove the Curl session from its Curl multi manager and destroy the + Curl session, the XML response buffer, the Curl transaction, and the RPC. +-----------------------------------------------------------------------------*/ + curlTransaction * curlTransactionP; + rpc * rpcP; + + curl_easy_getinfo(curlSessionP, CURLINFO_PRIVATE, &curlTransactionP); + + rpcP = curlTransactionP->rpcP; + + curlMulti_removeHandle(curlTransactionP->curlMultiP, + curlTransactionP->curlSessionP); + { + xmlrpc_env env; + + xmlrpc_env_init(&env); + + if (result != CURLE_OK) { + xmlrpc_env_set_fault_formatted( + envP, XMLRPC_NETWORK_ERROR, "libcurl failed to execute the " + "HTTP POST transaction. %s", curlTransactionP->curlError); + } else + getCurlTransactionError(curlTransactionP, &env); + + rpcP->complete(rpcP->callInfoP, rpcP->responseXmlP, env); + + xmlrpc_env_clean(&env); + } + + curl_easy_cleanup(curlSessionP); + + XMLRPC_MEMBLOCK_FREE(char, rpcP->responseXmlP); + + destroyRpc(rpcP); +} + + + +static struct timeval +selectTimeout(xmlrpc_timeoutType const timeoutType, + struct timeval const timeoutTime) { +/*---------------------------------------------------------------------------- + Return the value that should be used in the select() call to wait for + there to be work for the Curl multi manager to do, given that the user + wants to timeout according to 'timeoutType' and 'timeoutTime'. +-----------------------------------------------------------------------------*/ + unsigned int selectTimeoutMillisec; + struct timeval retval; + + selectTimeoutMillisec = 0; // quiet compiler warning + + /* We assume there is work to do at least every 3 seconds, because + the Curl multi manager often has retries and other scheduled work + that doesn't involve file handles on which we can select(). + */ + switch (timeoutType) { + case timeout_no: + selectTimeoutMillisec = 3000; + break; + case timeout_yes: { + struct timeval nowTime; + int timeLeft; + + gettimeofday(&nowTime, NULL); + timeLeft = timeDiffMillisec(timeoutTime, nowTime); + + selectTimeoutMillisec = MIN(3000, MAX(0, timeLeft)); + } + break; + } + retval.tv_sec = selectTimeoutMillisec / 1000; + retval.tv_usec = (selectTimeoutMillisec % 1000) * 1000; + + return retval; +} + + + +static void +processCurlMessages(xmlrpc_env * const envP, + struct curlMulti * const curlMultiP) { + + bool endOfMessages; + + endOfMessages = false; /* initial assumption */ + + while (!endOfMessages && !envP->fault_occurred) { + CURLMsg curlMsg; + + curlMulti_getMessage(curlMultiP, &endOfMessages, &curlMsg); + + if (!endOfMessages) { + if (curlMsg.msg == CURLMSG_DONE) + finishCurlTransaction(envP, curlMsg.easy_handle, + curlMsg.data.result); + } + } +} + + + +static void +waitForWork(xmlrpc_env * const envP, + struct curlMulti * const curlMultiP, + xmlrpc_timeoutType const timeoutType, + struct timeval const deadline) { + + fd_set readFdSet; + fd_set writeFdSet; + fd_set exceptFdSet; + int maxFd; + + curlMulti_fdset(envP, curlMultiP, + &readFdSet, &writeFdSet, &exceptFdSet, &maxFd); + if (!envP->fault_occurred) { + if (maxFd == -1) { + /* There are no Curl file descriptors on which to wait. + So either there's work to do right now or all transactions + are already complete. + */ + } else { + struct timeval selectTimeoutArg; + int rc; + + selectTimeoutArg = selectTimeout(timeoutType, deadline); + + rc = select(maxFd+1, &readFdSet, &writeFdSet, &exceptFdSet, + &selectTimeoutArg); + + if (rc < 0) + xmlrpc_faultf(envP, "Impossible failure of select() " + "with errno %d (%s)", + errno, strerror(errno)); + else { + /* Believe it or not, the Curl multi manager needs the + results of our select(). So hand them over: + */ + curlMulti_updateFdSet(curlMultiP, + readFdSet, writeFdSet, exceptFdSet); + } + } + } +} + + + +static void +doCurlWork(xmlrpc_env * const envP, + struct curlMulti * const curlMultiP, + bool * const rpcStillRunningP) { +/*---------------------------------------------------------------------------- + Do whatever work is ready to be done by the Curl multi manager + identified by 'curlMultiP'. This typically is transferring data on + an HTTP connection because the server is ready. + + Return *rpcStillRunningP false if this work completes all of the + manager's transactions so that there is no reason to call us ever + again. + + Where the multi manager completes an HTTP transaction, also complete + the associated RPC. +-----------------------------------------------------------------------------*/ + bool immediateWorkToDo; + int runningHandles; + + immediateWorkToDo = true; /* initial assumption */ + + while (immediateWorkToDo && !envP->fault_occurred) { + curlMulti_perform(envP, curlMultiP, + &immediateWorkToDo, &runningHandles); + } + + /* We either did all the work that's ready to do or hit an error. */ + + if (!envP->fault_occurred) { + /* The work we did may have resulted in asynchronous messages + (asynchronous to the thing the refer to, not to us, of course). + In particular the message "Curl transaction has completed". + So we process those now. + */ + processCurlMessages(envP, curlMultiP); + + *rpcStillRunningP = runningHandles > 0; + } +} + + + +static void +finishCurlSessions(xmlrpc_env * const envP, + struct curlMulti * const curlMultiP, + xmlrpc_timeoutType const timeoutType, + struct timeval const deadline) { + + bool rpcStillRunning; + bool timedOut; + + rpcStillRunning = true; /* initial assumption */ + timedOut = false; + + while (rpcStillRunning && !timedOut && !envP->fault_occurred) { + waitForWork(envP, curlMultiP, timeoutType, deadline); + + if (!envP->fault_occurred) { + struct timeval nowTime; + + doCurlWork(envP, curlMultiP, &rpcStillRunning); + + gettimeofday(&nowTime, NULL); + + timedOut = (timeoutType == timeout_yes && + timeIsAfter(nowTime, deadline)); + } + } +} + + + +static void +finishAsynch( + struct xmlrpc_client_transport * const clientTransportP, + xmlrpc_timeoutType const timeoutType, + xmlrpc_timeout const timeout) { +/*---------------------------------------------------------------------------- + Wait for the Curl multi manager to finish the Curl transactions for + all outstanding RPCs and destroy those RPCs. + + This does the 'finish_asynch' operation for a Curl client transport. + + It would be cool to replace this with something analogous to the + Curl asynchronous interface: Have something like curl_multi_fdset() + that returns a bunch of file descriptors on which the user can wait + (along with possibly other file descriptors of his own) and + something like curl_multi_perform() to finish whatever RPCs are + ready to finish at that moment. The implementation would be little + more than wrapping curl_multi_fdset() and curl_multi_perform(). +-----------------------------------------------------------------------------*/ + xmlrpc_env env; + + struct timeval waitTimeoutTime; + /* The datetime after which we should quit waiting */ + + xmlrpc_env_init(&env); + + if (timeoutType == timeout_yes) { + struct timeval waitStartTime; + gettimeofday(&waitStartTime, NULL); + addMilliseconds(waitStartTime, timeout, &waitTimeoutTime); + } + + finishCurlSessions(&env, clientTransportP->curlMultiP, + timeoutType, waitTimeoutTime); + + /* If the above fails, it is catastrophic, because it means there is + no way to complete outstanding Curl transactions and RPCs, and + no way to release their resources. + + We should at least expand this interface some day to push the + problem back up the user, but for now we just do this Hail Mary + response. + + Note that a failure of finishCurlSessions() does not mean that + a session completed with an error or an RPC completed with an + error. Those things are reported up through the user's + xmlrpc_transport_asynch_complete routine. A failure here is + something that stopped us from calling that. + */ + + if (env.fault_occurred) + fprintf(stderr, "finishAsync() failed. Xmlrpc-c Curl transport " + "is now in an unknown state and may not be able to " + "continue functioning. Specifics of the failure: %s\n", + env.fault_string); + + xmlrpc_env_clean(&env); +} + + + +static void +call(xmlrpc_env * const envP, + struct xmlrpc_client_transport * const clientTransportP, + const xmlrpc_server_info * const serverP, + xmlrpc_mem_block * const callXmlP, + xmlrpc_mem_block ** const responseXmlPP) { + + xmlrpc_mem_block * responseXmlP; + rpc * rpcP; + + XMLRPC_ASSERT_ENV_OK(envP); + XMLRPC_ASSERT_PTR_OK(serverP); + XMLRPC_ASSERT_PTR_OK(callXmlP); + XMLRPC_ASSERT_PTR_OK(responseXmlPP); + + responseXmlP = XMLRPC_MEMBLOCK_NEW(char, envP, 0); + if (!envP->fault_occurred) { + /* Only one RPC at a time can use a Curl session, so we have to + hold the lock as long as our RPC exists. + */ + lockSyncCurlSession(clientTransportP); + createRpc(envP, clientTransportP, clientTransportP->syncCurlSessionP, + serverP, + callXmlP, responseXmlP, + NULL, NULL, + &rpcP); + + if (!envP->fault_occurred) { + performRpc(envP, rpcP); + + *responseXmlPP = responseXmlP; + + destroyRpc(rpcP); + } + unlockSyncCurlSession(clientTransportP); + if (envP->fault_occurred) + XMLRPC_MEMBLOCK_FREE(char, responseXmlP); + } +} + + + +static void +setupGlobalConstants(xmlrpc_env * const envP) { +/*---------------------------------------------------------------------------- + See longwinded discussion of the global constant issue at the top of + this file. +-----------------------------------------------------------------------------*/ + initWindowsStuff(envP); + + if (!envP->fault_occurred) { + CURLcode rc; + + rc = curl_global_init(CURL_GLOBAL_ALL); + + if (rc != CURLE_OK) + xmlrpc_faultf(envP, "curl_global_init() failed with code %d", rc); + } +} + + + +static void +teardownGlobalConstants(void) { +/*---------------------------------------------------------------------------- + See longwinded discussionof the global constant issue at the top of + this file. +-----------------------------------------------------------------------------*/ + curl_global_cleanup(); + + termWindowsStuff(); +} + + + +struct xmlrpc_client_transport_ops xmlrpc_curl_transport_ops = { + &setupGlobalConstants, + &teardownGlobalConstants, + &create, + &destroy, + &sendRequest, + &call, + &finishAsynch, +}; diff --git a/lib/curl_transport/xmlrpc_curl_transport.h b/lib/curl_transport/xmlrpc_curl_transport.h new file mode 100644 index 0000000..1425add --- /dev/null +++ b/lib/curl_transport/xmlrpc_curl_transport.h @@ -0,0 +1,8 @@ +#ifndef XMLRPC_CURL_TRANSPORT_H +#define XMLRPC_CURL_TRANSPORT_H + +#include "xmlrpc-c/transport.h" + +extern struct xmlrpc_client_transport_ops xmlrpc_curl_transport_ops; + +#endif diff --git a/lib/expat/Makefile b/lib/expat/Makefile new file mode 100644 index 0000000..7a85187 --- /dev/null +++ b/lib/expat/Makefile @@ -0,0 +1,36 @@ +ifeq ($(SRCDIR)x,x) +SRCDIR = $(CURDIR)/../.. +endif +SUBDIR = lib/expat + +include $(SRCDIR)/Makefile.config + +# Build up SUBDIRS: +SUBDIRS = gennmtab xmlparse xmltok + +default: all + +.PHONY: all clean distclean tags distdir intall check dep + +all: $(SUBDIRS:%=%/all) + +clean: $(SUBDIRS:%=%/clean) clean-common + +distclean: $(SUBDIRS:%=%/distclean) distclean-common + +tags: $(SUBDIRS:%=%/tags) TAGS + +DISTFILES = + +distdir: distdir-common + +install: $(SUBDIRS:%=%/install) + +check: + +dep: $(SUBDIRS:%=%/dep) + +include $(SRCDIR)/Makefile.common + + + diff --git a/lib/expat/Makefile.depend b/lib/expat/Makefile.depend new file mode 100644 index 0000000..e69de29 diff --git a/lib/expat/expat.dsw b/lib/expat/expat.dsw new file mode 100644 index 0000000..b57c9a8 --- /dev/null +++ b/lib/expat/expat.dsw @@ -0,0 +1,75 @@ +Microsoft Developer Studio Workspace File, Format Version 6.00 +# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! + +############################################################################### + +Project: "gennmtab"=".\gennmtab\gennmtab.dsp" - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "xmlparse"=".\xmlparse\xmlparse.dsp" - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ + Begin Project Dependency + Project_Dep_Name xmltok + End Project Dependency +}}} + +############################################################################### + +Project: "xmltok"=".\xmltok\xmltok.dsp" - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ + Begin Project Dependency + Project_Dep_Name gennmtab + End Project Dependency +}}} + +############################################################################### + +Project: "xmlwf"=".\xmlwf\xmlwf.dsp" - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ + Begin Project Dependency + Project_Dep_Name xmlparse + Project_Dep_Name xmltok + End Project Dependency +}}} + +############################################################################### + +Global: + +Package=<5> +{{{ +}}} + +Package=<3> +{{{ +}}} + +############################################################################### + diff --git a/lib/expat/expat.html b/lib/expat/expat.html new file mode 100644 index 0000000..22216b6 --- /dev/null +++ b/lib/expat/expat.html @@ -0,0 +1,86 @@ + + + + +expat + + + +

expat - XML Parser Toolkit

+ +

Version 1.2

+ +

Copyright (c) 1998, 1999, 2000 Thai Open Source Software Center +Ltd. Expat is freely available with source under a very liberal license (the MIT license).

+ +

This is a production version of expat. Relative to expat 1.1, it +adds support for parsing external DTDs and parameter entities. +Compiling with -DXML_DTD enables this support. There's a new +-p option for xmlwf which will cause it to process +external DTDs and parameter entities; this implies the -x +option. See the comment above XML_SetParamEntityParsing +in xmlparse.h for the API addition that enables this.

+ +

Expat is an XML 1.0 parser +written in C. It aims to be fully conforming. It is currently not a +validating XML processor. The current production version of expat 1.X +can be downloaded from ftp://ftp.jclark.com/pub/xml/expat.zip.

+ +

Development of expat 2.0 is being handled by a team led by Clark +Cooper, hosted by sourceforge.net. See http://expat.sourceforge.net for +the latest on expat 2.0.

+ +

The directory xmltok contains a low-level library for +tokenizing XML. The interface is documented in +xmltok/xmltok.h.

+ +

The directory xmlparse contains an XML parser library +which is built on top of the xmltok library. The +interface is documented in xmlparse/xmlparse.h. The +directory sample contains a simple example program using +this interface; sample/build.bat is a batch file to build +the example using Visual C++.

+ +

The directory xmlwf contains the xmlwf +application, which uses the xmlparse library. The +arguments to xmlwf are one or more files which are each +to be checked for well-formedness. An option -d +dir can be specified; for each well-formed input +file the corresponding canonical XML will +be written to dir/f, where +f is the filename (without any path) of the +input file. A -x option will cause references to +external general entities to be processed. A -s option +will make documents that are not standalone cause an error (a document +is considered standalone if either it is intrinsically standalone +because it has no external subset and no references to parameter +entities in the internal subset or it is declared as standalone in the +XML declaration).

+ +

The bin directory contains Win32 executables. The +lib directory contains Win32 import libraries.

+ +

Answers to some frequently asked questions about expat can be found +in the expat +FAQ.

+ +

+ +
+ +James Clark + +
+ + + + diff --git a/lib/expat/gennmtab/.cvsignore b/lib/expat/gennmtab/.cvsignore new file mode 100644 index 0000000..b1f2027 --- /dev/null +++ b/lib/expat/gennmtab/.cvsignore @@ -0,0 +1 @@ +gennmtab diff --git a/lib/expat/gennmtab/Makefile b/lib/expat/gennmtab/Makefile new file mode 100644 index 0000000..03891e9 --- /dev/null +++ b/lib/expat/gennmtab/Makefile @@ -0,0 +1,45 @@ +ifeq ($(SRCDIR)x,x) +SRCDIR = $(CURDIR)/../../.. +endif + +include $(SRCDIR)/Makefile.config + +CFLAGS = $(CFLAGS_COMMON) $(CFLAGS_PERSONAL) $(CADD) + +LDFLAGS = $(LADD) + +INCLUDES = -I$(SRCDIR) -I$(SRCDIR)/lib/util/include + +default: all + +include $(SRCDIR)/Makefile.common + +.PHONY: all +all: gennmtab + +.PHONY: clean +clean: clean-common + rm -f gennmtab + +.PHONY: distclean +distclean: clean distclean-common + +.PHONY: tags +tags: TAGS + +.PHONY: distdir +distdir: + +.PHONY: install +install: + +.PHONY: dep +dep: dep-common + +gennmtab.o:%.o:%.c + $(BUILDTOOL_CC) -c $< -o $@ $(CFLAGS) $(INCLUDES) + +gennmtab:%:%.o + $(BUILDTOOL_CCLD) -o $@ $(LDFLAGS) $^ + +include Makefile.depend diff --git a/lib/expat/gennmtab/Makefile.depend b/lib/expat/gennmtab/Makefile.depend new file mode 100644 index 0000000..e69de29 diff --git a/lib/expat/gennmtab/gennmtab.c b/lib/expat/gennmtab/gennmtab.c new file mode 100644 index 0000000..c6bdb7d --- /dev/null +++ b/lib/expat/gennmtab/gennmtab.c @@ -0,0 +1,433 @@ +/* +Copyright (c) 1998, 1999 Thai Open Source Software Center Ltd +See the file copying.txt for copying permission. +*/ + +#include +#include +#include + +#include "xmlrpc_config.h" + +struct range { + int start; + int end; +}; + +struct range nmstrt[] = { + { '_', 0 }, + { ':', 0 }, + /* BaseChar */ + { 0x0041, 0x005a }, + { 0x0061, 0x007a }, + { 0x00c0, 0x00d6 }, + { 0x00d8, 0x00f6 }, + { 0x00f8, 0x00ff }, + { 0x0100, 0x0131 }, + { 0x0134, 0x013e }, + { 0x0141, 0x0148 }, + { 0x014a, 0x017e }, + { 0x0180, 0x01c3 }, + { 0x01cd, 0x01f0 }, + { 0x01f4, 0x01f5 }, + { 0x01fa, 0x0217 }, + { 0x0250, 0x02a8 }, + { 0x02bb, 0x02c1 }, + { 0x0386, 0 }, + { 0x0388, 0x038a }, + { 0x038c, 0 }, + { 0x038e, 0x03a1 }, + { 0x03a3, 0x03ce }, + { 0x03d0, 0x03d6 }, + { 0x03da, 0 }, + { 0x03dc, 0 }, + { 0x03de, 0 }, + { 0x03e0, 0 }, + { 0x03e2, 0x03f3 }, + { 0x0401, 0x040c }, + { 0x040e, 0x044f }, + { 0x0451, 0x045c }, + { 0x045e, 0x0481 }, + { 0x0490, 0x04c4 }, + { 0x04c7, 0x04c8 }, + { 0x04cb, 0x04cc }, + { 0x04d0, 0x04eb }, + { 0x04ee, 0x04f5 }, + { 0x04f8, 0x04f9 }, + { 0x0531, 0x0556 }, + { 0x0559, 0 }, + { 0x0561, 0x0586 }, + { 0x05d0, 0x05ea }, + { 0x05f0, 0x05f2 }, + { 0x0621, 0x063a }, + { 0x0641, 0x064a }, + { 0x0671, 0x06b7 }, + { 0x06ba, 0x06be }, + { 0x06c0, 0x06ce }, + { 0x06d0, 0x06d3 }, + { 0x06d5, 0 }, + { 0x06e5, 0x06e6 }, + { 0x0905, 0x0939 }, + { 0x093d, 0 }, + { 0x0958, 0x0961 }, + { 0x0985, 0x098c }, + { 0x098f, 0x0990 }, + { 0x0993, 0x09a8 }, + { 0x09aa, 0x09b0 }, + { 0x09b2, 0 }, + { 0x09b6, 0x09b9 }, + { 0x09dc, 0x09dd }, + { 0x09df, 0x09e1 }, + { 0x09f0, 0x09f1 }, + { 0x0a05, 0x0a0a }, + { 0x0a0f, 0x0a10 }, + { 0x0a13, 0x0a28 }, + { 0x0a2a, 0x0a30 }, + { 0x0a32, 0x0a33 }, + { 0x0a35, 0x0a36 }, + { 0x0a38, 0x0a39 }, + { 0x0a59, 0x0a5c }, + { 0x0a5e, 0 }, + { 0x0a72, 0x0a74 }, + { 0x0a85, 0x0a8b }, + { 0x0a8d, 0 }, + { 0x0a8f, 0x0a91 }, + { 0x0a93, 0x0aa8 }, + { 0x0aaa, 0x0ab0 }, + { 0x0ab2, 0x0ab3 }, + { 0x0ab5, 0x0ab9 }, + { 0x0abd, 0 }, + { 0x0ae0, 0 }, + { 0x0b05, 0x0b0c }, + { 0x0b0f, 0x0b10 }, + { 0x0b13, 0x0b28 }, + { 0x0b2a, 0x0b30 }, + { 0x0b32, 0x0b33 }, + { 0x0b36, 0x0b39 }, + { 0x0b3d, 0 }, + { 0x0b5c, 0x0b5d }, + { 0x0b5f, 0x0b61 }, + { 0x0b85, 0x0b8a }, + { 0x0b8e, 0x0b90 }, + { 0x0b92, 0x0b95 }, + { 0x0b99, 0x0b9a }, + { 0x0b9c, 0 }, + { 0x0b9e, 0x0b9f }, + { 0x0ba3, 0x0ba4 }, + { 0x0ba8, 0x0baa }, + { 0x0bae, 0x0bb5 }, + { 0x0bb7, 0x0bb9 }, + { 0x0c05, 0x0c0c }, + { 0x0c0e, 0x0c10 }, + { 0x0c12, 0x0c28 }, + { 0x0c2a, 0x0c33 }, + { 0x0c35, 0x0c39 }, + { 0x0c60, 0x0c61 }, + { 0x0c85, 0x0c8c }, + { 0x0c8e, 0x0c90 }, + { 0x0c92, 0x0ca8 }, + { 0x0caa, 0x0cb3 }, + { 0x0cb5, 0x0cb9 }, + { 0x0cde, 0 }, + { 0x0ce0, 0x0ce1 }, + { 0x0d05, 0x0d0c }, + { 0x0d0e, 0x0d10 }, + { 0x0d12, 0x0d28 }, + { 0x0d2a, 0x0d39 }, + { 0x0d60, 0x0d61 }, + { 0x0e01, 0x0e2e }, + { 0x0e30, 0 }, + { 0x0e32, 0x0e33 }, + { 0x0e40, 0x0e45 }, + { 0x0e81, 0x0e82 }, + { 0x0e84, 0 }, + { 0x0e87, 0x0e88 }, + { 0x0e8a, 0 }, + { 0x0e8d, 0 }, + { 0x0e94, 0x0e97 }, + { 0x0e99, 0x0e9f }, + { 0x0ea1, 0x0ea3 }, + { 0x0ea5, 0 }, + { 0x0ea7, 0 }, + { 0x0eaa, 0x0eab }, + { 0x0ead, 0x0eae }, + { 0x0eb0, 0 }, + { 0x0eb2, 0x0eb3 }, + { 0x0ebd, 0 }, + { 0x0ec0, 0x0ec4 }, + { 0x0f40, 0x0f47 }, + { 0x0f49, 0x0f69 }, + { 0x10a0, 0x10c5 }, + { 0x10d0, 0x10f6 }, + { 0x1100, 0 }, + { 0x1102, 0x1103 }, + { 0x1105, 0x1107 }, + { 0x1109, 0 }, + { 0x110b, 0x110c }, + { 0x110e, 0x1112 }, + { 0x113c, 0 }, + { 0x113e, 0 }, + { 0x1140, 0 }, + { 0x114c, 0 }, + { 0x114e, 0 }, + { 0x1150, 0 }, + { 0x1154, 0x1155 }, + { 0x1159, 0 }, + { 0x115f, 0x1161 }, + { 0x1163, 0 }, + { 0x1165, 0 }, + { 0x1167, 0 }, + { 0x1169, 0 }, + { 0x116d, 0x116e }, + { 0x1172, 0x1173 }, + { 0x1175, 0 }, + { 0x119e, 0 }, + { 0x11a8, 0 }, + { 0x11ab, 0 }, + { 0x11ae, 0x11af }, + { 0x11b7, 0x11b8 }, + { 0x11ba, 0 }, + { 0x11bc, 0x11c2 }, + { 0x11eb, 0 }, + { 0x11f0, 0 }, + { 0x11f9, 0 }, + { 0x1e00, 0x1e9b }, + { 0x1ea0, 0x1ef9 }, + { 0x1f00, 0x1f15 }, + { 0x1f18, 0x1f1d }, + { 0x1f20, 0x1f45 }, + { 0x1f48, 0x1f4d }, + { 0x1f50, 0x1f57 }, + { 0x1f59, 0 }, + { 0x1f5b, 0 }, + { 0x1f5d, 0 }, + { 0x1f5f, 0x1f7d }, + { 0x1f80, 0x1fb4 }, + { 0x1fb6, 0x1fbc }, + { 0x1fbe, 0 }, + { 0x1fc2, 0x1fc4 }, + { 0x1fc6, 0x1fcc }, + { 0x1fd0, 0x1fd3 }, + { 0x1fd6, 0x1fdb }, + { 0x1fe0, 0x1fec }, + { 0x1ff2, 0x1ff4 }, + { 0x1ff6, 0x1ffc }, + { 0x2126, 0 }, + { 0x212a, 0x212b }, + { 0x212e, 0 }, + { 0x2180, 0x2182 }, + { 0x3041, 0x3094 }, + { 0x30a1, 0x30fa }, + { 0x3105, 0x312c }, + { 0xac00, 0xd7a3 }, + /* Ideographic */ + { 0x4e00, 0x9fa5 }, + { 0x3007, 0 }, + { 0x3021, 0x3029 }, +}; + +/* name chars that are not name start chars */ +struct range name[] = { + { '.', 0 }, + { '-', 0 }, + /* CombiningChar */ + { 0x0300, 0x0345 }, + { 0x0360, 0x0361 }, + { 0x0483, 0x0486 }, + { 0x0591, 0x05a1 }, + { 0x05a3, 0x05b9 }, + { 0x05bb, 0x05bd }, + { 0x05bf, 0 }, + { 0x05c1, 0x05c2 }, + { 0x05c4, 0 }, + { 0x064b, 0x0652 }, + { 0x0670, 0 }, + { 0x06d6, 0x06dc }, + { 0x06dd, 0x06df }, + { 0x06e0, 0x06e4 }, + { 0x06e7, 0x06e8 }, + { 0x06ea, 0x06ed }, + { 0x0901, 0x0903 }, + { 0x093c, 0 }, + { 0x093e, 0x094c }, + { 0x094d, 0 }, + { 0x0951, 0x0954 }, + { 0x0962, 0x0963 }, + { 0x0981, 0x0983 }, + { 0x09bc, 0 }, + { 0x09be, 0 }, + { 0x09bf, 0 }, + { 0x09c0, 0x09c4 }, + { 0x09c7, 0x09c8 }, + { 0x09cb, 0x09cd }, + { 0x09d7, 0 }, + { 0x09e2, 0x09e3 }, + { 0x0a02, 0 }, + { 0x0a3c, 0 }, + { 0x0a3e, 0 }, + { 0x0a3f, 0 }, + { 0x0a40, 0x0a42 }, + { 0x0a47, 0x0a48 }, + { 0x0a4b, 0x0a4d }, + { 0x0a70, 0x0a71 }, + { 0x0a81, 0x0a83 }, + { 0x0abc, 0 }, + { 0x0abe, 0x0ac5 }, + { 0x0ac7, 0x0ac9 }, + { 0x0acb, 0x0acd }, + { 0x0b01, 0x0b03 }, + { 0x0b3c, 0 }, + { 0x0b3e, 0x0b43 }, + { 0x0b47, 0x0b48 }, + { 0x0b4b, 0x0b4d }, + { 0x0b56, 0x0b57 }, + { 0x0b82, 0x0b83 }, + { 0x0bbe, 0x0bc2 }, + { 0x0bc6, 0x0bc8 }, + { 0x0bca, 0x0bcd }, + { 0x0bd7, 0 }, + { 0x0c01, 0x0c03 }, + { 0x0c3e, 0x0c44 }, + { 0x0c46, 0x0c48 }, + { 0x0c4a, 0x0c4d }, + { 0x0c55, 0x0c56 }, + { 0x0c82, 0x0c83 }, + { 0x0cbe, 0x0cc4 }, + { 0x0cc6, 0x0cc8 }, + { 0x0cca, 0x0ccd }, + { 0x0cd5, 0x0cd6 }, + { 0x0d02, 0x0d03 }, + { 0x0d3e, 0x0d43 }, + { 0x0d46, 0x0d48 }, + { 0x0d4a, 0x0d4d }, + { 0x0d57, 0 }, + { 0x0e31, 0 }, + { 0x0e34, 0x0e3a }, + { 0x0e47, 0x0e4e }, + { 0x0eb1, 0 }, + { 0x0eb4, 0x0eb9 }, + { 0x0ebb, 0x0ebc }, + { 0x0ec8, 0x0ecd }, + { 0x0f18, 0x0f19 }, + { 0x0f35, 0 }, + { 0x0f37, 0 }, + { 0x0f39, 0 }, + { 0x0f3e, 0 }, + { 0x0f3f, 0 }, + { 0x0f71, 0x0f84 }, + { 0x0f86, 0x0f8b }, + { 0x0f90, 0x0f95 }, + { 0x0f97, 0 }, + { 0x0f99, 0x0fad }, + { 0x0fb1, 0x0fb7 }, + { 0x0fb9, 0 }, + { 0x20d0, 0x20dc }, + { 0x20e1, 0 }, + { 0x302a, 0x302f }, + { 0x3099, 0 }, + { 0x309a, 0 }, + /* Digit */ + { 0x0030, 0x0039 }, + { 0x0660, 0x0669 }, + { 0x06f0, 0x06f9 }, + { 0x0966, 0x096f }, + { 0x09e6, 0x09ef }, + { 0x0a66, 0x0a6f }, + { 0x0ae6, 0x0aef }, + { 0x0b66, 0x0b6f }, + { 0x0be7, 0x0bef }, + { 0x0c66, 0x0c6f }, + { 0x0ce6, 0x0cef }, + { 0x0d66, 0x0d6f }, + { 0x0e50, 0x0e59 }, + { 0x0ed0, 0x0ed9 }, + { 0x0f20, 0x0f29 }, + /* Extender */ + { 0xb7 , 0 }, + { 0x02d0, 0 }, + { 0x02d1, 0 }, + { 0x0387, 0 }, + { 0x0640, 0 }, + { 0x0e46, 0 }, + { 0x0ec6, 0 }, + { 0x3005, 0 }, + { 0x3031, 0x3035 }, + { 0x309d, 0x309e }, + { 0x30fc, 0x30fe }, +}; + +static void +setTab(char *tab, struct range *ranges, size_t nRanges) +{ + size_t i; + int j; + for (i = 0; i < nRanges; i++) { + if (ranges[i].end) { + for (j = ranges[i].start; j <= ranges[i].end; j++) + tab[j] = 1; + } + else + tab[ranges[i].start] = 1; + } +} + +static void +printTabs(char *tab) +{ + int nBitmaps = 2; + int i, j, k; + unsigned char pageIndex[512]; + + printf( +"static const unsigned namingBitmap[] = {\n\ +0x00000000, 0x00000000, 0x00000000, 0x00000000,\n\ +0x00000000, 0x00000000, 0x00000000, 0x00000000,\n\ +0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,\n\ +0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,\n"); + for (i = 0; i < 512; i++) { + int kind = tab[i*256]; + for (j = 1; j < 256; j++) + if (tab[i*256 +j] != kind) { + kind = -1; + break; + } + if (i >= 256 && memcmp(tab + (i - 256)*256, tab + i*256, 256) == 0) + pageIndex[i] = pageIndex[i - 256]; + else if (kind == -1) { + pageIndex[i] = nBitmaps++; + for (j = 0; j < 8; j++) { + unsigned val = 0; + for (k = 0; k < 32; k++) { + if (tab[i*256 + j*32 +k]) + val |= (1 << k); + } + printf("0x%08X,", val); + putchar((((j + 1) & 3) == 0) ? '\n' : ' '); + } + } + else + pageIndex[i] = kind; + } + printf("};\n"); + printf("static const unsigned char nmstrtPages[] = {\n"); + for (i = 0; i < 512; i++) { + if (i == 256) + printf("};\nstatic const unsigned char namePages[] = {\n"); + printf("0x%02X,", pageIndex[i]); + putchar((((i + 1) & 7) == 0) ? '\n' : ' '); + } + printf("};\n"); +} + +int +main(int const argc ATTR_UNUSED, + char ** const argv ATTR_UNUSED) { + + char tab[2*65536]; + memset(tab, 0, 65536); + setTab(tab, nmstrt, sizeof(nmstrt)/sizeof(nmstrt[0])); + memcpy(tab + 65536, tab, 65536); + setTab(tab + 65536, name, sizeof(name)/sizeof(name[0])); + printTabs(tab); + return 0; +} diff --git a/lib/expat/gennmtab/gennmtab.dsp b/lib/expat/gennmtab/gennmtab.dsp new file mode 100644 index 0000000..917dc44 --- /dev/null +++ b/lib/expat/gennmtab/gennmtab.dsp @@ -0,0 +1,110 @@ +# Microsoft Developer Studio Project File - Name="gennmtab" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + +CFG=gennmtab - Win32 Release +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "gennmtab.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "gennmtab.mak" CFG="gennmtab - Win32 Release" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "gennmtab - Win32 Release" (based on "Win32 (x86) Console Application") +!MESSAGE "gennmtab - Win32 Debug" (based on "Win32 (x86) Console Application") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "gennmtab" +# PROP Scc_LocalPath "." +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "gennmtab - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir ".\Release" +# PROP BASE Intermediate_Dir ".\Release" +# PROP BASE Target_Dir "." +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release\gennmtab" +# PROP Intermediate_Dir "Release\gennmtab" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "." +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /YX /c +# ADD CPP /nologo /MD /W3 /GX /O2 /I "..\..\.." /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /YX /FD /c +# ADD BASE RSC /l 0x809 /d "NDEBUG" +# ADD RSC /l 0x809 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 /out:"..\..\..\Bin\gennmtab.exe" +# Begin Special Build Tool +SOURCE="$(InputPath)" +PostBuild_Cmds=..\..\..\Bin\gennmtab.exe >..\xmltok\nametab.h +# End Special Build Tool + +!ELSEIF "$(CFG)" == "gennmtab - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir ".\Debug" +# PROP BASE Intermediate_Dir ".\Debug" +# PROP BASE Target_Dir "." +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug\gennmtab" +# PROP Intermediate_Dir "Debug\gennmtab" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "." +# ADD BASE CPP /nologo /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /YX /c +# ADD CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /I "..\..\.." /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /YX /FD /c +# ADD BASE RSC /l 0x809 /d "_DEBUG" +# ADD RSC /l 0x809 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /out:"..\..\..\Bin\gennmtabD.exe" +# Begin Special Build Tool +SOURCE="$(InputPath)" +PostBuild_Cmds=..\..\..\Bin\gennmtabD.exe >..\xmltok\nametab.h +# End Special Build Tool + +!ENDIF + +# Begin Target + +# Name "gennmtab - Win32 Release" +# Name "gennmtab - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat;for;f90" +# Begin Source File + +SOURCE=.\gennmtab.c +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl;fi;fd" +# End Group +# Begin Group "Resource Files" + +# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;cnt;rtf;gif;jpg;jpeg;jpe" +# End Group +# End Target +# End Project diff --git a/lib/expat/xmlparse/Makefile b/lib/expat/xmlparse/Makefile new file mode 100644 index 0000000..96c0be8 --- /dev/null +++ b/lib/expat/xmlparse/Makefile @@ -0,0 +1,57 @@ +ifeq ($(SRCDIR)x,x) +SRCDIR = $(CURDIR)/../../.. +endif +SUBDIR = lib/expat/xmlparse +# BLDDIR is for use in places where a symbolic link won't work. +# BUILDDIR is for places in Makefile.common that can use the 'blddir' +# symbolic link (but in other directories, doesn't). +BLDDIR = ../../.. +BUILDDIR = blddir +VPATH = .:$(SRCDIR) + +XMLTOKDIR = ../xmltok +UTILDIR = $(SRCDIR)/lib/util + +include $(BLDDIR)/Makefile.config + +default: all + +all: libxmlrpc_xmlparse.la + +LIBXMLRPC_XMLPARSE_OBJS = xmlparse.lo + +INCLUDES = -Iblddir -I$(SRCDIR) -I$(UTILDIR)/include -I$(XMLTOKDIR) + +LDFLAGS = $(LADD) + +LIBLDFLAGS = $(LDFLAGS_VERSINFO) -rpath $(LIBINST_DIR) $(LADD) + +libxmlrpc_xmlparse.la: $(LIBXMLRPC_XMLPARSE_OBJS) + $(LIBTOOL) --mode=link $(CCLD) -o $@ $(LIBLDFLAGS) $^ + +CFLAGS = $(CFLAGS_COMMON) $(CFLAGS_PERSONAL) $(CADD) + +$(LIBXMLRPC_XMLPARSE_OBJS):%.lo:%.c + $(LIBTOOL) --mode=compile $(CC) -c $(INCLUDES) $(CFLAGS) $< + +LTLIBRARIES_TO_INSTALL = libxmlrpc_xmlparse.la + +.PHONY: install +install: install-common + +.PHONY: clean distclean +clean: clean-common + +distclean: clean distclean-common + +.PHONY: dep +dep: dep-common + +# This 'Makefile.common' dependency makes sure the symlinks get built before +# this make file is used for anything. + +$(SRCDIR)/Makefile.common: srcdir blddir + +include $(SRCDIR)/Makefile.common + +include Makefile.depend diff --git a/lib/expat/xmlparse/Makefile.depend b/lib/expat/xmlparse/Makefile.depend new file mode 100644 index 0000000..e69de29 diff --git a/lib/expat/xmlparse/xmlparse.c b/lib/expat/xmlparse/xmlparse.c new file mode 100644 index 0000000..abe9874 --- /dev/null +++ b/lib/expat/xmlparse/xmlparse.c @@ -0,0 +1,4057 @@ +/* +Copyright (c) 1998, 1999, 2000 Thai Open Source Software Center Ltd +See the file copying.txt for copying permission. +*/ + +/* In 2001, this was part of the Expat package. We copied it into + Xmlrpc-c because it's easier on the user than making him get and + link Expat separately, and we don't expect to benefit from separate + maintenance of Expat. + + But we changed all the external symbols that in Expat are named + "XML_xxxx" to "xmlrpc_XML_xxxx" because people do link Xmlrpc-c + libraries into programs that also link Expat (a good example is + where an Apache module uses Xmlrpc-c). We don't want our names to + collide with Expat's. +*/ + +#include + +#include "xmlrpc_config.h" +#include "c_util.h" +#include "xmldef.h" +#include "xmlparse.h" + +#ifdef XML_UNICODE +#define XML_ENCODE_MAX XML_UTF16_ENCODE_MAX +#define XmlConvert XmlUtf16Convert +#define XmlGetInternalEncoding xmlrpc_XmlGetUtf16InternalEncoding +#define XmlGetInternalEncodingNS xmlrpc_XmlGetUtf16InternalEncodingNS +#define XmlEncode xmlrpc_XmlUtf16Encode +#define MUST_CONVERT(enc, s) (!(enc)->isUtf16 || (((unsigned long)s) & 1)) +typedef unsigned short ICHAR; +#else +#define XML_ENCODE_MAX XML_UTF8_ENCODE_MAX +#define XmlConvert XmlUtf8Convert +#define XmlGetInternalEncoding xmlrpc_XmlGetUtf8InternalEncoding +#define XmlGetInternalEncodingNS xmlrpc_XmlGetUtf8InternalEncodingNS +#define XmlEncode xmlrpc_XmlUtf8Encode +#define MUST_CONVERT(enc, s) (!(enc)->isUtf8) +typedef char ICHAR; +#endif + + +#ifndef XML_NS + +#define XmlInitEncodingNS xmlrpc_XmlInitEncoding +#define XmlInitUnknownEncodingNS xmlrpc_XmlInitUnknownEncoding +#undef XmlGetInternalEncodingNS +#define XmlGetInternalEncodingNS XmlGetInternalEncoding +#define XmlParseXmlDeclNS xmlrpc_XmlParseXmlDecl + +#endif + +#ifdef XML_UNICODE_WCHAR_T +#define XML_T(x) L ## x +#else +#define XML_T(x) x +#endif + +/* Round up n to be a multiple of sz, where sz is a power of 2. */ +#define ROUND_UP(n, sz) (((n) + ((sz) - 1)) & ~((sz) - 1)) + +#include "xmltok.h" +#include "xmlrole.h" + +typedef const XML_Char *KEY; + +typedef struct { + KEY name; +} NAMED; + +typedef struct { + NAMED **v; + size_t size; + size_t used; + size_t usedLim; +} HASH_TABLE; + +typedef struct { + NAMED **p; + NAMED **end; +} HASH_TABLE_ITER; + +#define INIT_TAG_BUF_SIZE 32 /* must be a multiple of sizeof(XML_Char) */ +#define INIT_DATA_BUF_SIZE 1024 +#define INIT_ATTS_SIZE 16 +#define INIT_BLOCK_SIZE 1024 +#define INIT_BUFFER_SIZE 1024 + +#define EXPAND_SPARE 24 + +typedef struct binding { + struct prefix *prefix; + struct binding *nextTagBinding; + struct binding *prevPrefixBinding; + const struct attribute_id *attId; + XML_Char *uri; + int uriLen; + int uriAlloc; +} BINDING; + +typedef struct prefix { + const XML_Char *name; + BINDING *binding; +} PREFIX; + +typedef struct { + const XML_Char *str; + const XML_Char *localPart; + int uriLen; +} TAG_NAME; + +typedef struct tag { + struct tag *parent; + const char *rawName; + int rawNameLength; + TAG_NAME name; + char *buf; + char *bufEnd; + BINDING *bindings; +} TAG; + +typedef struct { + const XML_Char *name; + const XML_Char *textPtr; + int textLen; + const XML_Char *systemId; + const XML_Char *base; + const XML_Char *publicId; + const XML_Char *notation; + char open; +} ENTITY; + +typedef struct block { + struct block *next; + int size; + XML_Char s[1]; +} BLOCK; + +typedef struct { + BLOCK *blocks; + BLOCK *freeBlocks; + const XML_Char *end; + XML_Char *ptr; + XML_Char *start; +} STRING_POOL; + +/* The XML_Char before the name is used to determine whether +an attribute has been specified. */ +typedef struct attribute_id { + XML_Char *name; + PREFIX *prefix; + char maybeTokenized; + char xmlns; +} ATTRIBUTE_ID; + +typedef struct { + const ATTRIBUTE_ID *id; + char isCdata; + const XML_Char *value; +} DEFAULT_ATTRIBUTE; + +typedef struct { + const XML_Char *name; + PREFIX *prefix; + const ATTRIBUTE_ID *idAtt; + int nDefaultAtts; + int allocDefaultAtts; + DEFAULT_ATTRIBUTE *defaultAtts; +} ELEMENT_TYPE; + +typedef struct { + HASH_TABLE generalEntities; + HASH_TABLE elementTypes; + HASH_TABLE attributeIds; + HASH_TABLE prefixes; + STRING_POOL pool; + int complete; + int standalone; +#ifdef XML_DTD + HASH_TABLE paramEntities; +#endif /* XML_DTD */ + PREFIX defaultPrefix; +} DTD; + +typedef struct open_internal_entity { + const char *internalEventPtr; + const char *internalEventEndPtr; + struct open_internal_entity *next; + ENTITY *entity; +} OPEN_INTERNAL_ENTITY; + +typedef enum XML_Error Processor(XML_Parser parser, + const char *start, + const char *end, + const char **endPtr); + +static Processor prologProcessor; +static Processor prologInitProcessor; +static Processor contentProcessor; +static Processor cdataSectionProcessor; +#ifdef XML_DTD +static Processor ignoreSectionProcessor; +#endif /* XML_DTD */ +static Processor epilogProcessor; +static Processor errorProcessor; +static Processor externalEntityInitProcessor; +static Processor externalEntityInitProcessor2; +static Processor externalEntityInitProcessor3; +static Processor externalEntityContentProcessor; + +static enum XML_Error +handleUnknownEncoding(XML_Parser parser, const XML_Char *encodingName); +static enum XML_Error +processXmlDecl(XML_Parser parser, int isGeneralTextEntity, const char *, const char *); +static enum XML_Error +initializeEncoding(XML_Parser parser); +static enum XML_Error +doProlog(XML_Parser parser, const ENCODING *enc, const char *s, + const char *end, int tok, const char *next, const char **nextPtr); +static enum XML_Error +doContent(XML_Parser parser, int startTagLevel, const ENCODING *enc, + const char *start, const char *end, const char **endPtr); +static enum XML_Error +doCdataSection(XML_Parser parser, const ENCODING *, const char **startPtr, const char *end, const char **nextPtr); +#ifdef XML_DTD +static enum XML_Error +doIgnoreSection(XML_Parser parser, const ENCODING *, const char **startPtr, const char *end, const char **nextPtr); +#endif /* XML_DTD */ +static enum XML_Error storeAtts(XML_Parser parser, const ENCODING *, const char *s, + TAG_NAME *tagNamePtr, BINDING **bindingsPtr); +static +int addBinding(XML_Parser parser, PREFIX *prefix, const ATTRIBUTE_ID *attId, const XML_Char *uri, BINDING **bindingsPtr); +static int +defineAttribute(ELEMENT_TYPE *type, ATTRIBUTE_ID *, int isCdata, int isId, const XML_Char *dfltValue); +static enum XML_Error +storeAttributeValue(XML_Parser parser, const ENCODING *, int isCdata, const char *, const char *, + STRING_POOL *); +static enum XML_Error +appendAttributeValue(XML_Parser parser, const ENCODING *, int isCdata, const char *, const char *, + STRING_POOL *); +static ATTRIBUTE_ID * +getAttributeId(XML_Parser parser, const ENCODING *enc, const char *start, const char *end); +static int setElementTypePrefix(XML_Parser parser, ELEMENT_TYPE *); +static enum XML_Error +storeEntityValue(XML_Parser parser, const ENCODING *enc, const char *start, const char *end); +static int +reportProcessingInstruction(XML_Parser parser, const ENCODING *enc, const char *start, const char *end); +static int +reportComment(XML_Parser parser, const ENCODING *enc, const char *start, const char *end); +static void +reportDefault(XML_Parser parser, const ENCODING *enc, const char *start, const char *end); + +static const XML_Char *getContext(XML_Parser parser); +static int setContext(XML_Parser parser, const XML_Char *context); +static void normalizePublicId(XML_Char *s); +static int dtdInit(DTD *); +static void dtdDestroy(DTD *); +static int dtdCopy(DTD *newDtd, const DTD *oldDtd); +static int copyEntityTable(HASH_TABLE *, STRING_POOL *, const HASH_TABLE *); +#ifdef XML_DTD +static void dtdSwap(DTD *, DTD *); +#endif /* XML_DTD */ +static NAMED *lookup(HASH_TABLE *table, KEY name, size_t createSize); +static void hashTableInit(HASH_TABLE *); +static void hashTableDestroy(HASH_TABLE *); +static void hashTableIterInit(HASH_TABLE_ITER *, const HASH_TABLE *); +static NAMED *hashTableIterNext(HASH_TABLE_ITER *); +static void poolInit(STRING_POOL *); +static void poolClear(STRING_POOL *); +static void poolDestroy(STRING_POOL *); +static XML_Char *poolAppend(STRING_POOL *pool, const ENCODING *enc, + const char *ptr, const char *end); +static XML_Char *poolStoreString(STRING_POOL *pool, const ENCODING *enc, + const char *ptr, const char *end); +static int poolGrow(STRING_POOL *pool); +static const XML_Char *poolCopyString(STRING_POOL *pool, const XML_Char *s); +static const XML_Char *poolCopyStringN(STRING_POOL *pool, const XML_Char *s, int n); + +#define poolStart(pool) ((pool)->start) +#define poolEnd(pool) ((pool)->ptr) +#define poolLength(pool) ((pool)->ptr - (pool)->start) +#define poolChop(pool) ((void)--(pool->ptr)) +#define poolLastChar(pool) (((pool)->ptr)[-1]) +#define poolDiscard(pool) ((pool)->ptr = (pool)->start) +#define poolFinish(pool) ((pool)->start = (pool)->ptr) +#define poolAppendChar(pool, c) \ + (((pool)->ptr == (pool)->end && !poolGrow(pool)) \ + ? 0 \ + : ((*((pool)->ptr)++ = c), 1)) + +typedef struct { + /* The first member must be userData so that the XML_GetUserData macro works. */ + void *m_userData; + void *m_handlerArg; + char *m_buffer; + /* first character to be parsed */ + const char *m_bufferPtr; + /* past last character to be parsed */ + char *m_bufferEnd; + /* allocated end of buffer */ + const char *m_bufferLim; + long m_parseEndByteIndex; + const char *m_parseEndPtr; + XML_Char *m_dataBuf; + XML_Char *m_dataBufEnd; + XML_StartElementHandler m_startElementHandler; + XML_EndElementHandler m_endElementHandler; + XML_CharacterDataHandler m_characterDataHandler; + XML_ProcessingInstructionHandler m_processingInstructionHandler; + XML_CommentHandler m_commentHandler; + XML_StartCdataSectionHandler m_startCdataSectionHandler; + XML_EndCdataSectionHandler m_endCdataSectionHandler; + XML_DefaultHandler m_defaultHandler; + XML_StartDoctypeDeclHandler m_startDoctypeDeclHandler; + XML_EndDoctypeDeclHandler m_endDoctypeDeclHandler; + XML_UnparsedEntityDeclHandler m_unparsedEntityDeclHandler; + XML_NotationDeclHandler m_notationDeclHandler; + XML_ExternalParsedEntityDeclHandler m_externalParsedEntityDeclHandler; + XML_InternalParsedEntityDeclHandler m_internalParsedEntityDeclHandler; + XML_StartNamespaceDeclHandler m_startNamespaceDeclHandler; + XML_EndNamespaceDeclHandler m_endNamespaceDeclHandler; + XML_NotStandaloneHandler m_notStandaloneHandler; + XML_ExternalEntityRefHandler m_externalEntityRefHandler; + void *m_externalEntityRefHandlerArg; + XML_UnknownEncodingHandler m_unknownEncodingHandler; + const ENCODING *m_encoding; + INIT_ENCODING m_initEncoding; + const ENCODING *m_internalEncoding; + const XML_Char *m_protocolEncodingName; + int m_ns; + void *m_unknownEncodingMem; + void *m_unknownEncodingData; + void *m_unknownEncodingHandlerData; + void (*m_unknownEncodingRelease)(void *); + PROLOG_STATE m_prologState; + Processor *m_processor; + enum XML_Error m_errorCode; + const char *m_eventPtr; + const char *m_eventEndPtr; + const char *m_positionPtr; + OPEN_INTERNAL_ENTITY *m_openInternalEntities; + int m_defaultExpandInternalEntities; + int m_tagLevel; + ENTITY *m_declEntity; + const XML_Char *m_declNotationName; + const XML_Char *m_declNotationPublicId; + ELEMENT_TYPE *m_declElementType; + ATTRIBUTE_ID *m_declAttributeId; + char m_declAttributeIsCdata; + char m_declAttributeIsId; + DTD m_dtd; + const XML_Char *m_curBase; + TAG *m_tagStack; + TAG *m_freeTagList; + BINDING *m_inheritedBindings; + BINDING *m_freeBindingList; + int m_attsSize; + int m_nSpecifiedAtts; + int m_idAttIndex; + ATTRIBUTE *m_atts; + POSITION m_position; + STRING_POOL m_tempPool; + STRING_POOL m_temp2Pool; + char *m_groupConnector; + unsigned m_groupSize; + int m_hadExternalDoctype; + XML_Char m_namespaceSeparator; +#ifdef XML_DTD + enum XML_ParamEntityParsing m_paramEntityParsing; + XML_Parser m_parentParser; +#endif +} Parser; + +#define userData (((Parser *)parser)->m_userData) +#define handlerArg (((Parser *)parser)->m_handlerArg) +#define startElementHandler (((Parser *)parser)->m_startElementHandler) +#define endElementHandler (((Parser *)parser)->m_endElementHandler) +#define characterDataHandler (((Parser *)parser)->m_characterDataHandler) +#define processingInstructionHandler (((Parser *)parser)->m_processingInstructionHandler) +#define commentHandler (((Parser *)parser)->m_commentHandler) +#define startCdataSectionHandler (((Parser *)parser)->m_startCdataSectionHandler) +#define endCdataSectionHandler (((Parser *)parser)->m_endCdataSectionHandler) +#define defaultHandler (((Parser *)parser)->m_defaultHandler) +#define startDoctypeDeclHandler (((Parser *)parser)->m_startDoctypeDeclHandler) +#define endDoctypeDeclHandler (((Parser *)parser)->m_endDoctypeDeclHandler) +#define unparsedEntityDeclHandler (((Parser *)parser)->m_unparsedEntityDeclHandler) +#define notationDeclHandler (((Parser *)parser)->m_notationDeclHandler) +#define externalParsedEntityDeclHandler (((Parser *)parser)->m_externalParsedEntityDeclHandler) +#define internalParsedEntityDeclHandler (((Parser *)parser)->m_internalParsedEntityDeclHandler) +#define startNamespaceDeclHandler (((Parser *)parser)->m_startNamespaceDeclHandler) +#define endNamespaceDeclHandler (((Parser *)parser)->m_endNamespaceDeclHandler) +#define notStandaloneHandler (((Parser *)parser)->m_notStandaloneHandler) +#define externalEntityRefHandler (((Parser *)parser)->m_externalEntityRefHandler) +#define externalEntityRefHandlerArg (((Parser *)parser)->m_externalEntityRefHandlerArg) +#define unknownEncodingHandler (((Parser *)parser)->m_unknownEncodingHandler) +#define encoding (((Parser *)parser)->m_encoding) +#define initEncoding (((Parser *)parser)->m_initEncoding) +#define internalEncoding (((Parser *)parser)->m_internalEncoding) +#define unknownEncodingMem (((Parser *)parser)->m_unknownEncodingMem) +#define unknownEncodingData (((Parser *)parser)->m_unknownEncodingData) +#define unknownEncodingHandlerData \ + (((Parser *)parser)->m_unknownEncodingHandlerData) +#define unknownEncodingRelease (((Parser *)parser)->m_unknownEncodingRelease) +#define protocolEncodingName (((Parser *)parser)->m_protocolEncodingName) +#define ns (((Parser *)parser)->m_ns) +#define prologState (((Parser *)parser)->m_prologState) +#define processor (((Parser *)parser)->m_processor) +#define errorCode (((Parser *)parser)->m_errorCode) +#define eventPtr (((Parser *)parser)->m_eventPtr) +#define eventEndPtr (((Parser *)parser)->m_eventEndPtr) +#define positionPtr (((Parser *)parser)->m_positionPtr) +#define position (((Parser *)parser)->m_position) +#define openInternalEntities (((Parser *)parser)->m_openInternalEntities) +#define defaultExpandInternalEntities (((Parser *)parser)->m_defaultExpandInternalEntities) +#define tagLevel (((Parser *)parser)->m_tagLevel) +#define buffer (((Parser *)parser)->m_buffer) +#define bufferPtr (((Parser *)parser)->m_bufferPtr) +#define bufferEnd (((Parser *)parser)->m_bufferEnd) +#define parseEndByteIndex (((Parser *)parser)->m_parseEndByteIndex) +#define parseEndPtr (((Parser *)parser)->m_parseEndPtr) +#define bufferLim (((Parser *)parser)->m_bufferLim) +#define dataBuf (((Parser *)parser)->m_dataBuf) +#define dataBufEnd (((Parser *)parser)->m_dataBufEnd) +#define dtd (((Parser *)parser)->m_dtd) +#define curBase (((Parser *)parser)->m_curBase) +#define declEntity (((Parser *)parser)->m_declEntity) +#define declNotationName (((Parser *)parser)->m_declNotationName) +#define declNotationPublicId (((Parser *)parser)->m_declNotationPublicId) +#define declElementType (((Parser *)parser)->m_declElementType) +#define declAttributeId (((Parser *)parser)->m_declAttributeId) +#define declAttributeIsCdata (((Parser *)parser)->m_declAttributeIsCdata) +#define declAttributeIsId (((Parser *)parser)->m_declAttributeIsId) +#define freeTagList (((Parser *)parser)->m_freeTagList) +#define freeBindingList (((Parser *)parser)->m_freeBindingList) +#define inheritedBindings (((Parser *)parser)->m_inheritedBindings) +#define tagStack (((Parser *)parser)->m_tagStack) +#define atts (((Parser *)parser)->m_atts) +#define attsSize (((Parser *)parser)->m_attsSize) +#define nSpecifiedAtts (((Parser *)parser)->m_nSpecifiedAtts) +#define idAttIndex (((Parser *)parser)->m_idAttIndex) +#define tempPool (((Parser *)parser)->m_tempPool) +#define temp2Pool (((Parser *)parser)->m_temp2Pool) +#define groupConnector (((Parser *)parser)->m_groupConnector) +#define groupSize (((Parser *)parser)->m_groupSize) +#define hadExternalDoctype (((Parser *)parser)->m_hadExternalDoctype) +#define namespaceSeparator (((Parser *)parser)->m_namespaceSeparator) +#ifdef XML_DTD +#define parentParser (((Parser *)parser)->m_parentParser) +#define paramEntityParsing (((Parser *)parser)->m_paramEntityParsing) +#endif /* XML_DTD */ + +#ifdef _MSC_VER +#ifdef _DEBUG +Parser *asParser(XML_Parser parser) +{ + return parser; +} +#endif +#endif + +XML_Parser +xmlrpc_XML_ParserCreate(const XML_Char *encodingName) +{ + XML_Parser parser = malloc(sizeof(Parser)); + if (!parser) + return parser; + processor = prologInitProcessor; + xmlrpc_XmlPrologStateInit(&prologState); + userData = 0; + handlerArg = 0; + startElementHandler = 0; + endElementHandler = 0; + characterDataHandler = 0; + processingInstructionHandler = 0; + commentHandler = 0; + startCdataSectionHandler = 0; + endCdataSectionHandler = 0; + defaultHandler = 0; + startDoctypeDeclHandler = 0; + endDoctypeDeclHandler = 0; + unparsedEntityDeclHandler = 0; + notationDeclHandler = 0; + externalParsedEntityDeclHandler = 0; + internalParsedEntityDeclHandler = 0; + startNamespaceDeclHandler = 0; + endNamespaceDeclHandler = 0; + notStandaloneHandler = 0; + externalEntityRefHandler = 0; + externalEntityRefHandlerArg = parser; + unknownEncodingHandler = 0; + buffer = 0; + bufferPtr = 0; + bufferEnd = 0; + parseEndByteIndex = 0; + parseEndPtr = 0; + bufferLim = 0; + declElementType = 0; + declAttributeId = 0; + declEntity = 0; + declNotationName = 0; + declNotationPublicId = 0; + memset(&position, 0, sizeof(POSITION)); + errorCode = XML_ERROR_NONE; + eventPtr = 0; + eventEndPtr = 0; + positionPtr = 0; + openInternalEntities = 0; + tagLevel = 0; + tagStack = 0; + freeTagList = 0; + freeBindingList = 0; + inheritedBindings = 0; + attsSize = INIT_ATTS_SIZE; + atts = malloc(attsSize * sizeof(ATTRIBUTE)); + nSpecifiedAtts = 0; + dataBuf = malloc(INIT_DATA_BUF_SIZE * sizeof(XML_Char)); + groupSize = 0; + groupConnector = 0; + hadExternalDoctype = 0; + unknownEncodingMem = 0; + unknownEncodingRelease = 0; + unknownEncodingData = 0; + unknownEncodingHandlerData = 0; + namespaceSeparator = '!'; +#ifdef XML_DTD + parentParser = 0; + paramEntityParsing = XML_PARAM_ENTITY_PARSING_NEVER; +#endif + ns = 0; + poolInit(&tempPool); + poolInit(&temp2Pool); + protocolEncodingName = encodingName ? poolCopyString(&tempPool, encodingName) : 0; + curBase = 0; + if (!dtdInit(&dtd) || !atts || !dataBuf + || (encodingName && !protocolEncodingName)) { + xmlrpc_XML_ParserFree(parser); + return 0; + } + dataBufEnd = dataBuf + INIT_DATA_BUF_SIZE; + xmlrpc_XmlInitEncoding(&initEncoding, &encoding, 0); + internalEncoding = XmlGetInternalEncoding(); + return parser; +} + +XML_Parser +xmlrpc_XML_ParserCreateNS(const XML_Char *encodingName, XML_Char nsSep) +{ + static + const XML_Char implicitContext[] = { + XML_T('x'), XML_T('m'), XML_T('l'), XML_T('='), + XML_T('h'), XML_T('t'), XML_T('t'), XML_T('p'), XML_T(':'), + XML_T('/'), XML_T('/'), XML_T('w'), XML_T('w'), XML_T('w'), + XML_T('.'), XML_T('w'), XML_T('3'), + XML_T('.'), XML_T('o'), XML_T('r'), XML_T('g'), + XML_T('/'), XML_T('X'), XML_T('M'), XML_T('L'), + XML_T('/'), XML_T('1'), XML_T('9'), XML_T('9'), XML_T('8'), + XML_T('/'), XML_T('n'), XML_T('a'), XML_T('m'), XML_T('e'), + XML_T('s'), XML_T('p'), XML_T('a'), XML_T('c'), XML_T('e'), + XML_T('\0') + }; + + XML_Parser parser = xmlrpc_XML_ParserCreate(encodingName); + if (parser) { + XmlInitEncodingNS(&initEncoding, &encoding, 0); + ns = 1; + internalEncoding = XmlGetInternalEncodingNS(); + namespaceSeparator = nsSep; + } + if (!setContext(parser, implicitContext)) { + xmlrpc_XML_ParserFree(parser); + return 0; + } + return parser; +} + +int +xmlrpc_XML_SetEncoding(XML_Parser parser, const XML_Char *encodingName) +{ + if (!encodingName) + protocolEncodingName = 0; + else { + protocolEncodingName = poolCopyString(&tempPool, encodingName); + if (!protocolEncodingName) + return 0; + } + return 1; +} + +XML_Parser +xmlrpc_XML_ExternalEntityParserCreate(XML_Parser oldParser, + const XML_Char *context, + const XML_Char *encodingName) +{ + XML_Parser parser = oldParser; + DTD *oldDtd = &dtd; + XML_StartElementHandler oldStartElementHandler = startElementHandler; + XML_EndElementHandler oldEndElementHandler = endElementHandler; + XML_CharacterDataHandler oldCharacterDataHandler = characterDataHandler; + XML_ProcessingInstructionHandler oldProcessingInstructionHandler = processingInstructionHandler; + XML_CommentHandler oldCommentHandler = commentHandler; + XML_StartCdataSectionHandler oldStartCdataSectionHandler = startCdataSectionHandler; + XML_EndCdataSectionHandler oldEndCdataSectionHandler = endCdataSectionHandler; + XML_DefaultHandler oldDefaultHandler = defaultHandler; + XML_UnparsedEntityDeclHandler oldUnparsedEntityDeclHandler = unparsedEntityDeclHandler; + XML_NotationDeclHandler oldNotationDeclHandler = notationDeclHandler; + XML_ExternalParsedEntityDeclHandler oldExternalParsedEntityDeclHandler = externalParsedEntityDeclHandler; + XML_InternalParsedEntityDeclHandler oldInternalParsedEntityDeclHandler = internalParsedEntityDeclHandler; + XML_StartNamespaceDeclHandler oldStartNamespaceDeclHandler = startNamespaceDeclHandler; + XML_EndNamespaceDeclHandler oldEndNamespaceDeclHandler = endNamespaceDeclHandler; + XML_NotStandaloneHandler oldNotStandaloneHandler = notStandaloneHandler; + XML_ExternalEntityRefHandler oldExternalEntityRefHandler = externalEntityRefHandler; + XML_UnknownEncodingHandler oldUnknownEncodingHandler = unknownEncodingHandler; + void *oldUserData = userData; + void *oldHandlerArg = handlerArg; + int oldDefaultExpandInternalEntities = defaultExpandInternalEntities; + void *oldExternalEntityRefHandlerArg = externalEntityRefHandlerArg; +#ifdef XML_DTD + int oldParamEntityParsing = paramEntityParsing; +#endif + parser = (ns + ? xmlrpc_XML_ParserCreateNS(encodingName, namespaceSeparator) + : xmlrpc_XML_ParserCreate(encodingName)); + if (!parser) + return 0; + startElementHandler = oldStartElementHandler; + endElementHandler = oldEndElementHandler; + characterDataHandler = oldCharacterDataHandler; + processingInstructionHandler = oldProcessingInstructionHandler; + commentHandler = oldCommentHandler; + startCdataSectionHandler = oldStartCdataSectionHandler; + endCdataSectionHandler = oldEndCdataSectionHandler; + defaultHandler = oldDefaultHandler; + unparsedEntityDeclHandler = oldUnparsedEntityDeclHandler; + notationDeclHandler = oldNotationDeclHandler; + externalParsedEntityDeclHandler = oldExternalParsedEntityDeclHandler; + internalParsedEntityDeclHandler = oldInternalParsedEntityDeclHandler; + startNamespaceDeclHandler = oldStartNamespaceDeclHandler; + endNamespaceDeclHandler = oldEndNamespaceDeclHandler; + notStandaloneHandler = oldNotStandaloneHandler; + externalEntityRefHandler = oldExternalEntityRefHandler; + unknownEncodingHandler = oldUnknownEncodingHandler; + userData = oldUserData; + if (oldUserData == oldHandlerArg) + handlerArg = userData; + else + handlerArg = parser; + if (oldExternalEntityRefHandlerArg != oldParser) + externalEntityRefHandlerArg = oldExternalEntityRefHandlerArg; + defaultExpandInternalEntities = oldDefaultExpandInternalEntities; +#ifdef XML_DTD + paramEntityParsing = oldParamEntityParsing; + if (context) { +#endif /* XML_DTD */ + if (!dtdCopy(&dtd, oldDtd) || !setContext(parser, context)) { + xmlrpc_XML_ParserFree(parser); + return 0; + } + processor = externalEntityInitProcessor; +#ifdef XML_DTD + } + else { + dtdSwap(&dtd, oldDtd); + parentParser = oldParser; + XmlPrologStateInitExternalEntity(&prologState); + dtd.complete = 1; + hadExternalDoctype = 1; + } +#endif /* XML_DTD */ + return parser; +} + +static +void destroyBindings(BINDING *bindings) +{ + for (;;) { + BINDING *b = bindings; + if (!b) + break; + bindings = b->nextTagBinding; + free(b->uri); + free(b); + } +} + +void +xmlrpc_XML_ParserFree(XML_Parser parser) +{ + for (;;) { + TAG *p; + if (tagStack == 0) { + if (freeTagList == 0) + break; + tagStack = freeTagList; + freeTagList = 0; + } + p = tagStack; + tagStack = tagStack->parent; + free(p->buf); + destroyBindings(p->bindings); + free(p); + } + destroyBindings(freeBindingList); + destroyBindings(inheritedBindings); + poolDestroy(&tempPool); + poolDestroy(&temp2Pool); +#ifdef XML_DTD + if (parentParser) { + if (hadExternalDoctype) + dtd.complete = 0; + dtdSwap(&dtd, &((Parser *)parentParser)->m_dtd); + } +#endif /* XML_DTD */ + dtdDestroy(&dtd); + free((void *)atts); + free(groupConnector); + free(buffer); + free(dataBuf); + free(unknownEncodingMem); + if (unknownEncodingRelease) + unknownEncodingRelease(unknownEncodingData); + free(parser); +} + +void +xmlrpc_XML_UseParserAsHandlerArg(XML_Parser parser) +{ + handlerArg = parser; +} + +void +xmlrpc_XML_SetUserData(XML_Parser parser, void *p) +{ + if (handlerArg == userData) + handlerArg = userData = p; + else + userData = p; +} + +int +xmlrpc_XML_SetBase(XML_Parser parser, const XML_Char *p) +{ + if (p) { + p = poolCopyString(&dtd.pool, p); + if (!p) + return 0; + curBase = p; + } + else + curBase = 0; + return 1; +} + +const XML_Char * +xmlrpc_XML_GetBase(XML_Parser parser) +{ + return curBase; +} + +int +xmlrpc_XML_GetSpecifiedAttributeCount(XML_Parser parser) +{ + return nSpecifiedAtts; +} + +int +xmlrpc_XML_GetIdAttributeIndex(XML_Parser parser) +{ + return idAttIndex; +} + +void +xmlrpc_XML_SetElementHandler(XML_Parser parser, + XML_StartElementHandler start, + XML_EndElementHandler end) +{ + startElementHandler = start; + endElementHandler = end; +} + +void +xmlrpc_XML_SetCharacterDataHandler(XML_Parser parser, + XML_CharacterDataHandler handler) +{ + characterDataHandler = handler; +} + +void +xmlrpc_XML_SetProcessingInstructionHandler( + XML_Parser parser, + XML_ProcessingInstructionHandler handler) +{ + processingInstructionHandler = handler; +} + +void +xmlrpc_XML_SetCommentHandler(XML_Parser parser, + XML_CommentHandler handler) +{ + commentHandler = handler; +} + +void +xmlrpc_XML_SetCdataSectionHandler(XML_Parser parser, + XML_StartCdataSectionHandler start, + XML_EndCdataSectionHandler end) +{ + startCdataSectionHandler = start; + endCdataSectionHandler = end; +} + +void +xmlrpc_XML_SetDefaultHandler(XML_Parser parser, + XML_DefaultHandler handler) +{ + defaultHandler = handler; + defaultExpandInternalEntities = 0; +} + +void +xmlrpc_XML_SetDefaultHandlerExpand(XML_Parser parser, + XML_DefaultHandler handler) +{ + defaultHandler = handler; + defaultExpandInternalEntities = 1; +} + +void +xmlrpc_XML_SetDoctypeDeclHandler(XML_Parser parser, + XML_StartDoctypeDeclHandler start, + XML_EndDoctypeDeclHandler end) +{ + startDoctypeDeclHandler = start; + endDoctypeDeclHandler = end; +} + +void +xmlrpc_XML_SetUnparsedEntityDeclHandler(XML_Parser parser, + XML_UnparsedEntityDeclHandler handler) +{ + unparsedEntityDeclHandler = handler; +} + +void +xmlrpc_XML_SetExternalParsedEntityDeclHandler( + XML_Parser parser, + XML_ExternalParsedEntityDeclHandler handler) +{ + externalParsedEntityDeclHandler = handler; +} + +void +xmlrpc_XML_SetInternalParsedEntityDeclHandler( + XML_Parser parser, + XML_InternalParsedEntityDeclHandler handler) +{ + internalParsedEntityDeclHandler = handler; +} + +void +xmlrpc_XML_SetNotationDeclHandler(XML_Parser parser, + XML_NotationDeclHandler handler) +{ + notationDeclHandler = handler; +} + +void +xmlrpc_XML_SetNamespaceDeclHandler(XML_Parser parser, + XML_StartNamespaceDeclHandler start, + XML_EndNamespaceDeclHandler end) +{ + startNamespaceDeclHandler = start; + endNamespaceDeclHandler = end; +} + +void +xmlrpc_XML_SetNotStandaloneHandler(XML_Parser parser, + XML_NotStandaloneHandler handler) +{ + notStandaloneHandler = handler; +} + +void +xmlrpc_XML_SetExternalEntityRefHandler(XML_Parser parser, + XML_ExternalEntityRefHandler handler) +{ + externalEntityRefHandler = handler; +} + +void +xmlrpc_XML_SetExternalEntityRefHandlerArg(XML_Parser parser, void *arg) +{ + if (arg) + externalEntityRefHandlerArg = arg; + else + externalEntityRefHandlerArg = parser; +} + +void +xmlrpc_XML_SetUnknownEncodingHandler(XML_Parser parser, + XML_UnknownEncodingHandler handler, + void *data) +{ + unknownEncodingHandler = handler; + unknownEncodingHandlerData = data; +} + + + +int +xmlrpc_XML_SetParamEntityParsing( + XML_Parser const parser ATTR_UNUSED, + enum XML_ParamEntityParsing const parsing) { + + int retval; + +#ifdef XML_DTD + paramEntityParsing = parsing; + retval = 1; +#else + retval = parsing == XML_PARAM_ENTITY_PARSING_NEVER; +#endif + + return retval; +} + + + +int +xmlrpc_XML_Parse(XML_Parser parser, const char *s, int len, int isFinal) +{ + if (len == 0) { + if (!isFinal) + return 1; + positionPtr = bufferPtr; + errorCode = processor(parser, bufferPtr, parseEndPtr = bufferEnd, 0); + if (errorCode == XML_ERROR_NONE) + return 1; + eventEndPtr = eventPtr; + processor = errorProcessor; + return 0; + } + else if (bufferPtr == bufferEnd) { + const char *end; + int nLeftOver; + parseEndByteIndex += len; + positionPtr = s; + if (isFinal) { + errorCode = processor(parser, s, parseEndPtr = s + len, 0); + if (errorCode == XML_ERROR_NONE) + return 1; + eventEndPtr = eventPtr; + processor = errorProcessor; + return 0; + } + errorCode = processor(parser, s, parseEndPtr = s + len, &end); + if (errorCode != XML_ERROR_NONE) { + eventEndPtr = eventPtr; + processor = errorProcessor; + return 0; + } + XmlUpdatePosition(encoding, positionPtr, end, &position); + nLeftOver = s + len - end; + if (nLeftOver) { + if (buffer == 0 || nLeftOver > bufferLim - buffer) { + /* FIXME avoid integer overflow */ + buffer = buffer == 0 ? malloc(len * 2) : realloc(buffer, len * 2); + /* FIXME storage leak if realloc fails */ + if (!buffer) { + errorCode = XML_ERROR_NO_MEMORY; + eventPtr = eventEndPtr = 0; + processor = errorProcessor; + return 0; + } + bufferLim = buffer + len * 2; + } + memcpy(buffer, end, nLeftOver); + bufferPtr = buffer; + bufferEnd = buffer + nLeftOver; + } + return 1; + } + else { + memcpy(xmlrpc_XML_GetBuffer(parser, len), s, len); + return xmlrpc_XML_ParseBuffer(parser, len, isFinal); + } +} + +int +xmlrpc_XML_ParseBuffer(XML_Parser parser, int len, int isFinal) +{ + const char *start = bufferPtr; + positionPtr = start; + bufferEnd += len; + parseEndByteIndex += len; + errorCode = processor(parser, start, parseEndPtr = bufferEnd, + isFinal ? (const char **)0 : &bufferPtr); + if (errorCode == XML_ERROR_NONE) { + if (!isFinal) + XmlUpdatePosition(encoding, positionPtr, bufferPtr, &position); + return 1; + } + else { + eventEndPtr = eventPtr; + processor = errorProcessor; + return 0; + } +} + +void * +xmlrpc_XML_GetBuffer(XML_Parser parser, int len) +{ + if (len > bufferLim - bufferEnd) { + /* FIXME avoid integer overflow */ + int neededSize = len + (bufferEnd - bufferPtr); + if (neededSize <= bufferLim - buffer) { + memmove(buffer, bufferPtr, bufferEnd - bufferPtr); + bufferEnd = buffer + (bufferEnd - bufferPtr); + bufferPtr = buffer; + } + else { + char *newBuf; + int bufferSize = bufferLim - bufferPtr; + if (bufferSize == 0) + bufferSize = INIT_BUFFER_SIZE; + do { + bufferSize *= 2; + } while (bufferSize < neededSize); + newBuf = malloc(bufferSize); + if (newBuf == 0) { + errorCode = XML_ERROR_NO_MEMORY; + return 0; + } + bufferLim = newBuf + bufferSize; + if (bufferPtr) { + memcpy(newBuf, bufferPtr, bufferEnd - bufferPtr); + free(buffer); + } + bufferEnd = newBuf + (bufferEnd - bufferPtr); + bufferPtr = buffer = newBuf; + } + } + return bufferEnd; +} + +enum XML_Error +xmlrpc_XML_GetErrorCode(XML_Parser parser) +{ + return errorCode; +} + +long +xmlrpc_XML_GetCurrentByteIndex(XML_Parser parser) +{ + if (eventPtr) + return parseEndByteIndex - (parseEndPtr - eventPtr); + return -1; +} + +int +xmlrpc_XML_GetCurrentByteCount(XML_Parser parser) +{ + if (eventEndPtr && eventPtr) + return eventEndPtr - eventPtr; + return 0; +} + +int +xmlrpc_XML_GetCurrentLineNumber(XML_Parser parser) +{ + if (eventPtr) { + XmlUpdatePosition(encoding, positionPtr, eventPtr, &position); + positionPtr = eventPtr; + } + return position.lineNumber + 1; +} + +int +xmlrpc_XML_GetCurrentColumnNumber(XML_Parser parser) +{ + if (eventPtr) { + XmlUpdatePosition(encoding, positionPtr, eventPtr, &position); + positionPtr = eventPtr; + } + return position.columnNumber; +} + +void +xmlrpc_XML_DefaultCurrent(XML_Parser parser) +{ + if (defaultHandler) { + if (openInternalEntities) + reportDefault(parser, + internalEncoding, + openInternalEntities->internalEventPtr, + openInternalEntities->internalEventEndPtr); + else + reportDefault(parser, encoding, eventPtr, eventEndPtr); + } +} + +const XML_LChar * +xmlrpc_XML_ErrorString(int const code) { + + static const XML_LChar * const message[] = { + NULL, + XML_T("out of memory"), + XML_T("syntax error"), + XML_T("no element found"), + XML_T("not well-formed"), + XML_T("unclosed token"), + XML_T("unclosed token"), + XML_T("mismatched tag"), + XML_T("duplicate attribute"), + XML_T("junk after document element"), + XML_T("illegal parameter entity reference"), + XML_T("undefined entity"), + XML_T("recursive entity reference"), + XML_T("asynchronous entity"), + XML_T("reference to invalid character number"), + XML_T("reference to binary entity"), + XML_T("reference to external entity in attribute"), + XML_T("xml processing instruction not at start of external entity"), + XML_T("unknown encoding"), + XML_T("encoding specified in XML declaration is incorrect"), + XML_T("unclosed CDATA section"), + XML_T("error in processing external entity reference"), + XML_T("document is not standalone") + }; + + const XML_LChar * retval; + + if (code > 0 && (unsigned)code < ARRAY_SIZE(message)) + retval = message[code]; + else + retval = NULL; + + return retval; +} + +static +enum XML_Error contentProcessor(XML_Parser parser, + const char *start, + const char *end, + const char **endPtr) +{ + return doContent(parser, 0, encoding, start, end, endPtr); +} + +static +enum XML_Error externalEntityInitProcessor(XML_Parser parser, + const char *start, + const char *end, + const char **endPtr) +{ + enum XML_Error result = initializeEncoding(parser); + if (result != XML_ERROR_NONE) + return result; + processor = externalEntityInitProcessor2; + return externalEntityInitProcessor2(parser, start, end, endPtr); +} + +static +enum XML_Error externalEntityInitProcessor2(XML_Parser parser, + const char *start, + const char *end, + const char **endPtr) +{ + const char *next; + int tok = XmlContentTok(encoding, start, end, &next); + switch (tok) { + case XML_TOK_BOM: + start = next; + break; + case XML_TOK_PARTIAL: + if (endPtr) { + *endPtr = start; + return XML_ERROR_NONE; + } + eventPtr = start; + return XML_ERROR_UNCLOSED_TOKEN; + case XML_TOK_PARTIAL_CHAR: + if (endPtr) { + *endPtr = start; + return XML_ERROR_NONE; + } + eventPtr = start; + return XML_ERROR_PARTIAL_CHAR; + } + processor = externalEntityInitProcessor3; + return externalEntityInitProcessor3(parser, start, end, endPtr); +} + +static +enum XML_Error externalEntityInitProcessor3(XML_Parser parser, + const char *start, + const char *end, + const char **endPtr) +{ + const char *next; + int tok = XmlContentTok(encoding, start, end, &next); + switch (tok) { + case XML_TOK_XML_DECL: + { + enum XML_Error result = processXmlDecl(parser, 1, start, next); + if (result != XML_ERROR_NONE) + return result; + start = next; + } + break; + case XML_TOK_PARTIAL: + if (endPtr) { + *endPtr = start; + return XML_ERROR_NONE; + } + eventPtr = start; + return XML_ERROR_UNCLOSED_TOKEN; + case XML_TOK_PARTIAL_CHAR: + if (endPtr) { + *endPtr = start; + return XML_ERROR_NONE; + } + eventPtr = start; + return XML_ERROR_PARTIAL_CHAR; + } + processor = externalEntityContentProcessor; + tagLevel = 1; + return doContent(parser, 1, encoding, start, end, endPtr); +} + +static +enum XML_Error externalEntityContentProcessor(XML_Parser parser, + const char *start, + const char *end, + const char **endPtr) +{ + return doContent(parser, 1, encoding, start, end, endPtr); +} + +static enum XML_Error +doContent(XML_Parser parser, + int startTagLevel, + const ENCODING *enc, + const char *s, + const char *end, + const char **nextPtr) +{ + const char **eventPP; + const char **eventEndPP; + if (enc == encoding) { + eventPP = &eventPtr; + eventEndPP = &eventEndPtr; + } + else { + eventPP = &(openInternalEntities->internalEventPtr); + eventEndPP = &(openInternalEntities->internalEventEndPtr); + } + *eventPP = s; + for (;;) { + const char *next = s; /* XmlContentTok doesn't always set the last arg */ + int tok = XmlContentTok(enc, s, end, &next); + *eventEndPP = next; + switch (tok) { + case XML_TOK_TRAILING_CR: + if (nextPtr) { + *nextPtr = s; + return XML_ERROR_NONE; + } + *eventEndPP = end; + if (characterDataHandler) { + XML_Char c = 0xA; + characterDataHandler(handlerArg, &c, 1); + } + else if (defaultHandler) + reportDefault(parser, enc, s, end); + if (startTagLevel == 0) + return XML_ERROR_NO_ELEMENTS; + if (tagLevel != startTagLevel) + return XML_ERROR_ASYNC_ENTITY; + return XML_ERROR_NONE; + case XML_TOK_NONE: + if (nextPtr) { + *nextPtr = s; + return XML_ERROR_NONE; + } + if (startTagLevel > 0) { + if (tagLevel != startTagLevel) + return XML_ERROR_ASYNC_ENTITY; + return XML_ERROR_NONE; + } + return XML_ERROR_NO_ELEMENTS; + case XML_TOK_INVALID: + *eventPP = next; + return XML_ERROR_INVALID_TOKEN; + case XML_TOK_PARTIAL: + if (nextPtr) { + *nextPtr = s; + return XML_ERROR_NONE; + } + return XML_ERROR_UNCLOSED_TOKEN; + case XML_TOK_PARTIAL_CHAR: + if (nextPtr) { + *nextPtr = s; + return XML_ERROR_NONE; + } + return XML_ERROR_PARTIAL_CHAR; + case XML_TOK_ENTITY_REF: + { + const XML_Char *name; + ENTITY *entity; + XML_Char ch = XmlPredefinedEntityName(enc, + s + enc->minBytesPerChar, + next - enc->minBytesPerChar); + if (ch) { + if (characterDataHandler) + characterDataHandler(handlerArg, &ch, 1); + else if (defaultHandler) + reportDefault(parser, enc, s, next); + break; + } + name = poolStoreString(&dtd.pool, enc, + s + enc->minBytesPerChar, + next - enc->minBytesPerChar); + if (!name) + return XML_ERROR_NO_MEMORY; + entity = (ENTITY *)lookup(&dtd.generalEntities, name, 0); + poolDiscard(&dtd.pool); + if (!entity) { + if (dtd.complete || dtd.standalone) + return XML_ERROR_UNDEFINED_ENTITY; + if (defaultHandler) + reportDefault(parser, enc, s, next); + break; + } + if (entity->open) + return XML_ERROR_RECURSIVE_ENTITY_REF; + if (entity->notation) + return XML_ERROR_BINARY_ENTITY_REF; + if (entity) { + if (entity->textPtr) { + enum XML_Error result; + OPEN_INTERNAL_ENTITY openEntity; + if (defaultHandler && !defaultExpandInternalEntities) { + reportDefault(parser, enc, s, next); + break; + } + entity->open = 1; + openEntity.next = openInternalEntities; + openInternalEntities = &openEntity; + openEntity.entity = entity; + openEntity.internalEventPtr = 0; + openEntity.internalEventEndPtr = 0; + result = doContent(parser, + tagLevel, + internalEncoding, + (char *)entity->textPtr, + (char *)(entity->textPtr + entity->textLen), + 0); + entity->open = 0; + openInternalEntities = openEntity.next; + if (result) + return result; + } + else if (externalEntityRefHandler) { + const XML_Char *context; + entity->open = 1; + context = getContext(parser); + entity->open = 0; + if (!context) + return XML_ERROR_NO_MEMORY; + if (!externalEntityRefHandler(externalEntityRefHandlerArg, + context, + entity->base, + entity->systemId, + entity->publicId)) + return XML_ERROR_EXTERNAL_ENTITY_HANDLING; + poolDiscard(&tempPool); + } + else if (defaultHandler) + reportDefault(parser, enc, s, next); + } + break; + } + case XML_TOK_START_TAG_WITH_ATTS: + if (!startElementHandler) { + enum XML_Error result = storeAtts(parser, enc, s, 0, 0); + if (result) + return result; + } + /* fall through */ + case XML_TOK_START_TAG_NO_ATTS: + { + TAG *tag; + if (freeTagList) { + tag = freeTagList; + freeTagList = freeTagList->parent; + } + else { + tag = malloc(sizeof(TAG)); + if (!tag) + return XML_ERROR_NO_MEMORY; + tag->buf = malloc(INIT_TAG_BUF_SIZE); + if (!tag->buf) + return XML_ERROR_NO_MEMORY; + tag->bufEnd = tag->buf + INIT_TAG_BUF_SIZE; + } + tag->bindings = 0; + tag->parent = tagStack; + tagStack = tag; + tag->name.localPart = 0; + tag->rawName = s + enc->minBytesPerChar; + tag->rawNameLength = XmlNameLength(enc, tag->rawName); + if (nextPtr) { + /* Need to guarantee that: + tag->buf + ROUND_UP(tag->rawNameLength, sizeof(XML_Char)) <= tag->bufEnd - sizeof(XML_Char) */ + if (tag->rawNameLength + (int)(sizeof(XML_Char) - 1) + (int)sizeof(XML_Char) > tag->bufEnd - tag->buf) { + int bufSize = tag->rawNameLength * 4; + bufSize = ROUND_UP(bufSize, sizeof(XML_Char)); + tag->buf = realloc(tag->buf, bufSize); + if (!tag->buf) + return XML_ERROR_NO_MEMORY; + tag->bufEnd = tag->buf + bufSize; + } + memcpy(tag->buf, tag->rawName, tag->rawNameLength); + tag->rawName = tag->buf; + } + ++tagLevel; + if (startElementHandler) { + enum XML_Error result; + XML_Char *toPtr; + for (;;) { + const char *rawNameEnd = tag->rawName + tag->rawNameLength; + const char *fromPtr = tag->rawName; + int bufSize; + if (nextPtr) + toPtr = (XML_Char *)(tag->buf + ROUND_UP(tag->rawNameLength, sizeof(XML_Char))); + else + toPtr = (XML_Char *)tag->buf; + tag->name.str = toPtr; + XmlConvert(enc, + &fromPtr, rawNameEnd, + (ICHAR **)&toPtr, (ICHAR *)tag->bufEnd - 1); + if (fromPtr == rawNameEnd) + break; + bufSize = (tag->bufEnd - tag->buf) << 1; + tag->buf = realloc(tag->buf, bufSize); + if (!tag->buf) + return XML_ERROR_NO_MEMORY; + tag->bufEnd = tag->buf + bufSize; + if (nextPtr) + tag->rawName = tag->buf; + } + *toPtr = XML_T('\0'); + result = storeAtts(parser, enc, s, &(tag->name), &(tag->bindings)); + if (result) + return result; + startElementHandler(handlerArg, tag->name.str, (const XML_Char **)atts); + poolClear(&tempPool); + } + else { + tag->name.str = 0; + if (defaultHandler) + reportDefault(parser, enc, s, next); + } + break; + } + case XML_TOK_EMPTY_ELEMENT_WITH_ATTS: + if (!startElementHandler) { + enum XML_Error result = storeAtts(parser, enc, s, 0, 0); + if (result) + return result; + } + /* fall through */ + case XML_TOK_EMPTY_ELEMENT_NO_ATTS: + if (startElementHandler || endElementHandler) { + const char *rawName = s + enc->minBytesPerChar; + enum XML_Error result; + BINDING *bindings = 0; + TAG_NAME name; + name.str = poolStoreString(&tempPool, enc, rawName, + rawName + XmlNameLength(enc, rawName)); + if (!name.str) + return XML_ERROR_NO_MEMORY; + poolFinish(&tempPool); + result = storeAtts(parser, enc, s, &name, &bindings); + if (result) + return result; + poolFinish(&tempPool); + if (startElementHandler) + startElementHandler(handlerArg, name.str, (const XML_Char **)atts); + if (endElementHandler) { + if (startElementHandler) + *eventPP = *eventEndPP; + endElementHandler(handlerArg, name.str); + } + poolClear(&tempPool); + while (bindings) { + BINDING *b = bindings; + if (endNamespaceDeclHandler) + endNamespaceDeclHandler(handlerArg, b->prefix->name); + bindings = bindings->nextTagBinding; + b->nextTagBinding = freeBindingList; + freeBindingList = b; + b->prefix->binding = b->prevPrefixBinding; + } + } + else if (defaultHandler) + reportDefault(parser, enc, s, next); + if (tagLevel == 0) + return epilogProcessor(parser, next, end, nextPtr); + break; + case XML_TOK_END_TAG: + if (tagLevel == startTagLevel) + return XML_ERROR_ASYNC_ENTITY; + else { + int len; + const char *rawName; + TAG *tag = tagStack; + tagStack = tag->parent; + tag->parent = freeTagList; + freeTagList = tag; + rawName = s + enc->minBytesPerChar*2; + len = XmlNameLength(enc, rawName); + if (len != tag->rawNameLength + || memcmp(tag->rawName, rawName, len) != 0) { + *eventPP = rawName; + return XML_ERROR_TAG_MISMATCH; + } + --tagLevel; + if (endElementHandler && tag->name.str) { + if (tag->name.localPart) { + XML_Char *to = (XML_Char *)tag->name.str + tag->name.uriLen; + const XML_Char *from = tag->name.localPart; + while ((*to++ = *from++) != 0) + ; + } + endElementHandler(handlerArg, tag->name.str); + } + else if (defaultHandler) + reportDefault(parser, enc, s, next); + while (tag->bindings) { + BINDING *b = tag->bindings; + if (endNamespaceDeclHandler) + endNamespaceDeclHandler(handlerArg, b->prefix->name); + tag->bindings = tag->bindings->nextTagBinding; + b->nextTagBinding = freeBindingList; + freeBindingList = b; + b->prefix->binding = b->prevPrefixBinding; + } + if (tagLevel == 0) + return epilogProcessor(parser, next, end, nextPtr); + } + break; + case XML_TOK_CHAR_REF: + { + int n = XmlCharRefNumber(enc, s); + if (n < 0) + return XML_ERROR_BAD_CHAR_REF; + if (characterDataHandler) { + XML_Char buf[XML_ENCODE_MAX]; + characterDataHandler(handlerArg, buf, XmlEncode(n, (ICHAR *)buf)); + } + else if (defaultHandler) + reportDefault(parser, enc, s, next); + } + break; + case XML_TOK_XML_DECL: + return XML_ERROR_MISPLACED_XML_PI; + case XML_TOK_DATA_NEWLINE: + if (characterDataHandler) { + XML_Char c = 0xA; + characterDataHandler(handlerArg, &c, 1); + } + else if (defaultHandler) + reportDefault(parser, enc, s, next); + break; + case XML_TOK_CDATA_SECT_OPEN: + { + enum XML_Error result; + if (startCdataSectionHandler) + startCdataSectionHandler(handlerArg); +#if 0 + /* Suppose you doing a transformation on a document that involves + changing only the character data. You set up a defaultHandler + and a characterDataHandler. The defaultHandler simply copies + characters through. The characterDataHandler does the transformation + and writes the characters out escaping them as necessary. This case + will fail to work if we leave out the following two lines (because & + and < inside CDATA sections will be incorrectly escaped). + + However, now we have a start/endCdataSectionHandler, so it seems + easier to let the user deal with this. */ + + else if (characterDataHandler) + characterDataHandler(handlerArg, dataBuf, 0); +#endif + else if (defaultHandler) + reportDefault(parser, enc, s, next); + result = doCdataSection(parser, enc, &next, end, nextPtr); + if (!next) { + processor = cdataSectionProcessor; + return result; + } + } + break; + case XML_TOK_TRAILING_RSQB: + if (nextPtr) { + *nextPtr = s; + return XML_ERROR_NONE; + } + if (characterDataHandler) { + if (MUST_CONVERT(enc, s)) { + ICHAR *dataPtr = (ICHAR *)dataBuf; + XmlConvert(enc, &s, end, &dataPtr, (ICHAR *)dataBufEnd); + characterDataHandler(handlerArg, dataBuf, + dataPtr - (ICHAR *)dataBuf); + } + else + characterDataHandler(handlerArg, + (XML_Char *)s, + (XML_Char *)end - (XML_Char *)s); + } + else if (defaultHandler) + reportDefault(parser, enc, s, end); + if (startTagLevel == 0) { + *eventPP = end; + return XML_ERROR_NO_ELEMENTS; + } + if (tagLevel != startTagLevel) { + *eventPP = end; + return XML_ERROR_ASYNC_ENTITY; + } + return XML_ERROR_NONE; + case XML_TOK_DATA_CHARS: + if (characterDataHandler) { + if (MUST_CONVERT(enc, s)) { + for (;;) { + ICHAR *dataPtr = (ICHAR *)dataBuf; + XmlConvert(enc, &s, next, &dataPtr, (ICHAR *)dataBufEnd); + *eventEndPP = s; + characterDataHandler(handlerArg, dataBuf, + dataPtr - (ICHAR *)dataBuf); + if (s == next) + break; + *eventPP = s; + } + } + else + characterDataHandler(handlerArg, + (XML_Char *)s, + (XML_Char *)next - (XML_Char *)s); + } + else if (defaultHandler) + reportDefault(parser, enc, s, next); + break; + case XML_TOK_PI: + if (!reportProcessingInstruction(parser, enc, s, next)) + return XML_ERROR_NO_MEMORY; + break; + case XML_TOK_COMMENT: + if (!reportComment(parser, enc, s, next)) + return XML_ERROR_NO_MEMORY; + break; + default: + if (defaultHandler) + reportDefault(parser, enc, s, next); + break; + } + *eventPP = s = next; + } + /* not reached */ +} + +/* If tagNamePtr is non-null, build a real list of attributes, +otherwise just check the attributes for well-formedness. */ + +static enum XML_Error storeAtts(XML_Parser parser, const ENCODING *enc, + const char *attStr, TAG_NAME *tagNamePtr, + BINDING **bindingsPtr) +{ + ELEMENT_TYPE *elementType = 0; + int nDefaultAtts = 0; + const XML_Char ** appAtts; + /* the attribute list to pass to the application */ + int attIndex = 0; + int i; + int n; + int nPrefixes = 0; + BINDING *binding; + const XML_Char *localPart; + + /* lookup the element type name */ + if (tagNamePtr) { + elementType = (ELEMENT_TYPE *) + lookup(&dtd.elementTypes, tagNamePtr->str, 0); + if (!elementType) { + tagNamePtr->str = poolCopyString(&dtd.pool, tagNamePtr->str); + if (!tagNamePtr->str) + return XML_ERROR_NO_MEMORY; + elementType = (ELEMENT_TYPE *) + lookup(&dtd.elementTypes, tagNamePtr->str, sizeof(ELEMENT_TYPE)); + if (!elementType) + return XML_ERROR_NO_MEMORY; + if (ns && !setElementTypePrefix(parser, elementType)) + return XML_ERROR_NO_MEMORY; + } + nDefaultAtts = elementType->nDefaultAtts; + } + /* get the attributes from the tokenizer */ + n = XmlGetAttributes(enc, attStr, attsSize, atts); + if (n + nDefaultAtts > attsSize) { + int oldAttsSize = attsSize; + attsSize = n + nDefaultAtts + INIT_ATTS_SIZE; + atts = realloc((void *)atts, attsSize * sizeof(ATTRIBUTE)); + if (!atts) + return XML_ERROR_NO_MEMORY; + if (n > oldAttsSize) + XmlGetAttributes(enc, attStr, n, atts); + } + appAtts = (const XML_Char **)atts; + for (i = 0; i < n; i++) { + /* add the name and value to the attribute list */ + ATTRIBUTE_ID *attId = getAttributeId(parser, enc, atts[i].name, + atts[i].name + + XmlNameLength(enc, atts[i].name)); + if (!attId) + return XML_ERROR_NO_MEMORY; + /* detect duplicate attributes */ + if ((attId->name)[-1]) { + if (enc == encoding) + eventPtr = atts[i].name; + return XML_ERROR_DUPLICATE_ATTRIBUTE; + } + (attId->name)[-1] = 1; + appAtts[attIndex++] = attId->name; + if (!atts[i].normalized) { + enum XML_Error result; + int isCdata = 1; + + /* figure out whether declared as other than CDATA */ + if (attId->maybeTokenized) { + int j; + for (j = 0; j < nDefaultAtts; j++) { + if (attId == elementType->defaultAtts[j].id) { + isCdata = elementType->defaultAtts[j].isCdata; + break; + } + } + } + + /* normalize the attribute value */ + result = storeAttributeValue(parser, enc, isCdata, + atts[i].valuePtr, atts[i].valueEnd, + &tempPool); + if (result) + return result; + if (tagNamePtr) { + appAtts[attIndex] = poolStart(&tempPool); + poolFinish(&tempPool); + } + else + poolDiscard(&tempPool); + } + else if (tagNamePtr) { + /* the value did not need normalizing */ + appAtts[attIndex] = + poolStoreString(&tempPool, enc, atts[i].valuePtr, atts[i].valueEnd); + if (appAtts[attIndex] == 0) + return XML_ERROR_NO_MEMORY; + poolFinish(&tempPool); + } + /* handle prefixed attribute names */ + if (attId->prefix && tagNamePtr) { + if (attId->xmlns) { + /* deal with namespace declarations here */ + if (!addBinding(parser, attId->prefix, attId, appAtts[attIndex], + bindingsPtr)) + return XML_ERROR_NO_MEMORY; + --attIndex; + } + else { + /* deal with other prefixed names later */ + attIndex++; + nPrefixes++; + (attId->name)[-1] = 2; + } + } + else + attIndex++; + } + if (tagNamePtr) { + int j; + nSpecifiedAtts = attIndex; + if (elementType->idAtt && (elementType->idAtt->name)[-1]) { + for (i = 0; i < attIndex; i += 2) + if (appAtts[i] == elementType->idAtt->name) { + idAttIndex = i; + break; + } + } + else + idAttIndex = -1; + /* do attribute defaulting */ + for (j = 0; j < nDefaultAtts; j++) { + const DEFAULT_ATTRIBUTE *da = elementType->defaultAtts + j; + if (!(da->id->name)[-1] && da->value) { + if (da->id->prefix) { + if (da->id->xmlns) { + if (!addBinding(parser, da->id->prefix, da->id, da->value, + bindingsPtr)) + return XML_ERROR_NO_MEMORY; + } + else { + (da->id->name)[-1] = 2; + nPrefixes++; + appAtts[attIndex++] = da->id->name; + appAtts[attIndex++] = da->value; + } + } + else { + (da->id->name)[-1] = 1; + appAtts[attIndex++] = da->id->name; + appAtts[attIndex++] = da->value; + } + } + } + appAtts[attIndex] = 0; + } + i = 0; + if (nPrefixes) { + /* expand prefixed attribute names */ + for (; i < attIndex; i += 2) { + if (appAtts[i][-1] == 2) { + ATTRIBUTE_ID *id; + ((XML_Char *)(appAtts[i]))[-1] = 0; + id = (ATTRIBUTE_ID *)lookup(&dtd.attributeIds, appAtts[i], 0); + if (id->prefix->binding) { + int j; + const BINDING *b = id->prefix->binding; + const XML_Char *s = appAtts[i]; + for (j = 0; j < b->uriLen; j++) { + if (!poolAppendChar(&tempPool, b->uri[j])) + return XML_ERROR_NO_MEMORY; + } + while (*s++ != ':') + ; + do { + if (!poolAppendChar(&tempPool, *s)) + return XML_ERROR_NO_MEMORY; + } while (*s++); + appAtts[i] = poolStart(&tempPool); + poolFinish(&tempPool); + } + if (!--nPrefixes) + break; + } + else + ((XML_Char *)(appAtts[i]))[-1] = 0; + } + } + /* clear the flags that say whether attributes were specified */ + for (; i < attIndex; i += 2) + ((XML_Char *)(appAtts[i]))[-1] = 0; + if (!tagNamePtr) + return XML_ERROR_NONE; + for (binding = *bindingsPtr; binding; binding = binding->nextTagBinding) + binding->attId->name[-1] = 0; + /* expand the element type name */ + if (elementType->prefix) { + binding = elementType->prefix->binding; + if (!binding) + return XML_ERROR_NONE; + localPart = tagNamePtr->str; + while (*localPart++ != XML_T(':')) + ; + } + else if (dtd.defaultPrefix.binding) { + binding = dtd.defaultPrefix.binding; + localPart = tagNamePtr->str; + } + else + return XML_ERROR_NONE; + tagNamePtr->localPart = localPart; + tagNamePtr->uriLen = binding->uriLen; + for (i = 0; localPart[i++];) + ; + n = i + binding->uriLen; + if (n > binding->uriAlloc) { + TAG *p; + XML_Char *uri = malloc((n + EXPAND_SPARE) * sizeof(XML_Char)); + if (!uri) + return XML_ERROR_NO_MEMORY; + binding->uriAlloc = n + EXPAND_SPARE; + memcpy(uri, binding->uri, binding->uriLen * sizeof(XML_Char)); + for (p = tagStack; p; p = p->parent) + if (p->name.str == binding->uri) + p->name.str = uri; + free(binding->uri); + binding->uri = uri; + } + memcpy(binding->uri + binding->uriLen, localPart, i * sizeof(XML_Char)); + tagNamePtr->str = binding->uri; + return XML_ERROR_NONE; +} + +static +int addBinding(XML_Parser parser, + PREFIX *prefix, + const ATTRIBUTE_ID *attId, + const XML_Char *uri, + BINDING **bindingsPtr) +{ + BINDING *b; + int len; + for (len = 0; uri[len]; len++) + ; + if (namespaceSeparator) + len++; + if (freeBindingList) { + b = freeBindingList; + if (len > b->uriAlloc) { + b->uri = realloc(b->uri, sizeof(XML_Char) * (len + EXPAND_SPARE)); + if (!b->uri) + return 0; + b->uriAlloc = len + EXPAND_SPARE; + } + freeBindingList = b->nextTagBinding; + } + else { + b = malloc(sizeof(BINDING)); + if (!b) + return 0; + b->uri = malloc(sizeof(XML_Char) * (len + EXPAND_SPARE)); + if (!b->uri) { + free(b); + return 0; + } + b->uriAlloc = len + EXPAND_SPARE; + } + b->uriLen = len; + memcpy(b->uri, uri, len * sizeof(XML_Char)); + if (namespaceSeparator) + b->uri[len - 1] = namespaceSeparator; + b->prefix = prefix; + b->attId = attId; + b->prevPrefixBinding = prefix->binding; + if (*uri == XML_T('\0') && prefix == &dtd.defaultPrefix) + prefix->binding = 0; + else + prefix->binding = b; + b->nextTagBinding = *bindingsPtr; + *bindingsPtr = b; + if (startNamespaceDeclHandler) + startNamespaceDeclHandler(handlerArg, prefix->name, + prefix->binding ? uri : 0); + return 1; +} + +/* The idea here is to avoid using stack for each CDATA section when +the whole file is parsed with one call. */ + +static +enum XML_Error cdataSectionProcessor(XML_Parser parser, + const char *start, + const char *end, + const char **endPtr) +{ + enum XML_Error result = + doCdataSection(parser, encoding, &start, end, endPtr); + if (start) { + processor = contentProcessor; + return contentProcessor(parser, start, end, endPtr); + } + return result; +} + +/* startPtr gets set to non-null is the section is closed, and to null if +the section is not yet closed. */ + +static +enum XML_Error doCdataSection(XML_Parser parser, + const ENCODING *enc, + const char **startPtr, + const char *end, + const char **nextPtr) +{ + const char *s = *startPtr; + const char **eventPP; + const char **eventEndPP; + if (enc == encoding) { + eventPP = &eventPtr; + *eventPP = s; + eventEndPP = &eventEndPtr; + } + else { + eventPP = &(openInternalEntities->internalEventPtr); + eventEndPP = &(openInternalEntities->internalEventEndPtr); + } + *eventPP = s; + *startPtr = 0; + for (;;) { + const char *next; + int tok = XmlCdataSectionTok(enc, s, end, &next); + *eventEndPP = next; + switch (tok) { + case XML_TOK_CDATA_SECT_CLOSE: + if (endCdataSectionHandler) + endCdataSectionHandler(handlerArg); + else if (defaultHandler) + reportDefault(parser, enc, s, next); + *startPtr = next; + return XML_ERROR_NONE; + case XML_TOK_DATA_NEWLINE: + if (characterDataHandler) { + XML_Char c = 0xA; + characterDataHandler(handlerArg, &c, 1); + } + else if (defaultHandler) + reportDefault(parser, enc, s, next); + break; + case XML_TOK_DATA_CHARS: + if (characterDataHandler) { + if (MUST_CONVERT(enc, s)) { + for (;;) { + ICHAR *dataPtr = (ICHAR *)dataBuf; + XmlConvert(enc, &s, next, &dataPtr, (ICHAR *)dataBufEnd); + *eventEndPP = next; + characterDataHandler(handlerArg, dataBuf, dataPtr - (ICHAR *)dataBuf); + if (s == next) + break; + *eventPP = s; + } + } + else + characterDataHandler(handlerArg, + (XML_Char *)s, + (XML_Char *)next - (XML_Char *)s); + } + else if (defaultHandler) + reportDefault(parser, enc, s, next); + break; + case XML_TOK_INVALID: + *eventPP = next; + return XML_ERROR_INVALID_TOKEN; + case XML_TOK_PARTIAL_CHAR: + if (nextPtr) { + *nextPtr = s; + return XML_ERROR_NONE; + } + return XML_ERROR_PARTIAL_CHAR; + case XML_TOK_PARTIAL: + case XML_TOK_NONE: + if (nextPtr) { + *nextPtr = s; + return XML_ERROR_NONE; + } + return XML_ERROR_UNCLOSED_CDATA_SECTION; + default: + abort(); + } + *eventPP = s = next; + } + /* not reached */ +} + +#ifdef XML_DTD + +/* The idea here is to avoid using stack for each IGNORE section when +the whole file is parsed with one call. */ + +static +enum XML_Error ignoreSectionProcessor(XML_Parser parser, + const char *start, + const char *end, + const char **endPtr) +{ + enum XML_Error result = + doIgnoreSection(parser, encoding, &start, end, endPtr); + if (start) { + processor = prologProcessor; + return prologProcessor(parser, start, end, endPtr); + } + return result; +} + +/* startPtr gets set to non-null is the section is closed, and to null if +the section is not yet closed. */ + +static +enum XML_Error doIgnoreSection(XML_Parser parser, + const ENCODING *enc, + const char **startPtr, + const char *end, + const char **nextPtr) +{ + const char *next; + int tok; + const char *s = *startPtr; + const char **eventPP; + const char **eventEndPP; + if (enc == encoding) { + eventPP = &eventPtr; + *eventPP = s; + eventEndPP = &eventEndPtr; + } + else { + eventPP = &(openInternalEntities->internalEventPtr); + eventEndPP = &(openInternalEntities->internalEventEndPtr); + } + *eventPP = s; + *startPtr = 0; + tok = XmlIgnoreSectionTok(enc, s, end, &next); + *eventEndPP = next; + switch (tok) { + case XML_TOK_IGNORE_SECT: + if (defaultHandler) + reportDefault(parser, enc, s, next); + *startPtr = next; + return XML_ERROR_NONE; + case XML_TOK_INVALID: + *eventPP = next; + return XML_ERROR_INVALID_TOKEN; + case XML_TOK_PARTIAL_CHAR: + if (nextPtr) { + *nextPtr = s; + return XML_ERROR_NONE; + } + return XML_ERROR_PARTIAL_CHAR; + case XML_TOK_PARTIAL: + case XML_TOK_NONE: + if (nextPtr) { + *nextPtr = s; + return XML_ERROR_NONE; + } + return XML_ERROR_SYNTAX; /* XML_ERROR_UNCLOSED_IGNORE_SECTION */ + default: + abort(); + } + /* not reached */ +} + +#endif /* XML_DTD */ + +static enum XML_Error +initializeEncoding(XML_Parser parser) +{ + const char *s; +#ifdef XML_UNICODE + char encodingBuf[128]; + if (!protocolEncodingName) + s = 0; + else { + int i; + for (i = 0; protocolEncodingName[i]; i++) { + if (i == sizeof(encodingBuf) - 1 + || (protocolEncodingName[i] & ~0x7f) != 0) { + encodingBuf[0] = '\0'; + break; + } + encodingBuf[i] = (char)protocolEncodingName[i]; + } + encodingBuf[i] = '\0'; + s = encodingBuf; + } +#else + s = protocolEncodingName; +#endif + if ((ns ? XmlInitEncodingNS : xmlrpc_XmlInitEncoding)(&initEncoding, &encoding, s)) + return XML_ERROR_NONE; + return handleUnknownEncoding(parser, protocolEncodingName); +} + +static enum XML_Error +processXmlDecl(XML_Parser parser, int isGeneralTextEntity, + const char *s, const char *next) +{ + const char *encodingName = 0; + const ENCODING *newEncoding = 0; + const char *version; + int standalone = -1; + if (!(ns + ? XmlParseXmlDeclNS + : xmlrpc_XmlParseXmlDecl)(isGeneralTextEntity, + encoding, + s, + next, + &eventPtr, + &version, + &encodingName, + &newEncoding, + &standalone)) + return XML_ERROR_SYNTAX; + if (!isGeneralTextEntity && standalone == 1) { + dtd.standalone = 1; +#ifdef XML_DTD + if (paramEntityParsing == XML_PARAM_ENTITY_PARSING_UNLESS_STANDALONE) + paramEntityParsing = XML_PARAM_ENTITY_PARSING_NEVER; +#endif /* XML_DTD */ + } + if (defaultHandler) + reportDefault(parser, encoding, s, next); + if (!protocolEncodingName) { + if (newEncoding) { + if (newEncoding->minBytesPerChar != encoding->minBytesPerChar) { + eventPtr = encodingName; + return XML_ERROR_INCORRECT_ENCODING; + } + encoding = newEncoding; + } + else if (encodingName) { + enum XML_Error result; + const XML_Char * s = + poolStoreString(&tempPool, + encoding, + encodingName, + encodingName + + XmlNameLength(encoding, encodingName)); + if (!s) + return XML_ERROR_NO_MEMORY; + result = handleUnknownEncoding(parser, s); + poolDiscard(&tempPool); + if (result == XML_ERROR_UNKNOWN_ENCODING) + eventPtr = encodingName; + return result; + } + } + return XML_ERROR_NONE; +} + +static enum XML_Error +handleUnknownEncoding(XML_Parser parser, const XML_Char *encodingName) +{ + if (unknownEncodingHandler) { + XML_Encoding info; + int i; + for (i = 0; i < 256; i++) + info.map[i] = -1; + info.convert = 0; + info.data = 0; + info.release = 0; + if (unknownEncodingHandler(unknownEncodingHandlerData, + encodingName, &info)) { + ENCODING *enc; + unknownEncodingMem = malloc(xmlrpc_XmlSizeOfUnknownEncoding()); + if (!unknownEncodingMem) { + if (info.release) + info.release(info.data); + return XML_ERROR_NO_MEMORY; + } + enc = (ns + ? XmlInitUnknownEncodingNS + : xmlrpc_XmlInitUnknownEncoding)(unknownEncodingMem, + info.map, + info.convert, + info.data); + if (enc) { + unknownEncodingData = info.data; + unknownEncodingRelease = info.release; + encoding = enc; + return XML_ERROR_NONE; + } + } + if (info.release) + info.release(info.data); + } + return XML_ERROR_UNKNOWN_ENCODING; +} + +static enum XML_Error +prologInitProcessor(XML_Parser parser, + const char *s, + const char *end, + const char **nextPtr) +{ + enum XML_Error result = initializeEncoding(parser); + if (result != XML_ERROR_NONE) + return result; + processor = prologProcessor; + return prologProcessor(parser, s, end, nextPtr); +} + +static enum XML_Error +prologProcessor(XML_Parser parser, + const char *s, + const char *end, + const char **nextPtr) +{ + const char *next; + int tok = XmlPrologTok(encoding, s, end, &next); + return doProlog(parser, encoding, s, end, tok, next, nextPtr); +} + +static enum XML_Error +doProlog(XML_Parser parser, + const ENCODING *enc, + const char *s, + const char *end, + int tok, + const char *next, + const char **nextPtr) +{ +#ifdef XML_DTD + static const XML_Char externalSubsetName[] = { '#' , '\0' }; +#endif /* XML_DTD */ + + const char **eventPP; + const char **eventEndPP; + if (enc == encoding) { + eventPP = &eventPtr; + eventEndPP = &eventEndPtr; + } + else { + eventPP = &(openInternalEntities->internalEventPtr); + eventEndPP = &(openInternalEntities->internalEventEndPtr); + } + for (;;) { + int role; + *eventPP = s; + *eventEndPP = next; + if (tok <= 0) { + if (nextPtr != 0 && tok != XML_TOK_INVALID) { + *nextPtr = s; + return XML_ERROR_NONE; + } + switch (tok) { + case XML_TOK_INVALID: + *eventPP = next; + return XML_ERROR_INVALID_TOKEN; + case XML_TOK_PARTIAL: + return XML_ERROR_UNCLOSED_TOKEN; + case XML_TOK_PARTIAL_CHAR: + return XML_ERROR_PARTIAL_CHAR; + case XML_TOK_NONE: +#ifdef XML_DTD + if (enc != encoding) + return XML_ERROR_NONE; + if (parentParser) { + if (XmlTokenRole(&prologState, XML_TOK_NONE, end, end, enc) + == XML_ROLE_ERROR) + return XML_ERROR_SYNTAX; + hadExternalDoctype = 0; + return XML_ERROR_NONE; + } +#endif /* XML_DTD */ + return XML_ERROR_NO_ELEMENTS; + default: + tok = -tok; + next = end; + break; + } + } + role = XmlTokenRole(&prologState, tok, s, next, enc); + switch (role) { + case XML_ROLE_XML_DECL: + { + enum XML_Error result = processXmlDecl(parser, 0, s, next); + if (result != XML_ERROR_NONE) + return result; + enc = encoding; + } + break; + case XML_ROLE_DOCTYPE_NAME: + if (startDoctypeDeclHandler) { + const XML_Char *name = poolStoreString(&tempPool, enc, s, next); + if (!name) + return XML_ERROR_NO_MEMORY; + startDoctypeDeclHandler(handlerArg, name); + poolClear(&tempPool); + } + break; +#ifdef XML_DTD + case XML_ROLE_TEXT_DECL: + { + enum XML_Error result = processXmlDecl(parser, 1, s, next); + if (result != XML_ERROR_NONE) + return result; + enc = encoding; + } + break; +#endif /* XML_DTD */ + case XML_ROLE_DOCTYPE_PUBLIC_ID: +#ifdef XML_DTD + declEntity = (ENTITY *)lookup(&dtd.paramEntities, + externalSubsetName, + sizeof(ENTITY)); + if (!declEntity) + return XML_ERROR_NO_MEMORY; +#endif /* XML_DTD */ + /* fall through */ + case XML_ROLE_ENTITY_PUBLIC_ID: + if (!XmlIsPublicId(enc, s, next, eventPP)) + return XML_ERROR_SYNTAX; + if (declEntity) { + XML_Char *tem = poolStoreString(&dtd.pool, + enc, + s + enc->minBytesPerChar, + next - enc->minBytesPerChar); + if (!tem) + return XML_ERROR_NO_MEMORY; + normalizePublicId(tem); + declEntity->publicId = tem; + poolFinish(&dtd.pool); + } + break; + case XML_ROLE_DOCTYPE_CLOSE: + if (dtd.complete && hadExternalDoctype) { + dtd.complete = 0; +#ifdef XML_DTD + if (paramEntityParsing && externalEntityRefHandler) { + ENTITY *entity = (ENTITY *)lookup(&dtd.paramEntities, + externalSubsetName, + 0); + if (!externalEntityRefHandler(externalEntityRefHandlerArg, + 0, + entity->base, + entity->systemId, + entity->publicId)) + return XML_ERROR_EXTERNAL_ENTITY_HANDLING; + } +#endif /* XML_DTD */ + if (!dtd.complete + && !dtd.standalone + && notStandaloneHandler + && !notStandaloneHandler(handlerArg)) + return XML_ERROR_NOT_STANDALONE; + } + if (endDoctypeDeclHandler) + endDoctypeDeclHandler(handlerArg); + break; + case XML_ROLE_INSTANCE_START: + processor = contentProcessor; + return contentProcessor(parser, s, end, nextPtr); + case XML_ROLE_ATTLIST_ELEMENT_NAME: + { + const XML_Char *name = poolStoreString(&dtd.pool, enc, s, next); + if (!name) + return XML_ERROR_NO_MEMORY; + declElementType = (ELEMENT_TYPE *) + lookup(&dtd.elementTypes, name, sizeof(ELEMENT_TYPE)); + if (!declElementType) + return XML_ERROR_NO_MEMORY; + if (declElementType->name != name) + poolDiscard(&dtd.pool); + else { + poolFinish(&dtd.pool); + if (!setElementTypePrefix(parser, declElementType)) + return XML_ERROR_NO_MEMORY; + } + break; + } + case XML_ROLE_ATTRIBUTE_NAME: + declAttributeId = getAttributeId(parser, enc, s, next); + if (!declAttributeId) + return XML_ERROR_NO_MEMORY; + declAttributeIsCdata = 0; + declAttributeIsId = 0; + break; + case XML_ROLE_ATTRIBUTE_TYPE_CDATA: + declAttributeIsCdata = 1; + break; + case XML_ROLE_ATTRIBUTE_TYPE_ID: + declAttributeIsId = 1; + break; + case XML_ROLE_IMPLIED_ATTRIBUTE_VALUE: + case XML_ROLE_REQUIRED_ATTRIBUTE_VALUE: + if (dtd.complete + && !defineAttribute(declElementType, declAttributeId, + declAttributeIsCdata, + declAttributeIsId, 0)) + return XML_ERROR_NO_MEMORY; + break; + case XML_ROLE_DEFAULT_ATTRIBUTE_VALUE: + case XML_ROLE_FIXED_ATTRIBUTE_VALUE: + { + const XML_Char *attVal; + enum XML_Error result + = storeAttributeValue(parser, enc, declAttributeIsCdata, + s + enc->minBytesPerChar, + next - enc->minBytesPerChar, + &dtd.pool); + if (result) + return result; + attVal = poolStart(&dtd.pool); + poolFinish(&dtd.pool); + if (dtd.complete + /* ID attributes aren't allowed to have a default */ + && !defineAttribute(declElementType, declAttributeId, + declAttributeIsCdata, 0, attVal)) + return XML_ERROR_NO_MEMORY; + break; + } + case XML_ROLE_ENTITY_VALUE: + { + enum XML_Error result = storeEntityValue(parser, enc, + s + enc->minBytesPerChar, + next - enc->minBytesPerChar); + if (declEntity) { + declEntity->textPtr = poolStart(&dtd.pool); + declEntity->textLen = poolLength(&dtd.pool); + poolFinish(&dtd.pool); + if (internalParsedEntityDeclHandler + /* Check it's not a parameter entity */ + && ((ENTITY *)lookup(&dtd.generalEntities, declEntity->name, 0) + == declEntity)) { + *eventEndPP = s; + internalParsedEntityDeclHandler(handlerArg, + declEntity->name, + declEntity->textPtr, + declEntity->textLen); + } + } + else + poolDiscard(&dtd.pool); + if (result != XML_ERROR_NONE) + return result; + } + break; + case XML_ROLE_DOCTYPE_SYSTEM_ID: + if (!dtd.standalone +#ifdef XML_DTD + && !paramEntityParsing +#endif /* XML_DTD */ + && notStandaloneHandler + && !notStandaloneHandler(handlerArg)) + return XML_ERROR_NOT_STANDALONE; + hadExternalDoctype = 1; +#ifndef XML_DTD + break; +#else /* XML_DTD */ + if (!declEntity) { + declEntity = (ENTITY *)lookup(&dtd.paramEntities, + externalSubsetName, + sizeof(ENTITY)); + if (!declEntity) + return XML_ERROR_NO_MEMORY; + } + /* fall through */ +#endif /* XML_DTD */ + case XML_ROLE_ENTITY_SYSTEM_ID: + if (declEntity) { + declEntity->systemId = poolStoreString(&dtd.pool, enc, + s + enc->minBytesPerChar, + next - enc->minBytesPerChar); + if (!declEntity->systemId) + return XML_ERROR_NO_MEMORY; + declEntity->base = curBase; + poolFinish(&dtd.pool); + } + break; + case XML_ROLE_ENTITY_NOTATION_NAME: + if (declEntity) { + declEntity->notation = poolStoreString(&dtd.pool, enc, s, next); + if (!declEntity->notation) + return XML_ERROR_NO_MEMORY; + poolFinish(&dtd.pool); + if (unparsedEntityDeclHandler) { + *eventEndPP = s; + unparsedEntityDeclHandler(handlerArg, + declEntity->name, + declEntity->base, + declEntity->systemId, + declEntity->publicId, + declEntity->notation); + } + + } + break; + case XML_ROLE_EXTERNAL_GENERAL_ENTITY_NO_NOTATION: + if (declEntity && externalParsedEntityDeclHandler) { + *eventEndPP = s; + externalParsedEntityDeclHandler(handlerArg, + declEntity->name, + declEntity->base, + declEntity->systemId, + declEntity->publicId); + } + break; + case XML_ROLE_GENERAL_ENTITY_NAME: + { + const XML_Char *name; + if (XmlPredefinedEntityName(enc, s, next)) { + declEntity = 0; + break; + } + name = poolStoreString(&dtd.pool, enc, s, next); + if (!name) + return XML_ERROR_NO_MEMORY; + if (dtd.complete) { + declEntity = (ENTITY *) + lookup(&dtd.generalEntities, name, sizeof(ENTITY)); + if (!declEntity) + return XML_ERROR_NO_MEMORY; + if (declEntity->name != name) { + poolDiscard(&dtd.pool); + declEntity = 0; + } + else + poolFinish(&dtd.pool); + } + else { + poolDiscard(&dtd.pool); + declEntity = 0; + } + } + break; + case XML_ROLE_PARAM_ENTITY_NAME: +#ifdef XML_DTD + if (dtd.complete) { + const XML_Char *name = poolStoreString(&dtd.pool, enc, s, next); + if (!name) + return XML_ERROR_NO_MEMORY; + declEntity = (ENTITY *) + lookup(&dtd.paramEntities, name, sizeof(ENTITY)); + if (!declEntity) + return XML_ERROR_NO_MEMORY; + if (declEntity->name != name) { + poolDiscard(&dtd.pool); + declEntity = 0; + } + else + poolFinish(&dtd.pool); + } +#else /* not XML_DTD */ + declEntity = 0; +#endif /* not XML_DTD */ + break; + case XML_ROLE_NOTATION_NAME: + declNotationPublicId = 0; + declNotationName = 0; + if (notationDeclHandler) { + declNotationName = poolStoreString(&tempPool, enc, s, next); + if (!declNotationName) + return XML_ERROR_NO_MEMORY; + poolFinish(&tempPool); + } + break; + case XML_ROLE_NOTATION_PUBLIC_ID: + if (!XmlIsPublicId(enc, s, next, eventPP)) + return XML_ERROR_SYNTAX; + if (declNotationName) { + XML_Char *tem = poolStoreString(&tempPool, + enc, + s + enc->minBytesPerChar, + next - enc->minBytesPerChar); + if (!tem) + return XML_ERROR_NO_MEMORY; + normalizePublicId(tem); + declNotationPublicId = tem; + poolFinish(&tempPool); + } + break; + case XML_ROLE_NOTATION_SYSTEM_ID: + if (declNotationName && notationDeclHandler) { + const XML_Char *systemId + = poolStoreString(&tempPool, enc, + s + enc->minBytesPerChar, + next - enc->minBytesPerChar); + if (!systemId) + return XML_ERROR_NO_MEMORY; + *eventEndPP = s; + notationDeclHandler(handlerArg, + declNotationName, + curBase, + systemId, + declNotationPublicId); + } + poolClear(&tempPool); + break; + case XML_ROLE_NOTATION_NO_SYSTEM_ID: + if (declNotationPublicId && notationDeclHandler) { + *eventEndPP = s; + notationDeclHandler(handlerArg, + declNotationName, + curBase, + 0, + declNotationPublicId); + } + poolClear(&tempPool); + break; + case XML_ROLE_ERROR: + switch (tok) { + case XML_TOK_PARAM_ENTITY_REF: + return XML_ERROR_PARAM_ENTITY_REF; + case XML_TOK_XML_DECL: + return XML_ERROR_MISPLACED_XML_PI; + default: + return XML_ERROR_SYNTAX; + } +#ifdef XML_DTD + case XML_ROLE_IGNORE_SECT: + { + enum XML_Error result; + if (defaultHandler) + reportDefault(parser, enc, s, next); + result = doIgnoreSection(parser, enc, &next, end, nextPtr); + if (!next) { + processor = ignoreSectionProcessor; + return result; + } + } + break; +#endif /* XML_DTD */ + case XML_ROLE_GROUP_OPEN: + if (prologState.level >= groupSize) { + if (groupSize) + groupConnector = realloc(groupConnector, groupSize *= 2); + else + groupConnector = malloc(groupSize = 32); + if (!groupConnector) + return XML_ERROR_NO_MEMORY; + } + groupConnector[prologState.level] = 0; + break; + case XML_ROLE_GROUP_SEQUENCE: + if (groupConnector[prologState.level] == '|') + return XML_ERROR_SYNTAX; + groupConnector[prologState.level] = ','; + break; + case XML_ROLE_GROUP_CHOICE: + if (groupConnector[prologState.level] == ',') + return XML_ERROR_SYNTAX; + groupConnector[prologState.level] = '|'; + break; + case XML_ROLE_PARAM_ENTITY_REF: +#ifdef XML_DTD + case XML_ROLE_INNER_PARAM_ENTITY_REF: + if (paramEntityParsing + && (dtd.complete || role == XML_ROLE_INNER_PARAM_ENTITY_REF)) { + const XML_Char *name; + ENTITY *entity; + name = poolStoreString(&dtd.pool, enc, + s + enc->minBytesPerChar, + next - enc->minBytesPerChar); + if (!name) + return XML_ERROR_NO_MEMORY; + entity = (ENTITY *)lookup(&dtd.paramEntities, name, 0); + poolDiscard(&dtd.pool); + if (!entity) { + /* FIXME what to do if !dtd.complete? */ + return XML_ERROR_UNDEFINED_ENTITY; + } + if (entity->open) + return XML_ERROR_RECURSIVE_ENTITY_REF; + if (entity->textPtr) { + enum XML_Error result; + result = processInternalParamEntity(parser, entity); + if (result != XML_ERROR_NONE) + return result; + break; + } + if (role == XML_ROLE_INNER_PARAM_ENTITY_REF) + return XML_ERROR_PARAM_ENTITY_REF; + if (externalEntityRefHandler) { + dtd.complete = 0; + entity->open = 1; + if (!externalEntityRefHandler(externalEntityRefHandlerArg, + 0, + entity->base, + entity->systemId, + entity->publicId)) { + entity->open = 0; + return XML_ERROR_EXTERNAL_ENTITY_HANDLING; + } + entity->open = 0; + if (dtd.complete) + break; + } + } +#endif /* XML_DTD */ + if (!dtd.standalone + && notStandaloneHandler + && !notStandaloneHandler(handlerArg)) + return XML_ERROR_NOT_STANDALONE; + dtd.complete = 0; + if (defaultHandler) + reportDefault(parser, enc, s, next); + break; + case XML_ROLE_NONE: + switch (tok) { + case XML_TOK_PI: + if (!reportProcessingInstruction(parser, enc, s, next)) + return XML_ERROR_NO_MEMORY; + break; + case XML_TOK_COMMENT: + if (!reportComment(parser, enc, s, next)) + return XML_ERROR_NO_MEMORY; + break; + } + break; + } + if (defaultHandler) { + switch (tok) { + case XML_TOK_PI: + case XML_TOK_COMMENT: + case XML_TOK_BOM: + case XML_TOK_XML_DECL: +#ifdef XML_DTD + case XML_TOK_IGNORE_SECT: +#endif /* XML_DTD */ + case XML_TOK_PARAM_ENTITY_REF: + break; + default: +#ifdef XML_DTD + if (role != XML_ROLE_IGNORE_SECT) +#endif /* XML_DTD */ + reportDefault(parser, enc, s, next); + } + } + s = next; + tok = XmlPrologTok(enc, s, end, &next); + } + /* not reached */ +} + +static +enum XML_Error epilogProcessor(XML_Parser parser, + const char *s, + const char *end, + const char **nextPtr) +{ + processor = epilogProcessor; + eventPtr = s; + for (;;) { + const char *next; + int tok = XmlPrologTok(encoding, s, end, &next); + eventEndPtr = next; + switch (tok) { + case -XML_TOK_PROLOG_S: + if (defaultHandler) { + eventEndPtr = end; + reportDefault(parser, encoding, s, end); + } + /* fall through */ + case XML_TOK_NONE: + if (nextPtr) + *nextPtr = end; + return XML_ERROR_NONE; + case XML_TOK_PROLOG_S: + if (defaultHandler) + reportDefault(parser, encoding, s, next); + break; + case XML_TOK_PI: + if (!reportProcessingInstruction(parser, encoding, s, next)) + return XML_ERROR_NO_MEMORY; + break; + case XML_TOK_COMMENT: + if (!reportComment(parser, encoding, s, next)) + return XML_ERROR_NO_MEMORY; + break; + case XML_TOK_INVALID: + eventPtr = next; + return XML_ERROR_INVALID_TOKEN; + case XML_TOK_PARTIAL: + if (nextPtr) { + *nextPtr = s; + return XML_ERROR_NONE; + } + return XML_ERROR_UNCLOSED_TOKEN; + case XML_TOK_PARTIAL_CHAR: + if (nextPtr) { + *nextPtr = s; + return XML_ERROR_NONE; + } + return XML_ERROR_PARTIAL_CHAR; + default: + return XML_ERROR_JUNK_AFTER_DOC_ELEMENT; + } + eventPtr = s = next; + } +} + +#ifdef XML_DTD + +static enum XML_Error +processInternalParamEntity(XML_Parser parser, ENTITY *entity) +{ + const char *s, *end, *next; + int tok; + enum XML_Error result; + OPEN_INTERNAL_ENTITY openEntity; + entity->open = 1; + openEntity.next = openInternalEntities; + openInternalEntities = &openEntity; + openEntity.entity = entity; + openEntity.internalEventPtr = 0; + openEntity.internalEventEndPtr = 0; + s = (char *)entity->textPtr; + end = (char *)(entity->textPtr + entity->textLen); + tok = XmlPrologTok(internalEncoding, s, end, &next); + result = doProlog(parser, internalEncoding, s, end, tok, next, 0); + entity->open = 0; + openInternalEntities = openEntity.next; + return result; +} + +#endif /* XML_DTD */ + + + +static enum XML_Error +errorProcessor(XML_Parser const parser ATTR_UNUSED, + const char * const s ATTR_UNUSED, + const char * const end ATTR_UNUSED, + const char ** const nextPtr ATTR_UNUSED) { + + return errorCode; +} + + + +static enum XML_Error +storeAttributeValue(XML_Parser parser, const ENCODING *enc, int isCdata, + const char *ptr, const char *end, + STRING_POOL *pool) +{ + enum XML_Error result = + appendAttributeValue(parser, enc, isCdata, ptr, end, pool); + if (result) + return result; + if (!isCdata && poolLength(pool) && poolLastChar(pool) == 0x20) + poolChop(pool); + if (!poolAppendChar(pool, XML_T('\0'))) + return XML_ERROR_NO_MEMORY; + return XML_ERROR_NONE; +} + +static enum XML_Error +appendAttributeValue(XML_Parser parser, const ENCODING *enc, int isCdata, + const char *ptr, const char *end, + STRING_POOL *pool) +{ + for (;;) { + const char *next; + int tok = XmlAttributeValueTok(enc, ptr, end, &next); + switch (tok) { + case XML_TOK_NONE: + return XML_ERROR_NONE; + case XML_TOK_INVALID: + if (enc == encoding) + eventPtr = next; + return XML_ERROR_INVALID_TOKEN; + case XML_TOK_PARTIAL: + if (enc == encoding) + eventPtr = ptr; + return XML_ERROR_INVALID_TOKEN; + case XML_TOK_CHAR_REF: + { + XML_Char buf[XML_ENCODE_MAX]; + int i; + int n = XmlCharRefNumber(enc, ptr); + if (n < 0) { + if (enc == encoding) + eventPtr = ptr; + return XML_ERROR_BAD_CHAR_REF; + } + if (!isCdata + && n == 0x20 /* space */ + && (poolLength(pool) == 0 || poolLastChar(pool) == 0x20)) + break; + n = XmlEncode(n, (ICHAR *)buf); + if (!n) { + if (enc == encoding) + eventPtr = ptr; + return XML_ERROR_BAD_CHAR_REF; + } + for (i = 0; i < n; i++) { + if (!poolAppendChar(pool, buf[i])) + return XML_ERROR_NO_MEMORY; + } + } + break; + case XML_TOK_DATA_CHARS: + if (!poolAppend(pool, enc, ptr, next)) + return XML_ERROR_NO_MEMORY; + break; + break; + case XML_TOK_TRAILING_CR: + next = ptr + enc->minBytesPerChar; + /* fall through */ + case XML_TOK_ATTRIBUTE_VALUE_S: + case XML_TOK_DATA_NEWLINE: + if (!isCdata && (poolLength(pool) == 0 || poolLastChar(pool) == 0x20)) + break; + if (!poolAppendChar(pool, 0x20)) + return XML_ERROR_NO_MEMORY; + break; + case XML_TOK_ENTITY_REF: + { + const XML_Char *name; + ENTITY *entity; + XML_Char ch = XmlPredefinedEntityName(enc, + ptr + enc->minBytesPerChar, + next - enc->minBytesPerChar); + if (ch) { + if (!poolAppendChar(pool, ch)) + return XML_ERROR_NO_MEMORY; + break; + } + name = poolStoreString(&temp2Pool, enc, + ptr + enc->minBytesPerChar, + next - enc->minBytesPerChar); + if (!name) + return XML_ERROR_NO_MEMORY; + entity = (ENTITY *)lookup(&dtd.generalEntities, name, 0); + poolDiscard(&temp2Pool); + if (!entity) { + if (dtd.complete) { + if (enc == encoding) + eventPtr = ptr; + return XML_ERROR_UNDEFINED_ENTITY; + } + } + else if (entity->open) { + if (enc == encoding) + eventPtr = ptr; + return XML_ERROR_RECURSIVE_ENTITY_REF; + } + else if (entity->notation) { + if (enc == encoding) + eventPtr = ptr; + return XML_ERROR_BINARY_ENTITY_REF; + } + else if (!entity->textPtr) { + if (enc == encoding) + eventPtr = ptr; + return XML_ERROR_ATTRIBUTE_EXTERNAL_ENTITY_REF; + } + else { + enum XML_Error result; + const XML_Char *textEnd = entity->textPtr + entity->textLen; + entity->open = 1; + result = appendAttributeValue(parser, internalEncoding, + isCdata, (char *)entity->textPtr, + (char *)textEnd, pool); + entity->open = 0; + if (result) + return result; + } + } + break; + default: + abort(); + } + ptr = next; + } + /* not reached */ +} + +static +enum XML_Error storeEntityValue(XML_Parser parser, + const ENCODING *enc, + const char *entityTextPtr, + const char *entityTextEnd) +{ + STRING_POOL *pool = &(dtd.pool); + for (;;) { + const char *next; + int tok = XmlEntityValueTok(enc, entityTextPtr, entityTextEnd, &next); + switch (tok) { + case XML_TOK_PARAM_ENTITY_REF: +#ifdef XML_DTD + if (parentParser || enc != encoding) { + enum XML_Error result; + const XML_Char *name; + ENTITY *entity; + name = poolStoreString(&tempPool, enc, + entityTextPtr + enc->minBytesPerChar, + next - enc->minBytesPerChar); + if (!name) + return XML_ERROR_NO_MEMORY; + entity = (ENTITY *)lookup(&dtd.paramEntities, name, 0); + poolDiscard(&tempPool); + if (!entity) { + if (enc == encoding) + eventPtr = entityTextPtr; + return XML_ERROR_UNDEFINED_ENTITY; + } + if (entity->open) { + if (enc == encoding) + eventPtr = entityTextPtr; + return XML_ERROR_RECURSIVE_ENTITY_REF; + } + if (entity->systemId) { + if (enc == encoding) + eventPtr = entityTextPtr; + return XML_ERROR_PARAM_ENTITY_REF; + } + entity->open = 1; + result = storeEntityValue(parser, + internalEncoding, + (char *)entity->textPtr, + (char *)(entity->textPtr + entity->textLen)); + entity->open = 0; + if (result) + return result; + break; + } +#endif /* XML_DTD */ + eventPtr = entityTextPtr; + return XML_ERROR_SYNTAX; + case XML_TOK_NONE: + return XML_ERROR_NONE; + case XML_TOK_ENTITY_REF: + case XML_TOK_DATA_CHARS: + if (!poolAppend(pool, enc, entityTextPtr, next)) + return XML_ERROR_NO_MEMORY; + break; + case XML_TOK_TRAILING_CR: + next = entityTextPtr + enc->minBytesPerChar; + /* fall through */ + case XML_TOK_DATA_NEWLINE: + if (pool->end == pool->ptr && !poolGrow(pool)) + return XML_ERROR_NO_MEMORY; + *(pool->ptr)++ = 0xA; + break; + case XML_TOK_CHAR_REF: + { + XML_Char buf[XML_ENCODE_MAX]; + int i; + int n = XmlCharRefNumber(enc, entityTextPtr); + if (n < 0) { + if (enc == encoding) + eventPtr = entityTextPtr; + return XML_ERROR_BAD_CHAR_REF; + } + n = XmlEncode(n, (ICHAR *)buf); + if (!n) { + if (enc == encoding) + eventPtr = entityTextPtr; + return XML_ERROR_BAD_CHAR_REF; + } + for (i = 0; i < n; i++) { + if (pool->end == pool->ptr && !poolGrow(pool)) + return XML_ERROR_NO_MEMORY; + *(pool->ptr)++ = buf[i]; + } + } + break; + case XML_TOK_PARTIAL: + if (enc == encoding) + eventPtr = entityTextPtr; + return XML_ERROR_INVALID_TOKEN; + case XML_TOK_INVALID: + if (enc == encoding) + eventPtr = next; + return XML_ERROR_INVALID_TOKEN; + default: + abort(); + } + entityTextPtr = next; + } + /* not reached */ +} + +static void +normalizeLines(XML_Char *s) +{ + XML_Char *p; + for (;; s++) { + if (*s == XML_T('\0')) + return; + if (*s == 0xD) + break; + } + p = s; + do { + if (*s == 0xD) { + *p++ = 0xA; + if (*++s == 0xA) + s++; + } + else + *p++ = *s++; + } while (*s); + *p = XML_T('\0'); +} + +static int +reportProcessingInstruction(XML_Parser parser, + const ENCODING *enc, + const char *start, + const char *end) +{ + const XML_Char *target; + XML_Char *data; + const char *tem; + if (!processingInstructionHandler) { + if (defaultHandler) + reportDefault(parser, enc, start, end); + return 1; + } + start += enc->minBytesPerChar * 2; + tem = start + XmlNameLength(enc, start); + target = poolStoreString(&tempPool, enc, start, tem); + if (!target) + return 0; + poolFinish(&tempPool); + data = poolStoreString(&tempPool, enc, + XmlSkipS(enc, tem), + end - enc->minBytesPerChar*2); + if (!data) + return 0; + normalizeLines(data); + processingInstructionHandler(handlerArg, target, data); + poolClear(&tempPool); + return 1; +} + +static int +reportComment(XML_Parser parser, + const ENCODING *enc, + const char *start, + const char *end) +{ + XML_Char *data; + if (!commentHandler) { + if (defaultHandler) + reportDefault(parser, enc, start, end); + return 1; + } + data = poolStoreString(&tempPool, + enc, + start + enc->minBytesPerChar * 4, + end - enc->minBytesPerChar * 3); + if (!data) + return 0; + normalizeLines(data); + commentHandler(handlerArg, data); + poolClear(&tempPool); + return 1; +} + +static void +reportDefault(XML_Parser parser, + const ENCODING *enc, + const char *s, + const char *end) +{ + if (MUST_CONVERT(enc, s)) { + const char **eventPP; + const char **eventEndPP; + if (enc == encoding) { + eventPP = &eventPtr; + eventEndPP = &eventEndPtr; + } + else { + eventPP = &(openInternalEntities->internalEventPtr); + eventEndPP = &(openInternalEntities->internalEventEndPtr); + } + do { + ICHAR *dataPtr = (ICHAR *)dataBuf; + XmlConvert(enc, &s, end, &dataPtr, (ICHAR *)dataBufEnd); + *eventEndPP = s; + defaultHandler(handlerArg, dataBuf, dataPtr - (ICHAR *)dataBuf); + *eventPP = s; + } while (s != end); + } + else + defaultHandler(handlerArg, (XML_Char *)s, (XML_Char *)end - (XML_Char *)s); +} + + +static int +defineAttribute(ELEMENT_TYPE *type, + ATTRIBUTE_ID *attId, + int isCdata, + int isId, + const XML_Char *value) +{ + DEFAULT_ATTRIBUTE *att; + if (value || isId) { + /* The handling of default attributes gets messed up if we have + a default which duplicates a non-default. */ + int i; + for (i = 0; i < type->nDefaultAtts; i++) + if (attId == type->defaultAtts[i].id) + return 1; + if (isId && !type->idAtt && !attId->xmlns) + type->idAtt = attId; + } + if (type->nDefaultAtts == type->allocDefaultAtts) { + if (type->allocDefaultAtts == 0) { + type->allocDefaultAtts = 8; + type->defaultAtts = + malloc(type->allocDefaultAtts*sizeof(DEFAULT_ATTRIBUTE)); + } + else { + type->allocDefaultAtts *= 2; + type->defaultAtts = + realloc(type->defaultAtts, + type->allocDefaultAtts*sizeof(DEFAULT_ATTRIBUTE)); + } + if (!type->defaultAtts) + return 0; + } + att = type->defaultAtts + type->nDefaultAtts; + att->id = attId; + att->value = value; + att->isCdata = isCdata; + if (!isCdata) + attId->maybeTokenized = 1; + type->nDefaultAtts += 1; + return 1; +} + +static int setElementTypePrefix(XML_Parser parser, ELEMENT_TYPE *elementType) +{ + const XML_Char *name; + for (name = elementType->name; *name; name++) { + if (*name == XML_T(':')) { + PREFIX *prefix; + const XML_Char *s; + for (s = elementType->name; s != name; s++) { + if (!poolAppendChar(&dtd.pool, *s)) + return 0; + } + if (!poolAppendChar(&dtd.pool, XML_T('\0'))) + return 0; + prefix = (PREFIX *) + lookup(&dtd.prefixes, poolStart(&dtd.pool), sizeof(PREFIX)); + if (!prefix) + return 0; + if (prefix->name == poolStart(&dtd.pool)) + poolFinish(&dtd.pool); + else + poolDiscard(&dtd.pool); + elementType->prefix = prefix; + + } + } + return 1; +} + +static ATTRIBUTE_ID * +getAttributeId(XML_Parser parser, + const ENCODING *enc, + const char *start, + const char *end) +{ + ATTRIBUTE_ID *id; + const XML_Char *name; + if (!poolAppendChar(&dtd.pool, XML_T('\0'))) + return 0; + name = poolStoreString(&dtd.pool, enc, start, end); + if (!name) + return 0; + ++name; + id = (ATTRIBUTE_ID *)lookup(&dtd.attributeIds, name, sizeof(ATTRIBUTE_ID)); + if (!id) + return 0; + if (id->name != name) + poolDiscard(&dtd.pool); + else { + poolFinish(&dtd.pool); + if (!ns) + ; + else if (name[0] == 'x' + && name[1] == 'm' + && name[2] == 'l' + && name[3] == 'n' + && name[4] == 's' + && (name[5] == XML_T('\0') || name[5] == XML_T(':'))) { + if (name[5] == '\0') + id->prefix = &dtd.defaultPrefix; + else + id->prefix = (PREFIX *)lookup(&dtd.prefixes, name + 6, sizeof(PREFIX)); + id->xmlns = 1; + } + else { + int i; + for (i = 0; name[i]; i++) { + if (name[i] == XML_T(':')) { + int j; + for (j = 0; j < i; j++) { + if (!poolAppendChar(&dtd.pool, name[j])) + return 0; + } + if (!poolAppendChar(&dtd.pool, XML_T('\0'))) + return 0; + id->prefix = (PREFIX *) + lookup(&dtd.prefixes, poolStart(&dtd.pool), sizeof(PREFIX)); + if (id->prefix->name == poolStart(&dtd.pool)) + poolFinish(&dtd.pool); + else + poolDiscard(&dtd.pool); + break; + } + } + } + } + return id; +} + +#define CONTEXT_SEP XML_T('\f') + +static +const XML_Char *getContext(XML_Parser parser) +{ + HASH_TABLE_ITER iter; + int needSep = 0; + + if (dtd.defaultPrefix.binding) { + int i; + int len; + if (!poolAppendChar(&tempPool, XML_T('='))) + return 0; + len = dtd.defaultPrefix.binding->uriLen; + if (namespaceSeparator != XML_T('\0')) + len--; + for (i = 0; i < len; i++) + if (!poolAppendChar(&tempPool, dtd.defaultPrefix.binding->uri[i])) + return 0; + needSep = 1; + } + + hashTableIterInit(&iter, &(dtd.prefixes)); + for (;;) { + int i; + int len; + const XML_Char *s; + PREFIX *prefix = (PREFIX *)hashTableIterNext(&iter); + if (!prefix) + break; + if (!prefix->binding) + continue; + if (needSep && !poolAppendChar(&tempPool, CONTEXT_SEP)) + return 0; + for (s = prefix->name; *s; s++) + if (!poolAppendChar(&tempPool, *s)) + return 0; + if (!poolAppendChar(&tempPool, XML_T('='))) + return 0; + len = prefix->binding->uriLen; + if (namespaceSeparator != XML_T('\0')) + len--; + for (i = 0; i < len; i++) + if (!poolAppendChar(&tempPool, prefix->binding->uri[i])) + return 0; + needSep = 1; + } + + + hashTableIterInit(&iter, &(dtd.generalEntities)); + for (;;) { + const XML_Char *s; + ENTITY *e = (ENTITY *)hashTableIterNext(&iter); + if (!e) + break; + if (!e->open) + continue; + if (needSep && !poolAppendChar(&tempPool, CONTEXT_SEP)) + return 0; + for (s = e->name; *s; s++) + if (!poolAppendChar(&tempPool, *s)) + return 0; + needSep = 1; + } + + if (!poolAppendChar(&tempPool, XML_T('\0'))) + return 0; + return tempPool.start; +} + +static +int setContext(XML_Parser parser, const XML_Char *context) +{ + const XML_Char *s = context; + + while (*context != XML_T('\0')) { + if (*s == CONTEXT_SEP || *s == XML_T('\0')) { + ENTITY *e; + if (!poolAppendChar(&tempPool, XML_T('\0'))) + return 0; + e = (ENTITY *)lookup(&dtd.generalEntities, poolStart(&tempPool), 0); + if (e) + e->open = 1; + if (*s != XML_T('\0')) + s++; + context = s; + poolDiscard(&tempPool); + } + else if (*s == '=') { + PREFIX *prefix; + if (poolLength(&tempPool) == 0) + prefix = &dtd.defaultPrefix; + else { + if (!poolAppendChar(&tempPool, XML_T('\0'))) + return 0; + prefix = (PREFIX *) + lookup(&dtd.prefixes, poolStart(&tempPool), sizeof(PREFIX)); + if (!prefix) + return 0; + if (prefix->name == poolStart(&tempPool)) { + prefix->name = poolCopyString(&dtd.pool, prefix->name); + if (!prefix->name) + return 0; + } + poolDiscard(&tempPool); + } + for (context = s + 1; + *context != CONTEXT_SEP && *context != XML_T('\0'); + ++context) + if (!poolAppendChar(&tempPool, *context)) + return 0; + if (!poolAppendChar(&tempPool, XML_T('\0'))) + return 0; + if (!addBinding(parser, prefix, 0, poolStart(&tempPool), + &inheritedBindings)) + return 0; + poolDiscard(&tempPool); + if (*context != XML_T('\0')) + ++context; + s = context; + } + else { + if (!poolAppendChar(&tempPool, *s)) + return 0; + s++; + } + } + return 1; +} + + +static +void normalizePublicId(XML_Char *publicId) +{ + XML_Char *p = publicId; + XML_Char *s; + for (s = publicId; *s; s++) { + switch (*s) { + case 0x20: + case 0xD: + case 0xA: + if (p != publicId && p[-1] != 0x20) + *p++ = 0x20; + break; + default: + *p++ = *s; + } + } + if (p != publicId && p[-1] == 0x20) + --p; + *p = XML_T('\0'); +} + +static int dtdInit(DTD *p) +{ + poolInit(&(p->pool)); + hashTableInit(&(p->generalEntities)); + hashTableInit(&(p->elementTypes)); + hashTableInit(&(p->attributeIds)); + hashTableInit(&(p->prefixes)); + p->complete = 1; + p->standalone = 0; +#ifdef XML_DTD + hashTableInit(&(p->paramEntities)); +#endif /* XML_DTD */ + p->defaultPrefix.name = 0; + p->defaultPrefix.binding = 0; + return 1; +} + +#ifdef XML_DTD + +static void dtdSwap(DTD *p1, DTD *p2) +{ + DTD tem; + memcpy(&tem, p1, sizeof(DTD)); + memcpy(p1, p2, sizeof(DTD)); + memcpy(p2, &tem, sizeof(DTD)); +} + +#endif /* XML_DTD */ + +static void dtdDestroy(DTD *p) +{ + HASH_TABLE_ITER iter; + hashTableIterInit(&iter, &(p->elementTypes)); + for (;;) { + ELEMENT_TYPE *e = (ELEMENT_TYPE *)hashTableIterNext(&iter); + if (!e) + break; + if (e->allocDefaultAtts != 0) + free(e->defaultAtts); + } + hashTableDestroy(&(p->generalEntities)); +#ifdef XML_DTD + hashTableDestroy(&(p->paramEntities)); +#endif /* XML_DTD */ + hashTableDestroy(&(p->elementTypes)); + hashTableDestroy(&(p->attributeIds)); + hashTableDestroy(&(p->prefixes)); + poolDestroy(&(p->pool)); +} + +/* Do a deep copy of the DTD. Return 0 for out of memory; non-zero otherwise. +The new DTD has already been initialized. */ + +static int dtdCopy(DTD *newDtd, const DTD *oldDtd) +{ + HASH_TABLE_ITER iter; + + /* Copy the prefix table. */ + + hashTableIterInit(&iter, &(oldDtd->prefixes)); + for (;;) { + const XML_Char *name; + const PREFIX *oldP = (PREFIX *)hashTableIterNext(&iter); + if (!oldP) + break; + name = poolCopyString(&(newDtd->pool), oldP->name); + if (!name) + return 0; + if (!lookup(&(newDtd->prefixes), name, sizeof(PREFIX))) + return 0; + } + + hashTableIterInit(&iter, &(oldDtd->attributeIds)); + + /* Copy the attribute id table. */ + + for (;;) { + ATTRIBUTE_ID *newA; + const XML_Char *name; + const ATTRIBUTE_ID *oldA = (ATTRIBUTE_ID *)hashTableIterNext(&iter); + + if (!oldA) + break; + /* Remember to allocate the scratch byte before the name. */ + if (!poolAppendChar(&(newDtd->pool), XML_T('\0'))) + return 0; + name = poolCopyString(&(newDtd->pool), oldA->name); + if (!name) + return 0; + ++name; + newA = (ATTRIBUTE_ID *) + lookup(&(newDtd->attributeIds), name, sizeof(ATTRIBUTE_ID)); + if (!newA) + return 0; + newA->maybeTokenized = oldA->maybeTokenized; + if (oldA->prefix) { + newA->xmlns = oldA->xmlns; + if (oldA->prefix == &oldDtd->defaultPrefix) + newA->prefix = &newDtd->defaultPrefix; + else + newA->prefix = (PREFIX *) + lookup(&(newDtd->prefixes), oldA->prefix->name, 0); + } + } + + /* Copy the element type table. */ + + hashTableIterInit(&iter, &(oldDtd->elementTypes)); + + for (;;) { + int i; + ELEMENT_TYPE *newE; + const XML_Char *name; + const ELEMENT_TYPE *oldE = (ELEMENT_TYPE *)hashTableIterNext(&iter); + if (!oldE) + break; + name = poolCopyString(&(newDtd->pool), oldE->name); + if (!name) + return 0; + newE = (ELEMENT_TYPE *) + lookup(&(newDtd->elementTypes), name, sizeof(ELEMENT_TYPE)); + if (!newE) + return 0; + if (oldE->nDefaultAtts) { + newE->defaultAtts = (DEFAULT_ATTRIBUTE *) + malloc(oldE->nDefaultAtts * sizeof(DEFAULT_ATTRIBUTE)); + if (!newE->defaultAtts) + return 0; + } + if (oldE->idAtt) + newE->idAtt = (ATTRIBUTE_ID *) + lookup(&(newDtd->attributeIds), oldE->idAtt->name, 0); + newE->allocDefaultAtts = newE->nDefaultAtts = oldE->nDefaultAtts; + if (oldE->prefix) + newE->prefix = (PREFIX *) + lookup(&(newDtd->prefixes), oldE->prefix->name, 0); + for (i = 0; i < newE->nDefaultAtts; i++) { + newE->defaultAtts[i].id = (ATTRIBUTE_ID *) + lookup(&(newDtd->attributeIds), oldE->defaultAtts[i].id->name, 0); + newE->defaultAtts[i].isCdata = oldE->defaultAtts[i].isCdata; + if (oldE->defaultAtts[i].value) { + newE->defaultAtts[i].value = + poolCopyString(&(newDtd->pool), oldE->defaultAtts[i].value); + if (!newE->defaultAtts[i].value) + return 0; + } + else + newE->defaultAtts[i].value = 0; + } + } + + /* Copy the entity tables. */ + if (!copyEntityTable(&(newDtd->generalEntities), + &(newDtd->pool), + &(oldDtd->generalEntities))) + return 0; + +#ifdef XML_DTD + if (!copyEntityTable(&(newDtd->paramEntities), + &(newDtd->pool), + &(oldDtd->paramEntities))) + return 0; +#endif /* XML_DTD */ + + newDtd->complete = oldDtd->complete; + newDtd->standalone = oldDtd->standalone; + return 1; +} + +static int copyEntityTable(HASH_TABLE *newTable, + STRING_POOL *newPool, + const HASH_TABLE *oldTable) +{ + HASH_TABLE_ITER iter; + const XML_Char *cachedOldBase = 0; + const XML_Char *cachedNewBase = 0; + + hashTableIterInit(&iter, oldTable); + + for (;;) { + ENTITY *newE; + const XML_Char *name; + const ENTITY *oldE = (ENTITY *)hashTableIterNext(&iter); + if (!oldE) + break; + name = poolCopyString(newPool, oldE->name); + if (!name) + return 0; + newE = (ENTITY *)lookup(newTable, name, sizeof(ENTITY)); + if (!newE) + return 0; + if (oldE->systemId) { + const XML_Char *tem = poolCopyString(newPool, oldE->systemId); + if (!tem) + return 0; + newE->systemId = tem; + if (oldE->base) { + if (oldE->base == cachedOldBase) + newE->base = cachedNewBase; + else { + cachedOldBase = oldE->base; + tem = poolCopyString(newPool, cachedOldBase); + if (!tem) + return 0; + cachedNewBase = newE->base = tem; + } + } + } + else { + const XML_Char *tem = + poolCopyStringN(newPool, oldE->textPtr, oldE->textLen); + if (!tem) + return 0; + newE->textPtr = tem; + newE->textLen = oldE->textLen; + } + if (oldE->notation) { + const XML_Char *tem = poolCopyString(newPool, oldE->notation); + if (!tem) + return 0; + newE->notation = tem; + } + } + return 1; +} + +#define INIT_SIZE 64 + +static +int keyeq(KEY s1, KEY s2) +{ + for (; *s1 == *s2; s1++, s2++) + if (*s1 == 0) + return 1; + return 0; +} + +static +unsigned long hash(KEY s) +{ + unsigned long h = 0; + while (*s) + h = (h << 5) + h + (unsigned char)*s++; + return h; +} + +static +NAMED *lookup(HASH_TABLE *table, KEY name, size_t createSize) +{ + size_t i; + if (table->size == 0) { + if (!createSize) + return 0; + table->v = calloc(INIT_SIZE, sizeof(NAMED *)); + if (!table->v) + return 0; + table->size = INIT_SIZE; + table->usedLim = INIT_SIZE / 2; + i = hash(name) & (table->size - 1); + } + else { + unsigned long h = hash(name); + for (i = h & (table->size - 1); + table->v[i]; + i == 0 ? i = table->size - 1 : --i) { + if (keyeq(name, table->v[i]->name)) + return table->v[i]; + } + if (!createSize) + return 0; + if (table->used == table->usedLim) { + /* check for overflow */ + size_t newSize = table->size * 2; + NAMED **newV = calloc(newSize, sizeof(NAMED *)); + if (!newV) + return 0; + for (i = 0; i < table->size; i++) + if (table->v[i]) { + size_t j; + for (j = hash(table->v[i]->name) & (newSize - 1); + newV[j]; + j == 0 ? j = newSize - 1 : --j) + ; + newV[j] = table->v[i]; + } + free(table->v); + table->v = newV; + table->size = newSize; + table->usedLim = newSize/2; + for (i = h & (table->size - 1); + table->v[i]; + i == 0 ? i = table->size - 1 : --i) + ; + } + } + table->v[i] = calloc(1, createSize); + if (!table->v[i]) + return 0; + table->v[i]->name = name; + (table->used)++; + return table->v[i]; +} + +static +void hashTableDestroy(HASH_TABLE *table) +{ + size_t i; + for (i = 0; i < table->size; i++) { + NAMED *p = table->v[i]; + if (p) + free(p); + } + if (table->v) + free(table->v); +} + +static +void hashTableInit(HASH_TABLE *p) +{ + p->size = 0; + p->usedLim = 0; + p->used = 0; + p->v = 0; +} + +static +void hashTableIterInit(HASH_TABLE_ITER *iter, const HASH_TABLE *table) +{ + iter->p = table->v; + iter->end = iter->p + table->size; +} + +static +NAMED *hashTableIterNext(HASH_TABLE_ITER *iter) +{ + while (iter->p != iter->end) { + NAMED *tem = *(iter->p)++; + if (tem) + return tem; + } + return 0; +} + + +static +void poolInit(STRING_POOL *pool) +{ + pool->blocks = 0; + pool->freeBlocks = 0; + pool->start = 0; + pool->ptr = 0; + pool->end = 0; +} + +static +void poolClear(STRING_POOL *pool) +{ + if (!pool->freeBlocks) + pool->freeBlocks = pool->blocks; + else { + BLOCK *p = pool->blocks; + while (p) { + BLOCK *tem = p->next; + p->next = pool->freeBlocks; + pool->freeBlocks = p; + p = tem; + } + } + pool->blocks = 0; + pool->start = 0; + pool->ptr = 0; + pool->end = 0; +} + +static +void poolDestroy(STRING_POOL *pool) +{ + BLOCK *p = pool->blocks; + while (p) { + BLOCK *tem = p->next; + free(p); + p = tem; + } + pool->blocks = 0; + p = pool->freeBlocks; + while (p) { + BLOCK *tem = p->next; + free(p); + p = tem; + } + pool->freeBlocks = 0; + pool->ptr = 0; + pool->start = 0; + pool->end = 0; +} + +static +XML_Char *poolAppend(STRING_POOL *pool, const ENCODING *enc, + const char *ptr, const char *end) +{ + if (!pool->ptr && !poolGrow(pool)) + return 0; + for (;;) { + XmlConvert(enc, &ptr, end, (ICHAR **)&(pool->ptr), (ICHAR *)pool->end); + if (ptr == end) + break; + if (!poolGrow(pool)) + return 0; + } + return pool->start; +} + +static const XML_Char *poolCopyString(STRING_POOL *pool, const XML_Char *s) +{ + do { + if (!poolAppendChar(pool, *s)) + return 0; + } while (*s++); + s = pool->start; + poolFinish(pool); + return s; +} + +static const XML_Char * +poolCopyStringN(STRING_POOL *pool, + const XML_Char *s, + int n) +{ + if (!pool->ptr && !poolGrow(pool)) + return 0; + for (; n > 0; --n, s++) { + if (!poolAppendChar(pool, *s)) + return 0; + + } + s = pool->start; + poolFinish(pool); + return s; +} + +static +XML_Char *poolStoreString(STRING_POOL *pool, const ENCODING *enc, + const char *ptr, const char *end) +{ + if (!poolAppend(pool, enc, ptr, end)) + return 0; + if (pool->ptr == pool->end && !poolGrow(pool)) + return 0; + *(pool->ptr)++ = 0; + return pool->start; +} + +static +int poolGrow(STRING_POOL *pool) +{ + if (pool->freeBlocks) { + if (pool->start == 0) { + pool->blocks = pool->freeBlocks; + pool->freeBlocks = pool->freeBlocks->next; + pool->blocks->next = 0; + pool->start = pool->blocks->s; + pool->end = pool->start + pool->blocks->size; + pool->ptr = pool->start; + return 1; + } + if (pool->end - pool->start < pool->freeBlocks->size) { + BLOCK *tem = pool->freeBlocks->next; + pool->freeBlocks->next = pool->blocks; + pool->blocks = pool->freeBlocks; + pool->freeBlocks = tem; + memcpy(pool->blocks->s, pool->start, + (pool->end - pool->start) * sizeof(XML_Char)); + pool->ptr = pool->blocks->s + (pool->ptr - pool->start); + pool->start = pool->blocks->s; + pool->end = pool->start + pool->blocks->size; + return 1; + } + } + if (pool->blocks && pool->start == pool->blocks->s) { + int blockSize = (pool->end - pool->start)*2; + pool->blocks = realloc(pool->blocks, offsetof(BLOCK, s) + + blockSize * sizeof(XML_Char)); + if (!pool->blocks) + return 0; + pool->blocks->size = blockSize; + pool->ptr = pool->blocks->s + (pool->ptr - pool->start); + pool->start = pool->blocks->s; + pool->end = pool->start + blockSize; + } + else { + BLOCK *tem; + int blockSize = pool->end - pool->start; + if (blockSize < INIT_BLOCK_SIZE) + blockSize = INIT_BLOCK_SIZE; + else + blockSize *= 2; + tem = malloc(offsetof(BLOCK, s) + blockSize * sizeof(XML_Char)); + if (!tem) + return 0; + tem->size = blockSize; + tem->next = pool->blocks; + pool->blocks = tem; + if (pool->ptr != pool->start) + memcpy(tem->s, pool->start, + (pool->ptr - pool->start) * sizeof(XML_Char)); + pool->ptr = tem->s + (pool->ptr - pool->start); + pool->start = tem->s; + pool->end = tem->s + blockSize; + } + return 1; +} diff --git a/lib/expat/xmlparse/xmlparse.dsp b/lib/expat/xmlparse/xmlparse.dsp new file mode 100644 index 0000000..b95795a --- /dev/null +++ b/lib/expat/xmlparse/xmlparse.dsp @@ -0,0 +1,279 @@ +# Microsoft Developer Studio Project File - Name="xmlparse" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102 +# TARGTYPE "Win32 (x86) Static Library" 0x0104 + +CFG=xmlparse - Win32 Release +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "xmlparse.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "xmlparse.mak" CFG="xmlparse - Win32 Release" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "xmlparse - Win32 Release" (based on "Win32 (x86) Static Library") +!MESSAGE "xmlparse - Win32 Debug" (based on "Win32 (x86) Static Library") +!MESSAGE "xmlparse - Win32 Release DLL" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE "xmlparse - Win32 Debug DLL" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE "xmlparse - Win32 MinSize DLL" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "xmlparse" +# PROP Scc_LocalPath ".." + +!IF "$(CFG)" == "xmlparse - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir ".\Release" +# PROP BASE Intermediate_Dir ".\Release" +# PROP BASE Target_Dir "." +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release\xmlparse" +# PROP Intermediate_Dir "Release\xmlparse" +# PROP Target_Dir "." +LINK32=link.exe -lib +MTL=midl.exe +CPP=cl.exe +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c +# ADD CPP /nologo /MT /W3 /GX /O2 /I "..\xmltok" /I "..\xmlwf" /I "..\..\.." /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "XML_DTD" /D "_MBCS" /D "_LIB" /YX /FD /c +RSC=rc.exe +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo + +!ELSEIF "$(CFG)" == "xmlparse - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir ".\Debug" +# PROP BASE Intermediate_Dir ".\Debug" +# PROP BASE Target_Dir "." +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug\xmlparse" +# PROP Intermediate_Dir "Debug\xmlparse" +# PROP Target_Dir "." +LINK32=link.exe -lib +MTL=midl.exe +CPP=cl.exe +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c +# ADD CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /I "..\xmltok" /I "..\xmlwf" /I "..\..\.." /D "WIN32" /D "_WINDOWS" /D "XML_DTD" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c +RSC=rc.exe +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo + +!ELSEIF "$(CFG)" == "xmlparse - Win32 Release DLL" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir ".\ReleaseDLL" +# PROP BASE Intermediate_Dir ".\ReleaseDLL" +# PROP BASE Target_Dir "." +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "ReleaseDLL\xmlparse" +# PROP Intermediate_Dir "ReleaseDLL\xmlparse" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "." +CPP=cl.exe +# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /c +# ADD CPP /nologo /MT /W3 /GX /O2 /I "..\xmltok" /I "..\xmlwf" /I "..\..\.." /D XMLTOKAPI=__declspec(dllimport) /D XMLPARSEAPI=__declspec(dllexport) /D "NDEBUG" /D "XML_NS" /D "WIN32" /D "_WINDOWS" /D "XML_DTD" /YX /FD /c +MTL=midl.exe +# ADD BASE MTL /nologo /D "NDEBUG" /win32 +# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +RSC=rc.exe +# ADD BASE RSC /l 0x809 /d "NDEBUG" +# ADD RSC /l 0x809 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /dll /machine:I386 +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /base:"0x20000000" /subsystem:windows /dll /machine:I386 /link50compat +# SUBTRACT LINK32 /pdb:none + +!ELSEIF "$(CFG)" == "xmlparse - Win32 Debug DLL" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir ".\DebugDLL" +# PROP BASE Intermediate_Dir ".\DebugDLL" +# PROP BASE Target_Dir "." +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "DebugDLL\xmlparse" +# PROP Intermediate_Dir "DebugDLL\xmlparse" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "." +CPP=cl.exe +# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /YX /c +# ADD CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /I "..\xmltok" /I "..\xmlwf" /I "..\..\.." /D "_DEBUG" /D XMLTOKAPI=__declspec(dllimport) /D XMLPARSEAPI=__declspec(dllexport) /D "WIN32" /D "_WINDOWS" /D "XML_DTD" /YX /FD /c +MTL=midl.exe +# ADD BASE MTL /nologo /D "_DEBUG" /win32 +# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +RSC=rc.exe +# ADD BASE RSC /l 0x809 /d "_DEBUG" +# ADD RSC /l 0x809 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /dll /debug /machine:I386 +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /base:"0x20000000" /subsystem:windows /dll /debug /machine:I386 + +!ELSEIF "$(CFG)" == "xmlparse - Win32 MinSize DLL" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir ".\ReleaseMinSizeDLL" +# PROP BASE Intermediate_Dir ".\ReleaseMinSizeDLL" +# PROP BASE Ignore_Export_Lib 0 +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "ReleaseMinSizeDLL\xmlparse" +# PROP Intermediate_Dir "ReleaseMinSizeDLL\xmlparse" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +CPP=cl.exe +# ADD BASE CPP /nologo /MD /W3 /GX /O2 /I "..\xmltok" /I "..\xmlwf" /D XMLTOKAPI=__declspec(dllimport) /D XMLPARSEAPI=__declspec(dllexport) /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "XML_NS" /YX /FD /c +# ADD CPP /nologo /MD /W3 /GX /O1 /I "..\xmltok" /I "..\xmlwf" /I "..\..\.." /D "XML_MIN_SIZE" /D "XML_WINLIB" /D XMLPARSEAPI=__declspec(dllexport) /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /YX /FD /c +MTL=midl.exe +# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +RSC=rc.exe +# ADD BASE RSC /l 0x809 /d "NDEBUG" +# ADD RSC /l 0x809 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /base:"0x20000000" /subsystem:windows /dll /machine:I386 +# SUBTRACT BASE LINK32 /profile +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /base:"0x20000000" /entry:"DllMain" /subsystem:windows /dll /machine:I386 +# SUBTRACT LINK32 /profile /nodefaultlib + +!ENDIF + +# Begin Target + +# Name "xmlparse - Win32 Release" +# Name "xmlparse - Win32 Debug" +# Name "xmlparse - Win32 Release DLL" +# Name "xmlparse - Win32 Debug DLL" +# Name "xmlparse - Win32 MinSize DLL" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat;for;f90" +# Begin Source File + +SOURCE=..\xmltok\dllmain.c + +!IF "$(CFG)" == "xmlparse - Win32 Release" + +# PROP Exclude_From_Build 1 + +!ELSEIF "$(CFG)" == "xmlparse - Win32 Debug" + +# PROP Exclude_From_Build 1 + +!ELSEIF "$(CFG)" == "xmlparse - Win32 Release DLL" + +!ELSEIF "$(CFG)" == "xmlparse - Win32 Debug DLL" + +!ELSEIF "$(CFG)" == "xmlparse - Win32 MinSize DLL" + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=.\xmlparse.c +# End Source File +# Begin Source File + +SOURCE=..\xmltok\xmlrole.c + +!IF "$(CFG)" == "xmlparse - Win32 Release" + +# PROP Exclude_From_Build 1 + +!ELSEIF "$(CFG)" == "xmlparse - Win32 Debug" + +# PROP Exclude_From_Build 1 + +!ELSEIF "$(CFG)" == "xmlparse - Win32 Release DLL" + +# PROP Exclude_From_Build 1 + +!ELSEIF "$(CFG)" == "xmlparse - Win32 Debug DLL" + +# PROP Exclude_From_Build 1 + +!ELSEIF "$(CFG)" == "xmlparse - Win32 MinSize DLL" + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\xmltok\xmltok.c + +!IF "$(CFG)" == "xmlparse - Win32 Release" + +# PROP Exclude_From_Build 1 + +!ELSEIF "$(CFG)" == "xmlparse - Win32 Debug" + +# PROP Exclude_From_Build 1 + +!ELSEIF "$(CFG)" == "xmlparse - Win32 Release DLL" + +# PROP Exclude_From_Build 1 + +!ELSEIF "$(CFG)" == "xmlparse - Win32 Debug DLL" + +# PROP Exclude_From_Build 1 + +!ELSEIF "$(CFG)" == "xmlparse - Win32 MinSize DLL" + +!ENDIF + +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl;fi;fd" +# Begin Source File + +SOURCE=.\xmlparse.h +# End Source File +# End Group +# Begin Group "Resource Files" + +# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;cnt;rtf;gif;jpg;jpeg;jpe" +# End Group +# End Target +# End Project diff --git a/lib/expat/xmlparse/xmlparse.h b/lib/expat/xmlparse/xmlparse.h new file mode 100644 index 0000000..7db48f4 --- /dev/null +++ b/lib/expat/xmlparse/xmlparse.h @@ -0,0 +1,552 @@ +/* + Copyright (c) 1998, 1999, 2000 Thai Open Source Software Center Ltd + See the file copying.txt for copying permission. +*/ + +#ifndef XMLPARSE_H_INCLUDED +#define XMLPARSE_H_INCLUDED + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef XMLPARSEAPI +#define XMLPARSEAPI /* as nothing */ +#endif + +typedef void *XML_Parser; + +#ifdef XML_UNICODE_WCHAR_T + +/* XML_UNICODE_WCHAR_T will work only if sizeof(wchar_t) == 2 and wchar_t + uses Unicode. +*/ +/* Information is UTF-16 encoded as wchar_ts */ + +#ifndef XML_UNICODE +#define XML_UNICODE +#endif + +#include +typedef wchar_t XML_Char; +typedef wchar_t XML_LChar; + +#else /* not XML_UNICODE_WCHAR_T */ + +#ifdef XML_UNICODE + +/* Information is UTF-16 encoded as unsigned shorts */ +typedef unsigned short XML_Char; +typedef char XML_LChar; + +#else /* not XML_UNICODE */ + +/* Information is UTF-8 encoded. */ +typedef char XML_Char; +typedef char XML_LChar; + +#endif /* not XML_UNICODE */ + +#endif /* not XML_UNICODE_WCHAR_T */ + + +/* Constructs a new parser; encoding is the encoding specified by the external +protocol or null if there is none specified. */ + +XML_Parser XMLPARSEAPI +xmlrpc_XML_ParserCreate(const XML_Char * encoding); + +/* Constructs a new parser and namespace processor. Element type names +and attribute names that belong to a namespace will be expanded; +unprefixed attribute names are never expanded; unprefixed element type +names are expanded only if there is a default namespace. The expanded +name is the concatenation of the namespace URI, the namespace separator character, +and the local part of the name. If the namespace separator is '\0' then +the namespace URI and the local part will be concatenated without any +separator. When a namespace is not declared, the name and prefix will be +passed through without expansion. */ + +XML_Parser XMLPARSEAPI +xmlrpc_XML_ParserCreateNS(const XML_Char *encoding, + XML_Char namespaceSeparator); + + +/* atts is array of name/value pairs, terminated by 0; + names and values are 0 terminated. */ + +typedef void (*XML_StartElementHandler)(void *userData, + const XML_Char *name, + const XML_Char **atts); + +typedef void (*XML_EndElementHandler)(void *userData, + const XML_Char *name); + +/* s is not 0 terminated. */ +typedef void (*XML_CharacterDataHandler)(void *userData, + const XML_Char *s, + int len); + +/* target and data are 0 terminated */ +typedef void (*XML_ProcessingInstructionHandler)(void *userData, + const XML_Char *target, + const XML_Char *data); + +/* data is 0 terminated */ +typedef void (*XML_CommentHandler)(void *userData, const XML_Char *data); + +typedef void (*XML_StartCdataSectionHandler)(void *userData); +typedef void (*XML_EndCdataSectionHandler)(void *userData); + +/* This is called for any characters in the XML document for +which there is no applicable handler. This includes both +characters that are part of markup which is of a kind that is +not reported (comments, markup declarations), or characters +that are part of a construct which could be reported but +for which no handler has been supplied. The characters are passed +exactly as they were in the XML document except that +they will be encoded in UTF-8. Line boundaries are not normalized. +Note that a byte order mark character is not passed to the default handler. +There are no guarantees about how characters are divided between calls +to the default handler: for example, a comment might be split between +multiple calls. */ + +typedef void (*XML_DefaultHandler)(void *userData, + const XML_Char *s, + int len); + +/* This is called for the start of the DOCTYPE declaration when the +name of the DOCTYPE is encountered. */ +typedef void (*XML_StartDoctypeDeclHandler)(void *userData, + const XML_Char *doctypeName); + +/* This is called for the start of the DOCTYPE declaration when the +closing > is encountered, but after processing any external subset. */ +typedef void (*XML_EndDoctypeDeclHandler)(void *userData); + +/* This is called for a declaration of an unparsed (NDATA) +entity. The base argument is whatever was set by XML_SetBase. +The entityName, systemId and notationName arguments will never be null. +The other arguments may be. */ + +typedef void (*XML_UnparsedEntityDeclHandler)(void *userData, + const XML_Char *entityName, + const XML_Char *base, + const XML_Char *systemId, + const XML_Char *publicId, + const XML_Char *notationName); + +/* This is called for a declaration of notation. +The base argument is whatever was set by XML_SetBase. +The notationName will never be null. The other arguments can be. */ + +typedef void (*XML_NotationDeclHandler)(void *userData, + const XML_Char *notationName, + const XML_Char *base, + const XML_Char *systemId, + const XML_Char *publicId); + +typedef void (*XML_ExternalParsedEntityDeclHandler)(void *userData, + const XML_Char *entityName, + const XML_Char *base, + const XML_Char *systemId, + const XML_Char *publicId); + +typedef void (*XML_InternalParsedEntityDeclHandler)(void *userData, + const XML_Char *entityName, + const XML_Char *replacementText, + int replacementTextLength); + +/* When namespace processing is enabled, these are called once for +each namespace declaration. The call to the start and end element +handlers occur between the calls to the start and end namespace +declaration handlers. For an xmlns attribute, prefix will be null. +For an xmlns="" attribute, uri will be null. */ + +typedef void (*XML_StartNamespaceDeclHandler)(void *userData, + const XML_Char *prefix, + const XML_Char *uri); + +typedef void (*XML_EndNamespaceDeclHandler)(void *userData, + const XML_Char *prefix); + +/* This is called if the document is not standalone (it has an +external subset or a reference to a parameter entity, but does not +have standalone="yes"). If this handler returns 0, then processing +will not continue, and the parser will return a +XML_ERROR_NOT_STANDALONE error. */ + +typedef int (*XML_NotStandaloneHandler)(void *userData); + +/* This is called for a reference to an external parsed general entity. +The referenced entity is not automatically parsed. +The application can parse it immediately or later using +XML_ExternalEntityParserCreate. +The parser argument is the parser parsing the entity containing the reference; +it can be passed as the parser argument to XML_ExternalEntityParserCreate. +The systemId argument is the system identifier as specified in the entity declaration; +it will not be null. +The base argument is the system identifier that should be used as the base for +resolving systemId if systemId was relative; this is set by XML_SetBase; +it may be null. +The publicId argument is the public identifier as specified in the entity declaration, +or null if none was specified; the whitespace in the public identifier +will have been normalized as required by the XML spec. +The context argument specifies the parsing context in the format +expected by the context argument to +XML_ExternalEntityParserCreate; context is valid only until the handler +returns, so if the referenced entity is to be parsed later, it must be copied. +The handler should return 0 if processing should not continue because of +a fatal error in the handling of the external entity. +In this case the calling parser will return an XML_ERROR_EXTERNAL_ENTITY_HANDLING +error. +Note that unlike other handlers the first argument is the parser, not userData. */ + +typedef int (*XML_ExternalEntityRefHandler)(XML_Parser parser, + const XML_Char *context, + const XML_Char *base, + const XML_Char *systemId, + const XML_Char *publicId); + +/* This structure is filled in by the XML_UnknownEncodingHandler +to provide information to the parser about encodings that are unknown +to the parser. +The map[b] member gives information about byte sequences +whose first byte is b. +If map[b] is c where c is >= 0, then b by itself encodes the Unicode scalar value c. +If map[b] is -1, then the byte sequence is malformed. +If map[b] is -n, where n >= 2, then b is the first byte of an n-byte +sequence that encodes a single Unicode scalar value. +The data member will be passed as the first argument to the convert function. +The convert function is used to convert multibyte sequences; +s will point to a n-byte sequence where map[(unsigned char)*s] == -n. +The convert function must return the Unicode scalar value +represented by this byte sequence or -1 if the byte sequence is malformed. +The convert function may be null if the encoding is a single-byte encoding, +that is if map[b] >= -1 for all bytes b. +When the parser is finished with the encoding, then if release is not null, +it will call release passing it the data member; +once release has been called, the convert function will not be called again. + +Expat places certain restrictions on the encodings that are supported +using this mechanism. + +1. Every ASCII character that can appear in a well-formed XML document, +other than the characters + + $@\^`{}~ + +must be represented by a single byte, and that byte must be the +same byte that represents that character in ASCII. + +2. No character may require more than 4 bytes to encode. + +3. All characters encoded must have Unicode scalar values <= 0xFFFF, +(ie characters that would be encoded by surrogates in UTF-16 +are not allowed). Note that this restriction doesn't apply to +the built-in support for UTF-8 and UTF-16. + +4. No Unicode character may be encoded by more than one distinct sequence +of bytes. */ + +typedef struct { + int map[256]; + void *data; + int (*convert)(void *data, const char *s); + void (*release)(void *data); +} XML_Encoding; + +/* This is called for an encoding that is unknown to the parser. +The encodingHandlerData argument is that which was passed as the +second argument to XML_SetUnknownEncodingHandler. +The name argument gives the name of the encoding as specified in +the encoding declaration. +If the callback can provide information about the encoding, +it must fill in the XML_Encoding structure, and return 1. +Otherwise it must return 0. +If info does not describe a suitable encoding, +then the parser will return an XML_UNKNOWN_ENCODING error. */ + +typedef int (*XML_UnknownEncodingHandler)(void *encodingHandlerData, + const XML_Char *name, + XML_Encoding *info); + +void XMLPARSEAPI +xmlrpc_XML_SetElementHandler(XML_Parser parser, + XML_StartElementHandler start, + XML_EndElementHandler end); + +void XMLPARSEAPI +xmlrpc_XML_SetCharacterDataHandler(XML_Parser parser, + XML_CharacterDataHandler handler); + +void XMLPARSEAPI +xmlrpc_XML_SetProcessingInstructionHandler( + XML_Parser parser, + XML_ProcessingInstructionHandler handler); +void XMLPARSEAPI +xmlrpc_XML_SetCommentHandler(XML_Parser parser, + XML_CommentHandler handler); + +void XMLPARSEAPI +xmlrpc_XML_SetCdataSectionHandler(XML_Parser parser, + XML_StartCdataSectionHandler start, + XML_EndCdataSectionHandler end); + +/* This sets the default handler and also inhibits expansion of + internal entities. The entity reference will be passed to the default + handler. +*/ + +void XMLPARSEAPI +xmlrpc_XML_SetDefaultHandler(XML_Parser parser, + XML_DefaultHandler handler); + +/* This sets the default handler but does not inhibit expansion of internal entities. +The entity reference will not be passed to the default handler. */ + +void XMLPARSEAPI +xmlrpc_XML_SetDefaultHandlerExpand(XML_Parser parser, + XML_DefaultHandler handler); + +void XMLPARSEAPI +xmlrpc_XML_SetDoctypeDeclHandler(XML_Parser parser, + XML_StartDoctypeDeclHandler start, + XML_EndDoctypeDeclHandler end); + +void XMLPARSEAPI +xmlrpc_XML_SetUnparsedEntityDeclHandler(XML_Parser parser, + XML_UnparsedEntityDeclHandler handler); + +void XMLPARSEAPI +xmlrpc_XML_SetNotationDeclHandler(XML_Parser parser, + XML_NotationDeclHandler handler); + +void XMLPARSEAPI +xmlrpc_XML_SetExternalParsedEntityDeclHandler( + XML_Parser parser, + XML_ExternalParsedEntityDeclHandler handler); + +void XMLPARSEAPI +xmlrpc_XML_SetInternalParsedEntityDeclHandler( + XML_Parser parser, + XML_InternalParsedEntityDeclHandler handler); + +void XMLPARSEAPI +xmlrpc_XML_SetNamespaceDeclHandler(XML_Parser parser, + XML_StartNamespaceDeclHandler start, + XML_EndNamespaceDeclHandler end); + +void XMLPARSEAPI +xmlrpc_XML_SetNotStandaloneHandler(XML_Parser parser, + XML_NotStandaloneHandler handler); + +void XMLPARSEAPI +xmlrpc_XML_SetExternalEntityRefHandler(XML_Parser parser, + XML_ExternalEntityRefHandler handler); + +/* If a non-null value for arg is specified here, then it will be + passed as the first argument to the external entity ref handler + instead of the parser object. +*/ +void XMLPARSEAPI +xmlrpc_XML_SetExternalEntityRefHandlerArg(XML_Parser, void *arg); + +void XMLPARSEAPI +xmlrpc_XML_SetUnknownEncodingHandler(XML_Parser parser, + XML_UnknownEncodingHandler handler, + void *encodingHandlerData); + +/* This can be called within a handler for a start element, end element, + processing instruction or character data. It causes the corresponding + markup to be passed to the default handler. +*/ +void XMLPARSEAPI +xmlrpc_XML_DefaultCurrent(XML_Parser parser); + +/* This value is passed as the userData argument to callbacks. */ +void XMLPARSEAPI +xmlrpc_XML_SetUserData(XML_Parser parser, void *userData); + +/* Returns the last value set by XML_SetUserData or null. */ +#define XML_GetUserData(parser) (*(void **)(parser)) + +/* This is equivalent to supplying an encoding argument +to XML_ParserCreate. It must not be called after XML_Parse +or XML_ParseBuffer. */ + +int XMLPARSEAPI +xmlrpc_XML_SetEncoding(XML_Parser parser, const XML_Char *encoding); + +/* If this function is called, then the parser will be passed + as the first argument to callbacks instead of userData. + The userData will still be accessible using XML_GetUserData. +*/ +void XMLPARSEAPI +xmlrpc_XML_UseParserAsHandlerArg(XML_Parser parser); + +/* Sets the base to be used for resolving relative URIs in system + identifiers in declarations. Resolving relative identifiers is left + to the application: this value will be passed through as the base + argument to the XML_ExternalEntityRefHandler, XML_NotationDeclHandler + and XML_UnparsedEntityDeclHandler. The base argument will be copied. + Returns zero if out of memory, non-zero otherwise. +*/ +int XMLPARSEAPI +xmlrpc_XML_SetBase(XML_Parser parser, const XML_Char *base); + +const XML_Char XMLPARSEAPI * +xmlrpc_XML_GetBase(XML_Parser parser); + +/* Returns the number of the attribute/value pairs passed in last call + to the XML_StartElementHandler that were specified in the start-tag + rather than defaulted. Each attribute/value pair counts as 2; thus + this correspondds to an index into the atts array passed to the + XML_StartElementHandler. +*/ +int XMLPARSEAPI +xmlrpc_XML_GetSpecifiedAttributeCount(XML_Parser parser); + +/* Returns the index of the ID attribute passed in the last call to + XML_StartElementHandler, or -1 if there is no ID attribute. Each + attribute/value pair counts as 2; thus this correspondds to an index + into the atts array passed to the XML_StartElementHandler. +*/ +int XMLPARSEAPI +xmlrpc_XML_GetIdAttributeIndex(XML_Parser parser); + +/* Parses some input. Returns 0 if a fatal error is detected. + The last call to XML_Parse must have isFinal true; + len may be zero for this call (or any other). +*/ +int XMLPARSEAPI +xmlrpc_XML_Parse(XML_Parser parser, const char *s, int len, int isFinal); + +void XMLPARSEAPI * +xmlrpc_XML_GetBuffer(XML_Parser parser, int len); + +int XMLPARSEAPI +xmlrpc_XML_ParseBuffer(XML_Parser parser, int len, int isFinal); + +/* Creates an XML_Parser object that can parse an external general + entity; context is a '\0'-terminated string specifying the parse + context; encoding is a '\0'-terminated string giving the name of the + externally specified encoding, or null if there is no externally + specified encoding. The context string consists of a sequence of + tokens separated by formfeeds (\f); a token consisting of a name + specifies that the general entity of the name is open; a token of the + form prefix=uri specifies the namespace for a particular prefix; a + token of the form =uri specifies the default namespace. This can be + called at any point after the first call to an + ExternalEntityRefHandler so longer as the parser has not yet been + freed. The new parser is completely independent and may safely be + used in a separate thread. The handlers and userData are initialized + from the parser argument. Returns 0 if out of memory. Otherwise + returns a new XML_Parser object. +*/ +XML_Parser XMLPARSEAPI +xmlrpc_XML_ExternalEntityParserCreate(XML_Parser parser, + const XML_Char *context, + const XML_Char *encoding); + +enum XML_ParamEntityParsing { + XML_PARAM_ENTITY_PARSING_NEVER, + XML_PARAM_ENTITY_PARSING_UNLESS_STANDALONE, + XML_PARAM_ENTITY_PARSING_ALWAYS +}; + +/* Controls parsing of parameter entities (including the external DTD + subset). If parsing of parameter entities is enabled, then references + to external parameter entities (including the external DTD subset) + will be passed to the handler set with + XML_SetExternalEntityRefHandler. The context passed will be 0. + Unlike external general entities, external parameter entities can only + be parsed synchronously. If the external parameter entity is to be + parsed, it must be parsed during the call to the external entity ref + handler: the complete sequence of XML_ExternalEntityParserCreate, + XML_Parse/XML_ParseBuffer and XML_ParserFree calls must be made during + this call. After XML_ExternalEntityParserCreate has been called to + create the parser for the external parameter entity (context must be 0 + for this call), it is illegal to make any calls on the old parser + until XML_ParserFree has been called on the newly created parser. If + the library has been compiled without support for parameter entity + parsing (ie without XML_DTD being defined), then + XML_SetParamEntityParsing will return 0 if parsing of parameter + entities is requested; otherwise it will return non-zero. +*/ +int XMLPARSEAPI +xmlrpc_XML_SetParamEntityParsing(XML_Parser parser, + enum XML_ParamEntityParsing parsing); + +enum XML_Error { + XML_ERROR_NONE, + XML_ERROR_NO_MEMORY, + XML_ERROR_SYNTAX, + XML_ERROR_NO_ELEMENTS, + XML_ERROR_INVALID_TOKEN, + XML_ERROR_UNCLOSED_TOKEN, + XML_ERROR_PARTIAL_CHAR, + XML_ERROR_TAG_MISMATCH, + XML_ERROR_DUPLICATE_ATTRIBUTE, + XML_ERROR_JUNK_AFTER_DOC_ELEMENT, + XML_ERROR_PARAM_ENTITY_REF, + XML_ERROR_UNDEFINED_ENTITY, + XML_ERROR_RECURSIVE_ENTITY_REF, + XML_ERROR_ASYNC_ENTITY, + XML_ERROR_BAD_CHAR_REF, + XML_ERROR_BINARY_ENTITY_REF, + XML_ERROR_ATTRIBUTE_EXTERNAL_ENTITY_REF, + XML_ERROR_MISPLACED_XML_PI, + XML_ERROR_UNKNOWN_ENCODING, + XML_ERROR_INCORRECT_ENCODING, + XML_ERROR_UNCLOSED_CDATA_SECTION, + XML_ERROR_EXTERNAL_ENTITY_HANDLING, + XML_ERROR_NOT_STANDALONE +}; + +/* If xmlrpc_XML_Parse or xmlrpc_XML_ParseBuffer have returned 0, then + xmlrpc_XML_GetErrorCode returns information about the error. +*/ + +enum XML_Error XMLPARSEAPI +xmlrpc_XML_GetErrorCode(XML_Parser parser); + +/* These functions return information about the current parse location. + They may be called when XML_Parse or XML_ParseBuffer return 0; + in this case the location is the location of the character at which + the error was detected. + They may also be called from any other callback called to report + some parse event; in this the location is the location of the first + of the sequence of characters that generated the event. +*/ + +int XMLPARSEAPI +xmlrpc_XML_GetCurrentLineNumber(XML_Parser parser); +int XMLPARSEAPI +xmlrpc_XML_GetCurrentColumnNumber(XML_Parser parser); +long XMLPARSEAPI +xmlrpc_XML_GetCurrentByteIndex(XML_Parser parser); + +/* Return the number of bytes in the current event. +Returns 0 if the event is in an internal entity. */ + +int XMLPARSEAPI +xmlrpc_XML_GetCurrentByteCount(XML_Parser parser); + +/* For backwards compatibility with previous versions. */ +#define XML_GetErrorLineNumber XML_GetCurrentLineNumber +#define XML_GetErrorColumnNumber XML_GetCurrentColumnNumber +#define XML_GetErrorByteIndex XML_GetCurrentByteIndex + +/* Frees memory used by the parser. */ +void XMLPARSEAPI +xmlrpc_XML_ParserFree(XML_Parser parser); + +/* Returns a string describing the error. */ +const XML_LChar XMLPARSEAPI * +xmlrpc_XML_ErrorString(int code); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/lib/expat/xmltok/.cvsignore b/lib/expat/xmltok/.cvsignore new file mode 100644 index 0000000..38cd01c --- /dev/null +++ b/lib/expat/xmltok/.cvsignore @@ -0,0 +1 @@ +nametab.h diff --git a/lib/expat/xmltok/Makefile b/lib/expat/xmltok/Makefile new file mode 100644 index 0000000..2af8543 --- /dev/null +++ b/lib/expat/xmltok/Makefile @@ -0,0 +1,66 @@ +ifeq ($(SRCDIR)x,x) +SRCDIR = $(CURDIR)/../../.. +endif + +include $(SRCDIR)/Makefile.config + +# I can't figure out what XML_BYTE_ORDER is, but it doesn't look like the +# code has ever defined it. That means it's treated like 0 in #if. Since +# we started using the Gcc -Wundef option, that generates a warning, so +# se set it explicitly to 0 here. + +CFLAGS = $(CFLAGS_COMMON) -DXML_BYTE_ORDER=0 $(CFLAGS_PERSONAL) $(CADD) + +LIBLDFLAGS = $(LDFLAGS_VERSINFO) -rpath $(LIBINST_DIR) $(LADD) + +INCLUDES = -I$(SRCDIR) -I$(SRCDIR)/lib/util/include + +default: all + +include $(SRCDIR)/Makefile.common + +.PHONY: all +all: libxmlrpc_xmltok.la + +.PHONY: clean +clean: clean-common + rm -f nametab.h + +.PHONY: distclean +distclean: clean distclean-common + +.PHONY: tags +tags: TAGS + +.PHONY: distdir +distdir: + +.PHONY: install +install: install-common + +.PHONY: dep +dep: dep-common + +LTLIBRARIES_TO_INSTALL = libxmlrpc_xmltok.la + +LIBXMLRPC_XMLTOK_OBJS = xmltok.lo xmlrole.lo + +libxmlrpc_xmltok.la: $(LIBXMLRPC_XMLTOK_OBJS) + $(LIBTOOL) --mode=link $(CCLD) -o $@ $(LIBLDFLAGS) $^ + +$(LIBXMLRPC_XMLTOK_OBJS):%.lo:%.c + $(LIBTOOL) --mode=compile $(CC) -c $(INCLUDES) $(LIBXML_INCLUDES) \ + $(CFLAGS) $< + +GENNMTAB = ../gennmtab/gennmtab + +nametab.h: $(GENNMTAB) + rm -f $@ + $(GENNMTAB) >$@ || (rm -f $@ || false) + +$(GENNMTAB): + $(MAKE) -C $(dir $@) $(notdir $@) + +xmltok.lo: nametab.h + +include Makefile.depend diff --git a/lib/expat/xmltok/Makefile.depend b/lib/expat/xmltok/Makefile.depend new file mode 100644 index 0000000..e69de29 diff --git a/lib/expat/xmltok/ascii.h b/lib/expat/xmltok/ascii.h new file mode 100644 index 0000000..a8a621c --- /dev/null +++ b/lib/expat/xmltok/ascii.h @@ -0,0 +1,86 @@ +/* +Copyright (c) 1998, 1999 Thai Open Source Software Center Ltd +See the file copying.txt for copying permission. +*/ + +#define ASCII_A 0x41 +#define ASCII_B 0x42 +#define ASCII_C 0x43 +#define ASCII_D 0x44 +#define ASCII_E 0x45 +#define ASCII_F 0x46 +#define ASCII_G 0x47 +#define ASCII_H 0x48 +#define ASCII_I 0x49 +#define ASCII_J 0x4A +#define ASCII_K 0x4B +#define ASCII_L 0x4C +#define ASCII_M 0x4D +#define ASCII_N 0x4E +#define ASCII_O 0x4F +#define ASCII_P 0x50 +#define ASCII_Q 0x51 +#define ASCII_R 0x52 +#define ASCII_S 0x53 +#define ASCII_T 0x54 +#define ASCII_U 0x55 +#define ASCII_V 0x56 +#define ASCII_W 0x57 +#define ASCII_X 0x58 +#define ASCII_Y 0x59 +#define ASCII_Z 0x5A + +#define ASCII_a 0x61 +#define ASCII_b 0x62 +#define ASCII_c 0x63 +#define ASCII_d 0x64 +#define ASCII_e 0x65 +#define ASCII_f 0x66 +#define ASCII_g 0x67 +#define ASCII_h 0x68 +#define ASCII_i 0x69 +#define ASCII_j 0x6A +#define ASCII_k 0x6B +#define ASCII_l 0x6C +#define ASCII_m 0x6D +#define ASCII_n 0x6E +#define ASCII_o 0x6F +#define ASCII_p 0x70 +#define ASCII_q 0x71 +#define ASCII_r 0x72 +#define ASCII_s 0x73 +#define ASCII_t 0x74 +#define ASCII_u 0x75 +#define ASCII_v 0x76 +#define ASCII_w 0x77 +#define ASCII_x 0x78 +#define ASCII_y 0x79 +#define ASCII_z 0x7A + +#define ASCII_0 0x30 +#define ASCII_1 0x31 +#define ASCII_2 0x32 +#define ASCII_3 0x33 +#define ASCII_4 0x34 +#define ASCII_5 0x35 +#define ASCII_6 0x36 +#define ASCII_7 0x37 +#define ASCII_8 0x38 +#define ASCII_9 0x39 + +#define ASCII_TAB 0x09 +#define ASCII_SPACE 0x20 +#define ASCII_EXCL 0x21 +#define ASCII_QUOT 0x22 +#define ASCII_AMP 0x26 +#define ASCII_APOS 0x27 +#define ASCII_MINUS 0x2D +#define ASCII_PERIOD 0x2E +#define ASCII_COLON 0x3A +#define ASCII_SEMI 0x3B +#define ASCII_LT 0x3C +#define ASCII_EQUALS 0x3D +#define ASCII_GT 0x3E +#define ASCII_LSQB 0x5B +#define ASCII_RSQB 0x5D +#define ASCII_UNDERSCORE 0x5F diff --git a/lib/expat/xmltok/asciitab.h b/lib/expat/xmltok/asciitab.h new file mode 100644 index 0000000..e994576 --- /dev/null +++ b/lib/expat/xmltok/asciitab.h @@ -0,0 +1,37 @@ +/* +Copyright (c) 1998, 1999 Thai Open Source Software Center Ltd +See the file copying.txt for copying permission. +*/ + +/* 0x00 */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML, +/* 0x04 */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML, +/* 0x08 */ BT_NONXML, BT_S, BT_LF, BT_NONXML, +/* 0x0C */ BT_NONXML, BT_CR, BT_NONXML, BT_NONXML, +/* 0x10 */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML, +/* 0x14 */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML, +/* 0x18 */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML, +/* 0x1C */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML, +/* 0x20 */ BT_S, BT_EXCL, BT_QUOT, BT_NUM, +/* 0x24 */ BT_OTHER, BT_PERCNT, BT_AMP, BT_APOS, +/* 0x28 */ BT_LPAR, BT_RPAR, BT_AST, BT_PLUS, +/* 0x2C */ BT_COMMA, BT_MINUS, BT_NAME, BT_SOL, +/* 0x30 */ BT_DIGIT, BT_DIGIT, BT_DIGIT, BT_DIGIT, +/* 0x34 */ BT_DIGIT, BT_DIGIT, BT_DIGIT, BT_DIGIT, +/* 0x38 */ BT_DIGIT, BT_DIGIT, BT_COLON, BT_SEMI, +/* 0x3C */ BT_LT, BT_EQUALS, BT_GT, BT_QUEST, +/* 0x40 */ BT_OTHER, BT_HEX, BT_HEX, BT_HEX, +/* 0x44 */ BT_HEX, BT_HEX, BT_HEX, BT_NMSTRT, +/* 0x48 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, +/* 0x4C */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, +/* 0x50 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, +/* 0x54 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, +/* 0x58 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_LSQB, +/* 0x5C */ BT_OTHER, BT_RSQB, BT_OTHER, BT_NMSTRT, +/* 0x60 */ BT_OTHER, BT_HEX, BT_HEX, BT_HEX, +/* 0x64 */ BT_HEX, BT_HEX, BT_HEX, BT_NMSTRT, +/* 0x68 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, +/* 0x6C */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, +/* 0x70 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, +/* 0x74 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, +/* 0x78 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_OTHER, +/* 0x7C */ BT_VERBAR, BT_OTHER, BT_OTHER, BT_OTHER, diff --git a/lib/expat/xmltok/dllmain.c b/lib/expat/xmltok/dllmain.c new file mode 100644 index 0000000..d5aa4a3 --- /dev/null +++ b/lib/expat/xmltok/dllmain.c @@ -0,0 +1,15 @@ +/* +Copyright (c) 1998, 1999 Thai Open Source Software Center Ltd +See the file copying.txt for copying permission. +*/ + +#define STRICT 1 +#define WIN32_LEAN_AND_MEAN 1 + +#include + +BOOL WINAPI DllMain(HANDLE hInst, ULONG ul_reason_for_call, LPVOID lpReserved) +{ + return TRUE; +} + diff --git a/lib/expat/xmltok/iasciitab.h b/lib/expat/xmltok/iasciitab.h new file mode 100644 index 0000000..2694d9d --- /dev/null +++ b/lib/expat/xmltok/iasciitab.h @@ -0,0 +1,38 @@ +/* +Copyright (c) 1998, 1999 Thai Open Source Software Center Ltd +See the file copying.txt for copying permission. +*/ + +/* Like asciitab.h, except that 0xD has code BT_S rather than BT_CR */ +/* 0x00 */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML, +/* 0x04 */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML, +/* 0x08 */ BT_NONXML, BT_S, BT_LF, BT_NONXML, +/* 0x0C */ BT_NONXML, BT_S, BT_NONXML, BT_NONXML, +/* 0x10 */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML, +/* 0x14 */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML, +/* 0x18 */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML, +/* 0x1C */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML, +/* 0x20 */ BT_S, BT_EXCL, BT_QUOT, BT_NUM, +/* 0x24 */ BT_OTHER, BT_PERCNT, BT_AMP, BT_APOS, +/* 0x28 */ BT_LPAR, BT_RPAR, BT_AST, BT_PLUS, +/* 0x2C */ BT_COMMA, BT_MINUS, BT_NAME, BT_SOL, +/* 0x30 */ BT_DIGIT, BT_DIGIT, BT_DIGIT, BT_DIGIT, +/* 0x34 */ BT_DIGIT, BT_DIGIT, BT_DIGIT, BT_DIGIT, +/* 0x38 */ BT_DIGIT, BT_DIGIT, BT_COLON, BT_SEMI, +/* 0x3C */ BT_LT, BT_EQUALS, BT_GT, BT_QUEST, +/* 0x40 */ BT_OTHER, BT_HEX, BT_HEX, BT_HEX, +/* 0x44 */ BT_HEX, BT_HEX, BT_HEX, BT_NMSTRT, +/* 0x48 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, +/* 0x4C */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, +/* 0x50 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, +/* 0x54 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, +/* 0x58 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_LSQB, +/* 0x5C */ BT_OTHER, BT_RSQB, BT_OTHER, BT_NMSTRT, +/* 0x60 */ BT_OTHER, BT_HEX, BT_HEX, BT_HEX, +/* 0x64 */ BT_HEX, BT_HEX, BT_HEX, BT_NMSTRT, +/* 0x68 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, +/* 0x6C */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, +/* 0x70 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, +/* 0x74 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, +/* 0x78 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_OTHER, +/* 0x7C */ BT_VERBAR, BT_OTHER, BT_OTHER, BT_OTHER, diff --git a/lib/expat/xmltok/latin1tab.h b/lib/expat/xmltok/latin1tab.h new file mode 100644 index 0000000..6e01d50 --- /dev/null +++ b/lib/expat/xmltok/latin1tab.h @@ -0,0 +1,37 @@ +/* +Copyright (c) 1998, 1999 Thai Open Source Software Center Ltd +See the file copying.txt for copying permission. +*/ + +/* 0x80 */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER, +/* 0x84 */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER, +/* 0x88 */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER, +/* 0x8C */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER, +/* 0x90 */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER, +/* 0x94 */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER, +/* 0x98 */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER, +/* 0x9C */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER, +/* 0xA0 */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER, +/* 0xA4 */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER, +/* 0xA8 */ BT_OTHER, BT_OTHER, BT_NMSTRT, BT_OTHER, +/* 0xAC */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER, +/* 0xB0 */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER, +/* 0xB4 */ BT_OTHER, BT_NMSTRT, BT_OTHER, BT_NAME, +/* 0xB8 */ BT_OTHER, BT_OTHER, BT_NMSTRT, BT_OTHER, +/* 0xBC */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER, +/* 0xC0 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, +/* 0xC4 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, +/* 0xC8 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, +/* 0xCC */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, +/* 0xD0 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, +/* 0xD4 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_OTHER, +/* 0xD8 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, +/* 0xDC */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, +/* 0xE0 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, +/* 0xE4 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, +/* 0xE8 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, +/* 0xEC */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, +/* 0xF0 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, +/* 0xF4 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_OTHER, +/* 0xF8 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, +/* 0xFC */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, diff --git a/lib/expat/xmltok/utf8tab.h b/lib/expat/xmltok/utf8tab.h new file mode 100644 index 0000000..28d9b59 --- /dev/null +++ b/lib/expat/xmltok/utf8tab.h @@ -0,0 +1,38 @@ +/* +Copyright (c) 1998, 1999 Thai Open Source Software Center Ltd +See the file copying.txt for copying permission. +*/ + + +/* 0x80 */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL, +/* 0x84 */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL, +/* 0x88 */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL, +/* 0x8C */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL, +/* 0x90 */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL, +/* 0x94 */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL, +/* 0x98 */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL, +/* 0x9C */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL, +/* 0xA0 */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL, +/* 0xA4 */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL, +/* 0xA8 */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL, +/* 0xAC */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL, +/* 0xB0 */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL, +/* 0xB4 */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL, +/* 0xB8 */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL, +/* 0xBC */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL, +/* 0xC0 */ BT_LEAD2, BT_LEAD2, BT_LEAD2, BT_LEAD2, +/* 0xC4 */ BT_LEAD2, BT_LEAD2, BT_LEAD2, BT_LEAD2, +/* 0xC8 */ BT_LEAD2, BT_LEAD2, BT_LEAD2, BT_LEAD2, +/* 0xCC */ BT_LEAD2, BT_LEAD2, BT_LEAD2, BT_LEAD2, +/* 0xD0 */ BT_LEAD2, BT_LEAD2, BT_LEAD2, BT_LEAD2, +/* 0xD4 */ BT_LEAD2, BT_LEAD2, BT_LEAD2, BT_LEAD2, +/* 0xD8 */ BT_LEAD2, BT_LEAD2, BT_LEAD2, BT_LEAD2, +/* 0xDC */ BT_LEAD2, BT_LEAD2, BT_LEAD2, BT_LEAD2, +/* 0xE0 */ BT_LEAD3, BT_LEAD3, BT_LEAD3, BT_LEAD3, +/* 0xE4 */ BT_LEAD3, BT_LEAD3, BT_LEAD3, BT_LEAD3, +/* 0xE8 */ BT_LEAD3, BT_LEAD3, BT_LEAD3, BT_LEAD3, +/* 0xEC */ BT_LEAD3, BT_LEAD3, BT_LEAD3, BT_LEAD3, +/* 0xF0 */ BT_LEAD4, BT_LEAD4, BT_LEAD4, BT_LEAD4, +/* 0xF4 */ BT_LEAD4, BT_NONXML, BT_NONXML, BT_NONXML, +/* 0xF8 */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML, +/* 0xFC */ BT_NONXML, BT_NONXML, BT_MALFORM, BT_MALFORM, diff --git a/lib/expat/xmltok/xmldef.h b/lib/expat/xmltok/xmldef.h new file mode 100644 index 0000000..57b8333 --- /dev/null +++ b/lib/expat/xmltok/xmldef.h @@ -0,0 +1,52 @@ +/* +Copyright (c) 1998, 1999 Thai Open Source Software Center Ltd +See the file copying.txt for copying permission. +*/ + +#include + +#ifdef XML_WINLIB + +#define WIN32_LEAN_AND_MEAN +#define STRICT +#include + +#define malloc(x) HeapAlloc(GetProcessHeap(), 0, (x)) +#define calloc(x, y) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, (x)*(y)) +#define free(x) HeapFree(GetProcessHeap(), 0, (x)) +#define realloc(x, y) HeapReAlloc(GetProcessHeap(), 0, x, y) +#define abort() /* as nothing */ + +#else /* not XML_WINLIB */ + +#include + +#endif /* not XML_WINLIB */ + +/* This file can be used for any definitions needed in +particular environments. */ + +/* Mozilla specific defines */ + +#ifdef MOZILLA_CLIENT + +#include "nspr.h" +#define malloc(x) PR_Malloc((size_t)(x)) +#define realloc(x, y) PR_Realloc((x), (size_t)(y)) +#define calloc(x, y) PR_Calloc((x),(y)) +#define free(x) PR_Free(x) +#if PR_BYTES_PER_INT != 4 +#define int int32 +#endif + +/* Enable Unicode string processing in expat. */ +#ifndef XML_UNICODE +#define XML_UNICODE +#endif + +/* Enable external parameter entity parsing in expat */ +#ifndef XML_DTD +#define XML_DTD 1 +#endif + +#endif /* MOZILLA_CLIENT */ diff --git a/lib/expat/xmltok/xmlrole.c b/lib/expat/xmltok/xmlrole.c new file mode 100644 index 0000000..04144d7 --- /dev/null +++ b/lib/expat/xmltok/xmlrole.c @@ -0,0 +1,1266 @@ +/* +Copyright (c) 1998, 1999 Thai Open Source Software Center Ltd +See the file copying.txt for copying permission. +*/ +#include "xmlrpc_config.h" + +#include "xmldef.h" +#include "xmlrole.h" +#include "ascii.h" + +/* Doesn't check: + + that ,| are not mixed in a model group + content of literals + +*/ + +static const char KW_ANY[] = { ASCII_A, ASCII_N, ASCII_Y, '\0' }; +static const char KW_ATTLIST[] = { ASCII_A, ASCII_T, ASCII_T, ASCII_L, ASCII_I, ASCII_S, ASCII_T, '\0' }; +static const char KW_CDATA[] = { ASCII_C, ASCII_D, ASCII_A, ASCII_T, ASCII_A, '\0' }; +static const char KW_DOCTYPE[] = { ASCII_D, ASCII_O, ASCII_C, ASCII_T, ASCII_Y, ASCII_P, ASCII_E, '\0' }; +static const char KW_ELEMENT[] = { ASCII_E, ASCII_L, ASCII_E, ASCII_M, ASCII_E, ASCII_N, ASCII_T, '\0' }; +static const char KW_EMPTY[] = { ASCII_E, ASCII_M, ASCII_P, ASCII_T, ASCII_Y, '\0' }; +static const char KW_ENTITIES[] = { ASCII_E, ASCII_N, ASCII_T, ASCII_I, ASCII_T, ASCII_I, ASCII_E, ASCII_S, '\0' }; +static const char KW_ENTITY[] = { ASCII_E, ASCII_N, ASCII_T, ASCII_I, ASCII_T, ASCII_Y, '\0' }; +static const char KW_FIXED[] = { ASCII_F, ASCII_I, ASCII_X, ASCII_E, ASCII_D, '\0' }; +static const char KW_ID[] = { ASCII_I, ASCII_D, '\0' }; +static const char KW_IDREF[] = { ASCII_I, ASCII_D, ASCII_R, ASCII_E, ASCII_F, '\0' }; +static const char KW_IDREFS[] = { ASCII_I, ASCII_D, ASCII_R, ASCII_E, ASCII_F, ASCII_S, '\0' }; +static const char KW_IGNORE[] = { ASCII_I, ASCII_G, ASCII_N, ASCII_O, ASCII_R, ASCII_E, '\0' }; +static const char KW_IMPLIED[] = { ASCII_I, ASCII_M, ASCII_P, ASCII_L, ASCII_I, ASCII_E, ASCII_D, '\0' }; +static const char KW_INCLUDE[] = { ASCII_I, ASCII_N, ASCII_C, ASCII_L, ASCII_U, ASCII_D, ASCII_E, '\0' }; +static const char KW_NDATA[] = { ASCII_N, ASCII_D, ASCII_A, ASCII_T, ASCII_A, '\0' }; +static const char KW_NMTOKEN[] = { ASCII_N, ASCII_M, ASCII_T, ASCII_O, ASCII_K, ASCII_E, ASCII_N, '\0' }; +static const char KW_NMTOKENS[] = { ASCII_N, ASCII_M, ASCII_T, ASCII_O, ASCII_K, ASCII_E, ASCII_N, ASCII_S, '\0' }; +static const char KW_NOTATION[] = { ASCII_N, ASCII_O, ASCII_T, ASCII_A, ASCII_T, ASCII_I, ASCII_O, ASCII_N, '\0' }; +static const char KW_PCDATA[] = { ASCII_P, ASCII_C, ASCII_D, ASCII_A, ASCII_T, ASCII_A, '\0' }; +static const char KW_PUBLIC[] = { ASCII_P, ASCII_U, ASCII_B, ASCII_L, ASCII_I, ASCII_C, '\0' }; +static const char KW_REQUIRED[] = { ASCII_R, ASCII_E, ASCII_Q, ASCII_U, ASCII_I, ASCII_R, ASCII_E, ASCII_D, '\0' }; +static const char KW_SYSTEM[] = { ASCII_S, ASCII_Y, ASCII_S, ASCII_T, ASCII_E, ASCII_M, '\0' }; + +#ifndef MIN_BYTES_PER_CHAR +#define MIN_BYTES_PER_CHAR(enc) ((enc)->minBytesPerChar) +#endif + +#ifdef XML_DTD +#define setTopLevel(state) \ + ((state)->handler = ((state)->documentEntity \ + ? internalSubset \ + : externalSubset1)) +#else /* not XML_DTD */ +#define setTopLevel(state) ((state)->handler = internalSubset) +#endif /* not XML_DTD */ + +typedef int PROLOG_HANDLER(PROLOG_STATE *state, + int tok, + const char *ptr, + const char *end, + const ENCODING *enc); + +static PROLOG_HANDLER + prolog0, prolog1, prolog2, + doctype0, doctype1, doctype2, doctype3, doctype4, doctype5, + internalSubset, + entity0, entity1, entity2, entity3, entity4, entity5, entity6, + entity7, entity8, entity9, + notation0, notation1, notation2, notation3, notation4, + attlist0, attlist1, attlist2, attlist3, attlist4, attlist5, attlist6, + attlist7, attlist8, attlist9, + element0, element1, element2, element3, element4, element5, element6, + element7, +#ifdef XML_DTD + externalSubset0, externalSubset1, + condSect0, condSect1, condSect2, +#endif /* XML_DTD */ + declClose, + error; + +static +int common(PROLOG_STATE *state, int tok); + +static +int prolog0(PROLOG_STATE *state, + int tok, + const char *ptr, + const char *end, + const ENCODING *enc) +{ + switch (tok) { + case XML_TOK_PROLOG_S: + state->handler = prolog1; + return XML_ROLE_NONE; + case XML_TOK_XML_DECL: + state->handler = prolog1; + return XML_ROLE_XML_DECL; + case XML_TOK_PI: + state->handler = prolog1; + return XML_ROLE_NONE; + case XML_TOK_COMMENT: + state->handler = prolog1; + case XML_TOK_BOM: + return XML_ROLE_NONE; + case XML_TOK_DECL_OPEN: + if (!XmlNameMatchesAscii(enc, + ptr + 2 * MIN_BYTES_PER_CHAR(enc), + end, + KW_DOCTYPE)) + break; + state->handler = doctype0; + return XML_ROLE_NONE; + case XML_TOK_INSTANCE_START: + state->handler = error; + return XML_ROLE_INSTANCE_START; + } + return common(state, tok); +} + +static +int prolog1(PROLOG_STATE *state, + int tok, + const char *ptr, + const char *end, + const ENCODING *enc) +{ + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_NONE; + case XML_TOK_PI: + case XML_TOK_COMMENT: + case XML_TOK_BOM: + return XML_ROLE_NONE; + case XML_TOK_DECL_OPEN: + if (!XmlNameMatchesAscii(enc, + ptr + 2 * MIN_BYTES_PER_CHAR(enc), + end, + KW_DOCTYPE)) + break; + state->handler = doctype0; + return XML_ROLE_NONE; + case XML_TOK_INSTANCE_START: + state->handler = error; + return XML_ROLE_INSTANCE_START; + } + return common(state, tok); +} + +static +int prolog2(PROLOG_STATE *state, + int tok, + const char *ptr ATTR_UNUSED, + const char *end ATTR_UNUSED, + const ENCODING *enc ATTR_UNUSED) +{ + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_NONE; + case XML_TOK_PI: + case XML_TOK_COMMENT: + return XML_ROLE_NONE; + case XML_TOK_INSTANCE_START: + state->handler = error; + return XML_ROLE_INSTANCE_START; + } + return common(state, tok); +} + +static +int doctype0(PROLOG_STATE *state, + int tok, + const char *ptr ATTR_UNUSED, + const char *end ATTR_UNUSED, + const ENCODING *enc ATTR_UNUSED) +{ + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_NONE; + case XML_TOK_NAME: + case XML_TOK_PREFIXED_NAME: + state->handler = doctype1; + return XML_ROLE_DOCTYPE_NAME; + } + return common(state, tok); +} + +static +int doctype1(PROLOG_STATE *state, + int tok, + const char *ptr, + const char *end, + const ENCODING *enc) +{ + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_NONE; + case XML_TOK_OPEN_BRACKET: + state->handler = internalSubset; + return XML_ROLE_NONE; + case XML_TOK_DECL_CLOSE: + state->handler = prolog2; + return XML_ROLE_DOCTYPE_CLOSE; + case XML_TOK_NAME: + if (XmlNameMatchesAscii(enc, ptr, end, KW_SYSTEM)) { + state->handler = doctype3; + return XML_ROLE_NONE; + } + if (XmlNameMatchesAscii(enc, ptr, end, KW_PUBLIC)) { + state->handler = doctype2; + return XML_ROLE_NONE; + } + break; + } + return common(state, tok); +} + +static +int doctype2(PROLOG_STATE *state, + int tok, + const char *ptr ATTR_UNUSED, + const char *end ATTR_UNUSED, + const ENCODING *enc ATTR_UNUSED) +{ + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_NONE; + case XML_TOK_LITERAL: + state->handler = doctype3; + return XML_ROLE_DOCTYPE_PUBLIC_ID; + } + return common(state, tok); +} + +static +int doctype3(PROLOG_STATE *state, + int tok, + const char *ptr ATTR_UNUSED, + const char *end ATTR_UNUSED, + const ENCODING *enc ATTR_UNUSED) +{ + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_NONE; + case XML_TOK_LITERAL: + state->handler = doctype4; + return XML_ROLE_DOCTYPE_SYSTEM_ID; + } + return common(state, tok); +} + +static +int doctype4(PROLOG_STATE *state, + int tok, + const char *ptr ATTR_UNUSED, + const char *end ATTR_UNUSED, + const ENCODING *enc ATTR_UNUSED) +{ + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_NONE; + case XML_TOK_OPEN_BRACKET: + state->handler = internalSubset; + return XML_ROLE_NONE; + case XML_TOK_DECL_CLOSE: + state->handler = prolog2; + return XML_ROLE_DOCTYPE_CLOSE; + } + return common(state, tok); +} + +static +int doctype5(PROLOG_STATE *state, + int tok, + const char *ptr ATTR_UNUSED, + const char *end ATTR_UNUSED, + const ENCODING *enc ATTR_UNUSED) +{ + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_NONE; + case XML_TOK_DECL_CLOSE: + state->handler = prolog2; + return XML_ROLE_DOCTYPE_CLOSE; + } + return common(state, tok); +} + +static +int internalSubset(PROLOG_STATE *state, + int tok, + const char *ptr, + const char *end, + const ENCODING *enc) +{ + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_NONE; + case XML_TOK_DECL_OPEN: + if (XmlNameMatchesAscii(enc, + ptr + 2 * MIN_BYTES_PER_CHAR(enc), + end, + KW_ENTITY)) { + state->handler = entity0; + return XML_ROLE_NONE; + } + if (XmlNameMatchesAscii(enc, + ptr + 2 * MIN_BYTES_PER_CHAR(enc), + end, + KW_ATTLIST)) { + state->handler = attlist0; + return XML_ROLE_NONE; + } + if (XmlNameMatchesAscii(enc, + ptr + 2 * MIN_BYTES_PER_CHAR(enc), + end, + KW_ELEMENT)) { + state->handler = element0; + return XML_ROLE_NONE; + } + if (XmlNameMatchesAscii(enc, + ptr + 2 * MIN_BYTES_PER_CHAR(enc), + end, + KW_NOTATION)) { + state->handler = notation0; + return XML_ROLE_NONE; + } + break; + case XML_TOK_PI: + case XML_TOK_COMMENT: + return XML_ROLE_NONE; + case XML_TOK_PARAM_ENTITY_REF: + return XML_ROLE_PARAM_ENTITY_REF; + case XML_TOK_CLOSE_BRACKET: + state->handler = doctype5; + return XML_ROLE_NONE; + } + return common(state, tok); +} + +#ifdef XML_DTD + +static +int externalSubset0(PROLOG_STATE *state, + int tok, + const char *ptr, + const char *end, + const ENCODING *enc) +{ + state->handler = externalSubset1; + if (tok == XML_TOK_XML_DECL) + return XML_ROLE_TEXT_DECL; + return externalSubset1(state, tok, ptr, end, enc); +} + +static +int externalSubset1(PROLOG_STATE *state, + int tok, + const char *ptr, + const char *end, + const ENCODING *enc) +{ + switch (tok) { + case XML_TOK_COND_SECT_OPEN: + state->handler = condSect0; + return XML_ROLE_NONE; + case XML_TOK_COND_SECT_CLOSE: + if (state->includeLevel == 0) + break; + state->includeLevel -= 1; + return XML_ROLE_NONE; + case XML_TOK_PROLOG_S: + return XML_ROLE_NONE; + case XML_TOK_CLOSE_BRACKET: + break; + case XML_TOK_NONE: + if (state->includeLevel) + break; + return XML_ROLE_NONE; + default: + return internalSubset(state, tok, ptr, end, enc); + } + return common(state, tok); +} + +#endif /* XML_DTD */ + +static +int entity0(PROLOG_STATE *state, + int tok, + const char *ptr ATTR_UNUSED, + const char *end ATTR_UNUSED, + const ENCODING *enc ATTR_UNUSED) +{ + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_NONE; + case XML_TOK_PERCENT: + state->handler = entity1; + return XML_ROLE_NONE; + case XML_TOK_NAME: + state->handler = entity2; + return XML_ROLE_GENERAL_ENTITY_NAME; + } + return common(state, tok); +} + +static +int entity1(PROLOG_STATE *state, + int tok, + const char *ptr ATTR_UNUSED, + const char *end ATTR_UNUSED, + const ENCODING *enc ATTR_UNUSED) +{ + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_NONE; + case XML_TOK_NAME: + state->handler = entity7; + return XML_ROLE_PARAM_ENTITY_NAME; + } + return common(state, tok); +} + +static +int entity2(PROLOG_STATE *state, + int tok, + const char *ptr, + const char *end, + const ENCODING *enc) +{ + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_NONE; + case XML_TOK_NAME: + if (XmlNameMatchesAscii(enc, ptr, end, KW_SYSTEM)) { + state->handler = entity4; + return XML_ROLE_NONE; + } + if (XmlNameMatchesAscii(enc, ptr, end, KW_PUBLIC)) { + state->handler = entity3; + return XML_ROLE_NONE; + } + break; + case XML_TOK_LITERAL: + state->handler = declClose; + return XML_ROLE_ENTITY_VALUE; + } + return common(state, tok); +} + +static +int entity3(PROLOG_STATE *state, + int tok, + const char *ptr ATTR_UNUSED, + const char *end ATTR_UNUSED, + const ENCODING *enc ATTR_UNUSED) +{ + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_NONE; + case XML_TOK_LITERAL: + state->handler = entity4; + return XML_ROLE_ENTITY_PUBLIC_ID; + } + return common(state, tok); +} + + +static +int entity4(PROLOG_STATE *state, + int tok, + const char *ptr ATTR_UNUSED, + const char *end ATTR_UNUSED, + const ENCODING *enc ATTR_UNUSED) +{ + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_NONE; + case XML_TOK_LITERAL: + state->handler = entity5; + return XML_ROLE_ENTITY_SYSTEM_ID; + } + return common(state, tok); +} + +static +int entity5(PROLOG_STATE *state, + int tok, + const char *ptr, + const char *end, + const ENCODING *enc) +{ + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_NONE; + case XML_TOK_DECL_CLOSE: + setTopLevel(state); + return XML_ROLE_EXTERNAL_GENERAL_ENTITY_NO_NOTATION; + case XML_TOK_NAME: + if (XmlNameMatchesAscii(enc, ptr, end, KW_NDATA)) { + state->handler = entity6; + return XML_ROLE_NONE; + } + break; + } + return common(state, tok); +} + +static +int entity6(PROLOG_STATE *state, + int tok, + const char *ptr ATTR_UNUSED, + const char *end ATTR_UNUSED, + const ENCODING *enc ATTR_UNUSED) +{ + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_NONE; + case XML_TOK_NAME: + state->handler = declClose; + return XML_ROLE_ENTITY_NOTATION_NAME; + } + return common(state, tok); +} + +static +int entity7(PROLOG_STATE *state, + int tok, + const char *ptr, + const char *end, + const ENCODING *enc) +{ + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_NONE; + case XML_TOK_NAME: + if (XmlNameMatchesAscii(enc, ptr, end, KW_SYSTEM)) { + state->handler = entity9; + return XML_ROLE_NONE; + } + if (XmlNameMatchesAscii(enc, ptr, end, KW_PUBLIC)) { + state->handler = entity8; + return XML_ROLE_NONE; + } + break; + case XML_TOK_LITERAL: + state->handler = declClose; + return XML_ROLE_ENTITY_VALUE; + } + return common(state, tok); +} + +static +int entity8(PROLOG_STATE *state, + int tok, + const char *ptr ATTR_UNUSED, + const char *end ATTR_UNUSED, + const ENCODING *enc ATTR_UNUSED) +{ + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_NONE; + case XML_TOK_LITERAL: + state->handler = entity9; + return XML_ROLE_ENTITY_PUBLIC_ID; + } + return common(state, tok); +} + +static +int entity9(PROLOG_STATE *state, + int tok, + const char *ptr ATTR_UNUSED, + const char *end ATTR_UNUSED, + const ENCODING *enc ATTR_UNUSED) +{ + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_NONE; + case XML_TOK_LITERAL: + state->handler = declClose; + return XML_ROLE_ENTITY_SYSTEM_ID; + } + return common(state, tok); +} + +static +int notation0(PROLOG_STATE *state, + int tok, + const char *ptr ATTR_UNUSED, + const char *end ATTR_UNUSED, + const ENCODING *enc ATTR_UNUSED) +{ + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_NONE; + case XML_TOK_NAME: + state->handler = notation1; + return XML_ROLE_NOTATION_NAME; + } + return common(state, tok); +} + +static +int notation1(PROLOG_STATE *state, + int tok, + const char *ptr, + const char *end, + const ENCODING *enc) +{ + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_NONE; + case XML_TOK_NAME: + if (XmlNameMatchesAscii(enc, ptr, end, KW_SYSTEM)) { + state->handler = notation3; + return XML_ROLE_NONE; + } + if (XmlNameMatchesAscii(enc, ptr, end, KW_PUBLIC)) { + state->handler = notation2; + return XML_ROLE_NONE; + } + break; + } + return common(state, tok); +} + +static +int notation2(PROLOG_STATE *state, + int tok, + const char *ptr ATTR_UNUSED, + const char *end ATTR_UNUSED, + const ENCODING *enc ATTR_UNUSED) +{ + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_NONE; + case XML_TOK_LITERAL: + state->handler = notation4; + return XML_ROLE_NOTATION_PUBLIC_ID; + } + return common(state, tok); +} + +static +int notation3(PROLOG_STATE *state, + int tok, + const char *ptr ATTR_UNUSED, + const char *end ATTR_UNUSED, + const ENCODING *enc ATTR_UNUSED) +{ + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_NONE; + case XML_TOK_LITERAL: + state->handler = declClose; + return XML_ROLE_NOTATION_SYSTEM_ID; + } + return common(state, tok); +} + +static +int notation4(PROLOG_STATE *state, + int tok, + const char *ptr ATTR_UNUSED, + const char *end ATTR_UNUSED, + const ENCODING *enc ATTR_UNUSED) +{ + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_NONE; + case XML_TOK_LITERAL: + state->handler = declClose; + return XML_ROLE_NOTATION_SYSTEM_ID; + case XML_TOK_DECL_CLOSE: + setTopLevel(state); + return XML_ROLE_NOTATION_NO_SYSTEM_ID; + } + return common(state, tok); +} + +static +int attlist0(PROLOG_STATE *state, + int tok, + const char *ptr ATTR_UNUSED, + const char *end ATTR_UNUSED, + const ENCODING *enc ATTR_UNUSED) +{ + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_NONE; + case XML_TOK_NAME: + case XML_TOK_PREFIXED_NAME: + state->handler = attlist1; + return XML_ROLE_ATTLIST_ELEMENT_NAME; + } + return common(state, tok); +} + +static +int attlist1(PROLOG_STATE *state, + int tok, + const char *ptr ATTR_UNUSED, + const char *end ATTR_UNUSED, + const ENCODING *enc ATTR_UNUSED) +{ + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_NONE; + case XML_TOK_DECL_CLOSE: + setTopLevel(state); + return XML_ROLE_NONE; + case XML_TOK_NAME: + case XML_TOK_PREFIXED_NAME: + state->handler = attlist2; + return XML_ROLE_ATTRIBUTE_NAME; + } + return common(state, tok); +} + +static +int attlist2(PROLOG_STATE *state, + int tok, + const char *ptr, + const char *end, + const ENCODING *enc) +{ + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_NONE; + case XML_TOK_NAME: + { + static const char *types[] = { + KW_CDATA, + KW_ID, + KW_IDREF, + KW_IDREFS, + KW_ENTITY, + KW_ENTITIES, + KW_NMTOKEN, + KW_NMTOKENS, + }; + int i; + for (i = 0; i < (int)(sizeof(types)/sizeof(types[0])); i++) + if (XmlNameMatchesAscii(enc, ptr, end, types[i])) { + state->handler = attlist8; + return XML_ROLE_ATTRIBUTE_TYPE_CDATA + i; + } + } + if (XmlNameMatchesAscii(enc, ptr, end, KW_NOTATION)) { + state->handler = attlist5; + return XML_ROLE_NONE; + } + break; + case XML_TOK_OPEN_PAREN: + state->handler = attlist3; + return XML_ROLE_NONE; + } + return common(state, tok); +} + +static +int attlist3(PROLOG_STATE *state, + int tok, + const char *ptr ATTR_UNUSED, + const char *end ATTR_UNUSED, + const ENCODING *enc ATTR_UNUSED) +{ + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_NONE; + case XML_TOK_NMTOKEN: + case XML_TOK_NAME: + case XML_TOK_PREFIXED_NAME: + state->handler = attlist4; + return XML_ROLE_ATTRIBUTE_ENUM_VALUE; + } + return common(state, tok); +} + +static +int attlist4(PROLOG_STATE *state, + int tok, + const char *ptr ATTR_UNUSED, + const char *end ATTR_UNUSED, + const ENCODING *enc ATTR_UNUSED) +{ + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_NONE; + case XML_TOK_CLOSE_PAREN: + state->handler = attlist8; + return XML_ROLE_NONE; + case XML_TOK_OR: + state->handler = attlist3; + return XML_ROLE_NONE; + } + return common(state, tok); +} + +static +int attlist5(PROLOG_STATE *state, + int tok, + const char *ptr ATTR_UNUSED, + const char *end ATTR_UNUSED, + const ENCODING *enc ATTR_UNUSED) +{ + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_NONE; + case XML_TOK_OPEN_PAREN: + state->handler = attlist6; + return XML_ROLE_NONE; + } + return common(state, tok); +} + + +static +int attlist6(PROLOG_STATE *state, + int tok, + const char *ptr ATTR_UNUSED, + const char *end ATTR_UNUSED, + const ENCODING *enc ATTR_UNUSED) +{ + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_NONE; + case XML_TOK_NAME: + state->handler = attlist7; + return XML_ROLE_ATTRIBUTE_NOTATION_VALUE; + } + return common(state, tok); +} + +static +int attlist7(PROLOG_STATE *state, + int tok, + const char *ptr ATTR_UNUSED, + const char *end ATTR_UNUSED, + const ENCODING *enc ATTR_UNUSED) +{ + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_NONE; + case XML_TOK_CLOSE_PAREN: + state->handler = attlist8; + return XML_ROLE_NONE; + case XML_TOK_OR: + state->handler = attlist6; + return XML_ROLE_NONE; + } + return common(state, tok); +} + +/* default value */ +static +int attlist8(PROLOG_STATE *state, + int tok, + const char *ptr, + const char *end, + const ENCODING *enc) +{ + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_NONE; + case XML_TOK_POUND_NAME: + if (XmlNameMatchesAscii(enc, + ptr + MIN_BYTES_PER_CHAR(enc), + end, + KW_IMPLIED)) { + state->handler = attlist1; + return XML_ROLE_IMPLIED_ATTRIBUTE_VALUE; + } + if (XmlNameMatchesAscii(enc, + ptr + MIN_BYTES_PER_CHAR(enc), + end, + KW_REQUIRED)) { + state->handler = attlist1; + return XML_ROLE_REQUIRED_ATTRIBUTE_VALUE; + } + if (XmlNameMatchesAscii(enc, + ptr + MIN_BYTES_PER_CHAR(enc), + end, + KW_FIXED)) { + state->handler = attlist9; + return XML_ROLE_NONE; + } + break; + case XML_TOK_LITERAL: + state->handler = attlist1; + return XML_ROLE_DEFAULT_ATTRIBUTE_VALUE; + } + return common(state, tok); +} + +static +int attlist9(PROLOG_STATE *state, + int tok, + const char *ptr ATTR_UNUSED, + const char *end ATTR_UNUSED, + const ENCODING *enc ATTR_UNUSED) +{ + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_NONE; + case XML_TOK_LITERAL: + state->handler = attlist1; + return XML_ROLE_FIXED_ATTRIBUTE_VALUE; + } + return common(state, tok); +} + +static +int element0(PROLOG_STATE *state, + int tok, + const char *ptr ATTR_UNUSED, + const char *end ATTR_UNUSED, + const ENCODING *enc ATTR_UNUSED) +{ + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_NONE; + case XML_TOK_NAME: + case XML_TOK_PREFIXED_NAME: + state->handler = element1; + return XML_ROLE_ELEMENT_NAME; + } + return common(state, tok); +} + +static +int element1(PROLOG_STATE *state, + int tok, + const char *ptr, + const char *end, + const ENCODING *enc) +{ + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_NONE; + case XML_TOK_NAME: + if (XmlNameMatchesAscii(enc, ptr, end, KW_EMPTY)) { + state->handler = declClose; + return XML_ROLE_CONTENT_EMPTY; + } + if (XmlNameMatchesAscii(enc, ptr, end, KW_ANY)) { + state->handler = declClose; + return XML_ROLE_CONTENT_ANY; + } + break; + case XML_TOK_OPEN_PAREN: + state->handler = element2; + state->level = 1; + return XML_ROLE_GROUP_OPEN; + } + return common(state, tok); +} + +static +int element2(PROLOG_STATE *state, + int tok, + const char *ptr, + const char *end, + const ENCODING *enc) +{ + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_NONE; + case XML_TOK_POUND_NAME: + if (XmlNameMatchesAscii(enc, + ptr + MIN_BYTES_PER_CHAR(enc), + end, + KW_PCDATA)) { + state->handler = element3; + return XML_ROLE_CONTENT_PCDATA; + } + break; + case XML_TOK_OPEN_PAREN: + state->level = 2; + state->handler = element6; + return XML_ROLE_GROUP_OPEN; + case XML_TOK_NAME: + case XML_TOK_PREFIXED_NAME: + state->handler = element7; + return XML_ROLE_CONTENT_ELEMENT; + case XML_TOK_NAME_QUESTION: + state->handler = element7; + return XML_ROLE_CONTENT_ELEMENT_OPT; + case XML_TOK_NAME_ASTERISK: + state->handler = element7; + return XML_ROLE_CONTENT_ELEMENT_REP; + case XML_TOK_NAME_PLUS: + state->handler = element7; + return XML_ROLE_CONTENT_ELEMENT_PLUS; + } + return common(state, tok); +} + +static +int element3(PROLOG_STATE *state, + int tok, + const char *ptr ATTR_UNUSED, + const char *end ATTR_UNUSED, + const ENCODING *enc ATTR_UNUSED) +{ + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_NONE; + case XML_TOK_CLOSE_PAREN: + case XML_TOK_CLOSE_PAREN_ASTERISK: + state->handler = declClose; + return XML_ROLE_GROUP_CLOSE_REP; + case XML_TOK_OR: + state->handler = element4; + return XML_ROLE_NONE; + } + return common(state, tok); +} + +static +int element4(PROLOG_STATE *state, + int tok, + const char *ptr ATTR_UNUSED, + const char *end ATTR_UNUSED, + const ENCODING *enc ATTR_UNUSED) +{ + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_NONE; + case XML_TOK_NAME: + case XML_TOK_PREFIXED_NAME: + state->handler = element5; + return XML_ROLE_CONTENT_ELEMENT; + } + return common(state, tok); +} + +static +int element5(PROLOG_STATE *state, + int tok, + const char *ptr ATTR_UNUSED, + const char *end ATTR_UNUSED, + const ENCODING *enc ATTR_UNUSED) +{ + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_NONE; + case XML_TOK_CLOSE_PAREN_ASTERISK: + state->handler = declClose; + return XML_ROLE_GROUP_CLOSE_REP; + case XML_TOK_OR: + state->handler = element4; + return XML_ROLE_NONE; + } + return common(state, tok); +} + +static +int element6(PROLOG_STATE *state, + int tok, + const char *ptr ATTR_UNUSED, + const char *end ATTR_UNUSED, + const ENCODING *enc ATTR_UNUSED) +{ + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_NONE; + case XML_TOK_OPEN_PAREN: + state->level += 1; + return XML_ROLE_GROUP_OPEN; + case XML_TOK_NAME: + case XML_TOK_PREFIXED_NAME: + state->handler = element7; + return XML_ROLE_CONTENT_ELEMENT; + case XML_TOK_NAME_QUESTION: + state->handler = element7; + return XML_ROLE_CONTENT_ELEMENT_OPT; + case XML_TOK_NAME_ASTERISK: + state->handler = element7; + return XML_ROLE_CONTENT_ELEMENT_REP; + case XML_TOK_NAME_PLUS: + state->handler = element7; + return XML_ROLE_CONTENT_ELEMENT_PLUS; + } + return common(state, tok); +} + +static +int element7(PROLOG_STATE *state, + int tok, + const char *ptr ATTR_UNUSED, + const char *end ATTR_UNUSED, + const ENCODING *enc ATTR_UNUSED) +{ + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_NONE; + case XML_TOK_CLOSE_PAREN: + state->level -= 1; + if (state->level == 0) + state->handler = declClose; + return XML_ROLE_GROUP_CLOSE; + case XML_TOK_CLOSE_PAREN_ASTERISK: + state->level -= 1; + if (state->level == 0) + state->handler = declClose; + return XML_ROLE_GROUP_CLOSE_REP; + case XML_TOK_CLOSE_PAREN_QUESTION: + state->level -= 1; + if (state->level == 0) + state->handler = declClose; + return XML_ROLE_GROUP_CLOSE_OPT; + case XML_TOK_CLOSE_PAREN_PLUS: + state->level -= 1; + if (state->level == 0) + state->handler = declClose; + return XML_ROLE_GROUP_CLOSE_PLUS; + case XML_TOK_COMMA: + state->handler = element6; + return XML_ROLE_GROUP_SEQUENCE; + case XML_TOK_OR: + state->handler = element6; + return XML_ROLE_GROUP_CHOICE; + } + return common(state, tok); +} + +#ifdef XML_DTD + +static +int condSect0(PROLOG_STATE *state, + int tok, + const char *ptr, + const char *end, + const ENCODING *enc) +{ + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_NONE; + case XML_TOK_NAME: + if (XmlNameMatchesAscii(enc, ptr, end, KW_INCLUDE)) { + state->handler = condSect1; + return XML_ROLE_NONE; + } + if (XmlNameMatchesAscii(enc, ptr, end, KW_IGNORE)) { + state->handler = condSect2; + return XML_ROLE_NONE; + } + break; + } + return common(state, tok); +} + +static +int condSect1(PROLOG_STATE *state, + int tok, + const char *ptr, + const char *end, + const ENCODING *enc) +{ + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_NONE; + case XML_TOK_OPEN_BRACKET: + state->handler = externalSubset1; + state->includeLevel += 1; + return XML_ROLE_NONE; + } + return common(state, tok); +} + +static +int condSect2(PROLOG_STATE *state, + int tok, + const char *ptr, + const char *end, + const ENCODING *enc) +{ + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_NONE; + case XML_TOK_OPEN_BRACKET: + state->handler = externalSubset1; + return XML_ROLE_IGNORE_SECT; + } + return common(state, tok); +} + +#endif /* XML_DTD */ + +static +int declClose(PROLOG_STATE *state, + int tok, + const char *ptr ATTR_UNUSED, + const char *end ATTR_UNUSED, + const ENCODING *enc ATTR_UNUSED) +{ + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_NONE; + case XML_TOK_DECL_CLOSE: + setTopLevel(state); + return XML_ROLE_NONE; + } + return common(state, tok); +} + +#if 0 + +static +int ignore(PROLOG_STATE *state, + int tok, + const char *ptr, + const char *end, + const ENCODING *enc) +{ + switch (tok) { + case XML_TOK_DECL_CLOSE: + state->handler = internalSubset; + return 0; + default: + return XML_ROLE_NONE; + } + return common(state, tok); +} +#endif + +static +int error(PROLOG_STATE *state ATTR_UNUSED, + int tok ATTR_UNUSED, + const char *ptr ATTR_UNUSED, + const char *end ATTR_UNUSED, + const ENCODING *enc ATTR_UNUSED) +{ + return XML_ROLE_NONE; +} + +static +int common(PROLOG_STATE *state, int tok ATTR_UNUSED) +{ +#ifdef XML_DTD + if (!state->documentEntity && tok == XML_TOK_PARAM_ENTITY_REF) + return XML_ROLE_INNER_PARAM_ENTITY_REF; +#endif + state->handler = error; + return XML_ROLE_ERROR; +} + +void xmlrpc_XmlPrologStateInit(PROLOG_STATE *state) +{ + state->handler = prolog0; +#ifdef XML_DTD + state->documentEntity = 1; + state->includeLevel = 0; +#endif /* XML_DTD */ +} + +#ifdef XML_DTD + +void XmlPrologStateInitExternalEntity(PROLOG_STATE *state) +{ + state->handler = externalSubset0; + state->documentEntity = 0; + state->includeLevel = 0; +} + +#endif /* XML_DTD */ diff --git a/lib/expat/xmltok/xmlrole.h b/lib/expat/xmltok/xmlrole.h new file mode 100644 index 0000000..d604c72 --- /dev/null +++ b/lib/expat/xmltok/xmlrole.h @@ -0,0 +1,99 @@ +/* +Copyright (c) 1998, 1999 Thai Open Source Software Center Ltd +See the file copying.txt for copying permission. +*/ + +#ifndef XmlRole_INCLUDED +#define XmlRole_INCLUDED 1 + +#include "xmltok.h" + +#ifdef __cplusplus +extern "C" { +#endif + +enum { + XML_ROLE_ERROR = -1, + XML_ROLE_NONE = 0, + XML_ROLE_XML_DECL, + XML_ROLE_INSTANCE_START, + XML_ROLE_DOCTYPE_NAME, + XML_ROLE_DOCTYPE_SYSTEM_ID, + XML_ROLE_DOCTYPE_PUBLIC_ID, + XML_ROLE_DOCTYPE_CLOSE, + XML_ROLE_GENERAL_ENTITY_NAME, + XML_ROLE_PARAM_ENTITY_NAME, + XML_ROLE_ENTITY_VALUE, + XML_ROLE_ENTITY_SYSTEM_ID, + XML_ROLE_ENTITY_PUBLIC_ID, + XML_ROLE_ENTITY_NOTATION_NAME, + XML_ROLE_NOTATION_NAME, + XML_ROLE_NOTATION_SYSTEM_ID, + XML_ROLE_NOTATION_NO_SYSTEM_ID, + XML_ROLE_NOTATION_PUBLIC_ID, + XML_ROLE_ATTRIBUTE_NAME, + XML_ROLE_ATTRIBUTE_TYPE_CDATA, + XML_ROLE_ATTRIBUTE_TYPE_ID, + XML_ROLE_ATTRIBUTE_TYPE_IDREF, + XML_ROLE_ATTRIBUTE_TYPE_IDREFS, + XML_ROLE_ATTRIBUTE_TYPE_ENTITY, + XML_ROLE_ATTRIBUTE_TYPE_ENTITIES, + XML_ROLE_ATTRIBUTE_TYPE_NMTOKEN, + XML_ROLE_ATTRIBUTE_TYPE_NMTOKENS, + XML_ROLE_ATTRIBUTE_ENUM_VALUE, + XML_ROLE_ATTRIBUTE_NOTATION_VALUE, + XML_ROLE_ATTLIST_ELEMENT_NAME, + XML_ROLE_IMPLIED_ATTRIBUTE_VALUE, + XML_ROLE_REQUIRED_ATTRIBUTE_VALUE, + XML_ROLE_DEFAULT_ATTRIBUTE_VALUE, + XML_ROLE_FIXED_ATTRIBUTE_VALUE, + XML_ROLE_ELEMENT_NAME, + XML_ROLE_CONTENT_ANY, + XML_ROLE_CONTENT_EMPTY, + XML_ROLE_CONTENT_PCDATA, + XML_ROLE_GROUP_OPEN, + XML_ROLE_GROUP_CLOSE, + XML_ROLE_GROUP_CLOSE_REP, + XML_ROLE_GROUP_CLOSE_OPT, + XML_ROLE_GROUP_CLOSE_PLUS, + XML_ROLE_GROUP_CHOICE, + XML_ROLE_GROUP_SEQUENCE, + XML_ROLE_CONTENT_ELEMENT, + XML_ROLE_CONTENT_ELEMENT_REP, + XML_ROLE_CONTENT_ELEMENT_OPT, + XML_ROLE_CONTENT_ELEMENT_PLUS, +#ifdef XML_DTD + XML_ROLE_TEXT_DECL, + XML_ROLE_IGNORE_SECT, + XML_ROLE_INNER_PARAM_ENTITY_REF, +#endif /* XML_DTD */ + XML_ROLE_PARAM_ENTITY_REF, + XML_ROLE_EXTERNAL_GENERAL_ENTITY_NO_NOTATION +}; + +typedef struct prolog_state { + int (*handler)(struct prolog_state *state, + int tok, + const char *ptr, + const char *end, + const ENCODING *enc); + unsigned level; +#ifdef XML_DTD + unsigned includeLevel; + int documentEntity; +#endif /* XML_DTD */ +} PROLOG_STATE; + +void XMLTOKAPI xmlrpc_XmlPrologStateInit(PROLOG_STATE *); +#ifdef XML_DTD +void XMLTOKAPI xmlrpc_XmlPrologStateInitExternalEntity(PROLOG_STATE *); +#endif /* XML_DTD */ + +#define XmlTokenRole(state, tok, ptr, end, enc) \ + (((state)->handler)(state, tok, ptr, end, enc)) + +#ifdef __cplusplus +} +#endif + +#endif /* not XmlRole_INCLUDED */ diff --git a/lib/expat/xmltok/xmltok.c b/lib/expat/xmltok/xmltok.c new file mode 100644 index 0000000..b96fdaa --- /dev/null +++ b/lib/expat/xmltok/xmltok.c @@ -0,0 +1,1561 @@ +/* +Copyright (c) 1998, 1999 Thai Open Source Software Center Ltd +See the file copying.txt for copying permission. +*/ + +#include "xmlrpc_config.h" +#include "xmldef.h" +#include "xmltok.h" +#include "nametab.h" + +#ifdef XML_DTD +#define IGNORE_SECTION_TOK_VTABLE , PREFIX(ignoreSectionTok) +#else +#define IGNORE_SECTION_TOK_VTABLE /* as nothing */ +#endif + +#define VTABLE1 \ + { PREFIX(prologTok), PREFIX(contentTok), \ + PREFIX(cdataSectionTok) IGNORE_SECTION_TOK_VTABLE }, \ + { PREFIX(attributeValueTok), PREFIX(entityValueTok) }, \ + PREFIX(sameName), \ + PREFIX(nameMatchesAscii), \ + PREFIX(nameLength), \ + PREFIX(skipS), \ + PREFIX(getAtts), \ + PREFIX(charRefNumber), \ + PREFIX(predefinedEntityName), \ + PREFIX(updatePosition), \ + PREFIX(isPublicId) + +#define VTABLE VTABLE1, PREFIX(toUtf8), PREFIX(toUtf16) + +#define UCS2_GET_NAMING(pages, hi, lo) \ + (namingBitmap[(pages[hi] << 3) + ((lo) >> 5)] & (1 << ((lo) & 0x1F))) + +/* A 2 byte UTF-8 representation splits the characters 11 bits +between the bottom 5 and 6 bits of the bytes. +We need 8 bits to index into pages, 3 bits to add to that index and +5 bits to generate the mask. */ +#define UTF8_GET_NAMING2(pages, byte) \ + (namingBitmap[((pages)[(((byte)[0]) >> 2) & 7] << 3) \ + + ((((byte)[0]) & 3) << 1) \ + + ((((byte)[1]) >> 5) & 1)] \ + & (1 << (((byte)[1]) & 0x1F))) + +/* A 3 byte UTF-8 representation splits the characters 16 bits +between the bottom 4, 6 and 6 bits of the bytes. +We need 8 bits to index into pages, 3 bits to add to that index and +5 bits to generate the mask. */ +#define UTF8_GET_NAMING3(pages, byte) \ + (namingBitmap[((pages)[((((byte)[0]) & 0xF) << 4) \ + + ((((byte)[1]) >> 2) & 0xF)] \ + << 3) \ + + ((((byte)[1]) & 3) << 1) \ + + ((((byte)[2]) >> 5) & 1)] \ + & (1 << (((byte)[2]) & 0x1F))) + +#define UTF8_GET_NAMING(pages, p, n) \ + ((n) == 2 \ + ? UTF8_GET_NAMING2(pages, (const unsigned char *)(p)) \ + : ((n) == 3 \ + ? UTF8_GET_NAMING3(pages, (const unsigned char *)(p)) \ + : 0)) + +#define UTF8_INVALID3(p) \ + ((*p) == 0xED \ + ? (((p)[1] & 0x20) != 0) \ + : ((*p) == 0xEF \ + ? ((p)[1] == 0xBF && ((p)[2] == 0xBF || (p)[2] == 0xBE)) \ + : 0)) + +#define UTF8_INVALID4(p) ((*p) == 0xF4 && ((p)[1] & 0x30) != 0) + +static +int isNever(const ENCODING *enc ATTR_UNUSED, const char *p ATTR_UNUSED) +{ + return 0; +} + +static +int utf8_isName2(const ENCODING *enc ATTR_UNUSED, const char *p) +{ + return UTF8_GET_NAMING2(namePages, (const unsigned char *)p); +} + +static +int utf8_isName3(const ENCODING *enc ATTR_UNUSED, const char *p) +{ + return UTF8_GET_NAMING3(namePages, (const unsigned char *)p); +} + +#define utf8_isName4 isNever + +static +int utf8_isNmstrt2(const ENCODING *enc ATTR_UNUSED, const char *p) +{ + return UTF8_GET_NAMING2(nmstrtPages, (const unsigned char *)p); +} + +static +int utf8_isNmstrt3(const ENCODING *enc ATTR_UNUSED, const char *p) +{ + return UTF8_GET_NAMING3(nmstrtPages, (const unsigned char *)p); +} + +#define utf8_isNmstrt4 isNever + +#define utf8_isInvalid2 isNever + +static +int utf8_isInvalid3(const ENCODING *enc ATTR_UNUSED, const char *p) +{ + return UTF8_INVALID3((const unsigned char *)p); +} + +static +int utf8_isInvalid4(const ENCODING *enc ATTR_UNUSED, const char *p) +{ + return UTF8_INVALID4((const unsigned char *)p); +} + +struct normal_encoding { + ENCODING enc; + unsigned char type[256]; +#ifdef XML_MIN_SIZE + int (*byteType)(const ENCODING *, const char *); + int (*isNameMin)(const ENCODING *, const char *); + int (*isNmstrtMin)(const ENCODING *, const char *); + int (*byteToAscii)(const ENCODING *, const char *); + int (*charMatches)(const ENCODING *, const char *, int); +#endif /* XML_MIN_SIZE */ + int (*isName2)(const ENCODING *, const char *); + int (*isName3)(const ENCODING *, const char *); + int (*isName4)(const ENCODING *, const char *); + int (*isNmstrt2)(const ENCODING *, const char *); + int (*isNmstrt3)(const ENCODING *, const char *); + int (*isNmstrt4)(const ENCODING *, const char *); + int (*isInvalid2)(const ENCODING *, const char *); + int (*isInvalid3)(const ENCODING *, const char *); + int (*isInvalid4)(const ENCODING *, const char *); +}; + +#ifdef XML_MIN_SIZE + +#define STANDARD_VTABLE(E) \ + E ## byteType, \ + E ## isNameMin, \ + E ## isNmstrtMin, \ + E ## byteToAscii, \ + E ## charMatches, + +#else + +#define STANDARD_VTABLE(E) /* as nothing */ + +#endif + +#define NORMAL_VTABLE(E) \ + E ## isName2, \ + E ## isName3, \ + E ## isName4, \ + E ## isNmstrt2, \ + E ## isNmstrt3, \ + E ## isNmstrt4, \ + E ## isInvalid2, \ + E ## isInvalid3, \ + E ## isInvalid4 + +#define NULL_NORMAL_VTABLE \ + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL + +static int checkCharRefNumber(int); + +#include "xmltok_impl.h" +#include "ascii.h" + +#ifdef XML_MIN_SIZE +#define sb_isNameMin isNever +#define sb_isNmstrtMin isNever +#endif + +#ifdef XML_MIN_SIZE +#define MINBPC(enc) ((enc)->minBytesPerChar) +#else +/* minimum bytes per character */ +#define MINBPC(enc) 1 +#endif + +#define SB_BYTE_TYPE(enc, p) \ + (((struct normal_encoding *)(enc))->type[(unsigned char)*(p)]) + +#ifdef XML_MIN_SIZE +static +int sb_byteType(const ENCODING *enc, const char *p) +{ + return SB_BYTE_TYPE(enc, p); +} +#define BYTE_TYPE(enc, p) \ + (((const struct normal_encoding *)(enc))->byteType(enc, p)) +#else +#define BYTE_TYPE(enc, p) SB_BYTE_TYPE(enc, p) +#endif + +#ifdef XML_MIN_SIZE +#define BYTE_TO_ASCII(enc, p) \ + (((const struct normal_encoding *)(enc))->byteToAscii(enc, p)) +static +int sb_byteToAscii(const ENCODING *enc, const char *p) +{ + return *p; +} +#else +#define BYTE_TO_ASCII(enc, p) (*(p)) +#endif + +#define IS_NAME_CHAR(enc, p, n) \ + (((const struct normal_encoding *)(enc))->isName ## n(enc, p)) +#define IS_NMSTRT_CHAR(enc, p, n) \ + (((const struct normal_encoding *)(enc))->isNmstrt ## n(enc, p)) +#define IS_INVALID_CHAR(enc, p, n) \ + (((const struct normal_encoding *)(enc))->isInvalid ## n(enc, p)) + +#ifdef XML_MIN_SIZE +#define IS_NAME_CHAR_MINBPC(enc, p) \ + (((const struct normal_encoding *)(enc))->isNameMin(enc, p)) +#define IS_NMSTRT_CHAR_MINBPC(enc, p) \ + (((const struct normal_encoding *)(enc))->isNmstrtMin(enc, p)) +#else +#define IS_NAME_CHAR_MINBPC(enc, p) (0) +#define IS_NMSTRT_CHAR_MINBPC(enc, p) (0) +#endif + +#ifdef XML_MIN_SIZE +#define CHAR_MATCHES(enc, p, c) \ + (((const struct normal_encoding *)(enc))->charMatches(enc, p, c)) +static +int sb_charMatches(const ENCODING *enc, const char *p, int c) +{ + return *p == c; +} +#else +/* c is an ASCII character */ +#define CHAR_MATCHES(enc, p, c) (*(p) == c) +#endif + +#define PREFIX(ident) normal_ ## ident +#include "xmltok_impl.c" + +#undef MINBPC +#undef BYTE_TYPE +#undef BYTE_TO_ASCII +#undef CHAR_MATCHES +#undef IS_NAME_CHAR +#undef IS_NAME_CHAR_MINBPC +#undef IS_NMSTRT_CHAR +#undef IS_NMSTRT_CHAR_MINBPC +#undef IS_INVALID_CHAR + +enum { /* UTF8_cvalN is value of masked first byte of N byte sequence */ + UTF8_cval1 = 0x00, + UTF8_cval2 = 0xc0, + UTF8_cval3 = 0xe0, + UTF8_cval4 = 0xf0 +}; + +static +void utf8_toUtf8(const ENCODING * enc ATTR_UNUSED, + const char **fromP, const char *fromLim, + char **toP, const char *toLim) +{ + char *to; + const char *from; + if (fromLim - *fromP > toLim - *toP) { + /* Avoid copying partial characters. */ + for (fromLim = *fromP + (toLim - *toP); fromLim > *fromP; fromLim--) + if (((unsigned char)fromLim[-1] & 0xc0) != 0x80) + break; + } + for (to = *toP, from = *fromP; from != fromLim; from++, to++) + *to = *from; + *fromP = from; + *toP = to; +} + +static +void utf8_toUtf16(const ENCODING *enc, + const char **fromP, const char *fromLim, + unsigned short **toP, const unsigned short *toLim) +{ + unsigned short *to = *toP; + const char *from = *fromP; + while (from != fromLim && to != toLim) { + switch (((struct normal_encoding *)enc)->type[(unsigned char)*from]) { + case BT_LEAD2: + *to++ = ((from[0] & 0x1f) << 6) | (from[1] & 0x3f); + from += 2; + break; + case BT_LEAD3: + *to++ = ((from[0] & 0xf) << 12) | ((from[1] & 0x3f) << 6) | (from[2] & 0x3f); + from += 3; + break; + case BT_LEAD4: + { + unsigned long n; + if (to + 1 == toLim) + break; + n = ((from[0] & 0x7) << 18) | ((from[1] & 0x3f) << 12) | ((from[2] & 0x3f) << 6) | (from[3] & 0x3f); + n -= 0x10000; + to[0] = (unsigned short)((n >> 10) | 0xD800); + to[1] = (unsigned short)((n & 0x3FF) | 0xDC00); + to += 2; + from += 4; + } + break; + default: + *to++ = *from++; + break; + } + } + *fromP = from; + *toP = to; +} + +#ifdef XML_NS +static const struct normal_encoding utf8_encoding_ns = { + { VTABLE1, utf8_toUtf8, utf8_toUtf16, 1, 1, 0 }, + { +#include "asciitab.h" +#include "utf8tab.h" + }, + STANDARD_VTABLE(sb_) NORMAL_VTABLE(utf8_) +}; +#endif + +static const struct normal_encoding utf8_encoding = { + { VTABLE1, utf8_toUtf8, utf8_toUtf16, 1, 1, 0 }, + { +#define BT_COLON BT_NMSTRT +#include "asciitab.h" +#undef BT_COLON +#include "utf8tab.h" + }, + STANDARD_VTABLE(sb_) NORMAL_VTABLE(utf8_) +}; + +#ifdef XML_NS + +static const struct normal_encoding internal_utf8_encoding_ns = { + { VTABLE1, utf8_toUtf8, utf8_toUtf16, 1, 1, 0 }, + { +#include "iasciitab.h" +#include "utf8tab.h" + }, + STANDARD_VTABLE(sb_) NORMAL_VTABLE(utf8_) +}; + +#endif + +static const struct normal_encoding internal_utf8_encoding = { + { VTABLE1, utf8_toUtf8, utf8_toUtf16, 1, 1, 0 }, + { +#define BT_COLON BT_NMSTRT +#include "iasciitab.h" +#undef BT_COLON +#include "utf8tab.h" + }, + STANDARD_VTABLE(sb_) NORMAL_VTABLE(utf8_) +}; + +static +void latin1_toUtf8(const ENCODING *enc ATTR_UNUSED, + const char **fromP, const char *fromLim, + char **toP, const char *toLim) +{ + for (;;) { + unsigned char c; + if (*fromP == fromLim) + break; + c = (unsigned char)**fromP; + if (c & 0x80) { + if (toLim - *toP < 2) + break; + *(*toP)++ = ((c >> 6) | UTF8_cval2); + *(*toP)++ = ((c & 0x3f) | 0x80); + (*fromP)++; + } + else { + if (*toP == toLim) + break; + *(*toP)++ = *(*fromP)++; + } + } +} + +static +void latin1_toUtf16(const ENCODING *enc ATTR_UNUSED, + const char **fromP, const char *fromLim, + unsigned short **toP, const unsigned short *toLim) +{ + while (*fromP != fromLim && *toP != toLim) + *(*toP)++ = (unsigned char)*(*fromP)++; +} + +#ifdef XML_NS + +static const struct normal_encoding latin1_encoding_ns = { + { VTABLE1, latin1_toUtf8, latin1_toUtf16, 1, 0, 0 }, + { +#include "asciitab.h" +#include "latin1tab.h" + }, + STANDARD_VTABLE(sb_) NULL_NORMAL_VTABLE +}; + +#endif + +static const struct normal_encoding latin1_encoding = { + { VTABLE1, latin1_toUtf8, latin1_toUtf16, 1, 0, 0 }, + { +#define BT_COLON BT_NMSTRT +#include "asciitab.h" +#undef BT_COLON +#include "latin1tab.h" + }, + STANDARD_VTABLE(sb_) NULL_NORMAL_VTABLE +}; + +static +void ascii_toUtf8(const ENCODING *enc ATTR_UNUSED, + const char **fromP, const char *fromLim, + char **toP, const char *toLim) +{ + while (*fromP != fromLim && *toP != toLim) + *(*toP)++ = *(*fromP)++; +} + +#ifdef XML_NS + +static const struct normal_encoding ascii_encoding_ns = { + { VTABLE1, ascii_toUtf8, latin1_toUtf16, 1, 1, 0 }, + { +#include "asciitab.h" +/* BT_NONXML == 0 */ + }, + STANDARD_VTABLE(sb_) +}; + +#endif + +static const struct normal_encoding ascii_encoding = { + { VTABLE1, ascii_toUtf8, latin1_toUtf16, 1, 1, 0 }, + { +#define BT_COLON BT_NMSTRT +#include "asciitab.h" +#undef BT_COLON +/* BT_NONXML == 0 */ + }, + STANDARD_VTABLE(sb_) NULL_NORMAL_VTABLE +}; + +static int unicode_byte_type(char hi, char lo) +{ + switch ((unsigned char)hi) { + case 0xD8: case 0xD9: case 0xDA: case 0xDB: + return BT_LEAD4; + case 0xDC: case 0xDD: case 0xDE: case 0xDF: + return BT_TRAIL; + case 0xFF: + switch ((unsigned char)lo) { + case 0xFF: + case 0xFE: + return BT_NONXML; + } + break; + } + return BT_NONASCII; +} + +#define DEFINE_UTF16_TO_UTF8(E) \ +static \ +void E ## toUtf8(const ENCODING *enc ATTR_UNUSED, \ + const char **fromP, const char *fromLim, \ + char **toP, const char *toLim) \ +{ \ + const char *from; \ + for (from = *fromP; from != fromLim; from += 2) { \ + int plane; \ + unsigned char lo2; \ + unsigned char lo = GET_LO(from); \ + unsigned char hi = GET_HI(from); \ + switch (hi) { \ + case 0: \ + if (lo < 0x80) { \ + if (*toP == toLim) { \ + *fromP = from; \ + return; \ + } \ + *(*toP)++ = lo; \ + break; \ + } \ + /* fall through */ \ + case 0x1: case 0x2: case 0x3: \ + case 0x4: case 0x5: case 0x6: case 0x7: \ + if (toLim - *toP < 2) { \ + *fromP = from; \ + return; \ + } \ + *(*toP)++ = ((lo >> 6) | (hi << 2) | UTF8_cval2); \ + *(*toP)++ = ((lo & 0x3f) | 0x80); \ + break; \ + default: \ + if (toLim - *toP < 3) { \ + *fromP = from; \ + return; \ + } \ + /* 16 bits divided 4, 6, 6 amongst 3 bytes */ \ + *(*toP)++ = ((hi >> 4) | UTF8_cval3); \ + *(*toP)++ = (((hi & 0xf) << 2) | (lo >> 6) | 0x80); \ + *(*toP)++ = ((lo & 0x3f) | 0x80); \ + break; \ + case 0xD8: case 0xD9: case 0xDA: case 0xDB: \ + if (toLim - *toP < 4) { \ + *fromP = from; \ + return; \ + } \ + plane = (((hi & 0x3) << 2) | ((lo >> 6) & 0x3)) + 1; \ + *(*toP)++ = ((plane >> 2) | UTF8_cval4); \ + *(*toP)++ = (((lo >> 2) & 0xF) | ((plane & 0x3) << 4) | 0x80); \ + from += 2; \ + lo2 = GET_LO(from); \ + *(*toP)++ = (((lo & 0x3) << 4) \ + | ((GET_HI(from) & 0x3) << 2) \ + | (lo2 >> 6) \ + | 0x80); \ + *(*toP)++ = ((lo2 & 0x3f) | 0x80); \ + break; \ + } \ + } \ + *fromP = from; \ +} + +#define DEFINE_UTF16_TO_UTF16(E) \ +static \ +void E ## toUtf16(const ENCODING *enc ATTR_UNUSED, \ + const char **fromP, const char *fromLim, \ + unsigned short **toP, const unsigned short *toLim) \ +{ \ + /* Avoid copying first half only of surrogate */ \ + if (fromLim - *fromP > ((toLim - *toP) << 1) \ + && (GET_HI(fromLim - 2) & 0xF8) == 0xD8) \ + fromLim -= 2; \ + for (; *fromP != fromLim && *toP != toLim; *fromP += 2) \ + *(*toP)++ = (GET_HI(*fromP) << 8) | GET_LO(*fromP); \ +} + +#define SET2(ptr, ch) \ + (((ptr)[0] = ((ch) & 0xff)), ((ptr)[1] = ((ch) >> 8))) +#define GET_LO(ptr) ((unsigned char)(ptr)[0]) +#define GET_HI(ptr) ((unsigned char)(ptr)[1]) + +DEFINE_UTF16_TO_UTF8(little2_) +DEFINE_UTF16_TO_UTF16(little2_) + +#undef SET2 +#undef GET_LO +#undef GET_HI + +#define SET2(ptr, ch) \ + (((ptr)[0] = ((ch) >> 8)), ((ptr)[1] = ((ch) & 0xFF))) +#define GET_LO(ptr) ((unsigned char)(ptr)[1]) +#define GET_HI(ptr) ((unsigned char)(ptr)[0]) + +DEFINE_UTF16_TO_UTF8(big2_) +DEFINE_UTF16_TO_UTF16(big2_) + +#undef SET2 +#undef GET_LO +#undef GET_HI + +#define LITTLE2_BYTE_TYPE(enc, p) \ + ((p)[1] == 0 \ + ? ((struct normal_encoding *)(enc))->type[(unsigned char)*(p)] \ + : unicode_byte_type((p)[1], (p)[0])) +#define LITTLE2_BYTE_TO_ASCII(enc, p) ((p)[1] == 0 ? (p)[0] : -1) +#define LITTLE2_CHAR_MATCHES(enc, p, c) ((p)[1] == 0 && (p)[0] == c) +#define LITTLE2_IS_NAME_CHAR_MINBPC(enc, p) \ + UCS2_GET_NAMING(namePages, (unsigned char)p[1], (unsigned char)p[0]) +#define LITTLE2_IS_NMSTRT_CHAR_MINBPC(enc, p) \ + UCS2_GET_NAMING(nmstrtPages, (unsigned char)p[1], (unsigned char)p[0]) + +#ifdef XML_MIN_SIZE + +static +int little2_byteType(const ENCODING *enc, const char *p) +{ + return LITTLE2_BYTE_TYPE(enc, p); +} + +static +int little2_byteToAscii(const ENCODING *enc, const char *p) +{ + return LITTLE2_BYTE_TO_ASCII(enc, p); +} + +static +int little2_charMatches(const ENCODING *enc, const char *p, int c) +{ + return LITTLE2_CHAR_MATCHES(enc, p, c); +} + +static +int little2_isNameMin(const ENCODING *enc, const char *p) +{ + return LITTLE2_IS_NAME_CHAR_MINBPC(enc, p); +} + +static +int little2_isNmstrtMin(const ENCODING *enc, const char *p) +{ + return LITTLE2_IS_NMSTRT_CHAR_MINBPC(enc, p); +} + +#undef VTABLE +#define VTABLE VTABLE1, little2_toUtf8, little2_toUtf16 + +#else /* not XML_MIN_SIZE */ + +#undef PREFIX +#define PREFIX(ident) little2_ ## ident +#define MINBPC(enc) 2 +/* CHAR_MATCHES is guaranteed to have MINBPC bytes available. */ +#define BYTE_TYPE(enc, p) LITTLE2_BYTE_TYPE(enc, p) +#define BYTE_TO_ASCII(enc, p) LITTLE2_BYTE_TO_ASCII(enc, p) +#define CHAR_MATCHES(enc, p, c) LITTLE2_CHAR_MATCHES(enc, p, c) +#define IS_NAME_CHAR(enc, p, n) 0 +#define IS_NAME_CHAR_MINBPC(enc, p) LITTLE2_IS_NAME_CHAR_MINBPC(enc, p) +#define IS_NMSTRT_CHAR(enc, p, n) (0) +#define IS_NMSTRT_CHAR_MINBPC(enc, p) LITTLE2_IS_NMSTRT_CHAR_MINBPC(enc, p) + +#include "xmltok_impl.c" + +#undef MINBPC +#undef BYTE_TYPE +#undef BYTE_TO_ASCII +#undef CHAR_MATCHES +#undef IS_NAME_CHAR +#undef IS_NAME_CHAR_MINBPC +#undef IS_NMSTRT_CHAR +#undef IS_NMSTRT_CHAR_MINBPC +#undef IS_INVALID_CHAR + +#endif /* not XML_MIN_SIZE */ + +#ifdef XML_NS + +static const struct normal_encoding little2_encoding_ns = { + { VTABLE, 2, 0, +#if XML_BYTE_ORDER == 12 + 1 +#else + 0 +#endif + }, + { +#include "asciitab.h" +#include "latin1tab.h" + }, + STANDARD_VTABLE(little2_) NULL_NORMAL_VTABLE +}; + +#endif + +static const struct normal_encoding little2_encoding = { + { VTABLE, 2, 0, +#if XML_BYTE_ORDER == 12 + 1 +#else + 0 +#endif + }, + { +#define BT_COLON BT_NMSTRT +#include "asciitab.h" +#undef BT_COLON +#include "latin1tab.h" + }, + STANDARD_VTABLE(little2_) NULL_NORMAL_VTABLE +}; + +#if XML_BYTE_ORDER != 21 + +#ifdef XML_NS + +static const struct normal_encoding internal_little2_encoding_ns = { + { VTABLE, 2, 0, 1 }, + { +#include "iasciitab.h" +#include "latin1tab.h" + }, + STANDARD_VTABLE(little2_) NULL_NORMAL_VTABLE +}; + +#endif + +static const struct normal_encoding internal_little2_encoding = { + { VTABLE, 2, 0, 1 }, + { +#define BT_COLON BT_NMSTRT +#include "iasciitab.h" +#undef BT_COLON +#include "latin1tab.h" + }, + STANDARD_VTABLE(little2_) NULL_NORMAL_VTABLE +}; + +#endif + + +#define BIG2_BYTE_TYPE(enc, p) \ + ((p)[0] == 0 \ + ? ((struct normal_encoding *)(enc))->type[(unsigned char)(p)[1]] \ + : unicode_byte_type((p)[0], (p)[1])) +#define BIG2_BYTE_TO_ASCII(enc, p) ((p)[0] == 0 ? (p)[1] : -1) +#define BIG2_CHAR_MATCHES(enc, p, c) ((p)[0] == 0 && (p)[1] == c) +#define BIG2_IS_NAME_CHAR_MINBPC(enc, p) \ + UCS2_GET_NAMING(namePages, (unsigned char)p[0], (unsigned char)p[1]) +#define BIG2_IS_NMSTRT_CHAR_MINBPC(enc, p) \ + UCS2_GET_NAMING(nmstrtPages, (unsigned char)p[0], (unsigned char)p[1]) + +#ifdef XML_MIN_SIZE + +static +int big2_byteType(const ENCODING *enc, const char *p) +{ + return BIG2_BYTE_TYPE(enc, p); +} + +static +int big2_byteToAscii(const ENCODING *enc, const char *p) +{ + return BIG2_BYTE_TO_ASCII(enc, p); +} + +static +int big2_charMatches(const ENCODING *enc, const char *p, int c) +{ + return BIG2_CHAR_MATCHES(enc, p, c); +} + +static +int big2_isNameMin(const ENCODING *enc, const char *p) +{ + return BIG2_IS_NAME_CHAR_MINBPC(enc, p); +} + +static +int big2_isNmstrtMin(const ENCODING *enc, const char *p) +{ + return BIG2_IS_NMSTRT_CHAR_MINBPC(enc, p); +} + +#undef VTABLE +#define VTABLE VTABLE1, big2_toUtf8, big2_toUtf16 + +#else /* not XML_MIN_SIZE */ + +#undef PREFIX +#define PREFIX(ident) big2_ ## ident +#define MINBPC(enc) 2 +/* CHAR_MATCHES is guaranteed to have MINBPC bytes available. */ +#define BYTE_TYPE(enc, p) BIG2_BYTE_TYPE(enc, p) +#define BYTE_TO_ASCII(enc, p) BIG2_BYTE_TO_ASCII(enc, p) +#define CHAR_MATCHES(enc, p, c) BIG2_CHAR_MATCHES(enc, p, c) +#define IS_NAME_CHAR(enc, p, n) 0 +#define IS_NAME_CHAR_MINBPC(enc, p) BIG2_IS_NAME_CHAR_MINBPC(enc, p) +#define IS_NMSTRT_CHAR(enc, p, n) (0) +#define IS_NMSTRT_CHAR_MINBPC(enc, p) BIG2_IS_NMSTRT_CHAR_MINBPC(enc, p) + +#include "xmltok_impl.c" + +#undef MINBPC +#undef BYTE_TYPE +#undef BYTE_TO_ASCII +#undef CHAR_MATCHES +#undef IS_NAME_CHAR +#undef IS_NAME_CHAR_MINBPC +#undef IS_NMSTRT_CHAR +#undef IS_NMSTRT_CHAR_MINBPC +#undef IS_INVALID_CHAR + +#endif /* not XML_MIN_SIZE */ + +#ifdef XML_NS + +static const struct normal_encoding big2_encoding_ns = { + { VTABLE, 2, 0, +#if XML_BYTE_ORDER == 21 + 1 +#else + 0 +#endif + }, + { +#include "asciitab.h" +#include "latin1tab.h" + }, + STANDARD_VTABLE(big2_) NULL_NORMAL_VTABLE +}; + +#endif + +static const struct normal_encoding big2_encoding = { + { VTABLE, 2, 0, +#if XML_BYTE_ORDER == 21 + 1 +#else + 0 +#endif + }, + { +#define BT_COLON BT_NMSTRT +#include "asciitab.h" +#undef BT_COLON +#include "latin1tab.h" + }, + STANDARD_VTABLE(big2_) NULL_NORMAL_VTABLE +}; + +#if XML_BYTE_ORDER != 12 + +#ifdef XML_NS + +static const struct normal_encoding internal_big2_encoding_ns = { + { VTABLE, 2, 0, 1 }, + { +#include "iasciitab.h" +#include "latin1tab.h" + }, + STANDARD_VTABLE(big2_) +}; + +#endif + +static const struct normal_encoding internal_big2_encoding = { + { VTABLE, 2, 0, 1 }, + { +#define BT_COLON BT_NMSTRT +#include "iasciitab.h" +#undef BT_COLON +#include "latin1tab.h" + }, + STANDARD_VTABLE(big2_) NULL_NORMAL_VTABLE +}; + +#endif + +#undef PREFIX + +static +int streqci(const char *s1, const char *s2) +{ + for (;;) { + char c1 = *s1++; + char c2 = *s2++; + if (ASCII_a <= c1 && c1 <= ASCII_z) + c1 += ASCII_A - ASCII_a; + if (ASCII_a <= c2 && c2 <= ASCII_z) + c2 += ASCII_A - ASCII_a; + if (c1 != c2) + return 0; + if (!c1) + break; + } + return 1; +} + +static +void initUpdatePosition(const ENCODING *enc ATTR_UNUSED, const char *ptr, + const char *end, POSITION *pos) +{ + normal_updatePosition(&utf8_encoding.enc, ptr, end, pos); +} + +static +int toAscii(const ENCODING *enc, const char *ptr, const char *end) +{ + char buf[1]; + char *p = buf; + XmlUtf8Convert(enc, &ptr, end, &p, p + 1); + if (p == buf) + return -1; + else + return buf[0]; +} + +static +int isSpace(int c) +{ + switch (c) { + case 0x20: + case 0xD: + case 0xA: + case 0x9: + return 1; + } + return 0; +} + +/* Return 1 if there's just optional white space +or there's an S followed by name=val. */ +static +int parsePseudoAttribute(const ENCODING *enc, + const char *ptr, + const char *end, + const char **namePtr, + const char **nameEndPtr, + const char **valPtr, + const char **nextTokPtr) +{ + int c; + char open; + if (ptr == end) { + *namePtr = 0; + return 1; + } + if (!isSpace(toAscii(enc, ptr, end))) { + *nextTokPtr = ptr; + return 0; + } + do { + ptr += enc->minBytesPerChar; + } while (isSpace(toAscii(enc, ptr, end))); + if (ptr == end) { + *namePtr = 0; + return 1; + } + *namePtr = ptr; + for (;;) { + c = toAscii(enc, ptr, end); + if (c == -1) { + *nextTokPtr = ptr; + return 0; + } + if (c == ASCII_EQUALS) { + *nameEndPtr = ptr; + break; + } + if (isSpace(c)) { + *nameEndPtr = ptr; + do { + ptr += enc->minBytesPerChar; + } while (isSpace(c = toAscii(enc, ptr, end))); + if (c != ASCII_EQUALS) { + *nextTokPtr = ptr; + return 0; + } + break; + } + ptr += enc->minBytesPerChar; + } + if (ptr == *namePtr) { + *nextTokPtr = ptr; + return 0; + } + ptr += enc->minBytesPerChar; + c = toAscii(enc, ptr, end); + while (isSpace(c)) { + ptr += enc->minBytesPerChar; + c = toAscii(enc, ptr, end); + } + if (c != ASCII_QUOT && c != ASCII_APOS) { + *nextTokPtr = ptr; + return 0; + } + open = c; + ptr += enc->minBytesPerChar; + *valPtr = ptr; + for (;; ptr += enc->minBytesPerChar) { + c = toAscii(enc, ptr, end); + if (c == open) + break; + if (!(ASCII_a <= c && c <= ASCII_z) + && !(ASCII_A <= c && c <= ASCII_Z) + && !(ASCII_0 <= c && c <= ASCII_9) + && c != ASCII_PERIOD + && c != ASCII_MINUS + && c != ASCII_UNDERSCORE) { + *nextTokPtr = ptr; + return 0; + } + } + *nextTokPtr = ptr + enc->minBytesPerChar; + return 1; +} + +static const char KW_version[] = { + ASCII_v, ASCII_e, ASCII_r, ASCII_s, ASCII_i, ASCII_o, ASCII_n, '\0' +}; + +static const char KW_encoding[] = { + ASCII_e, ASCII_n, ASCII_c, ASCII_o, ASCII_d, ASCII_i, ASCII_n, ASCII_g, '\0' +}; + +static const char KW_standalone[] = { + ASCII_s, ASCII_t, ASCII_a, ASCII_n, ASCII_d, ASCII_a, ASCII_l, ASCII_o, ASCII_n, ASCII_e, '\0' +}; + +static const char KW_yes[] = { + ASCII_y, ASCII_e, ASCII_s, '\0' +}; + +static const char KW_no[] = { + ASCII_n, ASCII_o, '\0' +}; + +static +int doParseXmlDecl(const ENCODING *(*encodingFinder)(const ENCODING *, + const char *, + const char *), + int isGeneralTextEntity, + const ENCODING *enc, + const char *ptr, + const char *end, + const char **badPtr, + const char **versionPtr, + const char **encodingName, + const ENCODING **encoding, + int *standalone) +{ + const char *val = 0; + const char *name = 0; + const char *nameEnd = 0; + ptr += 5 * enc->minBytesPerChar; + end -= 2 * enc->minBytesPerChar; + if (!parsePseudoAttribute(enc, ptr, end, &name, &nameEnd, &val, &ptr) || !name) { + *badPtr = ptr; + return 0; + } + if (!XmlNameMatchesAscii(enc, name, nameEnd, KW_version)) { + if (!isGeneralTextEntity) { + *badPtr = name; + return 0; + } + } + else { + if (versionPtr) + *versionPtr = val; + if (!parsePseudoAttribute(enc, ptr, end, &name, &nameEnd, &val, &ptr)) { + *badPtr = ptr; + return 0; + } + if (!name) { + if (isGeneralTextEntity) { + /* a TextDecl must have an EncodingDecl */ + *badPtr = ptr; + return 0; + } + return 1; + } + } + if (XmlNameMatchesAscii(enc, name, nameEnd, KW_encoding)) { + int c = toAscii(enc, val, end); + if (!(ASCII_a <= c && c <= ASCII_z) && !(ASCII_A <= c && c <= ASCII_Z)) { + *badPtr = val; + return 0; + } + if (encodingName) + *encodingName = val; + if (encoding) + *encoding = encodingFinder(enc, val, ptr - enc->minBytesPerChar); + if (!parsePseudoAttribute(enc, ptr, end, &name, &nameEnd, &val, &ptr)) { + *badPtr = ptr; + return 0; + } + if (!name) + return 1; + } + if (!XmlNameMatchesAscii(enc, name, nameEnd, KW_standalone) || isGeneralTextEntity) { + *badPtr = name; + return 0; + } + if (XmlNameMatchesAscii(enc, val, ptr - enc->minBytesPerChar, KW_yes)) { + if (standalone) + *standalone = 1; + } + else if (XmlNameMatchesAscii(enc, val, ptr - enc->minBytesPerChar, KW_no)) { + if (standalone) + *standalone = 0; + } + else { + *badPtr = val; + return 0; + } + while (isSpace(toAscii(enc, ptr, end))) + ptr += enc->minBytesPerChar; + if (ptr != end) { + *badPtr = ptr; + return 0; + } + return 1; +} + +static +int checkCharRefNumber(int result) +{ + switch (result >> 8) { + case 0xD8: case 0xD9: case 0xDA: case 0xDB: + case 0xDC: case 0xDD: case 0xDE: case 0xDF: + return -1; + case 0: + if (latin1_encoding.type[result] == BT_NONXML) + return -1; + break; + case 0xFF: + if (result == 0xFFFE || result == 0xFFFF) + return -1; + break; + } + return result; +} + +int xmlrpc_XmlUtf8Encode(int c, char *buf) +{ + enum { + /* minN is minimum legal resulting value for N byte sequence */ + min2 = 0x80, + min3 = 0x800, + min4 = 0x10000 + }; + + if (c < 0) + return 0; + if (c < min2) { + buf[0] = (c | UTF8_cval1); + return 1; + } + if (c < min3) { + buf[0] = ((c >> 6) | UTF8_cval2); + buf[1] = ((c & 0x3f) | 0x80); + return 2; + } + if (c < min4) { + buf[0] = ((c >> 12) | UTF8_cval3); + buf[1] = (((c >> 6) & 0x3f) | 0x80); + buf[2] = ((c & 0x3f) | 0x80); + return 3; + } + if (c < 0x110000) { + buf[0] = ((c >> 18) | UTF8_cval4); + buf[1] = (((c >> 12) & 0x3f) | 0x80); + buf[2] = (((c >> 6) & 0x3f) | 0x80); + buf[3] = ((c & 0x3f) | 0x80); + return 4; + } + return 0; +} + +int xmlrpc_XmlUtf16Encode(int charNum, unsigned short *buf) +{ + if (charNum < 0) + return 0; + if (charNum < 0x10000) { + buf[0] = charNum; + return 1; + } + if (charNum < 0x110000) { + charNum -= 0x10000; + buf[0] = (charNum >> 10) + 0xD800; + buf[1] = (charNum & 0x3FF) + 0xDC00; + return 2; + } + return 0; +} + +struct unknown_encoding { + struct normal_encoding normal; + int (*convert)(void *userData, const char *p); + void *userData; + unsigned short utf16[256]; + char utf8[256][4]; +}; + +int xmlrpc_XmlSizeOfUnknownEncoding(void) +{ + return sizeof(struct unknown_encoding); +} + +static +int unknown_isName(const ENCODING *enc, const char *p) +{ + int c = ((const struct unknown_encoding *)enc) + ->convert(((const struct unknown_encoding *)enc)->userData, p); + if (c & ~0xFFFF) + return 0; + return UCS2_GET_NAMING(namePages, c >> 8, c & 0xFF); +} + +static +int unknown_isNmstrt(const ENCODING *enc, const char *p) +{ + int c = ((const struct unknown_encoding *)enc) + ->convert(((const struct unknown_encoding *)enc)->userData, p); + if (c & ~0xFFFF) + return 0; + return UCS2_GET_NAMING(nmstrtPages, c >> 8, c & 0xFF); +} + +static +int unknown_isInvalid(const ENCODING *enc, const char *p) +{ + int c = ((const struct unknown_encoding *)enc) + ->convert(((const struct unknown_encoding *)enc)->userData, p); + return (c & ~0xFFFF) || checkCharRefNumber(c) < 0; +} + +static +void unknown_toUtf8(const ENCODING *enc, + const char **fromP, const char *fromLim, + char **toP, const char *toLim) +{ + char buf[XML_UTF8_ENCODE_MAX]; + for (;;) { + const char *utf8; + int n; + if (*fromP == fromLim) + break; + utf8 = ((const struct unknown_encoding *)enc)->utf8[(unsigned char)**fromP]; + n = *utf8++; + if (n == 0) { + int c = ((const struct unknown_encoding *)enc) + ->convert(((const struct unknown_encoding *)enc)->userData, *fromP); + n = xmlrpc_XmlUtf8Encode(c, buf); + if (n > toLim - *toP) + break; + utf8 = buf; + *fromP += ((const struct normal_encoding *)enc)->type[(unsigned char)**fromP] + - (BT_LEAD2 - 2); + } + else { + if (n > toLim - *toP) + break; + (*fromP)++; + } + do { + *(*toP)++ = *utf8++; + } while (--n != 0); + } +} + +static +void unknown_toUtf16(const ENCODING *enc, + const char **fromP, const char *fromLim, + unsigned short **toP, const unsigned short *toLim) +{ + while (*fromP != fromLim && *toP != toLim) { + unsigned short c + = ((const struct unknown_encoding *)enc)->utf16[(unsigned char)**fromP]; + if (c == 0) { + c = (unsigned short)((const struct unknown_encoding *)enc) + ->convert(((const struct unknown_encoding *)enc)->userData, *fromP); + *fromP += ((const struct normal_encoding *)enc)->type[(unsigned char)**fromP] + - (BT_LEAD2 - 2); + } + else + (*fromP)++; + *(*toP)++ = c; + } +} + +ENCODING * +xmlrpc_XmlInitUnknownEncoding(void *mem, + int *table, + int (*convert)(void *userData, const char *p), + void *userData) +{ + int i; + struct unknown_encoding *e = mem; + for (i = 0; i < (int)sizeof(struct normal_encoding); i++) + ((char *)mem)[i] = ((char *)&latin1_encoding)[i]; + for (i = 0; i < 128; i++) + if (latin1_encoding.type[i] != BT_OTHER + && latin1_encoding.type[i] != BT_NONXML + && table[i] != i) + return 0; + for (i = 0; i < 256; i++) { + int c = table[i]; + if (c == -1) { + e->normal.type[i] = BT_MALFORM; + /* This shouldn't really get used. */ + e->utf16[i] = 0xFFFF; + e->utf8[i][0] = 1; + e->utf8[i][1] = 0; + } + else if (c < 0) { + if (c < -4) + return 0; + e->normal.type[i] = BT_LEAD2 - (c + 2); + e->utf8[i][0] = 0; + e->utf16[i] = 0; + } + else if (c < 0x80) { + if (latin1_encoding.type[c] != BT_OTHER + && latin1_encoding.type[c] != BT_NONXML + && c != i) + return 0; + e->normal.type[i] = latin1_encoding.type[c]; + e->utf8[i][0] = 1; + e->utf8[i][1] = (char)c; + e->utf16[i] = c == 0 ? 0xFFFF : c; + } + else if (checkCharRefNumber(c) < 0) { + e->normal.type[i] = BT_NONXML; + /* This shouldn't really get used. */ + e->utf16[i] = 0xFFFF; + e->utf8[i][0] = 1; + e->utf8[i][1] = 0; + } + else { + if (c > 0xFFFF) + return 0; + if (UCS2_GET_NAMING(nmstrtPages, c >> 8, c & 0xff)) + e->normal.type[i] = BT_NMSTRT; + else if (UCS2_GET_NAMING(namePages, c >> 8, c & 0xff)) + e->normal.type[i] = BT_NAME; + else + e->normal.type[i] = BT_OTHER; + e->utf8[i][0] = (char)xmlrpc_XmlUtf8Encode(c, e->utf8[i] + 1); + e->utf16[i] = c; + } + } + e->userData = userData; + e->convert = convert; + if (convert) { + e->normal.isName2 = unknown_isName; + e->normal.isName3 = unknown_isName; + e->normal.isName4 = unknown_isName; + e->normal.isNmstrt2 = unknown_isNmstrt; + e->normal.isNmstrt3 = unknown_isNmstrt; + e->normal.isNmstrt4 = unknown_isNmstrt; + e->normal.isInvalid2 = unknown_isInvalid; + e->normal.isInvalid3 = unknown_isInvalid; + e->normal.isInvalid4 = unknown_isInvalid; + } + e->normal.enc.utf8Convert = unknown_toUtf8; + e->normal.enc.utf16Convert = unknown_toUtf16; + return &(e->normal.enc); +} + +/* If this enumeration is changed, getEncodingIndex and encodings +must also be changed. */ +enum { + UNKNOWN_ENC = -1, + ISO_8859_1_ENC = 0, + US_ASCII_ENC, + UTF_8_ENC, + UTF_16_ENC, + UTF_16BE_ENC, + UTF_16LE_ENC, + /* must match encodingNames up to here */ + NO_ENC +}; + +static const char KW_ISO_8859_1[] = { + ASCII_I, ASCII_S, ASCII_O, ASCII_MINUS, ASCII_8, ASCII_8, ASCII_5, ASCII_9, ASCII_MINUS, ASCII_1, '\0' +}; +static const char KW_US_ASCII[] = { + ASCII_U, ASCII_S, ASCII_MINUS, ASCII_A, ASCII_S, ASCII_C, ASCII_I, ASCII_I, '\0' +}; +static const char KW_UTF_8[] = { + ASCII_U, ASCII_T, ASCII_F, ASCII_MINUS, ASCII_8, '\0' +}; +static const char KW_UTF_16[] = { + ASCII_U, ASCII_T, ASCII_F, ASCII_MINUS, ASCII_1, ASCII_6, '\0' +}; +static const char KW_UTF_16BE[] = { + ASCII_U, ASCII_T, ASCII_F, ASCII_MINUS, ASCII_1, ASCII_6, ASCII_B, ASCII_E, '\0' +}; +static const char KW_UTF_16LE[] = { + ASCII_U, ASCII_T, ASCII_F, ASCII_MINUS, ASCII_1, ASCII_6, ASCII_L, ASCII_E, '\0' +}; + +static +int getEncodingIndex(const char *name) +{ + static const char *encodingNames[] = { + KW_ISO_8859_1, + KW_US_ASCII, + KW_UTF_8, + KW_UTF_16, + KW_UTF_16BE, + KW_UTF_16LE, + }; + int i; + if (name == 0) + return NO_ENC; + for (i = 0; i < (int)(sizeof(encodingNames)/sizeof(encodingNames[0])); i++) + if (streqci(name, encodingNames[i])) + return i; + return UNKNOWN_ENC; +} + +/* For binary compatibility, we store the index of the encoding specified +at initialization in the isUtf16 member. */ + +#define INIT_ENC_INDEX(enc) ((int)(enc)->initEnc.isUtf16) +#define SET_INIT_ENC_INDEX(enc, i) ((enc)->initEnc.isUtf16 = (char)i) + +/* This is what detects the encoding. +encodingTable maps from encoding indices to encodings; +INIT_ENC_INDEX(enc) is the index of the external (protocol) specified encoding; +state is XML_CONTENT_STATE if we're parsing an external text entity, +and XML_PROLOG_STATE otherwise. +*/ + + +static +int initScan(const ENCODING **encodingTable, + const INIT_ENCODING *enc, + int state, + const char *ptr, + const char *end, + const char **nextTokPtr) +{ + const ENCODING **encPtr; + + if (ptr == end) + return XML_TOK_NONE; + encPtr = enc->encPtr; + if (ptr + 1 == end) { + /* only a single byte available for auto-detection */ +#ifndef XML_DTD /* FIXME */ + /* a well-formed document entity must have more than one byte */ + if (state != XML_CONTENT_STATE) + return XML_TOK_PARTIAL; +#endif + /* so we're parsing an external text entity... */ + /* if UTF-16 was externally specified, then we need at least 2 bytes */ + switch (INIT_ENC_INDEX(enc)) { + case UTF_16_ENC: + case UTF_16LE_ENC: + case UTF_16BE_ENC: + return XML_TOK_PARTIAL; + } + switch ((unsigned char)*ptr) { + case 0xFE: + case 0xFF: + case 0xEF: /* possibly first byte of UTF-8 BOM */ + if (INIT_ENC_INDEX(enc) == ISO_8859_1_ENC + && state == XML_CONTENT_STATE) + break; + /* fall through */ + case 0x00: + case 0x3C: + return XML_TOK_PARTIAL; + } + } + else { + switch (((unsigned char)ptr[0] << 8) | (unsigned char)ptr[1]) { + case 0xFEFF: + if (INIT_ENC_INDEX(enc) == ISO_8859_1_ENC + && state == XML_CONTENT_STATE) + break; + *nextTokPtr = ptr + 2; + *encPtr = encodingTable[UTF_16BE_ENC]; + return XML_TOK_BOM; + /* 00 3C is handled in the default case */ + case 0x3C00: + if ((INIT_ENC_INDEX(enc) == UTF_16BE_ENC + || INIT_ENC_INDEX(enc) == UTF_16_ENC) + && state == XML_CONTENT_STATE) + break; + *encPtr = encodingTable[UTF_16LE_ENC]; + return XmlTok(*encPtr, state, ptr, end, nextTokPtr); + case 0xFFFE: + if (INIT_ENC_INDEX(enc) == ISO_8859_1_ENC + && state == XML_CONTENT_STATE) + break; + *nextTokPtr = ptr + 2; + *encPtr = encodingTable[UTF_16LE_ENC]; + return XML_TOK_BOM; + case 0xEFBB: + /* Maybe a UTF-8 BOM (EF BB BF) */ + /* If there's an explicitly specified (external) encoding + of ISO-8859-1 or some flavour of UTF-16 + and this is an external text entity, + don't look for the BOM, + because it might be a legal data. */ + if (state == XML_CONTENT_STATE) { + int e = INIT_ENC_INDEX(enc); + if (e == ISO_8859_1_ENC || e == UTF_16BE_ENC || e == UTF_16LE_ENC || e == UTF_16_ENC) + break; + } + if (ptr + 2 == end) + return XML_TOK_PARTIAL; + if ((unsigned char)ptr[2] == 0xBF) { + *encPtr = encodingTable[UTF_8_ENC]; + return XML_TOK_BOM; + } + break; + default: + if (ptr[0] == '\0') { + /* 0 isn't a legal data character. Furthermore a document entity can only + start with ASCII characters. So the only way this can fail to be big-endian + UTF-16 if it it's an external parsed general entity that's labelled as + UTF-16LE. */ + if (state == XML_CONTENT_STATE && INIT_ENC_INDEX(enc) == UTF_16LE_ENC) + break; + *encPtr = encodingTable[UTF_16BE_ENC]; + return XmlTok(*encPtr, state, ptr, end, nextTokPtr); + } + else if (ptr[1] == '\0') { + /* We could recover here in the case: + - parsing an external entity + - second byte is 0 + - no externally specified encoding + - no encoding declaration + by assuming UTF-16LE. But we don't, because this would mean when + presented just with a single byte, we couldn't reliably determine + whether we needed further bytes. */ + if (state == XML_CONTENT_STATE) + break; + *encPtr = encodingTable[UTF_16LE_ENC]; + return XmlTok(*encPtr, state, ptr, end, nextTokPtr); + } + break; + } + } + *encPtr = encodingTable[INIT_ENC_INDEX(enc)]; + return XmlTok(*encPtr, state, ptr, end, nextTokPtr); +} + + +#define NS(x) x +#define ns(x) x +#include "xmltok_ns.c" +#undef NS +#undef ns + +#ifdef XML_NS + +#define NS(x) x ## NS +#define ns(x) x ## _ns + +#include "xmltok_ns.c" + +#undef NS +#undef ns + +ENCODING * +xmlrpc_XmlInitUnknownEncodingNS(void *mem, + int *table, + int (*convert)(void *userData, const char *p), + void *userData) +{ + ENCODING *enc = xmlrpc_XmlInitUnknownEncoding(mem, table, convert, userData); + if (enc) + ((struct normal_encoding *)enc)->type[ASCII_COLON] = BT_COLON; + return enc; +} + +#endif /* XML_NS */ diff --git a/lib/expat/xmltok/xmltok.dsp b/lib/expat/xmltok/xmltok.dsp new file mode 100644 index 0000000..58a70ef --- /dev/null +++ b/lib/expat/xmltok/xmltok.dsp @@ -0,0 +1,259 @@ +# Microsoft Developer Studio Project File - Name="xmltok" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102 +# TARGTYPE "Win32 (x86) Static Library" 0x0104 + +CFG=xmltok - Win32 Release +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "xmltok.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "xmltok.mak" CFG="xmltok - Win32 Release" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "xmltok - Win32 Release" (based on "Win32 (x86) Static Library") +!MESSAGE "xmltok - Win32 Debug" (based on "Win32 (x86) Static Library") +!MESSAGE "xmltok - Win32 Release DLL" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE "xmltok - Win32 Debug DLL" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "xmltok" +# PROP Scc_LocalPath ".." + +!IF "$(CFG)" == "xmltok - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir ".\Release" +# PROP BASE Intermediate_Dir ".\Release" +# PROP BASE Target_Dir "." +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release\xmltok" +# PROP Intermediate_Dir "Release\xmltok" +# PROP Target_Dir "." +LINK32=link.exe -lib +MTL=midl.exe +CPP=cl.exe +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_LIB" /YX /FD /c +# ADD CPP /nologo /MT /W3 /GX /O2 /I "..\..\.." /D "NDEBUG" /D "XML_NS" /D XMLTOKAPI=__declspec(dllexport) /D "WIN32" /D "_WINDOWS" /D "XML_DTD" /D "_MBCS" /D "_LIB" /YX /FD /c +RSC=rc.exe +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo + +!ELSEIF "$(CFG)" == "xmltok - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir ".\Debug" +# PROP BASE Intermediate_Dir ".\Debug" +# PROP BASE Target_Dir "." +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug\xmltok" +# PROP Intermediate_Dir "Debug\xmltok" +# PROP Target_Dir "." +LINK32=link.exe -lib +MTL=midl.exe +CPP=cl.exe +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c +# ADD CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /I "..\..\.." /D "_DEBUG" /D XMLTOKAPI=__declspec(dllexport) /D "WIN32" /D "_WINDOWS" /D "XML_DTD" /D "XML_NS" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c +RSC=rc.exe +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo + +!ELSEIF "$(CFG)" == "xmltok - Win32 Release DLL" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir ".\ReleaseDLL" +# PROP BASE Intermediate_Dir ".\ReleaseDLL" +# PROP BASE Target_Dir "." +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "ReleaseDLL\xmltok" +# PROP Intermediate_Dir "ReleaseDLL\xmltok" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "." +CPP=cl.exe +# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /c +# ADD CPP /nologo /MT /W3 /GX /O2 /I "..\..\.." /D "NDEBUG" /D "XML_NS" /D XMLTOKAPI=__declspec(dllexport) /D "WIN32" /D "_WINDOWS" /D "XML_DTD" /YX /FD /c +MTL=midl.exe +# ADD BASE MTL /nologo /D "NDEBUG" /win32 +# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +RSC=rc.exe +# ADD BASE RSC /l 0x809 /d "NDEBUG" +# ADD RSC /l 0x809 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /dll /machine:I386 +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /entry:"DllMain" /subsystem:windows /dll /machine:I386 /out:"..\..\xmltok.dll" /link50compat +# SUBTRACT LINK32 /pdb:none + +!ELSEIF "$(CFG)" == "xmltok - Win32 Debug DLL" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir ".\DebugDLL" +# PROP BASE Intermediate_Dir ".\DebugDLL" +# PROP BASE Target_Dir "." +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "DebugDLL\xmltok" +# PROP Intermediate_Dir "DebugDLL\xmltok" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "." +CPP=cl.exe +# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /YX /c +# ADD CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /I "..\..\.." /D "_DEBUG" /D XMLTOKAPI=__declspec(dllexport) /D "WIN32" /D "_WINDOWS" /D "XML_DTD" /D "XML_NS" /YX /FD /c +MTL=midl.exe +# ADD BASE MTL /nologo /D "_DEBUG" /win32 +# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +RSC=rc.exe +# ADD BASE RSC /l 0x809 /d "_DEBUG" +# ADD RSC /l 0x809 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /dll /debug /machine:I386 +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /dll /debug /machine:I386 /out:"..\..\xmltokD.dll" + +!ENDIF + +# Begin Target + +# Name "xmltok - Win32 Release" +# Name "xmltok - Win32 Debug" +# Name "xmltok - Win32 Release DLL" +# Name "xmltok - Win32 Debug DLL" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat;for;f90" +# Begin Source File + +SOURCE=.\dllmain.c + +!IF "$(CFG)" == "xmltok - Win32 Release" + +# PROP Exclude_From_Build 1 + +!ELSEIF "$(CFG)" == "xmltok - Win32 Debug" + +# PROP Exclude_From_Build 1 + +!ELSEIF "$(CFG)" == "xmltok - Win32 Release DLL" + +!ELSEIF "$(CFG)" == "xmltok - Win32 Debug DLL" + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\gennmtab\gennmtab.c + +!IF "$(CFG)" == "xmltok - Win32 Release" + +# PROP Ignore_Default_Tool 1 + +!ELSEIF "$(CFG)" == "xmltok - Win32 Debug" + +# PROP Ignore_Default_Tool 1 + +!ELSEIF "$(CFG)" == "xmltok - Win32 Release DLL" + +!ELSEIF "$(CFG)" == "xmltok - Win32 Debug DLL" + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=.\xmlrole.c +# End Source File +# Begin Source File + +SOURCE=.\xmltok.c +# End Source File +# Begin Source File + +SOURCE=.\xmltok_impl.c +# PROP BASE Exclude_From_Build 1 +# PROP Exclude_From_Build 1 +# End Source File +# Begin Source File + +SOURCE=.\xmltok_ns.c +# PROP Exclude_From_Build 1 +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl;fi;fd" +# Begin Source File + +SOURCE=.\asciitab.h +# End Source File +# Begin Source File + +SOURCE=.\iasciitab.h +# End Source File +# Begin Source File + +SOURCE=.\latin1tab.h +# End Source File +# Begin Source File + +SOURCE=.\nametab.h +# End Source File +# Begin Source File + +SOURCE=.\utf8tab.h +# End Source File +# Begin Source File + +SOURCE=.\xmldef.h +# End Source File +# Begin Source File + +SOURCE=.\xmlrole.h +# End Source File +# Begin Source File + +SOURCE=.\xmltok.h +# End Source File +# Begin Source File + +SOURCE=.\xmltok_impl.h +# End Source File +# End Group +# Begin Group "Resource Files" + +# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;cnt;rtf;gif;jpg;jpeg;jpe" +# End Group +# End Target +# End Project diff --git a/lib/expat/xmltok/xmltok.h b/lib/expat/xmltok/xmltok.h new file mode 100644 index 0000000..a5b4cef --- /dev/null +++ b/lib/expat/xmltok/xmltok.h @@ -0,0 +1,327 @@ +/* +Copyright (c) 1998, 1999 Thai Open Source Software Center Ltd +See the file copying.txt for copying permission. +*/ + +#ifndef XmlTok_INCLUDED +#define XmlTok_INCLUDED 1 + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef XMLTOKAPI +#define XMLTOKAPI /* as nothing */ +#endif + +/* The following token may be returned by XmlContentTok */ +#define XML_TOK_TRAILING_RSQB -5 /* ] or ]] at the end of the scan; might be start of + illegal ]]> sequence */ +/* The following tokens may be returned by both XmlPrologTok and XmlContentTok */ +#define XML_TOK_NONE -4 /* The string to be scanned is empty */ +#define XML_TOK_TRAILING_CR -3 /* A CR at the end of the scan; + might be part of CRLF sequence */ +#define XML_TOK_PARTIAL_CHAR -2 /* only part of a multibyte sequence */ +#define XML_TOK_PARTIAL -1 /* only part of a token */ +#define XML_TOK_INVALID 0 + +/* The following tokens are returned by XmlContentTok; some are also + returned by XmlAttributeValueTok, XmlEntityTok, XmlCdataSectionTok */ + +#define XML_TOK_START_TAG_WITH_ATTS 1 +#define XML_TOK_START_TAG_NO_ATTS 2 +#define XML_TOK_EMPTY_ELEMENT_WITH_ATTS 3 /* empty element tag */ +#define XML_TOK_EMPTY_ELEMENT_NO_ATTS 4 +#define XML_TOK_END_TAG 5 +#define XML_TOK_DATA_CHARS 6 +#define XML_TOK_DATA_NEWLINE 7 +#define XML_TOK_CDATA_SECT_OPEN 8 +#define XML_TOK_ENTITY_REF 9 +#define XML_TOK_CHAR_REF 10 /* numeric character reference */ + +/* The following tokens may be returned by both XmlPrologTok and XmlContentTok */ +#define XML_TOK_PI 11 /* processing instruction */ +#define XML_TOK_XML_DECL 12 /* XML decl or text decl */ +#define XML_TOK_COMMENT 13 +#define XML_TOK_BOM 14 /* Byte order mark */ + +/* The following tokens are returned only by XmlPrologTok */ +#define XML_TOK_PROLOG_S 15 +#define XML_TOK_DECL_OPEN 16 /* */ +#define XML_TOK_NAME 18 +#define XML_TOK_NMTOKEN 19 +#define XML_TOK_POUND_NAME 20 /* #name */ +#define XML_TOK_OR 21 /* | */ +#define XML_TOK_PERCENT 22 +#define XML_TOK_OPEN_PAREN 23 +#define XML_TOK_CLOSE_PAREN 24 +#define XML_TOK_OPEN_BRACKET 25 +#define XML_TOK_CLOSE_BRACKET 26 +#define XML_TOK_LITERAL 27 +#define XML_TOK_PARAM_ENTITY_REF 28 +#define XML_TOK_INSTANCE_START 29 + +/* The following occur only in element type declarations */ +#define XML_TOK_NAME_QUESTION 30 /* name? */ +#define XML_TOK_NAME_ASTERISK 31 /* name* */ +#define XML_TOK_NAME_PLUS 32 /* name+ */ +#define XML_TOK_COND_SECT_OPEN 33 /* */ +#define XML_TOK_CLOSE_PAREN_QUESTION 35 /* )? */ +#define XML_TOK_CLOSE_PAREN_ASTERISK 36 /* )* */ +#define XML_TOK_CLOSE_PAREN_PLUS 37 /* )+ */ +#define XML_TOK_COMMA 38 + +/* The following token is returned only by XmlAttributeValueTok */ +#define XML_TOK_ATTRIBUTE_VALUE_S 39 + +/* The following token is returned only by XmlCdataSectionTok */ +#define XML_TOK_CDATA_SECT_CLOSE 40 + +/* With namespace processing this is returned by XmlPrologTok + for a name with a colon. */ +#define XML_TOK_PREFIXED_NAME 41 + +#ifdef XML_DTD +#define XML_TOK_IGNORE_SECT 42 +#endif /* XML_DTD */ + +#ifdef XML_DTD +#define XML_N_STATES 4 +#else /* not XML_DTD */ +#define XML_N_STATES 3 +#endif /* not XML_DTD */ + +#define XML_PROLOG_STATE 0 +#define XML_CONTENT_STATE 1 +#define XML_CDATA_SECTION_STATE 2 +#ifdef XML_DTD +#define XML_IGNORE_SECTION_STATE 3 +#endif /* XML_DTD */ + +#define XML_N_LITERAL_TYPES 2 +#define XML_ATTRIBUTE_VALUE_LITERAL 0 +#define XML_ENTITY_VALUE_LITERAL 1 + +/* The size of the buffer passed to XmlUtf8Encode must be at least this. */ +#define XML_UTF8_ENCODE_MAX 4 +/* The size of the buffer passed to XmlUtf16Encode must be at least this. */ +#define XML_UTF16_ENCODE_MAX 2 + +typedef struct position { + /* first line and first column are 0 not 1 */ + unsigned long lineNumber; + unsigned long columnNumber; +} POSITION; + +typedef struct { + const char *name; + const char *valuePtr; + const char *valueEnd; + char normalized; +} ATTRIBUTE; + +struct encoding; +typedef struct encoding ENCODING; + +struct encoding { + int (*scanners[XML_N_STATES])(const ENCODING *, + const char *, + const char *, + const char **); + int (*literalScanners[XML_N_LITERAL_TYPES])(const ENCODING *, + const char *, + const char *, + const char **); + int (*sameName)(const ENCODING *, + const char *, const char *); + int (*nameMatchesAscii)(const ENCODING *, + const char *, const char *, const char *); + int (*nameLength)(const ENCODING *, const char *); + const char *(*skipS)(const ENCODING *, const char *); + int (*getAtts)(const ENCODING *enc, const char *ptr, + int attsMax, ATTRIBUTE *atts); + int (*charRefNumber)(const ENCODING *enc, const char *ptr); + int (*predefinedEntityName)(const ENCODING *, const char *, const char *); + void (*updatePosition)(const ENCODING *, + const char *ptr, + const char *end, + POSITION *); + int (*isPublicId)(const ENCODING *enc, const char *ptr, const char *end, + const char **badPtr); + void (*utf8Convert)(const ENCODING *enc, + const char **fromP, + const char *fromLim, + char **toP, + const char *toLim); + void (*utf16Convert)(const ENCODING *enc, + const char **fromP, + const char *fromLim, + unsigned short **toP, + const unsigned short *toLim); + int minBytesPerChar; + char isUtf8; + char isUtf16; +}; + +/* +Scan the string starting at ptr until the end of the next complete token, +but do not scan past eptr. Return an integer giving the type of token. + +Return XML_TOK_NONE when ptr == eptr; nextTokPtr will not be set. + +Return XML_TOK_PARTIAL when the string does not contain a complete token; +nextTokPtr will not be set. + +Return XML_TOK_INVALID when the string does not start a valid token; nextTokPtr +will be set to point to the character which made the token invalid. + +Otherwise the string starts with a valid token; nextTokPtr will be set to point +to the character following the end of that token. + +Each data character counts as a single token, but adjacent data characters +may be returned together. Similarly for characters in the prolog outside +literals, comments and processing instructions. +*/ + + +#define XmlTok(enc, state, ptr, end, nextTokPtr) \ + (((enc)->scanners[state])(enc, ptr, end, nextTokPtr)) + +#define XmlPrologTok(enc, ptr, end, nextTokPtr) \ + XmlTok(enc, XML_PROLOG_STATE, ptr, end, nextTokPtr) + +#define XmlContentTok(enc, ptr, end, nextTokPtr) \ + XmlTok(enc, XML_CONTENT_STATE, ptr, end, nextTokPtr) + +#define XmlCdataSectionTok(enc, ptr, end, nextTokPtr) \ + XmlTok(enc, XML_CDATA_SECTION_STATE, ptr, end, nextTokPtr) + +#ifdef XML_DTD + +#define XmlIgnoreSectionTok(enc, ptr, end, nextTokPtr) \ + XmlTok(enc, XML_IGNORE_SECTION_STATE, ptr, end, nextTokPtr) + +#endif /* XML_DTD */ + +/* This is used for performing a 2nd-level tokenization on +the content of a literal that has already been returned by XmlTok. */ + +#define XmlLiteralTok(enc, literalType, ptr, end, nextTokPtr) \ + (((enc)->literalScanners[literalType])(enc, ptr, end, nextTokPtr)) + +#define XmlAttributeValueTok(enc, ptr, end, nextTokPtr) \ + XmlLiteralTok(enc, XML_ATTRIBUTE_VALUE_LITERAL, ptr, end, nextTokPtr) + +#define XmlEntityValueTok(enc, ptr, end, nextTokPtr) \ + XmlLiteralTok(enc, XML_ENTITY_VALUE_LITERAL, ptr, end, nextTokPtr) + +#define XmlSameName(enc, ptr1, ptr2) (((enc)->sameName)(enc, ptr1, ptr2)) + +#define XmlNameMatchesAscii(enc, ptr1, end1, ptr2) \ + (((enc)->nameMatchesAscii)(enc, ptr1, end1, ptr2)) + +#define XmlNameLength(enc, ptr) \ + (((enc)->nameLength)(enc, ptr)) + +#define XmlSkipS(enc, ptr) \ + (((enc)->skipS)(enc, ptr)) + +#define XmlGetAttributes(enc, ptr, attsMax, atts) \ + (((enc)->getAtts)(enc, ptr, attsMax, atts)) + +#define XmlCharRefNumber(enc, ptr) \ + (((enc)->charRefNumber)(enc, ptr)) + +#define XmlPredefinedEntityName(enc, ptr, end) \ + (((enc)->predefinedEntityName)(enc, ptr, end)) + +#define XmlUpdatePosition(enc, ptr, end, pos) \ + (((enc)->updatePosition)(enc, ptr, end, pos)) + +#define XmlIsPublicId(enc, ptr, end, badPtr) \ + (((enc)->isPublicId)(enc, ptr, end, badPtr)) + +#define XmlUtf8Convert(enc, fromP, fromLim, toP, toLim) \ + (((enc)->utf8Convert)(enc, fromP, fromLim, toP, toLim)) + +#define XmlUtf16Convert(enc, fromP, fromLim, toP, toLim) \ + (((enc)->utf16Convert)(enc, fromP, fromLim, toP, toLim)) + +typedef struct { + ENCODING initEnc; + const ENCODING **encPtr; +} INIT_ENCODING; + +int XMLTOKAPI +xmlrpc_XmlParseXmlDecl(int isGeneralTextEntity, + const ENCODING * enc, + const char * ptr, + const char * end, + const char ** badPtr, + const char ** versionPtr, + const char ** encodingNamePtr, + const ENCODING ** namedEncodingPtr, + int * standalonePtr); + +int +XMLTOKAPI +xmlrpc_XmlInitEncoding(INIT_ENCODING *, + const ENCODING **, + const char * name); + +const ENCODING XMLTOKAPI * +xmlrpc_XmlGetUtf8InternalEncoding(void); + +const ENCODING XMLTOKAPI * +xmlrpc_XmlGetUtf16InternalEncoding(void); + +int XMLTOKAPI +xmlrpc_XmlUtf8Encode(int charNumber, char *buf); + +int XMLTOKAPI +xmlrpc_XmlUtf16Encode(int charNumber, + unsigned short * buf); + +int XMLTOKAPI +xmlrpc_XmlSizeOfUnknownEncoding(void); + +ENCODING XMLTOKAPI * +xmlrpc_XmlInitUnknownEncoding(void * mem, + int * table, + int (* conv)(void * userData, const char * p), + void * userData); + +int XMLTOKAPI +xmlrpc_XmlParseXmlDeclNS(int isGeneralTextEntity, + const ENCODING * enc, + const char * ptr, + const char * end, + const char ** badPtr, + const char ** versionPtr, + const char ** encodingNamePtr, + const ENCODING ** namedEncodingPtr, + int * standalonePtr); + +int XMLTOKAPI +xmlrpc_XmlInitEncodingNS(INIT_ENCODING *, + const ENCODING **, + const char * name); + +const ENCODING XMLTOKAPI * +xmlrpc_XmlGetUtf8InternalEncodingNS(void); + +const ENCODING XMLTOKAPI * +xmlrpc_XmlGetUtf16InternalEncodingNS(void); + +ENCODING XMLTOKAPI * +xmlrpc_XmlInitUnknownEncodingNS(void * mem, + int * table, + int (* conv)(void * userData, const char * p), + void * userData); +#ifdef __cplusplus +} +#endif + +#endif /* not XmlTok_INCLUDED */ diff --git a/lib/expat/xmltok/xmltok_impl.c b/lib/expat/xmltok/xmltok_impl.c new file mode 100644 index 0000000..0ebb945 --- /dev/null +++ b/lib/expat/xmltok/xmltok_impl.c @@ -0,0 +1,1774 @@ +/* +Copyright (c) 1998, 1999 Thai Open Source Software Center Ltd +See the file copying.txt for copying permission. +*/ + +#ifndef IS_INVALID_CHAR +#define IS_INVALID_CHAR(enc, ptr, n) (0) +#endif + +#define INVALID_LEAD_CASE(n, ptr, nextTokPtr) \ + case BT_LEAD ## n: \ + if (end - ptr < n) \ + return XML_TOK_PARTIAL_CHAR; \ + if (IS_INVALID_CHAR(enc, ptr, n)) { \ + *(nextTokPtr) = (ptr); \ + return XML_TOK_INVALID; \ + } \ + ptr += n; \ + break; + +#define INVALID_CASES(ptr, nextTokPtr) \ + INVALID_LEAD_CASE(2, ptr, nextTokPtr) \ + INVALID_LEAD_CASE(3, ptr, nextTokPtr) \ + INVALID_LEAD_CASE(4, ptr, nextTokPtr) \ + case BT_NONXML: \ + case BT_MALFORM: \ + case BT_TRAIL: \ + *(nextTokPtr) = (ptr); \ + return XML_TOK_INVALID; + +#define CHECK_NAME_CASE(n, enc, ptr, end, nextTokPtr) \ + case BT_LEAD ## n: \ + if (end - ptr < n) \ + return XML_TOK_PARTIAL_CHAR; \ + if (!IS_NAME_CHAR(enc, ptr, n)) { \ + *nextTokPtr = ptr; \ + return XML_TOK_INVALID; \ + } \ + ptr += n; \ + break; + +#define CHECK_NAME_CASES(enc, ptr, end, nextTokPtr) \ + case BT_NONASCII: \ + if (!IS_NAME_CHAR_MINBPC(enc, ptr)) { \ + *nextTokPtr = ptr; \ + return XML_TOK_INVALID; \ + } \ + case BT_NMSTRT: \ + case BT_HEX: \ + case BT_DIGIT: \ + case BT_NAME: \ + case BT_MINUS: \ + ptr += MINBPC(enc); \ + break; \ + CHECK_NAME_CASE(2, enc, ptr, end, nextTokPtr) \ + CHECK_NAME_CASE(3, enc, ptr, end, nextTokPtr) \ + CHECK_NAME_CASE(4, enc, ptr, end, nextTokPtr) + +#define CHECK_NMSTRT_CASE(n, enc, ptr, end, nextTokPtr) \ + case BT_LEAD ## n: \ + if (end - ptr < n) \ + return XML_TOK_PARTIAL_CHAR; \ + if (!IS_NMSTRT_CHAR(enc, ptr, n)) { \ + *nextTokPtr = ptr; \ + return XML_TOK_INVALID; \ + } \ + ptr += n; \ + break; + +#define CHECK_NMSTRT_CASES(enc, ptr, end, nextTokPtr) \ + case BT_NONASCII: \ + if (!IS_NMSTRT_CHAR_MINBPC(enc, ptr)) { \ + *nextTokPtr = ptr; \ + return XML_TOK_INVALID; \ + } \ + case BT_NMSTRT: \ + case BT_HEX: \ + ptr += MINBPC(enc); \ + break; \ + CHECK_NMSTRT_CASE(2, enc, ptr, end, nextTokPtr) \ + CHECK_NMSTRT_CASE(3, enc, ptr, end, nextTokPtr) \ + CHECK_NMSTRT_CASE(4, enc, ptr, end, nextTokPtr) + +#ifndef PREFIX +#define PREFIX(ident) ident +#endif + +/* ptr points to character following " */ + switch (BYTE_TYPE(enc, ptr + MINBPC(enc))) { + case BT_S: case BT_CR: case BT_LF: case BT_PERCNT: + *nextTokPtr = ptr; + return XML_TOK_INVALID; + } + /* fall through */ + case BT_S: case BT_CR: case BT_LF: + *nextTokPtr = ptr; + return XML_TOK_DECL_OPEN; + case BT_NMSTRT: + case BT_HEX: + ptr += MINBPC(enc); + break; + default: + *nextTokPtr = ptr; + return XML_TOK_INVALID; + } + } + return XML_TOK_PARTIAL; +} + +static +int PREFIX(checkPiTarget)(const ENCODING * enc ATTR_UNUSED, + const char * ptr, + const char * end, + int * tokPtr) +{ + int upper = 0; + *tokPtr = XML_TOK_PI; + if (end - ptr != MINBPC(enc)*3) + return 1; + switch (BYTE_TO_ASCII(enc, ptr)) { + case ASCII_x: + break; + case ASCII_X: + upper = 1; + break; + default: + return 1; + } + ptr += MINBPC(enc); + switch (BYTE_TO_ASCII(enc, ptr)) { + case ASCII_m: + break; + case ASCII_M: + upper = 1; + break; + default: + return 1; + } + ptr += MINBPC(enc); + switch (BYTE_TO_ASCII(enc, ptr)) { + case ASCII_l: + break; + case ASCII_L: + upper = 1; + break; + default: + return 1; + } + if (upper) + return 0; + *tokPtr = XML_TOK_XML_DECL; + return 1; +} + +/* ptr points to character following " 1) { + size_t n = end - ptr; + if (n & (MINBPC(enc) - 1)) { + n &= ~(MINBPC(enc) - 1); + if (n == 0) + return XML_TOK_PARTIAL; + end = ptr + n; + } + } + switch (BYTE_TYPE(enc, ptr)) { + case BT_RSQB: + ptr += MINBPC(enc); + if (ptr == end) + return XML_TOK_PARTIAL; + if (!CHAR_MATCHES(enc, ptr, ASCII_RSQB)) + break; + ptr += MINBPC(enc); + if (ptr == end) + return XML_TOK_PARTIAL; + if (!CHAR_MATCHES(enc, ptr, ASCII_GT)) { + ptr -= MINBPC(enc); + break; + } + *nextTokPtr = ptr + MINBPC(enc); + return XML_TOK_CDATA_SECT_CLOSE; + case BT_CR: + ptr += MINBPC(enc); + if (ptr == end) + return XML_TOK_PARTIAL; + if (BYTE_TYPE(enc, ptr) == BT_LF) + ptr += MINBPC(enc); + *nextTokPtr = ptr; + return XML_TOK_DATA_NEWLINE; + case BT_LF: + *nextTokPtr = ptr + MINBPC(enc); + return XML_TOK_DATA_NEWLINE; + INVALID_CASES(ptr, nextTokPtr) + default: + ptr += MINBPC(enc); + break; + } + while (ptr != end) { + switch (BYTE_TYPE(enc, ptr)) { +#define LEAD_CASE(n) \ + case BT_LEAD ## n: \ + if (end - ptr < n || IS_INVALID_CHAR(enc, ptr, n)) { \ + *nextTokPtr = ptr; \ + return XML_TOK_DATA_CHARS; \ + } \ + ptr += n; \ + break; + LEAD_CASE(2) LEAD_CASE(3) LEAD_CASE(4) +#undef LEAD_CASE + case BT_NONXML: + case BT_MALFORM: + case BT_TRAIL: + case BT_CR: + case BT_LF: + case BT_RSQB: + *nextTokPtr = ptr; + return XML_TOK_DATA_CHARS; + default: + ptr += MINBPC(enc); + break; + } + } + *nextTokPtr = ptr; + return XML_TOK_DATA_CHARS; +} + +/* ptr points to character following " 1) { + size_t n = end - ptr; + if (n & (MINBPC(enc) - 1)) { + n &= ~(MINBPC(enc) - 1); + if (n == 0) + return XML_TOK_PARTIAL; + end = ptr + n; + } + } + switch (BYTE_TYPE(enc, ptr)) { + case BT_LT: + return PREFIX(scanLt)(enc, ptr + MINBPC(enc), end, nextTokPtr); + case BT_AMP: + return PREFIX(scanRef)(enc, ptr + MINBPC(enc), end, nextTokPtr); + case BT_CR: + ptr += MINBPC(enc); + if (ptr == end) + return XML_TOK_TRAILING_CR; + if (BYTE_TYPE(enc, ptr) == BT_LF) + ptr += MINBPC(enc); + *nextTokPtr = ptr; + return XML_TOK_DATA_NEWLINE; + case BT_LF: + *nextTokPtr = ptr + MINBPC(enc); + return XML_TOK_DATA_NEWLINE; + case BT_RSQB: + ptr += MINBPC(enc); + if (ptr == end) + return XML_TOK_TRAILING_RSQB; + if (!CHAR_MATCHES(enc, ptr, ASCII_RSQB)) + break; + ptr += MINBPC(enc); + if (ptr == end) + return XML_TOK_TRAILING_RSQB; + if (!CHAR_MATCHES(enc, ptr, ASCII_GT)) { + ptr -= MINBPC(enc); + break; + } + *nextTokPtr = ptr; + return XML_TOK_INVALID; + INVALID_CASES(ptr, nextTokPtr) + default: + ptr += MINBPC(enc); + break; + } + while (ptr != end) { + switch (BYTE_TYPE(enc, ptr)) { +#define LEAD_CASE(n) \ + case BT_LEAD ## n: \ + if (end - ptr < n || IS_INVALID_CHAR(enc, ptr, n)) { \ + *nextTokPtr = ptr; \ + return XML_TOK_DATA_CHARS; \ + } \ + ptr += n; \ + break; + LEAD_CASE(2) LEAD_CASE(3) LEAD_CASE(4) +#undef LEAD_CASE + case BT_RSQB: + if (ptr + MINBPC(enc) != end) { + if (!CHAR_MATCHES(enc, ptr + MINBPC(enc), ASCII_RSQB)) { + ptr += MINBPC(enc); + break; + } + if (ptr + 2*MINBPC(enc) != end) { + if (!CHAR_MATCHES(enc, ptr + 2*MINBPC(enc), ASCII_GT)) { + ptr += MINBPC(enc); + break; + } + *nextTokPtr = ptr + 2*MINBPC(enc); + return XML_TOK_INVALID; + } + } + /* fall through */ + case BT_AMP: + case BT_LT: + case BT_NONXML: + case BT_MALFORM: + case BT_TRAIL: + case BT_CR: + case BT_LF: + *nextTokPtr = ptr; + return XML_TOK_DATA_CHARS; + default: + ptr += MINBPC(enc); + break; + } + } + *nextTokPtr = ptr; + return XML_TOK_DATA_CHARS; +} + +/* ptr points to character following "%" */ + +static +int PREFIX(scanPercent)(const ENCODING *enc, const char *ptr, const char *end, + const char **nextTokPtr) +{ + if (ptr == end) + return XML_TOK_PARTIAL; + switch (BYTE_TYPE(enc, ptr)) { + CHECK_NMSTRT_CASES(enc, ptr, end, nextTokPtr) + case BT_S: case BT_LF: case BT_CR: case BT_PERCNT: + *nextTokPtr = ptr; + return XML_TOK_PERCENT; + default: + *nextTokPtr = ptr; + return XML_TOK_INVALID; + } + while (ptr != end) { + switch (BYTE_TYPE(enc, ptr)) { + CHECK_NAME_CASES(enc, ptr, end, nextTokPtr) + case BT_SEMI: + *nextTokPtr = ptr + MINBPC(enc); + return XML_TOK_PARAM_ENTITY_REF; + default: + *nextTokPtr = ptr; + return XML_TOK_INVALID; + } + } + return XML_TOK_PARTIAL; +} + +static +int PREFIX(scanPoundName)(const ENCODING *enc, const char *ptr, const char *end, + const char **nextTokPtr) +{ + if (ptr == end) + return XML_TOK_PARTIAL; + switch (BYTE_TYPE(enc, ptr)) { + CHECK_NMSTRT_CASES(enc, ptr, end, nextTokPtr) + default: + *nextTokPtr = ptr; + return XML_TOK_INVALID; + } + while (ptr != end) { + switch (BYTE_TYPE(enc, ptr)) { + CHECK_NAME_CASES(enc, ptr, end, nextTokPtr) + case BT_CR: case BT_LF: case BT_S: + case BT_RPAR: case BT_GT: case BT_PERCNT: case BT_VERBAR: + *nextTokPtr = ptr; + return XML_TOK_POUND_NAME; + default: + *nextTokPtr = ptr; + return XML_TOK_INVALID; + } + } + return -XML_TOK_POUND_NAME; +} + +static +int PREFIX(scanLit)(int open, const ENCODING *enc, + const char *ptr, const char *end, + const char **nextTokPtr) +{ + while (ptr != end) { + int t = BYTE_TYPE(enc, ptr); + switch (t) { + INVALID_CASES(ptr, nextTokPtr) + case BT_QUOT: + case BT_APOS: + ptr += MINBPC(enc); + if (t != open) + break; + if (ptr == end) + return -XML_TOK_LITERAL; + *nextTokPtr = ptr; + switch (BYTE_TYPE(enc, ptr)) { + case BT_S: case BT_CR: case BT_LF: + case BT_GT: case BT_PERCNT: case BT_LSQB: + return XML_TOK_LITERAL; + default: + return XML_TOK_INVALID; + } + default: + ptr += MINBPC(enc); + break; + } + } + return XML_TOK_PARTIAL; +} + +static +int PREFIX(prologTok)(const ENCODING *enc, const char *ptr, const char *end, + const char **nextTokPtr) +{ + int tok; + if (ptr == end) + return XML_TOK_NONE; + if (MINBPC(enc) > 1) { + size_t n = end - ptr; + if (n & (MINBPC(enc) - 1)) { + n &= ~(MINBPC(enc) - 1); + if (n == 0) + return XML_TOK_PARTIAL; + end = ptr + n; + } + } + switch (BYTE_TYPE(enc, ptr)) { + case BT_QUOT: + return PREFIX(scanLit)(BT_QUOT, enc, ptr + MINBPC(enc), end, nextTokPtr); + case BT_APOS: + return PREFIX(scanLit)(BT_APOS, enc, ptr + MINBPC(enc), end, nextTokPtr); + case BT_LT: + { + ptr += MINBPC(enc); + if (ptr == end) + return XML_TOK_PARTIAL; + switch (BYTE_TYPE(enc, ptr)) { + case BT_EXCL: + return PREFIX(scanDecl)(enc, ptr + MINBPC(enc), end, nextTokPtr); + case BT_QUEST: + return PREFIX(scanPi)(enc, ptr + MINBPC(enc), end, nextTokPtr); + case BT_NMSTRT: + case BT_HEX: + case BT_NONASCII: + case BT_LEAD2: + case BT_LEAD3: + case BT_LEAD4: + *nextTokPtr = ptr - MINBPC(enc); + return XML_TOK_INSTANCE_START; + } + *nextTokPtr = ptr; + return XML_TOK_INVALID; + } + case BT_CR: + if (ptr + MINBPC(enc) == end) + return -XML_TOK_PROLOG_S; + /* fall through */ + case BT_S: case BT_LF: + for (;;) { + ptr += MINBPC(enc); + if (ptr == end) + break; + switch (BYTE_TYPE(enc, ptr)) { + case BT_S: case BT_LF: + break; + case BT_CR: + /* don't split CR/LF pair */ + if (ptr + MINBPC(enc) != end) + break; + /* fall through */ + default: + *nextTokPtr = ptr; + return XML_TOK_PROLOG_S; + } + } + *nextTokPtr = ptr; + return XML_TOK_PROLOG_S; + case BT_PERCNT: + return PREFIX(scanPercent)(enc, ptr + MINBPC(enc), end, nextTokPtr); + case BT_COMMA: + *nextTokPtr = ptr + MINBPC(enc); + return XML_TOK_COMMA; + case BT_LSQB: + *nextTokPtr = ptr + MINBPC(enc); + return XML_TOK_OPEN_BRACKET; + case BT_RSQB: + ptr += MINBPC(enc); + if (ptr == end) + return -XML_TOK_CLOSE_BRACKET; + if (CHAR_MATCHES(enc, ptr, ASCII_RSQB)) { + if (ptr + MINBPC(enc) == end) + return XML_TOK_PARTIAL; + if (CHAR_MATCHES(enc, ptr + MINBPC(enc), ASCII_GT)) { + *nextTokPtr = ptr + 2*MINBPC(enc); + return XML_TOK_COND_SECT_CLOSE; + } + } + *nextTokPtr = ptr; + return XML_TOK_CLOSE_BRACKET; + case BT_LPAR: + *nextTokPtr = ptr + MINBPC(enc); + return XML_TOK_OPEN_PAREN; + case BT_RPAR: + ptr += MINBPC(enc); + if (ptr == end) + return -XML_TOK_CLOSE_PAREN; + switch (BYTE_TYPE(enc, ptr)) { + case BT_AST: + *nextTokPtr = ptr + MINBPC(enc); + return XML_TOK_CLOSE_PAREN_ASTERISK; + case BT_QUEST: + *nextTokPtr = ptr + MINBPC(enc); + return XML_TOK_CLOSE_PAREN_QUESTION; + case BT_PLUS: + *nextTokPtr = ptr + MINBPC(enc); + return XML_TOK_CLOSE_PAREN_PLUS; + case BT_CR: case BT_LF: case BT_S: + case BT_GT: case BT_COMMA: case BT_VERBAR: + case BT_RPAR: + *nextTokPtr = ptr; + return XML_TOK_CLOSE_PAREN; + } + *nextTokPtr = ptr; + return XML_TOK_INVALID; + case BT_VERBAR: + *nextTokPtr = ptr + MINBPC(enc); + return XML_TOK_OR; + case BT_GT: + *nextTokPtr = ptr + MINBPC(enc); + return XML_TOK_DECL_CLOSE; + case BT_NUM: + return PREFIX(scanPoundName)(enc, ptr + MINBPC(enc), end, nextTokPtr); +#define LEAD_CASE(n) \ + case BT_LEAD ## n: \ + if (end - ptr < n) \ + return XML_TOK_PARTIAL_CHAR; \ + if (IS_NMSTRT_CHAR(enc, ptr, n)) { \ + ptr += n; \ + tok = XML_TOK_NAME; \ + break; \ + } \ + if (IS_NAME_CHAR(enc, ptr, n)) { \ + ptr += n; \ + tok = XML_TOK_NMTOKEN; \ + break; \ + } \ + *nextTokPtr = ptr; \ + return XML_TOK_INVALID; + LEAD_CASE(2) LEAD_CASE(3) LEAD_CASE(4) +#undef LEAD_CASE + case BT_NMSTRT: + case BT_HEX: + tok = XML_TOK_NAME; + ptr += MINBPC(enc); + break; + case BT_DIGIT: + case BT_NAME: + case BT_MINUS: +#ifdef XML_NS + case BT_COLON: +#endif + tok = XML_TOK_NMTOKEN; + ptr += MINBPC(enc); + break; + case BT_NONASCII: + if (IS_NMSTRT_CHAR_MINBPC(enc, ptr)) { + ptr += MINBPC(enc); + tok = XML_TOK_NAME; + break; + } + if (IS_NAME_CHAR_MINBPC(enc, ptr)) { + ptr += MINBPC(enc); + tok = XML_TOK_NMTOKEN; + break; + } + /* fall through */ + default: + *nextTokPtr = ptr; + return XML_TOK_INVALID; + } + while (ptr != end) { + switch (BYTE_TYPE(enc, ptr)) { + CHECK_NAME_CASES(enc, ptr, end, nextTokPtr) + case BT_GT: case BT_RPAR: case BT_COMMA: + case BT_VERBAR: case BT_LSQB: case BT_PERCNT: + case BT_S: case BT_CR: case BT_LF: + *nextTokPtr = ptr; + return tok; +#ifdef XML_NS + case BT_COLON: + ptr += MINBPC(enc); + switch (tok) { + case XML_TOK_NAME: + if (ptr == end) + return XML_TOK_PARTIAL; + tok = XML_TOK_PREFIXED_NAME; + switch (BYTE_TYPE(enc, ptr)) { + CHECK_NAME_CASES(enc, ptr, end, nextTokPtr) + default: + tok = XML_TOK_NMTOKEN; + break; + } + break; + case XML_TOK_PREFIXED_NAME: + tok = XML_TOK_NMTOKEN; + break; + } + break; +#endif + case BT_PLUS: + if (tok == XML_TOK_NMTOKEN) { + *nextTokPtr = ptr; + return XML_TOK_INVALID; + } + *nextTokPtr = ptr + MINBPC(enc); + return XML_TOK_NAME_PLUS; + case BT_AST: + if (tok == XML_TOK_NMTOKEN) { + *nextTokPtr = ptr; + return XML_TOK_INVALID; + } + *nextTokPtr = ptr + MINBPC(enc); + return XML_TOK_NAME_ASTERISK; + case BT_QUEST: + if (tok == XML_TOK_NMTOKEN) { + *nextTokPtr = ptr; + return XML_TOK_INVALID; + } + *nextTokPtr = ptr + MINBPC(enc); + return XML_TOK_NAME_QUESTION; + default: + *nextTokPtr = ptr; + return XML_TOK_INVALID; + } + } + return -tok; +} + +static +int PREFIX(attributeValueTok)(const ENCODING *enc, const char *ptr, const char *end, + const char **nextTokPtr) +{ + const char *start; + if (ptr == end) + return XML_TOK_NONE; + start = ptr; + while (ptr != end) { + switch (BYTE_TYPE(enc, ptr)) { +#define LEAD_CASE(n) \ + case BT_LEAD ## n: ptr += n; break; + LEAD_CASE(2) LEAD_CASE(3) LEAD_CASE(4) +#undef LEAD_CASE + case BT_AMP: + if (ptr == start) + return PREFIX(scanRef)(enc, ptr + MINBPC(enc), end, nextTokPtr); + *nextTokPtr = ptr; + return XML_TOK_DATA_CHARS; + case BT_LT: + /* this is for inside entity references */ + *nextTokPtr = ptr; + return XML_TOK_INVALID; + case BT_LF: + if (ptr == start) { + *nextTokPtr = ptr + MINBPC(enc); + return XML_TOK_DATA_NEWLINE; + } + *nextTokPtr = ptr; + return XML_TOK_DATA_CHARS; + case BT_CR: + if (ptr == start) { + ptr += MINBPC(enc); + if (ptr == end) + return XML_TOK_TRAILING_CR; + if (BYTE_TYPE(enc, ptr) == BT_LF) + ptr += MINBPC(enc); + *nextTokPtr = ptr; + return XML_TOK_DATA_NEWLINE; + } + *nextTokPtr = ptr; + return XML_TOK_DATA_CHARS; + case BT_S: + if (ptr == start) { + *nextTokPtr = ptr + MINBPC(enc); + return XML_TOK_ATTRIBUTE_VALUE_S; + } + *nextTokPtr = ptr; + return XML_TOK_DATA_CHARS; + default: + ptr += MINBPC(enc); + break; + } + } + *nextTokPtr = ptr; + return XML_TOK_DATA_CHARS; +} + +static +int PREFIX(entityValueTok)(const ENCODING *enc, const char *ptr, const char *end, + const char **nextTokPtr) +{ + const char *start; + if (ptr == end) + return XML_TOK_NONE; + start = ptr; + while (ptr != end) { + switch (BYTE_TYPE(enc, ptr)) { +#define LEAD_CASE(n) \ + case BT_LEAD ## n: ptr += n; break; + LEAD_CASE(2) LEAD_CASE(3) LEAD_CASE(4) +#undef LEAD_CASE + case BT_AMP: + if (ptr == start) + return PREFIX(scanRef)(enc, ptr + MINBPC(enc), end, nextTokPtr); + *nextTokPtr = ptr; + return XML_TOK_DATA_CHARS; + case BT_PERCNT: + if (ptr == start) + return PREFIX(scanPercent)(enc, ptr + MINBPC(enc), end, nextTokPtr); + *nextTokPtr = ptr; + return XML_TOK_DATA_CHARS; + case BT_LF: + if (ptr == start) { + *nextTokPtr = ptr + MINBPC(enc); + return XML_TOK_DATA_NEWLINE; + } + *nextTokPtr = ptr; + return XML_TOK_DATA_CHARS; + case BT_CR: + if (ptr == start) { + ptr += MINBPC(enc); + if (ptr == end) + return XML_TOK_TRAILING_CR; + if (BYTE_TYPE(enc, ptr) == BT_LF) + ptr += MINBPC(enc); + *nextTokPtr = ptr; + return XML_TOK_DATA_NEWLINE; + } + *nextTokPtr = ptr; + return XML_TOK_DATA_CHARS; + default: + ptr += MINBPC(enc); + break; + } + } + *nextTokPtr = ptr; + return XML_TOK_DATA_CHARS; +} + +#ifdef XML_DTD + +static +int PREFIX(ignoreSectionTok)(const ENCODING *enc, const char *ptr, const char *end, + const char **nextTokPtr) +{ + int level = 0; + if (MINBPC(enc) > 1) { + size_t n = end - ptr; + if (n & (MINBPC(enc) - 1)) { + n &= ~(MINBPC(enc) - 1); + end = ptr + n; + } + } + while (ptr != end) { + switch (BYTE_TYPE(enc, ptr)) { + INVALID_CASES(ptr, nextTokPtr) + case BT_LT: + if ((ptr += MINBPC(enc)) == end) + return XML_TOK_PARTIAL; + if (CHAR_MATCHES(enc, ptr, ASCII_EXCL)) { + if ((ptr += MINBPC(enc)) == end) + return XML_TOK_PARTIAL; + if (CHAR_MATCHES(enc, ptr, ASCII_LSQB)) { + ++level; + ptr += MINBPC(enc); + } + } + break; + case BT_RSQB: + if ((ptr += MINBPC(enc)) == end) + return XML_TOK_PARTIAL; + if (CHAR_MATCHES(enc, ptr, ASCII_RSQB)) { + if ((ptr += MINBPC(enc)) == end) + return XML_TOK_PARTIAL; + if (CHAR_MATCHES(enc, ptr, ASCII_GT)) { + ptr += MINBPC(enc); + if (level == 0) { + *nextTokPtr = ptr; + return XML_TOK_IGNORE_SECT; + } + --level; + } + } + break; + default: + ptr += MINBPC(enc); + break; + } + } + return XML_TOK_PARTIAL; +} + +#endif /* XML_DTD */ + +static +int PREFIX(isPublicId)(const ENCODING *enc, const char *ptr, const char *end, + const char **badPtr) +{ + ptr += MINBPC(enc); + end -= MINBPC(enc); + for (; ptr != end; ptr += MINBPC(enc)) { + switch (BYTE_TYPE(enc, ptr)) { + case BT_DIGIT: + case BT_HEX: + case BT_MINUS: + case BT_APOS: + case BT_LPAR: + case BT_RPAR: + case BT_PLUS: + case BT_COMMA: + case BT_SOL: + case BT_EQUALS: + case BT_QUEST: + case BT_CR: + case BT_LF: + case BT_SEMI: + case BT_EXCL: + case BT_AST: + case BT_PERCNT: + case BT_NUM: +#ifdef XML_NS + case BT_COLON: +#endif + break; + case BT_S: + if (CHAR_MATCHES(enc, ptr, ASCII_TAB)) { + *badPtr = ptr; + return 0; + } + break; + case BT_NAME: + case BT_NMSTRT: + if (!(BYTE_TO_ASCII(enc, ptr) & ~0x7f)) + break; + default: + switch (BYTE_TO_ASCII(enc, ptr)) { + case 0x24: /* $ */ + case 0x40: /* @ */ + break; + default: + *badPtr = ptr; + return 0; + } + break; + } + } + return 1; +} + +/* This must only be called for a well-formed start-tag or empty element tag. +Returns the number of attributes. Pointers to the first attsMax attributes +are stored in atts. */ + +static +int PREFIX(getAtts)(const ENCODING *enc, const char *ptr, + int attsMax, ATTRIBUTE *atts) +{ + enum { other, inName, inValue } state = inName; + int nAtts = 0; + int open = 0; /* defined when state == inValue; + initialization just to shut up compilers */ + + for (ptr += MINBPC(enc);; ptr += MINBPC(enc)) { + switch (BYTE_TYPE(enc, ptr)) { +#define START_NAME \ + if (state == other) { \ + if (nAtts < attsMax) { \ + atts[nAtts].name = ptr; \ + atts[nAtts].normalized = 1; \ + } \ + state = inName; \ + } +#define LEAD_CASE(n) \ + case BT_LEAD ## n: START_NAME ptr += (n - MINBPC(enc)); break; + LEAD_CASE(2) LEAD_CASE(3) LEAD_CASE(4) +#undef LEAD_CASE + case BT_NONASCII: + case BT_NMSTRT: + case BT_HEX: + START_NAME + break; +#undef START_NAME + case BT_QUOT: + if (state != inValue) { + if (nAtts < attsMax) + atts[nAtts].valuePtr = ptr + MINBPC(enc); + state = inValue; + open = BT_QUOT; + } + else if (open == BT_QUOT) { + state = other; + if (nAtts < attsMax) + atts[nAtts].valueEnd = ptr; + nAtts++; + } + break; + case BT_APOS: + if (state != inValue) { + if (nAtts < attsMax) + atts[nAtts].valuePtr = ptr + MINBPC(enc); + state = inValue; + open = BT_APOS; + } + else if (open == BT_APOS) { + state = other; + if (nAtts < attsMax) + atts[nAtts].valueEnd = ptr; + nAtts++; + } + break; + case BT_AMP: + if (nAtts < attsMax) + atts[nAtts].normalized = 0; + break; + case BT_S: + if (state == inName) + state = other; + else if (state == inValue + && nAtts < attsMax + && atts[nAtts].normalized + && (ptr == atts[nAtts].valuePtr + || BYTE_TO_ASCII(enc, ptr) != ASCII_SPACE + || BYTE_TO_ASCII(enc, ptr + MINBPC(enc)) == ASCII_SPACE + || BYTE_TYPE(enc, ptr + MINBPC(enc)) == open)) + atts[nAtts].normalized = 0; + break; + case BT_CR: case BT_LF: + /* This case ensures that the first attribute name is counted + Apart from that we could just change state on the quote. */ + if (state == inName) + state = other; + else if (state == inValue && nAtts < attsMax) + atts[nAtts].normalized = 0; + break; + case BT_GT: + case BT_SOL: + if (state != inValue) + return nAtts; + break; + default: + break; + } + } + /* not reached */ +} + +static +int PREFIX(charRefNumber)(const ENCODING *enc ATTR_UNUSED, const char *ptr) +{ + int result = 0; + /* skip &# */ + ptr += 2*MINBPC(enc); + if (CHAR_MATCHES(enc, ptr, ASCII_x)) { + for (ptr += MINBPC(enc); !CHAR_MATCHES(enc, ptr, ASCII_SEMI); ptr += MINBPC(enc)) { + int c = BYTE_TO_ASCII(enc, ptr); + switch (c) { + case ASCII_0: case ASCII_1: case ASCII_2: case ASCII_3: case ASCII_4: + case ASCII_5: case ASCII_6: case ASCII_7: case ASCII_8: case ASCII_9: + result <<= 4; + result |= (c - ASCII_0); + break; + case ASCII_A: case ASCII_B: case ASCII_C: case ASCII_D: case ASCII_E: case ASCII_F: + result <<= 4; + result += 10 + (c - ASCII_A); + break; + case ASCII_a: case ASCII_b: case ASCII_c: case ASCII_d: case ASCII_e: case ASCII_f: + result <<= 4; + result += 10 + (c - ASCII_a); + break; + } + if (result >= 0x110000) + return -1; + } + } + else { + for (; !CHAR_MATCHES(enc, ptr, ASCII_SEMI); ptr += MINBPC(enc)) { + int c = BYTE_TO_ASCII(enc, ptr); + result *= 10; + result += (c - ASCII_0); + if (result >= 0x110000) + return -1; + } + } + return checkCharRefNumber(result); +} + +static +int PREFIX(predefinedEntityName)(const ENCODING * enc ATTR_UNUSED, + const char * ptr, + const char * end) +{ + switch ((end - ptr)/MINBPC(enc)) { + case 2: + if (CHAR_MATCHES(enc, ptr + MINBPC(enc), ASCII_t)) { + switch (BYTE_TO_ASCII(enc, ptr)) { + case ASCII_l: + return ASCII_LT; + case ASCII_g: + return ASCII_GT; + } + } + break; + case 3: + if (CHAR_MATCHES(enc, ptr, ASCII_a)) { + ptr += MINBPC(enc); + if (CHAR_MATCHES(enc, ptr, ASCII_m)) { + ptr += MINBPC(enc); + if (CHAR_MATCHES(enc, ptr, ASCII_p)) + return ASCII_AMP; + } + } + break; + case 4: + switch (BYTE_TO_ASCII(enc, ptr)) { + case ASCII_q: + ptr += MINBPC(enc); + if (CHAR_MATCHES(enc, ptr, ASCII_u)) { + ptr += MINBPC(enc); + if (CHAR_MATCHES(enc, ptr, ASCII_o)) { + ptr += MINBPC(enc); + if (CHAR_MATCHES(enc, ptr, ASCII_t)) + return ASCII_QUOT; + } + } + break; + case ASCII_a: + ptr += MINBPC(enc); + if (CHAR_MATCHES(enc, ptr, ASCII_p)) { + ptr += MINBPC(enc); + if (CHAR_MATCHES(enc, ptr, ASCII_o)) { + ptr += MINBPC(enc); + if (CHAR_MATCHES(enc, ptr, ASCII_s)) + return ASCII_APOS; + } + } + break; + } + } + return 0; +} + +static +int PREFIX(sameName)(const ENCODING *enc, const char *ptr1, const char *ptr2) +{ + for (;;) { + switch (BYTE_TYPE(enc, ptr1)) { +#define LEAD_CASE(n) \ + case BT_LEAD ## n: \ + if (*ptr1++ != *ptr2++) \ + return 0; + LEAD_CASE(4) LEAD_CASE(3) LEAD_CASE(2) +#undef LEAD_CASE + /* fall through */ + if (*ptr1++ != *ptr2++) + return 0; + break; + case BT_NONASCII: + case BT_NMSTRT: +#ifdef XML_NS + case BT_COLON: +#endif + case BT_HEX: + case BT_DIGIT: + case BT_NAME: + case BT_MINUS: + if (*ptr2++ != *ptr1++) + return 0; + if (MINBPC(enc) > 1) { + if (*ptr2++ != *ptr1++) + return 0; + if (MINBPC(enc) > 2) { + if (*ptr2++ != *ptr1++) + return 0; + if (MINBPC(enc) > 3) { + if (*ptr2++ != *ptr1++) + return 0; + } + } + } + break; + default: + if (MINBPC(enc) == 1 && *ptr1 == *ptr2) + return 1; + switch (BYTE_TYPE(enc, ptr2)) { + case BT_LEAD2: + case BT_LEAD3: + case BT_LEAD4: + case BT_NONASCII: + case BT_NMSTRT: +#ifdef XML_NS + case BT_COLON: +#endif + case BT_HEX: + case BT_DIGIT: + case BT_NAME: + case BT_MINUS: + return 0; + default: + return 1; + } + } + } + /* not reached */ +} + +static +int PREFIX(nameMatchesAscii)(const ENCODING * enc ATTR_UNUSED, + const char * ptr1, + const char * end1, + const char * ptr2) +{ + for (; *ptr2; ptr1 += MINBPC(enc), ptr2++) { + if (ptr1 == end1) + return 0; + if (!CHAR_MATCHES(enc, ptr1, *ptr2)) + return 0; + } + return ptr1 == end1; +} + +static +int PREFIX(nameLength)(const ENCODING *enc, const char *ptr) +{ + const char *start = ptr; + for (;;) { + switch (BYTE_TYPE(enc, ptr)) { +#define LEAD_CASE(n) \ + case BT_LEAD ## n: ptr += n; break; + LEAD_CASE(2) LEAD_CASE(3) LEAD_CASE(4) +#undef LEAD_CASE + case BT_NONASCII: + case BT_NMSTRT: +#ifdef XML_NS + case BT_COLON: +#endif + case BT_HEX: + case BT_DIGIT: + case BT_NAME: + case BT_MINUS: + ptr += MINBPC(enc); + break; + default: + return ptr - start; + } + } +} + +static +const char *PREFIX(skipS)(const ENCODING *enc, const char *ptr) +{ + for (;;) { + switch (BYTE_TYPE(enc, ptr)) { + case BT_LF: + case BT_CR: + case BT_S: + ptr += MINBPC(enc); + break; + default: + return ptr; + } + } +} + +static +void PREFIX(updatePosition)(const ENCODING *enc, + const char *ptr, + const char *end, + POSITION *pos) +{ + while (ptr != end) { + switch (BYTE_TYPE(enc, ptr)) { +#define LEAD_CASE(n) \ + case BT_LEAD ## n: \ + ptr += n; \ + break; + LEAD_CASE(2) LEAD_CASE(3) LEAD_CASE(4) +#undef LEAD_CASE + case BT_LF: + pos->columnNumber = (unsigned)-1; + pos->lineNumber++; + ptr += MINBPC(enc); + break; + case BT_CR: + pos->lineNumber++; + ptr += MINBPC(enc); + if (ptr != end && BYTE_TYPE(enc, ptr) == BT_LF) + ptr += MINBPC(enc); + pos->columnNumber = (unsigned)-1; + break; + default: + ptr += MINBPC(enc); + break; + } + pos->columnNumber++; + } +} + +#undef DO_LEAD_CASE +#undef MULTIBYTE_CASES +#undef INVALID_CASES +#undef CHECK_NAME_CASE +#undef CHECK_NAME_CASES +#undef CHECK_NMSTRT_CASE +#undef CHECK_NMSTRT_CASES diff --git a/lib/expat/xmltok/xmltok_impl.h b/lib/expat/xmltok/xmltok_impl.h new file mode 100644 index 0000000..eb92802 --- /dev/null +++ b/lib/expat/xmltok/xmltok_impl.h @@ -0,0 +1,46 @@ +/* +Copyright (c) 1998, 1999 Thai Open Source Software Center Ltd +See the file copying.txt for copying permission. +*/ + +enum { + BT_NONXML, + BT_MALFORM, + BT_LT, + BT_AMP, + BT_RSQB, + BT_LEAD2, + BT_LEAD3, + BT_LEAD4, + BT_TRAIL, + BT_CR, + BT_LF, + BT_GT, + BT_QUOT, + BT_APOS, + BT_EQUALS, + BT_QUEST, + BT_EXCL, + BT_SOL, + BT_SEMI, + BT_NUM, + BT_LSQB, + BT_S, + BT_NMSTRT, + BT_COLON, + BT_HEX, + BT_DIGIT, + BT_NAME, + BT_MINUS, + BT_OTHER, /* known not to be a name or name start character */ + BT_NONASCII, /* might be a name or name start character */ + BT_PERCNT, + BT_LPAR, + BT_RPAR, + BT_AST, + BT_PLUS, + BT_COMMA, + BT_VERBAR +}; + +#include diff --git a/lib/expat/xmltok/xmltok_ns.c b/lib/expat/xmltok/xmltok_ns.c new file mode 100644 index 0000000..205cfc2 --- /dev/null +++ b/lib/expat/xmltok/xmltok_ns.c @@ -0,0 +1,96 @@ +const ENCODING *NS(xmlrpc_XmlGetUtf8InternalEncoding)(void) +{ + return &ns(internal_utf8_encoding).enc; +} + +const ENCODING *NS(xmlrpc_XmlGetUtf16InternalEncoding)(void) +{ +#if XML_BYTE_ORDER == 12 + return &ns(internal_little2_encoding).enc; +#elif XML_BYTE_ORDER == 21 + return &ns(internal_big2_encoding).enc; +#else + const short n = 1; + return *(const char *)&n ? &ns(internal_little2_encoding).enc : &ns(internal_big2_encoding).enc; +#endif +} + +static +const ENCODING *NS(encodings)[] = { + &ns(latin1_encoding).enc, + &ns(ascii_encoding).enc, + &ns(utf8_encoding).enc, + &ns(big2_encoding).enc, + &ns(big2_encoding).enc, + &ns(little2_encoding).enc, + &ns(utf8_encoding).enc /* NO_ENC */ +}; + +static +int NS(initScanProlog)(const ENCODING *enc, const char *ptr, const char *end, + const char **nextTokPtr) +{ + return initScan(NS(encodings), (const INIT_ENCODING *)enc, XML_PROLOG_STATE, ptr, end, nextTokPtr); +} + +static +int NS(initScanContent)(const ENCODING *enc, const char *ptr, const char *end, + const char **nextTokPtr) +{ + return initScan(NS(encodings), (const INIT_ENCODING *)enc, XML_CONTENT_STATE, ptr, end, nextTokPtr); +} + +int NS(xmlrpc_XmlInitEncoding)(INIT_ENCODING *p, const ENCODING **encPtr, const char *name) +{ + int i = getEncodingIndex(name); + if (i == UNKNOWN_ENC) + return 0; + SET_INIT_ENC_INDEX(p, i); + p->initEnc.scanners[XML_PROLOG_STATE] = NS(initScanProlog); + p->initEnc.scanners[XML_CONTENT_STATE] = NS(initScanContent); + p->initEnc.updatePosition = initUpdatePosition; + p->encPtr = encPtr; + *encPtr = &(p->initEnc); + return 1; +} + +static +const ENCODING *NS(findEncoding)(const ENCODING *enc, const char *ptr, const char *end) +{ +#define ENCODING_MAX 128 + char buf[ENCODING_MAX]; + char *p = buf; + int i; + XmlUtf8Convert(enc, &ptr, end, &p, p + ENCODING_MAX - 1); + if (ptr != end) + return 0; + *p = 0; + if (streqci(buf, KW_UTF_16) && enc->minBytesPerChar == 2) + return enc; + i = getEncodingIndex(buf); + if (i == UNKNOWN_ENC) + return 0; + return NS(encodings)[i]; +} + +int NS(xmlrpc_XmlParseXmlDecl)(int isGeneralTextEntity, + const ENCODING *enc, + const char *ptr, + const char *end, + const char **badPtr, + const char **versionPtr, + const char **encodingName, + const ENCODING **encoding, + int *standalone) +{ + return doParseXmlDecl(NS(findEncoding), + isGeneralTextEntity, + enc, + ptr, + end, + badPtr, + versionPtr, + encodingName, + encoding, + standalone); +} diff --git a/lib/expat/xmlwf/.cvsignore b/lib/expat/xmlwf/.cvsignore new file mode 100644 index 0000000..f3c7a7c --- /dev/null +++ b/lib/expat/xmlwf/.cvsignore @@ -0,0 +1 @@ +Makefile diff --git a/lib/expat/xmlwf/Makefile.in b/lib/expat/xmlwf/Makefile.in new file mode 100644 index 0000000..0860147 --- /dev/null +++ b/lib/expat/xmlwf/Makefile.in @@ -0,0 +1,209 @@ +# Copyright (C) 1994, 1995-8, 1999 Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + + +SHELL = @SHELL@ + +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +VPATH = @srcdir@ +prefix = @prefix@ +exec_prefix = @exec_prefix@ + +bindir = @bindir@ +sbindir = @sbindir@ +libexecdir = @libexecdir@ +datadir = @datadir@ +sysconfdir = @sysconfdir@ +sharedstatedir = @sharedstatedir@ +localstatedir = @localstatedir@ +libdir = @libdir@ +infodir = @infodir@ +mandir = @mandir@ +includedir = @includedir@ +oldincludedir = /usr/include + +DESTDIR = + +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ + +top_builddir = ../../.. + +ACLOCAL = @ACLOCAL@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ + +INSTALL = @INSTALL@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ $(AM_INSTALL_PROGRAM_FLAGS) +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +transform = @program_transform_name@ + +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +host_alias = @host_alias@ +host_triplet = @host@ +ABYSS_SUBDIR = @ABYSS_SUBDIR@ +AS = @AS@ +ASYNCH_CLIENT = @ASYNCH_CLIENT@ +AUTH_CLIENT = @AUTH_CLIENT@ +AVAILABLE_MODULES = @AVAILABLE_MODULES@ +CC = @CC@ +CC_WARN_FLAGS = @CC_WARN_FLAGS@ +CLIENTTEST = @CLIENTTEST@ +CONFIGURE_DATE = @CONFIGURE_DATE@ +CPPTEST = @CPPTEST@ +CPP_WARN_FLAGS = @CPP_WARN_FLAGS@ +CXX = @CXX@ +DLLTOOL = @DLLTOOL@ +EFRPCTEST = @EFRPCTEST@ +EFRPCTEST_WRAPPER = @EFRPCTEST_WRAPPER@ +INTEROP_CGI = @INTEROP_CGI@ +INTEROP_CLIENT_SUBDIR = @INTEROP_CLIENT_SUBDIR@ +LIBTOOL = @LIBTOOL@ +LIBWWW_CFLAGS = @LIBWWW_CFLAGS@ +LIBWWW_CONFIG = @LIBWWW_CONFIG@ +LIBWWW_LDADD = @LIBWWW_LDADD@ +LIBWWW_LIBDIR = @LIBWWW_LIBDIR@ +LIBWWW_RPATH = @LIBWWW_RPATH@ +LIBWWW_WL_RPATH = @LIBWWW_WL_RPATH@ +LIBXMLRPC_ABYSS_SERVER_LA = @LIBXMLRPC_ABYSS_SERVER_LA@ +LIBXMLRPC_CGI_LA = @LIBXMLRPC_CGI_LA@ +LIBXMLRPC_CLIENT_LA = @LIBXMLRPC_CLIENT_LA@ +LIBXMLRPC_CPP_A = @LIBXMLRPC_CPP_A@ +LN_S = @LN_S@ +MAKEINFO = @MAKEINFO@ +MEERKAT_APP_LIST = @MEERKAT_APP_LIST@ +OBJDUMP = @OBJDUMP@ +PACKAGE = @PACKAGE@ +QUERY_MEERKAT = @QUERY_MEERKAT@ +RANLIB = @RANLIB@ +SAMPLE_CGI_CGI = @SAMPLE_CGI_CGI@ +SERVER = @SERVER@ +SERVERTEST = @SERVERTEST@ +SYNCH_CLIENT = @SYNCH_CLIENT@ +VALIDATEE = @VALIDATEE@ +VERSION = @VERSION@ +VERSION_INFO = @VERSION_INFO@ +XMLRPCCPP_H = @XMLRPCCPP_H@ +XMLRPC_ABYSS_H = @XMLRPC_ABYSS_H@ +XMLRPC_CGI_H = @XMLRPC_CGI_H@ +XMLRPC_CLIENT_H = @XMLRPC_CLIENT_H@ +XML_RPC_API2CPP_SUBDIR = @XML_RPC_API2CPP_SUBDIR@ + +EXTRA_DIST = codepage.c filemap.h unixfilemap.c xmlfile.c xmltchar.h xmlwf.dsp codepage.h readfilemap.c win32filemap.c xmlfile.h xmlwf.c + +mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs +CONFIG_HEADER = ../../../xmlrpc_config.h +CONFIG_CLEAN_FILES = +DIST_COMMON = Makefile.in + + +DISTFILES = $(DIST_COMMON) $(SOURCES) $(HEADERS) $(TEXINFOS) $(EXTRA_DIST) + +TAR = gtar +GZIP_ENV = --best +all: all-redirect +.SUFFIXES: + +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + cd $(top_builddir) \ + && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status + +tags: TAGS +TAGS: + + +distdir = $(top_builddir)/$(PACKAGE)-$(VERSION)/$(subdir) + +subdir = lib/expat/xmlwf + +distdir: $(DISTFILES) + @for file in $(DISTFILES); do \ + d=$(srcdir); \ + if test -d $$d/$$file; then \ + cp -pr $$d/$$file $(distdir)/$$file; \ + else \ + test -f $(distdir)/$$file \ + || ln $$d/$$file $(distdir)/$$file 2> /dev/null \ + || cp -p $$d/$$file $(distdir)/$$file || :; \ + fi; \ + done +info-am: +info: info-am +dvi-am: +dvi: dvi-am +check-am: all-am +check: check-am +installcheck-am: +installcheck: installcheck-am +install-exec-am: +install-exec: install-exec-am + +install-data-am: +install-data: install-data-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am +install: install-am +uninstall-am: +uninstall: uninstall-am +all-am: Makefile +all-redirect: all-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) AM_INSTALL_PROGRAM_FLAGS=-s install +installdirs: + + +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -rm -f Makefile $(CONFIG_CLEAN_FILES) + -rm -f config.cache config.log stamp-h stamp-h[0-9]* + +maintainer-clean-generic: +mostlyclean-am: mostlyclean-generic + +mostlyclean: mostlyclean-am + +clean-am: clean-generic mostlyclean-am + +clean: clean-am + +distclean-am: distclean-generic clean-am + -rm -f libtool + +distclean: distclean-am + +maintainer-clean-am: maintainer-clean-generic distclean-am + @echo "This command is intended for maintainers to use;" + @echo "it deletes files that may require special tools to rebuild." + +maintainer-clean: maintainer-clean-am + +.PHONY: tags distdir info-am info dvi-am dvi check check-am \ +installcheck-am installcheck install-exec-am install-exec \ +install-data-am install-data install-am install uninstall-am uninstall \ +all-redirect all-am all installdirs mostlyclean-generic \ +distclean-generic clean-generic maintainer-clean-generic clean \ +mostlyclean distclean maintainer-clean + + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/lib/expat/xmlwf/codepage.c b/lib/expat/xmlwf/codepage.c new file mode 100644 index 0000000..fe7ab15 --- /dev/null +++ b/lib/expat/xmlwf/codepage.c @@ -0,0 +1,65 @@ +/* +Copyright (c) 1998, 1999 Thai Open Source Software Center Ltd +See the file copying.txt for copying permission. +*/ + +#include "codepage.h" + +#ifdef WIN32 +#define STRICT 1 +#define WIN32_LEAN_AND_MEAN 1 + +#include + +int codepageMap(int cp, int *map) +{ + int i; + CPINFO info; + if (!GetCPInfo(cp, &info) || info.MaxCharSize > 2) + return 0; + for (i = 0; i < 256; i++) + map[i] = -1; + if (info.MaxCharSize > 1) { + for (i = 0; i < MAX_LEADBYTES; i++) { + int j, lim; + if (info.LeadByte[i] == 0 && info.LeadByte[i + 1] == 0) + break; + lim = info.LeadByte[i + 1]; + for (j = info.LeadByte[i]; j < lim; j++) + map[j] = -2; + } + } + for (i = 0; i < 256; i++) { + if (map[i] == -1) { + char c = i; + unsigned short n; + if (MultiByteToWideChar(cp, MB_PRECOMPOSED|MB_ERR_INVALID_CHARS, + &c, 1, &n, 1) == 1) + map[i] = n; + } + } + return 1; +} + +int codepageConvert(int cp, const char *p) +{ + unsigned short c; + if (MultiByteToWideChar(cp, MB_PRECOMPOSED|MB_ERR_INVALID_CHARS, + p, 2, &c, 1) == 1) + return c; + return -1; +} + +#else /* not WIN32 */ + +int codepageMap(int cp, int *map) +{ + return 0; +} + +int codepageConvert(int cp, const char *p) +{ + return -1; +} + +#endif /* not WIN32 */ diff --git a/lib/expat/xmlwf/codepage.h b/lib/expat/xmlwf/codepage.h new file mode 100644 index 0000000..b19a7f6 --- /dev/null +++ b/lib/expat/xmlwf/codepage.h @@ -0,0 +1,7 @@ +/* +Copyright (c) 1998, 1999 Thai Open Source Software Center Ltd +See the file copying.txt for copying permission. +*/ + +int codepageMap(int cp, int *map); +int codepageConvert(int cp, const char *p); diff --git a/lib/expat/xmlwf/filemap.h b/lib/expat/xmlwf/filemap.h new file mode 100644 index 0000000..a0a1847 --- /dev/null +++ b/lib/expat/xmlwf/filemap.h @@ -0,0 +1,17 @@ +/* +Copyright (c) 1998, 1999 Thai Open Source Software Center Ltd +See the file copying.txt for copying permission. +*/ + + +#include + +#ifdef XML_UNICODE +int filemap(const wchar_t *name, + void (*processor)(const void *, size_t, const wchar_t *, void *arg), + void *arg); +#else +int filemap(const char *name, + void (*processor)(const void *, size_t, const char *, void *arg), + void *arg); +#endif diff --git a/lib/expat/xmlwf/readfilemap.c b/lib/expat/xmlwf/readfilemap.c new file mode 100644 index 0000000..249af3e --- /dev/null +++ b/lib/expat/xmlwf/readfilemap.c @@ -0,0 +1,74 @@ +/* +Copyright (c) 1998, 1999 Thai Open Source Software Center Ltd +See the file copying.txt for copying permission. +*/ + +#include +#include +#include +#include +#include + +#ifndef S_ISREG +#ifndef S_IFREG +#define S_IFREG _S_IFREG +#endif +#ifndef S_IFMT +#define S_IFMT _S_IFMT +#endif +#define S_ISREG(m) (((m) & S_IFMT) == S_IFREG) +#endif /* not S_ISREG */ + +#ifndef O_BINARY +#ifdef _O_BINARY +#define O_BINARY _O_BINARY +#else +#define O_BINARY 0 +#endif +#endif + +int filemap(const char *name, + void (*processor)(const void *, size_t, const char *, void *arg), + void *arg) +{ + size_t nbytes; + int fd; + int n; + struct stat sb; + void *p; + + fd = open(name, O_RDONLY|O_BINARY); + if (fd < 0) { + perror(name); + return 0; + } + if (fstat(fd, &sb) < 0) { + perror(name); + return 0; + } + if (!S_ISREG(sb.st_mode)) { + fprintf(stderr, "%s: not a regular file\n", name); + return 0; + } + nbytes = sb.st_size; + p = malloc(nbytes); + if (!p) { + fprintf(stderr, "%s: out of memory\n", name); + return 0; + } + n = read(fd, p, nbytes); + if (n < 0) { + perror(name); + close(fd); + return 0; + } + if (n != nbytes) { + fprintf(stderr, "%s: read unexpected number of bytes\n", name); + close(fd); + return 0; + } + processor(p, nbytes, name, arg); + free(p); + close(fd); + return 1; +} diff --git a/lib/expat/xmlwf/unixfilemap.c b/lib/expat/xmlwf/unixfilemap.c new file mode 100644 index 0000000..4944b02 --- /dev/null +++ b/lib/expat/xmlwf/unixfilemap.c @@ -0,0 +1,57 @@ +/* +Copyright (c) 1998, 1999 Thai Open Source Software Center Ltd +See the file copying.txt for copying permission. +*/ + +#include +#include +#include +#include +#include +#include +#include + +#ifndef MAP_FILE +#define MAP_FILE 0 +#endif + +#include "filemap.h" + +int filemap(const char *name, + void (*processor)(const void *, size_t, const char *, void *arg), + void *arg) +{ + int fd; + size_t nbytes; + struct stat sb; + void *p; + + fd = open(name, O_RDONLY); + if (fd < 0) { + perror(name); + return 0; + } + if (fstat(fd, &sb) < 0) { + perror(name); + close(fd); + return 0; + } + if (!S_ISREG(sb.st_mode)) { + close(fd); + fprintf(stderr, "%s: not a regular file\n", name); + return 0; + } + + nbytes = sb.st_size; + p = (void *)mmap((caddr_t)0, (size_t)nbytes, PROT_READ, + MAP_FILE|MAP_PRIVATE, fd, (off_t)0); + if (p == (void *)-1) { + perror(name); + close(fd); + return 0; + } + processor(p, nbytes, name, arg); + munmap((caddr_t)p, nbytes); + close(fd); + return 1; +} diff --git a/lib/expat/xmlwf/win32filemap.c b/lib/expat/xmlwf/win32filemap.c new file mode 100644 index 0000000..ec30ff6 --- /dev/null +++ b/lib/expat/xmlwf/win32filemap.c @@ -0,0 +1,95 @@ +/* +Copyright (c) 1998, 1999 Thai Open Source Software Center Ltd +See the file copying.txt for copying permission. +*/ + +#define STRICT 1 +#define WIN32_LEAN_AND_MEAN 1 + +#ifdef XML_UNICODE_WCHAR_T +#ifndef XML_UNICODE +#define XML_UNICODE +#endif +#endif + +#ifdef XML_UNICODE +#define UNICODE +#define _UNICODE +#endif /* XML_UNICODE */ +#include +#include +#include +#include "filemap.h" + +static void win32perror(const TCHAR *); + +int filemap(const TCHAR *name, + void (*processor)(const void *, size_t, const TCHAR *, void *arg), + void *arg) +{ + HANDLE f; + HANDLE m; + DWORD size; + DWORD sizeHi; + void *p; + + f = CreateFile(name, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, + FILE_FLAG_SEQUENTIAL_SCAN, NULL); + if (f == INVALID_HANDLE_VALUE) { + win32perror(name); + return 0; + } + size = GetFileSize(f, &sizeHi); + if (size == (DWORD)-1) { + win32perror(name); + return 0; + } + if (sizeHi) { + _ftprintf(stderr, _T("%s: bigger than 2Gb\n"), name); + return 0; + } + /* CreateFileMapping barfs on zero length files */ + if (size == 0) { + static const char c = '\0'; + processor(&c, 0, name, arg); + CloseHandle(f); + return 1; + } + m = CreateFileMapping(f, NULL, PAGE_READONLY, 0, 0, NULL); + if (m == NULL) { + win32perror(name); + CloseHandle(f); + return 0; + } + p = MapViewOfFile(m, FILE_MAP_READ, 0, 0, 0); + if (p == NULL) { + win32perror(name); + CloseHandle(m); + CloseHandle(f); + return 0; + } + processor(p, size, name, arg); + UnmapViewOfFile(p); + CloseHandle(m); + CloseHandle(f); + return 1; +} + +static +void win32perror(const TCHAR *s) +{ + LPVOID buf; + if (FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, + NULL, + GetLastError(), + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), + (LPTSTR) &buf, + 0, + NULL)) { + _ftprintf(stderr, _T("%s: %s"), s, buf); + fflush(stderr); + LocalFree(buf); + } + else + _ftprintf(stderr, _T("%s: unknown Windows error\n"), s); +} diff --git a/lib/expat/xmlwf/xmlfile.c b/lib/expat/xmlwf/xmlfile.c new file mode 100644 index 0000000..6f79107 --- /dev/null +++ b/lib/expat/xmlwf/xmlfile.c @@ -0,0 +1,217 @@ +/* +Copyright (c) 1998, 1999 Thai Open Source Software Center Ltd +See the file copying.txt for copying permission. +*/ + +#include +#include +#include +#include +#include +#include "xmlparse.h" +#include "xmlfile.h" +#include "xmltchar.h" +#include "filemap.h" + +#ifdef _MSC_VER +#include +#endif + +#ifdef _POSIX_SOURCE +#include +#endif + +#ifndef O_BINARY +#ifdef _O_BINARY +#define O_BINARY _O_BINARY +#else +#define O_BINARY 0 +#endif +#endif + +#ifdef _DEBUG +#define READ_SIZE 16 +#else +#define READ_SIZE (1024*8) +#endif + + + +typedef struct { + XML_Parser parser; + int *retPtr; +} PROCESS_ARGS; + +static +void reportError(XML_Parser parser, const XML_Char *filename) +{ + int code = XML_GetErrorCode(parser); + const XML_Char *message = XML_ErrorString(code); + if (message) + ftprintf(stdout, T("%s:%d:%d: %s\n"), + filename, + XML_GetErrorLineNumber(parser), + XML_GetErrorColumnNumber(parser), + message); + else + ftprintf(stderr, T("%s: (unknown message %d)\n"), filename, code); +} + +static +void processFile(const void *data, + size_t size, + const XML_Char *filename, + void *args) +{ + XML_Parser parser = ((PROCESS_ARGS *)args)->parser; + int *retPtr = ((PROCESS_ARGS *)args)->retPtr; + if (!XML_Parse(parser, data, size, 1)) { + reportError(parser, filename); + *retPtr = 0; + } + else + *retPtr = 1; +} + +#ifdef WIN32 + +static +int isAsciiLetter(XML_Char c) +{ + return (T('a') <= c && c <= T('z')) || (T('A') <= c && c <= T('Z')); +} + +#endif /* WIN32 */ + +static +const XML_Char *resolveSystemId(const XML_Char *base, const XML_Char *systemId, XML_Char **toFree) +{ + XML_Char *s; + *toFree = 0; + if (!base + || *systemId == T('/') +#ifdef WIN32 + || *systemId == T('\\') + || (isAsciiLetter(systemId[0]) && systemId[1] == T(':')) +#endif + ) + return systemId; + *toFree = (XML_Char *)malloc((tcslen(base) + tcslen(systemId) + 2)*sizeof(XML_Char)); + if (!*toFree) + return systemId; + tcscpy(*toFree, base); + s = *toFree; + if (tcsrchr(s, T('/'))) + s = tcsrchr(s, T('/')) + 1; +#ifdef WIN32 + if (tcsrchr(s, T('\\'))) + s = tcsrchr(s, T('\\')) + 1; +#endif + tcscpy(s, systemId); + return *toFree; +} + +static +int externalEntityRefFilemap(XML_Parser parser, + const XML_Char *context, + const XML_Char *base, + const XML_Char *systemId, + const XML_Char *publicId) +{ + int result; + XML_Char *s; + const XML_Char *filename; + XML_Parser entParser = XML_ExternalEntityParserCreate(parser, context, 0); + PROCESS_ARGS args; + args.retPtr = &result; + args.parser = entParser; + filename = resolveSystemId(base, systemId, &s); + XML_SetBase(entParser, filename); + if (!filemap(filename, processFile, &args)) + result = 0; + free(s); + XML_ParserFree(entParser); + return result; +} + +static +int processStream(const XML_Char *filename, XML_Parser parser) +{ + int fd = topen(filename, O_BINARY|O_RDONLY); + if (fd < 0) { + tperror(filename); + return 0; + } + for (;;) { + int nread; + char *buf = XML_GetBuffer(parser, READ_SIZE); + if (!buf) { + close(fd); + ftprintf(stderr, T("%s: out of memory\n"), filename); + return 0; + } + nread = read(fd, buf, READ_SIZE); + if (nread < 0) { + tperror(filename); + close(fd); + return 0; + } + if (!XML_ParseBuffer(parser, nread, nread == 0)) { + reportError(parser, filename); + close(fd); + return 0; + } + if (nread == 0) { + close(fd); + break;; + } + } + return 1; +} + +static +int externalEntityRefStream(XML_Parser parser, + const XML_Char *context, + const XML_Char *base, + const XML_Char *systemId, + const XML_Char *publicId) +{ + XML_Char *s; + const XML_Char *filename; + int ret; + XML_Parser entParser = XML_ExternalEntityParserCreate(parser, context, 0); + filename = resolveSystemId(base, systemId, &s); + XML_SetBase(entParser, filename); + ret = processStream(filename, entParser); + free(s); + XML_ParserFree(entParser); + return ret; +} + +int XML_ProcessFile(XML_Parser parser, + const XML_Char *filename, + unsigned flags) +{ + int result; + + if (!XML_SetBase(parser, filename)) { + ftprintf(stderr, T("%s: out of memory"), filename); + exit(1); + } + + if (flags & XML_EXTERNAL_ENTITIES) + XML_SetExternalEntityRefHandler(parser, + (flags & XML_MAP_FILE) + ? externalEntityRefFilemap + : externalEntityRefStream); + if (flags & XML_MAP_FILE) { + PROCESS_ARGS args; + args.retPtr = &result; + args.parser = parser; + if (!filemap(filename, processFile, &args)) + result = 0; + } + else + result = processStream(filename, parser); + return result; +} diff --git a/lib/expat/xmlwf/xmlfile.h b/lib/expat/xmlwf/xmlfile.h new file mode 100644 index 0000000..0c7ac19 --- /dev/null +++ b/lib/expat/xmlwf/xmlfile.h @@ -0,0 +1,11 @@ +/* +Copyright (c) 1998, 1999 Thai Open Source Software Center Ltd +See the file copying.txt for copying permission. +*/ + +#define XML_MAP_FILE 01 +#define XML_EXTERNAL_ENTITIES 02 + +extern int XML_ProcessFile(XML_Parser parser, + const XML_Char *filename, + unsigned flags); diff --git a/lib/expat/xmlwf/xmltchar.h b/lib/expat/xmlwf/xmltchar.h new file mode 100644 index 0000000..1088575 --- /dev/null +++ b/lib/expat/xmlwf/xmltchar.h @@ -0,0 +1,36 @@ +#ifdef XML_UNICODE +#ifndef XML_UNICODE_WCHAR_T +#error xmlwf requires a 16-bit Unicode-compatible wchar_t +#endif +#define T(x) L ## x +#define ftprintf fwprintf +#define tfopen _wfopen +#define fputts fputws +#define puttc putwc +#define tcscmp wcscmp +#define tcscpy wcscpy +#define tcscat wcscat +#define tcschr wcschr +#define tcsrchr wcsrchr +#define tcslen wcslen +#define tperror _wperror +#define topen _wopen +#define tmain wmain +#define tremove _wremove +#else /* not XML_UNICODE */ +#define T(x) x +#define ftprintf fprintf +#define tfopen fopen +#define fputts fputs +#define puttc putc +#define tcscmp strcmp +#define tcscpy strcpy +#define tcscat strcat +#define tcschr strchr +#define tcsrchr strrchr +#define tcslen strlen +#define tperror perror +#define topen open +#define tmain main +#define tremove remove +#endif /* not XML_UNICODE */ diff --git a/lib/expat/xmlwf/xmlwf.c b/lib/expat/xmlwf/xmlwf.c new file mode 100644 index 0000000..2b8fe12 --- /dev/null +++ b/lib/expat/xmlwf/xmlwf.c @@ -0,0 +1,766 @@ +/* +Copyright (c) 1998, 1999 Thai Open Source Software Center Ltd +See the file copying.txt for copying permission. +*/ + +#include +#include +#include +#include + +#include "xmlparse.h" +#include "codepage.h" +#include "xmlfile.h" +#include "xmltchar.h" + +#ifdef _MSC_VER +#include +#endif + +/* This ensures proper sorting. */ + +#define NSSEP T('\001') + +static void characterData(void *userData, const XML_Char *s, int len) +{ + FILE *fp = userData; + for (; len > 0; --len, ++s) { + switch (*s) { + case T('&'): + fputts(T("&"), fp); + break; + case T('<'): + fputts(T("<"), fp); + break; + case T('>'): + fputts(T(">"), fp); + break; +#ifdef W3C14N + case 13: + fputts(T(" "), fp); + break; +#else + case T('"'): + fputts(T("""), fp); + break; + case 9: + case 10: + case 13: + ftprintf(fp, T("&#%d;"), *s); + break; +#endif + default: + puttc(*s, fp); + break; + } + } +} + +static void attributeValue(FILE *fp, const XML_Char *s) +{ + puttc(T('='), fp); + puttc(T('"'), fp); + for (;;) { + switch (*s) { + case 0: + case NSSEP: + puttc(T('"'), fp); + return; + case T('&'): + fputts(T("&"), fp); + break; + case T('<'): + fputts(T("<"), fp); + break; + case T('"'): + fputts(T("""), fp); + break; +#ifdef W3C14N + case 9: + fputts(T(" "), fp); + break; + case 10: + fputts(T(" "), fp); + break; + case 13: + fputts(T(" "), fp); + break; +#else + case T('>'): + fputts(T(">"), fp); + break; + case 9: + case 10: + case 13: + ftprintf(fp, T("&#%d;"), *s); + break; +#endif + default: + puttc(*s, fp); + break; + } + s++; + } +} + +/* Lexicographically comparing UTF-8 encoded attribute values, +is equivalent to lexicographically comparing based on the character number. */ + +static int attcmp(const void *att1, const void *att2) +{ + return tcscmp(*(const XML_Char **)att1, *(const XML_Char **)att2); +} + +static void startElement(void *userData, const XML_Char *name, const XML_Char **atts) +{ + int nAtts; + const XML_Char **p; + FILE *fp = userData; + puttc(T('<'), fp); + fputts(name, fp); + + p = atts; + while (*p) + ++p; + nAtts = (p - atts) >> 1; + if (nAtts > 1) + qsort((void *)atts, nAtts, sizeof(XML_Char *) * 2, attcmp); + while (*atts) { + puttc(T(' '), fp); + fputts(*atts++, fp); + attributeValue(fp, *atts); + atts++; + } + puttc(T('>'), fp); +} + +static void endElement(void *userData, const XML_Char *name) +{ + FILE *fp = userData; + puttc(T('<'), fp); + puttc(T('/'), fp); + fputts(name, fp); + puttc(T('>'), fp); +} + +static int nsattcmp(const void *p1, const void *p2) +{ + const XML_Char *att1 = *(const XML_Char **)p1; + const XML_Char *att2 = *(const XML_Char **)p2; + int sep1 = (tcsrchr(att1, NSSEP) != 0); + int sep2 = (tcsrchr(att1, NSSEP) != 0); + if (sep1 != sep2) + return sep1 - sep2; + return tcscmp(att1, att2); +} + +static void startElementNS(void *userData, const XML_Char *name, const XML_Char **atts) +{ + int nAtts; + int nsi; + const XML_Char **p; + FILE *fp = userData; + const XML_Char *sep; + puttc(T('<'), fp); + + sep = tcsrchr(name, NSSEP); + if (sep) { + fputts(T("n1:"), fp); + fputts(sep + 1, fp); + fputts(T(" xmlns:n1"), fp); + attributeValue(fp, name); + nsi = 2; + } + else { + fputts(name, fp); + nsi = 1; + } + + p = atts; + while (*p) + ++p; + nAtts = (p - atts) >> 1; + if (nAtts > 1) + qsort((void *)atts, nAtts, sizeof(XML_Char *) * 2, nsattcmp); + while (*atts) { + name = *atts++; + sep = tcsrchr(name, NSSEP); + puttc(T(' '), fp); + if (sep) { + ftprintf(fp, T("n%d:"), nsi); + fputts(sep + 1, fp); + } + else + fputts(name, fp); + attributeValue(fp, *atts); + if (sep) { + ftprintf(fp, T(" xmlns:n%d"), nsi++); + attributeValue(fp, name); + } + atts++; + } + puttc(T('>'), fp); +} + +static void endElementNS(void *userData, const XML_Char *name) +{ + FILE *fp = userData; + const XML_Char *sep; + puttc(T('<'), fp); + puttc(T('/'), fp); + sep = tcsrchr(name, NSSEP); + if (sep) { + fputts(T("n1:"), fp); + fputts(sep + 1, fp); + } + else + fputts(name, fp); + puttc(T('>'), fp); +} + +#ifndef W3C14N + +static void processingInstruction(void *userData, const XML_Char *target, const XML_Char *data) +{ + FILE *fp = userData; + puttc(T('<'), fp); + puttc(T('?'), fp); + fputts(target, fp); + puttc(T(' '), fp); + fputts(data, fp); + puttc(T('?'), fp); + puttc(T('>'), fp); +} + +#endif /* not W3C14N */ + +static void defaultCharacterData(XML_Parser parser, const XML_Char *s, int len) +{ + XML_DefaultCurrent(parser); +} + +static void defaultStartElement(XML_Parser parser, const XML_Char *name, const XML_Char **atts) +{ + XML_DefaultCurrent(parser); +} + +static void defaultEndElement(XML_Parser parser, const XML_Char *name) +{ + XML_DefaultCurrent(parser); +} + +static void defaultProcessingInstruction(XML_Parser parser, const XML_Char *target, const XML_Char *data) +{ + XML_DefaultCurrent(parser); +} + +static void nopCharacterData(XML_Parser parser, const XML_Char *s, int len) +{ +} + +static void nopStartElement(XML_Parser parser, const XML_Char *name, const XML_Char **atts) +{ +} + +static void nopEndElement(XML_Parser parser, const XML_Char *name) +{ +} + +static void nopProcessingInstruction(XML_Parser parser, const XML_Char *target, const XML_Char *data) +{ +} + +static void markup(XML_Parser parser, const XML_Char *s, int len) +{ + FILE *fp = XML_GetUserData(parser); + for (; len > 0; --len, ++s) + puttc(*s, fp); +} + +static +void metaLocation(XML_Parser parser) +{ + const XML_Char *uri = XML_GetBase(parser); + if (uri) + ftprintf(XML_GetUserData(parser), T(" uri=\"%s\""), uri); + ftprintf(XML_GetUserData(parser), + T(" byte=\"%ld\" nbytes=\"%d\" line=\"%d\" col=\"%d\""), + XML_GetCurrentByteIndex(parser), + XML_GetCurrentByteCount(parser), + XML_GetCurrentLineNumber(parser), + XML_GetCurrentColumnNumber(parser)); +} + +static +void metaStartDocument(XML_Parser parser) +{ + fputts(T("\n"), XML_GetUserData(parser)); +} + +static +void metaEndDocument(XML_Parser parser) +{ + fputts(T("\n"), XML_GetUserData(parser)); +} + +static +void metaStartElement(XML_Parser parser, const XML_Char *name, const XML_Char **atts) +{ + FILE *fp = XML_GetUserData(parser); + const XML_Char **specifiedAttsEnd + = atts + XML_GetSpecifiedAttributeCount(parser); + const XML_Char **idAttPtr; + int idAttIndex = XML_GetIdAttributeIndex(parser); + if (idAttIndex < 0) + idAttPtr = 0; + else + idAttPtr = atts + idAttIndex; + + ftprintf(fp, T("\n"), fp); + do { + ftprintf(fp, T("= specifiedAttsEnd) + fputts(T("\" defaulted=\"yes\"/>\n"), fp); + else if (atts == idAttPtr) + fputts(T("\" id=\"yes\"/>\n"), fp); + else + fputts(T("\"/>\n"), fp); + } while (*(atts += 2)); + fputts(T("\n"), fp); + } + else + fputts(T("/>\n"), fp); +} + +static +void metaEndElement(XML_Parser parser, const XML_Char *name) +{ + FILE *fp = XML_GetUserData(parser); + ftprintf(fp, T("\n"), fp); +} + +static +void metaProcessingInstruction(XML_Parser parser, const XML_Char *target, const XML_Char *data) +{ + FILE *fp = XML_GetUserData(parser); + ftprintf(fp, T("\n"), fp); +} + +static +void metaComment(XML_Parser parser, const XML_Char *data) +{ + FILE *fp = XML_GetUserData(parser); + fputts(T("\n"), fp); +} + +static +void metaStartCdataSection(XML_Parser parser) +{ + FILE *fp = XML_GetUserData(parser); + fputts(T("\n"), fp); +} + +static +void metaEndCdataSection(XML_Parser parser) +{ + FILE *fp = XML_GetUserData(parser); + fputts(T("\n"), fp); +} + +static +void metaCharacterData(XML_Parser parser, const XML_Char *s, int len) +{ + FILE *fp = XML_GetUserData(parser); + fputts(T("\n"), fp); +} + +static +void metaStartDoctypeDecl(XML_Parser parser, const XML_Char *doctypeName) +{ + FILE *fp = XML_GetUserData(parser); + ftprintf(fp, T("\n"), fp); +} + +static +void metaEndDoctypeDecl(XML_Parser parser) +{ + FILE *fp = XML_GetUserData(parser); + fputts(T("\n"), fp); +} + +static +void metaUnparsedEntityDecl(XML_Parser parser, + const XML_Char *entityName, + const XML_Char *base, + const XML_Char *systemId, + const XML_Char *publicId, + const XML_Char *notationName) +{ + FILE *fp = XML_GetUserData(parser); + ftprintf(fp, T("\n"), fp); +} + +static +void metaNotationDecl(XML_Parser parser, + const XML_Char *notationName, + const XML_Char *base, + const XML_Char *systemId, + const XML_Char *publicId) +{ + FILE *fp = XML_GetUserData(parser); + ftprintf(fp, T("\n"), fp); +} + + +static +void metaExternalParsedEntityDecl(XML_Parser parser, + const XML_Char *entityName, + const XML_Char *base, + const XML_Char *systemId, + const XML_Char *publicId) +{ + FILE *fp = XML_GetUserData(parser); + ftprintf(fp, T("\n"), fp); +} + +static +void metaInternalParsedEntityDecl(XML_Parser parser, + const XML_Char *entityName, + const XML_Char *text, + int textLen) +{ + FILE *fp = XML_GetUserData(parser); + ftprintf(fp, T("'), fp); + characterData(fp, text, textLen); + fputts(T("\n"), fp); +} + +static +void metaStartNamespaceDecl(XML_Parser parser, + const XML_Char *prefix, + const XML_Char *uri) +{ + FILE *fp = XML_GetUserData(parser); + fputts(T("\n"), fp); + } + else + fputts(T("/>\n"), fp); +} + +static +void metaEndNamespaceDecl(XML_Parser parser, const XML_Char *prefix) +{ + FILE *fp = XML_GetUserData(parser); + if (!prefix) + fputts(T("\n"), fp); + else + ftprintf(fp, T("\n"), prefix); +} + +static +int unknownEncodingConvert(void *data, const char *p) +{ + return codepageConvert(*(int *)data, p); +} + +static +int unknownEncoding(void *userData, + const XML_Char *name, + XML_Encoding *info) +{ + int cp; + static const XML_Char prefixL[] = T("windows-"); + static const XML_Char prefixU[] = T("WINDOWS-"); + int i; + + for (i = 0; prefixU[i]; i++) + if (name[i] != prefixU[i] && name[i] != prefixL[i]) + return 0; + + cp = 0; + for (; name[i]; i++) { + static const XML_Char digits[] = T("0123456789"); + const XML_Char *s = tcschr(digits, name[i]); + if (!s) + return 0; + cp *= 10; + cp += s - digits; + if (cp >= 0x10000) + return 0; + } + if (!codepageMap(cp, info->map)) + return 0; + info->convert = unknownEncodingConvert; + /* We could just cast the code page integer to a void *, + and avoid the use of release. */ + info->release = free; + info->data = malloc(sizeof(int)); + if (!info->data) + return 0; + *(int *)info->data = cp; + return 1; +} + +static +int notStandalone(void *userData) +{ + return 0; +} + +static +void usage(const XML_Char *prog) +{ + ftprintf(stderr, T("usage: %s [-n] [-p] [-r] [-s] [-w] [-x] [-d output-dir] [-e encoding] file ...\n"), prog); + exit(1); +} + +int tmain(int argc, XML_Char **argv) +{ + int i, j; + const XML_Char *outputDir = 0; + const XML_Char *encoding = 0; + unsigned processFlags = XML_MAP_FILE; + int windowsCodePages = 0; + int outputType = 0; + int useNamespaces = 0; + int requireStandalone = 0; + int paramEntityParsing = XML_PARAM_ENTITY_PARSING_NEVER; + +#ifdef _MSC_VER + _CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF|_CRTDBG_LEAK_CHECK_DF); +#endif + + i = 1; + j = 0; + while (i < argc) { + if (j == 0) { + if (argv[i][0] != T('-')) + break; + if (argv[i][1] == T('-') && argv[i][2] == T('\0')) { + i++; + break; + } + j++; + } + switch (argv[i][j]) { + case T('r'): + processFlags &= ~XML_MAP_FILE; + j++; + break; + case T('s'): + requireStandalone = 1; + j++; + break; + case T('n'): + useNamespaces = 1; + j++; + break; + case T('p'): + paramEntityParsing = XML_PARAM_ENTITY_PARSING_ALWAYS; + /* fall through */ + case T('x'): + processFlags |= XML_EXTERNAL_ENTITIES; + j++; + break; + case T('w'): + windowsCodePages = 1; + j++; + break; + case T('m'): + outputType = 'm'; + j++; + break; + case T('c'): + outputType = 'c'; + useNamespaces = 0; + j++; + break; + case T('t'): + outputType = 't'; + j++; + break; + case T('d'): + if (argv[i][j + 1] == T('\0')) { + if (++i == argc) + usage(argv[0]); + outputDir = argv[i]; + } + else + outputDir = argv[i] + j + 1; + i++; + j = 0; + break; + case T('e'): + if (argv[i][j + 1] == T('\0')) { + if (++i == argc) + usage(argv[0]); + encoding = argv[i]; + } + else + encoding = argv[i] + j + 1; + i++; + j = 0; + break; + case T('\0'): + if (j > 1) { + i++; + j = 0; + break; + } + /* fall through */ + default: + usage(argv[0]); + } + } + if (i == argc) + usage(argv[0]); + for (; i < argc; i++) { + FILE *fp = 0; + XML_Char *outName = 0; + int result; + XML_Parser parser; + if (useNamespaces) + parser = XML_ParserCreateNS(encoding, NSSEP); + else + parser = XML_ParserCreate(encoding); + if (requireStandalone) + XML_SetNotStandaloneHandler(parser, notStandalone); + XML_SetParamEntityParsing(parser, paramEntityParsing); + if (outputType == 't') { + /* This is for doing timings; this gives a more realistic estimate of + the parsing time. */ + outputDir = 0; + XML_SetElementHandler(parser, nopStartElement, nopEndElement); + XML_SetCharacterDataHandler(parser, nopCharacterData); + XML_SetProcessingInstructionHandler(parser, nopProcessingInstruction); + } + else if (outputDir) { + const XML_Char *file = argv[i]; + if (tcsrchr(file, T('/'))) + file = tcsrchr(file, T('/')) + 1; +#ifdef WIN32 + if (tcsrchr(file, T('\\'))) + file = tcsrchr(file, T('\\')) + 1; +#endif + outName = malloc((tcslen(outputDir) + tcslen(file) + 2) * sizeof(XML_Char)); + tcscpy(outName, outputDir); + tcscat(outName, T("/")); + tcscat(outName, file); + fp = tfopen(outName, T("wb")); + if (!fp) { + tperror(outName); + exit(1); + } + setvbuf(fp, NULL, _IOFBF, 16384); +#ifdef XML_UNICODE + puttc(0xFEFF, fp); +#endif + XML_SetUserData(parser, fp); + switch (outputType) { + case 'm': + XML_UseParserAsHandlerArg(parser); + XML_SetElementHandler(parser, metaStartElement, metaEndElement); + XML_SetProcessingInstructionHandler(parser, metaProcessingInstruction); + XML_SetCommentHandler(parser, metaComment); + XML_SetCdataSectionHandler(parser, metaStartCdataSection, metaEndCdataSection); + XML_SetCharacterDataHandler(parser, metaCharacterData); + XML_SetDoctypeDeclHandler(parser, metaStartDoctypeDecl, metaEndDoctypeDecl); + XML_SetUnparsedEntityDeclHandler(parser, metaUnparsedEntityDecl); + XML_SetNotationDeclHandler(parser, metaNotationDecl); + XML_SetExternalParsedEntityDeclHandler(parser, metaExternalParsedEntityDecl); + XML_SetInternalParsedEntityDeclHandler(parser, metaInternalParsedEntityDecl); + XML_SetNamespaceDeclHandler(parser, metaStartNamespaceDecl, metaEndNamespaceDecl); + metaStartDocument(parser); + break; + case 'c': + XML_UseParserAsHandlerArg(parser); + XML_SetDefaultHandler(parser, markup); + XML_SetElementHandler(parser, defaultStartElement, defaultEndElement); + XML_SetCharacterDataHandler(parser, defaultCharacterData); + XML_SetProcessingInstructionHandler(parser, defaultProcessingInstruction); + break; + default: + if (useNamespaces) + XML_SetElementHandler(parser, startElementNS, endElementNS); + else + XML_SetElementHandler(parser, startElement, endElement); + XML_SetCharacterDataHandler(parser, characterData); +#ifndef W3C14N + XML_SetProcessingInstructionHandler(parser, processingInstruction); +#endif /* not W3C14N */ + break; + } + } + if (windowsCodePages) + XML_SetUnknownEncodingHandler(parser, unknownEncoding, 0); + result = XML_ProcessFile(parser, argv[i], processFlags); + if (outputDir) { + if (outputType == 'm') + metaEndDocument(parser); + fclose(fp); + if (!result) + tremove(outName); + free(outName); + } + XML_ParserFree(parser); + } + return 0; +} diff --git a/lib/expat/xmlwf/xmlwf.dsp b/lib/expat/xmlwf/xmlwf.dsp new file mode 100644 index 0000000..1ca4f42 --- /dev/null +++ b/lib/expat/xmlwf/xmlwf.dsp @@ -0,0 +1,136 @@ +# Microsoft Developer Studio Project File - Name="xmlwf" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + +CFG=xmlwf - Win32 Release +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "xmlwf.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "xmlwf.mak" CFG="xmlwf - Win32 Release" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "xmlwf - Win32 Release" (based on "Win32 (x86) Console Application") +!MESSAGE "xmlwf - Win32 Debug" (based on "Win32 (x86) Console Application") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "xmlwf - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir ".\Release" +# PROP BASE Intermediate_Dir ".\Release" +# PROP BASE Target_Dir "." +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir ".\Release" +# PROP Intermediate_Dir ".\Release" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "." +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /YX /c +# ADD CPP /nologo /W3 /GX /O2 /I "..\xmlparse" /D "NDEBUG" /D "WIN32" /D "_CONSOLE" /D XMLTOKAPI=__declspec(dllimport) /D XMLPARSEAPI=__declspec(dllimport) /YX /FD /c +# ADD BASE RSC /l 0x809 /d "NDEBUG" +# ADD RSC /l 0x809 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 +# ADD LINK32 setargv.obj kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 /out:"..\bin\xmlwf.exe" + +!ELSEIF "$(CFG)" == "xmlwf - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir ".\Debug" +# PROP BASE Intermediate_Dir ".\Debug" +# PROP BASE Target_Dir "." +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir ".\Debug" +# PROP Intermediate_Dir ".\Debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "." +# ADD BASE CPP /nologo /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /YX /c +# ADD CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /I ".\xmlparse" /I "..\xmlparse" /D "_DEBUG" /D "WIN32" /D "_CONSOLE" /D XMLTOKAPI=__declspec(dllimport) /D XMLPARSEAPI=__declspec(dllimport) /YX /FD /c +# ADD BASE RSC /l 0x809 /d "_DEBUG" +# ADD RSC /l 0x809 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 +# ADD LINK32 setargv.obj kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /out:"..\dbgbin\xmlwf.exe" + +!ENDIF + +# Begin Target + +# Name "xmlwf - Win32 Release" +# Name "xmlwf - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat;for;f90" +# Begin Source File + +SOURCE=.\codepage.c +# End Source File +# Begin Source File + +SOURCE=.\readfilemap.c +# PROP Exclude_From_Build 1 +# End Source File +# Begin Source File + +SOURCE=.\unixfilemap.c +# PROP Exclude_From_Build 1 +# End Source File +# Begin Source File + +SOURCE=.\win32filemap.c +# End Source File +# Begin Source File + +SOURCE=.\xmlfile.c +# End Source File +# Begin Source File + +SOURCE=.\xmlwf.c +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl;fi;fd" +# Begin Source File + +SOURCE=.\codepage.h +# End Source File +# Begin Source File + +SOURCE=.\xmlfile.h +# End Source File +# Begin Source File + +SOURCE=.\xmltchar.h +# End Source File +# End Group +# Begin Group "Resource Files" + +# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;cnt;rtf;gif;jpg;jpeg;jpe" +# End Group +# End Target +# End Project diff --git a/lib/libutil/Makefile b/lib/libutil/Makefile new file mode 100644 index 0000000..aff219d --- /dev/null +++ b/lib/libutil/Makefile @@ -0,0 +1,71 @@ +############################################################################### +# This directory builds libxmlrpc_util, which contains utility +# functions that are used by the Xmlprc-c # libraries, and also +# directly by Xmlrpc-c programs. +# +# The functions in this library are characterized by being general purpose +# programming functions, such as one might wish were in the standard C +# library, which have nothing in particular to do with XML-RPC. +############################################################################### + +ifeq ($(SRCDIR)x,x) +SRCDIR = $(CURDIR)/../.. +endif +SUBDIR = lib/libutil +# BLDDIR is for use in places where a symbolic link won't work. +# BUILDDIR is for places in Makefile.common that can use the 'blddir' +# symbolic link (but in other directories, doesn't). +BLDDIR = ../.. +BUILDDIR = blddir +VPATH = .:$(SRCDIR) + +include $(BLDDIR)/Makefile.config + +default: all + +all: libxmlrpc_util.la + +LIBXMLRPC_UTIL_OBJS = \ + casprintf.lo \ + error.lo \ + make_printable.lo \ + memblock.lo \ + resource.lo \ + sleep.lo \ + +INCLUDES = -Iblddir -I$(SRCDIR) \ + -Isrcdir/include -Isrcdir/lib/util/include + +LDFLAGS = $(LADD) + +LIBLDFLAGS = $(LDFLAGS_VERSINFO) -rpath $(LIBINST_DIR) $(LADD) + +libxmlrpc_util.la: $(LIBXMLRPC_UTIL_OBJS) + $(LIBTOOL) --mode=link $(CCLD) -o $@ $(LIBLDFLAGS) $^ + +CFLAGS = $(CFLAGS_COMMON) $(CFLAGS_PERSONAL) $(CADD) + +$(LIBXMLRPC_UTIL_OBJS):%.lo:%.c + $(LIBTOOL) --mode=compile $(CC) -c $(INCLUDES) $(CFLAGS) $< + +LTLIBRARIES_TO_INSTALL = libxmlrpc_util.la + +.PHONY: install +install: install-common + +.PHONY: clean distclean +clean: clean-common + +distclean: clean distclean-common + +.PHONY: dep +dep: dep-common + +# This 'Makefile.common' dependency makes sure the symlinks get built before +# this make file is used for anything. + +$(SRCDIR)/Makefile.common: srcdir blddir + +include $(SRCDIR)/Makefile.common + +include Makefile.depend diff --git a/lib/libutil/Makefile.depend b/lib/libutil/Makefile.depend new file mode 100644 index 0000000..e69de29 diff --git a/lib/libutil/casprintf.c b/lib/libutil/casprintf.c new file mode 100644 index 0000000..45a8e0e --- /dev/null +++ b/lib/libutil/casprintf.c @@ -0,0 +1,93 @@ +#define _GNU_SOURCE +#include +#include +#include + +#include "xmlrpc_config.h" /* For HAVE_ASPRINTF, __inline__ */ +#include "xmlrpc-c/string_int.h" + + + +static __inline__ void +simpleVasprintf(char ** const retvalP, + const char * const fmt, + va_list varargs) { +/*---------------------------------------------------------------------------- + This is a poor man's implementation of vasprintf(), of GNU fame. +-----------------------------------------------------------------------------*/ + size_t const initialSize = 4096; + char * result; + + result = malloc(initialSize); + if (result != NULL) { + size_t bytesNeeded; + bytesNeeded = vsnprintf(result, initialSize, fmt, varargs); + if (bytesNeeded > initialSize) { + free(result); + result = malloc(bytesNeeded); + if (result != NULL) + vsnprintf(result, bytesNeeded, fmt, varargs); + } else if (bytesNeeded == initialSize) { + if (result[initialSize-1] != '\0') { + /* This is one of those old systems where vsnprintf() + returns the number of bytes it used, instead of the + number that it needed, and it in fact needed more than + we gave it. Rather than mess with this highly unlikely + case (old system and string > 4095 characters), we just + treat this like an out of memory failure. + */ + free(result); + result = NULL; + } + } + } + *retvalP = result; +} + + + +const char * const xmlrpc_strsol = "[insufficient memory to build string]"; + + + +void +xmlrpc_vasprintf(const char ** const retvalP, + const char * const fmt, + va_list varargs) { + + char * string; + +#if HAVE_ASPRINTF + vasprintf(&string, fmt, varargs); +#else + simpleVasprintf(&string, fmt, varargs); +#endif + + if (string == NULL) + *retvalP = xmlrpc_strsol; + else + *retvalP = string; +} + + + +void GNU_PRINTF_ATTR(2,3) +xmlrpc_asprintf(const char ** const retvalP, const char * const fmt, ...) { + + va_list varargs; /* mysterious structure used by variable arg facility */ + + va_start(varargs, fmt); /* start up the mysterious variable arg facility */ + + xmlrpc_vasprintf(retvalP, fmt, varargs); + + va_end(varargs); +} + + + +void +xmlrpc_strfree(const char * const string) { + + if (string != xmlrpc_strsol) + free((void *)string); +} diff --git a/lib/libutil/error.c b/lib/libutil/error.c new file mode 100644 index 0000000..eec5185 --- /dev/null +++ b/lib/libutil/error.c @@ -0,0 +1,158 @@ +/* Copyright information is at end of file */ + +#include "xmlrpc_config.h" + +#include +#include +#include +#include + +#include "xmlrpc-c/util_int.h" +#include "xmlrpc-c/util.h" + + +#define ERROR_BUFFER_SZ (256) + +void +xmlrpc_assertion_failed(const char * const fileName, + int const lineNumber) { + + fprintf(stderr, "%s:%d: assertion failed\n", fileName, lineNumber); + abort(); +} + + + +static const char * const default_fault_string = + "Not enough memory for error message"; + +void xmlrpc_env_init (xmlrpc_env* env) +{ + XMLRPC_ASSERT(env != NULL); + + env->fault_occurred = 0; + env->fault_code = 0; + env->fault_string = NULL; +} + +void +xmlrpc_env_clean(xmlrpc_env * const envP) { + + XMLRPC_ASSERT(envP != NULL); + XMLRPC_ASSERT(envP->fault_string != XMLRPC_BAD_POINTER); + + /* env->fault_string may be one of three things: + ** 1) a NULL pointer + ** 2) a pointer to the default_fault_string + ** 3) a pointer to a malloc'd fault string + ** If we have case (3), we'll need to free it. */ + if (envP->fault_string && envP->fault_string != default_fault_string) + free(envP->fault_string); + envP->fault_string = XMLRPC_BAD_POINTER; +} + + + +void +xmlrpc_env_set_fault(xmlrpc_env * const envP, + int const faultCode, + const char * const faultDescription) { + + XMLRPC_ASSERT(envP != NULL); + XMLRPC_ASSERT(faultDescription != NULL); + + /* Clean up any leftover pointers. */ + xmlrpc_env_clean(envP); + + envP->fault_occurred = 1; + envP->fault_code = faultCode; + + /* Try to copy the fault string. If this fails, use a default. */ + envP->fault_string = strdup(faultDescription); + if (envP->fault_string == NULL) + envP->fault_string = (char *)default_fault_string; +} + + + +static void +set_fault_formatted_v(xmlrpc_env * const envP, + int const code, + const char * const format, + va_list const args) { + + char buffer[ERROR_BUFFER_SZ]; + + vsnprintf(buffer, ERROR_BUFFER_SZ, format, args); + + /* vsnprintf is guaranteed to terminate the buffer, but we're paranoid. */ + buffer[ERROR_BUFFER_SZ - 1] = '\0'; + + /* Set the fault. */ + xmlrpc_env_set_fault(envP, code, buffer); +} + + + +void +xmlrpc_env_set_fault_formatted(xmlrpc_env * const envP, + int const code, + const char * const format, + ...) { + va_list args; + + XMLRPC_ASSERT(envP != NULL); + XMLRPC_ASSERT(format != NULL); + + /* Print our error message to the buffer. */ + va_start(args, format); + set_fault_formatted_v(envP, code, format, args); + va_end(args); +} + + + +void +xmlrpc_faultf(xmlrpc_env * const envP, + const char * const format, + ...) { + + va_list args; + + XMLRPC_ASSERT(envP != NULL); + XMLRPC_ASSERT(format != NULL); + + /* Print our error message to the buffer. */ + va_start(args, format); + set_fault_formatted_v(envP, XMLRPC_INTERNAL_ERROR, format, args); + va_end(args); + +} + + + +/* Copyright (C) 2001 by First Peer, Inc. All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +** ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +** OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +** HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +** LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +** OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +** SUCH DAMAGE. */ + diff --git a/lib/libutil/make_printable.c b/lib/libutil/make_printable.c new file mode 100644 index 0000000..8caf4da --- /dev/null +++ b/lib/libutil/make_printable.c @@ -0,0 +1,100 @@ +#define _GNU_SOURCE + +#include +#include +#include +#include +#include + +#include "xmlrpc_config.h" +#include "xmlrpc-c/string_int.h" + + + +const char * +xmlrpc_makePrintable_lp(const char * const input, + size_t const inputLength) { +/*---------------------------------------------------------------------------- + Convert an arbitrary string of characters in length-pointer form to + printable ASCII. E.g. convert newlines to "\n". + + Return the result in newly malloc'ed storage. Return NULL if we can't + get the storage. +-----------------------------------------------------------------------------*/ + char * output; + + output = malloc(inputLength*4+1); + /* Worst case, we render a character like \x01 -- 4 characters */ + + if (output != NULL) { + unsigned int inputCursor, outputCursor; + + for (inputCursor = 0, outputCursor = 0; + inputCursor < inputLength; + ++inputCursor) { + + if (isprint(input[inputCursor])) + output[outputCursor++] = input[inputCursor]; + else if (input[inputCursor] == '\n') { + output[outputCursor++] = '\\'; + output[outputCursor++] = 'n'; + } else if (input[inputCursor] == '\t') { + output[outputCursor++] = '\\'; + output[outputCursor++] = 't'; + } else if (input[inputCursor] == '\a') { + output[outputCursor++] = '\\'; + output[outputCursor++] = 'a'; + } else if (input[inputCursor] == '\r') { + output[outputCursor++] = '\\'; + output[outputCursor++] = 'r'; + } else if (input[inputCursor] == '\\') { + output[outputCursor++] = '\\'; + output[outputCursor++] = '\\'; + } else { + snprintf(&output[outputCursor], 5, "\\x%02x", + input[inputCursor]); + outputCursor += 4; + } + } + output[outputCursor++] = '\0'; + } + return output; +} + + + +const char * +xmlrpc_makePrintable(const char * const input) { +/*---------------------------------------------------------------------------- + Convert an arbitrary string of characters (NUL-terminated, though) to + printable ASCII. E.g. convert newlines to "\n". + + Return the result in newly malloc'ed storage. Return NULL if we can't + get the storage. +-----------------------------------------------------------------------------*/ + return xmlrpc_makePrintable_lp(input, strlen(input)); +} + + + +const char * +xmlrpc_makePrintableChar(char const input) { +/*---------------------------------------------------------------------------- + Return an ASCIIZ string consisting of the character 'input', + properly escaped so as to be printable. E.g., in C notation, '\n' + turns into "\\n" +-----------------------------------------------------------------------------*/ + const char * retval; + + if (input == '\0') + retval = strdup("\\0"); + else { + char buffer[2]; + + buffer[0] = input; + buffer[1] = '\0'; + + retval = xmlrpc_makePrintable(buffer); + } + return retval; +} diff --git a/lib/libutil/memblock.c b/lib/libutil/memblock.c new file mode 100644 index 0000000..d79d4ca --- /dev/null +++ b/lib/libutil/memblock.c @@ -0,0 +1,214 @@ +/* Copyright information is at end of file */ +#include "xmlrpc_config.h" + +#include +#include +#include +#include + +#include "xmlrpc-c/util_int.h" +#include "xmlrpc-c/util.h" + +#ifdef EFENCE + /* when looking for corruption don't allocate extra slop */ +#define BLOCK_ALLOC_MIN (1) +#else +#define BLOCK_ALLOC_MIN (16) +#endif +#define BLOCK_ALLOC_MAX (128 * 1024 * 1024) + + +xmlrpc_mem_block * +xmlrpc_mem_block_new(xmlrpc_env * const env, + size_t const size) { + + xmlrpc_mem_block* block; + + XMLRPC_ASSERT_ENV_OK(env); + + block = (xmlrpc_mem_block*) malloc(sizeof(xmlrpc_mem_block)); + XMLRPC_FAIL_IF_NULL(block, env, XMLRPC_INTERNAL_ERROR, + "Can't allocate memory block"); + + xmlrpc_mem_block_init(env, block, size); + XMLRPC_FAIL_IF_FAULT(env); + + cleanup: + if (env->fault_occurred) { + if (block) + free(block); + return NULL; + } else { + return block; + } +} + +/* Destroy an existing xmlrpc_mem_block, and everything it contains. */ +void +xmlrpc_mem_block_free(xmlrpc_mem_block * const blockP) { + + XMLRPC_ASSERT(blockP != NULL); + XMLRPC_ASSERT(blockP->_block != NULL); + + xmlrpc_mem_block_clean(blockP); + free(blockP); +} + + + +/* Initialize the contents of the provided xmlrpc_mem_block. */ +void +xmlrpc_mem_block_init(xmlrpc_env * const envP, + xmlrpc_mem_block * const blockP, + size_t const size) { + + XMLRPC_ASSERT_ENV_OK(envP); + XMLRPC_ASSERT(blockP != NULL); + + blockP->_size = size; + if (size < BLOCK_ALLOC_MIN) + blockP->_allocated = BLOCK_ALLOC_MIN; + else + blockP->_allocated = size; + + blockP->_block = (void*) malloc(blockP->_allocated); + if (!blockP->_block) + xmlrpc_faultf(envP, "Can't allocate %u-byte memory block", + blockP->_allocated); +} + + + +/* Deallocate the contents of the provided xmlrpc_mem_block, but not + the block itself. +*/ +void +xmlrpc_mem_block_clean(xmlrpc_mem_block * const blockP) { + + XMLRPC_ASSERT(blockP != NULL); + XMLRPC_ASSERT(blockP->_block != NULL); + + free(blockP->_block); + blockP->_block = XMLRPC_BAD_POINTER; +} + + + +/* Get the size of the xmlrpc_mem_block. */ +size_t +xmlrpc_mem_block_size(const xmlrpc_mem_block * const blockP) { + + XMLRPC_ASSERT(blockP != NULL); + return blockP->_size; +} + + + +/* Get the contents of the xmlrpc_mem_block. */ +void * +xmlrpc_mem_block_contents(const xmlrpc_mem_block * const blockP) { + + XMLRPC_ASSERT(blockP != NULL); + return blockP->_block; +} + + + +/* Resize an xmlrpc_mem_block, preserving as much of the contents as + possible. +*/ +void +xmlrpc_mem_block_resize (xmlrpc_env * const envP, + xmlrpc_mem_block * const blockP, + size_t const size) { + + size_t proposed_alloc; + void* new_block; + + XMLRPC_ASSERT_ENV_OK(envP); + XMLRPC_ASSERT(blockP != NULL); + + /* Check to see if we already have enough space. Maybe we'll get lucky. */ + if (size <= blockP->_allocated) { + blockP->_size = size; + return; + } + + /* Calculate a new allocation size. */ +#ifdef EFENCE + proposed_alloc = size; +#else + proposed_alloc = blockP->_allocated; + while (proposed_alloc < size && proposed_alloc <= BLOCK_ALLOC_MAX) + proposed_alloc *= 2; +#endif /* DEBUG_MEM_ERRORS */ + + if (proposed_alloc > BLOCK_ALLOC_MAX) + XMLRPC_FAIL(envP, XMLRPC_INTERNAL_ERROR, "Memory block too large"); + + /* Allocate our new memory block. */ + new_block = (void*) malloc(proposed_alloc); + XMLRPC_FAIL_IF_NULL(new_block, envP, XMLRPC_INTERNAL_ERROR, + "Can't resize memory block"); + + /* Copy over our data and update the xmlrpc_mem_block struct. */ + memcpy(new_block, blockP->_block, blockP->_size); + free(blockP->_block); + blockP->_block = new_block; + blockP->_size = size; + blockP->_allocated = proposed_alloc; + + cleanup: + return; +} + + + +void +xmlrpc_mem_block_append(xmlrpc_env * const envP, + xmlrpc_mem_block * const blockP, + const void * const data, + size_t const len) { + + int size; + + XMLRPC_ASSERT_ENV_OK(envP); + XMLRPC_ASSERT(blockP != NULL); + + size = blockP->_size; + xmlrpc_mem_block_resize(envP, blockP, size + len); + XMLRPC_FAIL_IF_FAULT(envP); + + memcpy(((unsigned char*) blockP->_block) + size, data, len); + + cleanup: + return; +} + + + +/* Copyright (C) 2001 by First Peer, Inc. All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +** ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +** OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +** HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +** LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +** OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +** SUCH DAMAGE. +*/ diff --git a/lib/libutil/resource.c b/lib/libutil/resource.c new file mode 100644 index 0000000..08743d0 --- /dev/null +++ b/lib/libutil/resource.c @@ -0,0 +1,31 @@ +#include "xmlrpc_config.h" + +#include "xmlrpc-c/util.h" + + +/*========================================================================= +** Resource Limits +**========================================================================= +*/ + +static size_t limits[XMLRPC_LAST_LIMIT_ID + 1] = { + XMLRPC_NESTING_LIMIT_DEFAULT, + XMLRPC_XML_SIZE_LIMIT_DEFAULT +}; + +void +xmlrpc_limit_set (int const limit_id, + size_t const value) { + + XMLRPC_ASSERT(0 <= limit_id && limit_id <= XMLRPC_LAST_LIMIT_ID); + limits[limit_id] = value; +} + + + +size_t +xmlrpc_limit_get(int const limit_id) { + + XMLRPC_ASSERT(0 <= limit_id && limit_id <= XMLRPC_LAST_LIMIT_ID); + return limits[limit_id]; +} diff --git a/lib/libutil/sleep.c b/lib/libutil/sleep.c new file mode 100644 index 0000000..379be0c --- /dev/null +++ b/lib/libutil/sleep.c @@ -0,0 +1,18 @@ +#include "xmlrpc-c/sleep_int.h" + +#ifdef WIN32 +#include +#else +#include +#endif + + +void +xmlrpc_millisecond_sleep(unsigned int const milliseconds) { + +#ifdef WIN32 + Sleep(milliseconds); +#else + usleep(milliseconds * 1000); +#endif +} diff --git a/lib/libwww_transport/Makefile b/lib/libwww_transport/Makefile new file mode 100644 index 0000000..acfcd66 --- /dev/null +++ b/lib/libwww_transport/Makefile @@ -0,0 +1,45 @@ +ifeq ($(SRCDIR)x,x) +SRCDIR = $(CURDIR)/../.. +endif + +include $(SRCDIR)/Makefile.config + +LIBWWW_INCLUDES := $(shell libwww-config --cflags) + +CFLAGS = $(CFLAGS_COMMON) $(CFLAGS_PERSONAL) $(CADD) +LDFLAGS = $(LADD) + +INCLUDES = -I$(SRCDIR) -I$(SRCDIR)/include -I$(SRCDIR)/lib/util/include \ + $(LIBWWW_INCLUDES) + +default: all + +.PHONY: all +all: xmlrpc_libwww_transport.lo + +.PHONY: clean +clean: clean-common + +.PHONY: distclean +distclean: clean distclean-common + +.PHONY: tags +tags: TAGS + +.PHONY: distdir +distdir: + +.PHONY: install +install: + +.PHONY: dep +dep: dep-common + +include $(SRCDIR)/Makefile.common + +include Makefile.depend + +xmlrpc_libwww_transport.lo:%.lo:%.c + $(LIBTOOL) --mode=compile $(CC) -c $(INCLUDES) $(CFLAGS) $< + + diff --git a/lib/libwww_transport/Makefile.depend b/lib/libwww_transport/Makefile.depend new file mode 100644 index 0000000..e69de29 diff --git a/lib/libwww_transport/xmlrpc_libwww_transport.c b/lib/libwww_transport/xmlrpc_libwww_transport.c new file mode 100644 index 0000000..61d16ac --- /dev/null +++ b/lib/libwww_transport/xmlrpc_libwww_transport.c @@ -0,0 +1,937 @@ +/* Copyright (C) 2001 by First Peer, Inc. All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +** ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +** OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +** HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +** LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +** OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +** SUCH DAMAGE. */ + +#include "xmlrpc_config.h" + +#include + +#include "bool.h" +#include "mallocvar.h" + +#include "xmlrpc-c/base.h" +#include "xmlrpc-c/base_int.h" +#include "xmlrpc-c/string_int.h" +#include "xmlrpc-c/client.h" +#include "xmlrpc-c/client_int.h" + +/* The libwww interface */ + +/* These headers mistakenly define the macro PACKAGE. As + xmlrpc_config.h already defines PACKAGE according to the package we're + actually part of, this causes a conflict. So we undef here and then + to avoid possible problems with an incorrect PACKAGE, we undef it again + after. +*/ +#undef PACKAGE +#include "WWWLib.h" +#include "WWWHTTP.h" +#include "WWWInit.h" +#undef PACKAGE + +/* Include our libwww SSL headers, if available. */ +#if HAVE_LIBWWW_SSL +#include "WWWSSL.h" +#endif + +#include "xmlrpc_libwww_transport.h" + +/* This value was discovered by Rick Blair. His efforts shaved two seconds +** off of every request processed. Many thanks. */ +#define SMALLEST_LEGAL_LIBWWW_TIMEOUT (21) + +#define XMLRPC_CLIENT_USE_TIMEOUT (2) + + +struct xmlrpc_client_transport { + int saved_flags; + HTList *xmlrpc_conversions; + void * cookieJarP; + /* This is a collection of all the cookies that servers have set + via responses to prior requests. It's not implemented today. + */ + bool tracingOn; +}; + +static struct xmlrpc_client_transport clientTransport; + + +typedef struct { +/*---------------------------------------------------------------------------- + This object represents one RPC. +-----------------------------------------------------------------------------*/ + struct xmlrpc_client_transport * clientTransportP; + + /* These fields are used when performing synchronous calls. */ + bool is_done; + int http_status; + + /* Low-level information used by libwww. */ + HTRequest * request; + HTChunk * response_data; + HTParentAnchor * source_anchor; + HTAnchor * dest_anchor; + + xmlrpc_transport_asynch_complete complete; + struct xmlrpc_call_info * callInfoP; +} rpc; + + + +static void +createCookieJar(xmlrpc_env * const envP ATTR_UNUSED, + void ** const cookieJarP ATTR_UNUSED) { + + /* Cookies not implemented yet */ +} + + + +static void +destroyCookieJar(void * cookieJarP ATTR_UNUSED) { + + /* Cookies not implemented yet */ +} + + + +static void +initLibwww(const char * const appname, + const char * const appversion) { + + /* We initialize the library using a robot profile, because we don't + ** care about redirects or HTTP authentication, and we want to + ** reduce our application footprint as much as possible. */ + HTProfile_newRobot(appname, appversion); + + /* Ilya Goldberg provided the following code to access + ** SSL-protected servers. */ +#if HAVE_LIBWWW_SSL + /* Set the SSL protocol method. By default, it is the highest + ** available protocol. Setting it up to SSL_V23 allows the client + ** to negotiate with the server and set up either TSLv1, SSLv3, + ** or SSLv2 */ + HTSSL_protMethod_set(HTSSL_V23); + + /* Set the certificate verification depth to 2 in order to be able to + ** validate self-signed certificates */ + HTSSL_verifyDepth_set(2); + + /* Register SSL stuff for handling ssl access. The parameter we pass + ** is NO because we can't be pre-emptive with POST */ + HTSSLhttps_init(NO); +#endif /* HAVE_LIBWWW_SSL */ + + /* For interoperability with Frontier, we need to tell libwww *not* + ** to send 'Expect: 100-continue' headers. But if we're not sending + ** these, we shouldn't wait for them. So set our built-in delays to + ** the smallest legal values. */ + HTTP_setBodyWriteDelay (SMALLEST_LEGAL_LIBWWW_TIMEOUT, + SMALLEST_LEGAL_LIBWWW_TIMEOUT); + + /* We attempt to disable all of libwww's chatty, interactive + ** prompts. Let's hope this works. */ + HTAlert_setInteractive(NO); + + /* Here are some alternate setup calls which will help greatly + ** with debugging, should the need arise. + ** + ** HTProfile_newNoCacheClient(appname, appversion); + ** HTAlert_setInteractive(YES); + ** HTPrint_setCallback(printer); + ** HTTrace_setCallback(tracer); */ +} + + + +static void +create(xmlrpc_env * const envP, + int const flags, + const char * const appname, + const char * const appversion, + const struct xmlrpc_xportparms * const transportParmsP ATTR_UNUSED, + size_t const parm_size ATTR_UNUSED, + struct xmlrpc_client_transport ** const handlePP) { +/*---------------------------------------------------------------------------- + This does the 'create' operation for a Libwww client transport. +-----------------------------------------------------------------------------*/ + /* The Libwww transport is not re-entrant -- you can have only one + per program instance. Even if we changed the Xmlrpc-c code not + to use global variables, that wouldn't help because Libwww + itself is not re-entrant. + + So we use a global variable ('clientTransport') for our transport state. + */ + struct xmlrpc_client_transport * const clientTransportP = &clientTransport; + *handlePP = clientTransportP; + + clientTransportP->saved_flags = flags; + + createCookieJar(envP, &clientTransportP->cookieJarP); + if (!envP->fault_occurred) { + if (!(clientTransportP->saved_flags & + XMLRPC_CLIENT_SKIP_LIBWWW_INIT)) + initLibwww(appname, appversion); + + /* Set up our list of conversions for XML-RPC requests. This is a + ** massively stripped-down version of the list in libwww's HTInit.c. + ** XXX - This is hackish; 10.0 is an arbitrary, large quality factor + ** designed to override the built-in converter for XML. */ + clientTransportP->xmlrpc_conversions = HTList_new(); + HTConversion_add(clientTransportP->xmlrpc_conversions, + "text/xml", "*/*", + HTThroughLine, 10.0, 0.0, 0.0); + + if (envP->fault_occurred) + destroyCookieJar(clientTransportP->cookieJarP); + } + if (getenv("XMLRPC_LIBWWW_TRACE")) + clientTransportP->tracingOn = TRUE; + else + clientTransportP->tracingOn = FALSE; +} + + + +static void +destroy(struct xmlrpc_client_transport * const clientTransportP) { +/*---------------------------------------------------------------------------- + This does the 'destroy' operation for a Libwww client transport. +-----------------------------------------------------------------------------*/ + XMLRPC_ASSERT(clientTransportP != NULL); + + if (!(clientTransportP->saved_flags & XMLRPC_CLIENT_SKIP_LIBWWW_INIT)) { + HTProfile_delete(); + } + destroyCookieJar(clientTransportP->cookieJarP); +} + + + +/*========================================================================= +** HTTP Error Reporting +**=======================================================================*/ + +static void +formatLibwwwError(HTRequest * const requestP, + const char ** const msgP) { +/*---------------------------------------------------------------------------- + When something fails in a Libwww request, Libwww generates a stack + of error information (precious little information, of course, in the + Unix tradition) and attaches it to the request object. We make a message + out of that information. + + We rely on Libwww's HTDialog_errorMessage() to do the bulk of the + formatting; we might be able to coax more information out of the request + if we interpreted the error stack directly. +-----------------------------------------------------------------------------*/ + HTList * const errStack = HTRequest_error(requestP); + + if (errStack == NULL) + xmlrpc_asprintf(msgP, "Libwww supplied no error details"); + else { + /* Get an error message from libwww. The middle three + parameters to HTDialog_errorMessage appear to be ignored. + XXX - The documentation for this API is terrible, so we may + be using it incorrectly. + */ + const char * msg = + HTDialog_errorMessage(requestP, HT_A_MESSAGE, HT_MSG_NULL, + "An error occurred", errStack); + + if (msg == NULL) + xmlrpc_asprintf(msgP, "Libwww supplied some error detail, " + "but its HTDialog_errorMessage() subroutine " + "mysteriously failed to interpret it for us."); + else + *msgP = msg; + } +} + + + +static void +set_fault_from_http_request(xmlrpc_env * const envP, + int const status, + HTRequest * const requestP) { +/*---------------------------------------------------------------------------- + Assuming 'requestP' identifies a completed libwww HTTP request, set + *envP according to its success/error status. +-----------------------------------------------------------------------------*/ + XMLRPC_ASSERT_PTR_OK(requestP); + + if (status == 200) { + /* No error. Don't set one in *envP */ + } else { + const char * libwwwMsg; + formatLibwwwError(requestP, &libwwwMsg); + + if (status == -1) + xmlrpc_env_set_fault_formatted( + envP, XMLRPC_NETWORK_ERROR, + "Unable to complete the HTTP request. %s", libwwwMsg); + else { + xmlrpc_env_set_fault_formatted( + envP, XMLRPC_NETWORK_ERROR, + "HTTP request completed with HTTp error %d. %s", + status, libwwwMsg); + } + xmlrpc_strfree(libwwwMsg); + } +} + + + +static BOOL +setCookie(HTRequest * const request, + HTCookie * const cookieP ATTR_UNUSED, + void * const param ATTR_UNUSED) { +/*---------------------------------------------------------------------------- + This is the callback from libwww to tell us the server (according to + its response) wants us to store a cookie (and include it in future + requests). + + We assume that the cookies "domain" is the server's host name + (there are options on the libwww connection to make libwww call this + callback only when that's the case). +-----------------------------------------------------------------------------*/ + rpc * const rpcP = HTRequest_context(request); + struct xmlrpc_client_transport * const clientTransportP = + rpcP->clientTransportP; + + BOOL retval; + + /* Avoid unused variable warning */ + if (clientTransportP->cookieJarP == clientTransportP->cookieJarP) {} + /* Cookies are not implemented today */ + retval = NO; + + return retval; +} + + + +static HTAssocList * +cookiesForHost(const char * const host ATTR_UNUSED, + void * const cookieJarP ATTR_UNUSED) { +/*---------------------------------------------------------------------------- + Find and return all the cookies in jar 'cookieJarP' that are for the + host 'host'. +-----------------------------------------------------------------------------*/ + HTAssocList * hisCookiesP; + + hisCookiesP = HTAssocList_new(); + + if (hisCookiesP) { + /* Cookies are not implemented yet */ + /* Library/Examples/cookie.c in the w3c-libwww source tree contains + an example of constructing the cookie list we are supposed to + return. But today, we return an empty list. + */ + } + return hisCookiesP; +} + + + +static HTAssocList * +findCookie(HTRequest * const request, + void * const param ATTR_UNUSED) { +/*---------------------------------------------------------------------------- + This is the callback from libwww to get the cookies to include in a + request (presumably values the server set via a prior response). +-----------------------------------------------------------------------------*/ + rpc * const rpcP = HTRequest_context(request); + struct xmlrpc_client_transport * const clientTransportP = + rpcP->clientTransportP; + const char * const addr = + HTAnchor_address((HTAnchor *) HTRequest_anchor(request)); + const char * const host = HTParse(addr, "", PARSE_HOST); + + return cookiesForHost(host, clientTransportP->cookieJarP); +} + + + +static void +deleteSourceAnchor(HTParentAnchor * const anchor) { + + /* We need to clear the document first, or else libwww won't + ** really delete the anchor. */ + HTAnchor_setDocument(anchor, NULL); + + /* XXX - Deleting this anchor causes HTLibTerminate to dump core. */ + /* HTAnchor_delete(anchor); */ +} + + + +static void +createSourceAnchor(xmlrpc_env * const envP, + HTParentAnchor ** const sourceAnchorPP, + xmlrpc_mem_block * const xmlP) { + + HTParentAnchor * const sourceAnchorP = HTTmpAnchor(NULL); + + if (sourceAnchorP == NULL) + xmlrpc_env_set_fault_formatted( + envP, XMLRPC_INTERNAL_ERROR, + "Unable to build source anchor. HTTmpAnchor() failed."); + else { + HTAnchor_setDocument(sourceAnchorP, + XMLRPC_MEMBLOCK_CONTENTS(char, xmlP)); + HTAnchor_setFormat(sourceAnchorP, HTAtom_for("text/xml")); + HTAnchor_setLength(sourceAnchorP, XMLRPC_MEMBLOCK_SIZE(char, xmlP)); + + *sourceAnchorPP = sourceAnchorP; + } +} + + + +static void +createDestAnchor(xmlrpc_env * const envP, + HTAnchor ** const destAnchorPP, + const xmlrpc_server_info * const serverP) { + + *destAnchorPP = HTAnchor_findAddress(serverP->_server_url); + + if (*destAnchorPP == NULL) + xmlrpc_env_set_fault_formatted( + envP, XMLRPC_INTERNAL_ERROR, + "Could not build destination anchor. HTAnchor_findAddress() " + "failed."); +} + + + +static void +rpcCreate(xmlrpc_env * const envP, + struct xmlrpc_client_transport * const clientTransportP, + const xmlrpc_server_info * const serverP, + xmlrpc_mem_block * const xmlP, + xmlrpc_transport_asynch_complete complete, + struct xmlrpc_call_info * const callInfoP, + rpc ** const rpcPP) { + + rpc *rpcP; + HTRqHd request_headers; + HTStream *target_stream; + + /* Allocate our structure. */ + MALLOCVAR(rpcP); + XMLRPC_FAIL_IF_NULL(rpcP, envP, XMLRPC_INTERNAL_ERROR, + "Out of memory in rpcCreate()"); + + /* Set up our basic members. */ + rpcP->clientTransportP = clientTransportP; + rpcP->is_done = FALSE; + rpcP->http_status = 0; + rpcP->complete = complete; + rpcP->callInfoP = callInfoP; + + /* Start cookie handler. */ + HTCookie_init(); + HTCookie_setCallbacks(setCookie, NULL, findCookie, NULL); + HTCookie_setCookieMode(HT_COOKIE_ACCEPT | + HT_COOKIE_SEND | + HT_COOKIE_SAME_HOST); + + /* Cookies aren't implemented today; reset. */ + HTCookie_setCookieMode(0); + + /* Create a HTRequest object. */ + rpcP->request = HTRequest_new(); + XMLRPC_FAIL_IF_NULL(rpcP, envP, XMLRPC_INTERNAL_ERROR, + "HTRequest_new failed"); + + /* Install ourselves as the request context. */ + HTRequest_setContext(rpcP->request, rpcP); + + /* XXX - Disable the 'Expect:' header so we can talk to Frontier. */ + request_headers = HTRequest_rqHd(rpcP->request); + request_headers = request_headers & ~HT_C_EXPECT; + HTRequest_setRqHd(rpcP->request, request_headers); + + /* Send an authorization header if we need one. */ + if (serverP->_http_basic_auth) + HTRequest_addCredentials(rpcP->request, "Authorization", + serverP->_http_basic_auth); + + /* Make sure there is no XML conversion handler to steal our data. + ** The 'override' parameter is currently ignored by libwww, so our + ** list of conversions must be designed to co-exist with the built-in + ** conversions. */ + HTRequest_setConversion(rpcP->request, + clientTransportP->xmlrpc_conversions, NO); + + /* Set up our response buffer. */ + target_stream = HTStreamToChunk(rpcP->request, &rpcP->response_data, 0); + XMLRPC_FAIL_IF_NULL(rpcP->response_data, envP, XMLRPC_INTERNAL_ERROR, + "HTStreamToChunk failed"); + XMLRPC_ASSERT(target_stream != NULL); + HTRequest_setOutputStream(rpcP->request, target_stream); + HTRequest_setOutputFormat(rpcP->request, WWW_SOURCE); + + createSourceAnchor(envP, &rpcP->source_anchor, xmlP); + + if (!envP->fault_occurred) { + createDestAnchor(envP, &rpcP->dest_anchor, serverP); + + if (envP->fault_occurred) + /* See below for comments about deleting the source and dest + ** anchors. This is a bit of a black art. */ + deleteSourceAnchor(rpcP->source_anchor); + } + + cleanup: + if (envP->fault_occurred) { + if (rpcP) { + if (rpcP->request) + HTRequest_delete(rpcP->request); + if (rpcP->response_data) + HTChunk_delete(rpcP->response_data); + free(rpcP); + } + } + *rpcPP = rpcP; +} + + + +static void +rpcDestroy(rpc * const rpcP) { + + XMLRPC_ASSERT_PTR_OK(rpcP); + XMLRPC_ASSERT(rpcP->request != XMLRPC_BAD_POINTER); + XMLRPC_ASSERT(rpcP->response_data != XMLRPC_BAD_POINTER); + + /* Junji Kanemaru reports on 05.04.11 that with asynch calls, he + get a segfault, and reversing the order of deleting the request + and the response chunk buffer cured it. But we find no reason + that should be so, so we're waiting for someone to arrive at an + explanation before changing anything. HTRequest_delete() does + destroy the output stream, and the output stream refers to the + response chunk, but HTRequest_delete() explicitly refrains from + destroying the response chunk. And the response chunk does not + refer to the request. + */ + + HTRequest_delete(rpcP->request); + rpcP->request = XMLRPC_BAD_POINTER; + HTChunk_delete(rpcP->response_data); + rpcP->response_data = XMLRPC_BAD_POINTER; + + /* This anchor points to private data, so we're allowed to delete it. */ + deleteSourceAnchor(rpcP->source_anchor); + + /* WARNING: We can't delete the destination anchor, because this points + ** to something in the outside world, and lives in a libwww hash table. + ** Under certain circumstances, this anchor may have been reissued to + ** somebody else. So over time, the anchor cache will grow. If this + ** is a problem for your application, read the documentation for + ** HTAnchor_deleteAll. + ** + ** However, we CAN check to make sure that no documents have been + ** attached to the anchor. This assertion may fail if you're using + ** libwww for something else, so please feel free to comment it out. */ + /* XMLRPC_ASSERT(HTAnchor_document(rpcP->dest_anchor) == NULL); + */ + + HTCookie_deleteCallbacks(); + HTCookie_terminate(); + + free(rpcP); +} + + + +static void +extract_response_chunk(xmlrpc_env * const envP, + rpc * const rpcP, + xmlrpc_mem_block ** const responseXmlPP) { + + /* Check to make sure that w3c-libwww actually sent us some data. + ** XXX - This may happen if libwww is shut down prematurely, believe it + ** or not--we'll get a 200 OK and no data. Gag me with a bogus design + ** decision. This may also fail if some naughty libwww converter + ** ate our data unexpectedly. */ + if (!HTChunk_data(rpcP->response_data)) + xmlrpc_env_set_fault(envP, XMLRPC_NETWORK_ERROR, + "w3c-libwww returned no data"); + else { + *responseXmlPP = XMLRPC_MEMBLOCK_NEW(char, envP, 0); + if (!envP->fault_occurred) { + if (rpcP->clientTransportP->tracingOn) { + fprintf(stderr, "HTTP chunk received: %u bytes: '%.*s'", + HTChunk_size(rpcP->response_data), + HTChunk_size(rpcP->response_data), + HTChunk_data(rpcP->response_data)); + } + + XMLRPC_MEMBLOCK_APPEND(char, envP, *responseXmlPP, + HTChunk_data(rpcP->response_data), + HTChunk_size(rpcP->response_data)); + if (envP->fault_occurred) + XMLRPC_MEMBLOCK_FREE(char, *responseXmlPP); + } + } +} + + + +static int +synch_terminate_handler(HTRequest * const request, + HTResponse * const response ATTR_UNUSED, + void * const param ATTR_UNUSED, + int const status) { +/*---------------------------------------------------------------------------- + This is a libwww request completion handler. + + HTEventList_newLoop() calls this when it completes a request (with this + registered as the completion handler). +-----------------------------------------------------------------------------*/ + rpc *rpcP; + + rpcP = HTRequest_context(request); + + rpcP->is_done = TRUE; + rpcP->http_status = status; + + HTEventList_stopLoop(); + + return HT_OK; +} + + + +static void +call(xmlrpc_env * const envP, + struct xmlrpc_client_transport * const clientTransportP, + const xmlrpc_server_info * const serverP, + xmlrpc_mem_block * const xmlP, + xmlrpc_mem_block ** const responsePP) { +/*---------------------------------------------------------------------------- + This does the 'call' operation for a Libwww client transport. +-----------------------------------------------------------------------------*/ + rpc * rpcP; + + XMLRPC_ASSERT_ENV_OK(envP); + XMLRPC_ASSERT_PTR_OK(serverP); + XMLRPC_ASSERT_PTR_OK(xmlP); + XMLRPC_ASSERT_PTR_OK(responsePP); + + rpcCreate(envP, clientTransportP, serverP, xmlP, NULL, NULL, &rpcP); + if (!envP->fault_occurred) { + int ok; + + /* Install our request handler. */ + HTRequest_addAfter(rpcP->request, &synch_terminate_handler, + NULL, NULL, HT_ALL, HT_FILTER_LAST, NO); + + /* Start our request running. */ + ok = HTPostAnchor(rpcP->source_anchor, + rpcP->dest_anchor, + rpcP->request); + if (!ok) + xmlrpc_env_set_fault( + envP, XMLRPC_NETWORK_ERROR, + "Libwww HTPostAnchor() failed to start POST request"); + else { + /* Run our event-processing loop. HTEventList_newLoop() + is what calls synch_terminate_handler(), by virtue of + it being registered as a handler. It may return for + other reasons than the request being complete, though. + so we call it in a loop until synch_terminate_handler() + really has been called. + */ + while (!rpcP->is_done) + HTEventList_newLoop(); + + /* Fail if we didn't get a "200 OK" response from the server */ + if (rpcP->http_status != 200) + set_fault_from_http_request( + envP, rpcP->http_status, + rpcP->request); + else { + /* XXX - Check to make sure response type is text/xml here. */ + + extract_response_chunk(envP, rpcP, responsePP); + } + } + rpcDestroy(rpcP); + } +} + + + +/*========================================================================= +** Event Loop +**========================================================================= +** We manage a fair bit of internal state about our event loop. This is +** needed to determine when (and if) we should exit the loop. +*/ + +static int outstanding_asynch_calls = 0; +static int event_loop_flags = 0; +static int timer_called = 0; + +static void +register_asynch_call(void) { + XMLRPC_ASSERT(outstanding_asynch_calls >= 0); + outstanding_asynch_calls++; +} + + + +static void +unregister_asynch_call(void) { + + XMLRPC_ASSERT(outstanding_asynch_calls > 0); + outstanding_asynch_calls--; + if (outstanding_asynch_calls == 0) + HTEventList_stopLoop(); +} + + + +static int +timer_callback(HTTimer * const timer ATTR_UNUSED, + void * const user_data ATTR_UNUSED, + HTEventType const event ATTR_UNUSED) { +/*---------------------------------------------------------------------------- + A handy timer callback which cancels the running event loop. +-----------------------------------------------------------------------------*/ + XMLRPC_ASSERT(event == HTEvent_TIMEOUT); + timer_called = 1; + HTEventList_stopLoop(); + + /* XXX - The meaning of this return value is undocumented, but close + ** inspection of libwww's source suggests that we want to return HT_OK. */ + return HT_OK; +} + + + +static void +eventLoopRun(int const flags, + xmlrpc_timeout const milliseconds) { +/*---------------------------------------------------------------------------- + Process all responses from outstanding requests as they come in. + Return when there are no more outstanding responses. + + Or, if 'flags' has the XMLRPC_CLIENT_USE_TIMEOUT flag set, return + when 'milliseconds' milliseconds have elapsed, regardless of whether + there are still outstanding responses. + + The processing we do consists of telling libwww to process the + completion of the libwww request. That normally includes calling + the xmlrpc_libwww_transport request termination handler, because + the submitter of the libwww request would have registered that as a + callback. +-----------------------------------------------------------------------------*/ + if (outstanding_asynch_calls > 0) { + HTTimer *timer; + + event_loop_flags = flags; + + /* Run an appropriate event loop. The HTEeventList_newLoop() + is what calls asynch_terminate_handler(), by virtue of it + being registered as a handler. + */ + if (event_loop_flags & XMLRPC_CLIENT_USE_TIMEOUT) { + + /* Run our event loop with a timer. Note that we need to be very + ** careful about race conditions--timers can be fired in either + ** HTimer_new or HTEventList_newLoop. And if our callback were to + ** get called before we entered the loop, we would never exit. + ** So we use a private flag of our own--we can't even rely on + ** HTTimer_hasTimerExpired, because that only checks the time, + ** not whether our callback has been run. Yuck. */ + timer_called = 0; + timer = HTTimer_new(NULL, &timer_callback, NULL, + milliseconds, YES, NO); + XMLRPC_ASSERT(timer != NULL); + if (!timer_called) + HTEventList_newLoop(); + HTTimer_delete(timer); + + } else { + /* Run our event loop without a timer. */ + HTEventList_newLoop(); + } + + /* Reset our flags, so we don't interfere with direct calls to the + ** libwww event loop functions. */ + event_loop_flags = 0; + } else { + /* There are *no* calls to process. This may mean that none + of the asynch calls were ever set up, and the client's + callbacks have already been called with an error, or that + all outstanding calls were completed during a previous + synchronous call. + */ + } +} + + + +static void +finishAsynch( + struct xmlrpc_client_transport * const clientTransportP ATTR_UNUSED, + xmlrpc_timeoutType const timeoutType, + xmlrpc_timeout const timeout) { +/*---------------------------------------------------------------------------- + This does the 'finish_asynch' operation for a Libwww client transport. +-----------------------------------------------------------------------------*/ + eventLoopRun(timeoutType == timeout_yes ? XMLRPC_CLIENT_USE_TIMEOUT : 0, + timeout); +} + + + +static int +asynch_terminate_handler(HTRequest * const request, + HTResponse * const response ATTR_UNUSED, + void * const param ATTR_UNUSED, + int const status) { +/*---------------------------------------------------------------------------- + Handle the completion of a libwww request. + + This is the bottom half of the xmlrpc_libwww_transport asynchronous + call dispatcher. It's what the dispatcher registers with libwww as + a "local after filter" so that libwww calls it when a request that + xmlrpc_libwww_transport submitted to it is complete. + + We destroy the RPC, including the request which is our argument. + Strange as that may seem, it is apparently legal for an after filter + to destroy the request that was passed to it -- or not. +-----------------------------------------------------------------------------*/ + xmlrpc_env env; + rpc * rpcP; + xmlrpc_mem_block * responseXmlP; + + XMLRPC_ASSERT_PTR_OK(request); + + xmlrpc_env_init(&env); + + rpcP = HTRequest_context(request); + + /* Unregister this call from the event loop. Among other things, this + ** may decide to stop the event loop. + **/ + unregister_asynch_call(); + + /* Give up if an error occurred. */ + if (status != 200) + set_fault_from_http_request(&env, status, request); + else { + /* XXX - Check to make sure response type is text/xml here. */ + extract_response_chunk(&env, rpcP, &responseXmlP); + } + rpcP->complete(rpcP->callInfoP, responseXmlP, env); + + if (!env.fault_occurred) + XMLRPC_MEMBLOCK_FREE(char, responseXmlP); + + rpcDestroy(rpcP); + + xmlrpc_env_clean(&env); + return HT_OK; +} + + + +static void +sendRequest(xmlrpc_env * const envP, + struct xmlrpc_client_transport * const clientTransportP, + const xmlrpc_server_info * const serverP, + xmlrpc_mem_block * const xmlP, + xmlrpc_transport_asynch_complete complete, + struct xmlrpc_call_info * const callInfoP) { +/*---------------------------------------------------------------------------- + Initiate an XML-RPC rpc asynchronously. Don't wait for it to go to + the server. + + Unless we return failure, we arrange to have complete() called when + the rpc completes. + + This does the 'send_request' operation for a Libwww client transport. +-----------------------------------------------------------------------------*/ + rpc * rpcP; + + XMLRPC_ASSERT_PTR_OK(envP); + XMLRPC_ASSERT_PTR_OK(serverP); + XMLRPC_ASSERT_PTR_OK(xmlP); + XMLRPC_ASSERT_PTR_OK(callInfoP); + + rpcCreate(envP, clientTransportP, serverP, xmlP, complete, callInfoP, + &rpcP); + if (!envP->fault_occurred) { + int ok; + + /* Install our request handler. */ + HTRequest_addAfter(rpcP->request, &asynch_terminate_handler, + NULL, NULL, HT_ALL, HT_FILTER_LAST, NO); + + /* Register our asynchronous call with the event loop. This means + the user's callback is guaranteed to be called eventually. + */ + register_asynch_call(); + + /* This makes the TCP connection and sends the XML to the server + as an HTTP POST request. + + There was a comment here that said this might return failure + (!ok) and still invoke our completion handler + (asynch_terminate_handler(). The code attempted to deal with + that. Well, it's impossible to deal with that, so if it really + happens, we must fix Libwww. -Bryan 04.11.23. + */ + + ok = HTPostAnchor(rpcP->source_anchor, + rpcP->dest_anchor, + rpcP->request); + if (!ok) { + unregister_asynch_call(); + xmlrpc_env_set_fault(envP, XMLRPC_NETWORK_ERROR, + "Libwww (HTPostAnchor()) failed to start the " + "POST request."); + } + if (envP->fault_occurred) + rpcDestroy(rpcP); + } +} + + + +struct xmlrpc_client_transport_ops xmlrpc_libwww_transport_ops = { + NULL, + NULL, + &create, + &destroy, + &sendRequest, + &call, + &finishAsynch, +}; diff --git a/lib/libwww_transport/xmlrpc_libwww_transport.h b/lib/libwww_transport/xmlrpc_libwww_transport.h new file mode 100644 index 0000000..66d8048 --- /dev/null +++ b/lib/libwww_transport/xmlrpc_libwww_transport.h @@ -0,0 +1,8 @@ +#ifndef XMLRPC_LIBWWW_TRANSPORT_H +#define XMLRPC_LIBWWW_TRANSPORT_H + +#include "xmlrpc-c/transport.h" + +extern struct xmlrpc_client_transport_ops xmlrpc_libwww_transport_ops; + +#endif diff --git a/lib/util/Makefile b/lib/util/Makefile new file mode 100644 index 0000000..27ae85d --- /dev/null +++ b/lib/util/Makefile @@ -0,0 +1,52 @@ +############################################################################### +# This directory builds object modules that provide utility functions that +# programs can use. Not libraries, though -- just programs. The reason +# we don't want any library to use object modules in here is that they'll +# probably pollute the name space when users link those libraries to their +# programs. In fact, if more than one Xmlrpc-c library includes one of these +# modules, the libraries will conflict with each other. +# +# So a utility function that is to be used by libraries (and, optionally, +# programs) should go in libxmlrpc_util. libxmlrpc_util is a prerequisite +# for many Xmlrpc-c libraries, gets included in a program link only once, +# and uses external symbol names that have the "xmlrpc_" prefix to avoid +# collision with users' code. +# +# If we knew a portable way to link multiple object modules into one and +# restrict the symbols exported by the whole, we could avoid this mess and +# just link utility object modules into each Xmlrpc-c library. +############################################################################## + +ifeq ($(SRCDIR)x,x) +SRCDIR = $(CURDIR)/../.. +endif +SUBDIR = lib/util +BUILDDIR = $(SRCDIR) + +default: all + +include $(BUILDDIR)/Makefile.config + +include $(SRCDIR)/Makefile.common + +.PHONY: all +all: cmdline_parser.lo getoptx.lo casprintf.lo + +INCLUDES = -Iinclude -I$(BUILDDIR) + +CFLAGS = $(CFLAGS_COMMON) $(INCLUDES) $(CFLAGS_PERSONAL) $(CADD) + +%.lo:%.c + $(LIBTOOL) --mode=compile $(CC) -c $(CFLAGS) $< + +include Makefile.depend + +.PHONY: clean distclean +clean: clean-common + +distclean: clean distclean-common + +.PHONY: dep +dep: dep-common + +install: \ No newline at end of file diff --git a/lib/util/Makefile.depend b/lib/util/Makefile.depend new file mode 100644 index 0000000..e69de29 diff --git a/lib/util/casprintf.c b/lib/util/casprintf.c new file mode 100644 index 0000000..8a56512 --- /dev/null +++ b/lib/util/casprintf.c @@ -0,0 +1,93 @@ +#define _GNU_SOURCE +#include +#include +#include + +#include "xmlrpc_config.h" /* For HAVE_ASPRINTF, __inline__ */ +#include "casprintf.h" + + + +static __inline__ void +simpleVasprintf(char ** const retvalP, + const char * const fmt, + va_list varargs) { +/*---------------------------------------------------------------------------- + This is a poor man's implementation of vasprintf(), of GNU fame. +-----------------------------------------------------------------------------*/ + size_t const initialSize = 4096; + char * result; + + result = malloc(initialSize); + if (result != NULL) { + size_t bytesNeeded; + bytesNeeded = vsnprintf(result, initialSize, fmt, varargs); + if (bytesNeeded > initialSize) { + free(result); + result = malloc(bytesNeeded); + if (result != NULL) + vsnprintf(result, bytesNeeded, fmt, varargs); + } else if (bytesNeeded == initialSize) { + if (result[initialSize-1] != '\0') { + /* This is one of those old systems where vsnprintf() + returns the number of bytes it used, instead of the + number that it needed, and it in fact needed more than + we gave it. Rather than mess with this highly unlikely + case (old system and string > 4095 characters), we just + treat this like an out of memory failure. + */ + free(result); + result = NULL; + } + } + } + *retvalP = result; +} + + + +const char * const strsol = "[Insufficient memory to build string]"; + + + +void +cvasprintf(const char ** const retvalP, + const char * const fmt, + va_list varargs) { + + char * string; + +#if HAVE_ASPRINTF + vasprintf(&string, fmt, varargs); +#else + simpleVasprintf(&string, fmt, varargs); +#endif + + if (string == NULL) + *retvalP = strsol; + else + *retvalP = string; +} + + + +void GNU_PRINTF_ATTR(2,3) +casprintf(const char ** const retvalP, const char * const fmt, ...) { + + va_list varargs; /* mysterious structure used by variable arg facility */ + + va_start(varargs, fmt); /* start up the mysterious variable arg facility */ + + cvasprintf(retvalP, fmt, varargs); + + va_end(varargs); +} + + + +void +strfree(const char * const string) { + + if (string != strsol) + free((void *)string); +} diff --git a/lib/util/cmdline_parser.c b/lib/util/cmdline_parser.c new file mode 100644 index 0000000..a2c19ab --- /dev/null +++ b/lib/util/cmdline_parser.c @@ -0,0 +1,449 @@ +#include "xmlrpc_config.h" /* prereq for mallocvar.h -- defines __inline__ */ + +#include +#include +#include +#include + +#include "bool.h" +#include "mallocvar.h" +#include "casprintf.h" +#include "getoptx.h" + +#include "cmdline_parser.h" + +#define MAXOPTS 100 + +struct optionDesc { + const char * name; + enum optiontype type; + bool present; + union { + unsigned int u; + int i; + const char * s; + } value; +}; + + + +struct cmdlineParserCtl { + struct optionDesc * optionDescArray; + unsigned int numOptions; + const char ** argumentArray; + unsigned int numArguments; +}; + + + +static struct optionx * +createLongOptsArray(struct optionDesc * const optionDescArray, + unsigned int const numOptions) { + + struct optionx * longopts; + + MALLOCARRAY(longopts, numOptions+1); + if (longopts != NULL) { + unsigned int i; + + for (i = 0; i < numOptions; ++i) { + longopts[i].name = optionDescArray[i].name; + /* If the option takes a value, we say it is optional even + though it never is. That's because if we say it is + mandatory, getopt_long_only() pretends it doesn't even + recognize the option if the user doesn't give a value. + We prefer to generate a meaningful error message when + the user omits a required option value. + */ + longopts[i].has_arg = + optionDescArray[i].type == OPTTYPE_FLAG ? + no_argument : optional_argument; + longopts[i].flag = NULL; + longopts[i].val = i; + } + longopts[numOptions].name = 0; + longopts[numOptions].has_arg = 0; + longopts[numOptions].flag = 0; + longopts[numOptions].val = 0; + } + return longopts; +} + + + +static void +parseOptionValue(const char * const optarg, + struct optionDesc * const optionP, + const char ** const errorP) { + + switch (optionP->type) { + case OPTTYPE_UINT: + case OPTTYPE_INT: { + if (optarg == NULL) + casprintf(errorP, "Option requires a value"); + else if (strlen(optarg) == 0) + casprintf(errorP, "Numeric option value is null string"); + else { + char * tailptr; + long const longvalue = strtol(optarg, &tailptr, 10); + if (*tailptr != '\0') + casprintf(errorP, "Non-numeric value " + "for numeric option value: '%s'", optarg); + else if (errno == ERANGE || longvalue > INT_MAX) + casprintf(errorP, "Numeric value out of range: %s", optarg); + else { + if (optionP->type == OPTTYPE_UINT) { + if (longvalue < 0) + casprintf(errorP, "Unsigned numeric value is " + "negative: %ld", longvalue); + else { + *errorP = NULL; + optionP->value.u = (unsigned int) longvalue; + } + } else { + *errorP = NULL; + optionP->value.u = (int) longvalue; + } + } + } + } + break; + case OPTTYPE_STRING: + if (optarg == NULL) + casprintf(errorP, "Option requires a value"); + else { + *errorP = NULL; + optionP->value.s = strdup(optarg); + } + break; + case OPTTYPE_FLAG: + *errorP = NULL; + break; + } +} + + + +static void +processOption(struct optionDesc * const optionP, + const char * const optarg, + const char ** const errorP) { + + const char * error; + + parseOptionValue(optarg, optionP, &error); + if (error) + casprintf(errorP, "Error in '%s' option: %s", optionP->name, error); + else + optionP->present = true; +} + + + +static void +extractArguments(struct cmdlineParserCtl * const cpP, + unsigned int const argc, + const char ** const argv) { + + cpP->numArguments = argc - getopt_argstart(); + MALLOCARRAY(cpP->argumentArray, cpP->numArguments); + + if (cpP->argumentArray == NULL) { + fprintf(stderr, "Unable to allocate memory for argument array\n"); + abort(); + } else { + unsigned int i; + + for (i = 0; i < cpP->numArguments; ++i) { + cpP->argumentArray[i] = strdup(argv[getopt_argstart() + i]); + if (cpP->argumentArray[i] == NULL) { + fprintf(stderr, "Unable to allocate memory for Argument %u\n", + i); + abort(); + } + } + } +} + + + +void +cmd_processOptions(cmdlineParser const cpP, + int const argc, + const char ** const argv, + const char ** const errorP) { + + struct optionx * longopts; + + longopts = createLongOptsArray(cpP->optionDescArray, cpP->numOptions); + + if (longopts == NULL) + casprintf(errorP, "Unable to get memory for longopts array"); + else { + int endOfOptions; + unsigned int i; + + *errorP = NULL; + + /* Set up initial assumption: No options present */ + + for (i = 0; i < cpP->numOptions; ++i) + cpP->optionDescArray[i].present = false; + + endOfOptions = false; /* initial value */ + + while (!endOfOptions && !*errorP) { + int const opterr0 = 0; + /* Don't let getopt_long_only() print an error message */ + unsigned int longoptsIndex; + const char * unrecognizedOption; + const char * optarg; + + getopt_long_onlyx(argc, (char**) argv, "", longopts, + &longoptsIndex, opterr0, + &endOfOptions, &optarg, &unrecognizedOption); + + if (unrecognizedOption) + casprintf(errorP, "Unrecognized option: '%s'", + unrecognizedOption); + else { + if (!endOfOptions) + processOption(&cpP->optionDescArray[longoptsIndex], optarg, + errorP); + } + } + if (!*errorP) + extractArguments(cpP, argc, argv); + + free(longopts); + } +} + + + +cmdlineParser +cmd_createOptionParser(void) { + + struct cmdlineParserCtl * cpP; + + MALLOCVAR(cpP); + + if (cpP != NULL) { + struct optionDesc * optionDescArray; + + cpP->numOptions = 0; + MALLOCARRAY(optionDescArray, MAXOPTS); + if (optionDescArray == NULL) { + free(cpP); + cpP = NULL; + } else + cpP->optionDescArray = optionDescArray; + } + return cpP; +} + + + +void +cmd_destroyOptionParser(cmdlineParser const cpP) { + + unsigned int i; + + for (i = 0; i < cpP->numOptions; ++i) { + struct optionDesc const option = cpP->optionDescArray[i]; + if (option.type == OPTTYPE_STRING && option.present) + strfree(option.value.s); + strfree(option.name); + } + + for (i = 0; i < cpP->numArguments; ++i) + strfree(cpP->argumentArray[i]); + + free(cpP->optionDescArray); + free(cpP); +} + + + +void +cmd_defineOption(cmdlineParser const cpP, + const char * const name, + enum optiontype const type) { + + if (cpP->numOptions < MAXOPTS) { + cpP->optionDescArray[cpP->numOptions].name = strdup(name); + cpP->optionDescArray[cpP->numOptions].type = type; + + ++cpP->numOptions; + } +} + + + +static struct optionDesc * +findOptionDesc(struct cmdlineParserCtl * const cpP, + const char * const name) { + + struct optionDesc * retval; + unsigned int i; + + retval = NULL; + + for (i = 0; i < cpP->numOptions && !retval; ++i) + if (strcmp(cpP->optionDescArray[i].name, name) == 0) + retval = &cpP->optionDescArray[i]; + + return retval; +} + + + +int +cmd_optionIsPresent(cmdlineParser const cpP, + const char * const name) { + + struct optionDesc * const optionDescP = findOptionDesc(cpP, name); + + bool present; + + if (!optionDescP) { + fprintf(stderr, "cmdlineParser called incorrectly. " + "optionIsPresent() called for undefined option '%s'\n", + name); + abort(); + } else + present = optionDescP->present; + + return present; +} + + + +unsigned int +cmd_getOptionValueUint(cmdlineParser const cpP, + const char * const name) { + + struct optionDesc * const optionDescP = findOptionDesc(cpP, name); + + unsigned int retval; + + if (!optionDescP) { + fprintf(stderr, "cmdlineParser called incorrectly. " + "cmd_getOptionValueUint() called for undefined option '%s'\n", + name); + abort(); + } else { + if (optionDescP->type != OPTTYPE_UINT) { + fprintf(stderr, "cmdlineParser called incorrectly. " + "cmd_getOptionValueUint() called for non-unsigned integer " + "option '%s'\n", optionDescP->name); + abort(); + } else { + if (optionDescP->present) + retval = optionDescP->value.u; + else + retval = 0; + } + } + return retval; +} + + + +int +cmd_getOptionValueInt(cmdlineParser const cpP, + const char * const name) { + + struct optionDesc * const optionDescP = findOptionDesc(cpP, name); + + int retval; + + if (!optionDescP) { + fprintf(stderr, "cmdlineParser called incorrectly. " + "cmd_getOptionValueInt() called for undefined option '%s'\n", + name); + abort(); + } else { + if (optionDescP->type != OPTTYPE_INT) { + fprintf(stderr, "cmdlineParser called incorrectly. " + "cmd_getOptionValueInt() called for non-integer " + "option '%s'\n", optionDescP->name); + abort(); + } else { + if (optionDescP->present) + retval = optionDescP->value.i; + else + retval = 0; + } + } + + return retval; +} + + + +const char * +cmd_getOptionValueString(cmdlineParser const cpP, + const char * const name) { + + struct optionDesc * const optionDescP = findOptionDesc(cpP, name); + + const char * retval; + + if (!optionDescP) { + fprintf(stderr, "cmdlineParser called incorrectly. " + "cmd_getOptionValueString() called for " + "undefined option '%s'\n", + name); + abort(); + } else { + if (optionDescP->type != OPTTYPE_STRING) { + fprintf(stderr, "cmdlineParser called incorrectly. " + "getOptionValueString() called for non-string " + "option '%s'\n", optionDescP->name); + abort(); + } else { + if (optionDescP->present) { + retval = strdup(optionDescP->value.s); + if (retval == NULL) { + fprintf(stderr, + "out of memory in cmd_getOptionValueString()\n"); + abort(); + } + } else + retval = NULL; + } + } + return retval; +} + + + +unsigned int +cmd_argumentCount(cmdlineParser const cpP) { + + return cpP->numArguments; + +} + + + +const char * +cmd_getArgument(cmdlineParser const cpP, + unsigned int const argNumber) { + + const char * retval; + + if (argNumber >= cpP->numArguments) + retval = NULL; + else { + retval = strdup(cpP->argumentArray[argNumber]); + + if (retval == NULL) { + fprintf(stderr, + "out of memory in cmd_getArgument()\n"); + abort(); + } + } + return retval; +} diff --git a/lib/util/getoptx.c b/lib/util/getoptx.c new file mode 100644 index 0000000..6ced36b --- /dev/null +++ b/lib/util/getoptx.c @@ -0,0 +1,466 @@ +/* This version of `getopt' appears to the caller like standard Unix getopt() + but it behaves differently for the user, since it allows the user + to intersperse the options with the other arguments. + + As getopt() works, it permutes the elements of `argv' so that, + when it is done, all the options precede everything else. Thus + all application programs are extended to handle flexible argument order. + + Setting the environment variable _POSIX_OPTION_ORDER disables permutation. + Then the behavior is completely standard. + + GNU application programs can use a third alternative mode in which + they can distinguish the relative order of options and other arguments. +*/ + +#include +#include +#include + +#include "getoptx.h" + +/* Note that on some systems, the header files above declare variables + for use with their native getopt facilities, and those variables have + the same names as we'd like to use. So we use things like optargx + instead of optarg to avoid the collision. +*/ + +/* For communication from `getopt' to the caller. + When `getopt' finds an option that takes an argument, + the argument value is returned here. +*/ +static char *optargx = 0; + +/* Index in ARGV of the next element to be scanned. + This is used for communication to and from the caller + and for communication between successive calls to getoptx(). + + On entry to getoptx(), zero means this is the first call; initialize. + + When getoptx() returns EOF, this is the index of the first of the + non-option elements that the caller should itself scan. + + Otherwise, `optindx' communicates from one call to the next + how much of ARGV has been scanned so far. +*/ + +static int optindx = 0; + +/* The next char to be scanned in the option-element + in which the last option character we returned was found. + This allows us to pick up the scan where we left off. + + If this is zero, or a null string, it means resume the scan + by advancing to the next ARGV-element. */ + +static char *nextchar; + +/* Callers store zero here to inhibit the error message + for unrecognized options. +*/ + +static int opterrx; + +/* Index in _GETOPT_LONG_OPTIONS of the long-named option actually found. + Only valid when a long-named option was found. */ + +static int option_index; + +struct optionx * _getopt_long_options; + +/* Handle permutation of arguments. */ + +/* Describe the part of ARGV that contains non-options that have + been skipped. `first_nonopt' is the index in ARGV of the first of them; + `last_nonopt' is the index after the last of them. */ + +static int first_nonopt; +static int last_nonopt; + +/* Exchange two adjacent subsequences of ARGV. + One subsequence is elements [first_nonopt,last_nonopt) + which contains all the non-options that have been skipped so far. + The other is elements [last_nonopt,optindx), which contains all + the options processed since those non-options were skipped. + + `first_nonopt' and `last_nonopt' are relocated so that they describe + the new indices of the non-options in ARGV after they are moved. */ + +static void +exchange(char ** const argv) { + unsigned int const nonopts_size = + (last_nonopt - first_nonopt) * sizeof (char *); + char **temp = (char **) malloc (nonopts_size); + + if (temp == NULL) + abort(); + + /* Interchange the two blocks of data in argv. */ + + bcopy (&argv[first_nonopt], temp, nonopts_size); + bcopy (&argv[last_nonopt], &argv[first_nonopt], + (optindx - last_nonopt) * sizeof (char *)); + bcopy (temp, &argv[first_nonopt + optindx - last_nonopt], + nonopts_size); + + /* Update records for the slots the non-options now occupy. */ + + first_nonopt += (optindx - last_nonopt); + last_nonopt = optindx; + + free(temp); +} + +/* Scan elements of ARGV (whose length is ARGC) for option characters + given in OPTSTRING. + + If an element of ARGV starts with '-', and is not exactly "-" or "--", + then it is an option element. The characters of this element + (aside from the initial '-') are option characters. If getoptx() + is called repeatedly, it returns successively each of the option characters + from each of the option elements. + + If getoptx() finds another option character, it returns that character, + updating `optindx' and `nextchar' so that the next call to getoptx() can + resume the scan with the following option character or ARGV-element. + + If there are no more option characters, getoptx() returns `EOF'. + Then `optindx' is the index in ARGV of the first ARGV-element + that is not an option. (The ARGV-elements have been permuted + so that those that are not options now come last.) + + OPTSTRING is a string containing the legitimate option characters. + If an option character is seen that is not listed in OPTSTRING, + return '?' after printing an error message. If you set `opterrx' to + zero, the error message is suppressed but we still return '?'. + + If a char in OPTSTRING is followed by a colon, that means it wants an arg, + so the following text in the same ARGV-element, or the text of the following + ARGV-element, is returned in `optargx'. Two colons mean an option that + wants an optional arg; if there is text in the current ARGV-element, + it is returned in `optargx', otherwise `optargx' is set to zero. + + If OPTSTRING starts with `-', it requests a different method of handling the + non-option ARGV-elements. See the comments about RETURN_IN_ORDER, above. + + Long-named options begin with `+' instead of `-'. + Their names may be abbreviated as long as the abbreviation is unique + or is an exact match for some defined option. If they have an + argument, it follows the option name in the same ARGV-element, separated + from the option name by a `=', or else the in next ARGV-element. + getoptx() returns 0 when it finds a long-named option. */ + +static int +getoptx(int const argc, + char ** const argv, + const char * const optstring) { + + optargx = 0; + + /* Initialize the internal data when the first call is made. + Start processing options with ARGV-element 1 (since ARGV-element 0 + is the program name); the sequence of previously skipped + non-option ARGV-elements is empty. */ + + if (optindx == 0) + { + first_nonopt = last_nonopt = optindx = 1; + + nextchar = 0; + + } + + if (nextchar == 0 || *nextchar == 0) + { + /* If we have just processed some options following some non-options, + exchange them so that the options come first. */ + + if (first_nonopt != last_nonopt && last_nonopt != optindx) + exchange (argv); + else if (last_nonopt != optindx) + first_nonopt = optindx; + + /* Now skip any additional non-options + and extend the range of non-options previously skipped. */ + + while (optindx < argc + && (argv[optindx][0] != '-'|| argv[optindx][1] == 0) + && (argv[optindx][0] != '+'|| argv[optindx][1] == 0)) + optindx++; + last_nonopt = optindx; + + /* Special ARGV-element `--' means premature end of options. + Skip it like a null option, + then exchange with previous non-options as if it were an option, + then skip everything else like a non-option. */ + + if (optindx != argc && !strcmp (argv[optindx], "--")) + { + optindx++; + + if (first_nonopt != last_nonopt && last_nonopt != optindx) + exchange (argv); + else if (first_nonopt == last_nonopt) + first_nonopt = optindx; + last_nonopt = argc; + + optindx = argc; + } + + /* If we have done all the ARGV-elements, stop the scan + and back over any non-options that we skipped and permuted. */ + + if (optindx == argc) + { + /* Set the next-arg-index to point at the non-options + that we previously skipped, so the caller will digest them. */ + if (first_nonopt != last_nonopt) + optindx = first_nonopt; + return EOF; + } + + /* If we have come to a non-option and did not permute it, + either stop the scan or describe it to the caller and pass + it by. + */ + + if ((argv[optindx][0] != '-' || argv[optindx][1] == 0) + && (argv[optindx][0] != '+' || argv[optindx][1] == 0)) + { + optargx = argv[optindx++]; + return 1; + } + + /* We have found another option-ARGV-element. + Start decoding its characters. */ + + nextchar = argv[optindx] + 1; + } + + if ((argv[optindx][0] == '+' || (argv[optindx][0] == '-')) + ) + { + struct optionx *p; + char *s = nextchar; + int exact = 0; + int ambig = 0; + struct optionx * pfound; + int indfound; + + while (*s && *s != '=') s++; + + indfound = 0; /* quite compiler warning */ + + /* Test all options for either exact match or abbreviated matches. */ + for (p = _getopt_long_options, option_index = 0, pfound = NULL; + p->name; + p++, option_index++) + if (!strncmp (p->name, nextchar, s - nextchar)) + { + if ((unsigned int)(s - nextchar) == strlen (p->name)) + { + /* Exact match found. */ + pfound = p; + indfound = option_index; + exact = 1; + break; + } + else if (!pfound) + { + /* First nonexact match found. */ + pfound = p; + indfound = option_index; + } + else + /* Second nonexact match found. */ + ambig = 1; + } + + if (ambig && !exact) + { + fprintf (stderr, "%s: option `%s' is ambiguous\n", + argv[0], argv[optindx]); + nextchar += strlen (nextchar); + return '?'; + } + + if (pfound) + { + option_index = indfound; + optindx++; + if (*s) + { + if (pfound->has_arg > 0) + optargx = s + 1; + else + { + fprintf (stderr, + "%s: option `%c%s' doesn't allow an argument\n", + argv[0], argv[optindx - 1][0], pfound->name); + nextchar += strlen (nextchar); + return '?'; + } + } + else if (pfound->has_arg) + { + if (optindx < argc) + optargx = argv[optindx++]; + else if (pfound->has_arg != 2) + { + fprintf (stderr, "%s: option `%s' requires an argument\n", + argv[0], argv[optindx - 1]); + nextchar += strlen (nextchar); + return '?'; + } + } + nextchar += strlen (nextchar); + if (pfound->flag) + *(pfound->flag) = pfound->val; + return 0; + } + if (argv[optindx][0] == '+' || index (optstring, *nextchar) == 0) + { + if (opterrx != 0) + fprintf (stderr, "%s: unrecognized option `%c%s'\n", + argv[0], argv[optindx][0], nextchar); + nextchar += strlen (nextchar); + return '?'; + } + } + + /* Look at and handle the next option-character. */ + + { + char c = *nextchar++; + char *temp = index (optstring, c); + + /* Increment `optindx' when we start to process its last character. */ + if (*nextchar == 0) + optindx++; + + if (temp == 0 || c == ':') + { + if (opterrx != 0) + { + if (c < 040 || c >= 0177) + fprintf (stderr, "%s: unrecognized option, " + "character code 0%o\n", + argv[0], c); + else + fprintf (stderr, "%s: unrecognized option `-%c'\n", + argv[0], c); + } + return '?'; + } + if (temp[1] == ':') + { + if (temp[2] == ':') + { + /* This is an option that accepts an argument optionally. */ + if (*nextchar != 0) + { + optargx = nextchar; + optindx++; + } + else + optargx = 0; + nextchar = 0; + } + else + { + /* This is an option that requires an argument. */ + if (*nextchar != 0) + { + optargx = nextchar; + /* If we end this ARGV-element by taking the rest + as an arg, we must advance to the next element + now. + */ + optindx++; + } + else if (optindx == argc) + { + if (opterrx != 0) + fprintf (stderr, + "%s: option `-%c' requires an argument\n", + argv[0], c); + c = '?'; + } + else + /* We already incremented `optindx' once; + increment it again when taking next ARGV-elt as + argument. + */ + optargx = argv[optindx++]; + nextchar = 0; + } + } + return c; + } +} + + + +void +getopt_long_onlyx(int const argc, + char ** const argv, + const char * const options, + struct optionx * const long_options, + unsigned int * const opt_index, + int const opterrArg, + int * const end_of_options, + const char ** const optarg_arg, + const char ** const unrecognized_option) { + + int rc; + + opterrx = opterrArg; + _getopt_long_options = long_options; + rc = getoptx(argc, argv, options); + if (rc == 0) + *opt_index = option_index; + + if (rc == '?') + *unrecognized_option = argv[optindx]; + else + *unrecognized_option = NULL; + + if (rc < 0) + *end_of_options = 1; + else + *end_of_options = 0; + + *optarg_arg = optargx; +} + + +unsigned int +getopt_argstart(void) { +/*---------------------------------------------------------------------------- + This is a replacement for what traditional getopt does with global + variables. + + You call this after getopt_long_onlyx() has returned "end of + options" +-----------------------------------------------------------------------------*/ + return optindx; +} + + +/* Getopt for GNU. + Copyright (C) 1987, 1989 Free Software Foundation, Inc. + + This program 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 1, 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., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ diff --git a/lib/util/getoptx.h b/lib/util/getoptx.h new file mode 100644 index 0000000..c688331 --- /dev/null +++ b/lib/util/getoptx.h @@ -0,0 +1,51 @@ +/* Interface to getopt_long_onlyx() */ + + +enum argreq {no_argument, required_argument, optional_argument}; + +struct optionx { + /* This describes an option. If the field `flag' is nonzero, it + points to a variable that is to be set to the value given in + the field `val' when the option is found, but left unchanged if + the option is not found. + */ + const char * name; + enum argreq has_arg; + int * flag; + int val; +}; + +/* long_options[] is a list terminated by an element that contains + a NULL 'name' member. +*/ +void +getopt_long_onlyx(int const argc, + char ** const argv, + const char * const options, + struct optionx * const long_options, + unsigned int * const opt_index, + int const opterrArg, + int * const end_of_options, + const char ** const optarg_arg, + const char ** const unrecognized_option); + +unsigned int +getopt_argstart(void); + +/* + Copyright (C) 1989 Free Software Foundation, Inc. + + This program 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 1, 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., 675 Mass Ave, Cambridge, MA 02139, USA. */ + diff --git a/lib/util/include/bool.h b/lib/util/include/bool.h new file mode 100644 index 0000000..312477c --- /dev/null +++ b/lib/util/include/bool.h @@ -0,0 +1,18 @@ +/* This takes the place of C99 stdbool.h, which at least some Windows + compilers don't have. (October 2005). + + One must not also include , because it might cause a name + collision. +*/ + +#ifndef __cplusplus +/* At least the GNU compiler defines __bool_true_false_are_defined */ +#ifndef __bool_true_false_are_defined +#define __bool_true_false_are_defined +typedef enum { + false = 0, + true = 1 +} bool; +#endif +#endif + diff --git a/lib/util/include/c_util.h b/lib/util/include/c_util.h new file mode 100644 index 0000000..da078e8 --- /dev/null +++ b/lib/util/include/c_util.h @@ -0,0 +1,20 @@ +#ifndef C_UTIL_H_INCLUDED +#define C_UTIL_H_INCLUDED + +/* C language stuff. Doesn't involve any libraries that aren't part of + the compiler. +*/ + +#define ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0])) + +/* GNU_PRINTF_ATTR lets the GNU compiler check printf-type + calls to be sure the arguments match the format string, thus preventing + runtime segmentation faults and incorrect messages. +*/ +#ifdef __GNUC__ +#define GNU_PRINTF_ATTR(a,b) __attribute__ ((format (printf, a, b))) +#else +#define GNU_PRINTF_ATTR(a,b) +#endif + +#endif diff --git a/lib/util/include/casprintf.h b/lib/util/include/casprintf.h new file mode 100644 index 0000000..a5d0e4a --- /dev/null +++ b/lib/util/include/casprintf.h @@ -0,0 +1,21 @@ +#ifndef CASPRINTF_H_INCLUDED +#define CASPRINTF_H_INCLUDED + +#include + +#include "c_util.h" + +extern const char * const strsol; + +void +cvasprintf(const char ** const retvalP, + const char * const fmt, + va_list varargs); + +void GNU_PRINTF_ATTR(2,3) +casprintf(const char ** const retvalP, const char * const fmt, ...); + +void +strfree(const char * const string); + +#endif diff --git a/lib/util/include/cmdline_parser.h b/lib/util/include/cmdline_parser.h new file mode 100644 index 0000000..ce42506 --- /dev/null +++ b/lib/util/include/cmdline_parser.h @@ -0,0 +1,59 @@ +#ifndef CMDLINE_PARSER_H +#define CMDLINE_PARSER_H + + +/* + + NOTE NOTE NOTE: cmd_getOptionValueString() and + cmd_getArgument() return malloc'ed memory (and abort the program if + out of memory). You must free it. + +*/ + +enum optiontype {OPTTYPE_FLAG, OPTTYPE_INT, OPTTYPE_UINT, OPTTYPE_STRING}; + +struct cmdlineParserCtl; + +typedef struct cmdlineParserCtl * cmdlineParser; + +void +cmd_processOptions(cmdlineParser const cpP, + int const argc, + const char ** const argv, + const char ** const errorP); + +cmdlineParser +cmd_createOptionParser(void); + +void +cmd_destroyOptionParser(cmdlineParser const cpP); + +void +cmd_defineOption(cmdlineParser const cpP, + const char * const name, + enum optiontype const type); + +int +cmd_optionIsPresent(cmdlineParser const cpP, + const char * const name); + +unsigned int +cmd_getOptionValueUint(cmdlineParser const cpP, + const char * const name); + +int +cmd_getOptionValueInt(cmdlineParser const cpP, + const char * const name); + +const char * +cmd_getOptionValueString(cmdlineParser const cpP, + const char * const name); + +unsigned int +cmd_argumentCount(cmdlineParser const cpP); + +const char * +cmd_getArgument(cmdlineParser const cpP, + unsigned int const argNumber); + +#endif diff --git a/lib/util/include/girmath.h b/lib/util/include/girmath.h new file mode 100644 index 0000000..0ced9c8 --- /dev/null +++ b/lib/util/include/girmath.h @@ -0,0 +1,8 @@ +#ifndef __GIRMATH_H +#define __GIRMATH_H + +#define MIN(a,b) ((a) < (b) ? (a) : (b)) +#define MAX(a,b) ((a) > (b) ? (a) : (b)) + +#endif + diff --git a/lib/util/include/girstring.h b/lib/util/include/girstring.h new file mode 100644 index 0000000..f2cdc81 --- /dev/null +++ b/lib/util/include/girstring.h @@ -0,0 +1,47 @@ +#ifndef GIRSTRING_H_INCLUDED +#define GIRSTRING_H_INCLUDED + +#include +#include "bool.h" + +char +stripeq(const char * const comparand, const char * const comparator); + +char +stripcaseeq(const char * const comparand, const char * const comparator); + +void +stripcpy(char * dest, const char * source); + +void +stripcasecpy(char * dest, const char * source); + +char * +stripdup(const char * const input); + +char * +strcasedup(const char input[]); + +static __inline__ bool +streq(const char * const comparator, + const char * const comparand) { + + return (strcmp(comparand, comparator) == 0); +} + +static __inline__ const char * +sdup(const char * const input) { + return (const char *) strdup(input); +} + +/* Copy string pointed by B to array A with size checking. */ +#define SSTRCPY(A,B) \ + (strncpy((A), (B), sizeof(A)), *((A)+sizeof(A)-1) = '\0') +#define SSTRCMP(A,B) \ + (strncmp((A), (B), sizeof(A))) + +/* Concatenate string B onto string in array A with size checking */ +#define STRSCAT(A,B) \ + (strncat((A), (B), sizeof(A)-strlen(A)), *((A)+sizeof(A)-1) = '\0') + +#endif diff --git a/lib/util/include/inline.h b/lib/util/include/inline.h new file mode 100644 index 0000000..f90032b --- /dev/null +++ b/lib/util/include/inline.h @@ -0,0 +1,19 @@ +#ifndef XMLRPC_INLINE_H_INCLUDED +#define XMLRPC_INLINE_H_INCLUDED + +/* Xmlrpc-c uses __inline__ to declare functions that should be + compiled as inline code. Some compilers, e.g. GNU, recognize the + __inline__ keyword. +*/ +#ifndef __GNUC__ +#ifndef __inline__ +#ifdef __sgi +#define __inline__ __inline +#else +#define __inline__ +#endif +#endif +#endif + + +#endif diff --git a/lib/util/include/linklist.h b/lib/util/include/linklist.h new file mode 100644 index 0000000..f6f2641 --- /dev/null +++ b/lib/util/include/linklist.h @@ -0,0 +1,193 @@ +#ifndef LINKLIST_H_INCLUDED +#define LINKLIST_H_INCLUDED + +#include "inline.h" + +struct list_head { +/*---------------------------------------------------------------------------- + This is a header for an element of a doubly linked list, or an anchor + for such a list. + + itemP == NULL means it's an anchor; otherwise it's a header. + + Initialize a list header with list_init_header(). You don't have to + do anything to terminate a list header. + + Initialize an anchor with list_make_emtpy(). You don't have to do anything + to terminate a list header. +-----------------------------------------------------------------------------*/ + struct list_head * nextP; + /* For a header, this is the address of the list header for + the next element in the list. If there is no next element, + it points to the anchor. If the header is not in a list at + all, it is NULL. + + For an anchor, it is the address of the list header of the + first element. If the list is empty, it points to the + anchor itself. + */ + struct list_head * prevP; + /* For a header, this is the address of the list header for + the previous element in the list. If there is no previous element, + it points to the anchor. If the header is not in a list at + all, it is NULL. + + For an anchor, it is the address of the list header of the + last element. If the list is empty, it points to the + anchor itself. + */ + void * itemP; + /* For a header, this is the address of the list element to which it + belongs. For an anchor, this is NULL. + */ +}; + +static __inline__ void +list_init_header(struct list_head * const headerP, + void * const itemP) { + + headerP->prevP = NULL; + headerP->nextP = NULL; + headerP->itemP = itemP; +} + + + +static __inline__ int +list_is_linked(struct list_head * headerP) { + return headerP->prevP != NULL; +} + + + +static __inline__ int +list_is_empty(struct list_head * const anchorP) { + return anchorP->nextP == anchorP; +} + + + +static __inline__ unsigned int +list_count(struct list_head * const anchorP) { + unsigned int count; + + struct list_head * p; + + for (p = anchorP->nextP, count = 0; + p != anchorP; + p = p->nextP, ++count); + + return count; +} + + + +static __inline__ void +list_make_empty(struct list_head * const anchorP) { + anchorP->prevP = anchorP; + anchorP->nextP = anchorP; + anchorP->itemP = NULL; +} + +static __inline__ void +list_insert_after(struct list_head * const beforeHeaderP, + struct list_head * const newHeaderP) { + newHeaderP->prevP = beforeHeaderP; + newHeaderP->nextP = beforeHeaderP->nextP; + + beforeHeaderP->nextP = newHeaderP; + newHeaderP->nextP->prevP = newHeaderP; +} + + + +static __inline__ void +list_add_tail(struct list_head * const anchorP, + struct list_head * const headerP) { + list_insert_after(anchorP->prevP, headerP); +} + + + +static __inline__ void +list_add_head(struct list_head * const anchorP, + struct list_head * const headerP) { + list_insert_after(anchorP, headerP); +} + + + +static __inline__ void +list_remove(struct list_head * const headerP) { + headerP->prevP->nextP = headerP->nextP; + headerP->nextP->prevP = headerP->prevP; + headerP->prevP = NULL; + headerP->nextP = NULL; +} + + + +static __inline__ struct list_head * +list_remove_head(struct list_head * const anchorP) { + struct list_head * retval; + + if (list_is_empty(anchorP)) + retval = NULL; + else { + retval = anchorP->nextP; + list_remove(retval); + } + return retval; +} + + + +static __inline__ struct list_head * +list_remove_tail(struct list_head * const anchorP) { + struct list_head * retval; + + if (list_is_empty(anchorP)) + retval = NULL; + else { + retval = anchorP->prevP; + list_remove(retval); + } + return retval; +} + + + +static __inline__ void * +list_foreach(struct list_head * const anchorP, + void * functionP(struct list_head *, void *), + void * const context) { + + struct list_head * p; + struct list_head * nextP; + void * result; + + for (p = anchorP->nextP, nextP = p->nextP, result=NULL; + p != anchorP && result == NULL; + p = nextP, nextP = p->nextP) + result = (*functionP)(p, context); + + return result; +} + + + +static __inline__ void +list_append(struct list_head * const newAnchorP, + struct list_head * const baseAnchorP) { + + if (!list_is_empty(newAnchorP)) { + baseAnchorP->prevP->nextP = newAnchorP->nextP; + newAnchorP->nextP->prevP = baseAnchorP->prevP; + newAnchorP->prevP->nextP = baseAnchorP; + baseAnchorP->prevP = newAnchorP->prevP; + } +} + +#endif + + diff --git a/lib/util/include/mallocvar.h b/lib/util/include/mallocvar.h new file mode 100644 index 0000000..9c4f994 --- /dev/null +++ b/lib/util/include/mallocvar.h @@ -0,0 +1,100 @@ +/* These are some dynamic memory allocation facilities. They are essentially + an extension to C, as they do allocations with a cognizance of C + variables. You can use them to make C read more like a high level + language. + + Before including this, you must define an __inline__ macro if your + compiler doesn't recognize it as a keyword. +*/ + +#ifndef MALLOCVAR_INCLUDED +#define MALLOCVAR_INCLUDED + +#include "xmlrpc_config.h" + +#include +#include + +static __inline__ void +mallocProduct(void ** const resultP, + unsigned int const factor1, + unsigned int const factor2) { +/*---------------------------------------------------------------------------- + malloc a space whose size in bytes is the product of 'factor1' and + 'factor2'. But if that size cannot be represented as an unsigned int, + return NULL without allocating anything. Also return NULL if the malloc + fails. + + If either factor is zero, malloc a single byte. + + Note that malloc() actually takes a size_t size argument, so the + proper test would be whether the size can be represented by size_t, + not unsigned int. But there is no reliable indication available to + us, like UINT_MAX, of what the limitations of size_t are. We + assume size_t is at least as expressive as unsigned int and that + nobody really needs to allocate more than 4GB of memory. +-----------------------------------------------------------------------------*/ + if (factor1 == 0 || factor2 == 0) + *resultP = malloc(1); + else { + if (UINT_MAX / factor2 < factor1) + *resultP = NULL; + else + *resultP = malloc(factor1 * factor2); + } +} + + + +static __inline__ void +reallocProduct(void ** const blockP, + unsigned int const factor1, + unsigned int const factor2) { + + if (UINT_MAX / factor2 < factor1) + *blockP = NULL; + else + *blockP = realloc(*blockP, factor1 * factor2); +} + + +/* IMPLEMENTATION NOTE: There are huge strict aliasing pitfalls here + if you cast pointers, e.g. (void **) +*/ + +#define MALLOCARRAY(arrayName, nElements) do { \ + void * array; \ + mallocProduct(&array, nElements, sizeof(arrayName[0])); \ + arrayName = array; \ +} while (0) + +#define REALLOCARRAY(arrayName, nElements) { \ + void * array = arrayName; \ + reallocProduct(&array, nElements, sizeof(arrayName[0])); \ + arrayName = array; \ +} while (0) + + +#define MALLOCARRAY_NOFAIL(arrayName, nElements) \ +do { \ + MALLOCARRAY(arrayName, nElements); \ + if ((arrayName) == NULL) \ + abort(); \ +} while(0) + +#define REALLOCARRAY_NOFAIL(arrayName, nElements) \ +do { \ + REALLOCARRAY(arrayName, nElements); \ + if ((arrayName) == NULL) \ + abort(); \ +} while(0) + + +#define MALLOCVAR(varName) \ + varName = malloc(sizeof(*varName)) + +#define MALLOCVAR_NOFAIL(varName) \ + do {if ((varName = malloc(sizeof(*varName))) == NULL) abort();} while(0) + +#endif + diff --git a/lib/util/include/pthreadx.h b/lib/util/include/pthreadx.h new file mode 100644 index 0000000..dcdb411 --- /dev/null +++ b/lib/util/include/pthreadx.h @@ -0,0 +1,68 @@ +/* Copyright (C) 2001 by First Peer, Inc. All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +** ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +** OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +** HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +** LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +** OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +** SUCH DAMAGE. */ + +#ifndef PTHREADX_H_INCLUDED +#define PTHREADX_H_INCLUDED + +#ifndef WIN32 +# define _REENTRANT +# include +#elif defined (WIN32) + +typedef HANDLE pthread_t; +typedef CRITICAL_SECTION pthread_mutex_t; + +#define PTHREAD_MUTEX_INITIALIZER NULL + //usage: pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; + +typedef +struct { + int attrs; //currently unused. placeholder. +} pthread_attr_t; + +typedef +struct { + int attrs; //currently unused. placeholder. +} pthread_mutexattr_t; + +//typedef void * (*pthread_func)(void *); +typedef unsigned ( __stdcall *pthread_func )( void * ); + +extern int pthread_create(pthread_t *new_thread_ID, + const pthread_attr_t *attr, + pthread_func start_func, void *arg); +extern int pthread_cancel(pthread_t target_thread); +extern int pthread_join(pthread_t target_thread, void **status); +extern int pthread_detach(pthread_t target_thread); + +extern int pthread_mutex_init(pthread_mutex_t *mp, + const pthread_mutexattr_t *attr); +extern int pthread_mutex_lock(pthread_mutex_t *mp); +extern int pthread_mutex_unlock(pthread_mutex_t *mp); +extern int pthread_mutex_destroy(pthread_mutex_t *mp); + +#endif /* WIN32 */ + +#endif diff --git a/lib/util/include/unistdx.h b/lib/util/include/unistdx.h new file mode 100644 index 0000000..69f1f6b --- /dev/null +++ b/lib/util/include/unistdx.h @@ -0,0 +1,14 @@ +#ifndef UNISTDX_H_INCLUDED +#define UNISTDX_H_INCLUDED + +/* Xmlrpc-c code #includes "unistdx.h" instead of because + does not exist on WIN32. +*/ + +#ifndef WIN32 +# include +#else + +#endif /* WIN32 */ + +#endif diff --git a/lib/util/pthreadx_win32.c b/lib/util/pthreadx_win32.c new file mode 100644 index 0000000..a295fb0 --- /dev/null +++ b/lib/util/pthreadx_win32.c @@ -0,0 +1,101 @@ +/* Copyright (C) 2001 by First Peer, Inc. All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +** ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +** OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +** HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +** LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +** OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +** SUCH DAMAGE. */ + +#include "xmlrpc_config.h" + +#if WIN32 + +#include "pthreadx.h" + +#include + +#undef PACKAGE +#undef VERSION + +int pthread_create(pthread_t *new_thread_ID, + const pthread_attr_t * attr, + pthread_func start_func, void *arg) +{ + HANDLE hThread; + DWORD dwThreadID; + + hThread = (HANDLE) _beginthreadex ( + NULL, 0, start_func, (LPVOID)arg, CREATE_SUSPENDED, &dwThreadID); + + SetThreadPriority (hThread, THREAD_PRIORITY_NORMAL); + ResumeThread (hThread); + + *new_thread_ID = hThread; + + return hThread ? 0 : -1; +} + +/* Just kill it. */ +int pthread_cancel(pthread_t target_thread) +{ + CloseHandle (target_thread); + return 0; +} + +/* Waits for the thread to exit before continuing. */ +int pthread_join(pthread_t target_thread, void **status) +{ + DWORD dwResult = WaitForSingleObject(target_thread, INFINITE); + (*status) = (void *)dwResult; + return 0; +} + +/* Stubbed. Do nothing. */ +int pthread_detach(pthread_t target_thread) +{ + return 0; +} + +int pthread_mutex_init(pthread_mutex_t *mp, + const pthread_mutexattr_t * attr) +{ + InitializeCriticalSection(mp); + return 0; +} + +int pthread_mutex_lock(pthread_mutex_t *mp) +{ + EnterCriticalSection(mp); + return 0; +} + +int pthread_mutex_unlock(pthread_mutex_t *mp) +{ + LeaveCriticalSection(mp); + return 0; +} + +int pthread_mutex_destroy(pthread_mutex_t *mp) +{ + DeleteCriticalSection(mp); + return 0; +} + +#endif diff --git a/lib/wininet_transport/Makefile b/lib/wininet_transport/Makefile new file mode 100644 index 0000000..cf0c52d --- /dev/null +++ b/lib/wininet_transport/Makefile @@ -0,0 +1,40 @@ +ifeq ($(SRCDIR)x,x) +SRCDIR = $(CURDIR)/../.. +endif + +include $(SRCDIR)/Makefile.config + +CFLAGS = $(CFLAGS_COMMON) $(CFLAGS_PERSONAL) $(CADD) +LDFLAGS = -lpthread $(LADD) + +INCLUDES = -I$(SRCDIR) -I$(SRCDIR)/src + +default: all + +.PHONY: all +all: xmlrpc_wininet_transport.lo + +.PHONY: clean +clean: clean-common + +.PHONY: distclean +distclean: clean distclean-common + +.PHONY: tags +tags: TAGS + +.PHONY: distdir +distdir: + +.PHONY: install +install: + +.PHONY: dep +dep: dep-common + +include $(SRCDIR)/Makefile.common + +include Makefile.depend + +xmlrpc_wininet_transport.lo:%.lo:%.c + $(LIBTOOL) --mode=compile $(CC) -c $(INCLUDES) $(CFLAGS) $< diff --git a/lib/wininet_transport/xmlrpc_wininet_transport.c b/lib/wininet_transport/xmlrpc_wininet_transport.c new file mode 100644 index 0000000..c583309 --- /dev/null +++ b/lib/wininet_transport/xmlrpc_wininet_transport.c @@ -0,0 +1,919 @@ +/*============================================================================= + xmlrpc_wininet_transport +=============================================================================== + WinInet-based client transport for Xmlrpc-c. Copyright information at + the bottom of this file. + + Changelog (changes by Steven A. Bone - sbone@pobox.com unless otherwise noted): + 05.01.01 - Significant refactoring of the transport layer due to internal + changes of the xmlrpc-c transports. Modeled after the CURL + based transport changes by Bryan Henderson. + 05.02.03 - Fixed Authorization header - thanks yamer. + 05.03.20 - Supports xmlrpc_xportparms, xmlrpc_wininet_xportparms added + *potential breaking change* - now by default we fail on invalid + SSL certs, use the xmlrpc_wininet_xportparms option to enable old + behavior. + +=============================================================================*/ + +#include +#include +#include +#include + +#include "xmlrpc_config.h" + +#include "bool.h" +#include "mallocvar.h" +#include "linklist.h" +#include "casprintf.h" + +#include "xmlrpc-c/base.h" +#include "xmlrpc-c/base_int.h" +#include "xmlrpc-c/client.h" +#include "xmlrpc-c/client_int.h" +#include "pthreadx.h" + +#if defined (WIN32) +# include +#endif /*WIN32*/ + +#if defined (WIN32) && defined(_DEBUG) +# include +# define new DEBUG_NEW +# define malloc(size) _malloc_dbg( size, _NORMAL_BLOCK, __FILE__, __LINE__) +# undef THIS_FILE + static char THIS_FILE[] = __FILE__; +#endif /*WIN32 && _DEBUG*/ + + +static HINTERNET hSyncInternetSession = NULL; + +/* Declare WinInet status callback. */ +void CALLBACK statusCallback (HINTERNET hInternet, + unsigned long dwContext, + unsigned long dwInternetStatus, + void * lpvStatusInformation, + unsigned long dwStatusInformationLength); + + +struct xmlrpc_client_transport { + pthread_mutex_t listLock; + struct list_head rpcList; + /* List of all RPCs that exist for this transport. An RPC exists + from the time the user requests it until the time the user + acknowledges it is done. + */ + int allowInvalidSSLCerts; + /* Flag to specify if we ignore invalid SSL Certificates. If this + is set to zero, calling a XMLRPC server with an invalid SSL + certificate will fail. This is the default behavior of the other + transports, but invalid certificates were allowed in pre 1.2 + wininet xmlrpc-c transports. + */ +}; + +typedef struct { + unsigned long http_status; + HINTERNET hHttpRequest; + HINTERNET hURL; + INTERNET_PORT nPort; + char szHostName[255]; + char szUrlPath[255]; + BOOL bUseSSL; + char *headerList; + BYTE *pSendData; + xmlrpc_mem_block *pResponseData; +} winInetTransaction; + +typedef struct { + struct list_head link; /* link in transport's list of RPCs */ + winInetTransaction * winInetTransactionP; + /* The object which does the HTTP transaction, with no knowledge + of XML-RPC or Xmlrpc-c. + */ + xmlrpc_mem_block * responseXmlP; + xmlrpc_bool threadExists; + pthread_t thread; + xmlrpc_transport_asynch_complete complete; + /* Routine to call to complete the RPC after it is complete HTTP-wise. + NULL if none. + */ + struct xmlrpc_call_info * callInfoP; + /* User's identifier for this RPC */ + struct xmlrpc_client_transport * clientTransportP; +} rpc; + +static void +createWinInetHeaderList( xmlrpc_env * const envP, + const xmlrpc_server_info * const serverP, + char ** const headerListP) { + + char *szHeaderList = NULL; + char *szContentType = "Content-Type: text/xml\r\n"; + + /* Send an authorization header if we need one. */ + if (serverP->_http_basic_auth) { + /* Make the header with content type and authorization */ + /* NOTE: A newline is required between each added header */ + szHeaderList = malloc(strlen(szContentType) + 17 + strlen(serverP->_http_basic_auth) + 1 ); + + if (szHeaderList == NULL) + xmlrpc_env_set_fault_formatted( + envP, XMLRPC_INTERNAL_ERROR, + "Couldn't allocate memory for authorization header"); + else { + memcpy(szHeaderList,szContentType, strlen(szContentType)); + memcpy(szHeaderList + strlen(szContentType),"\r\nAuthorization: ", 17); + memcpy(szHeaderList + strlen(szContentType) + 17, serverP->_http_basic_auth, + strlen(serverP->_http_basic_auth) + 1); + } + } + else + { + /* Just the content type header is needed */ + szHeaderList = malloc(strlen(szContentType) + 1); + + if (szHeaderList == NULL) + xmlrpc_env_set_fault_formatted( + envP, XMLRPC_INTERNAL_ERROR, "Couldn't allocate memory for standard header"); + else + memcpy(szHeaderList,szContentType, strlen(szContentType)+1); + } + + *headerListP = szHeaderList; +} + +static void +createWinInetTransaction(xmlrpc_env * const envP, + const xmlrpc_server_info * const serverP, + xmlrpc_mem_block * const callXmlP, + xmlrpc_mem_block * const responseXmlP, + winInetTransaction ** const winInetTransactionPP) { + + winInetTransaction * winInetTransactionP; + + MALLOCVAR(winInetTransactionP); + if (winInetTransactionP == NULL) + xmlrpc_env_set_fault_formatted( + envP, XMLRPC_INTERNAL_ERROR, + "No memory to create WinInet transaction."); + else { + char szExtraInfo[255]; + char szScheme[100]; + URL_COMPONENTS uc; + + /* Init to defaults */ + winInetTransactionP->http_status = 0; + winInetTransactionP->hHttpRequest = NULL; + winInetTransactionP->hURL = NULL; + winInetTransactionP->headerList=NULL; + winInetTransactionP->pSendData=NULL; + winInetTransactionP->pResponseData=responseXmlP; + + /* Parse the URL and store results into the winInetTransaction struct */ + memset (&uc, 0, sizeof (uc)); + uc.dwStructSize = sizeof (uc); + uc.lpszScheme = szScheme; + uc.dwSchemeLength = 100; + uc.lpszHostName = winInetTransactionP->szHostName; + uc.dwHostNameLength = 255; + uc.lpszUrlPath = winInetTransactionP->szUrlPath; + uc.dwUrlPathLength = 255; + uc.lpszExtraInfo = szExtraInfo; + uc.dwExtraInfoLength = 255; + if (InternetCrackUrl (serverP->_server_url, strlen (serverP->_server_url), ICU_ESCAPE, &uc) == FALSE) + { + xmlrpc_env_set_fault_formatted( envP, XMLRPC_INTERNAL_ERROR, + "Unable to parse the server URL."); + } + else + { + winInetTransactionP->nPort = (uc.nPort) ? uc.nPort : INTERNET_DEFAULT_HTTP_PORT; + if (_strnicmp (uc.lpszScheme, "https", 5) == 0) + winInetTransactionP->bUseSSL=TRUE; + else + winInetTransactionP->bUseSSL=FALSE; + createWinInetHeaderList(envP, serverP, &winInetTransactionP->headerList); + + XMLRPC_MEMBLOCK_APPEND(char, envP, callXmlP, "\0", 1); + if (!envP->fault_occurred) { + winInetTransactionP->pSendData = XMLRPC_MEMBLOCK_CONTENTS(char, callXmlP); + } + } + + + if (envP->fault_occurred) + free(winInetTransactionP); + } + *winInetTransactionPP = winInetTransactionP; +} + + + +static void +destroyWinInetTransaction(winInetTransaction * const winInetTransactionP) { + + XMLRPC_ASSERT_PTR_OK(winInetTransactionP); + + if (winInetTransactionP->hHttpRequest) + InternetCloseHandle (winInetTransactionP->hHttpRequest); + + if (winInetTransactionP->hURL) + InternetCloseHandle (winInetTransactionP->hURL); + + if (winInetTransactionP->headerList) + free(winInetTransactionP->headerList); + + free(winInetTransactionP); +} + +static void get_wininet_response ( xmlrpc_env * const envP, + winInetTransaction * const winInetTransactionP) +{ + INTERNET_BUFFERS inetBuffer; + LPTSTR pMsg = NULL; + PVOID pMsgMem = NULL; + unsigned long dwFlags; + unsigned long dwErr = 0; + unsigned long nExpected = 0; + unsigned long dwLen = sizeof (unsigned long); + void * body = NULL; + BOOL bOK = FALSE; + + inetBuffer.dwStructSize = sizeof (INTERNET_BUFFERS); + inetBuffer.Next = NULL; + inetBuffer.lpcszHeader = NULL; + inetBuffer.dwHeadersTotal = inetBuffer.dwHeadersLength = 0; + inetBuffer.dwOffsetHigh = inetBuffer.dwOffsetLow = 0; + inetBuffer.dwBufferLength = 0; + + bOK = HttpQueryInfo (winInetTransactionP->hHttpRequest, + HTTP_QUERY_CONTENT_LENGTH|HTTP_QUERY_FLAG_NUMBER, + &inetBuffer.dwBufferTotal, &dwLen, NULL); + if (!bOK) + { + dwErr = GetLastError (); + FormatMessage (FORMAT_MESSAGE_ALLOCATE_BUFFER | + FORMAT_MESSAGE_FROM_SYSTEM, + NULL, + dwErr, + MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT), + (LPTSTR) &pMsgMem, + 1024,NULL); + + pMsg = (pMsgMem) ? (LPTSTR)(pMsgMem) : "Sync HttpQueryInfo failed."; + XMLRPC_FAIL (envP, XMLRPC_NETWORK_ERROR, pMsg); + } + + if (inetBuffer.dwBufferTotal == 0) + XMLRPC_FAIL (envP, XMLRPC_NETWORK_ERROR, "WinInet returned no data"); + + body = inetBuffer.lpvBuffer = calloc (inetBuffer.dwBufferTotal, sizeof (TCHAR)); + dwFlags = IRF_SYNC; + inetBuffer.dwBufferLength = nExpected = inetBuffer.dwBufferTotal; + InternetQueryDataAvailable (winInetTransactionP->hHttpRequest, &inetBuffer.dwBufferLength, 0, 0); + + /* Read Response from InternetFile */ + do + { + if (inetBuffer.dwBufferLength != 0) + bOK = InternetReadFileEx (winInetTransactionP->hHttpRequest, &inetBuffer, dwFlags, 1); + + if (!bOK) + dwErr = GetLastError (); + + if (dwErr) + { + if (dwErr == WSAEWOULDBLOCK || dwErr == ERROR_IO_PENDING) + { + /* Non-block socket operation wait 10 msecs */ + SleepEx (10, TRUE); + /* Reset dwErr to zero for next pass */ + dwErr = 0; + } + else + { + FormatMessage (FORMAT_MESSAGE_ALLOCATE_BUFFER | + FORMAT_MESSAGE_FROM_SYSTEM, + NULL, + dwErr, + MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT), + (LPTSTR) &pMsgMem, + 1024,NULL); + pMsg = (pMsgMem) ? (LPTSTR)(pMsgMem) : "ASync InternetReadFileEx failed."; + XMLRPC_FAIL (envP, XMLRPC_NETWORK_ERROR, pMsg); + } + } + + if (inetBuffer.dwBufferLength) + { + TCHAR * bufptr = inetBuffer.lpvBuffer; + bufptr += inetBuffer.dwBufferLength; + inetBuffer.lpvBuffer = bufptr; + nExpected -= inetBuffer.dwBufferLength; + /* Adjust inetBuffer.dwBufferLength when it is greater than the */ + /* expected end of file */ + if (inetBuffer.dwBufferLength > nExpected) + inetBuffer.dwBufferLength = nExpected; + + } + else + inetBuffer.dwBufferLength = nExpected; + dwErr = 0; + } while (nExpected != 0); + + + /* Add to the response buffer. */ + xmlrpc_mem_block_append(envP, winInetTransactionP->pResponseData, body, inetBuffer.dwBufferTotal); + XMLRPC_FAIL_IF_FAULT (envP); + + cleanup: + /* Since the XMLRPC_FAIL calls goto cleanup, we must handle */ + /* the free'ing of the memory here. */ + if (pMsgMem != NULL) + { + LocalFree( pMsgMem ); + } + + if (body) + free (body); +} + + +static void +performWinInetTransaction(xmlrpc_env * const envP, + winInetTransaction * const winInetTransactionP, + struct xmlrpc_client_transport * const clientTransportP) { + LPTSTR pMsg = NULL; + LPVOID pMsgMem = NULL; + + unsigned long lastErr; + unsigned long reqFlags = INTERNET_FLAG_NO_UI; + char * acceptTypes[] = {"text/xml", NULL}; + unsigned long queryLen = sizeof (unsigned long); + + winInetTransactionP->hURL = InternetConnect (hSyncInternetSession, + winInetTransactionP->szHostName, winInetTransactionP->nPort, + NULL, NULL, INTERNET_SERVICE_HTTP, 0, 1); + + /* Start our request running. */ + if (winInetTransactionP->bUseSSL == TRUE) + reqFlags |= INTERNET_FLAG_SECURE |INTERNET_FLAG_IGNORE_CERT_CN_INVALID; + + winInetTransactionP->hHttpRequest = HttpOpenRequest (winInetTransactionP->hURL, "POST", + winInetTransactionP->szUrlPath, "HTTP/1.1", NULL, (const char **)&acceptTypes, + reqFlags, 1); + + XMLRPC_FAIL_IF_NULL(winInetTransactionP->hHttpRequest,envP, XMLRPC_INTERNAL_ERROR, + "Unable to open the requested URL."); + + if ( HttpAddRequestHeaders (winInetTransactionP->hHttpRequest, winInetTransactionP->headerList, + strlen (winInetTransactionP->headerList), HTTP_ADDREQ_FLAG_ADD|HTTP_ADDREQ_FLAG_REPLACE ) ==FALSE) + { + XMLRPC_FAIL (envP, XMLRPC_INTERNAL_ERROR, "Could not set Content-Type."); + } + +#ifdef DEBUG + /* Provide the user with transport status information */ + InternetSetStatusCallback (winInetTransactionP->hHttpRequest, statusCallback); +#endif + +Again: + /* Send the requested XML remote procedure command */ + if (HttpSendRequest (winInetTransactionP->hHttpRequest, NULL, 0, + winInetTransactionP->pSendData, + strlen(winInetTransactionP->pSendData))==FALSE) + { + lastErr = GetLastError (); + + FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | + FORMAT_MESSAGE_ALLOCATE_BUFFER | + FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, + lastErr, + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), + (LPTSTR) &pMsgMem, + 0, NULL); + + + if (pMsgMem == NULL) + { + switch (lastErr) + { + case ERROR_INTERNET_CANNOT_CONNECT: + pMsg = "Sync HttpSendRequest failed: Connection refused."; + break; + case ERROR_INTERNET_CLIENT_AUTH_CERT_NEEDED: + pMsg = "Sync HttpSendRequest failed: Client authorization certificate needed."; + break; + + /* The following conditions are recommendations that microsoft */ + /* provides in their knowledge base. */ + + /* HOWTO: Handle Invalid Certificate Authority Error with WinInet (Q182888) */ + case ERROR_INTERNET_INVALID_CA: + if (clientTransportP->allowInvalidSSLCerts){ + OutputDebugString ("Sync HttpSendRequest failed: " + "The function is unfamiliar with the certificate " + "authority that generated the server's certificate. "); + reqFlags = SECURITY_FLAG_IGNORE_UNKNOWN_CA; + + InternetSetOption (winInetTransactionP->hHttpRequest, INTERNET_OPTION_SECURITY_FLAGS, + &reqFlags, sizeof (reqFlags)); + + goto Again; + } + else{ + pMsg = "Invalid or unknown/untrusted SSL Certificate Authority."; + } + break; + + /* HOWTO: Make SSL Requests Using WinInet (Q168151) */ + case ERROR_INTERNET_SEC_CERT_CN_INVALID: + if (clientTransportP->allowInvalidSSLCerts){ + OutputDebugString ("Sync HttpSendRequest failed: " + "The SSL certificate common name (host name field) is incorrect\r\n " + "for example, if you entered www.server.com and the common name " + "on the certificate says www.different.com. "); + + reqFlags = INTERNET_FLAG_IGNORE_CERT_CN_INVALID; + + InternetSetOption (winInetTransactionP->hHttpRequest, INTERNET_OPTION_SECURITY_FLAGS, + &reqFlags, sizeof (reqFlags)); + + goto Again; + } + else{ + pMsg = "The SSL certificate common name (host name field) is incorrect."; + } + break; + + case ERROR_INTERNET_SEC_CERT_DATE_INVALID: + if (clientTransportP->allowInvalidSSLCerts){ + OutputDebugString ("Sync HttpSendRequest failed: " + "The SSL certificate date that was received from the server is " + "bad. The certificate is expired. "); + + reqFlags = INTERNET_FLAG_IGNORE_CERT_DATE_INVALID; + + InternetSetOption (winInetTransactionP->hHttpRequest, INTERNET_OPTION_SECURITY_FLAGS, + &reqFlags, sizeof (reqFlags)); + + goto Again; + } + else{ + pMsg = "The SSL certificate date that was received from the server is invalid."; + } + break; + + default: + pMsg = (LPTSTR)pMsgMem = LocalAlloc (LPTR, MAX_PATH); + sprintf (pMsg, "Sync HttpSendRequest failed: GetLastError (%d)", lastErr); + break; + + } + } + else + { + pMsg = (LPTSTR)(pMsgMem); + + } + XMLRPC_FAIL (envP, XMLRPC_NETWORK_ERROR, pMsg); + + } + + if( HttpQueryInfo (winInetTransactionP->hHttpRequest, + HTTP_QUERY_FLAG_NUMBER|HTTP_QUERY_STATUS_CODE, + &winInetTransactionP->http_status, &queryLen, NULL) == FALSE) + { + lastErr = GetLastError (); + FormatMessage (FORMAT_MESSAGE_ALLOCATE_BUFFER | + FORMAT_MESSAGE_FROM_SYSTEM, + NULL, + lastErr, + MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT), + (LPTSTR) &pMsgMem, + 1024,NULL); + + pMsg = (pMsgMem) ? (LPTSTR)(pMsgMem) : "Sync HttpQueryInfo failed."; + XMLRPC_FAIL (envP, XMLRPC_NETWORK_ERROR, pMsg); + + } + + /* Make sure we got a "200 OK" message from the remote server. */ + if(winInetTransactionP->http_status!=200) + { + unsigned long msgLen = 1024; + char errMsg [1024]; + *errMsg = 0; + HttpQueryInfo (winInetTransactionP->hHttpRequest, HTTP_QUERY_STATUS_TEXT, errMsg, &msgLen, NULL); + + /* Set our fault. We break this into multiple lines because it */ + /* will generally contain line breaks to begin with. */ + xmlrpc_env_set_fault_formatted (envP, XMLRPC_NETWORK_ERROR, + "HTTP error #%d occurred\n %s", winInetTransactionP->http_status, errMsg); + goto cleanup; + + } + /* Read the response. */ + get_wininet_response (envP, winInetTransactionP); + XMLRPC_FAIL_IF_FAULT (envP); + + cleanup: + /* Since the XMLRPC_FAIL calls goto cleanup, we must handle */ + /* the free'ing of the memory here. */ + if (pMsgMem != NULL) + { + LocalFree( pMsgMem ); + } + +} + +static unsigned __stdcall +doAsyncRpc(void * arg) { + rpc * const rpcP = arg; + xmlrpc_env env; + xmlrpc_env_init(&env); + performWinInetTransaction(&env, rpcP->winInetTransactionP, rpcP->clientTransportP ); + rpcP->complete(rpcP->callInfoP, rpcP->responseXmlP, env); + xmlrpc_env_clean(&env); + return 0; +} + + +static void +createRpcThread(xmlrpc_env * const envP, + rpc * const rpcP, + pthread_t * const threadP) { + + int rc; + + rc = pthread_create(threadP, NULL, doAsyncRpc, rpcP); + switch (rc) { + case 0: + break; + case EAGAIN: + xmlrpc_env_set_fault_formatted( + envP, XMLRPC_INTERNAL_ERROR, + "pthread_create() failed: System Resources exceeded."); + break; + case EINVAL: + xmlrpc_env_set_fault_formatted( + envP, XMLRPC_INTERNAL_ERROR, + "pthread_create() failed: Param Error for attr."); + break; + case ENOMEM: + xmlrpc_env_set_fault_formatted( + envP, XMLRPC_INTERNAL_ERROR, + "pthread_create() failed: No memory for new thread."); + break; + default: + xmlrpc_env_set_fault_formatted( + envP, XMLRPC_INTERNAL_ERROR, + "pthread_create() failed: Unrecognized error code %d.", rc); + break; + } +} + +static void +rpcCreate(xmlrpc_env * const envP, + struct xmlrpc_client_transport * const clientTransportP, + const xmlrpc_server_info * const serverP, + xmlrpc_mem_block * const callXmlP, + xmlrpc_mem_block * const responseXmlP, + xmlrpc_transport_asynch_complete complete, + struct xmlrpc_call_info * const callInfoP, + rpc ** const rpcPP) { + + rpc * rpcP; + + MALLOCVAR(rpcP); + if (rpcP == NULL) + xmlrpc_env_set_fault_formatted( + envP, XMLRPC_INTERNAL_ERROR, + "Couldn't allocate memory for rpc object"); + else { + rpcP->callInfoP = callInfoP; + rpcP->complete = complete; + rpcP->responseXmlP = responseXmlP; + rpcP->threadExists = FALSE; + + createWinInetTransaction(envP, serverP, + callXmlP, responseXmlP, + &rpcP->winInetTransactionP); + if (!envP->fault_occurred) { + if (complete) { + createRpcThread(envP, rpcP, &rpcP->thread); + if (!envP->fault_occurred) + rpcP->threadExists = TRUE; + } + if (!envP->fault_occurred) { + list_init_header(&rpcP->link, rpcP); + pthread_mutex_lock(&clientTransportP->listLock); + list_add_head(&clientTransportP->rpcList, &rpcP->link); + pthread_mutex_unlock(&clientTransportP->listLock); + } + if (envP->fault_occurred) + destroyWinInetTransaction(rpcP->winInetTransactionP); + } + if (envP->fault_occurred) + free(rpcP); + } + *rpcPP = rpcP; +} + +static void +rpcDestroy(rpc * const rpcP) { + + XMLRPC_ASSERT_PTR_OK(rpcP); + XMLRPC_ASSERT(!rpcP->threadExists); + + destroyWinInetTransaction(rpcP->winInetTransactionP); + + list_remove(&rpcP->link); + + free(rpcP); +} + +static void * +finishRpc(struct list_head * const headerP, + void * const context ATTR_UNUSED) { + + rpc * const rpcP = headerP->itemP; + + if (rpcP->threadExists) { + void *status; + int result; + + result = pthread_join(rpcP->thread, &status); + + rpcP->threadExists = FALSE; + } + + XMLRPC_MEMBLOCK_FREE(char, rpcP->responseXmlP); + + rpcDestroy(rpcP); + + return NULL; +} + + +/* Used for debugging purposes to track the status of +** your request. */ +void CALLBACK statusCallback (HINTERNET hInternet, + unsigned long dwContext, + unsigned long dwInternetStatus, + void * lpvStatusInformation, + unsigned long dwStatusInformationLength) +{ + switch (dwInternetStatus) + { + case INTERNET_STATUS_RESOLVING_NAME: + OutputDebugString("INTERNET_STATUS_RESOLVING_NAME\r\n"); + break; + + case INTERNET_STATUS_NAME_RESOLVED: + OutputDebugString("INTERNET_STATUS_NAME_RESOLVED\r\n"); + break; + + case INTERNET_STATUS_HANDLE_CREATED: + OutputDebugString("INTERNET_STATUS_HANDLE_CREATED\r\n"); + break; + + case INTERNET_STATUS_CONNECTING_TO_SERVER: + OutputDebugString("INTERNET_STATUS_CONNECTING_TO_SERVER\r\n"); + break; + + case INTERNET_STATUS_REQUEST_SENT: + OutputDebugString("INTERNET_STATUS_REQUEST_SENT\r\n"); + break; + + case INTERNET_STATUS_SENDING_REQUEST: + OutputDebugString("INTERNET_STATUS_SENDING_REQUEST\r\n"); + break; + + case INTERNET_STATUS_CONNECTED_TO_SERVER: + OutputDebugString("INTERNET_STATUS_CONNECTED_TO_SERVER\r\n"); + break; + + case INTERNET_STATUS_RECEIVING_RESPONSE: + OutputDebugString("INTERNET_STATUS_RECEIVING_RESPONSE\r\n"); + break; + + case INTERNET_STATUS_RESPONSE_RECEIVED: + OutputDebugString("INTERNET_STATUS_RESPONSE_RECEIVED\r\n"); + break; + + case INTERNET_STATUS_CLOSING_CONNECTION: + OutputDebugString("INTERNET_STATUS_CLOSING_CONNECTION\r\n"); + break; + + case INTERNET_STATUS_CONNECTION_CLOSED: + OutputDebugString("INTERNET_STATUS_CONNECTION_CLOSED\r\n"); + break; + + case INTERNET_STATUS_HANDLE_CLOSING: + OutputDebugString("INTERNET_STATUS_HANDLE_CLOSING\r\n"); + break; + + case INTERNET_STATUS_CTL_RESPONSE_RECEIVED: + OutputDebugString("INTERNET_STATUS_CTL_RESPONSE_RECEIVED\r\n"); + break; + + case INTERNET_STATUS_REDIRECT: + OutputDebugString("INTERNET_STATUS_REDIRECT\r\n"); + break; + + case INTERNET_STATUS_REQUEST_COMPLETE: + /* This indicates the data is ready. */ + OutputDebugString("INTERNET_STATUS_REQUEST_COMPLETE\r\n"); + break; + + default: + OutputDebugString("statusCallback, default case!\r\n"); + break; + } +} + +static void +create(xmlrpc_env * const envP, + int const flags ATTR_UNUSED, + const char * const appname ATTR_UNUSED, + const char * const appversion ATTR_UNUSED, + const struct xmlrpc_xportparms * const transportparmsP, + size_t const parm_size, + struct xmlrpc_client_transport ** const handlePP) { +/*---------------------------------------------------------------------------- + This does the 'create' operation for a WinInet client transport. +-----------------------------------------------------------------------------*/ + struct xmlrpc_client_transport * transportP; + + struct xmlrpc_wininet_xportparms * const wininetXportParmsP = + (struct xmlrpc_wininet_xportparms *) transportparmsP; + + MALLOCVAR(transportP); + if (transportP == NULL) + xmlrpc_env_set_fault_formatted( + envP, XMLRPC_INTERNAL_ERROR, + "Unable to allocate transport descriptor."); + else { + pthread_mutex_init(&transportP->listLock, NULL); + + list_make_empty(&transportP->rpcList); + + if (hSyncInternetSession == NULL) + hSyncInternetSession = InternetOpen ("xmlrpc-c wininet transport", + INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0); + + if (!wininetXportParmsP || parm_size < XMLRPC_WXPSIZE(allowInvalidSSLCerts)) + transportP->allowInvalidSSLCerts = 0; + else + transportP->allowInvalidSSLCerts = wininetXportParmsP->allowInvalidSSLCerts; + + *handlePP = transportP; + } +} + + +static void +destroy(struct xmlrpc_client_transport * const clientTransportP) { +/*---------------------------------------------------------------------------- + This does the 'destroy' operation for a WinInet client transport. +-----------------------------------------------------------------------------*/ + XMLRPC_ASSERT(clientTransportP != NULL); + + XMLRPC_ASSERT(list_is_empty(&clientTransportP->rpcList)); + + if (hSyncInternetSession) + InternetCloseHandle(hSyncInternetSession); + hSyncInternetSession = NULL; + + pthread_mutex_destroy(&clientTransportP->listLock); + + free(clientTransportP); +} + + +static void +sendRequest(xmlrpc_env * const envP, + struct xmlrpc_client_transport * const clientTransportP, + const xmlrpc_server_info * const serverP, + xmlrpc_mem_block * const callXmlP, + xmlrpc_transport_asynch_complete complete, + struct xmlrpc_call_info * const callInfoP) { +/*---------------------------------------------------------------------------- + Initiate an XML-RPC rpc asynchronously. Don't wait for it to go to + the server. + + Unless we return failure, we arrange to have complete() called when + the rpc completes. + + This does the 'send_request' operation for a WinInet client transport. +-----------------------------------------------------------------------------*/ + rpc * rpcP; + xmlrpc_mem_block * responseXmlP; + + responseXmlP = XMLRPC_MEMBLOCK_NEW(char, envP, 0); + if (!envP->fault_occurred) { + rpcCreate(envP, clientTransportP, serverP, callXmlP, responseXmlP, + complete, callInfoP, + &rpcP); + + if (envP->fault_occurred) + XMLRPC_MEMBLOCK_FREE(char, responseXmlP); + } + /* The user's eventual finish_asynch call will destroy this RPC + and response buffer + */ +} + +static void +finishAsynch(struct xmlrpc_client_transport * const clientTransportP, + xmlrpc_timeoutType const timeoutType ATTR_UNUSED, + xmlrpc_timeout const timeout ATTR_UNUSED) { +/*---------------------------------------------------------------------------- + Wait for the threads of all outstanding RPCs to exit and destroy those + RPCs. + + This does the 'finish_asynch' operation for a WinInet client transport. +-----------------------------------------------------------------------------*/ + /* We ignore any timeout request. Some day, we should figure out how + to set an alarm and interrupt running threads. + */ + + pthread_mutex_lock(&clientTransportP->listLock); + + list_foreach(&clientTransportP->rpcList, finishRpc, NULL); + + pthread_mutex_unlock(&clientTransportP->listLock); +} + + +static void +call(xmlrpc_env * const envP, + struct xmlrpc_client_transport * const clientTransportP, + const xmlrpc_server_info * const serverP, + xmlrpc_mem_block * const callXmlP, + xmlrpc_mem_block ** const responsePP) { + + + xmlrpc_mem_block * responseXmlP; + rpc * rpcP; + + XMLRPC_ASSERT_ENV_OK(envP); + XMLRPC_ASSERT_PTR_OK(serverP); + XMLRPC_ASSERT_PTR_OK(callXmlP); + XMLRPC_ASSERT_PTR_OK(responsePP); + + responseXmlP = XMLRPC_MEMBLOCK_NEW(char, envP, 0); + if (!envP->fault_occurred) { + rpcCreate(envP, clientTransportP, serverP, callXmlP, responseXmlP, + NULL, NULL, &rpcP); + if (!envP->fault_occurred) { + performWinInetTransaction(envP, rpcP->winInetTransactionP, clientTransportP); + + *responsePP = responseXmlP; + + rpcDestroy(rpcP); + } + if (envP->fault_occurred) + XMLRPC_MEMBLOCK_FREE(char, responseXmlP); + } +} + + +struct xmlrpc_client_transport_ops xmlrpc_wininet_transport_ops = { + NULL, + NULL, + &create, + &destroy, + &sendRequest, + &call, + &finishAsynch, +}; + +/* Copyright (C) 2001 by First Peer, Inc. All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +** ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +** OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +** HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +** LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +** OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +** SUCH DAMAGE. */ diff --git a/lib/wininet_transport/xmlrpc_wininet_transport.h b/lib/wininet_transport/xmlrpc_wininet_transport.h new file mode 100644 index 0000000..f4f0f4e --- /dev/null +++ b/lib/wininet_transport/xmlrpc_wininet_transport.h @@ -0,0 +1,8 @@ +#ifndef XMLRPC_WININET_TRANSPORT_H +#define XMLRPC_WININET_TRANSPORT_H + +#include "xmlrpc-c/transport.h" + +extern struct xmlrpc_client_transport_ops xmlrpc_wininet_transport_ops; + +#endif diff --git a/ltconfig b/ltconfig new file mode 100755 index 0000000..a01334f --- /dev/null +++ b/ltconfig @@ -0,0 +1,3078 @@ +#! /bin/sh + +# ltconfig - Create a system-specific libtool. +# Copyright (C) 1996-1999 Free Software Foundation, Inc. +# Originally by Gordon Matzigkeit , 1996 +# +# 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, 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. + +# A lot of this script is taken from autoconf-2.10. + +# Check that we are running under the correct shell. +SHELL=${CONFIG_SHELL-/bin/sh} +echo=echo +if test "X$1" = X--no-reexec; then + # Discard the --no-reexec flag, and continue. + shift +elif test "X$1" = X--fallback-echo; then + # Avoid inline document here, it may be left over + : +elif test "X`($echo '\t') 2>/dev/null`" = 'X\t'; then + # Yippee, $echo works! + : +else + # Restart under the correct shell. + exec "$SHELL" "$0" --no-reexec ${1+"$@"} +fi + +if test "X$1" = X--fallback-echo; then + # used as fallback echo + shift + cat </dev/null`} + case X$UNAME in + *-DOS) PATH_SEPARATOR=';' ;; + *) PATH_SEPARATOR=':' ;; + esac +fi + +# The HP-UX ksh and POSIX shell print the target directory to stdout +# if CDPATH is set. +if test "X${CDPATH+set}" = Xset; then CDPATH=:; export CDPATH; fi + +if test "X${echo_test_string+set}" != Xset; then + # find a string as large as possible, as long as the shell can cope with it + for cmd in 'sed 50q "$0"' 'sed 20q "$0"' 'sed 10q "$0"' 'sed 2q "$0"' 'echo test'; do + # expected sizes: less than 2Kb, 1Kb, 512 bytes, 16 bytes, ... + if (echo_test_string="`eval $cmd`") 2>/dev/null && + echo_test_string="`eval $cmd`" && + (test "X$echo_test_string" = "X$echo_test_string") 2>/dev/null; then + break + fi + done +fi + +if test "X`($echo '\t') 2>/dev/null`" != 'X\t' || + test "X`($echo "$echo_test_string") 2>/dev/null`" != X"$echo_test_string"; then + # The Solaris, AIX, and Digital Unix default echo programs unquote + # backslashes. This makes it impossible to quote backslashes using + # echo "$something" | sed 's/\\/\\\\/g' + # + # So, first we look for a working echo in the user's PATH. + + IFS="${IFS= }"; save_ifs="$IFS"; IFS="${IFS}${PATH_SEPARATOR}" + for dir in $PATH /usr/ucb; do + if (test -f $dir/echo || test -f $dir/echo$ac_exeext) && + test "X`($dir/echo '\t') 2>/dev/null`" = 'X\t' && + test "X`($dir/echo "$echo_test_string") 2>/dev/null`" = X"$echo_test_string"; then + echo="$dir/echo" + break + fi + done + IFS="$save_ifs" + + if test "X$echo" = Xecho; then + # We didn't find a better echo, so look for alternatives. + if test "X`(print -r '\t') 2>/dev/null`" = 'X\t' && + test "X`(print -r "$echo_test_string") 2>/dev/null`" = X"$echo_test_string"; then + # This shell has a builtin print -r that does the trick. + echo='print -r' + elif (test -f /bin/ksh || test -f /bin/ksh$ac_exeext) && + test "X$CONFIG_SHELL" != X/bin/ksh; then + # If we have ksh, try running ltconfig again with it. + ORIGINAL_CONFIG_SHELL="${CONFIG_SHELL-/bin/sh}" + export ORIGINAL_CONFIG_SHELL + CONFIG_SHELL=/bin/ksh + export CONFIG_SHELL + exec "$CONFIG_SHELL" "$0" --no-reexec ${1+"$@"} + else + # Try using printf. + echo='printf "%s\n"' + if test "X`($echo '\t') 2>/dev/null`" = 'X\t' && + test "X`($echo "$echo_test_string") 2>/dev/null`" = X"$echo_test_string"; then + # Cool, printf works + : + elif test "X`("$ORIGINAL_CONFIG_SHELL" "$0" --fallback-echo '\t') 2>/dev/null`" = 'X\t' && + test "X`("$ORIGINAL_CONFIG_SHELL" "$0" --fallback-echo "$echo_test_string") 2>/dev/null`" = X"$echo_test_string"; then + CONFIG_SHELL="$ORIGINAL_CONFIG_SHELL" + export CONFIG_SHELL + SHELL="$CONFIG_SHELL" + export SHELL + echo="$CONFIG_SHELL $0 --fallback-echo" + elif test "X`("$CONFIG_SHELL" "$0" --fallback-echo '\t') 2>/dev/null`" = 'X\t' && + test "X`("$CONFIG_SHELL" "$0" --fallback-echo "$echo_test_string") 2>/dev/null`" = X"$echo_test_string"; then + echo="$CONFIG_SHELL $0 --fallback-echo" + else + # maybe with a smaller string... + prev=: + + for cmd in 'echo test' 'sed 2q "$0"' 'sed 10q "$0"' 'sed 20q "$0"' 'sed 50q "$0"'; do + if (test "X$echo_test_string" = "X`eval $cmd`") 2>/dev/null; then + break + fi + prev="$cmd" + done + + if test "$prev" != 'sed 50q "$0"'; then + echo_test_string=`eval $prev` + export echo_test_string + exec "${ORIGINAL_CONFIG_SHELL}" "$0" ${1+"$@"} + else + # Oops. We lost completely, so just stick with echo. + echo=echo + fi + fi + fi + fi +fi + +# Sed substitution that helps us do robust quoting. It backslashifies +# metacharacters that are still active within double-quoted strings. +Xsed='sed -e s/^X//' +sed_quote_subst='s/\([\\"\\`$\\\\]\)/\\\1/g' + +# Same as above, but do not quote variable references. +double_quote_subst='s/\([\\"\\`\\\\]\)/\\\1/g' + +# Sed substitution to delay expansion of an escaped shell variable in a +# double_quote_subst'ed string. +delay_variable_subst='s/\\\\\\\\\\\$/\\\\\\$/g' + +# The name of this program. +progname=`$echo "X$0" | $Xsed -e 's%^.*/%%'` + +# Constants: +PROGRAM=ltconfig +PACKAGE=libtool +VERSION=1.3.4 +TIMESTAMP=" (1.385.2.196 1999/12/07 21:47:57)" +ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5' +ac_link='${CC-cc} -o conftest $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5' +rm="rm -f" + +help="Try \`$progname --help' for more information." + +# Global variables: +default_ofile=libtool +can_build_shared=yes +enable_shared=yes +# All known linkers require a `.a' archive for static linking (except M$VC, +# which needs '.lib'). +enable_static=yes +enable_fast_install=yes +enable_dlopen=unknown +enable_win32_dll=no +ltmain= +silent= +srcdir= +ac_config_guess= +ac_config_sub= +host= +nonopt= +ofile="$default_ofile" +verify_host=yes +with_gcc=no +with_gnu_ld=no +need_locks=yes +ac_ext=c +objext=o +libext=a +exeext= +cache_file= + +old_AR="$AR" +old_CC="$CC" +old_CFLAGS="$CFLAGS" +old_CPPFLAGS="$CPPFLAGS" +old_LDFLAGS="$LDFLAGS" +old_LD="$LD" +old_LN_S="$LN_S" +old_LIBS="$LIBS" +old_NM="$NM" +old_RANLIB="$RANLIB" +old_DLLTOOL="$DLLTOOL" +old_OBJDUMP="$OBJDUMP" +old_AS="$AS" + +# Parse the command line options. +args= +prev= +for option +do + case "$option" in + -*=*) optarg=`echo "$option" | sed 's/[-_a-zA-Z0-9]*=//'` ;; + *) optarg= ;; + esac + + # If the previous option needs an argument, assign it. + if test -n "$prev"; then + eval "$prev=\$option" + prev= + continue + fi + + case "$option" in + --help) cat <&2 + echo "$help" 1>&2 + exit 1 + ;; + + *) + if test -z "$ltmain"; then + ltmain="$option" + elif test -z "$host"; then +# This generates an unnecessary warning for sparc-sun-solaris4.1.3_U1 +# if test -n "`echo $option| sed 's/[-a-z0-9.]//g'`"; then +# echo "$progname: warning \`$option' is not a valid host type" 1>&2 +# fi + host="$option" + else + echo "$progname: too many arguments" 1>&2 + echo "$help" 1>&2 + exit 1 + fi ;; + esac +done + +if test -z "$ltmain"; then + echo "$progname: you must specify a LTMAIN file" 1>&2 + echo "$help" 1>&2 + exit 1 +fi + +if test ! -f "$ltmain"; then + echo "$progname: \`$ltmain' does not exist" 1>&2 + echo "$help" 1>&2 + exit 1 +fi + +# Quote any args containing shell metacharacters. +ltconfig_args= +for arg +do + case "$arg" in + *" "*|*" "*|*[\[\]\~\#\$\^\&\*\(\)\{\}\\\|\;\<\>\?]*) + ltconfig_args="$ltconfig_args '$arg'" ;; + *) ltconfig_args="$ltconfig_args $arg" ;; + esac +done + +# A relevant subset of AC_INIT. + +# File descriptor usage: +# 0 standard input +# 1 file creation +# 2 errors and warnings +# 3 some systems may open it to /dev/tty +# 4 used on the Kubota Titan +# 5 compiler messages saved in config.log +# 6 checking for... messages and results +if test "$silent" = yes; then + exec 6>/dev/null +else + exec 6>&1 +fi +exec 5>>./config.log + +# NLS nuisances. +# Only set LANG and LC_ALL to C if already set. +# These must not be set unconditionally because not all systems understand +# e.g. LANG=C (notably SCO). +if test "X${LC_ALL+set}" = Xset; then LC_ALL=C; export LC_ALL; fi +if test "X${LANG+set}" = Xset; then LANG=C; export LANG; fi + +if test -n "$cache_file" && test -r "$cache_file"; then + echo "loading cache $cache_file within ltconfig" + . $cache_file +fi + +if (echo "testing\c"; echo 1,2,3) | grep c >/dev/null; then + # Stardent Vistra SVR4 grep lacks -e, says ghazi@caip.rutgers.edu. + if (echo -n testing; echo 1,2,3) | sed s/-n/xn/ | grep xn >/dev/null; then + ac_n= ac_c=' +' ac_t=' ' + else + ac_n=-n ac_c= ac_t= + fi +else + ac_n= ac_c='\c' ac_t= +fi + +if test -z "$srcdir"; then + # Assume the source directory is the same one as the path to LTMAIN. + srcdir=`$echo "X$ltmain" | $Xsed -e 's%/[^/]*$%%'` + test "$srcdir" = "$ltmain" && srcdir=. +fi + +trap "$rm conftest*; exit 1" 1 2 15 +if test "$verify_host" = yes; then + # Check for config.guess and config.sub. + ac_aux_dir= + for ac_dir in $srcdir $srcdir/.. $srcdir/../..; do + if test -f $ac_dir/config.guess; then + ac_aux_dir=$ac_dir + break + fi + done + if test -z "$ac_aux_dir"; then + echo "$progname: cannot find config.guess in $srcdir $srcdir/.. $srcdir/../.." 1>&2 + echo "$help" 1>&2 + exit 1 + fi + ac_config_guess=$ac_aux_dir/config.guess + ac_config_sub=$ac_aux_dir/config.sub + + # Make sure we can run config.sub. + if $SHELL $ac_config_sub sun4 >/dev/null 2>&1; then : + else + echo "$progname: cannot run $ac_config_sub" 1>&2 + echo "$help" 1>&2 + exit 1 + fi + + echo $ac_n "checking host system type""... $ac_c" 1>&6 + + host_alias=$host + case "$host_alias" in + "") + if host_alias=`$SHELL $ac_config_guess`; then : + else + echo "$progname: cannot guess host type; you must specify one" 1>&2 + echo "$help" 1>&2 + exit 1 + fi ;; + esac + host=`$SHELL $ac_config_sub $host_alias` + echo "$ac_t$host" 1>&6 + + # Make sure the host verified. + test -z "$host" && exit 1 + +elif test -z "$host"; then + echo "$progname: you must specify a host type if you use \`--no-verify'" 1>&2 + echo "$help" 1>&2 + exit 1 +else + host_alias=$host +fi + +# Transform linux* to *-*-linux-gnu*, to support old configure scripts. +case "$host_os" in +linux-gnu*) ;; +linux*) host=`echo $host | sed 's/^\(.*-.*-linux\)\(.*\)$/\1-gnu\2/'` +esac + +host_cpu=`echo $host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\1/'` +host_vendor=`echo $host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\2/'` +host_os=`echo $host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\3/'` + +case "$host_os" in +aix3*) + # AIX sometimes has problems with the GCC collect2 program. For some + # reason, if we set the COLLECT_NAMES environment variable, the problems + # vanish in a puff of smoke. + if test "X${COLLECT_NAMES+set}" != Xset; then + COLLECT_NAMES= + export COLLECT_NAMES + fi + ;; +esac + +# Determine commands to create old-style static archives. +old_archive_cmds='$AR cru $oldlib$oldobjs' +old_postinstall_cmds='chmod 644 $oldlib' +old_postuninstall_cmds= + +# Set a sane default for `AR'. +test -z "$AR" && AR=ar + +# Set a sane default for `OBJDUMP'. +test -z "$OBJDUMP" && OBJDUMP=objdump + +# If RANLIB is not set, then run the test. +if test "${RANLIB+set}" != "set"; then + result=no + + echo $ac_n "checking for ranlib... $ac_c" 1>&6 + IFS="${IFS= }"; save_ifs="$IFS"; IFS="${IFS}${PATH_SEPARATOR}" + for dir in $PATH; do + test -z "$dir" && dir=. + if test -f $dir/ranlib || test -f $dir/ranlib$ac_exeext; then + RANLIB="ranlib" + result="ranlib" + break + fi + done + IFS="$save_ifs" + + echo "$ac_t$result" 1>&6 +fi + +if test -n "$RANLIB"; then + old_archive_cmds="$old_archive_cmds~\$RANLIB \$oldlib" + old_postinstall_cmds="\$RANLIB \$oldlib~$old_postinstall_cmds" +fi + +# Set sane defaults for `DLLTOOL', `OBJDUMP', and `AS', used on cygwin. +test -z "$DLLTOOL" && DLLTOOL=dlltool +test -z "$OBJDUMP" && OBJDUMP=objdump +test -z "$AS" && AS=as + +# Check to see if we are using GCC. +if test "$with_gcc" != yes || test -z "$CC"; then + # If CC is not set, then try to find GCC or a usable CC. + if test -z "$CC"; then + echo $ac_n "checking for gcc... $ac_c" 1>&6 + IFS="${IFS= }"; save_ifs="$IFS"; IFS="${IFS}${PATH_SEPARATOR}" + for dir in $PATH; do + test -z "$dir" && dir=. + if test -f $dir/gcc || test -f $dir/gcc$ac_exeext; then + CC="gcc" + break + fi + done + IFS="$save_ifs" + + if test -n "$CC"; then + echo "$ac_t$CC" 1>&6 + else + echo "$ac_t"no 1>&6 + fi + fi + + # Not "gcc", so try "cc", rejecting "/usr/ucb/cc". + if test -z "$CC"; then + echo $ac_n "checking for cc... $ac_c" 1>&6 + IFS="${IFS= }"; save_ifs="$IFS"; IFS="${IFS}${PATH_SEPARATOR}" + cc_rejected=no + for dir in $PATH; do + test -z "$dir" && dir=. + if test -f $dir/cc || test -f $dir/cc$ac_exeext; then + if test "$dir/cc" = "/usr/ucb/cc"; then + cc_rejected=yes + continue + fi + CC="cc" + break + fi + done + IFS="$save_ifs" + if test $cc_rejected = yes; then + # We found a bogon in the path, so make sure we never use it. + set dummy $CC + shift + if test $# -gt 0; then + # We chose a different compiler from the bogus one. + # However, it has the same name, so the bogon will be chosen + # first if we set CC to just the name; use the full file name. + shift + set dummy "$dir/cc" "$@" + shift + CC="$@" + fi + fi + + if test -n "$CC"; then + echo "$ac_t$CC" 1>&6 + else + echo "$ac_t"no 1>&6 + fi + + if test -z "$CC"; then + echo "$progname: error: no acceptable cc found in \$PATH" 1>&2 + exit 1 + fi + fi + + # Now see if the compiler is really GCC. + with_gcc=no + echo $ac_n "checking whether we are using GNU C... $ac_c" 1>&6 + echo "$progname:581: checking whether we are using GNU C" >&5 + + $rm conftest.c + cat > conftest.c <&5; (eval $ac_try) 2>&5; }; } | egrep yes >/dev/null 2>&1; then + with_gcc=yes + fi + $rm conftest.c + echo "$ac_t$with_gcc" 1>&6 +fi + +# Allow CC to be a program name with arguments. +set dummy $CC +compiler="$2" + +echo $ac_n "checking for object suffix... $ac_c" 1>&6 +$rm conftest* +echo 'int i = 1;' > conftest.c +echo "$progname:603: checking for object suffix" >& 5 +if { (eval echo $progname:604: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>conftest.err; }; then + # Append any warnings to the config.log. + cat conftest.err 1>&5 + + for ac_file in conftest.*; do + case $ac_file in + *.c) ;; + *) objext=`echo $ac_file | sed -e s/conftest.//` ;; + esac + done +else + cat conftest.err 1>&5 + echo "$progname: failed program was:" >&5 + cat conftest.c >&5 +fi +$rm conftest* +echo "$ac_t$objext" 1>&6 + +echo $ac_n "checking for executable suffix... $ac_c" 1>&6 +if eval "test \"`echo '$''{'ac_cv_exeext'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + ac_cv_exeext="no" + $rm conftest* + echo 'main () { return 0; }' > conftest.c + echo "$progname:629: checking for executable suffix" >& 5 + if { (eval echo $progname:630: \"$ac_link\") 1>&5; (eval $ac_link) 2>conftest.err; }; then + # Append any warnings to the config.log. + cat conftest.err 1>&5 + + for ac_file in conftest.*; do + case $ac_file in + *.c | *.err | *.$objext ) ;; + *) ac_cv_exeext=.`echo $ac_file | sed -e s/conftest.//` ;; + esac + done + else + cat conftest.err 1>&5 + echo "$progname: failed program was:" >&5 + cat conftest.c >&5 + fi + $rm conftest* +fi +if test "X$ac_cv_exeext" = Xno; then + exeext="" +else + exeext="$ac_cv_exeext" +fi +echo "$ac_t$ac_cv_exeext" 1>&6 + +echo $ac_n "checking for $compiler option to produce PIC... $ac_c" 1>&6 +pic_flag= +special_shlib_compile_flags= +wl= +link_static_flag= +no_builtin_flag= + +if test "$with_gcc" = yes; then + wl='-Wl,' + link_static_flag='-static' + + case "$host_os" in + beos* | irix5* | irix6* | osf3* | osf4* | osf5*) + # PIC is the default for these OSes. + ;; + aix*) + # Below there is a dirty hack to force normal static linking with -ldl + # The problem is because libdl dynamically linked with both libc and + # libC (AIX C++ library), which obviously doesn't included in libraries + # list by gcc. This cause undefined symbols with -static flags. + # This hack allows C programs to be linked with "-static -ldl", but + # we not sure about C++ programs. + link_static_flag="$link_static_flag ${wl}-lC" + ;; + cygwin* | mingw* | os2*) + # We can build DLLs from non-PIC. + ;; + amigaos*) + # FIXME: we need at least 68020 code to build shared libraries, but + # adding the `-m68020' flag to GCC prevents building anything better, + # like `-m68040'. + pic_flag='-m68020 -resident32 -malways-restore-a4' + ;; + sysv4*MP*) + if test -d /usr/nec; then + pic_flag=-Kconform_pic + fi + ;; + *) + pic_flag='-fPIC' + ;; + esac +else + # PORTME Check for PIC flags for the system compiler. + case "$host_os" in + aix3* | aix4*) + # All AIX code is PIC. + link_static_flag='-bnso -bI:/lib/syscalls.exp' + ;; + + hpux9* | hpux10* | hpux11*) + # Is there a better link_static_flag that works with the bundled CC? + wl='-Wl,' + link_static_flag="${wl}-a ${wl}archive" + pic_flag='+Z' + ;; + + irix5* | irix6*) + wl='-Wl,' + link_static_flag='-non_shared' + # PIC (with -KPIC) is the default. + ;; + + cygwin* | mingw* | os2*) + # We can build DLLs from non-PIC. + ;; + + osf3* | osf4* | osf5*) + # All OSF/1 code is PIC. + wl='-Wl,' + link_static_flag='-non_shared' + ;; + + sco3.2v5*) + pic_flag='-Kpic' + link_static_flag='-dn' + special_shlib_compile_flags='-belf' + ;; + + solaris*) + pic_flag='-KPIC' + link_static_flag='-Bstatic' + wl='-Wl,' + ;; + + sunos4*) + pic_flag='-PIC' + link_static_flag='-Bstatic' + wl='-Qoption ld ' + ;; + + sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*) + pic_flag='-KPIC' + link_static_flag='-Bstatic' + wl='-Wl,' + ;; + + uts4*) + pic_flag='-pic' + link_static_flag='-Bstatic' + ;; + sysv4*MP*) + if test -d /usr/nec ;then + pic_flag='-Kconform_pic' + link_static_flag='-Bstatic' + fi + ;; + *) + can_build_shared=no + ;; + esac +fi + +if test -n "$pic_flag"; then + echo "$ac_t$pic_flag" 1>&6 + + # Check to make sure the pic_flag actually works. + echo $ac_n "checking if $compiler PIC flag $pic_flag works... $ac_c" 1>&6 + $rm conftest* + echo "int some_variable = 0;" > conftest.c + save_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS $pic_flag -DPIC" + echo "$progname:776: checking if $compiler PIC flag $pic_flag works" >&5 + if { (eval echo $progname:777: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>conftest.err; } && test -s conftest.$objext; then + # Append any warnings to the config.log. + cat conftest.err 1>&5 + + case "$host_os" in + hpux9* | hpux10* | hpux11*) + # On HP-UX, both CC and GCC only warn that PIC is supported... then they + # create non-PIC objects. So, if there were any warnings, we assume that + # PIC is not supported. + if test -s conftest.err; then + echo "$ac_t"no 1>&6 + can_build_shared=no + pic_flag= + else + echo "$ac_t"yes 1>&6 + pic_flag=" $pic_flag" + fi + ;; + *) + echo "$ac_t"yes 1>&6 + pic_flag=" $pic_flag" + ;; + esac + else + # Append any errors to the config.log. + cat conftest.err 1>&5 + can_build_shared=no + pic_flag= + echo "$ac_t"no 1>&6 + fi + CFLAGS="$save_CFLAGS" + $rm conftest* +else + echo "$ac_t"none 1>&6 +fi + +# Check to see if options -o and -c are simultaneously supported by compiler +echo $ac_n "checking if $compiler supports -c -o file.o... $ac_c" 1>&6 +$rm -r conftest 2>/dev/null +mkdir conftest +cd conftest +$rm conftest* +echo "int some_variable = 0;" > conftest.c +mkdir out +# According to Tom Tromey, Ian Lance Taylor reported there are C compilers +# that will create temporary files in the current directory regardless of +# the output directory. Thus, making CWD read-only will cause this test +# to fail, enabling locking or at least warning the user not to do parallel +# builds. +chmod -w . +save_CFLAGS="$CFLAGS" +CFLAGS="$CFLAGS -o out/conftest2.o" +echo "$progname:829: checking if $compiler supports -c -o file.o" >&5 +if { (eval echo $progname:830: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>out/conftest.err; } && test -s out/conftest2.o; then + + # The compiler can only warn and ignore the option if not recognized + # So say no if there are warnings + if test -s out/conftest.err; then + echo "$ac_t"no 1>&6 + compiler_c_o=no + else + echo "$ac_t"yes 1>&6 + compiler_c_o=yes + fi +else + # Append any errors to the config.log. + cat out/conftest.err 1>&5 + compiler_c_o=no + echo "$ac_t"no 1>&6 +fi +CFLAGS="$save_CFLAGS" +chmod u+w . +$rm conftest* out/* +rmdir out +cd .. +rmdir conftest +$rm -r conftest 2>/dev/null + +if test x"$compiler_c_o" = x"yes"; then + # Check to see if we can write to a .lo + echo $ac_n "checking if $compiler supports -c -o file.lo... $ac_c" 1>&6 + $rm conftest* + echo "int some_variable = 0;" > conftest.c + save_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS -c -o conftest.lo" + echo "$progname:862: checking if $compiler supports -c -o file.lo" >&5 +if { (eval echo $progname:863: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>conftest.err; } && test -s conftest.lo; then + + # The compiler can only warn and ignore the option if not recognized + # So say no if there are warnings + if test -s conftest.err; then + echo "$ac_t"no 1>&6 + compiler_o_lo=no + else + echo "$ac_t"yes 1>&6 + compiler_o_lo=yes + fi + else + # Append any errors to the config.log. + cat conftest.err 1>&5 + compiler_o_lo=no + echo "$ac_t"no 1>&6 + fi + CFLAGS="$save_CFLAGS" + $rm conftest* +else + compiler_o_lo=no +fi + +# Check to see if we can do hard links to lock some files if needed +hard_links="nottested" +if test "$compiler_c_o" = no && test "$need_locks" != no; then + # do not overwrite the value of need_locks provided by the user + echo $ac_n "checking if we can lock with hard links... $ac_c" 1>&6 + hard_links=yes + $rm conftest* + ln conftest.a conftest.b 2>/dev/null && hard_links=no + touch conftest.a + ln conftest.a conftest.b 2>&5 || hard_links=no + ln conftest.a conftest.b 2>/dev/null && hard_links=no + echo "$ac_t$hard_links" 1>&6 + $rm conftest* + if test "$hard_links" = no; then + echo "*** WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&2 + need_locks=warn + fi +else + need_locks=no +fi + +if test "$with_gcc" = yes; then + # Check to see if options -fno-rtti -fno-exceptions are supported by compiler + echo $ac_n "checking if $compiler supports -fno-rtti -fno-exceptions ... $ac_c" 1>&6 + $rm conftest* + echo "int some_variable = 0;" > conftest.c + save_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS -fno-rtti -fno-exceptions -c conftest.c" + echo "$progname:914: checking if $compiler supports -fno-rtti -fno-exceptions" >&5 + if { (eval echo $progname:915: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>conftest.err; } && test -s conftest.o; then + + # The compiler can only warn and ignore the option if not recognized + # So say no if there are warnings + if test -s conftest.err; then + echo "$ac_t"no 1>&6 + compiler_rtti_exceptions=no + else + echo "$ac_t"yes 1>&6 + compiler_rtti_exceptions=yes + fi + else + # Append any errors to the config.log. + cat conftest.err 1>&5 + compiler_rtti_exceptions=no + echo "$ac_t"no 1>&6 + fi + CFLAGS="$save_CFLAGS" + $rm conftest* + + if test "$compiler_rtti_exceptions" = "yes"; then + no_builtin_flag=' -fno-builtin -fno-rtti -fno-exceptions' + else + no_builtin_flag=' -fno-builtin' + fi + +fi + +# Check for any special shared library compilation flags. +if test -n "$special_shlib_compile_flags"; then + echo "$progname: warning: \`$CC' requires \`$special_shlib_compile_flags' to build shared libraries" 1>&2 + if echo "$old_CC $old_CFLAGS " | egrep -e "[ ]$special_shlib_compile_flags[ ]" >/dev/null; then : + else + echo "$progname: add \`$special_shlib_compile_flags' to the CC or CFLAGS env variable and reconfigure" 1>&2 + can_build_shared=no + fi +fi + +echo $ac_n "checking if $compiler static flag $link_static_flag works... $ac_c" 1>&6 +$rm conftest* +echo 'main(){return(0);}' > conftest.c +save_LDFLAGS="$LDFLAGS" +LDFLAGS="$LDFLAGS $link_static_flag" +echo "$progname:958: checking if $compiler static flag $link_static_flag works" >&5 +if { (eval echo $progname:959: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then + echo "$ac_t$link_static_flag" 1>&6 +else + echo "$ac_t"none 1>&6 + link_static_flag= +fi +LDFLAGS="$save_LDFLAGS" +$rm conftest* + +if test -z "$LN_S"; then + # Check to see if we can use ln -s, or we need hard links. + echo $ac_n "checking whether ln -s works... $ac_c" 1>&6 + $rm conftest.dat + if ln -s X conftest.dat 2>/dev/null; then + $rm conftest.dat + LN_S="ln -s" + else + LN_S=ln + fi + if test "$LN_S" = "ln -s"; then + echo "$ac_t"yes 1>&6 + else + echo "$ac_t"no 1>&6 + fi +fi + +# Make sure LD is an absolute path. +if test -z "$LD"; then + ac_prog=ld + if test "$with_gcc" = yes; then + # Check if gcc -print-prog-name=ld gives a path. + echo $ac_n "checking for ld used by GCC... $ac_c" 1>&6 + echo "$progname:991: checking for ld used by GCC" >&5 + ac_prog=`($CC -print-prog-name=ld) 2>&5` + case "$ac_prog" in + # Accept absolute paths. + [\\/]* | [A-Za-z]:[\\/]*) + re_direlt='/[^/][^/]*/\.\./' + # Canonicalize the path of ld + ac_prog=`echo $ac_prog| sed 's%\\\\%/%g'` + while echo $ac_prog | grep "$re_direlt" > /dev/null 2>&1; do + ac_prog=`echo $ac_prog| sed "s%$re_direlt%/%"` + done + test -z "$LD" && LD="$ac_prog" + ;; + "") + # If it fails, then pretend we are not using GCC. + ac_prog=ld + ;; + *) + # If it is relative, then search for the first ld in PATH. + with_gnu_ld=unknown + ;; + esac + elif test "$with_gnu_ld" = yes; then + echo $ac_n "checking for GNU ld... $ac_c" 1>&6 + echo "$progname:1015: checking for GNU ld" >&5 + else + echo $ac_n "checking for non-GNU ld""... $ac_c" 1>&6 + echo "$progname:1018: checking for non-GNU ld" >&5 + fi + + if test -z "$LD"; then + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}${PATH_SEPARATOR}" + for ac_dir in $PATH; do + test -z "$ac_dir" && ac_dir=. + if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then + LD="$ac_dir/$ac_prog" + # Check to see if the program is GNU ld. I'd rather use --version, + # but apparently some GNU ld's only accept -v. + # Break only if it was the GNU/non-GNU ld that we prefer. + if "$LD" -v 2>&1 < /dev/null | egrep '(GNU|with BFD)' > /dev/null; then + test "$with_gnu_ld" != no && break + else + test "$with_gnu_ld" != yes && break + fi + fi + done + IFS="$ac_save_ifs" + fi + + if test -n "$LD"; then + echo "$ac_t$LD" 1>&6 + else + echo "$ac_t"no 1>&6 + fi + + if test -z "$LD"; then + echo "$progname: error: no acceptable ld found in \$PATH" 1>&2 + exit 1 + fi +fi + +# Check to see if it really is or is not GNU ld. +echo $ac_n "checking if the linker ($LD) is GNU ld... $ac_c" 1>&6 +# I'd rather use --version here, but apparently some GNU ld's only accept -v. +if $LD -v 2>&1 &5; then + with_gnu_ld=yes +else + with_gnu_ld=no +fi +echo "$ac_t$with_gnu_ld" 1>&6 + +# See if the linker supports building shared libraries. +echo $ac_n "checking whether the linker ($LD) supports shared libraries... $ac_c" 1>&6 + +allow_undefined_flag= +no_undefined_flag= +need_lib_prefix=unknown +need_version=unknown +# when you set need_version to no, make sure it does not cause -set_version +# flags to be left without arguments +archive_cmds= +archive_expsym_cmds= +old_archive_from_new_cmds= +export_dynamic_flag_spec= +whole_archive_flag_spec= +thread_safe_flag_spec= +hardcode_libdir_flag_spec= +hardcode_libdir_separator= +hardcode_direct=no +hardcode_minus_L=no +hardcode_shlibpath_var=unsupported +runpath_var= +always_export_symbols=no +export_symbols_cmds='$NM $libobjs $convenience | $global_symbol_pipe | sed '\''s/.* //'\'' | sort | uniq > $export_symbols' +# include_expsyms should be a list of space-separated symbols to be *always* +# included in the symbol list +include_expsyms= +# exclude_expsyms can be an egrep regular expression of symbols to exclude +# it will be wrapped by ` (' and `)$', so one must not match beginning or +# end of line. Example: `a|bc|.*d.*' will exclude the symbols `a' and `bc', +# as well as any symbol that contains `d'. +exclude_expsyms="_GLOBAL_OFFSET_TABLE_" +# Although _GLOBAL_OFFSET_TABLE_ is a valid symbol C name, most a.out +# platforms (ab)use it in PIC code, but their linkers get confused if +# the symbol is explicitly referenced. Since portable code cannot +# rely on this symbol name, it's probably fine to never include it in +# preloaded symbol tables. + +case "$host_os" in +cygwin* | mingw*) + # FIXME: the MSVC++ port hasn't been tested in a loooong time + # When not using gcc, we currently assume that we are using + # Microsoft Visual C++. + if test "$with_gcc" != yes; then + with_gnu_ld=no + fi + ;; + +esac + +ld_shlibs=yes +if test "$with_gnu_ld" = yes; then + # If archive_cmds runs LD, not CC, wlarc should be empty + wlarc='${wl}' + + # See if GNU ld supports shared libraries. + case "$host_os" in + aix3* | aix4*) + # On AIX, the GNU linker is very broken + ld_shlibs=no + cat <&2 + +*** Warning: the GNU linker, at least up to release 2.9.1, is reported +*** to be unable to reliably create shared libraries on AIX. +*** Therefore, libtool is disabling shared libraries support. If you +*** really care for shared libraries, you may want to modify your PATH +*** so that a non-GNU linker is found, and then restart. + +EOF + ;; + + amigaos*) + archive_cmds='$rm $objdir/a2ixlibrary.data~$echo "#define NAME $libname" > $objdir/a2ixlibrary.data~$echo "#define LIBRARY_ID 1" >> $objdir/a2ixlibrary.data~$echo "#define VERSION $major" >> $objdir/a2ixlibrary.data~$echo "#define REVISION $revision" >> $objdir/a2ixlibrary.data~$AR cru $lib $libobjs~$RANLIB $lib~(cd $objdir && a2ixlibrary -32)' + hardcode_libdir_flag_spec='-L$libdir' + hardcode_minus_L=yes + + # Samuel A. Falvo II reports + # that the semantics of dynamic libraries on AmigaOS, at least up + # to version 4, is to share data among multiple programs linked + # with the same dynamic library. Since this doesn't match the + # behavior of shared libraries on other platforms, we can use + # them. + ld_shlibs=no + ;; + + beos*) + if $LD --help 2>&1 | egrep ': supported targets:.* elf' > /dev/null; then + allow_undefined_flag=unsupported + # Joseph Beckenbach says some releases of gcc + # support --undefined. This deserves some investigation. FIXME + archive_cmds='$CC -nostart $libobjs $deplibs $linkopts ${wl}-soname $wl$soname -o $lib' + else + ld_shlibs=no + fi + ;; + + cygwin* | mingw*) + # hardcode_libdir_flag_spec is actually meaningless, as there is + # no search path for DLLs. + hardcode_libdir_flag_spec='-L$libdir' + allow_undefined_flag=unsupported + always_export_symbols=yes + + # Extract the symbol export list from an `--export-all' def file, + # then regenerate the def file from the symbol export list, so that + # the compiled dll only exports the symbol export list. + export_symbols_cmds='test -f $objdir/$soname-ltdll.c || sed -e "/^# \/\* ltdll\.c starts here \*\//,/^# \/\* ltdll.c ends here \*\// { s/^# //; p; }" -e d < $0 > $objdir/$soname-ltdll.c~ + test -f $objdir/$soname-ltdll.$objext || (cd $objdir && $CC -c $soname-ltdll.c)~ + $DLLTOOL --export-all --exclude-symbols DllMain@12,_cygwin_dll_entry@12,_cygwin_noncygwin_dll_entry@12 --output-def $objdir/$soname-def $objdir/$soname-ltdll.$objext $libobjs $convenience~ + sed -e "1,/EXPORTS/d" -e "s/ @ [0-9]* ; *//" < $objdir/$soname-def > $export_symbols' + + archive_expsym_cmds='echo EXPORTS > $objdir/$soname-def~ + _lt_hint=1; + for symbol in `cat $export_symbols`; do + echo " \$symbol @ \$_lt_hint ; " >> $objdir/$soname-def; + _lt_hint=`expr 1 + \$_lt_hint`; + done~ + test -f $objdir/$soname-ltdll.c || sed -e "/^# \/\* ltdll\.c starts here \*\//,/^# \/\* ltdll.c ends here \*\// { s/^# //; p; }" -e d < $0 > $objdir/$soname-ltdll.c~ + test -f $objdir/$soname-ltdll.$objext || (cd $objdir && $CC -c $soname-ltdll.c)~ + $CC -Wl,--base-file,$objdir/$soname-base -Wl,--dll -nostartfiles -Wl,-e,__cygwin_dll_entry@12 -o $lib $objdir/$soname-ltdll.$objext $libobjs $deplibs $linkopts~ + $DLLTOOL --as=$AS --dllname $soname --exclude-symbols DllMain@12,_cygwin_dll_entry@12,_cygwin_noncygwin_dll_entry@12 --def $objdir/$soname-def --base-file $objdir/$soname-base --output-exp $objdir/$soname-exp~ + $CC -Wl,--base-file,$objdir/$soname-base $objdir/$soname-exp -Wl,--dll -nostartfiles -Wl,-e,__cygwin_dll_entry@12 -o $lib $objdir/$soname-ltdll.$objext $libobjs $deplibs $linkopts~ + $DLLTOOL --as=$AS --dllname $soname --exclude-symbols DllMain@12,_cygwin_dll_entry@12,_cygwin_noncygwin_dll_entry@12 --def $objdir/$soname-def --base-file $objdir/$soname-base --output-exp $objdir/$soname-exp~ + $CC $objdir/$soname-exp -Wl,--dll -nostartfiles -Wl,-e,__cygwin_dll_entry@12 -o $lib $objdir/$soname-ltdll.$objext $libobjs $deplibs $linkopts' + + old_archive_from_new_cmds='$DLLTOOL --as=$AS --dllname $soname --def $objdir/$soname-def --output-lib $objdir/$libname.a' + ;; + + netbsd*) + if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then + archive_cmds='$CC -shared $libobjs $deplibs $linkopts ${wl}-soname $wl$soname -o $lib' + archive_expsym_cmds='$CC -shared $libobjs $deplibs $linkopts ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + else + archive_cmds='$LD -Bshareable $libobjs $deplibs $linkopts -o $lib' + # can we support soname and/or expsyms with a.out? -oliva + fi + ;; + + solaris* | sysv5*) + if $LD -v 2>&1 | egrep 'BFD 2\.8' > /dev/null; then + ld_shlibs=no + cat <&2 + +*** Warning: The releases 2.8.* of the GNU linker cannot reliably +*** create shared libraries on Solaris systems. Therefore, libtool +*** is disabling shared libraries support. We urge you to upgrade GNU +*** binutils to release 2.9.1 or newer. Another option is to modify +*** your PATH or compiler configuration so that the native linker is +*** used, and then restart. + +EOF + elif $LD --help 2>&1 | egrep ': supported targets:.* elf' > /dev/null; then + archive_cmds='$CC -shared $libobjs $deplibs $linkopts ${wl}-soname $wl$soname -o $lib' + archive_expsym_cmds='$CC -shared $libobjs $deplibs $linkopts ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + else + ld_shlibs=no + fi + ;; + + sunos4*) + archive_cmds='$LD -assert pure-text -Bshareable -o $lib $libobjs $deplibs $linkopts' + wlarc= + hardcode_direct=yes + hardcode_shlibpath_var=no + ;; + + *) + if $LD --help 2>&1 | egrep ': supported targets:.* elf' > /dev/null; then + archive_cmds='$CC -shared $libobjs $deplibs $linkopts ${wl}-soname $wl$soname -o $lib' + archive_expsym_cmds='$CC -shared $libobjs $deplibs $linkopts ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + else + ld_shlibs=no + fi + ;; + esac + + if test "$ld_shlibs" = yes; then + runpath_var=LD_RUN_PATH + hardcode_libdir_flag_spec='${wl}--rpath ${wl}$libdir' + export_dynamic_flag_spec='${wl}--export-dynamic' + case $host_os in + cygwin* | mingw*) + # dlltool doesn't understand --whole-archive et. al. + whole_archive_flag_spec= + ;; + *) + # ancient GNU ld didn't support --whole-archive et. al. + if $LD --help 2>&1 | egrep 'no-whole-archive' > /dev/null; then + whole_archive_flag_spec="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive' + else + whole_archive_flag_spec= + fi + ;; + esac + fi +else + # PORTME fill in a description of your system's linker (not GNU ld) + case "$host_os" in + aix3*) + allow_undefined_flag=unsupported + always_export_symbols=yes + archive_expsym_cmds='$LD -o $objdir/$soname $libobjs $deplibs $linkopts -bE:$export_symbols -T512 -H512 -bM:SRE~$AR cru $lib $objdir/$soname' + # Note: this linker hardcodes the directories in LIBPATH if there + # are no directories specified by -L. + hardcode_minus_L=yes + if test "$with_gcc" = yes && test -z "$link_static_flag"; then + # Neither direct hardcoding nor static linking is supported with a + # broken collect2. + hardcode_direct=unsupported + fi + ;; + + aix4*) + hardcode_libdir_flag_spec='${wl}-b ${wl}nolibpath ${wl}-b ${wl}libpath:$libdir:/usr/lib:/lib' + hardcode_libdir_separator=':' + if test "$with_gcc" = yes; then + collect2name=`${CC} -print-prog-name=collect2` + if test -f "$collect2name" && \ + strings "$collect2name" | grep resolve_lib_name >/dev/null + then + # We have reworked collect2 + hardcode_direct=yes + else + # We have old collect2 + hardcode_direct=unsupported + # It fails to find uninstalled libraries when the uninstalled + # path is not listed in the libpath. Setting hardcode_minus_L + # to unsupported forces relinking + hardcode_minus_L=yes + hardcode_libdir_flag_spec='-L$libdir' + hardcode_libdir_separator= + fi + shared_flag='-shared' + else + shared_flag='${wl}-bM:SRE' + hardcode_direct=yes + fi + allow_undefined_flag=' ${wl}-berok' + archive_cmds="\$CC $shared_flag"' -o $objdir/$soname $libobjs $deplibs $linkopts ${wl}-bexpall ${wl}-bnoentry${allow_undefined_flag}' + archive_expsym_cmds="\$CC $shared_flag"' -o $objdir/$soname $libobjs $deplibs $linkopts ${wl}-bE:$export_symbols ${wl}-bnoentry${allow_undefined_flag}' + case "$host_os" in aix4.[01]|aix4.[01].*) + # According to Greg Wooledge, -bexpall is only supported from AIX 4.2 on + always_export_symbols=yes ;; + esac + ;; + + amigaos*) + archive_cmds='$rm $objdir/a2ixlibrary.data~$echo "#define NAME $libname" > $objdir/a2ixlibrary.data~$echo "#define LIBRARY_ID 1" >> $objdir/a2ixlibrary.data~$echo "#define VERSION $major" >> $objdir/a2ixlibrary.data~$echo "#define REVISION $revision" >> $objdir/a2ixlibrary.data~$AR cru $lib $libobjs~$RANLIB $lib~(cd $objdir && a2ixlibrary -32)' + hardcode_libdir_flag_spec='-L$libdir' + hardcode_minus_L=yes + # see comment about different semantics on the GNU ld section + ld_shlibs=no + ;; + + cygwin* | mingw*) + # When not using gcc, we currently assume that we are using + # Microsoft Visual C++. + # hardcode_libdir_flag_spec is actually meaningless, as there is + # no search path for DLLs. + hardcode_libdir_flag_spec=' ' + allow_undefined_flag=unsupported + # Tell ltmain to make .lib files, not .a files. + libext=lib + # FIXME: Setting linknames here is a bad hack. + archive_cmds='$CC -o $lib $libobjs $linkopts `echo "$deplibs" | sed -e '\''s/ -lc$//'\''` -link -dll~linknames=' + # The linker will automatically build a .lib file if we build a DLL. + old_archive_from_new_cmds='true' + # FIXME: Should let the user specify the lib program. + old_archive_cmds='lib /OUT:$oldlib$oldobjs' + fix_srcfile_path='`cygpath -w $srcfile`' + ;; + + freebsd1*) + ld_shlibs=no + ;; + + # FreeBSD 2.2.[012] allows us to include c++rt0.o to get C++ constructor + # support. Future versions do this automatically, but an explicit c++rt0.o + # does not break anything, and helps significantly (at the cost of a little + # extra space). + freebsd2.2*) + archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linkopts /usr/lib/c++rt0.o' + hardcode_libdir_flag_spec='-R$libdir' + hardcode_direct=yes + hardcode_shlibpath_var=no + ;; + + # Unfortunately, older versions of FreeBSD 2 do not have this feature. + freebsd2*) + archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linkopts' + hardcode_direct=yes + hardcode_minus_L=yes + hardcode_shlibpath_var=no + ;; + + # FreeBSD 3 and greater uses gcc -shared to do shared libraries. + freebsd*) + archive_cmds='$CC -shared -o $lib $libobjs $deplibs $linkopts' + hardcode_libdir_flag_spec='-R$libdir' + hardcode_direct=yes + hardcode_shlibpath_var=no + ;; + + hpux9* | hpux10* | hpux11*) + case "$host_os" in + hpux9*) archive_cmds='$rm $objdir/$soname~$LD -b +b $install_libdir -o $objdir/$soname $libobjs $deplibs $linkopts~test $objdir/$soname = $lib || mv $objdir/$soname $lib' ;; + *) archive_cmds='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linkopts' ;; + esac + hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir' + hardcode_libdir_separator=: + hardcode_direct=yes + hardcode_minus_L=yes # Not in the search PATH, but as the default + # location of the library. + export_dynamic_flag_spec='${wl}-E' + ;; + + irix5* | irix6*) + if test "$with_gcc" = yes; then + archive_cmds='$CC -shared $libobjs $deplibs $linkopts ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${objdir}/so_locations -o $lib' + else + archive_cmds='$LD -shared $libobjs $deplibs $linkopts -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${objdir}/so_locations -o $lib' + fi + hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' + hardcode_libdir_separator=: + ;; + + netbsd*) + if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then + archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linkopts' # a.out + else + archive_cmds='$LD -shared -o $lib $libobjs $deplibs $linkopts' # ELF + fi + hardcode_libdir_flag_spec='${wl}-R$libdir' + hardcode_direct=yes + hardcode_shlibpath_var=no + ;; + + openbsd*) + archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linkopts' + hardcode_libdir_flag_spec='-R$libdir' + hardcode_direct=yes + hardcode_shlibpath_var=no + ;; + + os2*) + hardcode_libdir_flag_spec='-L$libdir' + hardcode_minus_L=yes + allow_undefined_flag=unsupported + archive_cmds='$echo "LIBRARY $libname INITINSTANCE" > $objdir/$libname.def~$echo "DESCRIPTION \"$libname\"" >> $objdir/$libname.def~$echo DATA >> $objdir/$libname.def~$echo " SINGLE NONSHARED" >> $objdir/$libname.def~$echo EXPORTS >> $objdir/$libname.def~emxexp $libobjs >> $objdir/$libname.def~$CC -Zdll -Zcrtdll -o $lib $libobjs $deplibs $linkopts $objdir/$libname.def' + old_archive_from_new_cmds='emximp -o $objdir/$libname.a $objdir/$libname.def' + ;; + + osf3*) + if test "$with_gcc" = yes; then + allow_undefined_flag=' ${wl}-expect_unresolved ${wl}\*' + archive_cmds='$CC -shared${allow_undefined_flag} $libobjs $deplibs $linkopts ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${objdir}/so_locations -o $lib' + else + allow_undefined_flag=' -expect_unresolved \*' + archive_cmds='$LD -shared${allow_undefined_flag} $libobjs $deplibs $linkopts -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${objdir}/so_locations -o $lib' + fi + hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' + hardcode_libdir_separator=: + ;; + + osf4* | osf5*) # As osf3* with the addition of the -msym flag + if test "$with_gcc" = yes; then + allow_undefined_flag=' ${wl}-expect_unresolved ${wl}\*' + archive_cmds='$CC -shared${allow_undefined_flag} $libobjs $deplibs $linkopts ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${objdir}/so_locations -o $lib' + else + allow_undefined_flag=' -expect_unresolved \*' + archive_cmds='$LD -shared${allow_undefined_flag} $libobjs $deplibs $linkopts -msym -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${objdir}/so_locations -o $lib' + fi + hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' + hardcode_libdir_separator=: + ;; + + sco3.2v5*) + archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linkopts' + hardcode_shlibpath_var=no + runpath_var=LD_RUN_PATH + hardcode_runpath_var=yes + ;; + + solaris*) + no_undefined_flag=' -z text' + # $CC -shared without GNU ld will not create a library from C++ + # object files and a static libstdc++, better avoid it by now + archive_cmds='$LD -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $linkopts' + archive_expsym_cmds='$echo "{ global:" > $lib.exp~cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~ + $LD -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linkopts~$rm $lib.exp' + hardcode_libdir_flag_spec='-R$libdir' + hardcode_shlibpath_var=no + case "$host_os" in + solaris2.[0-5] | solaris2.[0-5].*) ;; + *) # Supported since Solaris 2.6 (maybe 2.5.1?) + whole_archive_flag_spec='-z allextract$convenience -z defaultextract' ;; + esac + ;; + + sunos4*) + archive_cmds='$LD -assert pure-text -Bstatic -o $lib $libobjs $deplibs $linkopts' + hardcode_libdir_flag_spec='-L$libdir' + hardcode_direct=yes + hardcode_minus_L=yes + hardcode_shlibpath_var=no + ;; + + sysv4) + archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linkopts' + runpath_var='LD_RUN_PATH' + hardcode_shlibpath_var=no + hardcode_direct=no #Motorola manual says yes, but my tests say they lie + ;; + + sysv4.3*) + archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linkopts' + hardcode_shlibpath_var=no + export_dynamic_flag_spec='-Bexport' + ;; + + sysv5*) + no_undefined_flag=' -z text' + # $CC -shared without GNU ld will not create a library from C++ + # object files and a static libstdc++, better avoid it by now + archive_cmds='$LD -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $linkopts' + archive_expsym_cmds='$echo "{ global:" > $lib.exp~cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~ + $LD -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linkopts~$rm $lib.exp' + hardcode_libdir_flag_spec= + hardcode_shlibpath_var=no + runpath_var='LD_RUN_PATH' + ;; + + uts4*) + archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linkopts' + hardcode_libdir_flag_spec='-L$libdir' + hardcode_shlibpath_var=no + ;; + + dgux*) + archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linkopts' + hardcode_libdir_flag_spec='-L$libdir' + hardcode_shlibpath_var=no + ;; + + sysv4*MP*) + if test -d /usr/nec; then + archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linkopts' + hardcode_shlibpath_var=no + runpath_var=LD_RUN_PATH + hardcode_runpath_var=yes + ld_shlibs=yes + fi + ;; + + sysv4.2uw2*) + archive_cmds='$LD -G -o $lib $libobjs $deplibs $linkopts' + hardcode_direct=yes + hardcode_minus_L=no + hardcode_shlibpath_var=no + hardcode_runpath_var=yes + runpath_var=LD_RUN_PATH + ;; + + unixware7*) + archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linkopts' + runpath_var='LD_RUN_PATH' + hardcode_shlibpath_var=no + ;; + + *) + ld_shlibs=no + ;; + esac +fi +echo "$ac_t$ld_shlibs" 1>&6 +test "$ld_shlibs" = no && can_build_shared=no + +if test -z "$NM"; then + echo $ac_n "checking for BSD-compatible nm... $ac_c" 1>&6 + case "$NM" in + [\\/]* | [A-Za-z]:[\\/]*) ;; # Let the user override the test with a path. + *) + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}${PATH_SEPARATOR}" + for ac_dir in $PATH /usr/ucb /usr/ccs/bin /bin; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/nm || test -f $ac_dir/nm$ac_exeext; then + # Check to see if the nm accepts a BSD-compat flag. + # Adding the `sed 1q' prevents false positives on HP-UX, which says: + # nm: unknown option "B" ignored + if ($ac_dir/nm -B /dev/null 2>&1 | sed '1q'; exit 0) | egrep /dev/null >/dev/null; then + NM="$ac_dir/nm -B" + break + elif ($ac_dir/nm -p /dev/null 2>&1 | sed '1q'; exit 0) | egrep /dev/null >/dev/null; then + NM="$ac_dir/nm -p" + break + else + NM=${NM="$ac_dir/nm"} # keep the first match, but + continue # so that we can try to find one that supports BSD flags + fi + fi + done + IFS="$ac_save_ifs" + test -z "$NM" && NM=nm + ;; + esac + echo "$ac_t$NM" 1>&6 +fi + +# Check for command to grab the raw symbol name followed by C symbol from nm. +echo $ac_n "checking command to parse $NM output... $ac_c" 1>&6 + +# These are sane defaults that work on at least a few old systems. +# [They come from Ultrix. What could be older than Ultrix?!! ;)] + +# Character class describing NM global symbol codes. +symcode='[BCDEGRST]' + +# Regexp to match symbols that can be accessed directly from C. +sympat='\([_A-Za-z][_A-Za-z0-9]*\)' + +# Transform the above into a raw symbol and a C symbol. +symxfrm='\1 \2\3 \3' + +# Transform an extracted symbol line into a proper C declaration +global_symbol_to_cdecl="sed -n -e 's/^. .* \(.*\)$/extern char \1;/p'" + +# Define system-specific variables. +case "$host_os" in +aix*) + symcode='[BCDT]' + ;; +cygwin* | mingw*) + symcode='[ABCDGISTW]' + ;; +hpux*) # Its linker distinguishes data from code symbols + global_symbol_to_cdecl="sed -n -e 's/^T .* \(.*\)$/extern char \1();/p' -e 's/^. .* \(.*\)$/extern char \1;/p'" + ;; +irix*) + symcode='[BCDEGRST]' + ;; +solaris*) + symcode='[BDT]' + ;; +sysv4) + symcode='[DFNSTU]' + ;; +esac + +# If we're using GNU nm, then use its standard symbol codes. +if $NM -V 2>&1 | egrep '(GNU|with BFD)' > /dev/null; then + symcode='[ABCDGISTW]' +fi + +# Try without a prefix undercore, then with it. +for ac_symprfx in "" "_"; do + + # Write the raw and C identifiers. + global_symbol_pipe="sed -n -e 's/^.*[ ]\($symcode\)[ ][ ]*\($ac_symprfx\)$sympat$/$symxfrm/p'" + + # Check to see that the pipe works correctly. + pipe_works=no + $rm conftest* + cat > conftest.c <&5 + if { (eval echo $progname:1636: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; } && test -s conftest.$objext; then + # Now try to grab the symbols. + nlist=conftest.nm + if { echo "$progname:1639: eval \"$NM conftest.$objext | $global_symbol_pipe > $nlist\"" >&5; eval "$NM conftest.$objext | $global_symbol_pipe > $nlist 2>&5"; } && test -s "$nlist"; then + + # Try sorting and uniquifying the output. + if sort "$nlist" | uniq > "$nlist"T; then + mv -f "$nlist"T "$nlist" + else + rm -f "$nlist"T + fi + + # Make sure that we snagged all the symbols we need. + if egrep ' nm_test_var$' "$nlist" >/dev/null; then + if egrep ' nm_test_func$' "$nlist" >/dev/null; then + cat < conftest.c +#ifdef __cplusplus +extern "C" { +#endif + +EOF + # Now generate the symbol file. + eval "$global_symbol_to_cdecl"' < "$nlist" >> conftest.c' + + cat <> conftest.c +#if defined (__STDC__) && __STDC__ +# define lt_ptr_t void * +#else +# define lt_ptr_t char * +# define const +#endif + +/* The mapping between symbol names and symbols. */ +const struct { + const char *name; + lt_ptr_t address; +} +lt_preloaded_symbols[] = +{ +EOF + sed 's/^. \(.*\) \(.*\)$/ {"\2", (lt_ptr_t) \&\2},/' < "$nlist" >> conftest.c + cat <<\EOF >> conftest.c + {0, (lt_ptr_t) 0} +}; + +#ifdef __cplusplus +} +#endif +EOF + # Now try linking the two files. + mv conftest.$objext conftstm.$objext + save_LIBS="$LIBS" + save_CFLAGS="$CFLAGS" + LIBS="conftstm.$objext" + CFLAGS="$CFLAGS$no_builtin_flag" + if { (eval echo $progname:1691: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then + pipe_works=yes + else + echo "$progname: failed program was:" >&5 + cat conftest.c >&5 + fi + LIBS="$save_LIBS" + else + echo "cannot find nm_test_func in $nlist" >&5 + fi + else + echo "cannot find nm_test_var in $nlist" >&5 + fi + else + echo "cannot run $global_symbol_pipe" >&5 + fi + else + echo "$progname: failed program was:" >&5 + cat conftest.c >&5 + fi + $rm conftest* conftst* + + # Do not use the global_symbol_pipe unless it works. + if test "$pipe_works" = yes; then + break + else + global_symbol_pipe= + fi +done +if test "$pipe_works" = yes; then + echo "${ac_t}ok" 1>&6 +else + echo "${ac_t}failed" 1>&6 +fi + +if test -z "$global_symbol_pipe"; then + global_symbol_to_cdecl= +fi + +# Check hardcoding attributes. +echo $ac_n "checking how to hardcode library paths into programs... $ac_c" 1>&6 +hardcode_action= +if test -n "$hardcode_libdir_flag_spec" || \ + test -n "$runpath_var"; then + + # We can hardcode non-existant directories. + if test "$hardcode_direct" != no && + # If the only mechanism to avoid hardcoding is shlibpath_var, we + # have to relink, otherwise we might link with an installed library + # when we should be linking with a yet-to-be-installed one + ## test "$hardcode_shlibpath_var" != no && + test "$hardcode_minus_L" != no; then + # Linking always hardcodes the temporary library directory. + hardcode_action=relink + else + # We can link without hardcoding, and we can hardcode nonexisting dirs. + hardcode_action=immediate + fi +else + # We cannot hardcode anything, or else we can only hardcode existing + # directories. + hardcode_action=unsupported +fi +echo "$ac_t$hardcode_action" 1>&6 + + +reload_flag= +reload_cmds='$LD$reload_flag -o $output$reload_objs' +echo $ac_n "checking for $LD option to reload object files... $ac_c" 1>&6 +# PORTME Some linkers may need a different reload flag. +reload_flag='-r' +echo "$ac_t$reload_flag" 1>&6 +test -n "$reload_flag" && reload_flag=" $reload_flag" + +# PORTME Fill in your ld.so characteristics +library_names_spec= +libname_spec='lib$name' +soname_spec= +postinstall_cmds= +postuninstall_cmds= +finish_cmds= +finish_eval= +shlibpath_var= +shlibpath_overrides_runpath=unknown +version_type=none +dynamic_linker="$host_os ld.so" +sys_lib_dlsearch_path_spec="/lib /usr/lib" +sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib" +file_magic_cmd= +file_magic_test_file= +deplibs_check_method='unknown' +# Need to set the preceding variable on all platforms that support +# interlibrary dependencies. +# 'none' -- dependencies not supported. +# `unknown' -- same as none, but documents that we really don't know. +# 'pass_all' -- all dependencies passed with no checks. +# 'test_compile' -- check by making test program. +# 'file_magic [regex]' -- check by looking for files in library path +# which responds to the $file_magic_cmd with a given egrep regex. +# If you have `file' or equivalent on your system and you're not sure +# whether `pass_all' will *always* work, you probably want this one. +echo $ac_n "checking dynamic linker characteristics... $ac_c" 1>&6 +case "$host_os" in +aix3*) + version_type=linux + library_names_spec='${libname}${release}.so$versuffix $libname.a' + shlibpath_var=LIBPATH + + # AIX has no versioning support, so we append a major version to the name. + soname_spec='${libname}${release}.so$major' + ;; + +aix4*) + version_type=linux + # AIX has no versioning support, so currently we can not hardcode correct + # soname into executable. Probably we can add versioning support to + # collect2, so additional links can be useful in future. + # We preserve .a as extension for shared libraries though AIX4.2 + # and later linker supports .so + library_names_spec='${libname}${release}.so$versuffix ${libname}${release}.so$major $libname.a' + shlibpath_var=LIBPATH + deplibs_check_method=pass_all + ;; + +amigaos*) + library_names_spec='$libname.ixlibrary $libname.a' + # Create ${libname}_ixlibrary.a entries in /sys/libs. + finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`$echo "X$lib" | $Xsed -e '\''s%^.*/\([^/]*\)\.ixlibrary$%\1%'\''`; test $rm /sys/libs/${libname}_ixlibrary.a; $show "(cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a)"; (cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a) || exit 1; done' + ;; + +beos*) + library_names_spec='${libname}.so' + dynamic_linker="$host_os ld.so" + shlibpath_var=LIBRARY_PATH + deplibs_check_method=pass_all + lt_cv_dlopen="load_add_on" + lt_cv_dlopen_libs= + lt_cv_dlopen_self=yes + ;; + +bsdi4*) + version_type=linux + need_version=no + library_names_spec='${libname}${release}.so$versuffix ${libname}${release}.so$major $libname.so' + soname_spec='${libname}${release}.so$major' + finish_cmds='PATH="\$PATH:/sbin" ldconfig $libdir' + shlibpath_var=LD_LIBRARY_PATH + deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [ML]SB (shared object|dynamic lib)' + file_magic_cmd=/usr/bin/file + file_magic_test_file=/shlib/libc.so + sys_lib_search_path_spec="/shlib /usr/lib /usr/X11/lib /usr/contrib/lib /lib /usr/local/lib" + sys_lib_dlsearch_path_spec="/shlib /usr/lib /usr/local/lib" + export_dynamic_flag_spec=-rdynamic + # the default ld.so.conf also contains /usr/contrib/lib and + # /usr/X11R6/lib (/usr/X11 is a link to /usr/X11R6), but let us allow + # libtool to hard-code these into programs + ;; + +cygwin* | mingw*) + version_type=windows + need_version=no + need_lib_prefix=no + if test "$with_gcc" = yes; then + library_names_spec='${libname}`echo ${release} | sed -e 's/[.]/-/g'`${versuffix}.dll $libname.a' + else + library_names_spec='${libname}`echo ${release} | sed -e 's/[.]/-/g'`${versuffix}.dll $libname.lib' + fi + dynamic_linker='Win32 ld.exe' + deplibs_check_method='file_magic file format pei*-i386(.*architecture: i386)?' + file_magic_cmd='${OBJDUMP} -f' + # FIXME: first we should search . and the directory the executable is in + shlibpath_var=PATH + lt_cv_dlopen="LoadLibrary" + lt_cv_dlopen_libs= + ;; + +freebsd1*) + dynamic_linker=no + ;; + +freebsd*) + objformat=`test -x /usr/bin/objformat && /usr/bin/objformat || echo aout` + version_type=freebsd-$objformat + case "$version_type" in + freebsd-elf*) + deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [LM]SB shared object' + file_magic_cmd=/usr/bin/file + file_magic_test_file=`echo /usr/lib/libc.so*` + library_names_spec='${libname}${release}.so$versuffix ${libname}${release}.so $libname.so' + need_version=no + need_lib_prefix=no + ;; + freebsd-*) + deplibs_check_method=unknown + library_names_spec='${libname}${release}.so$versuffix $libname.so$versuffix' + need_version=yes + ;; + esac + shlibpath_var=LD_LIBRARY_PATH + case "$host_os" in + freebsd2* | freebsd3.[01]* | freebsdelf3.[01]*) + shlibpath_overrides_runpath=yes + ;; + *) # from 3.2 on + shlibpath_overrides_runpath=no + ;; + esac + ;; + +gnu*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}.so$versuffix ${libname}${release}.so${major} ${libname}.so' + soname_spec='${libname}${release}.so$major' + shlibpath_var=LD_LIBRARY_PATH + ;; + +hpux9* | hpux10* | hpux11*) + # Give a soname corresponding to the major version so that dld.sl refuses to + # link against other versions. + dynamic_linker="$host_os dld.sl" + version_type=sunos + need_lib_prefix=no + need_version=no + shlibpath_var=SHLIB_PATH + shlibpath_overrides_runpath=no # +s is required to enable SHLIB_PATH + library_names_spec='${libname}${release}.sl$versuffix ${libname}${release}.sl$major $libname.sl' + soname_spec='${libname}${release}.sl$major' + # HP-UX runs *really* slowly unless shared libraries are mode 555. + postinstall_cmds='chmod 555 $lib' + ;; + +irix5* | irix6*) + version_type=irix + need_lib_prefix=no + need_version=no + soname_spec='${libname}${release}.so.$major' + library_names_spec='${libname}${release}.so.$versuffix ${libname}${release}.so.$major ${libname}${release}.so $libname.so' + case "$host_os" in + irix5*) + libsuff= shlibsuff= + # this will be overridden with pass_all, but let us keep it just in case + deplibs_check_method="file_magic ELF 32-bit MSB dynamic lib MIPS - version 1" + ;; + *) + case "$LD" in # libtool.m4 will add one of these switches to LD + *-32|*"-32 ") libsuff= shlibsuff= libmagic=32-bit;; + *-n32|*"-n32 ") libsuff=32 shlibsuff=N32 libmagic=N32;; + *-64|*"-64 ") libsuff=64 shlibsuff=64 libmagic=64-bit;; + *) libsuff= shlibsuff= libmagic=never-match;; + esac + ;; + esac + shlibpath_var=LD_LIBRARY${shlibsuff}_PATH + shlibpath_overrides_runpath=no + sys_lib_search_path_spec="/usr/lib${libsuff} /lib${libsuff} /usr/local/lib${libsuff}" + sys_lib_dlsearch_path_spec="/usr/lib${libsuff} /lib${libsuff}" + file_magic_cmd=/usr/bin/file + file_magic_test_file=`echo /lib${libsuff}/libc.so*` + deplibs_check_method='pass_all' + ;; + +# No shared lib support for Linux oldld, aout, or coff. +linux-gnuoldld* | linux-gnuaout* | linux-gnucoff*) + dynamic_linker=no + ;; + +# This must be Linux ELF. +linux-gnu*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}.so$versuffix ${libname}${release}.so$major $libname.so' + soname_spec='${libname}${release}.so$major' + finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [LM]SB (shared object|dynamic lib )' + file_magic_cmd=/usr/bin/file + file_magic_test_file=`echo /lib/libc.so* /lib/libc-*.so` + + if test -f /lib/ld.so.1; then + dynamic_linker='GNU ld.so' + else + # Only the GNU ld.so supports shared libraries on MkLinux. + case "$host_cpu" in + powerpc*) dynamic_linker=no ;; + *) dynamic_linker='Linux ld.so' ;; + esac + fi + ;; + +netbsd*) + version_type=sunos + if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then + library_names_spec='${libname}${release}.so$versuffix ${libname}.so$versuffix' + finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' + dynamic_linker='NetBSD (a.out) ld.so' + else + library_names_spec='${libname}${release}.so$versuffix ${libname}${release}.so$major ${libname}${release}.so ${libname}.so' + soname_spec='${libname}${release}.so$major' + dynamic_linker='NetBSD ld.elf_so' + fi + shlibpath_var=LD_LIBRARY_PATH + ;; + +openbsd*) + version_type=sunos + if test "$with_gnu_ld" = yes; then + need_lib_prefix=no + need_version=no + fi + library_names_spec='${libname}${release}.so$versuffix ${libname}.so$versuffix' + finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' + shlibpath_var=LD_LIBRARY_PATH + ;; + +os2*) + libname_spec='$name' + need_lib_prefix=no + library_names_spec='$libname.dll $libname.a' + dynamic_linker='OS/2 ld.exe' + shlibpath_var=LIBPATH + ;; + +osf3* | osf4* | osf5*) + version_type=osf + need_version=no + soname_spec='${libname}${release}.so' + library_names_spec='${libname}${release}.so$versuffix ${libname}${release}.so $libname.so' + shlibpath_var=LD_LIBRARY_PATH + # this will be overridden with pass_all, but let us keep it just in case + deplibs_check_method='file_magic COFF format alpha shared library' + file_magic_cmd=/usr/bin/file + file_magic_test_file=/shlib/libc.so + deplibs_check_method='pass_all' + sys_lib_search_path_spec="/usr/shlib /usr/ccs/lib /usr/lib/cmplrs/cc /usr/lib /usr/local/lib /var/shlib" + sys_lib_dlsearch_path_spec="$sys_lib_search_path_spec" + ;; + +sco3.2v5*) + version_type=osf + soname_spec='${libname}${release}.so$major' + library_names_spec='${libname}${release}.so$versuffix ${libname}${release}.so$major $libname.so' + shlibpath_var=LD_LIBRARY_PATH + ;; + +solaris*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}.so$versuffix ${libname}${release}.so$major $libname.so' + soname_spec='${libname}${release}.so$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + # ldd complains unless libraries are executable + postinstall_cmds='chmod +x $lib' + deplibs_check_method="file_magic ELF [0-9][0-9]-bit [LM]SB dynamic lib" + file_magic_cmd=/usr/bin/file + file_magic_test_file=/lib/libc.so + ;; + +sunos4*) + version_type=sunos + library_names_spec='${libname}${release}.so$versuffix ${libname}.so$versuffix' + finish_cmds='PATH="\$PATH:/usr/etc" ldconfig $libdir' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + if test "$with_gnu_ld" = yes; then + need_lib_prefix=no + fi + need_version=yes + ;; + +sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*) + version_type=linux + library_names_spec='${libname}${release}.so$versuffix ${libname}${release}.so$major $libname.so' + soname_spec='${libname}${release}.so$major' + shlibpath_var=LD_LIBRARY_PATH + case "$host_vendor" in + ncr) + deplibs_check_method='pass_all' + ;; + motorola) + need_lib_prefix=no + need_version=no + shlibpath_overrides_runpath=no + sys_lib_search_path_spec='/lib /usr/lib /usr/ccs/lib' + deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [ML]SB (shared object|dynamic lib) M[0-9][0-9]* Version [0-9]' + file_magic_cmd=/usr/bin/file + file_magic_test_file=`echo /usr/lib/libc.so*` + ;; + esac + ;; + +uts4*) + version_type=linux + library_names_spec='${libname}${release}.so$versuffix ${libname}${release}.so$major $libname.so' + soname_spec='${libname}${release}.so$major' + shlibpath_var=LD_LIBRARY_PATH + ;; + +dgux*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}.so$versuffix ${libname}${release}.so$major $libname.so' + soname_spec='${libname}${release}.so$major' + shlibpath_var=LD_LIBRARY_PATH + ;; + +sysv4*MP*) + if test -d /usr/nec ;then + version_type=linux + library_names_spec='$libname.so.$versuffix $libname.so.$major $libname.so' + soname_spec='$libname.so.$major' + shlibpath_var=LD_LIBRARY_PATH + fi + ;; + +*) + dynamic_linker=no + ;; +esac +echo "$ac_t$dynamic_linker" 1>&6 +test "$dynamic_linker" = no && can_build_shared=no + +# Report the final consequences. +echo "checking if libtool supports shared libraries... $can_build_shared" 1>&6 + +# Only try to build win32 dlls if AC_LIBTOOL_WIN32_DLL was used in +# configure.in, otherwise build static only libraries. +case "$host_os" in +cygwin* | mingw* | os2*) + if test x$can_build_shared = xyes; then + test x$enable_win32_dll = xno && can_build_shared=no + echo "checking if package supports dlls... $can_build_shared" 1>&6 + fi +;; +esac + +if test -n "$file_magic_test_file" && test -n "$file_magic_cmd"; then + case "$deplibs_check_method" in + "file_magic "*) + file_magic_regex="`expr \"$deplibs_check_method\" : \"file_magic \(.*\)\"`" + if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null | + egrep "$file_magic_regex" > /dev/null; then + : + else + cat <&2 + +*** Warning: the command libtool uses to detect shared libraries, +*** $file_magic_cmd, produces output that libtool cannot recognize. +*** The result is that libtool may fail to recognize shared libraries +*** as such. This will affect the creation of libtool libraries that +*** depend on shared libraries, but programs linked with such libtool +*** libraries will work regardless of this problem. Nevertheless, you +*** may want to report the problem to your system manager and/or to +*** bug-libtool@gnu.org + +EOF + fi ;; + esac +fi + +echo $ac_n "checking whether to build shared libraries... $ac_c" 1>&6 +test "$can_build_shared" = "no" && enable_shared=no + +# On AIX, shared libraries and static libraries use the same namespace, and +# are all built from PIC. +case "$host_os" in +aix3*) + test "$enable_shared" = yes && enable_static=no + if test -n "$RANLIB"; then + archive_cmds="$archive_cmds~\$RANLIB \$lib" + postinstall_cmds='$RANLIB $lib' + fi + ;; + +aix4*) + test "$enable_shared" = yes && enable_static=no + ;; +esac + +echo "$ac_t$enable_shared" 1>&6 + +# Make sure either enable_shared or enable_static is yes. +test "$enable_shared" = yes || enable_static=yes + +echo "checking whether to build static libraries... $enable_static" 1>&6 + +if test "$hardcode_action" = relink; then + # Fast installation is not supported + enable_fast_install=no +elif test "$shlibpath_overrides_runpath" = yes || + test "$enable_shared" = no; then + # Fast installation is not necessary + enable_fast_install=needless +fi + +echo $ac_n "checking for objdir... $ac_c" 1>&6 +rm -f .libs 2>/dev/null +mkdir .libs 2>/dev/null +if test -d .libs; then + objdir=.libs +else + # MS-DOS does not allow filenames that begin with a dot. + objdir=_libs +fi +rmdir .libs 2>/dev/null +echo "$ac_t$objdir" 1>&6 + +if test "x$enable_dlopen" != xyes; then + enable_dlopen=unknown + enable_dlopen_self=unknown + enable_dlopen_self_static=unknown +else +if eval "test \"`echo '$''{'lt_cv_dlopen'+set}'`\" != set"; then + lt_cv_dlopen=no lt_cv_dlopen_libs= +echo $ac_n "checking for dlopen in -ldl""... $ac_c" 1>&6 +echo "$progname:2212: checking for dlopen in -ldl" >&5 +ac_lib_var=`echo dl'_'dlopen | sed 'y%./+-%__p_%'` +if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + ac_save_LIBS="$LIBS" +LIBS="-ldl $LIBS" +cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=yes" +else + echo "$progname: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=no" +fi +rm -f conftest* +LIBS="$ac_save_LIBS" + +fi +if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then + echo "$ac_t""yes" 1>&6 + lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl" +else + echo "$ac_t""no" 1>&6 +echo $ac_n "checking for dlopen""... $ac_c" 1>&6 +echo "$progname:2252: checking for dlopen" >&5 +if eval "test \"`echo '$''{'ac_cv_func_dlopen'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +/* Override any gcc2 internal prototype to avoid an error. */ +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char dlopen(); + +int main() { + +/* 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_dlopen) || defined (__stub___dlopen) +choke me +#else +dlopen(); +#endif + +; return 0; } +EOF +if { (eval echo $progname:2282: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + eval "ac_cv_func_dlopen=yes" +else + echo "$progname: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_func_dlopen=no" +fi +rm -f conftest* +fi +if eval "test \"`echo '$ac_cv_func_'dlopen`\" = yes"; then + echo "$ac_t""yes" 1>&6 + lt_cv_dlopen="dlopen" +else + echo "$ac_t""no" 1>&6 +echo $ac_n "checking for dld_link in -ldld""... $ac_c" 1>&6 +echo "$progname:2299: checking for dld_link in -ldld" >&5 +ac_lib_var=`echo dld'_'dld_link | sed 'y%./+-%__p_%'` +if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + ac_save_LIBS="$LIBS" +LIBS="-ldld $LIBS" +cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=yes" +else + echo "$progname: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=no" +fi +rm -f conftest* +LIBS="$ac_save_LIBS" + +fi +if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then + echo "$ac_t""yes" 1>&6 + lt_cv_dlopen="dld_link" lt_cv_dlopen_libs="-ldld" +else + echo "$ac_t""no" 1>&6 +echo $ac_n "checking for shl_load""... $ac_c" 1>&6 +echo "$progname:2339: checking for shl_load" >&5 +if eval "test \"`echo '$''{'ac_cv_func_shl_load'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +/* Override any gcc2 internal prototype to avoid an error. */ +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char shl_load(); + +int main() { + +/* 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_shl_load) || defined (__stub___shl_load) +choke me +#else +shl_load(); +#endif + +; return 0; } +EOF +if { (eval echo $progname:2369: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + eval "ac_cv_func_shl_load=yes" +else + echo "$progname: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_func_shl_load=no" +fi +rm -f conftest* +fi + +if eval "test \"`echo '$ac_cv_func_'shl_load`\" = yes"; then + echo "$ac_t""yes" 1>&6 + lt_cv_dlopen="shl_load" +else + echo "$ac_t""no" 1>&6 +echo $ac_n "checking for shl_load in -ldld""... $ac_c" 1>&6 +echo "$progname:2387: checking for shl_load in -ldld" >&5 +ac_lib_var=`echo dld'_'shl_load | sed 'y%./+-%__p_%'` +if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + ac_save_LIBS="$LIBS" +LIBS="-ldld $LIBS" +cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=yes" +else + echo "$progname: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=no" +fi +rm -f conftest* +LIBS="$ac_save_LIBS" + +fi +if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then + echo "$ac_t""yes" 1>&6 + lt_cv_dlopen="shl_load" lt_cv_dlopen_libs="-ldld" +else + echo "$ac_t""no" 1>&6 +fi + + +fi + + +fi + + +fi + + +fi + +fi + + if test "x$lt_cv_dlopen" != xno; then + enable_dlopen=yes + fi + + case "$lt_cv_dlopen" in + dlopen) +for ac_hdr in dlfcn.h; do +ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'` +echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6 +echo "$progname:2452: checking for $ac_hdr" >&5 +if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +int fnord = 0; +EOF +ac_try="$ac_compile >/dev/null 2>conftest.out" +{ (eval echo $progname:2462: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` +if test -z "$ac_err"; then + rm -rf conftest* + eval "ac_cv_header_$ac_safe=yes" +else + echo "$ac_err" >&5 + echo "$progname: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_header_$ac_safe=no" +fi +rm -f conftest* +fi +if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then + echo "$ac_t""yes" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi +done + + if test "x$ac_cv_header_dlfcn_h" = xyes; then + CPPFLAGS="$CPPFLAGS -DHAVE_DLFCN_H" + fi + eval LDFLAGS=\"\$LDFLAGS $export_dynamic_flag_spec\" + LIBS="$lt_cv_dlopen_libs $LIBS" + + echo $ac_n "checking whether a program can dlopen itself""... $ac_c" 1>&6 +echo "$progname:2490: checking whether a program can dlopen itself" >&5 +if test "${lt_cv_dlopen_self+set}" = set; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test "$cross_compiling" = yes; then + lt_cv_dlopen_self=cross + else + cat > conftest.c < +#endif + +#include + +#ifdef RTLD_GLOBAL +# define LTDL_GLOBAL RTLD_GLOBAL +#else +# ifdef DL_GLOBAL +# define LTDL_GLOBAL DL_GLOBAL +# else +# define LTDL_GLOBAL 0 +# endif +#endif + +/* We may have to define LTDL_LAZY_OR_NOW in the command line if we + find out it does not work in some platform. */ +#ifndef LTDL_LAZY_OR_NOW +# ifdef RTLD_LAZY +# define LTDL_LAZY_OR_NOW RTLD_LAZY +# else +# ifdef DL_LAZY +# define LTDL_LAZY_OR_NOW DL_LAZY +# else +# ifdef RTLD_NOW +# define LTDL_LAZY_OR_NOW RTLD_NOW +# else +# ifdef DL_NOW +# define LTDL_LAZY_OR_NOW DL_NOW +# else +# define LTDL_LAZY_OR_NOW 0 +# endif +# endif +# endif +# endif +#endif + +fnord() { int i=42;} +main() { void *self, *ptr1, *ptr2; self=dlopen(0,LTDL_GLOBAL|LTDL_LAZY_OR_NOW); + if(self) { ptr1=dlsym(self,"fnord"); ptr2=dlsym(self,"_fnord"); + if(ptr1 || ptr2) { dlclose(self); exit(0); } } exit(1); } + +EOF +if { (eval echo $progname:2544: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest && (./conftest; exit) 2>/dev/null +then + lt_cv_dlopen_self=yes +else + echo "$progname: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -fr conftest* + lt_cv_dlopen_self=no +fi +rm -fr conftest* +fi + +fi + +echo "$ac_t""$lt_cv_dlopen_self" 1>&6 + + if test "$lt_cv_dlopen_self" = yes; then + LDFLAGS="$LDFLAGS $link_static_flag" + echo $ac_n "checking whether a statically linked program can dlopen itself""... $ac_c" 1>&6 +echo "$progname:2563: checking whether a statically linked program can dlopen itself" >&5 +if test "${lt_cv_dlopen_self_static+set}" = set; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test "$cross_compiling" = yes; then + lt_cv_dlopen_self_static=cross + else + cat > conftest.c < +#endif + +#include + +#ifdef RTLD_GLOBAL +# define LTDL_GLOBAL RTLD_GLOBAL +#else +# ifdef DL_GLOBAL +# define LTDL_GLOBAL DL_GLOBAL +# else +# define LTDL_GLOBAL 0 +# endif +#endif + +/* We may have to define LTDL_LAZY_OR_NOW in the command line if we + find out it does not work in some platform. */ +#ifndef LTDL_LAZY_OR_NOW +# ifdef RTLD_LAZY +# define LTDL_LAZY_OR_NOW RTLD_LAZY +# else +# ifdef DL_LAZY +# define LTDL_LAZY_OR_NOW DL_LAZY +# else +# ifdef RTLD_NOW +# define LTDL_LAZY_OR_NOW RTLD_NOW +# else +# ifdef DL_NOW +# define LTDL_LAZY_OR_NOW DL_NOW +# else +# define LTDL_LAZY_OR_NOW 0 +# endif +# endif +# endif +# endif +#endif + +fnord() { int i=42;} +main() { void *self, *ptr1, *ptr2; self=dlopen(0,LTDL_GLOBAL|LTDL_LAZY_OR_NOW); + if(self) { ptr1=dlsym(self,"fnord"); ptr2=dlsym(self,"_fnord"); + if(ptr1 || ptr2) { dlclose(self); exit(0); } } exit(1); } + +EOF +if { (eval echo $progname:2617: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest && (./conftest; exit) 2>/dev/null +then + lt_cv_dlopen_self_static=yes +else + echo "$progname: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -fr conftest* + lt_cv_dlopen_self_static=no +fi +rm -fr conftest* +fi + +fi + +echo "$ac_t""$lt_cv_dlopen_self_static" 1>&6 +fi + ;; + esac + + case "$lt_cv_dlopen_self" in + yes|no) enable_dlopen_self=$lt_cv_dlopen_self ;; + *) enable_dlopen_self=unknown ;; + esac + + case "$lt_cv_dlopen_self_static" in + yes|no) enable_dlopen_self_static=$lt_cv_dlopen_self_static ;; + *) enable_dlopen_self_static=unknown ;; + esac +fi + +# Copy echo and quote the copy, instead of the original, because it is +# used later. +ltecho="$echo" +if test "X$ltecho" = "X$CONFIG_SHELL $0 --fallback-echo"; then + ltecho="$CONFIG_SHELL \$0 --fallback-echo" +fi +LTSHELL="$SHELL" + +LTCONFIG_VERSION="$VERSION" + +# Only quote variables if we're using ltmain.sh. +case "$ltmain" in +*.sh) + # Now quote all the things that may contain metacharacters. + for var in ltecho old_CC old_CFLAGS old_CPPFLAGS \ + old_LD old_LDFLAGS old_LIBS \ + old_NM old_RANLIB old_LN_S old_DLLTOOL old_OBJDUMP old_AS \ + AR CC LD LN_S NM LTSHELL LTCONFIG_VERSION \ + reload_flag reload_cmds wl \ + pic_flag link_static_flag no_builtin_flag export_dynamic_flag_spec \ + thread_safe_flag_spec whole_archive_flag_spec libname_spec \ + library_names_spec soname_spec \ + RANLIB old_archive_cmds old_archive_from_new_cmds old_postinstall_cmds \ + old_postuninstall_cmds archive_cmds archive_expsym_cmds postinstall_cmds postuninstall_cmds \ + file_magic_cmd export_symbols_cmds deplibs_check_method allow_undefined_flag no_undefined_flag \ + finish_cmds finish_eval global_symbol_pipe global_symbol_to_cdecl \ + hardcode_libdir_flag_spec hardcode_libdir_separator \ + sys_lib_search_path_spec sys_lib_dlsearch_path_spec \ + compiler_c_o compiler_o_lo need_locks exclude_expsyms include_expsyms; do + + case "$var" in + reload_cmds | old_archive_cmds | old_archive_from_new_cmds | \ + old_postinstall_cmds | old_postuninstall_cmds | \ + export_symbols_cmds | archive_cmds | archive_expsym_cmds | \ + postinstall_cmds | postuninstall_cmds | \ + finish_cmds | sys_lib_search_path_spec | sys_lib_dlsearch_path_spec) + # Double-quote double-evaled strings. + eval "$var=\\\"\`\$echo \"X\$$var\" | \$Xsed -e \"\$double_quote_subst\" -e \"\$sed_quote_subst\" -e \"\$delay_variable_subst\"\`\\\"" + ;; + *) + eval "$var=\\\"\`\$echo \"X\$$var\" | \$Xsed -e \"\$sed_quote_subst\"\`\\\"" + ;; + esac + done + + case "$ltecho" in + *'\$0 --fallback-echo"') + ltecho=`$echo "X$ltecho" | $Xsed -e 's/\\\\\\\$0 --fallback-echo"$/$0 --fallback-echo"/'` + ;; + esac + + trap "$rm \"$ofile\"; exit 1" 1 2 15 + echo "creating $ofile" + $rm "$ofile" + cat < "$ofile" +#! $SHELL + +# `$echo "$ofile" | sed 's%^.*/%%'` - Provide generalized library-building support services. +# Generated automatically by $PROGRAM (GNU $PACKAGE $VERSION$TIMESTAMP) +# NOTE: Changes made to this file will be lost: look at ltconfig or ltmain.sh. +# +# Copyright (C) 1996-1999 Free Software Foundation, Inc. +# Originally by Gordon Matzigkeit , 1996 +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# 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. + +# Sed that helps us avoid accidentally triggering echo(1) options like -n. +Xsed="sed -e s/^X//" + +# The HP-UX ksh and POSIX shell print the target directory to stdout +# if CDPATH is set. +if test "X\${CDPATH+set}" = Xset; then CDPATH=:; export CDPATH; fi + +### BEGIN LIBTOOL CONFIG +EOF + cfgfile="$ofile" + ;; + +*) + # Double-quote the variables that need it (for aesthetics). + for var in old_CC old_CFLAGS old_CPPFLAGS \ + old_LD old_LDFLAGS old_LIBS \ + old_NM old_RANLIB old_LN_S old_DLLTOOL old_OBJDUMP old_AS; do + eval "$var=\\\"\$var\\\"" + done + + # Just create a config file. + cfgfile="$ofile.cfg" + trap "$rm \"$cfgfile\"; exit 1" 1 2 15 + echo "creating $cfgfile" + $rm "$cfgfile" + cat < "$cfgfile" +# `$echo "$cfgfile" | sed 's%^.*/%%'` - Libtool configuration file. +# Generated automatically by $PROGRAM (GNU $PACKAGE $VERSION$TIMESTAMP) +EOF + ;; +esac + +cat <> "$cfgfile" +# Libtool was configured as follows, on host `(hostname || uname -n) 2>/dev/null | sed 1q`: +# +# CC=$old_CC CFLAGS=$old_CFLAGS CPPFLAGS=$old_CPPFLAGS \\ +# LD=$old_LD LDFLAGS=$old_LDFLAGS LIBS=$old_LIBS \\ +# NM=$old_NM RANLIB=$old_RANLIB LN_S=$old_LN_S \\ +# DLLTOOL=$old_DLLTOOL OBJDUMP=$old_OBJDUMP AS=$old_AS \\ +# $0$ltconfig_args +# +# Compiler and other test output produced by $progname, useful for +# debugging $progname, is in ./config.log if it exists. + +# The version of $progname that generated this script. +LTCONFIG_VERSION=$LTCONFIG_VERSION + +# Shell to use when invoking shell scripts. +SHELL=$LTSHELL + +# Whether or not to build shared libraries. +build_libtool_libs=$enable_shared + +# Whether or not to build static libraries. +build_old_libs=$enable_static + +# Whether or not to optimize for fast installation. +fast_install=$enable_fast_install + +# The host system. +host_alias=$host_alias +host=$host + +# An echo program that does not interpret backslashes. +echo=$ltecho + +# The archiver. +AR=$AR + +# The default C compiler. +CC=$CC + +# The linker used to build libraries. +LD=$LD + +# Whether we need hard or soft links. +LN_S=$LN_S + +# A BSD-compatible nm program. +NM=$NM + +# Used on cygwin: DLL creation program. +DLLTOOL="$DLLTOOL" + +# Used on cygwin: object dumper. +OBJDUMP="$OBJDUMP" + +# Used on cygwin: assembler. +AS="$AS" + +# The name of the directory that contains temporary libtool files. +objdir=$objdir + +# How to create reloadable object files. +reload_flag=$reload_flag +reload_cmds=$reload_cmds + +# How to pass a linker flag through the compiler. +wl=$wl + +# Object file suffix (normally "o"). +objext="$objext" + +# Old archive suffix (normally "a"). +libext="$libext" + +# Executable file suffix (normally ""). +exeext="$exeext" + +# Additional compiler flags for building library objects. +pic_flag=$pic_flag + +# Does compiler simultaneously support -c and -o options? +compiler_c_o=$compiler_c_o + +# Can we write directly to a .lo ? +compiler_o_lo=$compiler_o_lo + +# Must we lock files when doing compilation ? +need_locks=$need_locks + +# Do we need the lib prefix for modules? +need_lib_prefix=$need_lib_prefix + +# Do we need a version for libraries? +need_version=$need_version + +# Whether dlopen is supported. +dlopen=$enable_dlopen + +# Whether dlopen of programs is supported. +dlopen_self=$enable_dlopen_self + +# Whether dlopen of statically linked programs is supported. +dlopen_self_static=$enable_dlopen_self_static + +# Compiler flag to prevent dynamic linking. +link_static_flag=$link_static_flag + +# Compiler flag to turn off builtin functions. +no_builtin_flag=$no_builtin_flag + +# Compiler flag to allow reflexive dlopens. +export_dynamic_flag_spec=$export_dynamic_flag_spec + +# Compiler flag to generate shared objects directly from archives. +whole_archive_flag_spec=$whole_archive_flag_spec + +# Compiler flag to generate thread-safe objects. +thread_safe_flag_spec=$thread_safe_flag_spec + +# Library versioning type. +version_type=$version_type + +# Format of library name prefix. +libname_spec=$libname_spec + +# List of archive names. First name is the real one, the rest are links. +# The last name is the one that the linker finds with -lNAME. +library_names_spec=$library_names_spec + +# The coded name of the library, if different from the real name. +soname_spec=$soname_spec + +# Commands used to build and install an old-style archive. +RANLIB=$RANLIB +old_archive_cmds=$old_archive_cmds +old_postinstall_cmds=$old_postinstall_cmds +old_postuninstall_cmds=$old_postuninstall_cmds + +# Create an old-style archive from a shared archive. +old_archive_from_new_cmds=$old_archive_from_new_cmds + +# Commands used to build and install a shared archive. +archive_cmds=$archive_cmds +archive_expsym_cmds=$archive_expsym_cmds +postinstall_cmds=$postinstall_cmds +postuninstall_cmds=$postuninstall_cmds + +# Method to check whether dependent libraries are shared objects. +deplibs_check_method=$deplibs_check_method + +# Command to use when deplibs_check_method == file_magic. +file_magic_cmd=$file_magic_cmd + +# Flag that allows shared libraries with undefined symbols to be built. +allow_undefined_flag=$allow_undefined_flag + +# Flag that forces no undefined symbols. +no_undefined_flag=$no_undefined_flag + +# Commands used to finish a libtool library installation in a directory. +finish_cmds=$finish_cmds + +# Same as above, but a single script fragment to be evaled but not shown. +finish_eval=$finish_eval + +# Take the output of nm and produce a listing of raw symbols and C names. +global_symbol_pipe=$global_symbol_pipe + +# Transform the output of nm in a proper C declaration +global_symbol_to_cdecl=$global_symbol_to_cdecl + +# This is the shared library runtime path variable. +runpath_var=$runpath_var + +# This is the shared library path variable. +shlibpath_var=$shlibpath_var + +# Is shlibpath searched before the hard-coded library search path? +shlibpath_overrides_runpath=$shlibpath_overrides_runpath + +# How to hardcode a shared library path into an executable. +hardcode_action=$hardcode_action + +# Flag to hardcode \$libdir into a binary during linking. +# This must work even if \$libdir does not exist. +hardcode_libdir_flag_spec=$hardcode_libdir_flag_spec + +# Whether we need a single -rpath flag with a separated argument. +hardcode_libdir_separator=$hardcode_libdir_separator + +# Set to yes if using DIR/libNAME.so during linking hardcodes DIR into the +# resulting binary. +hardcode_direct=$hardcode_direct + +# Set to yes if using the -LDIR flag during linking hardcodes DIR into the +# resulting binary. +hardcode_minus_L=$hardcode_minus_L + +# Set to yes if using SHLIBPATH_VAR=DIR during linking hardcodes DIR into +# the resulting binary. +hardcode_shlibpath_var=$hardcode_shlibpath_var + +# Compile-time system search path for libraries +sys_lib_search_path_spec=$sys_lib_search_path_spec + +# Run-time system search path for libraries +sys_lib_dlsearch_path_spec=$sys_lib_dlsearch_path_spec + +# Fix the shell variable \$srcfile for the compiler. +fix_srcfile_path="$fix_srcfile_path" + +# Set to yes if exported symbols are required. +always_export_symbols=$always_export_symbols + +# The commands to list exported symbols. +export_symbols_cmds=$export_symbols_cmds + +# Symbols that should not be listed in the preloaded symbols. +exclude_expsyms=$exclude_expsyms + +# Symbols that must always be exported. +include_expsyms=$include_expsyms + +EOF + +case "$ltmain" in +*.sh) + echo '### END LIBTOOL CONFIG' >> "$ofile" + echo >> "$ofile" + case "$host_os" in + aix3*) + cat <<\EOF >> "$ofile" + +# AIX sometimes has problems with the GCC collect2 program. For some +# reason, if we set the COLLECT_NAMES environment variable, the problems +# vanish in a puff of smoke. +if test "X${COLLECT_NAMES+set}" != Xset; then + COLLECT_NAMES= + export COLLECT_NAMES +fi +EOF + ;; + esac + + # Append the ltmain.sh script. + sed '$q' "$ltmain" >> "$ofile" || (rm -f "$ofile"; exit 1) + # We use sed instead of cat because bash on DJGPP gets confused if + # if finds mixed CR/LF and LF-only lines. Since sed operates in + # text mode, it properly converts lines to CR/LF. This bash problem + # is reportedly fixed, but why not run on old versions too? + + chmod +x "$ofile" + ;; + +*) + # Compile the libtool program. + echo "FIXME: would compile $ltmain" + ;; +esac + +test -n "$cache_file" || exit 0 + +# AC_CACHE_SAVE +trap '' 1 2 15 +cat > confcache <<\EOF +# 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. It is not useful on other systems. +# If it contains results you don't want to keep, you may remove or edit it. +# +# By default, configure uses ./config.cache as the cache file, +# creating it if it does not exist already. You can give configure +# the --cache-file=FILE option to use a different cache file; that is +# what configure does when it calls configure scripts in +# subdirectories, so they share the cache. +# Giving --cache-file=/dev/null disables caching, for debugging configure. +# config.status only pays attention to the cache file if you give it the +# --recheck option to rerun configure. +# +EOF +# The following way of writing the cache mishandles newlines in values, +# but we know of no workaround that is simple, portable, and efficient. +# So, don't put newlines in cache variables' values. +# Ultrix sh set writes to stderr and can't be redirected directly, +# and sets the high bit in the cache file unless we assign to the vars. +(set) 2>&1 | + case `(ac_space=' '; set | grep ac_space) 2>&1` in + *ac_space=\ *) + # `set' does not quote correctly, so add quotes (double-quote substitution + # turns \\\\ into \\, and sed turns \\ into \). + sed -n \ + -e "s/'/'\\\\''/g" \ + -e "s/^\\([a-zA-Z0-9_]*_cv_[a-zA-Z0-9_]*\\)=\\(.*\\)/\\1=\${\\1='\\2'}/p" + ;; + *) + # `set' quotes correctly as required by POSIX, so do not add quotes. + sed -n -e 's/^\([a-zA-Z0-9_]*_cv_[a-zA-Z0-9_]*\)=\(.*\)/\1=${\1=\2}/p' + ;; + esac >> confcache +if cmp -s $cache_file confcache; then + : +else + if test -w $cache_file; then + echo "updating cache $cache_file" + cat confcache > $cache_file + else + echo "not updating unwritable cache $cache_file" + fi +fi +rm -f confcache + +exit 0 + +# Local Variables: +# mode:shell-script +# sh-indentation:2 +# End: diff --git a/ltmain.sh b/ltmain.sh new file mode 100644 index 0000000..50515ad --- /dev/null +++ b/ltmain.sh @@ -0,0 +1,4012 @@ +# ltmain.sh - Provide generalized library-building support services. +# NOTE: Changing this file will not affect anything until you rerun ltconfig. +# +# Copyright (C) 1996-1999 Free Software Foundation, Inc. +# Originally by Gordon Matzigkeit , 1996 +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# 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. + +# Check that we have a working $echo. +if test "X$1" = X--no-reexec; then + # Discard the --no-reexec flag, and continue. + shift +elif test "X$1" = X--fallback-echo; then + # Avoid inline document here, it may be left over + : +elif test "X`($echo '\t') 2>/dev/null`" = 'X\t'; then + # Yippee, $echo works! + : +else + # Restart under the correct shell, and then maybe $echo will work. + exec $SHELL "$0" --no-reexec ${1+"$@"} +fi + +if test "X$1" = X--fallback-echo; then + # used as fallback echo + shift + cat <&2 + echo "Fatal configuration error. See the $PACKAGE docs for more information." 1>&2 + exit 1 +fi + +if test "$build_libtool_libs" != yes && test "$build_old_libs" != yes; then + echo "$modename: not configured to build any kind of library" 1>&2 + echo "Fatal configuration error. See the $PACKAGE docs for more information." 1>&2 + exit 1 +fi + +# Global variables. +mode=$default_mode +nonopt= +prev= +prevopt= +run= +show="$echo" +show_help= +execute_dlfiles= +lo2o="s/\\.lo\$/.${objext}/" +o2lo="s/\\.${objext}\$/.lo/" + +# Parse our command line options once, thoroughly. +while test $# -gt 0 +do + arg="$1" + shift + + case "$arg" in + -*=*) optarg=`$echo "X$arg" | $Xsed -e 's/[-_a-zA-Z0-9]*=//'` ;; + *) optarg= ;; + esac + + # If the previous option needs an argument, assign it. + if test -n "$prev"; then + case "$prev" in + execute_dlfiles) + eval "$prev=\"\$$prev \$arg\"" + ;; + *) + eval "$prev=\$arg" + ;; + esac + + prev= + prevopt= + continue + fi + + # Have we seen a non-optional argument yet? + case "$arg" in + --help) + show_help=yes + ;; + + --version) + echo "$PROGRAM (GNU $PACKAGE) $VERSION$TIMESTAMP" + exit 0 + ;; + + --config) + sed -e '1,/^### BEGIN LIBTOOL CONFIG/d' -e '/^### END LIBTOOL CONFIG/,$d' $0 + exit 0 + ;; + + --debug) + echo "$progname: enabling shell trace mode" + set -x + ;; + + --dry-run | -n) + run=: + ;; + + --features) + echo "host: $host" + if test "$build_libtool_libs" = yes; then + echo "enable shared libraries" + else + echo "disable shared libraries" + fi + if test "$build_old_libs" = yes; then + echo "enable static libraries" + else + echo "disable static libraries" + fi + exit 0 + ;; + + --finish) mode="finish" ;; + + --mode) prevopt="--mode" prev=mode ;; + --mode=*) mode="$optarg" ;; + + --quiet | --silent) + show=: + ;; + + -dlopen) + prevopt="-dlopen" + prev=execute_dlfiles + ;; + + -*) + $echo "$modename: unrecognized option \`$arg'" 1>&2 + $echo "$help" 1>&2 + exit 1 + ;; + + *) + nonopt="$arg" + break + ;; + esac +done + +if test -n "$prevopt"; then + $echo "$modename: option \`$prevopt' requires an argument" 1>&2 + $echo "$help" 1>&2 + exit 1 +fi + +if test -z "$show_help"; then + + # Infer the operation mode. + if test -z "$mode"; then + case "$nonopt" in + *cc | *++ | gcc* | *-gcc*) + mode=link + for arg + do + case "$arg" in + -c) + mode=compile + break + ;; + esac + done + ;; + *db | *dbx | *strace | *truss) + mode=execute + ;; + *install*|cp|mv) + mode=install + ;; + *rm) + mode=uninstall + ;; + *) + # If we have no mode, but dlfiles were specified, then do execute mode. + test -n "$execute_dlfiles" && mode=execute + + # Just use the default operation mode. + if test -z "$mode"; then + if test -n "$nonopt"; then + $echo "$modename: warning: cannot infer operation mode from \`$nonopt'" 1>&2 + else + $echo "$modename: warning: cannot infer operation mode without MODE-ARGS" 1>&2 + fi + fi + ;; + esac + fi + + # Only execute mode is allowed to have -dlopen flags. + if test -n "$execute_dlfiles" && test "$mode" != execute; then + $echo "$modename: unrecognized option \`-dlopen'" 1>&2 + $echo "$help" 1>&2 + exit 1 + fi + + # Change the help message to a mode-specific one. + generic_help="$help" + help="Try \`$modename --help --mode=$mode' for more information." + + # These modes are in order of execution frequency so that they run quickly. + case "$mode" in + # libtool compile mode + compile) + modename="$modename: compile" + # Get the compilation command and the source file. + base_compile= + lastarg= + srcfile="$nonopt" + suppress_output= + + user_target=no + for arg + do + # Accept any command-line options. + case "$arg" in + -o) + if test "$user_target" != "no"; then + $echo "$modename: you cannot specify \`-o' more than once" 1>&2 + exit 1 + fi + user_target=next + ;; + + -static) + build_old_libs=yes + continue + ;; + esac + + case "$user_target" in + next) + # The next one is the -o target name + user_target=yes + continue + ;; + yes) + # We got the output file + user_target=set + libobj="$arg" + continue + ;; + esac + + # Accept the current argument as the source file. + lastarg="$srcfile" + srcfile="$arg" + + # Aesthetically quote the previous argument. + + # Backslashify any backslashes, double quotes, and dollar signs. + # These are the only characters that are still specially + # interpreted inside of double-quoted scrings. + lastarg=`$echo "X$lastarg" | $Xsed -e "$sed_quote_subst"` + + # Double-quote args containing other shell metacharacters. + # Many Bourne shells cannot handle close brackets correctly in scan + # sets, so we specify it separately. + case "$lastarg" in + *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*) + lastarg="\"$lastarg\"" + ;; + esac + + # Add the previous argument to base_compile. + if test -z "$base_compile"; then + base_compile="$lastarg" + else + base_compile="$base_compile $lastarg" + fi + done + + case "$user_target" in + set) + ;; + no) + # Get the name of the library object. + libobj=`$echo "X$srcfile" | $Xsed -e 's%^.*/%%'` + ;; + *) + $echo "$modename: you must specify a target with \`-o'" 1>&2 + exit 1 + ;; + esac + + # Recognize several different file suffixes. + # If the user specifies -o file.o, it is replaced with file.lo + xform='[cCFSfmso]' + case "$libobj" in + *.ada) xform=ada ;; + *.adb) xform=adb ;; + *.ads) xform=ads ;; + *.asm) xform=asm ;; + *.c++) xform=c++ ;; + *.cc) xform=cc ;; + *.cpp) xform=cpp ;; + *.cxx) xform=cxx ;; + *.f90) xform=f90 ;; + *.for) xform=for ;; + esac + + libobj=`$echo "X$libobj" | $Xsed -e "s/\.$xform$/.lo/"` + + case "$libobj" in + *.lo) obj=`$echo "X$libobj" | $Xsed -e "$lo2o"` ;; + *) + $echo "$modename: cannot determine name of library object from \`$libobj'" 1>&2 + exit 1 + ;; + esac + + if test -z "$base_compile"; then + $echo "$modename: you must specify a compilation command" 1>&2 + $echo "$help" 1>&2 + exit 1 + fi + + # Delete any leftover library objects. + if test "$build_old_libs" = yes; then + removelist="$obj $libobj" + else + removelist="$libobj" + fi + + $run $rm $removelist + trap "$run $rm $removelist; exit 1" 1 2 15 + + # Calculate the filename of the output object if compiler does + # not support -o with -c + if test "$compiler_c_o" = no; then + output_obj=`$echo "X$srcfile" | $Xsed -e 's%^.*/%%' -e 's%\..*$%%'`.${objext} + lockfile="$output_obj.lock" + removelist="$removelist $output_obj $lockfile" + trap "$run $rm $removelist; exit 1" 1 2 15 + else + need_locks=no + lockfile= + fi + + # Lock this critical section if it is needed + # We use this script file to make the link, it avoids creating a new file + if test "$need_locks" = yes; then + until ln "$0" "$lockfile" 2>/dev/null; do + $show "Waiting for $lockfile to be removed" + sleep 2 + done + elif test "$need_locks" = warn; then + if test -f "$lockfile"; then + echo "\ +*** ERROR, $lockfile exists and contains: +`cat $lockfile 2>/dev/null` + +This indicates that another process is trying to use the same +temporary object file, and libtool could not work around it because +your compiler does not support \`-c' and \`-o' together. If you +repeat this compilation, it may succeed, by chance, but you had better +avoid parallel builds (make -j) in this platform, or get a better +compiler." + + $run $rm $removelist + exit 1 + fi + echo $srcfile > "$lockfile" + fi + + if test -n "$fix_srcfile_path"; then + eval srcfile=\"$fix_srcfile_path\" + fi + + # Only build a PIC object if we are building libtool libraries. + if test "$build_libtool_libs" = yes; then + # Without this assignment, base_compile gets emptied. + fbsd_hideous_sh_bug=$base_compile + + # All platforms use -DPIC, to notify preprocessed assembler code. + command="$base_compile $srcfile $pic_flag -DPIC" + if test "$build_old_libs" = yes; then + lo_libobj="$libobj" + dir=`$echo "X$libobj" | $Xsed -e 's%/[^/]*$%%'` + if test "X$dir" = "X$libobj"; then + dir="$objdir" + else + dir="$dir/$objdir" + fi + libobj="$dir/"`$echo "X$libobj" | $Xsed -e 's%^.*/%%'` + + if test -d "$dir"; then + $show "$rm $libobj" + $run $rm $libobj + else + $show "$mkdir $dir" + $run $mkdir $dir + status=$? + if test $status -ne 0 && test ! -d $dir; then + exit $status + fi + fi + fi + if test "$compiler_o_lo" = yes; then + output_obj="$libobj" + command="$command -o $output_obj" + elif test "$compiler_c_o" = yes; then + output_obj="$obj" + command="$command -o $output_obj" + fi + + $run $rm "$output_obj" + $show "$command" + if $run eval "$command"; then : + else + test -n "$output_obj" && $run $rm $removelist + exit 1 + fi + + if test "$need_locks" = warn && + test x"`cat $lockfile 2>/dev/null`" != x"$srcfile"; then + echo "\ +*** ERROR, $lockfile contains: +`cat $lockfile 2>/dev/null` + +but it should contain: +$srcfile + +This indicates that another process is trying to use the same +temporary object file, and libtool could not work around it because +your compiler does not support \`-c' and \`-o' together. If you +repeat this compilation, it may succeed, by chance, but you had better +avoid parallel builds (make -j) in this platform, or get a better +compiler." + + $run $rm $removelist + exit 1 + fi + + # Just move the object if needed, then go on to compile the next one + if test x"$output_obj" != x"$libobj"; then + $show "$mv $output_obj $libobj" + if $run $mv $output_obj $libobj; then : + else + error=$? + $run $rm $removelist + exit $error + fi + fi + + # If we have no pic_flag, then copy the object into place and finish. + if test -z "$pic_flag" && test "$build_old_libs" = yes; then + # Rename the .lo from within objdir to obj + if test -f $obj; then + $show $rm $obj + $run $rm $obj + fi + + $show "$mv $libobj $obj" + if $run $mv $libobj $obj; then : + else + error=$? + $run $rm $removelist + exit $error + fi + + xdir=`$echo "X$obj" | $Xsed -e 's%/[^/]*$%%'` + if test "X$xdir" = "X$obj"; then + xdir="." + else + xdir="$xdir" + fi + baseobj=`$echo "X$obj" | $Xsed -e "s%.*/%%"` + libobj=`$echo "X$baseobj" | $Xsed -e "$o2lo"` + # Now arrange that obj and lo_libobj become the same file + $show "(cd $xdir && $LN_S $baseobj $libobj)" + if $run eval '(cd $xdir && $LN_S $baseobj $libobj)'; then + exit 0 + else + error=$? + $run $rm $removelist + exit $error + fi + fi + + # Allow error messages only from the first compilation. + suppress_output=' >/dev/null 2>&1' + fi + + # Only build a position-dependent object if we build old libraries. + if test "$build_old_libs" = yes; then + command="$base_compile $srcfile" + if test "$compiler_c_o" = yes; then + command="$command -o $obj" + output_obj="$obj" + fi + + # Suppress compiler output if we already did a PIC compilation. + command="$command$suppress_output" + $run $rm "$output_obj" + $show "$command" + if $run eval "$command"; then : + else + $run $rm $removelist + exit 1 + fi + + if test "$need_locks" = warn && + test x"`cat $lockfile 2>/dev/null`" != x"$srcfile"; then + echo "\ +*** ERROR, $lockfile contains: +`cat $lockfile 2>/dev/null` + +but it should contain: +$srcfile + +This indicates that another process is trying to use the same +temporary object file, and libtool could not work around it because +your compiler does not support \`-c' and \`-o' together. If you +repeat this compilation, it may succeed, by chance, but you had better +avoid parallel builds (make -j) in this platform, or get a better +compiler." + + $run $rm $removelist + exit 1 + fi + + # Just move the object if needed + if test x"$output_obj" != x"$obj"; then + $show "$mv $output_obj $obj" + if $run $mv $output_obj $obj; then : + else + error=$? + $run $rm $removelist + exit $error + fi + fi + + # Create an invalid libtool object if no PIC, so that we do not + # accidentally link it into a program. + if test "$build_libtool_libs" != yes; then + $show "echo timestamp > $libobj" + $run eval "echo timestamp > \$libobj" || exit $? + else + # Move the .lo from within objdir + $show "$mv $libobj $lo_libobj" + if $run $mv $libobj $lo_libobj; then : + else + error=$? + $run $rm $removelist + exit $error + fi + fi + fi + + # Unlock the critical section if it was locked + if test "$need_locks" != no; then + $rm "$lockfile" + fi + + exit 0 + ;; + + # libtool link mode + link) + modename="$modename: link" + case "$host" in + *-*-cygwin* | *-*-mingw* | *-*-os2*) + # It is impossible to link a dll without this setting, and + # we shouldn't force the makefile maintainer to figure out + # which system we are compiling for in order to pass an extra + # flag for every libtool invokation. + # allow_undefined=no + + # FIXME: Unfortunately, there are problems with the above when trying + # to make a dll which has undefined symbols, in which case not + # even a static library is built. For now, we need to specify + # -no-undefined on the libtool link line when we can be certain + # that all symbols are satisfied, otherwise we get a static library. + allow_undefined=yes + + # This is a source program that is used to create dlls on Windows + # Don't remove nor modify the starting and closing comments +# /* ltdll.c starts here */ +# #define WIN32_LEAN_AND_MEAN +# #include +# #undef WIN32_LEAN_AND_MEAN +# #include +# +# #ifndef __CYGWIN__ +# # ifdef __CYGWIN32__ +# # define __CYGWIN__ __CYGWIN32__ +# # endif +# #endif +# +# #ifdef __cplusplus +# extern "C" { +# #endif +# BOOL APIENTRY DllMain (HINSTANCE hInst, DWORD reason, LPVOID reserved); +# #ifdef __cplusplus +# } +# #endif +# +# #ifdef __CYGWIN__ +# #include +# DECLARE_CYGWIN_DLL( DllMain ); +# #endif +# HINSTANCE __hDllInstance_base; +# +# BOOL APIENTRY +# DllMain (HINSTANCE hInst, DWORD reason, LPVOID reserved) +# { +# __hDllInstance_base = hInst; +# return TRUE; +# } +# /* ltdll.c ends here */ + # This is a source program that is used to create import libraries + # on Windows for dlls which lack them. Don't remove nor modify the + # starting and closing comments +# /* impgen.c starts here */ +# /* Copyright (C) 1999 Free Software Foundation, Inc. +# +# This file is part of GNU libtool. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# */ +# +# #include /* for printf() */ +# #include /* for open(), lseek(), read() */ +# #include /* for O_RDONLY, O_BINARY */ +# #include /* for strdup() */ +# +# static unsigned int +# pe_get16 (fd, offset) +# int fd; +# int offset; +# { +# unsigned char b[2]; +# lseek (fd, offset, SEEK_SET); +# read (fd, b, 2); +# return b[0] + (b[1]<<8); +# } +# +# static unsigned int +# pe_get32 (fd, offset) +# int fd; +# int offset; +# { +# unsigned char b[4]; +# lseek (fd, offset, SEEK_SET); +# read (fd, b, 4); +# return b[0] + (b[1]<<8) + (b[2]<<16) + (b[3]<<24); +# } +# +# static unsigned int +# pe_as32 (ptr) +# void *ptr; +# { +# unsigned char *b = ptr; +# return b[0] + (b[1]<<8) + (b[2]<<16) + (b[3]<<24); +# } +# +# int +# main (argc, argv) +# int argc; +# char *argv[]; +# { +# int dll; +# unsigned long pe_header_offset, opthdr_ofs, num_entries, i; +# unsigned long export_rva, export_size, nsections, secptr, expptr; +# unsigned long name_rvas, nexp; +# unsigned char *expdata, *erva; +# char *filename, *dll_name; +# +# filename = argv[1]; +# +# dll = open(filename, O_RDONLY|O_BINARY); +# if (!dll) +# return 1; +# +# dll_name = filename; +# +# for (i=0; filename[i]; i++) +# if (filename[i] == '/' || filename[i] == '\\' || filename[i] == ':') +# dll_name = filename + i +1; +# +# pe_header_offset = pe_get32 (dll, 0x3c); +# opthdr_ofs = pe_header_offset + 4 + 20; +# num_entries = pe_get32 (dll, opthdr_ofs + 92); +# +# if (num_entries < 1) /* no exports */ +# return 1; +# +# export_rva = pe_get32 (dll, opthdr_ofs + 96); +# export_size = pe_get32 (dll, opthdr_ofs + 100); +# nsections = pe_get16 (dll, pe_header_offset + 4 +2); +# secptr = (pe_header_offset + 4 + 20 + +# pe_get16 (dll, pe_header_offset + 4 + 16)); +# +# expptr = 0; +# for (i = 0; i < nsections; i++) +# { +# char sname[8]; +# unsigned long secptr1 = secptr + 40 * i; +# unsigned long vaddr = pe_get32 (dll, secptr1 + 12); +# unsigned long vsize = pe_get32 (dll, secptr1 + 16); +# unsigned long fptr = pe_get32 (dll, secptr1 + 20); +# lseek(dll, secptr1, SEEK_SET); +# read(dll, sname, 8); +# if (vaddr <= export_rva && vaddr+vsize > export_rva) +# { +# expptr = fptr + (export_rva - vaddr); +# if (export_rva + export_size > vaddr + vsize) +# export_size = vsize - (export_rva - vaddr); +# break; +# } +# } +# +# expdata = (unsigned char*)malloc(export_size); +# lseek (dll, expptr, SEEK_SET); +# read (dll, expdata, export_size); +# erva = expdata - export_rva; +# +# nexp = pe_as32 (expdata+24); +# name_rvas = pe_as32 (expdata+32); +# +# printf ("EXPORTS\n"); +# for (i = 0; i&2 + fi + if test -n "$link_static_flag"; then + dlopen_self=$dlopen_self_static + fi + else + if test -z "$pic_flag" && test -n "$link_static_flag"; then + dlopen_self=$dlopen_self_static + fi + fi + build_libtool_libs=no + build_old_libs=yes + prefer_static_libs=yes + break + ;; + esac + done + + # See if our shared archives depend on static archives. + test -n "$old_archive_from_new_cmds" && build_old_libs=yes + + # Go through the arguments, transforming them on the way. + while test $# -gt 0; do + arg="$1" + shift + + # If the previous option needs an argument, assign it. + if test -n "$prev"; then + case "$prev" in + output) + compile_command="$compile_command @OUTPUT@" + finalize_command="$finalize_command @OUTPUT@" + ;; + esac + + case "$prev" in + dlfiles|dlprefiles) + if test "$preload" = no; then + # Add the symbol object into the linking commands. + compile_command="$compile_command @SYMFILE@" + finalize_command="$finalize_command @SYMFILE@" + preload=yes + fi + case "$arg" in + *.la | *.lo) ;; # We handle these cases below. + force) + if test "$dlself" = no; then + dlself=needless + export_dynamic=yes + fi + prev= + continue + ;; + self) + if test "$prev" = dlprefiles; then + dlself=yes + elif test "$prev" = dlfiles && test "$dlopen_self" != yes; then + dlself=yes + else + dlself=needless + export_dynamic=yes + fi + prev= + continue + ;; + *) + if test "$prev" = dlfiles; then + dlfiles="$dlfiles $arg" + else + dlprefiles="$dlprefiles $arg" + fi + prev= + ;; + esac + ;; + expsyms) + export_symbols="$arg" + if test ! -f "$arg"; then + $echo "$modename: symbol file \`$arg' does not exist" + exit 1 + fi + prev= + continue + ;; + expsyms_regex) + export_symbols_regex="$arg" + prev= + continue + ;; + release) + release="-$arg" + prev= + continue + ;; + rpath | xrpath) + # We need an absolute path. + case "$arg" in + [\\/]* | [A-Za-z]:[\\/]*) ;; + *) + $echo "$modename: only absolute run-paths are allowed" 1>&2 + exit 1 + ;; + esac + if test "$prev" = rpath; then + case "$rpath " in + *" $arg "*) ;; + *) rpath="$rpath $arg" ;; + esac + else + case "$xrpath " in + *" $arg "*) ;; + *) xrpath="$xrpath $arg" ;; + esac + fi + prev= + continue + ;; + *) + eval "$prev=\"\$arg\"" + prev= + continue + ;; + esac + fi + + prevarg="$arg" + + case "$arg" in + -all-static) + if test -n "$link_static_flag"; then + compile_command="$compile_command $link_static_flag" + finalize_command="$finalize_command $link_static_flag" + fi + continue + ;; + + -allow-undefined) + # FIXME: remove this flag sometime in the future. + $echo "$modename: \`-allow-undefined' is deprecated because it is the default" 1>&2 + continue + ;; + + -avoid-version) + avoid_version=yes + continue + ;; + + -dlopen) + prev=dlfiles + continue + ;; + + -dlpreopen) + prev=dlprefiles + continue + ;; + + -export-dynamic) + export_dynamic=yes + continue + ;; + + -export-symbols | -export-symbols-regex) + if test -n "$export_symbols" || test -n "$export_symbols_regex"; then + $echo "$modename: not more than one -exported-symbols argument allowed" + exit 1 + fi + if test "X$arg" = "X-export-symbols"; then + prev=expsyms + else + prev=expsyms_regex + fi + continue + ;; + + -L*) + dir=`$echo "X$arg" | $Xsed -e 's/^-L//'` + # We need an absolute path. + case "$dir" in + [\\/]* | [A-Za-z]:[\\/]*) ;; + *) + absdir=`cd "$dir" && pwd` + if test -z "$absdir"; then + $echo "$modename: warning: cannot determine absolute directory name of \`$dir'" 1>&2 + $echo "$modename: passing it literally to the linker, although it might fail" 1>&2 + absdir="$dir" + fi + dir="$absdir" + ;; + esac + case " $deplibs " in + *" $arg "*) ;; + *) deplibs="$deplibs $arg";; + esac + case " $lib_search_path " in + *" $dir "*) ;; + *) lib_search_path="$lib_search_path $dir";; + esac + case "$host" in + *-*-cygwin* | *-*-mingw* | *-*-os2*) + dllsearchdir=`cd "$dir" && pwd || echo "$dir"` + case ":$dllsearchpath:" in + ::) dllsearchpath="$dllsearchdir";; + *":$dllsearchdir:"*) ;; + *) dllsearchpath="$dllsearchpath:$dllsearchdir";; + esac + ;; + esac + ;; + + -l*) + if test "$arg" = "-lc"; then + case "$host" in + *-*-cygwin* | *-*-mingw* | *-*-os2* | *-*-beos*) + # These systems don't actually have c library (as such) + continue + ;; + esac + elif test "$arg" = "-lm"; then + case "$host" in + *-*-cygwin* | *-*-beos*) + # These systems don't actually have math library (as such) + continue + ;; + esac + fi + deplibs="$deplibs $arg" + ;; + + -module) + module=yes + continue + ;; + + -no-undefined) + allow_undefined=no + continue + ;; + + -o) prev=output ;; + + -release) + prev=release + continue + ;; + + -rpath) + prev=rpath + continue + ;; + + -R) + prev=xrpath + continue + ;; + + -R*) + dir=`$echo "X$arg" | $Xsed -e 's/^-R//'` + # We need an absolute path. + case "$dir" in + [\\/]* | [A-Za-z]:[\\/]*) ;; + *) + $echo "$modename: only absolute run-paths are allowed" 1>&2 + exit 1 + ;; + esac + case "$xrpath " in + *" $dir "*) ;; + *) xrpath="$xrpath $dir" ;; + esac + continue + ;; + + -static) + # If we have no pic_flag, then this is the same as -all-static. + if test -z "$pic_flag" && test -n "$link_static_flag"; then + compile_command="$compile_command $link_static_flag" + finalize_command="$finalize_command $link_static_flag" + fi + continue + ;; + + -thread-safe) + thread_safe=yes + continue + ;; + + -version-info) + prev=vinfo + continue + ;; + + # Some other compiler flag. + -* | +*) + # Unknown arguments in both finalize_command and compile_command need + # to be aesthetically quoted because they are evaled later. + arg=`$echo "X$arg" | $Xsed -e "$sed_quote_subst"` + case "$arg" in + *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*) + arg="\"$arg\"" + ;; + esac + ;; + + *.o | *.obj | *.a | *.lib) + # A standard object. + objs="$objs $arg" + ;; + + *.lo) + # A library object. + if test "$prev" = dlfiles; then + dlfiles="$dlfiles $arg" + if test "$build_libtool_libs" = yes && test "$dlopen" = yes; then + prev= + continue + else + # If libtool objects are unsupported, then we need to preload. + prev=dlprefiles + fi + fi + + if test "$prev" = dlprefiles; then + # Preload the old-style object. + dlprefiles="$dlprefiles "`$echo "X$arg" | $Xsed -e "$lo2o"` + prev= + fi + libobjs="$libobjs $arg" + ;; + + *.la) + # A libtool-controlled library. + + dlname= + libdir= + library_names= + old_library= + + # Check to see that this really is a libtool archive. + if (sed -e '2q' $arg | egrep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then : + else + $echo "$modename: \`$arg' is not a valid libtool archive" 1>&2 + exit 1 + fi + + # If the library was installed with an old release of libtool, + # it will not redefine variable installed. + installed=yes + + # Read the .la file + # If there is no directory component, then add one. + case "$arg" in + */* | *\\*) . $arg ;; + *) . ./$arg ;; + esac + + # Get the name of the library we link against. + linklib= + for l in $old_library $library_names; do + linklib="$l" + done + + if test -z "$linklib"; then + $echo "$modename: cannot find name of link library for \`$arg'" 1>&2 + exit 1 + fi + + # Find the relevant object directory and library name. + name=`$echo "X$arg" | $Xsed -e 's%^.*/%%' -e 's/\.la$//' -e 's/^lib//'` + + if test "X$installed" = Xyes; then + dir="$libdir" + else + dir=`$echo "X$arg" | $Xsed -e 's%/[^/]*$%%'` + if test "X$dir" = "X$arg"; then + dir="$objdir" + else + dir="$dir/$objdir" + fi + fi + + if test -n "$dependency_libs"; then + # Extract -R and -L from dependency_libs + temp_deplibs= + for deplib in $dependency_libs; do + case "$deplib" in + -R*) temp_xrpath=`$echo "X$deplib" | $Xsed -e 's/^-R//'` + case " $rpath $xrpath " in + *" $temp_xrpath "*) ;; + *) xrpath="$xrpath $temp_xrpath";; + esac;; + -L*) case "$compile_command $temp_deplibs " in + *" $deplib "*) ;; + *) temp_deplibs="$temp_deplibs $deplib";; + esac + temp_dir=`$echo "X$deplib" | $Xsed -e 's/^-L//'` + case " $lib_search_path " in + *" $temp_dir "*) ;; + *) lib_search_path="$lib_search_path $temp_dir";; + esac + ;; + *) temp_deplibs="$temp_deplibs $deplib";; + esac + done + dependency_libs="$temp_deplibs" + fi + + if test -z "$libdir"; then + # It is a libtool convenience library, so add in its objects. + convenience="$convenience $dir/$old_library" + old_convenience="$old_convenience $dir/$old_library" + deplibs="$deplibs$dependency_libs" + compile_command="$compile_command $dir/$old_library$dependency_libs" + finalize_command="$finalize_command $dir/$old_library$dependency_libs" + continue + fi + + # This library was specified with -dlopen. + if test "$prev" = dlfiles; then + dlfiles="$dlfiles $arg" + if test -z "$dlname" || test "$dlopen" != yes || test "$build_libtool_libs" = no; then + # If there is no dlname, no dlopen support or we're linking statically, + # we need to preload. + prev=dlprefiles + else + # We should not create a dependency on this library, but we + # may need any libraries it requires. + compile_command="$compile_command$dependency_libs" + finalize_command="$finalize_command$dependency_libs" + prev= + continue + fi + fi + + # The library was specified with -dlpreopen. + if test "$prev" = dlprefiles; then + # Prefer using a static library (so that no silly _DYNAMIC symbols + # are required to link). + if test -n "$old_library"; then + dlprefiles="$dlprefiles $dir/$old_library" + else + dlprefiles="$dlprefiles $dir/$linklib" + fi + prev= + fi + + if test -n "$library_names" && + { test "$prefer_static_libs" = no || test -z "$old_library"; }; then + link_against_libtool_libs="$link_against_libtool_libs $arg" + if test -n "$shlibpath_var"; then + # Make sure the rpath contains only unique directories. + case "$temp_rpath " in + *" $dir "*) ;; + *) temp_rpath="$temp_rpath $dir" ;; + esac + fi + + # We need an absolute path. + case "$dir" in + [\\/] | [A-Za-z]:[\\/]*) absdir="$dir" ;; + *) + absdir=`cd "$dir" && pwd` + if test -z "$absdir"; then + $echo "$modename: warning: cannot determine absolute directory name of \`$dir'" 1>&2 + $echo "$modename: passing it literally to the linker, although it might fail" 1>&2 + absdir="$dir" + fi + ;; + esac + + # This is the magic to use -rpath. + # Skip directories that are in the system default run-time + # search path, unless they have been requested with -R. + case " $sys_lib_dlsearch_path " in + *" $absdir "*) ;; + *) + case "$compile_rpath " in + *" $absdir "*) ;; + *) compile_rpath="$compile_rpath $absdir" + esac + ;; + esac + + case " $sys_lib_dlsearch_path " in + *" $libdir "*) ;; + *) + case "$finalize_rpath " in + *" $libdir "*) ;; + *) finalize_rpath="$finalize_rpath $libdir" + esac + ;; + esac + + lib_linked=yes + case "$hardcode_action" in + immediate | unsupported) + if test "$hardcode_direct" = no; then + compile_command="$compile_command $dir/$linklib" + deplibs="$deplibs $dir/$linklib" + case "$host" in + *-*-cygwin* | *-*-mingw* | *-*-os2*) + dllsearchdir=`cd "$dir" && pwd || echo "$dir"` + if test -n "$dllsearchpath"; then + dllsearchpath="$dllsearchpath:$dllsearchdir" + else + dllsearchpath="$dllsearchdir" + fi + ;; + esac + elif test "$hardcode_minus_L" = no; then + case "$host" in + *-*-sunos*) + compile_shlibpath="$compile_shlibpath$dir:" + ;; + esac + case "$compile_command " in + *" -L$dir "*) ;; + *) compile_command="$compile_command -L$dir";; + esac + compile_command="$compile_command -l$name" + deplibs="$deplibs -L$dir -l$name" + elif test "$hardcode_shlibpath_var" = no; then + case ":$compile_shlibpath:" in + *":$dir:"*) ;; + *) compile_shlibpath="$compile_shlibpath$dir:";; + esac + compile_command="$compile_command -l$name" + deplibs="$deplibs -l$name" + else + lib_linked=no + fi + ;; + + relink) + if test "$hardcode_direct" = yes; then + compile_command="$compile_command $absdir/$linklib" + deplibs="$deplibs $absdir/$linklib" + elif test "$hardcode_minus_L" = yes; then + case "$compile_command " in + *" -L$absdir "*) ;; + *) compile_command="$compile_command -L$absdir";; + esac + compile_command="$compile_command -l$name" + deplibs="$deplibs -L$absdir -l$name" + elif test "$hardcode_shlibpath_var" = yes; then + case ":$compile_shlibpath:" in + *":$absdir:"*) ;; + *) compile_shlibpath="$compile_shlibpath$absdir:";; + esac + compile_command="$compile_command -l$name" + deplibs="$deplibs -l$name" + else + lib_linked=no + fi + ;; + + *) + lib_linked=no + ;; + esac + + if test "$lib_linked" != yes; then + $echo "$modename: configuration error: unsupported hardcode properties" + exit 1 + fi + + # Finalize command for both is simple: just hardcode it. + if test "$hardcode_direct" = yes; then + finalize_command="$finalize_command $libdir/$linklib" + elif test "$hardcode_minus_L" = yes; then + case "$finalize_command " in + *" -L$libdir "*) ;; + *) finalize_command="$finalize_command -L$libdir";; + esac + finalize_command="$finalize_command -l$name" + elif test "$hardcode_shlibpath_var" = yes; then + case ":$finalize_shlibpath:" in + *":$libdir:"*) ;; + *) finalize_shlibpath="$finalize_shlibpath$libdir:";; + esac + finalize_command="$finalize_command -l$name" + else + # We cannot seem to hardcode it, guess we'll fake it. + case "$finalize_command " in + *" -L$dir "*) ;; + *) finalize_command="$finalize_command -L$libdir";; + esac + finalize_command="$finalize_command -l$name" + fi + else + # Transform directly to old archives if we don't build new libraries. + if test -n "$pic_flag" && test -z "$old_library"; then + $echo "$modename: cannot find static library for \`$arg'" 1>&2 + exit 1 + fi + + # Here we assume that one of hardcode_direct or hardcode_minus_L + # is not unsupported. This is valid on all known static and + # shared platforms. + if test "$hardcode_direct" != unsupported; then + test -n "$old_library" && linklib="$old_library" + compile_command="$compile_command $dir/$linklib" + finalize_command="$finalize_command $dir/$linklib" + else + case "$compile_command " in + *" -L$dir "*) ;; + *) compile_command="$compile_command -L$dir";; + esac + compile_command="$compile_command -l$name" + case "$finalize_command " in + *" -L$dir "*) ;; + *) finalize_command="$finalize_command -L$dir";; + esac + finalize_command="$finalize_command -l$name" + fi + fi + + # Add in any libraries that this one depends upon. + compile_command="$compile_command$dependency_libs" + finalize_command="$finalize_command$dependency_libs" + continue + ;; + + # Some other compiler argument. + *) + # Unknown arguments in both finalize_command and compile_command need + # to be aesthetically quoted because they are evaled later. + arg=`$echo "X$arg" | $Xsed -e "$sed_quote_subst"` + case "$arg" in + *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*) + arg="\"$arg\"" + ;; + esac + ;; + esac + + # Now actually substitute the argument into the commands. + if test -n "$arg"; then + compile_command="$compile_command $arg" + finalize_command="$finalize_command $arg" + fi + done + + if test -n "$prev"; then + $echo "$modename: the \`$prevarg' option requires an argument" 1>&2 + $echo "$help" 1>&2 + exit 1 + fi + + if test "$export_dynamic" = yes && test -n "$export_dynamic_flag_spec"; then + eval arg=\"$export_dynamic_flag_spec\" + compile_command="$compile_command $arg" + finalize_command="$finalize_command $arg" + fi + + oldlibs= + # calculate the name of the file, without its directory + outputname=`$echo "X$output" | $Xsed -e 's%^.*/%%'` + libobjs_save="$libobjs" + + case "$output" in + "") + $echo "$modename: you must specify an output file" 1>&2 + $echo "$help" 1>&2 + exit 1 + ;; + + *.a | *.lib) + if test -n "$link_against_libtool_libs"; then + $echo "$modename: error: cannot link libtool libraries into archives" 1>&2 + exit 1 + fi + + if test -n "$deplibs"; then + $echo "$modename: warning: \`-l' and \`-L' are ignored for archives" 1>&2 + fi + + if test -n "$dlfiles$dlprefiles" || test "$dlself" != no; then + $echo "$modename: warning: \`-dlopen' is ignored for archives" 1>&2 + fi + + if test -n "$rpath"; then + $echo "$modename: warning: \`-rpath' is ignored for archives" 1>&2 + fi + + if test -n "$xrpath"; then + $echo "$modename: warning: \`-R' is ignored for archives" 1>&2 + fi + + if test -n "$vinfo"; then + $echo "$modename: warning: \`-version-info' is ignored for archives" 1>&2 + fi + + if test -n "$release"; then + $echo "$modename: warning: \`-release' is ignored for archives" 1>&2 + fi + + if test -n "$export_symbols" || test -n "$export_symbols_regex"; then + $echo "$modename: warning: \`-export-symbols' is ignored for archives" 1>&2 + fi + + # Now set the variables for building old libraries. + build_libtool_libs=no + oldlibs="$output" + ;; + + *.la) + # Make sure we only generate libraries of the form `libNAME.la'. + case "$outputname" in + lib*) + name=`$echo "X$outputname" | $Xsed -e 's/\.la$//' -e 's/^lib//'` + eval libname=\"$libname_spec\" + ;; + *) + if test "$module" = no; then + $echo "$modename: libtool library \`$output' must begin with \`lib'" 1>&2 + $echo "$help" 1>&2 + exit 1 + fi + if test "$need_lib_prefix" != no; then + # Add the "lib" prefix for modules if required + name=`$echo "X$outputname" | $Xsed -e 's/\.la$//'` + eval libname=\"$libname_spec\" + else + libname=`$echo "X$outputname" | $Xsed -e 's/\.la$//'` + fi + ;; + esac + + output_objdir=`$echo "X$output" | $Xsed -e 's%/[^/]*$%%'` + if test "X$output_objdir" = "X$output"; then + output_objdir="$objdir" + else + output_objdir="$output_objdir/$objdir" + fi + + if test -n "$objs"; then + $echo "$modename: cannot build libtool library \`$output' from non-libtool objects:$objs" 2>&1 + exit 1 + fi + + # How the heck are we supposed to write a wrapper for a shared library? + if test -n "$link_against_libtool_libs"; then + $echo "$modename: error: cannot link shared libraries into libtool libraries" 1>&2 + exit 1 + fi + + if test -n "$dlfiles$dlprefiles" || test "$dlself" != no; then + $echo "$modename: warning: \`-dlopen' is ignored for libtool libraries" 1>&2 + fi + + set dummy $rpath + if test $# -gt 2; then + $echo "$modename: warning: ignoring multiple \`-rpath's for a libtool library" 1>&2 + fi + install_libdir="$2" + + oldlibs= + if test -z "$rpath"; then + if test "$build_libtool_libs" = yes; then + # Building a libtool convenience library. + libext=al + oldlibs="$output_objdir/$libname.$libext $oldlibs" + build_libtool_libs=convenience + build_old_libs=yes + fi + dependency_libs="$deplibs" + + if test -n "$vinfo"; then + $echo "$modename: warning: \`-version-info' is ignored for convenience libraries" 1>&2 + fi + + if test -n "$release"; then + $echo "$modename: warning: \`-release' is ignored for convenience libraries" 1>&2 + fi + else + + # Parse the version information argument. + IFS="${IFS= }"; save_ifs="$IFS"; IFS=':' + set dummy $vinfo 0 0 0 + IFS="$save_ifs" + + if test -n "$8"; then + $echo "$modename: too many parameters to \`-version-info'" 1>&2 + $echo "$help" 1>&2 + exit 1 + fi + + current="$2" + revision="$3" + age="$4" + + # Check that each of the things are valid numbers. + case "$current" in + 0 | [1-9] | [1-9][0-9]*) ;; + *) + $echo "$modename: CURRENT \`$current' is not a nonnegative integer" 1>&2 + $echo "$modename: \`$vinfo' is not valid version information" 1>&2 + exit 1 + ;; + esac + + case "$revision" in + 0 | [1-9] | [1-9][0-9]*) ;; + *) + $echo "$modename: REVISION \`$revision' is not a nonnegative integer" 1>&2 + $echo "$modename: \`$vinfo' is not valid version information" 1>&2 + exit 1 + ;; + esac + + case "$age" in + 0 | [1-9] | [1-9][0-9]*) ;; + *) + $echo "$modename: AGE \`$age' is not a nonnegative integer" 1>&2 + $echo "$modename: \`$vinfo' is not valid version information" 1>&2 + exit 1 + ;; + esac + + if test $age -gt $current; then + $echo "$modename: AGE \`$age' is greater than the current interface number \`$current'" 1>&2 + $echo "$modename: \`$vinfo' is not valid version information" 1>&2 + exit 1 + fi + + # Calculate the version variables. + major= + versuffix= + verstring= + case "$version_type" in + none) ;; + + irix) + major=`expr $current - $age + 1` + versuffix="$major.$revision" + verstring="sgi$major.$revision" + + # Add in all the interfaces that we are compatible with. + loop=$revision + while test $loop != 0; do + iface=`expr $revision - $loop` + loop=`expr $loop - 1` + verstring="sgi$major.$iface:$verstring" + done + ;; + + linux) + major=.`expr $current - $age` + versuffix="$major.$age.$revision" + ;; + + osf) + major=`expr $current - $age` + versuffix=".$current.$age.$revision" + verstring="$current.$age.$revision" + + # Add in all the interfaces that we are compatible with. + loop=$age + while test $loop != 0; do + iface=`expr $current - $loop` + loop=`expr $loop - 1` + verstring="$verstring:${iface}.0" + done + + # Make executables depend on our current version. + verstring="$verstring:${current}.0" + ;; + + sunos) + major=".$current" + versuffix=".$current.$revision" + ;; + + freebsd-aout) + major=".$current" + versuffix=".$current.$revision"; + ;; + + freebsd-elf) + major=".$current" + versuffix=".$current"; + ;; + + windows) + # Like Linux, but with '-' rather than '.', since we only + # want one extension on Windows 95. + major=`expr $current - $age` + versuffix="-$major-$age-$revision" + ;; + + *) + $echo "$modename: unknown library version type \`$version_type'" 1>&2 + echo "Fatal configuration error. See the $PACKAGE docs for more information." 1>&2 + exit 1 + ;; + esac + + # Clear the version info if we defaulted, and they specified a release. + if test -z "$vinfo" && test -n "$release"; then + major= + verstring="0.0" + if test "$need_version" = no; then + versuffix= + else + versuffix=".0.0" + fi + fi + + # Remove version info from name if versioning should be avoided + if test "$avoid_version" = yes && test "$need_version" = no; then + major= + versuffix= + verstring="" + fi + + # Check to see if the archive will have undefined symbols. + if test "$allow_undefined" = yes; then + if test "$allow_undefined_flag" = unsupported; then + $echo "$modename: warning: undefined symbols not allowed in $host shared libraries" 1>&2 + build_libtool_libs=no + build_old_libs=yes + fi + else + # Don't allow undefined symbols. + allow_undefined_flag="$no_undefined_flag" + fi + + dependency_libs="$deplibs" + case "$host" in + *-*-cygwin* | *-*-mingw* | *-*-os2* | *-*-beos*) + # these systems don't actually have a c library (as such)! + ;; + *) + # Add libc to deplibs on all other systems. + deplibs="$deplibs -lc" + ;; + esac + fi + + # Create the output directory, or remove our outputs if we need to. + if test -d $output_objdir; then + $show "${rm}r $output_objdir/$outputname $output_objdir/$libname.* $output_objdir/${libname}${release}.*" + $run ${rm}r $output_objdir/$outputname $output_objdir/$libname.* $output_objdir/${libname}${release}.* + else + $show "$mkdir $output_objdir" + $run $mkdir $output_objdir + status=$? + if test $status -ne 0 && test ! -d $output_objdir; then + exit $status + fi + fi + + # Now set the variables for building old libraries. + if test "$build_old_libs" = yes && test "$build_libtool_libs" != convenience ; then + oldlibs="$oldlibs $output_objdir/$libname.$libext" + + # Transform .lo files to .o files. + oldobjs="$objs "`$echo "X$libobjs" | $SP2NL | $Xsed -e '/\.'${libext}'$/d' -e "$lo2o" | $NL2SP` + fi + + if test "$build_libtool_libs" = yes; then + # Transform deplibs into only deplibs that can be linked in shared. + name_save=$name + libname_save=$libname + release_save=$release + versuffix_save=$versuffix + major_save=$major + # I'm not sure if I'm treating the release correctly. I think + # release should show up in the -l (ie -lgmp5) so we don't want to + # add it in twice. Is that correct? + release="" + versuffix="" + major="" + newdeplibs= + droppeddeps=no + case "$deplibs_check_method" in + pass_all) + # Don't check for shared/static. Everything works. + # This might be a little naive. We might want to check + # whether the library exists or not. But this is on + # osf3 & osf4 and I'm not really sure... Just + # implementing what was already the behaviour. + newdeplibs=$deplibs + ;; + test_compile) + # This code stresses the "libraries are programs" paradigm to its + # limits. Maybe even breaks it. We compile a program, linking it + # against the deplibs as a proxy for the library. Then we can check + # whether they linked in statically or dynamically with ldd. + $rm conftest.c + cat > conftest.c </dev/null` + for potent_lib in $potential_libs; do + # Follow soft links. + if ls -lLd "$potent_lib" 2>/dev/null \ + | grep " -> " >/dev/null; then + continue + fi + # The statement above tries to avoid entering an + # endless loop below, in case of cyclic links. + # We might still enter an endless loop, since a link + # loop can be closed while we follow links, + # but so what? + potlib="$potent_lib" + while test -h "$potlib" 2>/dev/null; do + potliblink=`ls -ld $potlib | sed 's/.* -> //'` + case "$potliblink" in + [\\/]* | [A-Za-z]:[\\/]*) potlib="$potliblink";; + *) potlib=`$echo "X$potlib" | $Xsed -e 's,[^/]*$,,'`"$potliblink";; + esac + done + if eval $file_magic_cmd \"\$potlib\" 2>/dev/null \ + | sed 10q \ + | egrep "$file_magic_regex" > /dev/null; then + newdeplibs="$newdeplibs $a_deplib" + a_deplib="" + break 2 + fi + done + done + if test -n "$a_deplib" ; then + droppeddeps=yes + echo + echo "*** Warning: This library needs some functionality provided by $a_deplib." + echo "*** I have the capability to make that library automatically link in when" + echo "*** you link to this library. But I can only do this if you have a" + echo "*** shared version of the library, which you do not appear to have." + fi + else + # Add a -L argument. + newdeplibs="$newdeplibs $a_deplib" + fi + done # Gone through all deplibs. + ;; + none | unknown | *) + newdeplibs="" + if $echo "X $deplibs" | $Xsed -e 's/ -lc$//' \ + -e 's/ -[LR][^ ]*//g' -e 's/[ ]//g' | + grep . >/dev/null; then + echo + if test "X$deplibs_check_method" = "Xnone"; then + echo "*** Warning: inter-library dependencies are not supported in this platform." + else + echo "*** Warning: inter-library dependencies are not known to be supported." + fi + echo "*** All declared inter-library dependencies are being dropped." + droppeddeps=yes + fi + ;; + esac + versuffix=$versuffix_save + major=$major_save + release=$release_save + libname=$libname_save + name=$name_save + + if test "$droppeddeps" = yes; then + if test "$module" = yes; then + echo + echo "*** Warning: libtool could not satisfy all declared inter-library" + echo "*** dependencies of module $libname. Therefore, libtool will create" + echo "*** a static module, that should work as long as the dlopening" + echo "*** application is linked with the -dlopen flag." + if test -z "$global_symbol_pipe"; then + echo + echo "*** However, this would only work if libtool was able to extract symbol" + echo "*** lists from a program, using \`nm' or equivalent, but libtool could" + echo "*** not find such a program. So, this module is probably useless." + echo "*** \`nm' from GNU binutils and a full rebuild may help." + fi + if test "$build_old_libs" = no; then + oldlibs="$output_objdir/$libname.$libext" + build_libtool_libs=module + build_old_libs=yes + else + build_libtool_libs=no + fi + else + echo "*** The inter-library dependencies that have been dropped here will be" + echo "*** automatically added whenever a program is linked with this library" + echo "*** or is declared to -dlopen it." + fi + fi + # Done checking deplibs! + deplibs=$newdeplibs + fi + + # All the library-specific variables (install_libdir is set above). + library_names= + old_library= + dlname= + + # Test again, we may have decided not to build it any more + if test "$build_libtool_libs" = yes; then + # Get the real and link names of the library. + eval library_names=\"$library_names_spec\" + set dummy $library_names + realname="$2" + shift; shift + + if test -n "$soname_spec"; then + eval soname=\"$soname_spec\" + else + soname="$realname" + fi + + lib="$output_objdir/$realname" + for link + do + linknames="$linknames $link" + done + + # Ensure that we have .o objects for linkers which dislike .lo + # (e.g. aix) in case we are running --disable-static + for obj in $libobjs; do + xdir=`$echo "X$obj" | $Xsed -e 's%/[^/]*$%%'` + if test "X$xdir" = "X$obj"; then + xdir="." + else + xdir="$xdir" + fi + baseobj=`$echo "X$obj" | $Xsed -e 's%^.*/%%'` + oldobj=`$echo "X$baseobj" | $Xsed -e "$lo2o"` + if test ! -f $xdir/$oldobj; then + $show "(cd $xdir && ${LN_S} $baseobj $oldobj)" + $run eval '(cd $xdir && ${LN_S} $baseobj $oldobj)' || exit $? + fi + done + + # Use standard objects if they are pic + test -z "$pic_flag" && libobjs=`$echo "X$libobjs" | $SP2NL | $Xsed -e "$lo2o" | $NL2SP` + + # Prepare the list of exported symbols + if test -z "$export_symbols"; then + if test "$always_export_symbols" = yes || test -n "$export_symbols_regex"; then + $show "generating symbol list for \`$libname.la'" + export_symbols="$output_objdir/$libname.exp" + $run $rm $export_symbols + eval cmds=\"$export_symbols_cmds\" + IFS="${IFS= }"; save_ifs="$IFS"; IFS='~' + for cmd in $cmds; do + IFS="$save_ifs" + $show "$cmd" + $run eval "$cmd" || exit $? + done + IFS="$save_ifs" + if test -n "$export_symbols_regex"; then + $show "egrep -e \"$export_symbols_regex\" \"$export_symbols\" > \"${export_symbols}T\"" + $run eval 'egrep -e "$export_symbols_regex" "$export_symbols" > "${export_symbols}T"' + $show "$mv \"${export_symbols}T\" \"$export_symbols\"" + $run eval '$mv "${export_symbols}T" "$export_symbols"' + fi + fi + fi + + if test -n "$export_symbols" && test -n "$include_expsyms"; then + $run eval '$echo "X$include_expsyms" | $SP2NL >> "$export_symbols"' + fi + + if test -n "$convenience"; then + if test -n "$whole_archive_flag_spec"; then + eval libobjs=\"\$libobjs $whole_archive_flag_spec\" + else + gentop="$output_objdir/${outputname}x" + $show "${rm}r $gentop" + $run ${rm}r "$gentop" + $show "mkdir $gentop" + $run mkdir "$gentop" + status=$? + if test $status -ne 0 && test ! -d "$gentop"; then + exit $status + fi + generated="$generated $gentop" + + for xlib in $convenience; do + # Extract the objects. + case "$xlib" in + [\\/]* | [A-Za-z]:[\\/]*) xabs="$xlib" ;; + *) xabs=`pwd`"/$xlib" ;; + esac + xlib=`$echo "X$xlib" | $Xsed -e 's%^.*/%%'` + xdir="$gentop/$xlib" + + $show "${rm}r $xdir" + $run ${rm}r "$xdir" + $show "mkdir $xdir" + $run mkdir "$xdir" + status=$? + if test $status -ne 0 && test ! -d "$xdir"; then + exit $status + fi + $show "(cd $xdir && $AR x $xabs)" + $run eval "(cd \$xdir && $AR x \$xabs)" || exit $? + + libobjs="$libobjs "`find $xdir -name \*.o -print -o -name \*.lo -print | $NL2SP` + done + fi + fi + + if test "$thread_safe" = yes && test -n "$thread_safe_flag_spec"; then + eval flag=\"$thread_safe_flag_spec\" + linkopts="$linkopts $flag" + fi + + # Do each of the archive commands. + if test -n "$export_symbols" && test -n "$archive_expsym_cmds"; then + eval cmds=\"$archive_expsym_cmds\" + else + eval cmds=\"$archive_cmds\" + fi + IFS="${IFS= }"; save_ifs="$IFS"; IFS='~' + for cmd in $cmds; do + IFS="$save_ifs" + $show "$cmd" + $run eval "$cmd" || exit $? + done + IFS="$save_ifs" + + # Create links to the real library. + for linkname in $linknames; do + if test "$realname" != "$linkname"; then + $show "(cd $output_objdir && $rm $linkname && $LN_S $realname $linkname)" + $run eval '(cd $output_objdir && $rm $linkname && $LN_S $realname $linkname)' || exit $? + fi + done + + # If -module or -export-dynamic was specified, set the dlname. + if test "$module" = yes || test "$export_dynamic" = yes; then + # On all known operating systems, these are identical. + dlname="$soname" + fi + fi + ;; + + *.lo | *.o | *.obj) + if test -n "$link_against_libtool_libs"; then + $echo "$modename: error: cannot link libtool libraries into objects" 1>&2 + exit 1 + fi + + if test -n "$deplibs"; then + $echo "$modename: warning: \`-l' and \`-L' are ignored for objects" 1>&2 + fi + + if test -n "$dlfiles$dlprefiles" || test "$dlself" != no; then + $echo "$modename: warning: \`-dlopen' is ignored for objects" 1>&2 + fi + + if test -n "$rpath"; then + $echo "$modename: warning: \`-rpath' is ignored for objects" 1>&2 + fi + + if test -n "$xrpath"; then + $echo "$modename: warning: \`-R' is ignored for objects" 1>&2 + fi + + if test -n "$vinfo"; then + $echo "$modename: warning: \`-version-info' is ignored for objects" 1>&2 + fi + + if test -n "$release"; then + $echo "$modename: warning: \`-release' is ignored for objects" 1>&2 + fi + + case "$output" in + *.lo) + if test -n "$objs"; then + $echo "$modename: cannot build library object \`$output' from non-libtool objects" 1>&2 + exit 1 + fi + libobj="$output" + obj=`$echo "X$output" | $Xsed -e "$lo2o"` + ;; + *) + libobj= + obj="$output" + ;; + esac + + # Delete the old objects. + $run $rm $obj $libobj + + # Objects from convenience libraries. This assumes + # single-version convenience libraries. Whenever we create + # different ones for PIC/non-PIC, this we'll have to duplicate + # the extraction. + reload_conv_objs= + gentop= + # reload_cmds runs $LD directly, so let us get rid of + # -Wl from whole_archive_flag_spec + wl= + + if test -n "$convenience"; then + if test -n "$whole_archive_flag_spec"; then + eval reload_conv_objs=\"\$reload_objs $whole_archive_flag_spec\" + else + gentop="$output_objdir/${obj}x" + $show "${rm}r $gentop" + $run ${rm}r "$gentop" + $show "mkdir $gentop" + $run mkdir "$gentop" + status=$? + if test $status -ne 0 && test ! -d "$gentop"; then + exit $status + fi + generated="$generated $gentop" + + for xlib in $convenience; do + # Extract the objects. + case "$xlib" in + [\\/]* | [A-Za-z]:[\\/]*) xabs="$xlib" ;; + *) xabs=`pwd`"/$xlib" ;; + esac + xlib=`$echo "X$xlib" | $Xsed -e 's%^.*/%%'` + xdir="$gentop/$xlib" + + $show "${rm}r $xdir" + $run ${rm}r "$xdir" + $show "mkdir $xdir" + $run mkdir "$xdir" + status=$? + if test $status -ne 0 && test ! -d "$xdir"; then + exit $status + fi + $show "(cd $xdir && $AR x $xabs)" + $run eval "(cd \$xdir && $AR x \$xabs)" || exit $? + + reload_conv_objs="$reload_objs "`find $xdir -name \*.o -print -o -name \*.lo -print | $NL2SP` + done + fi + fi + + # Create the old-style object. + reload_objs="$objs "`$echo "X$libobjs" | $SP2NL | $Xsed -e '/\.'${libext}$'/d' -e '/\.lib$/d' -e "$lo2o" | $NL2SP`" $reload_conv_objs" + + output="$obj" + eval cmds=\"$reload_cmds\" + IFS="${IFS= }"; save_ifs="$IFS"; IFS='~' + for cmd in $cmds; do + IFS="$save_ifs" + $show "$cmd" + $run eval "$cmd" || exit $? + done + IFS="$save_ifs" + + # Exit if we aren't doing a library object file. + if test -z "$libobj"; then + if test -n "$gentop"; then + $show "${rm}r $gentop" + $run ${rm}r $gentop + fi + + exit 0 + fi + + if test "$build_libtool_libs" != yes; then + if test -n "$gentop"; then + $show "${rm}r $gentop" + $run ${rm}r $gentop + fi + + # Create an invalid libtool object if no PIC, so that we don't + # accidentally link it into a program. + $show "echo timestamp > $libobj" + $run eval "echo timestamp > $libobj" || exit $? + exit 0 + fi + + if test -n "$pic_flag"; then + # Only do commands if we really have different PIC objects. + reload_objs="$libobjs $reload_conv_objs" + output="$libobj" + eval cmds=\"$reload_cmds\" + IFS="${IFS= }"; save_ifs="$IFS"; IFS='~' + for cmd in $cmds; do + IFS="$save_ifs" + $show "$cmd" + $run eval "$cmd" || exit $? + done + IFS="$save_ifs" + else + # Just create a symlink. + $show $rm $libobj + $run $rm $libobj + xdir=`$echo "X$libobj" | $Xsed -e 's%/[^/]*$%%'` + if test "X$xdir" = "X$libobj"; then + xdir="." + else + xdir="$xdir" + fi + baseobj=`$echo "X$libobj" | $Xsed -e 's%^.*/%%'` + oldobj=`$echo "X$baseobj" | $Xsed -e "$lo2o"` + $show "(cd $xdir && $LN_S $oldobj $baseobj)" + $run eval '(cd $xdir && $LN_S $oldobj $baseobj)' || exit $? + fi + + if test -n "$gentop"; then + $show "${rm}r $gentop" + $run ${rm}r $gentop + fi + + exit 0 + ;; + + # Anything else should be a program. + *) + if test -n "$vinfo"; then + $echo "$modename: warning: \`-version-info' is ignored for programs" 1>&2 + fi + + if test -n "$release"; then + $echo "$modename: warning: \`-release' is ignored for programs" 1>&2 + fi + + if test "$preload" = yes; then + if test "$dlopen" = unknown && test "$dlopen_self" = unknown && + test "$dlopen_self_static" = unknown; then + $echo "$modename: warning: \`AC_LIBTOOL_DLOPEN' not used. Assuming no dlopen support." + fi + fi + + if test -n "$rpath$xrpath"; then + # If the user specified any rpath flags, then add them. + for libdir in $rpath $xrpath; do + # This is the magic to use -rpath. + case "$compile_rpath " in + *" $libdir "*) ;; + *) compile_rpath="$compile_rpath $libdir" ;; + esac + case "$finalize_rpath " in + *" $libdir "*) ;; + *) finalize_rpath="$finalize_rpath $libdir" ;; + esac + done + fi + + # Now hardcode the library paths + rpath= + hardcode_libdirs= + for libdir in $compile_rpath $finalize_rpath; do + if test -n "$hardcode_libdir_flag_spec"; then + if test -n "$hardcode_libdir_separator"; then + if test -z "$hardcode_libdirs"; then + hardcode_libdirs="$libdir" + else + # Just accumulate the unique libdirs. + case "$hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator" in + *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*) + ;; + *) + hardcode_libdirs="$hardcode_libdirs$hardcode_libdir_separator$libdir" + ;; + esac + fi + else + eval flag=\"$hardcode_libdir_flag_spec\" + rpath="$rpath $flag" + fi + elif test -n "$runpath_var"; then + case "$perm_rpath " in + *" $libdir "*) ;; + *) perm_rpath="$perm_rpath $libdir" ;; + esac + fi + done + # Substitute the hardcoded libdirs into the rpath. + if test -n "$hardcode_libdir_separator" && + test -n "$hardcode_libdirs"; then + libdir="$hardcode_libdirs" + eval rpath=\" $hardcode_libdir_flag_spec\" + fi + compile_rpath="$rpath" + + rpath= + hardcode_libdirs= + for libdir in $finalize_rpath; do + if test -n "$hardcode_libdir_flag_spec"; then + if test -n "$hardcode_libdir_separator"; then + if test -z "$hardcode_libdirs"; then + hardcode_libdirs="$libdir" + else + # Just accumulate the unique libdirs. + case "$hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator" in + *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*) + ;; + *) + hardcode_libdirs="$hardcode_libdirs$hardcode_libdir_separator$libdir" + ;; + esac + fi + else + eval flag=\"$hardcode_libdir_flag_spec\" + rpath="$rpath $flag" + fi + elif test -n "$runpath_var"; then + case "$finalize_perm_rpath " in + *" $libdir "*) ;; + *) finalize_perm_rpath="$finalize_perm_rpath $libdir" ;; + esac + fi + done + # Substitute the hardcoded libdirs into the rpath. + if test -n "$hardcode_libdir_separator" && + test -n "$hardcode_libdirs"; then + libdir="$hardcode_libdirs" + eval rpath=\" $hardcode_libdir_flag_spec\" + fi + finalize_rpath="$rpath" + + output_objdir=`$echo "X$output" | $Xsed -e 's%/[^/]*$%%'` + if test "X$output_objdir" = "X$output"; then + output_objdir="$objdir" + else + output_objdir="$output_objdir/$objdir" + fi + + # Create the binary in the object directory, then wrap it. + if test ! -d $output_objdir; then + $show "$mkdir $output_objdir" + $run $mkdir $output_objdir + status=$? + if test $status -ne 0 && test ! -d $output_objdir; then + exit $status + fi + fi + + if test -n "$libobjs" && test "$build_old_libs" = yes; then + # Transform all the library objects into standard objects. + compile_command=`$echo "X$compile_command" | $SP2NL | $Xsed -e "$lo2o" | $NL2SP` + finalize_command=`$echo "X$finalize_command" | $SP2NL | $Xsed -e "$lo2o" | $NL2SP` + fi + + dlsyms= + if test -n "$dlfiles$dlprefiles" || test "$dlself" != no; then + if test -n "$NM" && test -n "$global_symbol_pipe"; then + dlsyms="${outputname}S.c" + else + $echo "$modename: not configured to extract global symbols from dlpreopened files" 1>&2 + fi + fi + + if test -n "$dlsyms"; then + case "$dlsyms" in + "") ;; + *.c) + # Discover the nlist of each of the dlfiles. + nlist="$output_objdir/${outputname}.nm" + + $show "$rm $nlist ${nlist}S ${nlist}T" + $run $rm "$nlist" "${nlist}S" "${nlist}T" + + # Parse the name list into a source file. + $show "creating $output_objdir/$dlsyms" + + test -z "$run" && $echo > "$output_objdir/$dlsyms" "\ +/* $dlsyms - symbol resolution table for \`$outputname' dlsym emulation. */ +/* Generated by $PROGRAM - GNU $PACKAGE $VERSION$TIMESTAMP */ + +#ifdef __cplusplus +extern \"C\" { +#endif + +/* Prevent the only kind of declaration conflicts we can make. */ +#define lt_preloaded_symbols some_other_symbol + +/* External symbol declarations for the compiler. */\ +" + + if test "$dlself" = yes; then + $show "generating symbol list for \`$output'" + + test -z "$run" && $echo ': @PROGRAM@ ' > "$nlist" + + # Add our own program objects to the symbol list. + progfiles=`$echo "X$objs" | $SP2NL | $Xsed -e "$lo2o" | $NL2SP` + for arg in $progfiles; do + $show "extracting global C symbols from \`$arg'" + $run eval "$NM $arg | $global_symbol_pipe >> '$nlist'" + done + + if test -n "$exclude_expsyms"; then + $run eval 'egrep -v " ($exclude_expsyms)$" "$nlist" > "$nlist"T' + $run eval '$mv "$nlist"T "$nlist"' + fi + + if test -n "$export_symbols_regex"; then + $run eval 'egrep -e "$export_symbols_regex" "$nlist" > "$nlist"T' + $run eval '$mv "$nlist"T "$nlist"' + fi + + # Prepare the list of exported symbols + if test -z "$export_symbols"; then + export_symbols="$output_objdir/$output.exp" + $run $rm $export_symbols + $run eval "sed -n -e '/^: @PROGRAM@$/d' -e 's/^.* \(.*\)$/\1/p' "'< "$nlist" > "$export_symbols"' + else + $run eval "sed -e 's/\([][.*^$]\)/\\\1/g' -e 's/^/ /' -e 's/$/$/'"' < "$export_symbols" > "$output_objdir/$output.exp"' + $run eval 'grep -f "$output_objdir/$output.exp" < "$nlist" > "$nlist"T' + $run eval 'mv "$nlist"T "$nlist"' + fi + fi + + for arg in $dlprefiles; do + $show "extracting global C symbols from \`$arg'" + name=`echo "$arg" | sed -e 's%^.*/%%'` + $run eval 'echo ": $name " >> "$nlist"' + $run eval "$NM $arg | $global_symbol_pipe >> '$nlist'" + done + + if test -z "$run"; then + # Make sure we have at least an empty file. + test -f "$nlist" || : > "$nlist" + + if test -n "$exclude_expsyms"; then + egrep -v " ($exclude_expsyms)$" "$nlist" > "$nlist"T + $mv "$nlist"T "$nlist" + fi + + # Try sorting and uniquifying the output. + if grep -v "^: " < "$nlist" | sort +2 | uniq > "$nlist"S; then + : + else + grep -v "^: " < "$nlist" > "$nlist"S + fi + + if test -f "$nlist"S; then + eval "$global_symbol_to_cdecl"' < "$nlist"S >> "$output_objdir/$dlsyms"' + else + echo '/* NONE */' >> "$output_objdir/$dlsyms" + fi + + $echo >> "$output_objdir/$dlsyms" "\ + +#undef lt_preloaded_symbols + +#if defined (__STDC__) && __STDC__ +# define lt_ptr_t void * +#else +# define lt_ptr_t char * +# define const +#endif + +/* The mapping between symbol names and symbols. */ +const struct { + const char *name; + lt_ptr_t address; +} +lt_preloaded_symbols[] = +{\ +" + + sed -n -e 's/^: \([^ ]*\) $/ {\"\1\", (lt_ptr_t) 0},/p' \ + -e 's/^. \([^ ]*\) \([^ ]*\)$/ {"\2", (lt_ptr_t) \&\2},/p' \ + < "$nlist" >> "$output_objdir/$dlsyms" + + $echo >> "$output_objdir/$dlsyms" "\ + {0, (lt_ptr_t) 0} +}; + +/* This works around a problem in FreeBSD linker */ +#ifdef FREEBSD_WORKAROUND +static const void *lt_preloaded_setup() { + return lt_preloaded_symbols; +} +#endif + +#ifdef __cplusplus +} +#endif\ +" + fi + + pic_flag_for_symtable= + case "$host" in + # compiling the symbol table file with pic_flag works around + # a FreeBSD bug that causes programs to crash when -lm is + # linked before any other PIC object. But we must not use + # pic_flag when linking with -static. The problem exists in + # FreeBSD 2.2.6 and is fixed in FreeBSD 3.1. + *-*-freebsd2*|*-*-freebsd3.0*|*-*-freebsdelf3.0*) + case "$compile_command " in + *" -static "*) ;; + *) pic_flag_for_symtable=" $pic_flag -DPIC -DFREEBSD_WORKAROUND";; + esac;; + *-*-hpux*) + case "$compile_command " in + *" -static "*) ;; + *) pic_flag_for_symtable=" $pic_flag -DPIC";; + esac + esac + + # Now compile the dynamic symbol file. + $show "(cd $output_objdir && $CC -c$no_builtin_flag$pic_flag_for_symtable \"$dlsyms\")" + $run eval '(cd $output_objdir && $CC -c$no_builtin_flag$pic_flag_for_symtable "$dlsyms")' || exit $? + + # Clean up the generated files. + $show "$rm $output_objdir/$dlsyms $nlist ${nlist}S ${nlist}T" + $run $rm "$output_objdir/$dlsyms" "$nlist" "${nlist}S" "${nlist}T" + + # Transform the symbol file into the correct name. + compile_command=`$echo "X$compile_command" | $Xsed -e "s%@SYMFILE@%$output_objdir/${outputname}S.${objext}%"` + finalize_command=`$echo "X$finalize_command" | $Xsed -e "s%@SYMFILE@%$output_objdir/${outputname}S.${objext}%"` + ;; + *) + $echo "$modename: unknown suffix for \`$dlsyms'" 1>&2 + exit 1 + ;; + esac + else + # We keep going just in case the user didn't refer to + # lt_preloaded_symbols. The linker will fail if global_symbol_pipe + # really was required. + + # Nullify the symbol file. + compile_command=`$echo "X$compile_command" | $Xsed -e "s% @SYMFILE@%%"` + finalize_command=`$echo "X$finalize_command" | $Xsed -e "s% @SYMFILE@%%"` + fi + + if test -z "$link_against_libtool_libs" || test "$build_libtool_libs" != yes; then + # Replace the output file specification. + compile_command=`$echo "X$compile_command" | $Xsed -e 's%@OUTPUT@%'"$output"'%g'` + link_command="$compile_command$compile_rpath" + + # We have no uninstalled library dependencies, so finalize right now. + $show "$link_command" + $run eval "$link_command" + status=$? + + # Delete the generated files. + if test -n "$dlsyms"; then + $show "$rm $output_objdir/${outputname}S.${objext}" + $run $rm "$output_objdir/${outputname}S.${objext}" + fi + + exit $status + fi + + if test -n "$shlibpath_var"; then + # We should set the shlibpath_var + rpath= + for dir in $temp_rpath; do + case "$dir" in + [\\/]* | [A-Za-z]:[\\/]*) + # Absolute path. + rpath="$rpath$dir:" + ;; + *) + # Relative path: add a thisdir entry. + rpath="$rpath\$thisdir/$dir:" + ;; + esac + done + temp_rpath="$rpath" + fi + + if test -n "$compile_shlibpath$finalize_shlibpath"; then + compile_command="$shlibpath_var=\"$compile_shlibpath$finalize_shlibpath\$$shlibpath_var\" $compile_command" + fi + if test -n "$finalize_shlibpath"; then + finalize_command="$shlibpath_var=\"$finalize_shlibpath\$$shlibpath_var\" $finalize_command" + fi + + compile_var= + finalize_var= + if test -n "$runpath_var"; then + if test -n "$perm_rpath"; then + # We should set the runpath_var. + rpath= + for dir in $perm_rpath; do + rpath="$rpath$dir:" + done + compile_var="$runpath_var=\"$rpath\$$runpath_var\" " + fi + if test -n "$finalize_perm_rpath"; then + # We should set the runpath_var. + rpath= + for dir in $finalize_perm_rpath; do + rpath="$rpath$dir:" + done + finalize_var="$runpath_var=\"$rpath\$$runpath_var\" " + fi + fi + + if test "$hardcode_action" = relink; then + # Fast installation is not supported + link_command="$compile_var$compile_command$compile_rpath" + relink_command="$finalize_var$finalize_command$finalize_rpath" + + $echo "$modename: warning: this platform does not like uninstalled shared libraries" 1>&2 + $echo "$modename: \`$output' will be relinked during installation" 1>&2 + else + if test "$fast_install" != no; then + link_command="$finalize_var$compile_command$finalize_rpath" + if test "$fast_install" = yes; then + relink_command=`$echo "X$compile_var$compile_command$compile_rpath" | $Xsed -e 's%@OUTPUT@%\$progdir/\$file%g'` + else + # fast_install is set to needless + relink_command= + fi + else + link_command="$compile_var$compile_command$compile_rpath" + relink_command="$finalize_var$finalize_command$finalize_rpath" + fi + fi + + # Replace the output file specification. + link_command=`$echo "X$link_command" | $Xsed -e 's%@OUTPUT@%'"$output_objdir/$outputname"'%g'` + + # Delete the old output files. + $run $rm $output $output_objdir/$outputname $output_objdir/lt-$outputname + + $show "$link_command" + $run eval "$link_command" || exit $? + + # Now create the wrapper script. + $show "creating $output" + + # Quote the relink command for shipping. + if test -n "$relink_command"; then + relink_command=`$echo "X$relink_command" | $Xsed -e "$sed_quote_subst"` + fi + + # Quote $echo for shipping. + if test "X$echo" = "X$SHELL $0 --fallback-echo"; then + case "$0" in + [\\/]* | [A-Za-z]:[\\/]*) qecho="$SHELL $0 --fallback-echo";; + *) qecho="$SHELL `pwd`/$0 --fallback-echo";; + esac + qecho=`$echo "X$qecho" | $Xsed -e "$sed_quote_subst"` + else + qecho=`$echo "X$echo" | $Xsed -e "$sed_quote_subst"` + fi + + # Only actually do things if our run command is non-null. + if test -z "$run"; then + # win32 will think the script is a binary if it has + # a .exe suffix, so we strip it off here. + case $output in + *.exe) output=`echo $output|sed 's,.exe$,,'` ;; + esac + $rm $output + trap "$rm $output; exit 1" 1 2 15 + + $echo > $output "\ +#! $SHELL + +# $output - temporary wrapper script for $objdir/$outputname +# Generated by $PROGRAM - GNU $PACKAGE $VERSION$TIMESTAMP +# +# The $output program cannot be directly executed until all the libtool +# libraries that it depends on are installed. +# +# This wrapper script should never be moved out of the build directory. +# If it is, it will not operate correctly. + +# Sed substitution that helps us do robust quoting. It backslashifies +# metacharacters that are still active within double-quoted strings. +Xsed='sed -e 1s/^X//' +sed_quote_subst='$sed_quote_subst' + +# The HP-UX ksh and POSIX shell print the target directory to stdout +# if CDPATH is set. +if test \"\${CDPATH+set}\" = set; then CDPATH=:; export CDPATH; fi + +relink_command=\"$relink_command\" + +# This environment variable determines our operation mode. +if test \"\$libtool_install_magic\" = \"$magic\"; then + # install mode needs the following variable: + link_against_libtool_libs='$link_against_libtool_libs' +else + # When we are sourced in execute mode, \$file and \$echo are already set. + if test \"\$libtool_execute_magic\" != \"$magic\"; then + echo=\"$qecho\" + file=\"\$0\" + # Make sure echo works. + if test \"X\$1\" = X--no-reexec; then + # Discard the --no-reexec flag, and continue. + shift + elif test \"X\`(\$echo '\t') 2>/dev/null\`\" = 'X\t'; then + # Yippee, \$echo works! + : + else + # Restart under the correct shell, and then maybe \$echo will work. + exec $SHELL \"\$0\" --no-reexec \${1+\"\$@\"} + fi + fi\ +" + $echo >> $output "\ + + # Find the directory that this script lives in. + thisdir=\`\$echo \"X\$file\" | \$Xsed -e 's%/[^/]*$%%'\` + test \"x\$thisdir\" = \"x\$file\" && thisdir=. + + # Follow symbolic links until we get to the real thisdir. + file=\`ls -ld \"\$file\" | sed -n 's/.*-> //p'\` + while test -n \"\$file\"; do + destdir=\`\$echo \"X\$file\" | \$Xsed -e 's%/[^/]*\$%%'\` + + # If there was a directory component, then change thisdir. + if test \"x\$destdir\" != \"x\$file\"; then + case \"\$destdir\" in + [\\/]* | [A-Za-z]:[\\/]*) thisdir=\"\$destdir\" ;; + *) thisdir=\"\$thisdir/\$destdir\" ;; + esac + fi + + file=\`\$echo \"X\$file\" | \$Xsed -e 's%^.*/%%'\` + file=\`ls -ld \"\$thisdir/\$file\" | sed -n 's/.*-> //p'\` + done + + # Try to get the absolute directory name. + absdir=\`cd \"\$thisdir\" && pwd\` + test -n \"\$absdir\" && thisdir=\"\$absdir\" +" + + if test "$fast_install" = yes; then + echo >> $output "\ + program=lt-'$outputname' + progdir=\"\$thisdir/$objdir\" + + if test ! -f \"\$progdir/\$program\" || \\ + { file=\`ls -1dt \"\$progdir/\$program\" \"\$progdir/../\$program\" 2>/dev/null | sed 1q\`; \\ + test \"X\$file\" != \"X\$progdir/\$program\"; }; then + + file=\"\$\$-\$program\" + + if test ! -d \"\$progdir\"; then + $mkdir \"\$progdir\" + else + $rm \"\$progdir/\$file\" + fi" + + echo >> $output "\ + + # relink executable if necessary + if test -n \"\$relink_command\"; then + if (cd \"\$thisdir\" && eval \$relink_command); then : + else + $rm \"\$progdir/\$file\" + exit 1 + fi + fi + + $mv \"\$progdir/\$file\" \"\$progdir/\$program\" 2>/dev/null || + { $rm \"\$progdir/\$program\"; + $mv \"\$progdir/\$file\" \"\$progdir/\$program\"; } + $rm \"\$progdir/\$file\" + fi" + else + echo >> $output "\ + program='$outputname' + progdir=\"\$thisdir/$objdir\" +" + fi + + echo >> $output "\ + + if test -f \"\$progdir/\$program\"; then" + + # Export our shlibpath_var if we have one. + if test "$shlibpath_overrides_runpath" = yes && test -n "$shlibpath_var" && test -n "$temp_rpath"; then + $echo >> $output "\ + # Add our own library path to $shlibpath_var + $shlibpath_var=\"$temp_rpath\$$shlibpath_var\" + + # Some systems cannot cope with colon-terminated $shlibpath_var + # The second colon is a workaround for a bug in BeOS R4 sed + $shlibpath_var=\`\$echo \"X\$$shlibpath_var\" | \$Xsed -e 's/::*\$//'\` + + export $shlibpath_var +" + fi + + # fixup the dll searchpath if we need to. + if test -n "$dllsearchpath"; then + $echo >> $output "\ + # Add the dll search path components to the executable PATH + PATH=$dllsearchpath:\$PATH +" + fi + + $echo >> $output "\ + if test \"\$libtool_execute_magic\" != \"$magic\"; then + # Run the actual program with our arguments. +" + case $host in + *-*-cygwin* | *-*-mingw | *-*-os2*) + # win32 systems need to use the prog path for dll + # lookup to work + $echo >> $output "\ + exec \$progdir\\\\\$program \${1+\"\$@\"} +" + ;; + *) + $echo >> $output "\ + # Export the path to the program. + PATH=\"\$progdir:\$PATH\" + export PATH + + exec \$program \${1+\"\$@\"} +" + ;; + esac + $echo >> $output "\ + \$echo \"\$0: cannot exec \$program \${1+\"\$@\"}\" + exit 1 + fi + else + # The program doesn't exist. + \$echo \"\$0: error: \$progdir/\$program does not exist\" 1>&2 + \$echo \"This script is just a wrapper for \$program.\" 1>&2 + echo \"See the $PACKAGE documentation for more information.\" 1>&2 + exit 1 + fi +fi\ +" + chmod +x $output + fi + exit 0 + ;; + esac + + # See if we need to build an old-fashioned archive. + for oldlib in $oldlibs; do + + if test "$build_libtool_libs" = convenience; then + oldobjs="$libobjs_save" + addlibs="$convenience" + build_libtool_libs=no + else + if test "$build_libtool_libs" = module; then + oldobjs="$libobjs_save" + build_libtool_libs=no + else + oldobjs="$objs "`$echo "X$libobjs_save" | $SP2NL | $Xsed -e '/\.'${libext}'$/d' -e '/\.lib$/d' -e "$lo2o" | $NL2SP` + fi + addlibs="$old_convenience" + fi + + if test -n "$addlibs"; then + gentop="$output_objdir/${outputname}x" + $show "${rm}r $gentop" + $run ${rm}r "$gentop" + $show "mkdir $gentop" + $run mkdir "$gentop" + status=$? + if test $status -ne 0 && test ! -d "$gentop"; then + exit $status + fi + generated="$generated $gentop" + + # Add in members from convenience archives. + for xlib in $addlibs; do + # Extract the objects. + case "$xlib" in + [\\/]* | [A-Za-z]:[\\/]*) xabs="$xlib" ;; + *) xabs=`pwd`"/$xlib" ;; + esac + xlib=`$echo "X$xlib" | $Xsed -e 's%^.*/%%'` + xdir="$gentop/$xlib" + + $show "${rm}r $xdir" + $run ${rm}r "$xdir" + $show "mkdir $xdir" + $run mkdir "$xdir" + status=$? + if test $status -ne 0 && test ! -d "$xdir"; then + exit $status + fi + $show "(cd $xdir && $AR x $xabs)" + $run eval "(cd \$xdir && $AR x \$xabs)" || exit $? + + oldobjs="$oldobjs "`find $xdir -name \*.${objext} -print -o -name \*.lo -print | $NL2SP` + done + fi + + # Do each command in the archive commands. + if test -n "$old_archive_from_new_cmds" && test "$build_libtool_libs" = yes; then + eval cmds=\"$old_archive_from_new_cmds\" + else + # Ensure that we have .o objects in place in case we decided + # not to build a shared library, and have fallen back to building + # static libs even though --disable-static was passed! + for oldobj in $oldobjs; do + if test ! -f $oldobj; then + xdir=`$echo "X$oldobj" | $Xsed -e 's%/[^/]*$%%'` + if test "X$xdir" = "X$oldobj"; then + xdir="." + else + xdir="$xdir" + fi + baseobj=`$echo "X$oldobj" | $Xsed -e 's%^.*/%%'` + obj=`$echo "X$baseobj" | $Xsed -e "$o2lo"` + $show "(cd $xdir && ${LN_S} $obj $baseobj)" + $run eval '(cd $xdir && ${LN_S} $obj $baseobj)' || exit $? + fi + done + + eval cmds=\"$old_archive_cmds\" + fi + IFS="${IFS= }"; save_ifs="$IFS"; IFS='~' + for cmd in $cmds; do + IFS="$save_ifs" + $show "$cmd" + $run eval "$cmd" || exit $? + done + IFS="$save_ifs" + done + + if test -n "$generated"; then + $show "${rm}r$generated" + $run ${rm}r$generated + fi + + # Now create the libtool archive. + case "$output" in + *.la) + old_library= + test "$build_old_libs" = yes && old_library="$libname.$libext" + $show "creating $output" + + if test -n "$xrpath"; then + temp_xrpath= + for libdir in $xrpath; do + temp_xrpath="$temp_xrpath -R$libdir" + done + dependency_libs="$temp_xrpath $dependency_libs" + fi + + # Only create the output if not a dry run. + if test -z "$run"; then + for installed in no yes; do + if test "$installed" = yes; then + if test -z "$install_libdir"; then + break + fi + output="$output_objdir/$outputname"i + fi + $rm $output + $echo > $output "\ +# $outputname - a libtool library file +# Generated by $PROGRAM - GNU $PACKAGE $VERSION$TIMESTAMP +# +# Please DO NOT delete this file! +# It is necessary for linking the library. + +# The name that we can dlopen(3). +dlname='$dlname' + +# Names of this library. +library_names='$library_names' + +# The name of the static archive. +old_library='$old_library' + +# Libraries that this one depends upon. +dependency_libs='$dependency_libs' + +# Version information for $libname. +current=$current +age=$age +revision=$revision + +# Is this an already installed library? +installed=$installed + +# Directory that this library needs to be installed in: +libdir='$install_libdir'\ +" + done + fi + + # Do a symbolic link so that the libtool archive can be found in + # LD_LIBRARY_PATH before the program is installed. + $show "(cd $output_objdir && $rm $outputname && $LN_S ../$outputname $outputname)" + $run eval "(cd $output_objdir && $rm $outputname && $LN_S ../$outputname $outputname)" || exit $? + ;; + esac + exit 0 + ;; + + # libtool install mode + install) + modename="$modename: install" + + # There may be an optional sh(1) argument at the beginning of + # install_prog (especially on Windows NT). + if test "$nonopt" = "$SHELL" || test "$nonopt" = /bin/sh; then + # Aesthetically quote it. + arg=`$echo "X$nonopt" | $Xsed -e "$sed_quote_subst"` + case "$arg" in + *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*) + arg="\"$arg\"" + ;; + esac + install_prog="$arg " + arg="$1" + shift + else + install_prog= + arg="$nonopt" + fi + + # The real first argument should be the name of the installation program. + # Aesthetically quote it. + arg=`$echo "X$arg" | $Xsed -e "$sed_quote_subst"` + case "$arg" in + *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*) + arg="\"$arg\"" + ;; + esac + install_prog="$install_prog$arg" + + # We need to accept at least all the BSD install flags. + dest= + files= + opts= + prev= + install_type= + isdir=no + stripme= + for arg + do + if test -n "$dest"; then + files="$files $dest" + dest="$arg" + continue + fi + + case "$arg" in + -d) isdir=yes ;; + -f) prev="-f" ;; + -g) prev="-g" ;; + -m) prev="-m" ;; + -o) prev="-o" ;; + -s) + stripme=" -s" + continue + ;; + -*) ;; + + *) + # If the previous option needed an argument, then skip it. + if test -n "$prev"; then + prev= + else + dest="$arg" + continue + fi + ;; + esac + + # Aesthetically quote the argument. + arg=`$echo "X$arg" | $Xsed -e "$sed_quote_subst"` + case "$arg" in + *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*) + arg="\"$arg\"" + ;; + esac + install_prog="$install_prog $arg" + done + + if test -z "$install_prog"; then + $echo "$modename: you must specify an install program" 1>&2 + $echo "$help" 1>&2 + exit 1 + fi + + if test -n "$prev"; then + $echo "$modename: the \`$prev' option requires an argument" 1>&2 + $echo "$help" 1>&2 + exit 1 + fi + + if test -z "$files"; then + if test -z "$dest"; then + $echo "$modename: no file or destination specified" 1>&2 + else + $echo "$modename: you must specify a destination" 1>&2 + fi + $echo "$help" 1>&2 + exit 1 + fi + + # Strip any trailing slash from the destination. + dest=`$echo "X$dest" | $Xsed -e 's%/$%%'` + + # Check to see that the destination is a directory. + test -d "$dest" && isdir=yes + if test "$isdir" = yes; then + destdir="$dest" + destname= + else + destdir=`$echo "X$dest" | $Xsed -e 's%/[^/]*$%%'` + test "X$destdir" = "X$dest" && destdir=. + destname=`$echo "X$dest" | $Xsed -e 's%^.*/%%'` + + # Not a directory, so check to see that there is only one file specified. + set dummy $files + if test $# -gt 2; then + $echo "$modename: \`$dest' is not a directory" 1>&2 + $echo "$help" 1>&2 + exit 1 + fi + fi + case "$destdir" in + [\\/]* | [A-Za-z]:[\\/]*) ;; + *) + for file in $files; do + case "$file" in + *.lo) ;; + *) + $echo "$modename: \`$destdir' must be an absolute directory name" 1>&2 + $echo "$help" 1>&2 + exit 1 + ;; + esac + done + ;; + esac + + # This variable tells wrapper scripts just to set variables rather + # than running their programs. + libtool_install_magic="$magic" + + staticlibs= + future_libdirs= + current_libdirs= + for file in $files; do + + # Do each installation. + case "$file" in + *.a | *.lib) + # Do the static libraries later. + staticlibs="$staticlibs $file" + ;; + + *.la) + # Check to see that this really is a libtool archive. + if (sed -e '2q' $file | egrep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then : + else + $echo "$modename: \`$file' is not a valid libtool archive" 1>&2 + $echo "$help" 1>&2 + exit 1 + fi + + library_names= + old_library= + # If there is no directory component, then add one. + case "$file" in + */* | *\\*) . $file ;; + *) . ./$file ;; + esac + + # Add the libdir to current_libdirs if it is the destination. + if test "X$destdir" = "X$libdir"; then + case "$current_libdirs " in + *" $libdir "*) ;; + *) current_libdirs="$current_libdirs $libdir" ;; + esac + else + # Note the libdir as a future libdir. + case "$future_libdirs " in + *" $libdir "*) ;; + *) future_libdirs="$future_libdirs $libdir" ;; + esac + fi + + dir="`$echo "X$file" | $Xsed -e 's%/[^/]*$%%'`/" + test "X$dir" = "X$file/" && dir= + dir="$dir$objdir" + + # See the names of the shared library. + set dummy $library_names + if test -n "$2"; then + realname="$2" + shift + shift + + # Install the shared library and build the symlinks. + $show "$install_prog $dir/$realname $destdir/$realname" + $run eval "$install_prog $dir/$realname $destdir/$realname" || exit $? + + if test $# -gt 0; then + # Delete the old symlinks, and create new ones. + for linkname + do + if test "$linkname" != "$realname"; then + $show "(cd $destdir && $rm $linkname && $LN_S $realname $linkname)" + $run eval "(cd $destdir && $rm $linkname && $LN_S $realname $linkname)" + fi + done + fi + + # Do each command in the postinstall commands. + lib="$destdir/$realname" + eval cmds=\"$postinstall_cmds\" + IFS="${IFS= }"; save_ifs="$IFS"; IFS='~' + for cmd in $cmds; do + IFS="$save_ifs" + $show "$cmd" + $run eval "$cmd" || exit $? + done + IFS="$save_ifs" + fi + + # Install the pseudo-library for information purposes. + name=`$echo "X$file" | $Xsed -e 's%^.*/%%'` + instname="$dir/$name"i + $show "$install_prog $instname $destdir/$name" + $run eval "$install_prog $instname $destdir/$name" || exit $? + + # Maybe install the static library, too. + test -n "$old_library" && staticlibs="$staticlibs $dir/$old_library" + ;; + + *.lo) + # Install (i.e. copy) a libtool object. + + # Figure out destination file name, if it wasn't already specified. + if test -n "$destname"; then + destfile="$destdir/$destname" + else + destfile=`$echo "X$file" | $Xsed -e 's%^.*/%%'` + destfile="$destdir/$destfile" + fi + + # Deduce the name of the destination old-style object file. + case "$destfile" in + *.lo) + staticdest=`$echo "X$destfile" | $Xsed -e "$lo2o"` + ;; + *.o | *.obj) + staticdest="$destfile" + destfile= + ;; + *) + $echo "$modename: cannot copy a libtool object to \`$destfile'" 1>&2 + $echo "$help" 1>&2 + exit 1 + ;; + esac + + # Install the libtool object if requested. + if test -n "$destfile"; then + $show "$install_prog $file $destfile" + $run eval "$install_prog $file $destfile" || exit $? + fi + + # Install the old object if enabled. + if test "$build_old_libs" = yes; then + # Deduce the name of the old-style object file. + staticobj=`$echo "X$file" | $Xsed -e "$lo2o"` + + $show "$install_prog $staticobj $staticdest" + $run eval "$install_prog \$staticobj \$staticdest" || exit $? + fi + exit 0 + ;; + + *) + # Figure out destination file name, if it wasn't already specified. + if test -n "$destname"; then + destfile="$destdir/$destname" + else + destfile=`$echo "X$file" | $Xsed -e 's%^.*/%%'` + destfile="$destdir/$destfile" + fi + + # Do a test to see if this is really a libtool program. + if (sed -e '4q' $file | egrep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then + link_against_libtool_libs= + relink_command= + + # If there is no directory component, then add one. + case "$file" in + */* | *\\*) . $file ;; + *) . ./$file ;; + esac + + # Check the variables that should have been set. + if test -z "$link_against_libtool_libs"; then + $echo "$modename: invalid libtool wrapper script \`$file'" 1>&2 + exit 1 + fi + + finalize=yes + for lib in $link_against_libtool_libs; do + # Check to see that each library is installed. + libdir= + if test -f "$lib"; then + # If there is no directory component, then add one. + case "$lib" in + */* | *\\*) . $lib ;; + *) . ./$lib ;; + esac + fi + libfile="$libdir/`$echo "X$lib" | $Xsed -e 's%^.*/%%g'`" + if test -n "$libdir" && test ! -f "$libfile"; then + $echo "$modename: warning: \`$lib' has not been installed in \`$libdir'" 1>&2 + finalize=no + fi + done + + outputname= + if test "$fast_install" = no && test -n "$relink_command"; then + if test "$finalize" = yes && test -z "$run"; then + tmpdir="/tmp" + test -n "$TMPDIR" && tmpdir="$TMPDIR" + tmpdir="$tmpdir/libtool-$$" + if $mkdir -p "$tmpdir" && chmod 700 "$tmpdir"; then : + else + $echo "$modename: error: cannot create temporary directory \`$tmpdir'" 1>&2 + continue + fi + outputname="$tmpdir/$file" + # Replace the output file specification. + relink_command=`$echo "X$relink_command" | $Xsed -e 's%@OUTPUT@%'"$outputname"'%g'` + + $show "$relink_command" + if $run eval "$relink_command"; then : + else + $echo "$modename: error: relink \`$file' with the above command before installing it" 1>&2 + ${rm}r "$tmpdir" + continue + fi + file="$outputname" + else + $echo "$modename: warning: cannot relink \`$file'" 1>&2 + fi + else + # Install the binary that we compiled earlier. + file=`$echo "X$file" | $Xsed -e "s%\([^/]*\)$%$objdir/\1%"` + fi + fi + + $show "$install_prog$stripme $file $destfile" + $run eval "$install_prog\$stripme \$file \$destfile" || exit $? + test -n "$outputname" && ${rm}r "$tmpdir" + ;; + esac + done + + for file in $staticlibs; do + name=`$echo "X$file" | $Xsed -e 's%^.*/%%'` + + # Set up the ranlib parameters. + oldlib="$destdir/$name" + + $show "$install_prog $file $oldlib" + $run eval "$install_prog \$file \$oldlib" || exit $? + + # Do each command in the postinstall commands. + eval cmds=\"$old_postinstall_cmds\" + IFS="${IFS= }"; save_ifs="$IFS"; IFS='~' + for cmd in $cmds; do + IFS="$save_ifs" + $show "$cmd" + $run eval "$cmd" || exit $? + done + IFS="$save_ifs" + done + + if test -n "$future_libdirs"; then + $echo "$modename: warning: remember to run \`$progname --finish$future_libdirs'" 1>&2 + fi + + if test -n "$current_libdirs"; then + # Maybe just do a dry run. + test -n "$run" && current_libdirs=" -n$current_libdirs" + exec $SHELL $0 --finish$current_libdirs + exit 1 + fi + + exit 0 + ;; + + # libtool finish mode + finish) + modename="$modename: finish" + libdirs="$nonopt" + admincmds= + + if test -n "$finish_cmds$finish_eval" && test -n "$libdirs"; then + for dir + do + libdirs="$libdirs $dir" + done + + for libdir in $libdirs; do + if test -n "$finish_cmds"; then + # Do each command in the finish commands. + eval cmds=\"$finish_cmds\" + IFS="${IFS= }"; save_ifs="$IFS"; IFS='~' + for cmd in $cmds; do + IFS="$save_ifs" + $show "$cmd" + $run eval "$cmd" || admincmds="$admincmds + $cmd" + done + IFS="$save_ifs" + fi + if test -n "$finish_eval"; then + # Do the single finish_eval. + eval cmds=\"$finish_eval\" + $run eval "$cmds" || admincmds="$admincmds + $cmds" + fi + done + fi + + # Exit here if they wanted silent mode. + test "$show" = : && exit 0 + + echo "----------------------------------------------------------------------" + echo "Libraries have been installed in:" + for libdir in $libdirs; do + echo " $libdir" + done + echo + echo "If you ever happen to want to link against installed libraries" + echo "in a given directory, LIBDIR, you must either use libtool, and" + echo "specify the full pathname of the library, or use \`-LLIBDIR'" + echo "flag during linking and do at least one of the following:" + if test -n "$shlibpath_var"; then + echo " - add LIBDIR to the \`$shlibpath_var' environment variable" + echo " during execution" + fi + if test -n "$runpath_var"; then + echo " - add LIBDIR to the \`$runpath_var' environment variable" + echo " during linking" + fi + if test -n "$hardcode_libdir_flag_spec"; then + libdir=LIBDIR + eval flag=\"$hardcode_libdir_flag_spec\" + + echo " - use the \`$flag' linker flag" + fi + if test -n "$admincmds"; then + echo " - have your system administrator run these commands:$admincmds" + fi + if test -f /etc/ld.so.conf; then + echo " - have your system administrator add LIBDIR to \`/etc/ld.so.conf'" + fi + echo + echo "See any operating system documentation about shared libraries for" + echo "more information, such as the ld(1) and ld.so(8) manual pages." + echo "----------------------------------------------------------------------" + exit 0 + ;; + + # libtool execute mode + execute) + modename="$modename: execute" + + # The first argument is the command name. + cmd="$nonopt" + if test -z "$cmd"; then + $echo "$modename: you must specify a COMMAND" 1>&2 + $echo "$help" + exit 1 + fi + + # Handle -dlopen flags immediately. + for file in $execute_dlfiles; do + if test ! -f "$file"; then + $echo "$modename: \`$file' is not a file" 1>&2 + $echo "$help" 1>&2 + exit 1 + fi + + dir= + case "$file" in + *.la) + # Check to see that this really is a libtool archive. + if (sed -e '2q' $file | egrep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then : + else + $echo "$modename: \`$lib' is not a valid libtool archive" 1>&2 + $echo "$help" 1>&2 + exit 1 + fi + + # Read the libtool library. + dlname= + library_names= + + # If there is no directory component, then add one. + case "$file" in + */* | *\\*) . $file ;; + *) . ./$file ;; + esac + + # Skip this library if it cannot be dlopened. + if test -z "$dlname"; then + # Warn if it was a shared library. + test -n "$library_names" && $echo "$modename: warning: \`$file' was not linked with \`-export-dynamic'" + continue + fi + + dir=`$echo "X$file" | $Xsed -e 's%/[^/]*$%%'` + test "X$dir" = "X$file" && dir=. + + if test -f "$dir/$objdir/$dlname"; then + dir="$dir/$objdir" + else + $echo "$modename: cannot find \`$dlname' in \`$dir' or \`$dir/$objdir'" 1>&2 + exit 1 + fi + ;; + + *.lo) + # Just add the directory containing the .lo file. + dir=`$echo "X$file" | $Xsed -e 's%/[^/]*$%%'` + test "X$dir" = "X$file" && dir=. + ;; + + *) + $echo "$modename: warning \`-dlopen' is ignored for non-libtool libraries and objects" 1>&2 + continue + ;; + esac + + # Get the absolute pathname. + absdir=`cd "$dir" && pwd` + test -n "$absdir" && dir="$absdir" + + # Now add the directory to shlibpath_var. + if eval "test -z \"\$$shlibpath_var\""; then + eval "$shlibpath_var=\"\$dir\"" + else + eval "$shlibpath_var=\"\$dir:\$$shlibpath_var\"" + fi + done + + # This variable tells wrapper scripts just to set shlibpath_var + # rather than running their programs. + libtool_execute_magic="$magic" + + # Check if any of the arguments is a wrapper script. + args= + for file + do + case "$file" in + -*) ;; + *) + # Do a test to see if this is really a libtool program. + if (sed -e '4q' $file | egrep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then + # If there is no directory component, then add one. + case "$file" in + */* | *\\*) . $file ;; + *) . ./$file ;; + esac + + # Transform arg to wrapped name. + file="$progdir/$program" + fi + ;; + esac + # Quote arguments (to preserve shell metacharacters). + file=`$echo "X$file" | $Xsed -e "$sed_quote_subst"` + args="$args \"$file\"" + done + + if test -z "$run"; then + if test -n "$shlibpath_var"; then + # Export the shlibpath_var. + eval "export $shlibpath_var" + fi + + # Restore saved enviroment variables + if test "${save_LC_ALL+set}" = set; then + LC_ALL="$save_LC_ALL"; export LC_ALL + fi + if test "${save_LANG+set}" = set; then + LANG="$save_LANG"; export LANG + fi + + # Now actually exec the command. + eval "exec \$cmd$args" + + $echo "$modename: cannot exec \$cmd$args" + exit 1 + else + # Display what would be done. + if test -n "$shlibpath_var"; then + eval "\$echo \"\$shlibpath_var=\$$shlibpath_var\"" + $echo "export $shlibpath_var" + fi + $echo "$cmd$args" + exit 0 + fi + ;; + + # libtool uninstall mode + uninstall) + modename="$modename: uninstall" + rm="$nonopt" + files= + + for arg + do + case "$arg" in + -*) rm="$rm $arg" ;; + *) files="$files $arg" ;; + esac + done + + if test -z "$rm"; then + $echo "$modename: you must specify an RM program" 1>&2 + $echo "$help" 1>&2 + exit 1 + fi + + for file in $files; do + dir=`$echo "X$file" | $Xsed -e 's%/[^/]*$%%'` + test "X$dir" = "X$file" && dir=. + name=`$echo "X$file" | $Xsed -e 's%^.*/%%'` + + rmfiles="$file" + + case "$name" in + *.la) + # Possibly a libtool archive, so verify it. + if (sed -e '2q' $file | egrep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then + . $dir/$name + + # Delete the libtool libraries and symlinks. + for n in $library_names; do + rmfiles="$rmfiles $dir/$n" + done + test -n "$old_library" && rmfiles="$rmfiles $dir/$old_library" + + $show "$rm $rmfiles" + $run $rm $rmfiles + + if test -n "$library_names"; then + # Do each command in the postuninstall commands. + eval cmds=\"$postuninstall_cmds\" + IFS="${IFS= }"; save_ifs="$IFS"; IFS='~' + for cmd in $cmds; do + IFS="$save_ifs" + $show "$cmd" + $run eval "$cmd" + done + IFS="$save_ifs" + fi + + if test -n "$old_library"; then + # Do each command in the old_postuninstall commands. + eval cmds=\"$old_postuninstall_cmds\" + IFS="${IFS= }"; save_ifs="$IFS"; IFS='~' + for cmd in $cmds; do + IFS="$save_ifs" + $show "$cmd" + $run eval "$cmd" + done + IFS="$save_ifs" + fi + + # FIXME: should reinstall the best remaining shared library. + fi + ;; + + *.lo) + if test "$build_old_libs" = yes; then + oldobj=`$echo "X$name" | $Xsed -e "$lo2o"` + rmfiles="$rmfiles $dir/$oldobj" + fi + $show "$rm $rmfiles" + $run $rm $rmfiles + ;; + + *) + $show "$rm $rmfiles" + $run $rm $rmfiles + ;; + esac + done + exit 0 + ;; + + "") + $echo "$modename: you must specify a MODE" 1>&2 + $echo "$generic_help" 1>&2 + exit 1 + ;; + esac + + $echo "$modename: invalid operation mode \`$mode'" 1>&2 + $echo "$generic_help" 1>&2 + exit 1 +fi # test -z "$show_help" + +# We need to display help for each of the modes. +case "$mode" in +"") $echo \ +"Usage: $modename [OPTION]... [MODE-ARG]... + +Provide generalized library-building support services. + + --config show all configuration variables + --debug enable verbose shell tracing +-n, --dry-run display commands without modifying any files + --features display basic configuration information and exit + --finish same as \`--mode=finish' + --help display this help message and exit + --mode=MODE use operation mode MODE [default=inferred from MODE-ARGS] + --quiet same as \`--silent' + --silent don't print informational messages + --version print version information + +MODE must be one of the following: + + compile compile a source file into a libtool object + execute automatically set library path, then run a program + finish complete the installation of libtool libraries + install install libraries or executables + link create a library or an executable + uninstall remove libraries from an installed directory + +MODE-ARGS vary depending on the MODE. Try \`$modename --help --mode=MODE' for +a more detailed description of MODE." + exit 0 + ;; + +compile) + $echo \ +"Usage: $modename [OPTION]... --mode=compile COMPILE-COMMAND... SOURCEFILE + +Compile a source file into a libtool library object. + +This mode accepts the following additional options: + + -o OUTPUT-FILE set the output file name to OUTPUT-FILE + -static always build a \`.o' file suitable for static linking + +COMPILE-COMMAND is a command to be used in creating a \`standard' object file +from the given SOURCEFILE. + +The output file name is determined by removing the directory component from +SOURCEFILE, then substituting the C source code suffix \`.c' with the +library object suffix, \`.lo'." + ;; + +execute) + $echo \ +"Usage: $modename [OPTION]... --mode=execute COMMAND [ARGS]... + +Automatically set library path, then run a program. + +This mode accepts the following additional options: + + -dlopen FILE add the directory containing FILE to the library path + +This mode sets the library path environment variable according to \`-dlopen' +flags. + +If any of the ARGS are libtool executable wrappers, then they are translated +into their corresponding uninstalled binary, and any of their required library +directories are added to the library path. + +Then, COMMAND is executed, with ARGS as arguments." + ;; + +finish) + $echo \ +"Usage: $modename [OPTION]... --mode=finish [LIBDIR]... + +Complete the installation of libtool libraries. + +Each LIBDIR is a directory that contains libtool libraries. + +The commands that this mode executes may require superuser privileges. Use +the \`--dry-run' option if you just want to see what would be executed." + ;; + +install) + $echo \ +"Usage: $modename [OPTION]... --mode=install INSTALL-COMMAND... + +Install executables or libraries. + +INSTALL-COMMAND is the installation command. The first component should be +either the \`install' or \`cp' program. + +The rest of the components are interpreted as arguments to that command (only +BSD-compatible install options are recognized)." + ;; + +link) + $echo \ +"Usage: $modename [OPTION]... --mode=link LINK-COMMAND... + +Link object files or libraries together to form another library, or to +create an executable program. + +LINK-COMMAND is a command using the C compiler that you would use to create +a program from several object files. + +The following components of LINK-COMMAND are treated specially: + + -all-static do not do any dynamic linking at all + -avoid-version do not add a version suffix if possible + -dlopen FILE \`-dlpreopen' FILE if it cannot be dlopened at runtime + -dlpreopen FILE link in FILE and add its symbols to lt_preloaded_symbols + -export-dynamic allow symbols from OUTPUT-FILE to be resolved with dlsym(3) + -export-symbols SYMFILE + try to export only the symbols listed in SYMFILE + -export-symbols-regex REGEX + try to export only the symbols matching REGEX + -LLIBDIR search LIBDIR for required installed libraries + -lNAME OUTPUT-FILE requires the installed library libNAME + -module build a library that can dlopened + -no-undefined declare that a library does not refer to external symbols + -o OUTPUT-FILE create OUTPUT-FILE from the specified objects + -release RELEASE specify package release information + -rpath LIBDIR the created library will eventually be installed in LIBDIR + -R[ ]LIBDIR add LIBDIR to the runtime path of programs and libraries + -static do not do any dynamic linking of libtool libraries + -version-info CURRENT[:REVISION[:AGE]] + specify library version info [each variable defaults to 0] + +All other options (arguments beginning with \`-') are ignored. + +Every other argument is treated as a filename. Files ending in \`.la' are +treated as uninstalled libtool libraries, other files are standard or library +object files. + +If the OUTPUT-FILE ends in \`.la', then a libtool library is created, +only library objects (\`.lo' files) may be specified, and \`-rpath' is +required, except when creating a convenience library. + +If OUTPUT-FILE ends in \`.a' or \`.lib', then a standard library is created +using \`ar' and \`ranlib', or on Windows using \`lib'. + +If OUTPUT-FILE ends in \`.lo' or \`.${objext}', then a reloadable object file +is created, otherwise an executable program is created." + ;; + +uninstall) + $echo \ +"Usage: $modename [OPTION]... --mode=uninstall RM [RM-OPTION]... FILE... + +Remove libraries from an installation directory. + +RM is the name of the program to use to delete files associated with each FILE +(typically \`/bin/rm'). RM-OPTIONS are options (such as \`-f') to be passed +to RM. + +If FILE is a libtool library, all the files associated with it are deleted. +Otherwise, only FILE itself is deleted using RM." + ;; + +*) + $echo "$modename: invalid operation mode \`$mode'" 1>&2 + $echo "$help" 1>&2 + exit 1 + ;; +esac + +echo +$echo "Try \`$modename --help' for more information about other modes." + +exit 0 + +# Local Variables: +# mode:shell-script +# sh-indentation:2 +# End: diff --git a/missing b/missing new file mode 100755 index 0000000..7789652 --- /dev/null +++ b/missing @@ -0,0 +1,190 @@ +#! /bin/sh +# Common stub for a few missing GNU programs while installing. +# Copyright (C) 1996, 1997 Free Software Foundation, Inc. +# Franc,ois Pinard , 1996. + +# This program 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, or (at your option) +# any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +# 02111-1307, USA. + +if test $# -eq 0; then + echo 1>&2 "Try \`$0 --help' for more information" + exit 1 +fi + +case "$1" in + + -h|--h|--he|--hel|--help) + echo "\ +$0 [OPTION]... PROGRAM [ARGUMENT]... + +Handle \`PROGRAM [ARGUMENT]...' for when PROGRAM is missing, or return an +error status if there is no known handling for PROGRAM. + +Options: + -h, --help display this help and exit + -v, --version output version information and exit + +Supported PROGRAM values: + aclocal touch file \`aclocal.m4' + autoconf touch file \`configure' + autoheader touch file \`config.h.in' + automake touch all \`Makefile.in' files + bison create \`y.tab.[ch]', if possible, from existing .[ch] + flex create \`lex.yy.c', if possible, from existing .c + lex create \`lex.yy.c', if possible, from existing .c + makeinfo touch the output file + yacc create \`y.tab.[ch]', if possible, from existing .[ch]" + ;; + + -v|--v|--ve|--ver|--vers|--versi|--versio|--version) + echo "missing - GNU libit 0.0" + ;; + + -*) + echo 1>&2 "$0: Unknown \`$1' option" + echo 1>&2 "Try \`$0 --help' for more information" + exit 1 + ;; + + aclocal) + echo 1>&2 "\ +WARNING: \`$1' is missing on your system. You should only need it if + you modified \`acinclude.m4' or \`configure.in'. You might want + to install the \`Automake' and \`Perl' packages. Grab them from + any GNU archive site." + touch aclocal.m4 + ;; + + autoconf) + echo 1>&2 "\ +WARNING: \`$1' is missing on your system. You should only need it if + you modified \`configure.in'. You might want to install the + \`Autoconf' and \`GNU m4' packages. Grab them from any GNU + archive site." + touch configure + ;; + + autoheader) + echo 1>&2 "\ +WARNING: \`$1' is missing on your system. You should only need it if + you modified \`acconfig.h' or \`configure.in'. You might want + to install the \`Autoconf' and \`GNU m4' packages. Grab them + from any GNU archive site." + files=`sed -n 's/^[ ]*A[CM]_CONFIG_HEADER(\([^)]*\)).*/\1/p' configure.in` + test -z "$files" && files="config.h" + touch_files= + for f in $files; do + case "$f" in + *:*) touch_files="$touch_files "`echo "$f" | + sed -e 's/^[^:]*://' -e 's/:.*//'`;; + *) touch_files="$touch_files $f.in";; + esac + done + touch $touch_files + ;; + + automake) + echo 1>&2 "\ +WARNING: \`$1' is missing on your system. You should only need it if + you modified \`Makefile.am', \`acinclude.m4' or \`configure.in'. + You might want to install the \`Automake' and \`Perl' packages. + Grab them from any GNU archive site." + find . -type f -name Makefile.am -print | + sed 's/\.am$/.in/' | + while read f; do touch "$f"; done + ;; + + bison|yacc) + echo 1>&2 "\ +WARNING: \`$1' is missing on your system. You should only need it if + you modified a \`.y' file. You may need the \`Bison' package + in order for those modifications to take effect. You can get + \`Bison' from any GNU archive site." + rm -f y.tab.c y.tab.h + if [ $# -ne 1 ]; then + eval LASTARG="\${$#}" + case "$LASTARG" in + *.y) + SRCFILE=`echo "$LASTARG" | sed 's/y$/c/'` + if [ -f "$SRCFILE" ]; then + cp "$SRCFILE" y.tab.c + fi + SRCFILE=`echo "$LASTARG" | sed 's/y$/h/'` + if [ -f "$SRCFILE" ]; then + cp "$SRCFILE" y.tab.h + fi + ;; + esac + fi + if [ ! -f y.tab.h ]; then + echo >y.tab.h + fi + if [ ! -f y.tab.c ]; then + echo 'main() { return 0; }' >y.tab.c + fi + ;; + + lex|flex) + echo 1>&2 "\ +WARNING: \`$1' is missing on your system. You should only need it if + you modified a \`.l' file. You may need the \`Flex' package + in order for those modifications to take effect. You can get + \`Flex' from any GNU archive site." + rm -f lex.yy.c + if [ $# -ne 1 ]; then + eval LASTARG="\${$#}" + case "$LASTARG" in + *.l) + SRCFILE=`echo "$LASTARG" | sed 's/l$/c/'` + if [ -f "$SRCFILE" ]; then + cp "$SRCFILE" lex.yy.c + fi + ;; + esac + fi + if [ ! -f lex.yy.c ]; then + echo 'main() { return 0; }' >lex.yy.c + fi + ;; + + makeinfo) + echo 1>&2 "\ +WARNING: \`$1' is missing on your system. You should only need it if + you modified a \`.texi' or \`.texinfo' file, or any other file + indirectly affecting the aspect of the manual. The spurious + call might also be the consequence of using a buggy \`make' (AIX, + DU, IRIX). You might want to install the \`Texinfo' package or + the \`GNU make' package. Grab either from any GNU archive site." + file=`echo "$*" | sed -n 's/.*-o \([^ ]*\).*/\1/p'` + if test -z "$file"; then + file=`echo "$*" | sed 's/.* \([^ ]*\) *$/\1/'` + file=`sed -n '/^@setfilename/ { s/.* \([^ ]*\) *$/\1/; p; q; }' $file` + fi + touch $file + ;; + + *) + echo 1>&2 "\ +WARNING: \`$1' is needed, and you do not seem to have it handy on your + system. You might have modified some files without having the + proper tools for further handling them. Check the \`README' file, + it often tells you about the needed prerequirements for installing + this package. You may also peek at any GNU archive site, in case + some other package would contain this missing \`$1' program." + exit 1 + ;; +esac + +exit 0 diff --git a/mkinstalldirs b/mkinstalldirs new file mode 100755 index 0000000..4f58503 --- /dev/null +++ b/mkinstalldirs @@ -0,0 +1,40 @@ +#! /bin/sh +# mkinstalldirs --- make directory hierarchy +# Author: Noah Friedman +# Created: 1993-05-16 +# Public domain + +# $Id: mkinstalldirs,v 1.13 1999/01/05 03:18:55 bje Exp $ + +errstatus=0 + +for file +do + set fnord `echo ":$file" | sed -ne 's/^:\//#/;s/^://;s/\// /g;s/^#/\//;p'` + shift + + pathcomp= + for d + do + pathcomp="$pathcomp$d" + case "$pathcomp" in + -* ) pathcomp=./$pathcomp ;; + esac + + if test ! -d "$pathcomp"; then + echo "mkdir $pathcomp" + + mkdir "$pathcomp" || lasterr=$? + + if test ! -d "$pathcomp"; then + errstatus=$lasterr + fi + fi + + pathcomp="$pathcomp/" + done +done + +exit $errstatus + +# mkinstalldirs ends here diff --git a/src/.cvsignore b/src/.cvsignore new file mode 100644 index 0000000..f4d6229 --- /dev/null +++ b/src/.cvsignore @@ -0,0 +1,5 @@ +rpctest +rpctest.static +cpptest +efrpctest +efrpctest_wrapper diff --git a/src/Makefile b/src/Makefile new file mode 100644 index 0000000..e78370d --- /dev/null +++ b/src/Makefile @@ -0,0 +1,203 @@ +ifeq ($(SRCDIR)x,x) +SRCDIR = $(CURDIR)/.. +endif +SUBDIR = src +BUILDDIR = $(SRCDIR) +VPATH = .:$(SRCDIR) + +include $(BUILDDIR)/Makefile.config + +ABYSS_LIBDIR = $(BUILDDIR)/lib/abyss/src/.libs +LIBUTIL_LIBDIR = $(BUILDDIR)/lib/libutil/.libs + +default: all + +SUBDIRS = + +ifeq ($(ENABLE_CPLUSPLUS),yes) + SUBDIRS += cpp +endif + +WININET_TRANSPORT_DIR = $(SRCDIR)/lib/wininet_transport +CURL_TRANSPORT_DIR = $(SRCDIR)/lib/curl_transport +LIBWWW_TRANSPORT_DIR = $(SRCDIR)/lib/libwww_transport + +# TRANSPORT_OBJS is the list of modules that have to go into the client +# library to provide the client XML transport functions. Since there is +# some variability in what XML transports we can build into the client +# library, this is a little complicated. + +# TRANSPORT_LIBDEP is linker -l options to declare what libraries contain +# things to which the transport objects refer. (like LIBxxx_LIBDEP -- +# see below) + +TRANSPORT_OBJS = +TRANSPORT_LIBDEP = +ifeq ($(MUST_BUILD_WININET_CLIENT),yes) + TRANSPORT_OBJS += $(WININET_TRANSPORT_DIR)/xmlrpc_wininet_transport.lo + TRANSPORT_LIBDEP += $(shell wininet-config --libs) +endif +ifeq ($(MUST_BUILD_CURL_CLIENT),yes) + TRANSPORT_OBJS += $(CURL_TRANSPORT_DIR)/xmlrpc_curl_transport.lo + TRANSPORT_LIBDEP += $(shell curl-config --libs) +endif +ifeq ($(MUST_BUILD_LIBWWW_CLIENT),yes) + TRANSPORT_OBJS += $(LIBWWW_TRANSPORT_DIR)/xmlrpc_libwww_transport.lo + TRANSPORT_LIBDEP += $(shell libwww-config --libs) +endif + +ifeq ($(ENABLE_LIBXML2_BACKEND),yes) + LIBXML_INCLUDES = $(shell xml2-config --cflags) + LIBXML_LIBS = $(shell xml2-config --libs) +else + LIBXML_INCLUDES = -I$(SRCDIR)/lib/expat/xmlparse +endif + +ABYSS_INCLUDES = -I$(SRCDIR)/lib/abyss/src + +ifeq ($(ENABLE_LIBXML2_BACKEND),yes) + XMLRPC_XML_PARSER = xmlrpc_libxml2.lo +else + XMLRPC_XML_PARSER = xmlrpc_expat.lo +endif + +# LIBxxx_OBJS is the list of object files that make up library libxxx. + +# LIBxxx_LIBDEP is linker -l options to declare what libraries contain +# things to which the library being built refers. This information +# makes its way to the dynamic linker, so it knows to load the +# referred-to library before it loads libxxx. Note that the link command +# may require the necessary -L options in addition. + +LIBXMLRPC_CLIENT_OBJS = xmlrpc_client.lo xmlrpc_client_global.lo +LIBXMLRPC_CLIENT_LIBDEP = -lxmlrpc_util -lxmlrpc + +LIBXMLRPC_SERVER_OBJS = registry.lo system_method.lo +LIBXMLRPC_SERVER_LIBDEP = -lxmlrpc_util -lxmlrpc + +LIBXMLRPC_SERVER_ABYSS_OBJS = xmlrpc_server_abyss.lo +LIBXMLRPC_SERVER_ABYSS_LIBDEP = \ + -lxmlrpc_util -lxmlrpc_server -L$(ABYSS_LIBDIR) -lxmlrpc_abyss -lxmlrpc + +LIBXMLRPC_SERVER_CGI_OBJS = xmlrpc_server_cgi.lo +LIBXMLRPC_SERVER_CGI_LIBDEP = -lxmlrpc_util -lxmlrpc_server -lxmlrpc + +LIBXMLRPC_OBJS = \ + trace.lo \ + xmlrpc_data.lo \ + xmlrpc_builddecomp.lo \ + xmlrpc_datetime.lo \ + xmlrpc_array.lo \ + xmlrpc_struct.lo \ + $(XMLRPC_XML_PARSER) \ + xmlrpc_parse.lo \ + xmlrpc_serialize.lo \ + xmlrpc_base64.lo \ + xmlrpc_utf8.lo \ + xmlrpc_authcookie.lo \ + +LIBXMLRPC_LIBDEP = -lxmlrpc_util $(LIBXML_LIBS) + +LIB_OBJS = $(LIBXMLRPC_CLIENT_OBJS) $(LIBXMLRPC_SERVER_OBJS) + +TRANSPORT_INCLUDES = \ + -I$(WININET_TRANSPORT_DIR) \ + -I$(CURL_TRANSPORT_DIR) \ + -I$(LIBWWW_TRANSPORT_DIR) \ + +INCLUDES = -I$(BUILDDIR) -I$(SRCDIR) \ + -I$(SRCDIR)/include -I$(SRCDIR)/lib/util/include \ + -I$(SRCDIR)/lib/abyss/src \ + $(TRANSPORT_INCLUDES) \ + $(LIBXML_INCLUDES) \ + +# People sometimes think that when the Xmlrpc-c build has been +# configured for no Abyss server (configure --disable-abyss), that +# libmxlrpc_server_abyss should not get built. But +# libxmlrpc_server_abyss is not part of the Abyss server; it is merely +# some code that exploits an Abyss server, and you don't need to have a +# built Abyss server to build it. + +TARGET_LTLIBRARIES = libxmlrpc.la libxmlrpc_server.la \ + libxmlrpc_server_abyss.la + +ifeq ($(MUST_BUILD_CLIENT),yes) + TARGET_LTLIBRARIES += libxmlrpc_client.la +endif + +ifeq ($(ENABLE_CGI_SERVER),yes) + TARGET_LTLIBRARIES += libxmlrpc_server_cgi.la +endif + +all: $(TARGET_LTLIBRARIES) $(SUBDIRS:%=%/all) + +LDFLAGS = $(LADD) + +LIBPATHS = -L.libs -L$(LIBUTIL_LIBDIR) + +LIBLDFLAGS = $(LDFLAGS_VERSINFO) -rpath $(LIBINST_DIR) $(LIBPATHS) $(LADD) + + +libxmlrpc.la: $(LIBXMLRPC_OBJS) + $(LIBTOOL) --mode=link $(CCLD) -o $@ $(LIBLDFLAGS) \ + $(LIBXMLRPC_OBJS) $(LIBXMLRPC_LIBDEP) + +libxmlrpc_client.la: $(LIBXMLRPC_CLIENT_OBJS) $(TRANSPORT_OBJS) + $(LIBTOOL) --mode=link $(CCLD) -o $@ $(LIBLDFLAGS) \ + $(LIBXMLRPC_CLIENT_OBJS) $(TRANSPORT_OBJS) \ + $(LIBXMLRPC_CLIENT_LIBDEP) $(TRANSPORT_LIBDEP) \ + +libxmlrpc_server.la: $(LIBXMLRPC_SERVER_OBJS) + $(LIBTOOL) --mode=link $(CCLD) -o $@ $(LIBLDFLAGS) \ + $(LIBXMLRPC_SERVER_OBJS) $(LIBXMLRPC_SERVER_LIBDEP) + +libxmlrpc_server_abyss.la: $(LIBXMLRPC_SERVER_ABYSS_OBJS) + $(LIBTOOL) --mode=link $(CCLD) -o $@ $(LIBLDFLAGS) \ + $(LIBXMLRPC_SERVER_ABYSS_OBJS) $(LIBXMLRPC_SERVER_ABYSS_LIBDEP) + +libxmlrpc_server_cgi.la: $(LIBXMLRPC_SERVER_CGI_OBJS) + $(LIBTOOL) --mode=link $(CCLD) -o $@ $(LIBLDFLAGS) \ + $(LIBXMLRPC_SERVER_CGI_OBJS) $(LIBXMLRPC_SERVER_CGI_LIBDEP) + + +CFLAGS = $(CFLAGS_COMMON) $(CFLAGS_PERSONAL) $(CADD) + +$(LIBXMLRPC_CLIENT_OBJS) $(LIBXMLRPC_SERVER_OBJS):%.lo:%.c + $(LIBTOOL) --mode=compile $(CC) -c $(INCLUDES) $(CFLAGS) $< + +$(LIBXMLRPC_OBJS):%.lo:%.c + $(LIBTOOL) --mode=compile $(CC) -c $(INCLUDES) $(LIBXML_INCLUDES) \ + $(CFLAGS) $< + +$(LIBXMLRPC_SERVER_ABYSS_OBJS):%.lo:%.c + $(LIBTOOL) --mode=compile $(CC) -c $(INCLUDES) $(ABYSS_INCLUDES) \ + $(CFLAGS) $< + +xmlrpc_server_cgi.lo:%.lo:%.c + $(LIBTOOL) --mode=compile $(CC) -c $(INCLUDES) \ + $(CFLAGS) $< + +LTLIBRARIES_TO_INSTALL = $(TARGET_LTLIBRARIES) + +check: + $(MAKE) -C test runtests + $(MAKE) -C cpp check + +.PHONY: install +install: install-common $(SUBDIRS:%=%/install) + +.PHONY: clean clean-local distclean +clean: clean-common clean-local $(SUBDIRS:%=%/clean) +clean-local: + $(MAKE) -C test clean + +distclean: clean-common clean-local distclean-common $(SUBDIRS:%=%/distclean) + +.PHONY: dep +dep: $(SUBDIRS:%=%/dep) $(BUILDDIR)/transport_config.h dep-common + +include $(SRCDIR)/Makefile.common + +xmlrpc_client.lo: $(BUILDDIR)/transport_config.h + +include Makefile.depend diff --git a/src/Makefile.depend b/src/Makefile.depend new file mode 100644 index 0000000..e69de29 diff --git a/src/cpp/Makefile b/src/cpp/Makefile new file mode 100644 index 0000000..35c8a34 --- /dev/null +++ b/src/cpp/Makefile @@ -0,0 +1,190 @@ +ifeq ($(SRCDIR)x,x) +SRCDIR := $(CURDIR)/../.. +endif +SUBDIR := src/cpp +# BLDDIR is for use in places where a symbolic link won't work. +# BUILDDIR is for places in Makefile.common that can use the 'blddir' +# symbolic link (but in directories that don't, like this one, have +# blddir, these places use something else -- hence the variable). +BLDDIR = ../.. +BUILDDIR := blddir +VPATH = .:$(SRCDIR) + +include $(BLDDIR)/Makefile.config + +default: all + +# libxmlrpc_cpp is the legacy C++ wrapper library. The others are the +# more elaborate replacements. + +TARGET_LIBRARY_NAMES := \ + libxmlrpc_cpp \ + libxmlrpc++ \ + libxmlrpc_server++ \ + libxmlrpc_server_abyss++ \ + +ifeq ($(MUST_BUILD_CLIENT),yes) + TARGET_LIBRARY_NAMES += libxmlrpc_client++ +endif + +STATIC_LIBRARIES_TO_INSTALL = $(TARGET_STATIC_LIBRARIES) + +SHARED_LIBS_TO_BUILD := $(TARGET_LIBRARY_NAMES) +SHARED_LIBS_TO_INSTALL := $(TARGET_LIBRARY_NAMES) + +# INCLUDES and DEP_SOURCES are used by dep-common target +INCLUDES = $(BASIC_INCLUDES) $(CLIENT_INCLUDES) $(LIBXML_INCLUDES) \ + $(SERVER_INCLUDES) $(SERVER_ABYSS_INCLUDES) $(TRANSPORT_INCLUDES) +DEP_SOURCES = *.cpp + +WININET_TRANSPORT_DIR = srcdir/lib/wininet_transport +CURL_TRANSPORT_DIR = srcdir/lib/curl_transport +LIBWWW_TRANSPORT_DIR = srcdir/lib/libwww_transport + +ifeq ($(ENABLE_LIBXML2_BACKEND),yes) + LIBXML_INCLUDES = $(LIBXML2_CFLAGS) +else + LIBXML_INCLUDES = -Isrcdir/lib/expat/xmlparse +endif + +LIBXMLRPCPP_OBJS = \ + base64.o \ + env_wrap.o \ + fault.o \ + girerr.o \ + girmem.o \ + outcome.o \ + param_list.o \ + value.o \ + xml.o \ + +LIBXMLRPC_SERVERPP_OBJS = registry.o +LIBXMLRPC_SERVER_ABYSSPP_OBJS = server_abyss.o +LIBXMLRPC_CLIENTPP_OBJS = client.o client_simple.o curl.o libwww.o wininet.o + +ALL_OBJS = \ + XmlRpcCpp.o \ + $(LIBXMLRPCCPP_OBJS) \ + $(LIBXMLRPC_SERVERPP_OBJS) \ + $(LIBXMLRPC_SERVER_ABYSSPP_OBJS) \ + $(LIBXMLRPC_CLIENTPP_OBJS) + +include $(SRCDIR)/Makefile.common + +# This 'Makefile.common' dependency makes sure the symlinks get built before +# this make file is used for anything. + +$(SRCDIR)/Makefile.common: srcdir blddir + +TRANSPORT_INCLUDES = \ + -I$(WININET_TRANSPORT_DIR) \ + -I$(CURL_TRANSPORT_DIR) \ + -I$(LIBWWW_TRANSPORT_DIR) \ + +BASIC_INCLUDES = -Isrcdir/include -Iblddir -Isrcdir \ + -Isrcdir/lib/util/include + +ifeq ($(SHARED_LIB_TYPE),unix) + include unix.make + endif + +ifeq ($(SHARED_LIB_TYPE),irix) + include irix.make + endif + +ifeq ($(SHARED_LIB_TYPE),dll) + include dll.make + endif + +ifeq ($(SHARED_LIB_TYPE),dylib) + include dylib.make + endif + +ifneq ($(SHARED_LIB_TYPE),NONE) + TARGET_SHARED_LIBRARIES = $(TARGET_LIBRARY_NAMES:%=%.$(SHLIB_SUFFIX)) + endif + +TARGET_STATIC_LIBRARIES = $(TARGET_LIBRARY_NAMES:%=%.a) + +TARGET_LIBRARIES = $(TARGET_STATIC_LIBRARIES) $(ALL_SHARED_LIBRARIES) + +all: $(TARGET_LIBRARIES) + +libxmlrpc_cpp.a: XmlRpcCpp.o + -rm -f $@ + $(AR) cru $@ $^ + $(RANLIB) $@ + +libxmlrpc++.a: $(LIBXMLRPCPP_OBJS) + -rm -f $@ + $(AR) cru $@ $^ + $(RANLIB) $@ + +libxmlrpc_server++.a: $(LIBXMLRPC_SERVERPP_OBJS) + -rm -f $@ + $(AR) cru $@ $^ + $(RANLIB) $@ + +libxmlrpc_server_abyss++.a: $(LIBXMLRPC_SERVER_ABYSSPP_OBJS) + -rm -f $@ + $(AR) cru $@ $^ + $(RANLIB) $@ + +libxmlrpc_client++.a: $(LIBXMLRPC_CLIENTPP_OBJS) + -rm -f $@ + $(AR) cru $@ $^ + $(RANLIB) $@ + +#----------------------------------------------------------------------------- +# RULES TO COMPILE OBJECT MODULES FOR LIBRARIES +#----------------------------------------------------------------------------- + +CXXFLAGS = $(CXXFLAGS_COMMON) $(CFLAGS_PERSONAL) $(CADD) + +XmlRpcCpp.o:%.o:%.cpp + $(CXX) -c $(BASIC_INCLUDES) $(CXXFLAGS) $< + +$(LIBXMLRPCPP_OBJS):%.o:%.cpp + $(CXX) -c $(BASIC_INCLUDES) $(CXXFLAGS) $< + +SERVER_INCLUDES = $(BASIC_INCLUDES) $(LIBXML_INCLUDES) + +$(LIBXMLRPC_SERVERPP_OBJS):%.o:%.cpp + $(CXX) -c $(SERVER_INCLUDES) $(CXXFLAGS) $< + +SERVER_ABYSS_INCLUDES = $(SERVER_INCLUDES) -Isrcdir/lib/abyss/src + +$(LIBXMLRPC_SERVER_ABYSSPP_OBJS):%.o:%.cpp + $(CXX) -c $(SERVER_ABYSS_INCLUDES) $(CXXFLAGS) $< + +CLIENT_INCLUDES = $(BASIC_INCLUDES) $(LIBXML_INCLUDES) $(TRANSPORT_INCLUDES) + +$(LIBXMLRPC_CLIENTPP_OBJS):%.o:%.cpp + $(CXX) -c $(CLIENT_INCLUDES) $(CXXFLAGS) $< + +client.o curl.o libwww.o wininet.o: $(BUILDDIR)/transport_config.h + +#----------------------------------------------------------------------------- +# MISCELLANEOUS RULES +#----------------------------------------------------------------------------- + +check: + $(MAKE) -C test runtests + +.PHONY: install +install: install-common + +.PHONY: clean clean-local distclean distclean-local +clean: clean-common clean-local +clean-local: + $(MAKE) -C test clean + +distclean: clean distclean-local distclean-common + +distclean-local: + $(MAKE) -C test distclean + +.PHONY: dep +dep: dep-common $(BUILDDIR)/transport_config.h + +include Makefile.depend diff --git a/src/cpp/Makefile.depend b/src/cpp/Makefile.depend new file mode 100644 index 0000000..e69de29 diff --git a/src/cpp/XmlRpcCpp.cpp b/src/cpp/XmlRpcCpp.cpp new file mode 100644 index 0000000..4226a2d --- /dev/null +++ b/src/cpp/XmlRpcCpp.cpp @@ -0,0 +1,395 @@ +// Copyright (C) 2001 by Eric Kidd. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// 3. The name of the author may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +// OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +// OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +// SUCH DAMAGE. + + +#include +#include + +#include "xmlrpc-c/oldcppwrapper.hpp" + +using std::string; + +//========================================================================= +// XmlRpcFault Methods +//========================================================================= + +XmlRpcFault::XmlRpcFault (const XmlRpcFault &fault) { + xmlrpc_env_init(&mFault); + xmlrpc_env_set_fault(&mFault, + fault.mFault.fault_code, + fault.mFault.fault_string); +} + +XmlRpcFault::XmlRpcFault (const int faultCode, const string faultString) { + xmlrpc_env_init(&mFault); + xmlrpc_env_set_fault(&mFault, faultCode, + const_cast(faultString.c_str())); +} + +XmlRpcFault::XmlRpcFault (const xmlrpc_env *env) { + if (!env->fault_string) + throw XmlRpcFault(XMLRPC_INTERNAL_ERROR, + "Tried to create empty fault"); + xmlrpc_env_init(&mFault); + xmlrpc_env_set_fault(&mFault, env->fault_code, + const_cast(env->fault_string)); +} + +XmlRpcFault::~XmlRpcFault (void) { + xmlrpc_env_clean(&mFault); +} + +string XmlRpcFault::getFaultString (void) const { + XMLRPC_ASSERT(mFault.fault_occurred); + return string(mFault.fault_string); +} + + +//========================================================================= +// XmlRpcEnv Methods +//========================================================================= + +XmlRpcEnv::XmlRpcEnv (const XmlRpcEnv &env) { + xmlrpc_env_init(&mEnv); + if (env.hasFaultOccurred()) + xmlrpc_env_set_fault(&mEnv, + env.mEnv.fault_code, + env.mEnv.fault_string); +} + +XmlRpcFault XmlRpcEnv::getFault (void) const { + return XmlRpcFault(&mEnv); +} + +void XmlRpcEnv::throwMe (void) const { + throw XmlRpcFault(&mEnv); +} + + +//========================================================================= +// XmlRpcValue Methods +//========================================================================= + +// If the user doesn't tell us what kind of value to create, use +// a false boolean value as the default. +XmlRpcValue::XmlRpcValue (void) { + XmlRpcEnv env; + mValue = xmlrpc_build_value(env, "b", (xmlrpc_bool) 0); + env.throwIfFaultOccurred(); +} + +XmlRpcValue XmlRpcValue::makeInt (const XmlRpcValue::int32 i) { + XmlRpcEnv env; + xmlrpc_value *value = xmlrpc_build_value(env, "i", i); + env.throwIfFaultOccurred(); + return XmlRpcValue(value, CONSUME_REFERENCE); +} + +XmlRpcValue XmlRpcValue::makeBool (const bool b) { + XmlRpcEnv env; + xmlrpc_value *value = xmlrpc_build_value(env, "b", (xmlrpc_bool) b); + env.throwIfFaultOccurred(); + return XmlRpcValue(value, CONSUME_REFERENCE); +} + +XmlRpcValue XmlRpcValue::makeDouble (const double d) { + XmlRpcEnv env; + xmlrpc_value *value = xmlrpc_build_value(env, "d", d); + env.throwIfFaultOccurred(); + return XmlRpcValue(value, CONSUME_REFERENCE); +} + +XmlRpcValue XmlRpcValue::makeDateTime (const string& dateTime) { + XmlRpcEnv env; + xmlrpc_value *value; + const char *data = dateTime.c_str(); // Make sure we're not using wchar_t. + value = xmlrpc_build_value(env, "8", data); + env.throwIfFaultOccurred(); + return XmlRpcValue(value, CONSUME_REFERENCE); +} + +XmlRpcValue XmlRpcValue::makeString (const string& str) { + XmlRpcEnv env; + const char *data = str.data(); // Make sure we're not using wchar_t. + size_t size = str.size(); + xmlrpc_value *value = xmlrpc_build_value(env, "s#", data, size); + env.throwIfFaultOccurred(); + return XmlRpcValue(value, CONSUME_REFERENCE); +} + +XmlRpcValue XmlRpcValue::makeString (const char *const str) { + XmlRpcEnv env; + xmlrpc_value *value = xmlrpc_build_value(env, "s", str); + env.throwIfFaultOccurred(); + return XmlRpcValue(value, CONSUME_REFERENCE); +} + +XmlRpcValue XmlRpcValue::makeString (const char *const str, size_t len) { + XmlRpcEnv env; + xmlrpc_value *value = xmlrpc_build_value(env, "s#", str, len); + env.throwIfFaultOccurred(); + return XmlRpcValue(value, CONSUME_REFERENCE); +} + +XmlRpcValue XmlRpcValue::makeArray (void) { + XmlRpcEnv env; + xmlrpc_value *value = xmlrpc_build_value(env, "()"); + env.throwIfFaultOccurred(); + return XmlRpcValue(value, CONSUME_REFERENCE); +} + +XmlRpcValue XmlRpcValue::makeStruct (void) { + XmlRpcEnv env; + xmlrpc_value *value = xmlrpc_struct_new(env); + env.throwIfFaultOccurred(); + return XmlRpcValue(value, CONSUME_REFERENCE); +} + +XmlRpcValue XmlRpcValue::makeBase64 (const unsigned char *const data, + size_t len) +{ + XmlRpcEnv env; + xmlrpc_value *value = xmlrpc_build_value(env, "6", data, len); + env.throwIfFaultOccurred(); + return XmlRpcValue(value, CONSUME_REFERENCE); +} + +XmlRpcValue::int32 XmlRpcValue::getInt (void) const { + XmlRpcEnv env; + XmlRpcValue::int32 result; + xmlrpc_parse_value(env, mValue, "i", &result); + env.throwIfFaultOccurred(); + return result; +} + +bool XmlRpcValue::getBool (void) const { + XmlRpcEnv env; + xmlrpc_bool result; + xmlrpc_parse_value(env, mValue, "b", &result); + env.throwIfFaultOccurred(); + return result; +} + +double XmlRpcValue::getDouble (void) const { + XmlRpcEnv env; + double result; + xmlrpc_parse_value(env, mValue, "d", &result); + env.throwIfFaultOccurred(); + return result; +} + +string XmlRpcValue::getRawDateTime (void) const { + XmlRpcEnv env; + char *result; + xmlrpc_parse_value(env, mValue, "8", &result); + env.throwIfFaultOccurred(); + return string(result); +} + +string XmlRpcValue::getString (void) const { + XmlRpcEnv env; + char *result; + size_t result_len; + xmlrpc_parse_value(env, mValue, "s#", &result, &result_len); + env.throwIfFaultOccurred(); + return string(result, result_len); + +} + +XmlRpcValue XmlRpcValue::getArray (void) const { + XmlRpcEnv env; + xmlrpc_value *result; + xmlrpc_parse_value(env, mValue, "A", &result); + env.throwIfFaultOccurred(); + return XmlRpcValue(result); +} + +XmlRpcValue XmlRpcValue::getStruct (void) const { + XmlRpcEnv env; + xmlrpc_value *result; + xmlrpc_parse_value(env, mValue, "S", &result); + env.throwIfFaultOccurred(); + return XmlRpcValue(result); +} + +void XmlRpcValue::getBase64 (const unsigned char *& out_data, + size_t& out_len) const +{ + XmlRpcEnv env; + xmlrpc_parse_value(env, mValue, "6", &out_data, &out_len); + env.throwIfFaultOccurred(); +} + +size_t XmlRpcValue::arraySize (void) const { + XmlRpcEnv env; + size_t result = xmlrpc_array_size(env, mValue); + env.throwIfFaultOccurred(); + return result; +} + +void XmlRpcValue::arrayAppendItem (const XmlRpcValue& value) { + XmlRpcEnv env; + xmlrpc_array_append_item(env, mValue, value.borrowReference()); + env.throwIfFaultOccurred(); +} + +XmlRpcValue XmlRpcValue::arrayGetItem (int index) const { + XmlRpcEnv env; + xmlrpc_value *result = xmlrpc_array_get_item(env, mValue, index); + env.throwIfFaultOccurred(); + return XmlRpcValue(result); +} + +size_t XmlRpcValue::structSize (void) const { + XmlRpcEnv env; + size_t result = xmlrpc_struct_size(env, mValue); + env.throwIfFaultOccurred(); + return result; +} + +bool XmlRpcValue::structHasKey (const string& key) const { + XmlRpcEnv env; + const char *keystr = key.data(); + size_t keylen = key.size(); + bool result = xmlrpc_struct_has_key_n(env, mValue, + const_cast(keystr), keylen); + env.throwIfFaultOccurred(); + return result; +} + +XmlRpcValue XmlRpcValue::structGetValue (const string& key) const { + XmlRpcEnv env; + const char *keystr = key.data(); + size_t keylen = key.size(); + xmlrpc_value *result = + xmlrpc_struct_get_value_n(env, mValue, + const_cast(keystr), keylen); + env.throwIfFaultOccurred(); + return XmlRpcValue(result); +} + +void XmlRpcValue::structSetValue (const string& key, const XmlRpcValue& value) +{ + XmlRpcEnv env; + const char *keystr = key.data(); + size_t keylen = key.size(); + xmlrpc_struct_set_value_n(env, mValue, (char*) keystr, keylen, + value.borrowReference()); + env.throwIfFaultOccurred(); +} + +void XmlRpcValue::structGetKeyAndValue (const int index, + string& out_key, + XmlRpcValue& out_value) const +{ + XmlRpcEnv env; + + xmlrpc_value *key, *value; + xmlrpc_struct_get_key_and_value(env, mValue, index, &key, &value); + env.throwIfFaultOccurred(); + + out_key = XmlRpcValue(key).getString(); + out_value = XmlRpcValue(value); +} + +XmlRpcGenSrv& XmlRpcGenSrv::addMethod (const string& name, + xmlrpc_method method, + void *data) +{ + XmlRpcEnv env; + + xmlrpc_registry_add_method (env, mRegistry, NULL, + name.c_str (), + method, data); + + env.throwIfFaultOccurred (); + return (*this); +} + +XmlRpcGenSrv& XmlRpcGenSrv::addMethod (const string& name, + xmlrpc_method method, + void* data, + const string& signature, + const string& help) +{ + XmlRpcEnv env; + + xmlrpc_registry_add_method_w_doc (env, mRegistry, NULL, + name.c_str (), + method, data, + signature.c_str (), + help.c_str ()); + + env.throwIfFaultOccurred (); + return (*this); +} + +xmlrpc_mem_block* XmlRpcGenSrv::alloc (XmlRpcEnv& env, const string& body) const +{ + xmlrpc_mem_block* result = NULL; + char* contents; + + result = xmlrpc_mem_block_new (env, body.length ()); + env.throwIfFaultOccurred (); + + contents = XMLRPC_TYPED_MEM_BLOCK_CONTENTS(char, result); + + memcpy (contents, body.c_str (), body.length ()); + return result; +} + +string XmlRpcGenSrv::handle (const string& body) const +{ + XmlRpcEnv env; + string result; + xmlrpc_mem_block* input = NULL, * output = NULL; + char* input_data, * output_data; + size_t input_size, output_size; + + if (body.length () > xmlrpc_limit_get (XMLRPC_XML_SIZE_LIMIT_ID)) + throw XmlRpcFault (XMLRPC_LIMIT_EXCEEDED_ERROR, "XML-RPC request too large"); + + input = alloc (env, body); + input_data = XMLRPC_TYPED_MEM_BLOCK_CONTENTS(char, input); + input_size = XMLRPC_TYPED_MEM_BLOCK_SIZE(char, input); + + output = xmlrpc_registry_process_call (env, mRegistry, NULL, + input_data, input_size); + + if (output) + { + output_data = XMLRPC_TYPED_MEM_BLOCK_CONTENTS(char, output); + output_size = XMLRPC_TYPED_MEM_BLOCK_SIZE(char, output); + + result.assign (output_data, output_size); + xmlrpc_mem_block_free (output); + } + + xmlrpc_mem_block_free (input); + if (!result.length ()) + throw XmlRpcFault (env); + + return result; +} diff --git a/src/cpp/base64.cpp b/src/cpp/base64.cpp new file mode 100644 index 0000000..f9c0dac --- /dev/null +++ b/src/cpp/base64.cpp @@ -0,0 +1,234 @@ +#include +#include +#include +#include + +#include "xmlrpc-c/girerr.hpp" +using girerr::error; +using girerr::throwf; +#include "xmlrpc-c/base64.hpp" + +using namespace std; +using namespace xmlrpc_c; + + +namespace { + +char const table_a2b_base64[] = { + -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, + -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, + -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,62, -1,-1,-1,63, + 52,53,54,55, 56,57,58,59, 60,61,-1,-1, -1, 0,-1,-1, /* Note PAD->0 */ + -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10, 11,12,13,14, + 15,16,17,18, 19,20,21,22, 23,24,25,-1, -1,-1,-1,-1, + -1,26,27,28, 29,30,31,32, 33,34,35,36, 37,38,39,40, + 41,42,43,44, 45,46,47,48, 49,50,51,-1, -1,-1,-1,-1 +}; + +char const base64Pad('='); +size_t const base64MaxChunkSize(57); + // Max binary chunk size (76 character line) +#define BASE64_LINE_SZ 128 /* Buffer size for a single line. */ + +unsigned char const table_b2a_base64[] = + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + +} // namespace + + + +class bitBuffer { +public: + bitBuffer() : bitsInBuffer(0) {}; + + void + shiftIn8Bits(unsigned char const newBits) { + // Shift in 8 bits to the right end of the buffer + + this->buffer = (this->buffer << 8) | newBits; + this->bitsInBuffer += 8; + + assert(this->bitsInBuffer <= 12); + } + + void + shiftIn6Bits(unsigned char const newBits) { + // Shift in 6 bits to the right end of the buffer + + this->buffer = (this->buffer << 6) | newBits; + this->bitsInBuffer += 6; + + assert(this->bitsInBuffer <= 12); + } + + void + shiftOut6Bits(unsigned char * const outputP) { + // Shift out 6 bits from the left end of the buffer + + assert(bitsInBuffer >= 6); + + *outputP = (this->buffer >> (this->bitsInBuffer - 6)) & 0x3f; + this->bitsInBuffer -= 6; + } + + void + shiftOut8Bits(unsigned char * const outputP) { + // Shift out 8 bits from the left end of the buffer + + assert(bitsInBuffer >= 8); + + *outputP = (this->buffer >> (this->bitsInBuffer - 8)) & 0x3f; + this->bitsInBuffer -= 8; + } + + void + shiftOutResidue(unsigned char * const outputP) { + // Shift out the residual 2 or 4 bits, padded on the right with 0 + // to 6 bits. + + while (this->bitsInBuffer < 6) { + this->buffer <<= 2; + this->bitsInBuffer += 2; + } + + this->shiftOut6Bits(outputP); + } + + void + discardResidue() { + assert(bitsInBuffer < 8); + + this->bitsInBuffer = 0; + } + + unsigned int + bitCount() { + return bitsInBuffer; + } + +private: + unsigned int buffer; + unsigned int bitsInBuffer; +}; + + +namespace xmlrpc_c { + + +static void +encodeChunk(vector const& bytes, + size_t const lineStart, + size_t const chunkSize, + string * const outputP) { + + bitBuffer buffer; + // A buffer in which we accumulate bits (up to 12 bits) + // until we have enough (6) for a base64 character. + + // I suppose this would be more efficient with an iterator on + // 'bytes' and/or *outputP. I'd have to find out how to use one. + + for (size_t linePos = 0; linePos < chunkSize; ++linePos) { + // Shift the data into our buffer + buffer.shiftIn8Bits(bytes[lineStart + linePos]); + + // Encode any complete 6 bit groups + while (buffer.bitCount() >= 6) { + unsigned char theseBits; + buffer.shiftOut6Bits(&theseBits); + outputP->append(1, table_b2a_base64[theseBits]); + } + } + if (buffer.bitCount() > 0) { + // Handle residual bits in the buffer + unsigned char theseBits; + buffer.shiftOutResidue(&theseBits); + + outputP->append(1, table_b2a_base64[theseBits]); + + // Pad to a multiple of 4 characters (24 bits) + assert(outputP->length() % 4 > 0); + outputP->append(4-outputP->length() % 4, base64Pad); + } else { + assert(outputP->length() % 4 == 0); + } +} + + + +string +base64FromBytes(vector const& bytes, + newlineCtl const newlineCtl) { + + string retval; + + if (bytes.size() == 0) { + if (newlineCtl == NEWLINE_YES) + retval = "\r\n"; + else + retval = ""; + } else { + // It would be good to preallocate retval. Need to look up + // how to do that. + for (size_t chunkStart = 0; + chunkStart < bytes.size(); + chunkStart += base64MaxChunkSize) { + + size_t const chunkSize( + min(base64MaxChunkSize, bytes.size() - chunkStart)); + + encodeChunk(bytes, chunkStart, chunkSize, &retval); + + if (newlineCtl == NEWLINE_YES) + // Append a courtesy crlf + retval += "\r\n"; + } + } + return retval; +} + + + +vector +bytesFromBase64(string const& base64) { + + vector retval; + bitBuffer buffer; + unsigned int npad; + + npad = 0; // No pad characters seen yet + + for (unsigned int cursor = 0; cursor < base64.length(); ++cursor) { + char const thisChar(base64[cursor] & 0x7f); + + if (thisChar == '\r' || thisChar == '\n' || thisChar == ' ') { + // ignore this punctuation + } else { + if (thisChar == base64Pad) { + // This pad character is here to synchronize a chunk to + // a multiple of 24 bits (4 base64 characters; 3 bytes). + buffer.discardResidue(); + } else { + unsigned int const tableIndex(thisChar); + if (table_a2b_base64[tableIndex] == -1) + throwf("Contains non-base64 character " + "with ASCII code 0x%02x", thisChar); + + buffer.shiftIn6Bits(table_a2b_base64[tableIndex]); + + if (buffer.bitCount() >= 8) { + unsigned char thisByte; + buffer.shiftOut8Bits(&thisByte); + retval.push_back(thisByte); + } + } + } + } + + if (buffer.bitCount() > 0) + throwf("Not a multiple of 4 characters"); + + return retval; +} + +} //namespace diff --git a/src/cpp/client.cpp b/src/cpp/client.cpp new file mode 100644 index 0000000..50d8695 --- /dev/null +++ b/src/cpp/client.cpp @@ -0,0 +1,962 @@ +/*============================================================================= + client.cpp +=============================================================================== + This is the C++ XML-RPC client library for Xmlrpc-c. + + Note that unlike most of Xmlprc-c's C++ API, this is _not_ based on the + C client library. This code is independent of the C client library, and + is based directly on the client XML transport libraries (with a little + help from internal C utility libraries). +=============================================================================*/ + +#include +#include +#include +#include + +#include "xmlrpc-c/girerr.hpp" +using girerr::error; +using girerr::throwf; +#include "xmlrpc-c/girmem.hpp" +using girmem::autoObjectPtr; +using girmem::autoObject; +#include "env_wrap.hpp" +#include "xmlrpc-c/base.h" +#include "xmlrpc-c/client.h" +#include "xmlrpc-c/transport.h" +#include "xmlrpc-c/base.hpp" +#include "xmlrpc-c/xml.hpp" +#include "xmlrpc-c/client.hpp" +#include "transport_config.h" + +using namespace std; +using namespace xmlrpc_c; + + +namespace { + +void +throwIfError(env_wrap const& env) { + + if (env.env_c.fault_occurred) + throw(error(env.env_c.fault_string)); +} + + + +class memblockStringWrapper { + +public: + memblockStringWrapper(string const value) { + + env_wrap env; + + this->memblockP = XMLRPC_MEMBLOCK_NEW(char, &env.env_c, 0); + throwIfError(env); + + XMLRPC_MEMBLOCK_APPEND(char, &env.env_c, this->memblockP, + value.c_str(), value.size()); + throwIfError(env); + } + + memblockStringWrapper(xmlrpc_mem_block * const memblockP) : + memblockP(memblockP) {}; + + ~memblockStringWrapper() { + XMLRPC_MEMBLOCK_FREE(char, this->memblockP); + } + + xmlrpc_mem_block * memblockP; +}; + +} // namespace + +namespace xmlrpc_c { + +carriageParm::carriageParm() {} + + + +carriageParm::~carriageParm() {} + + + +carriageParmPtr::carriageParmPtr() { + // Base class constructor will construct pointer that points to nothing +} + + + +carriageParmPtr::carriageParmPtr( + carriageParm * const carriageParmP) { + this->point(carriageParmP); +} + + + +carriageParm * +carriageParmPtr::operator->() const { + + autoObject * const p(this->objectP); + return dynamic_cast(p); +} + + + +carriageParm * +carriageParmPtr::get() const { + return dynamic_cast(objectP); +} + + + +carriageParm_http0::carriageParm_http0() : + c_serverInfoP(NULL) {} + + + +carriageParm_http0::carriageParm_http0(string const serverUrl) { + this->c_serverInfoP = NULL; + + this->instantiate(serverUrl); +} + + + +carriageParm_http0::~carriageParm_http0() { + + if (this->c_serverInfoP) + xmlrpc_server_info_free(this->c_serverInfoP); +} + + + +void +carriageParm_http0::instantiate(string const serverUrl) { + + if (c_serverInfoP) + throw(error("object already instantiated")); + + env_wrap env; + + this->c_serverInfoP = + xmlrpc_server_info_new(&env.env_c, serverUrl.c_str()); + throwIfError(env); +} + + + +void +carriageParm_http0::setBasicAuth(string const username, + string const password) { + + if (!c_serverInfoP) + throw(error("object not instantiated")); + + env_wrap env; + + xmlrpc_server_info_set_basic_auth( + &env.env_c, this->c_serverInfoP, username.c_str(), password.c_str()); + throwIfError(env); +} + + + +carriageParm_http0Ptr::carriageParm_http0Ptr() { + // Base class constructor will construct pointer that points to nothing +} + + + +carriageParm_http0Ptr::carriageParm_http0Ptr( + carriageParm_http0 * const carriageParmP) { + this->point(carriageParmP); +} + + + +carriageParm_http0 * +carriageParm_http0Ptr::operator->() const { + + autoObject * const p(this->objectP); + return dynamic_cast(p); +} + + + +xmlTransaction::xmlTransaction() {} + + + +void +xmlTransaction::finish(string const& responseXml) const { + + xml::trace("XML-RPC RESPONSE", responseXml); +} + + + +void +xmlTransaction::finishErr(error const&) const { + +} + + + +xmlTransactionPtr::xmlTransactionPtr() {} + + + +xmlTransaction * +xmlTransactionPtr::operator->() const { + autoObject * const p(this->objectP); + return dynamic_cast(p); +} + + + +struct xmlTranCtl { +/*---------------------------------------------------------------------------- + This contains information needed to conduct a transaction. You + construct it as you start the transaction and destroy it after the + work is done. You need this only for an asynchronous one, because + where the user starts and finishes the RPC in the same + libxmlrpc_client call, you can just keep this information in + various stack variables, and it's faster and easier to understand + that way. + + The C transport is designed to take a xmlrpc_call_info argument for + similar stuff needed by the the C client object. But it's really + opaque to the transport, so we just let xmlTranCtl masquerade as + xmlprc_call_info in our call to the C transport. +-----------------------------------------------------------------------------*/ + xmlTranCtl(xmlTransactionPtr const& xmlTranP, + string const& callXml) : + + xmlTranP(xmlTranP) { + + env_wrap env; + + this->callXmlP = XMLRPC_MEMBLOCK_NEW(char, &env.env_c, 0); + throwIfError(env); + + XMLRPC_MEMBLOCK_APPEND(char, &env.env_c, this->callXmlP, + callXml.c_str(), callXml.size()); + throwIfError(env); + } + + ~xmlTranCtl() { + XMLRPC_MEMBLOCK_FREE(char, this->callXmlP); + } + + xmlTransactionPtr const xmlTranP; + // The transaction we're controlling. Most notable use of this is + // that this object we inform when the transaction is done. This + // is where the response XML and other transaction results go. + + xmlrpc_mem_block * callXmlP; + // The XML of the call. This is what the transport transports. +}; + + + +clientXmlTransport::~clientXmlTransport() {} + + + +void +clientXmlTransport::start(carriageParm * const carriageParmP, + string const& callXml, + xmlTransactionPtr const& xmlTranP) { + + string responseXml; + + this->call(carriageParmP, callXml, &responseXml); + + xmlTranP->finish(responseXml); +} + + + +void +clientXmlTransport::finishAsync(xmlrpc_c::timeout const timeout) { + if (timeout.finite == timeout.finite) + throw(error("This class does not have finishAsync()")); +} + + + +void +clientXmlTransport::asyncComplete( + struct xmlrpc_call_info * const callInfoP, + xmlrpc_mem_block * const responseXmlMP, + xmlrpc_env const transportEnv) { + + xmlTranCtl * const xmlTranCtlP = reinterpret_cast(callInfoP); + + try { + if (transportEnv.fault_occurred) { + xmlTranCtlP->xmlTranP->finishErr(error(transportEnv.fault_string)); + } else { + string const responseXml( + XMLRPC_MEMBLOCK_CONTENTS(char, responseXmlMP), + XMLRPC_MEMBLOCK_SIZE(char, responseXmlMP)); + xmlTranCtlP->xmlTranP->finish(responseXml); + } + } catch(error) { + /* We can't throw an error back to C code, and the async_complete + interface does not provide for failure, so we define ->finish() + as not being capable of throwing an error. + */ + assert(false); + } + delete(xmlTranCtlP); + + /* Ordinarily, *xmlTranCtlP is the last reference to + xmlTranCtlP->xmlTranP, so that will get destroyed too. But + ->finish() could conceivably create a new reference to + xmlTranCtlP->xmlTranP, and then it would keep living. + */ +} + + + +clientXmlTransportPtr::clientXmlTransportPtr() { + // Base class constructor will construct pointer that points to nothing +} + + + +clientXmlTransportPtr::clientXmlTransportPtr( + clientXmlTransport * const transportP) { + this->point(transportP); +} + + + +clientXmlTransport * +clientXmlTransportPtr::get() const { + return dynamic_cast(objectP); +} + + + +clientXmlTransport * +clientXmlTransportPtr::operator->() const { + + autoObject * const p(this->objectP); + return dynamic_cast(p); +} + + + +clientXmlTransport_http::~clientXmlTransport_http() {} + + + +void +clientXmlTransport_http::call( + carriageParm * const carriageParmP, + string const& callXml, + string * const responseXmlP) { + + carriageParm_http0 * const carriageParmHttpP = + dynamic_cast(carriageParmP); + + if (carriageParmHttpP == NULL) + throw(error("HTTP client XML transport called with carriage " + "parameter object not of class carriageParm_http")); + + memblockStringWrapper callXmlM(callXml); + + xmlrpc_mem_block * responseXmlMP; + + env_wrap env; + + this->c_transportOpsP->call(&env.env_c, + this->c_transportP, + carriageParmHttpP->c_serverInfoP, + callXmlM.memblockP, + &responseXmlMP); + + throwIfError(env); + + memblockStringWrapper responseHolder(responseXmlMP); + // Makes responseXmlMP get freed at end of scope + + *responseXmlP = string(XMLRPC_MEMBLOCK_CONTENTS(char, responseXmlMP), + XMLRPC_MEMBLOCK_SIZE(char, responseXmlMP)); +} + + + +void +clientXmlTransport_http::start( + carriageParm * const carriageParmP, + string const& callXml, + xmlTransactionPtr const& xmlTranP) { + + env_wrap env; + + carriageParm_http0 * const carriageParmHttpP = + dynamic_cast(carriageParmP); + + if (carriageParmHttpP == NULL) + throw(error("HTTP client XML transport called with carriage " + "parameter object not of type carriageParm_http")); + + xmlTranCtl * const tranCtlP(new xmlTranCtl(xmlTranP, callXml)); + + try { + this->c_transportOpsP->send_request( + &env.env_c, + this->c_transportP, + carriageParmHttpP->c_serverInfoP, + tranCtlP->callXmlP, + &this->asyncComplete, + reinterpret_cast(tranCtlP)); + + throwIfError(env); + } catch (...) { + delete tranCtlP; + throw; + } +} + + + +void +clientXmlTransport_http::finishAsync(xmlrpc_c::timeout const timeout) { + + xmlrpc_timeoutType const c_timeoutType( + timeout.finite ? timeout_yes : timeout_no); + xmlrpc_timeout const c_timeout(timeout.duration); + + this->c_transportOpsP->finish_asynch( + this->c_transportP, c_timeoutType, c_timeout); +} + + +bool const haveCurl( +#if MUST_BUILD_CURL_CLIENT +true +#else +false +#endif +); + +bool const haveLibwww( +#if MUST_BUILD_LIBWWW_CLIENT +true +#else +false +#endif +); + +bool const haveWininet( +#if MUST_BUILD_WININET_CLIENT +true +#else +false +#endif +); + + + +vector +clientXmlTransport_http::availableTypes() { + + vector retval; + + if (haveCurl) + retval.push_back("curl"); + + if (haveLibwww) + retval.push_back("libwww"); + + if (haveWininet) + retval.push_back("wininet"); + + return retval; +} + + + +clientXmlTransportPtr +clientXmlTransport_http::create() { +/*---------------------------------------------------------------------------- + Make an HTTP Client XML transport of any kind (Caller doesn't care). + + Caller can find out what kind he got by trying dynamic casts. + + Caller can use a carriageParm_http0 with the transport. +-----------------------------------------------------------------------------*/ + if (haveCurl) + return clientXmlTransportPtr(new clientXmlTransport_curl()); + else if (haveLibwww) + return clientXmlTransportPtr(new clientXmlTransport_libwww()); + else if (haveWininet) + return clientXmlTransportPtr(new clientXmlTransport_wininet()); + else + throwf("This XML-RPC client library contains no HTTP XML transports"); +} + + + +clientTransaction::clientTransaction() {} + + + +clientTransactionPtr::clientTransactionPtr() {} + + + +clientTransactionPtr::~clientTransactionPtr() {} + + + +clientTransaction * +clientTransactionPtr::operator->() const { + autoObject * const p(this->objectP); + return dynamic_cast(p); +} + + + +client::~client() {} + + + +void +client::start(carriageParm * const carriageParmP, + string const& methodName, + paramList const& paramList, + clientTransactionPtr const& tranP) { +/*---------------------------------------------------------------------------- + Start an RPC, wait for it to complete, and finish it. + + Usually, a derived class overrides this with something that does + not wait for the RPC to complete, but rather arranges for something + to finish the RPC later when the RPC does complete. +-----------------------------------------------------------------------------*/ + rpcOutcome outcome; + + this->call(carriageParmP, methodName, paramList, &outcome); + + tranP->finish(outcome); +} + + + +clientPtr::clientPtr() { + // Base class constructor will construct pointer that points to nothing +} + + + +clientPtr::clientPtr( + client * const clientP) { + this->point(clientP); +} + + + +client * +clientPtr::operator->() const { + + autoObject * const p(this->objectP); + return dynamic_cast(p); +} + + + +client * +clientPtr::get() const { + return dynamic_cast(objectP); +} + + + +client_xml::client_xml(clientXmlTransport * const transportP) : + transportP(transportP) {} + + + +client_xml::client_xml(clientXmlTransportPtr const transportPtr) { + + this->transportPtr = transportPtr; + this->transportP = transportPtr.get(); +} + + + +void +client_xml::call(carriageParm * const carriageParmP, + string const& methodName, + paramList const& paramList, + rpcOutcome * const outcomeP) { + + string callXml; + string responseXml; + + xml::generateCall(methodName, paramList, &callXml); + + xml::trace("XML-RPC CALL", callXml); + + try { + this->transportP->call(carriageParmP, callXml, &responseXml); + } catch (error const& error) { + throwf("Unable to transport XML to server and " + "get XML response back. %s", error.what()); + } + xml::trace("XML-RPC RESPONSE", responseXml); + + try { + xml::parseResponse(responseXml, outcomeP); + } catch (error const& error) { + throwf("Response XML from server is not valid XML-RPC response. %s", + error.what()); + } +} + + + +void +client_xml::start(carriageParm * const carriageParmP, + string const& methodName, + paramList const& paramList, + clientTransactionPtr const& tranP) { + + string callXml; + + xml::generateCall(methodName, paramList, &callXml); + + xml::trace("XML-RPC CALL", callXml); + + xmlTransaction_clientPtr const xmlTranP(tranP); + + this->transportP->start(carriageParmP, callXml, xmlTranP); +} + + + +void +client_xml::finishAsync(xmlrpc_c::timeout const timeout) { + + transportP->finishAsync(timeout); +} + + + +serverAccessor::serverAccessor(clientPtr const clientP, + carriageParmPtr const carriageParmP) : + + clientP(clientP), carriageParmP(carriageParmP) {}; + + + +void +serverAccessor::call(std::string const& methodName, + xmlrpc_c::paramList const& paramList, + xmlrpc_c::rpcOutcome * const outcomeP) const { + + this->clientP->call(this->carriageParmP.get(), + methodName, + paramList, + outcomeP); +} + + + +serverAccessorPtr::serverAccessorPtr() { + // Base class constructor will construct pointer that points to nothing +} + + + +serverAccessorPtr::serverAccessorPtr( + serverAccessor * const serverAccessorParmP) { + this->point(serverAccessorParmP); +} + + + +serverAccessor * +serverAccessorPtr::operator->() const { + + autoObject * const p(this->objectP); + return dynamic_cast(p); +} + + + +serverAccessor * +serverAccessorPtr::get() const { + return dynamic_cast(objectP); +} + + + +connection::connection(client * const clientP, + carriageParm * const carriageParmP) : + clientP(clientP), carriageParmP(carriageParmP) {} + + + +connection::~connection() {} + + + +rpc::rpc(string const methodName, + xmlrpc_c::paramList const& paramList) { + + this->state = STATE_UNFINISHED; + this->methodName = methodName; + this->paramList = paramList; +} + + + +rpc::~rpc() { + + if (this->state == STATE_ERROR) + delete(this->errorP); +} + + + +void +rpc::call(client * const clientP, + carriageParm * const carriageParmP) { + + if (this->state != STATE_UNFINISHED) + throw(error("Attempt to execute an RPC that has already been " + "executed")); + + clientP->call(carriageParmP, + this->methodName, + this->paramList, + &this->outcome); + + this->state = outcome.succeeded() ? STATE_SUCCEEDED : STATE_FAILED; +} + + + +void +rpc::call(connection const& connection) { + + this->call(connection.clientP, connection.carriageParmP); + +} + + + +void +rpc::start(client * const clientP, + carriageParm * const carriageParmP) { + + if (this->state != STATE_UNFINISHED) + throw(error("Attempt to execute an RPC that has already been " + "executed")); + + clientP->start(carriageParmP, + this->methodName, + this->paramList, + rpcPtr(this)); +} + + + +void +rpc::start(xmlrpc_c::connection const& connection) { + + this->start(connection.clientP, connection.carriageParmP); +} + + + +void +rpc::finish(rpcOutcome const& outcome) { + + this->state = outcome.succeeded() ? STATE_SUCCEEDED : STATE_FAILED; + + this->outcome = outcome; + + this->notifyComplete(); +} + + + +void +rpc::finishErr(error const& error) { + + this->state = STATE_ERROR; + this->errorP = new girerr::error(error); + this->notifyComplete(); +} + + + +void +rpc::notifyComplete() { +/*---------------------------------------------------------------------------- + Anyone who does RPCs asynchronously and doesn't use polling will + want to make his own class derived from 'rpc' and override this + with a notifyFinish() that does something. + + Typically, notifyFinish() will queue the RPC so some other thread + will deal with the fact that the RPC is finished. + + + In the absence of the aforementioned queueing, the RPC becomes + unreferenced as soon as our Caller releases his reference, so the + RPC gets destroyed when we return. +-----------------------------------------------------------------------------*/ + +} + + + +value +rpc::getResult() const { + + switch (this->state) { + case STATE_UNFINISHED: + throw(error("Attempt to get result of RPC that is not finished.")); + break; + case STATE_ERROR: + throw(*this->errorP); + break; + case STATE_FAILED: + throw(error("RPC response indicates failure. " + + this->outcome.getFault().getDescription())); + break; + case STATE_SUCCEEDED: { + // All normal + } + } + + return this->outcome.getResult(); +} + + + + +fault +rpc::getFault() const { + + switch (this->state) { + case STATE_UNFINISHED: + throw(error("Attempt to get fault from RPC that is not finished")); + break; + case STATE_ERROR: + throw(*this->errorP); + break; + case STATE_SUCCEEDED: + throw(error("Attempt to get fault from an RPC that succeeded")); + break; + case STATE_FAILED: { + // All normal + } + } + + return this->outcome.getFault(); +} + + + +bool +rpc::isFinished() const { + return (this->state != STATE_UNFINISHED); +} + + + +bool +rpc::isSuccessful() const { + return (this->state == STATE_SUCCEEDED); +} + + + +rpcPtr::rpcPtr() {} + + + +rpcPtr::rpcPtr(rpc * const rpcP) { + this->point(rpcP); +} + + + +rpcPtr::rpcPtr(string const methodName, + xmlrpc_c::paramList const& paramList) { + + this->point(new rpc(methodName, paramList)); +} + + + +rpc * +rpcPtr::operator->() const { + + autoObject * const p(this->objectP); + return dynamic_cast(p); +} + + + +xmlTransaction_client::xmlTransaction_client( + clientTransactionPtr const& tranP) : + tranP(tranP) {} + + + +void +xmlTransaction_client::finish(string const& responseXml) const { + + xml::trace("XML-RPC RESPONSE", responseXml); + + try { + rpcOutcome outcome; + + xml::parseResponse(responseXml, &outcome); + + this->tranP->finish(outcome); + } catch (error const& error) { + this->tranP->finishErr(error); + } +} + + + +void +xmlTransaction_client::finishErr(error const& error) const { + + this->tranP->finishErr(error); +} + + + +xmlTransaction_clientPtr::xmlTransaction_clientPtr() {} + + + +xmlTransaction_clientPtr::xmlTransaction_clientPtr( + clientTransactionPtr const& tranP) { + + this->point(new xmlTransaction_client(tranP)); +} + + + +xmlTransaction_client * +xmlTransaction_clientPtr::operator->() const { + autoObject * const p(this->objectP); + return dynamic_cast(p); +} + + + +} // namespace diff --git a/src/cpp/client_simple.cpp b/src/cpp/client_simple.cpp new file mode 100644 index 0000000..3387b9e --- /dev/null +++ b/src/cpp/client_simple.cpp @@ -0,0 +1,169 @@ +#include +#include + +#include "xmlrpc-c/girerr.hpp" +using girerr::error; +#include "env_wrap.hpp" +#include "xmlrpc-c/base.h" +#include "xmlrpc-c/base.hpp" +#include "xmlrpc-c/client.hpp" +#include + +#include "xmlrpc-c/client_simple.hpp" + +using namespace std; +using namespace xmlrpc_c; + +namespace xmlrpc_c { + + +namespace { + +void +throwIfError(env_wrap const& env) { + + if (env.env_c.fault_occurred) + throw(error(env.env_c.fault_string)); +} + + +class cValueWrapper { +/*---------------------------------------------------------------------------- + Use an object of this class to set up to remove a reference to an + xmlrpc_value object (a C object with manual reference management) + at then end of a scope -- even if the scope ends with a throw. +-----------------------------------------------------------------------------*/ + xmlrpc_value * valueP; +public: + cValueWrapper(xmlrpc_value * valueP) : valueP(valueP) {} + ~cValueWrapper() { xmlrpc_DECREF(valueP); } +}; + +} // namespace + + + +clientSimple::clientSimple() { + + clientXmlTransportPtr const transportP(clientXmlTransport_http::create()); + + this->clientP = clientPtr(new client_xml(transportP)); +} + + + +void +clientSimple::call(string const serverUrl, + string const methodName, + value * const resultP) { + + carriageParm_http0 carriageParm(serverUrl); + + rpcPtr rpcPtr(methodName, paramList()); + + rpcPtr->call(this->clientP.get(), &carriageParm); + + *resultP = rpcPtr->getResult(); +} + + +namespace { + +void +makeParamArray(string const format, + xmlrpc_value ** const paramArrayPP, + va_list args) { + + env_wrap env; + + /* The format is a sequence of parameter specifications, such as + "iiii" for 4 integer parameters. We add parentheses to make it + an array of those parameters: "(iiii)". + */ + string const arrayFormat("(" + string(format) + ")"); + const char * tail; + + xmlrpc_build_value_va(&env.env_c, arrayFormat.c_str(), + args, paramArrayPP, &tail); + + if (env.env_c.fault_occurred) + throw(error(env.env_c.fault_string)); + + if (strlen(tail) != 0) { + /* xmlrpc_build_value_va() parses off a single value specification + from its format string, and 'tail' points to whatever is after + it. Our format string should have been a single array value, + meaning tail is end-of-string. If it's not, that means + something closed our array early. + */ + xmlrpc_DECREF(*paramArrayPP); + throw(error("format string is invalid. It apparently has a " + "stray right parenthesis")); + } +} + +} // namespace + + +void +clientSimple::call(string const serverUrl, + string const methodName, + string const format, + value * const resultP, + ...) { + + carriageParm_http0 carriageParm(serverUrl); + + env_wrap env; + xmlrpc_value * paramArrayP; + + va_list args; + va_start(args, resultP); + makeParamArray(format, ¶mArrayP, args); + va_end(args); + + if (env.env_c.fault_occurred) + throw(error(env.env_c.fault_string)); + else { + cValueWrapper paramArrayWrapper(paramArrayP); // ensure destruction + unsigned int const paramCount( + xmlrpc_array_size(&env.env_c, paramArrayP)); + + if (env.env_c.fault_occurred) + throw(error(env.env_c.fault_string)); + + paramList paramList; + for (unsigned int i = 0; i < paramCount; ++i) { + xmlrpc_value * paramP; + xmlrpc_array_read_item(&env.env_c, paramArrayP, i, ¶mP); + if (env.env_c.fault_occurred) + throw(error(env.env_c.fault_string)); + else { + cValueWrapper paramWrapper(paramP); // ensure destruction + paramList.add(value(paramP)); + } + } + rpcPtr rpcPtr(methodName, paramList); + rpcPtr->call(this->clientP.get(), &carriageParm); + *resultP = rpcPtr->getResult(); + } +} + + + +void +clientSimple::call(string const serverUrl, + string const methodName, + paramList const& paramList, + value * const resultP) { + + carriageParm_http0 carriageParm(serverUrl); + + rpcPtr rpcPtr(methodName, paramList); + + rpcPtr->call(this->clientP.get(), &carriageParm); + + *resultP = rpcPtr->getResult(); +} + +} // namespace diff --git a/src/cpp/curl.cpp b/src/cpp/curl.cpp new file mode 100644 index 0000000..65e8cc3 --- /dev/null +++ b/src/cpp/curl.cpp @@ -0,0 +1,285 @@ +/*============================================================================= + curl.cpp +=============================================================================== + This is the Curl XML transport of the C++ XML-RPC client library for + Xmlrpc-c. + + Note that unlike most of Xmlprc-c's C++ API, this is _not_ based on the + C client library. This code is independent of the C client library, and + is based directly on the client XML transport libraries (with a little + help from internal C utility libraries). +=============================================================================*/ + +#include +#include +#include + +#include "xmlrpc-c/girerr.hpp" +using girerr::error; +using girerr::throwf; +#include "xmlrpc-c/girmem.hpp" +using girmem::autoObjectPtr; +using girmem::autoObject; +#include "env_wrap.hpp" +#include "xmlrpc-c/base.h" +#include "xmlrpc-c/client.h" +#include "xmlrpc-c/transport.h" +#include "xmlrpc-c/base_int.h" + +#include "xmlrpc_curl_transport.h" + +/* transport_config.h defines MUST_BUILD_CURL_CLIENT */ +#include "transport_config.h" + +#include "xmlrpc-c/client_transport.hpp" + + +using namespace std; +using namespace xmlrpc_c; + + + +namespace { + +class globalConstant { +public: + globalConstant(); + ~globalConstant(); +}; + + + +globalConstant::globalConstant() { + + // Not thread safe + + xmlrpc_transport_setup setupFn; + +#if MUST_BUILD_CURL_CLIENT + setupFn = xmlrpc_curl_transport_ops.setup_global_const; +#else + setupFn = NULL; +#endif + if (setupFn) { + env_wrap env; + + setupFn(&env.env_c); // Not thread safe + + if (env.env_c.fault_occurred) + throwf("Failed to do global initialization " + "of Curl transport code. %s", env.env_c.fault_string); + } +} + + + +globalConstant::~globalConstant() { + + // Not thread safe + + xmlrpc_transport_teardown teardownFn; + +#if MUST_BUILD_CURL_CLIENT + teardownFn = xmlrpc_curl_transport_ops.teardown_global_const; +#else + teardownFn = NULL; +#endif + if (teardownFn) + teardownFn(); // not thread safe +} + +globalConstant globalConst; + // This object is never accessed. Its whole purpose to to be born and + // to die, which it does automatically as part of C++ program + // program initialization and termination. + +} // namespace + + +namespace xmlrpc_c { + +carriageParm_curl0::carriageParm_curl0( + string const serverUrl + ) { + + this->instantiate(serverUrl); +} + + + +carriageParm_curl0Ptr::carriageParm_curl0Ptr() { + // Base class constructor will construct pointer that points to nothing +} + + + +carriageParm_curl0Ptr::carriageParm_curl0Ptr( + carriageParm_curl0 * const carriageParmP) { + this->point(carriageParmP); +} + + + +carriageParm_curl0 * +carriageParm_curl0Ptr::operator->() const { + + autoObject * const p(this->objectP); + return dynamic_cast(p); +} + + + +clientXmlTransport_curl::constrOpt::constrOpt() { + + present.network_interface = false; + present.no_ssl_verifypeer = false; + present.no_ssl_verifyhost = false; + present.user_agent = false; + present.ssl_cert = false; + present.sslcerttype = false; + present.sslcertpasswd = false; + present.sslkey = false; + present.sslkeytype = false; + present.sslkeypasswd = false; + present.sslengine = false; + present.sslengine_default = false; + present.sslversion = false; + present.cainfo = false; + present.capath = false; + present.randomfile = false; + present.egdsocket = false; + present.ssl_cipher_list = false; +} + + + +#define DEFINE_OPTION_SETTER(OPTION_NAME, TYPE) \ +clientXmlTransport_curl::constrOpt & \ +clientXmlTransport_curl::constrOpt::OPTION_NAME(TYPE const& arg) { \ + this->value.OPTION_NAME = arg; \ + this->present.OPTION_NAME = true; \ + return *this; \ +} + +DEFINE_OPTION_SETTER(network_interface, string); +DEFINE_OPTION_SETTER(no_ssl_verifypeer, bool); +DEFINE_OPTION_SETTER(no_ssl_verifyhost, bool); +DEFINE_OPTION_SETTER(user_agent, string); +DEFINE_OPTION_SETTER(ssl_cert, string); +DEFINE_OPTION_SETTER(sslcerttype, string); +DEFINE_OPTION_SETTER(sslcertpasswd, string); +DEFINE_OPTION_SETTER(sslkey, string); +DEFINE_OPTION_SETTER(sslkeytype, string); +DEFINE_OPTION_SETTER(sslkeypasswd, string); +DEFINE_OPTION_SETTER(sslengine, string); +DEFINE_OPTION_SETTER(sslengine_default, bool); +DEFINE_OPTION_SETTER(sslversion, xmlrpc_sslversion); +DEFINE_OPTION_SETTER(cainfo, string); +DEFINE_OPTION_SETTER(capath, string); +DEFINE_OPTION_SETTER(randomfile, string); +DEFINE_OPTION_SETTER(egdsocket, string); +DEFINE_OPTION_SETTER(ssl_cipher_list, string); + +#undef DEFINE_OPTION_SETTER + +#if MUST_BUILD_CURL_CLIENT + +void +clientXmlTransport_curl::initialize(constrOpt const& opt) { + struct xmlrpc_curl_xportparms transportParms; + + transportParms.network_interface = opt.present.network_interface ? + opt.value.network_interface.c_str() : NULL; + transportParms.no_ssl_verifypeer = opt.present.no_ssl_verifypeer ? + opt.value.no_ssl_verifypeer : false; + transportParms.no_ssl_verifyhost = opt.present.no_ssl_verifyhost ? + opt.value.no_ssl_verifyhost : false; + transportParms.user_agent = opt.present.user_agent ? + opt.value.user_agent.c_str() : NULL; + transportParms.ssl_cert = opt.present.ssl_cert ? + opt.value.ssl_cert.c_str() : NULL; + transportParms.sslcerttype = opt.present.sslcerttype ? + opt.value.sslcerttype.c_str() : NULL; + transportParms.sslcertpasswd = opt.present.sslcertpasswd ? + opt.value.sslcertpasswd.c_str() : NULL; + transportParms.sslkey = opt.present.sslkey ? + opt.value.sslkey.c_str() : NULL; + transportParms.sslkeytype = opt.present.sslkeytype ? + opt.value.sslkeytype.c_str() : NULL; + transportParms.sslkeypasswd = opt.present.sslkeypasswd ? + opt.value.sslkeypasswd.c_str() : NULL; + transportParms.sslengine = opt.present.sslengine ? + opt.value.sslengine.c_str() : NULL; + transportParms.sslengine_default = opt.present.sslengine_default ? + opt.value.sslengine_default : false; + transportParms.sslversion = opt.present.sslversion ? + opt.value.sslversion : XMLRPC_SSLVERSION_DEFAULT; + transportParms.cainfo = opt.present.cainfo ? + opt.value.cainfo.c_str() : NULL; + transportParms.capath = opt.present.capath ? + opt.value.capath.c_str() : NULL; + transportParms.randomfile = opt.present.randomfile ? + opt.value.randomfile.c_str() : NULL; + transportParms.egdsocket = opt.present.egdsocket ? + opt.value.egdsocket.c_str() : NULL; + transportParms.ssl_cipher_list = opt.present.ssl_cipher_list ? + opt.value.ssl_cipher_list.c_str() : NULL; + + this->c_transportOpsP = &xmlrpc_curl_transport_ops; + + env_wrap env; + + xmlrpc_curl_transport_ops.create( + &env.env_c, 0, "", "", (xmlrpc_xportparms *)&transportParms, + XMLRPC_CXPSIZE(ssl_cipher_list), + &this->c_transportP); + + if (env.env_c.fault_occurred) + throw(error(env.env_c.fault_string)); +} + +#else // MUST_BUILD_CURL_CLIENT + +void +clientXmlTransport_curl::initialize(constrOpt const& opt) { + + throw(error("There is no Curl client XML transport in this XML-RPC client " + "library")); +} + +#endif + +clientXmlTransport_curl::clientXmlTransport_curl(constrOpt const& opt) { + + this->initialize(opt); +} + + + +clientXmlTransport_curl::clientXmlTransport_curl( + string const networkInterface, + bool const noSslVerifyPeer, + bool const noSslVerifyHost, + string const userAgent) { + + clientXmlTransport_curl::constrOpt opt; + + if (networkInterface.size() > 0) + opt.network_interface(networkInterface); + opt.no_ssl_verifypeer(noSslVerifyPeer); + opt.no_ssl_verifyhost(noSslVerifyHost); + if (userAgent.size() > 0) + opt.user_agent(userAgent); + + this->initialize(opt); +} + + + +clientXmlTransport_curl::~clientXmlTransport_curl() { + + this->c_transportOpsP->destroy(this->c_transportP); +} + + +} // namespace diff --git a/src/cpp/dll.make b/src/cpp/dll.make new file mode 100644 index 0000000..46da433 --- /dev/null +++ b/src/cpp/dll.make @@ -0,0 +1,13 @@ +# -*-makefile-*- <-- an Emacs control + +# This is stuff for creating Windows DLLs (shared libraries). + +# This is to be included by 'Makefile'. Most of the make variables here +# come from the main make file. + + +$(SHLIB_PREFIX)libxmlrpc++$(DLLVER).dll: $(LIBXMLRPCPP_OBJS) + $(LD) $(LDSHLIB) -Wl,--export-all-symbols \ + -Wl,-soname,$@ \ + -Wl,--out-implib,libxmlrpc++.dll.a -o $@ $(LDFLAGS) \ + $^ $(LDLIBS) $(LADD) diff --git a/src/cpp/dylib.make b/src/cpp/dylib.make new file mode 100644 index 0000000..67e6fa8 --- /dev/null +++ b/src/cpp/dylib.make @@ -0,0 +1,21 @@ +# -*-makefile-*- <-- an Emacs control + +# This is stuff for creating Macintosh shared libraries. + +# This is to be included by 'Makefile'. Most of the make variables here +# come from the main make file. + + +TARGET_LINKNAMES = $(TARGET_LIBRARY_NAMES:%=%.dylib) +TARGET_SONAMES = $(TARGET_LIBRARY_NAMES:%=%.$(MAJ).dylib + +$(TARGET_LINKNAMES): %.dylib : %.$(MAJ).dylib + rm -f $@ + $(SYMLINK) $< $@ + +$(TARGET_SONAMES): %.dylib : %.$(MIN).dylib + rm -f $@ + $(SYMLINK) $< $@ + +libxmlrpc++.$(MAJ).$(MIN).dylib: $(LIBXMLRPCPP_OBJS) + $(LD) $(LDSHLIB) -o $@ $^ -lc $(LADD) diff --git a/src/cpp/env_wrap.cpp b/src/cpp/env_wrap.cpp new file mode 100644 index 0000000..2ca903f --- /dev/null +++ b/src/cpp/env_wrap.cpp @@ -0,0 +1,18 @@ +#include "xmlrpc-c/util.h" + +#include "env_wrap.hpp" + +namespace xmlrpc_c { + +env_wrap::env_wrap() { + xmlrpc_env_init(&this->env_c); +} + + + +env_wrap::~env_wrap() { + xmlrpc_env_clean(&this->env_c); +} + + +} // namespace diff --git a/src/cpp/env_wrap.hpp b/src/cpp/env_wrap.hpp new file mode 100644 index 0000000..0172f2b --- /dev/null +++ b/src/cpp/env_wrap.hpp @@ -0,0 +1,26 @@ +#ifndef ENV_INT_HPP_INCLUDED +#define ENV_INT_HPP_INCLUDED + +#include "xmlrpc-c/util.h" + +namespace xmlrpc_c { + +class env_wrap { +/*---------------------------------------------------------------------------- + A wrapper to assist in using the Xmlrpc-c C libraries in + Xmlrpc-c C++ code. + + To use the C libraries, you have to use type xmlrpc_env, but that type + does not have an automatic destructor (because it's C), so it's hard + to throw an error from a context in which a variable of that type + exists. This wrapper provides that automatic destructor. +-----------------------------------------------------------------------------*/ +public: + env_wrap(); + ~env_wrap(); + xmlrpc_env env_c; +}; + + +} // namespace +#endif diff --git a/src/cpp/fault.cpp b/src/cpp/fault.cpp new file mode 100644 index 0000000..4db6bc8 --- /dev/null +++ b/src/cpp/fault.cpp @@ -0,0 +1,35 @@ +#include + +#include "xmlrpc-c/girerr.hpp" +using girerr::error; +#include "xmlrpc-c/base.hpp" + +using namespace std; + +namespace xmlrpc_c { + +fault::fault() : valid(false) {}; + +fault::fault(string const _description, + xmlrpc_c::fault::code_t const _code + ) : + valid(true), + code(_code), + description(_description) + {} + +xmlrpc_c::fault::code_t +fault::getCode() const { + if (!valid) + throw(error("Attempt to access placeholder xmlrpc_c::fault object")); + return this->code; +} + +string +fault::getDescription() const { + if (!valid) + throw(error("Attempt to access placeholder xmlrpc_c::fault object")); + return this->description; +} + +} // namespace diff --git a/src/cpp/girerr.cpp b/src/cpp/girerr.cpp new file mode 100644 index 0000000..953a2f9 --- /dev/null +++ b/src/cpp/girerr.cpp @@ -0,0 +1,28 @@ +#include + +#include "xmlrpc-c/string_int.h" +#include "xmlrpc-c/girerr.hpp" + +using namespace std; + +namespace girerr { + +void +throwf(const char * const format, ...) { + + va_list varargs; + va_start(varargs, format); + + const char * value; + xmlrpc_vasprintf(&value, format, varargs); + + string const valueString(value); + + xmlrpc_strfree(value); + + throw(girerr::error(valueString)); + + va_end(varargs); +} + +} // namespace diff --git a/src/cpp/girmem.cpp b/src/cpp/girmem.cpp new file mode 100644 index 0000000..14b7d00 --- /dev/null +++ b/src/cpp/girmem.cpp @@ -0,0 +1,156 @@ +#include "pthreadx.h" +#include "xmlrpc-c/girerr.hpp" +using girerr::error; +#include "xmlrpc-c/girmem.hpp" + +using namespace std; +using namespace girmem; + + +namespace girmem { + + +void +autoObject::incref() { + pthread_mutex_lock(&this->refcountLock); + ++this->refcount; + pthread_mutex_unlock(&this->refcountLock); +} + + + +void +autoObject::decref(bool * const unreferencedP) { + + if (this->refcount == 0) + throw(error("Decrementing ref count of unreferenced object")); + pthread_mutex_lock(&this->refcountLock); + --this->refcount; + *unreferencedP = (this->refcount == 0); + pthread_mutex_unlock(&this->refcountLock); +} + + + +autoObject::autoObject() { + int rc; + + rc = pthread_mutex_init(&this->refcountLock, NULL); + + if (rc != 0) + throw(error("Unable to initialize pthread mutex")); + + this->refcount = 0; +} + + + +autoObject::~autoObject() { + if (this->refcount > 0) + throw(error("Destroying referenced object")); + + int rc; + + rc = pthread_mutex_destroy(&this->refcountLock); + + if (rc != 0) + throw(error("Unable to destroy pthread mutex")); +} + + + +autoObjectPtr::autoObjectPtr() : objectP(NULL) {} + + + +autoObjectPtr::autoObjectPtr(autoObject * const objectP) { + + // Note: When someone attempts to use this constructor with a null + // argument, it's normally because a 'new' of the autoObject + // failed, before calling the autoObject's constructor, thus + // generating a null pointer. + + // E.g. the following code, where the system is out of memory: + // + // class client : public autoObject { ... } + // class clientPtr : public autoObjectPtr { ... } + // clientPtr clientP(new client); + + if (objectP == NULL) + throw(error("Object creation failed; trying to create autoObjectPtr " + "ith a null autoObject pointer")); + + this->objectP = objectP; + objectP->incref(); +} + + + +autoObjectPtr::autoObjectPtr(autoObjectPtr const& autoObjectPtr) { + // copy constructor + + this->objectP = autoObjectPtr.objectP; + if (this->objectP) + this->objectP->incref(); +} + + + +autoObjectPtr::~autoObjectPtr() { + + this->unpoint(); +} + + + +void +autoObjectPtr::point(autoObject * const objectP) { + + if (this->objectP != NULL) + throw(error("Already pointing")); + this->objectP = objectP; + objectP->incref(); +} + + + +void +autoObjectPtr::unpoint() { + + if (this->objectP) { + bool dead; + this->objectP->decref(&dead); + if (dead) + delete(this->objectP); + } +} + + + +autoObjectPtr +autoObjectPtr::operator=(autoObjectPtr const& autoObjectPtr) { + + if (this->objectP != NULL) + throw(error("Already pointing")); + this->objectP = autoObjectPtr.objectP; + this->objectP->incref(); + + return *this; +} + + + +autoObject * +autoObjectPtr::operator->() const { + return this->objectP; +} + + + +autoObject * +autoObjectPtr::get() const { + + return this->objectP; +} + +} // namespace diff --git a/src/cpp/irix.make b/src/cpp/irix.make new file mode 100644 index 0000000..22793f7 --- /dev/null +++ b/src/cpp/irix.make @@ -0,0 +1,22 @@ +# -*-makefile-*- <-- an Emacs control + +# This is stuff for creating Irix shared libraries + +# This is to be included by 'Makefile'. Most of the make variables here +# come from the main make file. + + +TARGET_LINKNAMES = $(TARGET_LIBRARY_NAMES:%=%.$(SHLIB_SUFFIX) + +$(TARGET_LINKNAMES): % : %.$(MAJ).$(MIN) + rm -f $@ + $(SYMLINK) $< $@ + +LDSHLIB = -lc \ + -soname $(@:%.$(MAJ)=%) \ + -set_version `perl -e 'print "sgi$(MAJ).".join(":sgi$(MAJ).",(0..$(MIN)))."\n"'` \ + + +libxmlrpc++.$(SHLIB_SUFFIX).$(MAJ): $(LIBXMLRPCPP_OBJS) + $(LD) $(LDSHLIB) -o $@ $^ $(LADD) + diff --git a/src/cpp/libwww.cpp b/src/cpp/libwww.cpp new file mode 100644 index 0000000..3e55539 --- /dev/null +++ b/src/cpp/libwww.cpp @@ -0,0 +1,160 @@ +/*============================================================================= + libwww.cpp +=============================================================================== + This is the Libwww XML transport of the C++ XML-RPC client library for + Xmlrpc-c. +=============================================================================*/ + +#include +#include +#include + +#include "xmlrpc-c/girerr.hpp" +using girerr::error; +using girerr::throwf; +#include "xmlrpc-c/girmem.hpp" +using girmem::autoObjectPtr; +using girmem::autoObject; +#include "env_wrap.hpp" +#include "xmlrpc-c/base.h" +#include "xmlrpc-c/client.h" +#include "xmlrpc-c/transport.h" +#include "xmlrpc-c/base_int.h" + +#include "xmlrpc_libwww_transport.h" + +/* transport_config.h defines MUST_BUILD_LIBWWW_CLIENT */ +#include "transport_config.h" + +#include "xmlrpc-c/client_transport.hpp" + + +using namespace std; +using namespace xmlrpc_c; + + +namespace { + +class globalConstant { +public: + globalConstant(); + ~globalConstant(); +}; + + + +globalConstant::globalConstant() { + + // Not thread safe + + xmlrpc_transport_setup setupFn; + +#if MUST_BUILD_LIBWWW_CLIENT + setupFn = xmlrpc_libwww_transport_ops.setup_global_const; +#else + setupFn = NULL; +#endif + if (setupFn) { + env_wrap env; + + setupFn(&env.env_c); // Not thread safe + + if (env.env_c.fault_occurred) + throwf("Failed to do global initialization " + "of Libwww transport code. %s", env.env_c.fault_string); + } +} + + + +globalConstant::~globalConstant() { + + // Not thread safe + + xmlrpc_transport_teardown teardownFn; + +#if MUST_BUILD_LIBWWW_CLIENT + teardownFn = xmlrpc_libwww_transport_ops.teardown_global_const; +#else + teardownFn = NULL; +#endif + if (teardownFn) + teardownFn(); // not thread safe +} + + +globalConstant globalConst; + // This object is never accessed. Its whole purpose to to be born and + // to die, which it does automatically as part of C++ program + // program initialization and termination. + +} // namespace + + +namespace xmlrpc_c { + +carriageParm_libwww0::carriageParm_libwww0( + string const serverUrl + ) { + + this->instantiate(serverUrl); +} + + + +carriageParm_libwww0Ptr::carriageParm_libwww0Ptr() { + // Base class constructor will construct pointer that points to nothing +} + + + +carriageParm_libwww0Ptr::carriageParm_libwww0Ptr( + carriageParm_libwww0 * const carriageParmP) { + this->point(carriageParmP); +} + + + +carriageParm_libwww0 * +carriageParm_libwww0Ptr::operator->() const { + + autoObject * const p(this->objectP); + return dynamic_cast(p); +} + + + +#if MUST_BUILD_LIBWWW_CLIENT + +clientXmlTransport_libwww::clientXmlTransport_libwww( + string const appname, + string const appversion) { + + this->c_transportOpsP = &xmlrpc_libwww_transport_ops; + + env_wrap env; + + xmlrpc_libwww_transport_ops.create( + &env.env_c, 0, appname.c_str(), appversion.c_str(), NULL, 0, + &this->c_transportP); + + if (env.env_c.fault_occurred) + throw(error(env.env_c.fault_string)); +} + +#else // MUST_BUILD_LIBWWW_CLIENT + clientXmlTransport_libwww::clientXmlTransport_libwww(string, string) { + + throw(error("There is no Libwww client XML transport " + "in this XML-RPC client library")); +} + +#endif + + +clientXmlTransport_libwww::~clientXmlTransport_libwww() { + + this->c_transportOpsP->destroy(this->c_transportP); +} + +} // namespace diff --git a/src/cpp/outcome.cpp b/src/cpp/outcome.cpp new file mode 100644 index 0000000..e004ef8 --- /dev/null +++ b/src/cpp/outcome.cpp @@ -0,0 +1,57 @@ +#include "xmlrpc-c/girerr.hpp" +using girerr::error; +#include "xmlrpc-c/base.hpp" + +using namespace std; + +namespace xmlrpc_c { + +rpcOutcome::rpcOutcome() : valid(false) {} + +rpcOutcome::rpcOutcome(xmlrpc_c::value const result) : + valid(true), _succeeded(true), result(result) + {} + + + +rpcOutcome::rpcOutcome(xmlrpc_c::fault const fault) : + valid(true), _succeeded(false), fault(fault) + {} + + + +bool +rpcOutcome::succeeded() const { + if (!valid) + throw(error("Attempt to access rpcOutcome object before setting it")); + return _succeeded; +} + + + +fault +rpcOutcome::getFault() const { + + if (!valid) + throw(error("Attempt to access rpcOutcome object before setting it")); + if (_succeeded) + throw(error("Attempt to get fault description from a non-failure " + "RPC outcome")); + return fault; +} + + + +value +rpcOutcome::getResult() const { + + if (!valid) + throw(error("Attempt to access rpcOutcome object before setting it")); + if (!_succeeded) + throw(error("Attempt to get result from an unsuccessful RPC outcome")); + return result; +} + + +} // namespace + diff --git a/src/cpp/param_list.cpp b/src/cpp/param_list.cpp new file mode 100644 index 0000000..9c69560 --- /dev/null +++ b/src/cpp/param_list.cpp @@ -0,0 +1,259 @@ +#include +#include +#include +#include + +#include "xmlrpc-c/girerr.hpp" +using girerr::error; +#include "xmlrpc-c/base.h" +#include "xmlrpc-c/base.hpp" + +using namespace std; +using namespace xmlrpc_c; + +namespace xmlrpc_c { + + +paramList::paramList(unsigned int const paramCount) { + + this->paramVector.reserve(paramCount); +} + + + +void +paramList::add(xmlrpc_c::value const param) { + + this->paramVector.push_back(param); +} + + + +unsigned int +paramList::size() const { + return this->paramVector.size(); +} + + + +xmlrpc_c::value +paramList::operator[](unsigned int const subscript) const { + + if (subscript >= this->paramVector.size()) + throw(girerr::error( + "Subscript of xmlrpc_c::paramList out of bounds")); + + return this->paramVector[subscript]; +} + + + +int +paramList::getInt(unsigned int const paramNumber, + int const minimum, + int const maximum) const { + + if (paramNumber >= this->paramVector.size()) + throw(fault("Not enough parameters", fault::CODE_TYPE)); + + if (this->paramVector[paramNumber].type() != value::TYPE_INT) + throw(fault("Parameter that is supposed to be integer is not", + fault::CODE_TYPE)); + + int const intvalue(static_cast( + value_int(this->paramVector[paramNumber]))); + + if (intvalue < minimum) + throw(fault("Integer parameter too low", fault::CODE_TYPE)); + + if (intvalue > maximum) + throw(fault("Integer parameter too high", fault::CODE_TYPE)); + + return intvalue; +} + + + +bool +paramList::getBoolean(unsigned int const paramNumber) const { + + if (paramNumber >= this->paramVector.size()) + throw(fault("Not enough parameters", fault::CODE_TYPE)); + + if (this->paramVector[paramNumber].type() != value::TYPE_BOOLEAN) + throw(fault("Parameter that is supposed to be boolean is not", + fault::CODE_TYPE)); + + return static_cast(value_boolean(this->paramVector[paramNumber])); +} + + + +double +paramList::getDouble(unsigned int const paramNumber, + double const minimum, + double const maximum) const { + + if (paramNumber >= this->paramVector.size()) + throw(fault("Not enough parameters", fault::CODE_TYPE)); + + if (this->paramVector[paramNumber].type() != value::TYPE_DOUBLE) + throw(fault("Parameter that is supposed to be floating point number " + "is not", + fault::CODE_TYPE)); + + double const doublevalue(static_cast( + value_double(this->paramVector[paramNumber]))); + + if (doublevalue < minimum) + throw(fault("Floating point number parameter too low", + fault::CODE_TYPE)); + + if (doublevalue > maximum) + throw(fault("Floating point number parameter too high", + fault::CODE_TYPE)); + + return doublevalue; +} + + + +time_t +paramList::getDatetime_sec( + unsigned int const paramNumber, + paramList::timeConstraint const constraint) const { + + if (paramNumber >= this->paramVector.size()) + throw(fault("Not enough parameters", fault::CODE_TYPE)); + + const xmlrpc_c::value * const paramP(&this->paramVector[paramNumber]); + + if (paramP->type() != value::TYPE_DATETIME) + throw(fault("Parameter that is supposed to be a datetime is not", + fault::CODE_TYPE)); + + time_t const timeValue(static_cast(value_datetime(*paramP))); + time_t const now(time(NULL)); + + switch (constraint) { + case TC_ANY: + /* He'll take anything; no problem */ + break; + case TC_NO_FUTURE: + if (timeValue > now) + throw(fault("Datetime parameter that is not supposed to be in " + "the future is.", fault::CODE_TYPE)); + break; + case TC_NO_PAST: + if (timeValue < now) + throw(fault("Datetime parameter that is not supposed to be in " + "the past is.", fault::CODE_TYPE)); + break; + } + + return timeValue; +} + + + +string +paramList::getString(unsigned int const paramNumber) const { + + if (paramNumber >= this->paramVector.size()) + throw(fault("Not enough parameters", fault::CODE_TYPE)); + + if (this->paramVector[paramNumber].type() != value::TYPE_STRING) + throw(fault("Parameter that is supposed to be a string is not", + fault::CODE_TYPE)); + + return static_cast(value_string(this->paramVector[paramNumber])); +} + + + +std::vector +paramList::getBytestring(unsigned int const paramNumber) const { + + if (paramNumber >= this->paramVector.size()) + throw(fault("Not enough parameters", fault::CODE_TYPE)); + + const xmlrpc_c::value * const paramP(&this->paramVector[paramNumber]); + + if (paramP->type() != value::TYPE_BYTESTRING) + throw(fault("Parameter that is supposed to be a byte string is not", + fault::CODE_TYPE)); + + return value_bytestring(*paramP).vectorUcharValue(); +} + + +std::vector +paramList::getArray(unsigned int const paramNumber, + unsigned int const minSize, + unsigned int const maxSize) const { + + if (paramNumber >= this->paramVector.size()) + throw(fault("Not enough parameters", fault::CODE_TYPE)); + + const xmlrpc_c::value * const paramP(&this->paramVector[paramNumber]); + + if (paramP->type() != value::TYPE_ARRAY) + throw(fault("Parameter that is supposed to be an array is not", + fault::CODE_TYPE)); + + xmlrpc_c::value_array const arrayValue(*paramP); + + if (arrayValue.size() < minSize) + throw(fault("Array parameter has too few elements", + fault::CODE_TYPE)); + + if (arrayValue.size() > maxSize) + throw(fault("Array parameter has too many elements", + fault::CODE_TYPE)); + + return value_array(*paramP).vectorValueValue(); +} + + + +std::map +paramList::getStruct(unsigned int const paramNumber) const { + + if (paramNumber >= this->paramVector.size()) + throw(fault("Not enough parameters", fault::CODE_TYPE)); + + const xmlrpc_c::value * const paramP(&this->paramVector[paramNumber]); + + if (paramP->type() != value::TYPE_STRUCT) + throw(fault("Parameter that is supposed to be a structure is not", + fault::CODE_TYPE)); + + return static_cast >( + value_struct(*paramP)); +} + + + +void +paramList::getNil(unsigned int const paramNumber) const { + + if (paramNumber >= this->paramVector.size()) + throw(fault("Not enough parameters", fault::CODE_TYPE)); + + if (this->paramVector[paramNumber].type() != value::TYPE_NIL) + throw(fault("Parameter that is supposed to be nil is not", + fault::CODE_TYPE)); +} + + + +void +paramList::verifyEnd(unsigned int const paramNumber) const { + + if (paramNumber < this->paramVector.size()) + throw(fault("Too many parameters", fault::CODE_TYPE)); + if (paramNumber > this->paramVector.size()) + throw(fault("Not enough parameters", fault::CODE_TYPE)); +} + +} // namespace diff --git a/src/cpp/registry.cpp b/src/cpp/registry.cpp new file mode 100644 index 0000000..9a53b92 --- /dev/null +++ b/src/cpp/registry.cpp @@ -0,0 +1,365 @@ +#include +#include +#include +#include + +#include "xmlrpc-c/girerr.hpp" +using girerr::error; +#include "xmlrpc-c/girmem.hpp" +using girmem::autoObject; +using girmem::autoObjectPtr; +#include "xmlrpc-c/base.h" +#include "xmlrpc-c/base.hpp" +#include "env_wrap.hpp" + +#include "xmlrpc-c/registry.hpp" + +using namespace std; +using namespace xmlrpc_c; + + +namespace { + +void +throwIfError(env_wrap const& env) { + + if (env.env_c.fault_occurred) + throw(error(env.env_c.fault_string)); +} + + +} // namespace + +namespace xmlrpc_c { + + +method::method() : + _signature("?"), + _help("No help is available for this method") + {}; + + + +method::~method() {} + + + +methodPtr::methodPtr(method * const methodP) { + this->point(methodP); +} + + + +method * +methodPtr::operator->() const { + + autoObject * const p(this->objectP); + return dynamic_cast(p); +} + + + +defaultMethod::~defaultMethod() {} + + + +defaultMethodPtr::defaultMethodPtr() {} + + +defaultMethodPtr::defaultMethodPtr(defaultMethod * const methodP) { + this->point(methodP); +} + + + +defaultMethod * +defaultMethodPtr::operator->() const { + + autoObject * const p(this->objectP); + return dynamic_cast(p); +} + + + +defaultMethod * +defaultMethodPtr::get() const { + + autoObject * const p(this->objectP); + return dynamic_cast(p); +} + + + +registry::registry() { + + env_wrap env; + + this->c_registryP = xmlrpc_registry_new(&env.env_c); + + throwIfError(env); +} + + + +registry::~registry(void) { + + xmlrpc_registry_free(this->c_registryP); +} + + + +registryPtr::registryPtr() {} + + + +registryPtr::registryPtr(registry * const registryP) { + this->point(registryP); +} + + + +registry * +registryPtr::operator->() const { + + autoObject * const p(this->objectP); + return dynamic_cast(p); +} + + + +registry * +registryPtr::get() const { + + autoObject * const p(this->objectP); + return dynamic_cast(p); +} + + + +static xmlrpc_c::paramList +pListFromXmlrpcArray(xmlrpc_value * const arrayP) { +/*---------------------------------------------------------------------------- + Convert an XML-RPC array in C (not C++) form to a parameter list object + that can be passed to a method execute method. + + This is glue code to allow us to hook up C++ Xmlrpc-c code to + C Xmlrpc-c code. +-----------------------------------------------------------------------------*/ + env_wrap env; + + XMLRPC_ASSERT_ARRAY_OK(arrayP); + + unsigned int const arraySize = xmlrpc_array_size(&env.env_c, arrayP); + + assert(!env.env_c.fault_occurred); + + xmlrpc_c::paramList paramList(arraySize); + + for (unsigned int i = 0; i < arraySize; ++i) { + xmlrpc_value * arrayItemP; + + xmlrpc_array_read_item(&env.env_c, arrayP, i, &arrayItemP); + assert(!env.env_c.fault_occurred); + + paramList.add(xmlrpc_c::value(arrayItemP)); + + xmlrpc_DECREF(arrayItemP); + } + return paramList; +} + + + +static xmlrpc_value * +c_executeMethod(xmlrpc_env * const envP, + xmlrpc_value * const paramArrayP, + void * const methodPtr) { +/*---------------------------------------------------------------------------- + This is a function designed to be called via a C registry to + execute an XML-RPC method, but use a C++ method object to do the + work. You register this function as the method function and a + pointer to the C++ method object as the method data in the C + registry. + + If we had a pure C++ registry, this would be unnecessary. + + Since we can't throw an error back to the C code, we catch anything + the XML-RPC method's execute() method throws, and any error we + encounter in processing the result it returns, and turn it into an + XML-RPC method failure. This will cause a leak if the execute() + method actually created a result, since it will not get destroyed. +-----------------------------------------------------------------------------*/ + xmlrpc_c::method * const methodP = + static_cast(methodPtr); + xmlrpc_c::paramList const paramList(pListFromXmlrpcArray(paramArrayP)); + + xmlrpc_value * retval; + + try { + xmlrpc_c::value result; + + try { + methodP->execute(paramList, &result); + } catch (xmlrpc_c::fault const& fault) { + xmlrpc_env_set_fault(envP, fault.getCode(), + fault.getDescription().c_str()); + } catch (girerr::error const& error) { + xmlrpc_env_set_fault(envP, 0, error.what()); + } + if (envP->fault_occurred) + retval = NULL; + else + retval = result.cValue(); + } catch (...) { + xmlrpc_env_set_fault(envP, XMLRPC_INTERNAL_ERROR, + "Unexpected error executing the code for this " + "particular method, detected by the Xmlrpc-c " + "method registry code. The method did not " + "fail; rather, it did not complete at all."); + retval = NULL; + } + return retval; +} + + + +static xmlrpc_value * +c_executeDefaultMethod(xmlrpc_env * const envP, + const char * const , // host + const char * const methodName, + xmlrpc_value * const paramArrayP, + void * const methodPtr) { +/*---------------------------------------------------------------------------- + This is a function designed to be called via a C registry to + execute an XML-RPC method, but use a C++ method object to do the + work. You register this function as the default method function and a + pointer to the C++ default method object as the method data in the C + registry. + + If we had a pure C++ registry, this would be unnecessary. + + Since we can't throw an error back to the C code, we catch anything + the XML-RPC method's execute() method throws, and any error we + encounter in processing the result it returns, and turn it into an + XML-RPC method failure. This will cause a leak if the execute() + method actually created a result, since it will not get destroyed. +-----------------------------------------------------------------------------*/ + defaultMethod * const methodP = + static_cast(methodPtr); + paramList const paramList(pListFromXmlrpcArray(paramArrayP)); + + xmlrpc_value * retval; + + try { + value result; + + try { + methodP->execute(methodName, paramList, &result); + } catch (xmlrpc_c::fault const& fault) { + xmlrpc_env_set_fault(envP, fault.getCode(), + fault.getDescription().c_str()); + } catch (girerr::error const& error) { + xmlrpc_env_set_fault(envP, 0, error.what()); + } + if (envP->fault_occurred) + retval = NULL; + else + retval = result.cValue(); + } catch (...) { + xmlrpc_env_set_fault(envP, XMLRPC_INTERNAL_ERROR, + "Unexpected error executing the default " + "method code, detected by the Xmlrpc-c " + "method registry code. The method did not " + "fail; rather, it did not complete at all."); + retval = NULL; + } + return retval; +} + + + +void +registry::addMethod(string const name, + methodPtr const methodP) { + + this->methodList.push_back(methodP); + + env_wrap env; + + xmlrpc_registry_add_method_w_doc( + &env.env_c, this->c_registryP, NULL, + name.c_str(), &c_executeMethod, + (void*) methodP.get(), + methodP->signature().c_str(), methodP->help().c_str()); + + throwIfError(env); +} + + + +void +registry::setDefaultMethod(defaultMethodPtr const methodP) { + + this->defaultMethodP = methodP; + + env_wrap env; + + xmlrpc_registry_set_default_method( + &env.env_c, this->c_registryP, + &c_executeDefaultMethod, (void*) methodP.get()); + + throwIfError(env); +} + + + +void +registry::disableIntrospection() { + + xmlrpc_registry_disable_introspection(this->c_registryP); +} + + + +void +registry::processCall(string const& callXml, + string * const responseXmlP) const { +/*---------------------------------------------------------------------------- + Process an XML-RPC call whose XML is 'callXml'. + + Return the response XML as *responseXmlP. + + If we are unable to execute the call, we throw an error. But if + the call executes and the method merely fails in an XML-RPC sense, we + don't. In that case, *responseXmlP indicates the failure. +-----------------------------------------------------------------------------*/ + env_wrap env; + xmlrpc_mem_block * output; + + // For the pure C++ version, this will have to parse 'callXml' + // into a method name and parameters, look up the method name in + // the registry, call the method's execute() method, then marshall + // the result into XML and return it as *responseXmlP. It will + // also have to execute system methods (e.g. introspection) + // itself. This will be more or less like what + // xmlrpc_registry_process_call() does. + + output = xmlrpc_registry_process_call( + &env.env_c, this->c_registryP, NULL, + callXml.c_str(), callXml.length()); + + throwIfError(env); + + *responseXmlP = string(XMLRPC_MEMBLOCK_CONTENTS(char, output), + XMLRPC_MEMBLOCK_SIZE(char, output)); + + xmlrpc_mem_block_free(output); +} + +xmlrpc_registry * +registry::c_registry() const { + + return this->c_registryP; +} + +} // namespace diff --git a/src/cpp/server_abyss.cpp b/src/cpp/server_abyss.cpp new file mode 100644 index 0000000..f4a9090 --- /dev/null +++ b/src/cpp/server_abyss.cpp @@ -0,0 +1,372 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +#include "xmlrpc-c/girerr.hpp" +using girerr::error; +using girerr::throwf; +#include "xmlrpc-c/base.h" +#include "xmlrpc-c/base.hpp" +#include "xmlrpc-c/server_abyss.h" +#include "xmlrpc-c/registry.hpp" +#include "xmlrpc-c/server_abyss.hpp" + +using namespace std; +using namespace xmlrpc_c; + +namespace xmlrpc_c { + +namespace { + + +static void +sigterm(int const signalClass) { + + cerr << "Signal of Class " << signalClass << " received. Exiting" << endl; + + exit(1); +} + + + +static void +sigchld(int const signalClass) { +/*---------------------------------------------------------------------------- + This is a signal handler for a SIGCHLD signal (which informs us that + one of our child processes has terminated). + + We respond by reaping the zombie process. + + Implementation note: In some systems, just setting the signal handler + to SIG_IGN (ignore signal) does this. In others, it doesn't. +-----------------------------------------------------------------------------*/ +#ifndef _WIN32 + /* Reap zombie children until there aren't any more. */ + + bool zombiesExist; + bool error; + + assert(signalClass == SIGCHLD); + + zombiesExist = true; // initial assumption + error = false; // no error yet + while (zombiesExist && !error) { + int status; + pid_t const pid = waitpid((pid_t) -1, &status, WNOHANG); + + if (pid == 0) + zombiesExist = false; + else if (pid < 0) { + /* because of ptrace */ + if (errno == EINTR) { + // This is OK - it's a ptrace notification + } else + error = true; + } + } +#endif /* _WIN32 */ +} + + + +void +setupSignalHandlers(void) { +#ifndef _WIN32 + struct sigaction mysigaction; + + sigemptyset(&mysigaction.sa_mask); + mysigaction.sa_flags = 0; + + /* These signals abort the program, with tracing */ + mysigaction.sa_handler = sigterm; + sigaction(SIGTERM, &mysigaction, NULL); + sigaction(SIGINT, &mysigaction, NULL); + sigaction(SIGHUP, &mysigaction, NULL); + sigaction(SIGUSR1, &mysigaction, NULL); + + /* This signal indicates connection closed in the middle */ + mysigaction.sa_handler = SIG_IGN; + sigaction(SIGPIPE, &mysigaction, NULL); + + /* This signal indicates a child process (request handler) has died */ + mysigaction.sa_handler = sigchld; + sigaction(SIGCHLD, &mysigaction, NULL); +#endif +} + + +} // namespace + + + +serverAbyss::constrOpt::constrOpt() { + present.registryPtr = false; + present.registryP = false; + present.socketFd = false; + present.portNumber = false; + present.logFileName = false; + present.keepaliveTimeout = false; + present.keepaliveMaxConn = false; + present.timeout = false; + present.dontAdvertise = false; + present.uriPath = false; + present.chunkResponse = false; + + // Set default values + value.dontAdvertise = false; + value.uriPath = string("/RPC2"); + value.chunkResponse = false; +} + + + +#define DEFINE_OPTION_SETTER(OPTION_NAME, TYPE) \ +serverAbyss::constrOpt & \ +serverAbyss::constrOpt::OPTION_NAME(TYPE const& arg) { \ + this->value.OPTION_NAME = arg; \ + this->present.OPTION_NAME = true; \ + return *this; \ +} + +DEFINE_OPTION_SETTER(registryPtr, xmlrpc_c::registryPtr); +DEFINE_OPTION_SETTER(registryP, const registry *); +DEFINE_OPTION_SETTER(socketFd, xmlrpc_socket); +DEFINE_OPTION_SETTER(portNumber, uint); +DEFINE_OPTION_SETTER(logFileName, string); +DEFINE_OPTION_SETTER(keepaliveTimeout, uint); +DEFINE_OPTION_SETTER(keepaliveMaxConn, uint); +DEFINE_OPTION_SETTER(timeout, uint); +DEFINE_OPTION_SETTER(dontAdvertise, bool); +DEFINE_OPTION_SETTER(uriPath, string); +DEFINE_OPTION_SETTER(chunkResponse, bool); + + + +void +serverAbyss::setAdditionalServerParms(constrOpt const& opt) { + + /* The following ought to be parameters on ServerCreate(), but it + looks like plugging them straight into the TServer structure is + the only way to set them. + */ + + if (opt.present.keepaliveTimeout) + ServerSetKeepaliveTimeout(&this->cServer, opt.value.keepaliveTimeout); + if (opt.present.keepaliveMaxConn) + ServerSetKeepaliveMaxConn(&this->cServer, opt.value.keepaliveMaxConn); + if (opt.present.timeout) + ServerSetTimeout(&this->cServer, opt.value.timeout); + ServerSetAdvertise(&this->cServer, !opt.value.dontAdvertise); +} + + + +static void +createServer(bool const logFileNameGiven, + string const& logFileName, + bool const socketFdGiven, + int const socketFd, + bool const portNumberGiven, + unsigned int const portNumber, + TServer * const srvPP) { + + const char * const logfileArg(logFileNameGiven ? + logFileName.c_str() : NULL); + + const char * const serverName("XmlRpcServer"); + + bool created; + + if (socketFdGiven) + created = + ServerCreateSocket(srvPP, serverName, socketFd, + DEFAULT_DOCS, logfileArg); + else if (portNumberGiven) { + if (portNumber > 0xffff) + throwf("Port number %u exceeds the maximum possible port number " + "(65535)", portNumber); + + created = + ServerCreate(srvPP, serverName, portNumber, + DEFAULT_DOCS, logfileArg); + } else + created = + ServerCreateNoAccept(srvPP, serverName, + DEFAULT_DOCS, logfileArg); + + if (!created) + throw(error("Failed to create Abyss server. See Abyss error log for " + "reason.")); +} + + + +void +serverAbyss::initialize(constrOpt const& opt) { + + const registry * registryP; + + if (!opt.present.registryP && !opt.present.registryPtr) + throwf("You must specify the 'registryP' or 'registryPtr' option"); + else if (opt.present.registryP && opt.present.registryPtr) + throwf("You may not specify both the 'registryP' and " + "the 'registryPtr' options"); + else { + if (opt.present.registryP) + registryP = opt.value.registryP; + else { + this->registryPtr = opt.value.registryPtr; + registryP = this->registryPtr.get(); + } + } + if (opt.present.portNumber && opt.present.socketFd) + throwf("You can't specify both portNumber and socketFd options"); + + DateInit(); + + createServer(opt.present.logFileName, opt.value.logFileName, + opt.present.socketFd, opt.value.socketFd, + opt.present.portNumber, opt.value.portNumber, + &this->cServer); + + try { + setAdditionalServerParms(opt); + + // chunked response implementation is incomplete. We must + // eventually get away from libxmlrpc_server_abyss and + // register our own handler with the Abyss server. At that + // time, we'll have some place to pass + // opt.value.chunkResponse. + + xmlrpc_c::server_abyss_set_handlers(&this->cServer, + registryP, + opt.value.uriPath); + + if (opt.present.portNumber || opt.present.socketFd) + ServerInit(&this->cServer); + + setupSignalHandlers(); + } catch (...) { + ServerFree(&this->cServer); + throw; + } +} + + + +serverAbyss::serverAbyss(constrOpt const& opt) { + + initialize(opt); +} + + + +serverAbyss::serverAbyss( + xmlrpc_c::registry const& registry, + unsigned int const portNumber, + string const& logFileName, + unsigned int const keepaliveTimeout, + unsigned int const keepaliveMaxConn, + unsigned int const timeout, + bool const dontAdvertise, + bool const socketBound, + xmlrpc_socket const socketFd) { +/*---------------------------------------------------------------------------- + This is a backward compatibility interface. This used to be the only + constructor. +-----------------------------------------------------------------------------*/ + serverAbyss::constrOpt opt; + + opt.registryP(®istry); + if (logFileName.length() > 0) + opt.logFileName(logFileName); + if (keepaliveTimeout > 0) + opt.keepaliveTimeout(keepaliveTimeout); + if (keepaliveMaxConn > 0) + opt.keepaliveMaxConn(keepaliveMaxConn); + if (timeout > 0) + opt.timeout(timeout); + opt.dontAdvertise(dontAdvertise); + if (socketBound) + opt.socketFd(socketFd); + else + opt.portNumber(portNumber); + + initialize(opt); +} + + + +serverAbyss::~serverAbyss() { + + ServerFree(&this->cServer); +} + + + +void +serverAbyss::run() { + + ServerRun(&this->cServer); +} + + + +void +serverAbyss::runOnce() { + + ServerRunOnce(&this->cServer); +} + + + +void +serverAbyss::runConn(int const socketFd) { + + ServerRunConn(&this->cServer, socketFd); +} + + + +void +server_abyss_set_handlers(TServer * const srvP, + registry const& registry, + string const& uriPath) { + + xmlrpc_server_abyss_set_handlers2(srvP, + uriPath.c_str(), + registry.c_registry()); +} + + + +void +server_abyss_set_handlers(TServer * const srvP, + const registry * const registryP, + string const& uriPath) { + + xmlrpc_server_abyss_set_handlers2(srvP, + uriPath.c_str(), + registryP->c_registry()); +} + + + +void +server_abyss_set_handlers(TServer * const srvP, + registryPtr const registryPtr, + string const& uriPath) { + + xmlrpc_server_abyss_set_handlers2(srvP, + uriPath.c_str(), + registryPtr->c_registry()); +} + + + +} // namespace diff --git a/src/cpp/test/.cvsignore b/src/cpp/test/.cvsignore new file mode 100644 index 0000000..9daeafb --- /dev/null +++ b/src/cpp/test/.cvsignore @@ -0,0 +1 @@ +test diff --git a/src/cpp/test/Makefile b/src/cpp/test/Makefile new file mode 100644 index 0000000..eab1e8f --- /dev/null +++ b/src/cpp/test/Makefile @@ -0,0 +1,91 @@ +ifeq ($(SRCDIR)x,x) +SRCDIR = $(CURDIR)/../../.. +endif +SUBDIR = src/test/cpp +# BLDDIR is for use in places where a symbolic link won't work. +# BUILDDIR is for places in Makefile.common that can use the 'blddir' +# symbolic link (but in other directories, doesn't). +BLDDIR = ../../.. +BUILDDIR = blddir +VPATH = .:$(SRCDIR) + +include $(BLDDIR)/Makefile.config + +PROGS = test + +default: all + +all: $(PROGS) + +XMLRPC_C_CONFIG = $(BUILDDIR)/xmlrpc-c-config.test + +CXXFLAGS = $(CXXFLAGS_COMMON) $(CFLAGS_PERSONAL) $(CADD) + +LDFLAGS += $(shell $(XMLRPC_C_CONFIG) client --ldadd) + +ifeq ($(MUST_BUILD_CURL_CLIENT),yes) + LDFLAGS += $(shell curl-config --libs) +endif +ifeq ($(MUST_BUILD_LIBWWW_CLIENT),yes) + LDFLAGS += $(shell libwww-config --libs) +endif + +LDFLAGS += "-lpthread" + +LDFLAGS += $(LADD) + +INCLUDES = -Isrcdir/include -Iblddir -Isrcdir -Isrcdir/lib/util/include + +# This 'Makefile' dependency makes sure the symlinks get built before +# this make file is used for anything. + +Makefile: blddir srcdir + +include $(SRCDIR)/Makefile.common + + +TEST_OBJS = test.o server_abyss.o tools.o + +ifeq ($(MUST_BUILD_CLIENT),yes) + TEST_OBJS += testclient.o + CLIENT_LIBS = $(LIBXMLRPC_CLIENT++) $(LIBXMLRPC_CLIENT_A) +else + TEST_OBJS += testclient_dummy.o + CLIENT_LIBS = +endif + + +test:$(TEST_OBJS) $(LIBXMLRPC_SERVER_ABYSS++) $(LIBXMLRPC_SERVER++) \ + $(CLIENT_LIBS) $(LIBXMLRPC++) $(LIBXMLRPC_CPP) \ + $(LIBXMLRPC_SERVER_ABYSS_A) $(LIBXMLRPC_SERVER_A) \ + $(LIBXMLRPC_A) $(LIBXMLRPC_ABYSS_A) $(LIBXMLRPC_XML) $(LIBXMLRPC_UTIL_A) + $(LIBTOOL) --mode=link $(CXXLD) -o $@ $(LDFLAGS) $^ + +%.o:%.cpp + $(CXX) -c $(INCLUDES) $(CXXFLAGS) $< + +# Note the difference between 'check' and 'runtests'. 'check' means to check +# our own correctness. 'runtests' means to run the tests that check our +# parent's correctness + +.PHONY: check +check: + +.PHONY: runtests +runtests: test + ./test + +.PHONY: install +install: + +.PHONY: clean clean-local distclean +clean: clean-common clean-local +clean-local: + rm -f $(PROGS) + +distclean: clean distclean-common + +.PHONY: dep +dep: dep-common + +include Makefile.depend diff --git a/src/cpp/test/Makefile.depend b/src/cpp/test/Makefile.depend new file mode 100644 index 0000000..e69de29 diff --git a/src/cpp/test/server_abyss.cpp b/src/cpp/test/server_abyss.cpp new file mode 100644 index 0000000..b1a6bda --- /dev/null +++ b/src/cpp/test/server_abyss.cpp @@ -0,0 +1,215 @@ +/*============================================================================= + server_abyss +=============================================================================== + Test the Abyss server C++ facilities of XML-RPC for C/C++. + +=============================================================================*/ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "xmlrpc-c/girerr.hpp" +using girerr::error; +using girerr::throwf; +#include "xmlrpc-c/base.hpp" +#include "xmlrpc-c/registry.hpp" +#include "xmlrpc-c/server_abyss.hpp" + +#include "tools.hpp" +#include "server_abyss.hpp" + +using namespace xmlrpc_c; +using namespace std; + + + +class boundSocket { + +public: + boundSocket(short const portNumber) { + this->fd = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); + + if (this->fd < 0) + throwf("socket() failed. errno=%d (%s)", + errno, strerror(errno)); + + struct sockaddr_in sockAddr; + int rc; + + sockAddr.sin_family = AF_INET; + sockAddr.sin_port = htons(portNumber); + sockAddr.sin_addr.s_addr = 0; + + rc = bind(this->fd, (struct sockaddr *)&sockAddr, sizeof(sockAddr)); + + if (rc != 0) { + close(this->fd); + throwf("Couldn't bind. bind() failed with errno=%d (%s)", + errno, strerror(errno)); + } + } + + ~boundSocket() { + close(this->fd); + } + + int fd; +}; + + + +class sampleAddMethod : public method { +public: + sampleAddMethod() { + this->_signature = "i:ii"; + this->_help = "This method adds two integers together"; + } + void + execute(xmlrpc_c::paramList const& paramList, + value * const retvalP) { + + int const addend(paramList.getInt(0)); + int const adder(paramList.getInt(1)); + + paramList.verifyEnd(2); + + *retvalP = value_int(addend + adder); + } +}; + + + +class addHandlerTestSuite : public testSuite { + +public: + virtual string suiteName() { + return "addHandlerTestSuite"; + } + virtual void runtests(unsigned int) { + TServer abyssServer; + + ServerCreate(&abyssServer, "testserver", 8080, NULL, NULL); + + registry myRegistry; + + myRegistry.addMethod("sample.add", methodPtr(new sampleAddMethod)); + + registryPtr myRegistryP(new registry); + + myRegistryP->addMethod("sample.add", methodPtr(new sampleAddMethod)); + + server_abyss_set_handlers(&abyssServer, myRegistry); + + server_abyss_set_handlers(&abyssServer, &myRegistry); + + server_abyss_set_handlers(&abyssServer, myRegistryP); + + server_abyss_set_handlers(&abyssServer, myRegistry, "/RPC3"); + + server_abyss_set_handlers(&abyssServer, &myRegistry, "/RPC3"); + + server_abyss_set_handlers(&abyssServer, myRegistryP, "/RPC3"); + + ServerFree(&abyssServer); + } +}; + + + +string +serverAbyssTestSuite::suiteName() { + return "serverAbyssTestSuite"; +} + + +void +serverAbyssTestSuite::runtests(unsigned int const indentation) { + + addHandlerTestSuite().run(indentation+1); + + registry myRegistry; + + myRegistry.addMethod("sample.add", methodPtr(new sampleAddMethod)); + + registryPtr myRegistryP(new registry); + + myRegistryP->addMethod("sample.add", methodPtr(new sampleAddMethod)); + + EXPECT_ERROR( // No registry + serverAbyss::constrOpt opt; + serverAbyss abyssServer(opt); + ); + EXPECT_ERROR( // Both portNumber and socketFd + serverAbyss abyssServer(serverAbyss::constrOpt() + .portNumber(8080) + .socketFd(3)); + ); + + // Due to the vagaries of Abyss, construction of the following + // objects may exit the program if it detects an error, such as + // port number already in use. We need to fix Abyss some day. + + { + serverAbyss abyssServer(serverAbyss::constrOpt() + .registryP(&myRegistry) + .portNumber(12345) + ); + } + { + serverAbyss abyssServer(serverAbyss::constrOpt() + .registryPtr(myRegistryP) + .portNumber(12345) + ); + + EXPECT_ERROR( // Both registryP and registryPtr + serverAbyss abyssServer(serverAbyss::constrOpt() + .registryPtr(myRegistryP) + .registryP(&myRegistry) + .portNumber(12345) + ); + ); + } + { + boundSocket socket(12345); + + serverAbyss abyssServer(serverAbyss::constrOpt() + .registryP(&myRegistry) + .socketFd(socket.fd) + ); + } + { + serverAbyss abyssServer(serverAbyss::constrOpt() + .registryP(&myRegistry) + ); + } + + { + // Test all the options + serverAbyss abyssServer(serverAbyss::constrOpt() + .registryPtr(myRegistryP) + .portNumber(12345) + .logFileName("/tmp/logfile") + .keepaliveTimeout(5) + .keepaliveMaxConn(4) + .timeout(20) + .dontAdvertise(true) + .uriPath("/xmlrpc") + ); + + } + { + serverAbyss abyssServer( + myRegistry, + 12345, // TCP port on which to listen + "/tmp/xmlrpc_log" // Log file + ); + } +} diff --git a/src/cpp/test/server_abyss.hpp b/src/cpp/test/server_abyss.hpp new file mode 100644 index 0000000..afd801d --- /dev/null +++ b/src/cpp/test/server_abyss.hpp @@ -0,0 +1,8 @@ +#include "tools.hpp" + +class serverAbyssTestSuite : public testSuite { + +public: + virtual std::string suiteName(); + virtual void runtests(unsigned int); +}; diff --git a/src/cpp/test/test.cpp b/src/cpp/test/test.cpp new file mode 100644 index 0000000..e026535 --- /dev/null +++ b/src/cpp/test/test.cpp @@ -0,0 +1,820 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +#include "xmlrpc-c/girerr.hpp" +using girerr::error; +#include "transport_config.h" +#include "xmlrpc-c/base.hpp" +#include "xmlrpc-c/oldcppwrapper.hpp" +#include "xmlrpc-c/registry.hpp" + +#include "testclient.hpp" +#include "server_abyss.hpp" +#include "tools.hpp" + +using namespace xmlrpc_c; +using namespace std; + +//========================================================================= +// Test Harness +//========================================================================= +// +// There are two styles of test in here. The older ones are vaguely +// inspired by Kent Beck's book on eXtreme Programming (XP) and use +// the TEST...() macros. +// +// But this style is not really appropriate for C++. It's based on +// code that explicitly tests for errors, as one would do in C. In C++, +// it is cumbersome to catch exceptions on every call, so we don't in +// the new style. + +// And there's not much point in trying to count test successes and +// failures. Any failure is a problem, so in the new style, we just +// quit after we recognize one (again, more in line with regular exception +// throwing). With exception throwing, you can't count what _didn't_ +// cause an exception, so there's no meaningful count of test successes. +// +// To run the tests, type './cpptest'. +// To check for memory leaks, install RedHat's 'memprof' utility, and +// type 'memprof cpptest'. +// +// If you add new tests to this file, please deallocate any data +// structures you use in the appropriate fashion. This allows us to test +// various destructor code for memory leaks. + + +class sampleAddMethod : public method { +public: + sampleAddMethod() { + this->_signature = "i:ii"; + this->_help = "This method adds two integers together"; + } + void + execute(xmlrpc_c::paramList const& paramList, + value * const retvalP) { + + int const addend(paramList.getInt(0)); + int const adder(paramList.getInt(1)); + + paramList.verifyEnd(2); + + *retvalP = value_int(addend + adder); + } +}; + + + +class nameMethod : public defaultMethod { + + void + execute(string const& methodName, + xmlrpc_c::paramList const& , // paramList + value * const retvalP) { + + *retvalP = value_string(string("no such method: ") + methodName); + } +}; + + +//========================================================================= +// Test Suites +//========================================================================= + +void +test_fault (void) { + + // Create a new fault and perform basic operations. + XmlRpcFault fault1 = XmlRpcFault(6, "Sample fault"); + TEST(fault1.getFaultCode() == 6); + TEST(fault1.getFaultString() == "Sample fault"); + + // Extract and examine the underlying xmlrpc_env struct. + xmlrpc_env *env1 = fault1.getFaultEnv(); + TEST(env1 != NULL); + TEST(env1->fault_occurred); + TEST(env1->fault_code == 6); + TEST(strcmp(env1->fault_string, "Sample fault") == 0); + + // Test our copy constructor. + XmlRpcFault fault2 = fault1; + TEST(fault2.getFaultCode() == 6); + TEST(fault2.getFaultString() == "Sample fault"); + + // Construct a fault from a pre-existing xmlrpc_env structure. + xmlrpc_env env3; + xmlrpc_env_init(&env3); + xmlrpc_env_set_fault(&env3, 7, "Another fault"); + XmlRpcFault fault3 = XmlRpcFault(&env3); + xmlrpc_env_clean(&env3); + TEST(fault3.getFaultCode() == 7); + TEST(fault3.getFaultString() == "Another fault"); + + // Attempt to construct a fault from a fault-free xmlrpc_env. + xmlrpc_env env4; + xmlrpc_env_init(&env4); + try { + XmlRpcFault fault4 = XmlRpcFault(&env4); + TEST_FAILED("Constructed invalid XmlRpcFault"); + } catch (XmlRpcFault const& fault) { + TEST_PASSED(); + TEST(fault.getFaultCode() == XMLRPC_INTERNAL_ERROR); + } + xmlrpc_env_clean(&env4); +} + + + +void test_env (void) { + + // Declare these here to prevent silly compiler warnings about + // potentially uninitialized variables. + XmlRpcEnv env1; + XmlRpcEnv env2; + + // Perform simple environment tests. + TEST(!env1.hasFaultOccurred()); + xmlrpc_env_set_fault(env1, 8, "Fault 8"); + TEST(env1.hasFaultOccurred()); + XmlRpcFault fault1 = env1.getFault(); + TEST(fault1.getFaultCode() == 8); + TEST(fault1.getFaultString() == "Fault 8"); + + // Test throwIfFaultOccurred. + try { + env2.throwIfFaultOccurred(); + TEST_PASSED(); + } catch (XmlRpcFault const& fault) { + TEST_FAILED("We threw a fault when one hadn't occurred"); + } + xmlrpc_env_set_fault(env2, 9, "Fault 9"); + try { + env2.throwIfFaultOccurred(); + TEST_FAILED("A fault occurred, and we didn't throw it"); + } catch (XmlRpcFault const& fault) { + TEST_PASSED(); + TEST(fault.getFaultCode() == 9); + TEST(fault.getFaultString() == "Fault 9"); + } + + // Make sure we can't get a fault if one hasn't occurred. + XmlRpcEnv env3; + try { + XmlRpcFault fault3 = env3.getFault(); + TEST_FAILED("We retrieved a non-existant fault"); + } catch (XmlRpcFault const& fault) { + TEST_PASSED(); + TEST(fault.getFaultCode() == XMLRPC_INTERNAL_ERROR); + } +} + +void test_value (void) { + XmlRpcEnv env; + + // Test basic reference counting behavior. + xmlrpc_value *v = xmlrpc_build_value(env, "i", (xmlrpc_int32) 1); + env.throwIfFaultOccurred(); + XmlRpcValue val1 = XmlRpcValue(v, XmlRpcValue::CONSUME_REFERENCE); + v = xmlrpc_build_value(env, "i", (xmlrpc_int32) 2); + env.throwIfFaultOccurred(); + XmlRpcValue val2 = v; + xmlrpc_DECREF(v); + + // Borrow a reference. + v = xmlrpc_build_value(env, "i", (xmlrpc_int32) 3); + env.throwIfFaultOccurred(); + XmlRpcValue val3 = XmlRpcValue(v, XmlRpcValue::CONSUME_REFERENCE); + xmlrpc_value *borrowed = val3.borrowReference(); + TEST(borrowed == v); + + // Make a reference. + v = xmlrpc_build_value(env, "i", (xmlrpc_int32) 4); + env.throwIfFaultOccurred(); + XmlRpcValue val4 = XmlRpcValue(v, XmlRpcValue::CONSUME_REFERENCE); + xmlrpc_value *made = val4.makeReference(); + TEST(made == v); + xmlrpc_DECREF(made); + + // Test our default constructor. + XmlRpcValue val5; + TEST(val5.getBool() == false); + + // Test our type introspection. + TEST(XmlRpcValue::makeInt(0).getType() == XMLRPC_TYPE_INT); + + // Test our basic data types. + TEST(XmlRpcValue::makeInt(30).getInt() == 30); + TEST(XmlRpcValue::makeInt(-30).getInt() == -30); + TEST(XmlRpcValue::makeBool(true).getBool() == true); + TEST(XmlRpcValue::makeBool(false).getBool() == false); + TEST(XmlRpcValue::makeDateTime("19980717T14:08:55").getRawDateTime() == + "19980717T14:08:55"); + TEST(XmlRpcValue::makeString("foo").getString() == "foo"); + TEST(XmlRpcValue::makeString("bar", 3).getString() == "bar"); + TEST(XmlRpcValue::makeString("bar", 3).getString() == "bar"); + TEST(XmlRpcValue::makeString("a\0b").getString() == string("a\0b")); + XmlRpcValue::makeArray().getArray(); + XmlRpcValue::makeStruct().getStruct(); + + // Test Base64 values. + const unsigned char *b64_data; + size_t b64_len; + XmlRpcValue val6 = XmlRpcValue::makeBase64((unsigned char*) "a\0\0b", 4); + val6.getBase64(b64_data, b64_len); + TEST(b64_len == 4); + TEST(memcmp(b64_data, "a\0\0b", 4) == 0); + + // Test arrays. + XmlRpcValue array = XmlRpcValue::makeArray(); + TEST(array.arraySize() == 0); + array.arrayAppendItem(XmlRpcValue::makeString("foo")); + TEST(array.arraySize() == 1); + array.arrayAppendItem(XmlRpcValue::makeString("bar")); + TEST(array.arraySize() == 2); + TEST(array.arrayGetItem(0).getString() == "foo"); + TEST(array.arrayGetItem(1).getString() == "bar"); + + // Test structs. + XmlRpcValue strct = XmlRpcValue::makeStruct(); + TEST(strct.structSize() == 0); + strct.structSetValue("foo", XmlRpcValue::makeString("fooval")); + TEST(strct.structSize() == 1); + strct.structSetValue("bar", XmlRpcValue::makeString("barval")); + TEST(strct.structSize() == 2); + TEST(strct.structHasKey("bar")); + TEST(!strct.structHasKey("nosuch")); + for (size_t i = 0; i < strct.structSize(); i++) { + string key; + XmlRpcValue value; + strct.structGetKeyAndValue(i, key, value); + TEST(key + "val" == value.getString()); + } +} + + + +static void +testXmlRpcCpp() { +/*---------------------------------------------------------------------------- + Test the legacy XmlRpcCpp.cpp library +-----------------------------------------------------------------------------*/ + cout << "Testing XmlRpcCpp library..." << endl; + + test_fault(); + test_env(); + test_value(); +} + + + +class intTestSuite : public testSuite { +public: + virtual string suiteName() { + return "intTestSuite"; + } + virtual void runtests(unsigned int const) { + value_int int1(7); + TEST(static_cast(int1) == 7); + value_int int2(-7); + TEST(static_cast(int2) == -7); + value val1(int1); + TEST(val1.type() == value::TYPE_INT); + value_int int3(val1); + TEST(static_cast(int3) == 7); + try { + value_int int4(value_double(3.7)); + TEST_FAILED("invalid cast double-int suceeded"); + } catch (error) {} + } +}; + + + +class doubleTestSuite : public testSuite { +public: + virtual string suiteName() { + return "doubleTestSuite"; + } + virtual void runtests(unsigned int const) { + value_double double1(3.14); + TEST(static_cast(double1) == 3.14); + value val1(double1); + TEST(val1.type() == value::TYPE_DOUBLE); + value_double double2(val1); + TEST(static_cast(double2) == 3.14); + try { + value_double double4(value_int(4)); + TEST_FAILED("invalid cast int-double suceeded"); + } catch (error) {} + } +}; + + + +class booleanTestSuite : public testSuite { +public: + virtual string suiteName() { + return "booleanTestSuite"; + } + virtual void runtests(unsigned int const) { + value_boolean boolean1(true); + TEST(static_cast(boolean1) == true); + value_boolean boolean2(false); + TEST(static_cast(boolean2) == false); + value val1(boolean1); + TEST(val1.type() == value::TYPE_BOOLEAN); + value_boolean boolean3(val1); + TEST(static_cast(boolean3) == true); + try { + value_boolean boolean4(value_int(4)); + TEST_FAILED("invalid cast int-boolean suceeded"); + } catch (error) {} + } +}; + + + +class datetimeTestSuite : public testSuite { +public: + virtual string suiteName() { + return "datetimeTestSuite"; + } + virtual void runtests(unsigned int const) { + time_t const testTime(900684535); + value_datetime datetime1("19980717T14:08:55"); + TEST(static_cast(datetime1) == testTime); + value_datetime datetime2(testTime); + TEST(static_cast(datetime2) == testTime); + value val1(datetime1); + TEST(val1.type() == value::TYPE_DATETIME); + value_datetime datetime3(val1); + TEST(static_cast(datetime3) == testTime); + try { + value_datetime datetime4(value_int(4)); + TEST_FAILED("invalid cast int-datetime suceeded"); + } catch (error) {} + } +}; + + + +class stringTestSuite : public testSuite { +public: + virtual string suiteName() { + return "stringTestSuite"; + } + virtual void runtests(unsigned int const) { + value_string string1("hello world"); + TEST(static_cast(string1) == "hello world"); + value_string string2("embedded\0null"); + TEST(static_cast(string2) == "embedded\0null"); + value val1(string1); + TEST(val1.type() == value::TYPE_STRING); + value_string string3(val1); + TEST(static_cast(string3) == "hello world"); + try { + value_string string4(value_int(4)); + TEST_FAILED("invalid cast int-string suceeded"); + } catch (error) {} + } +}; + + + +class bytestringTestSuite : public testSuite { +public: + virtual string suiteName() { + return "bytestringTestSuite"; + } + virtual void runtests(unsigned int const) { + unsigned char bytestringArray[] = {0x10, 0x11, 0x12, 0x13, 0x14}; + vector + bytestringData(&bytestringArray[0], &bytestringArray[4]); + value_bytestring bytestring1(bytestringData); + + vector const dataReadBack1( + bytestring1.vectorUcharValue()); + TEST(dataReadBack1 == bytestringData); + value val1(bytestring1); + TEST(val1.type() == value::TYPE_BYTESTRING); + value_bytestring bytestring2(val1); + vector const dataReadBack2( + bytestring2.vectorUcharValue()); + TEST(dataReadBack2 == bytestringData); + try { + value_bytestring bytestring4(value_int(4)); + TEST_FAILED("invalid cast int-bytestring suceeded"); + } catch (error) {} + } +}; + + + +class nilTestSuite : public testSuite { +public: + virtual string suiteName() { + return "nilTestSuite"; + } + virtual void runtests(unsigned int const) { + value_nil nil1; + value val1(nil1); + TEST(val1.type() == value::TYPE_NIL); + value_nil nil2(val1); + try { + value_nil nil4(value_int(4)); + TEST_FAILED("invalid cast int-nil suceeded"); + } catch (error) {} + } +}; + + + +class structTestSuite : public testSuite { +public: + virtual string suiteName() { + return "structTestSuite"; + } + virtual void runtests(unsigned int const) { + map structData; + pair member("the_integer", value_int(9)); + structData.insert(member); + + value_struct struct1(structData); + + map dataReadBack(struct1); + + TEST(static_cast(value_int(dataReadBack["the_integer"])) == 9); + + value val1(struct1); + TEST(val1.type() == value::TYPE_STRUCT); + value_struct struct2(val1); + try { + value_struct struct4(value_int(4)); + TEST_FAILED("invalid cast int-struct suceeded"); + } catch (error) {} + } +}; + + + +class arrayTestSuite : public testSuite { +public: + virtual string suiteName() { + return "arrayTestSuite"; + } + virtual void runtests(unsigned int const) { + vector arrayData; + arrayData.push_back(value_int(7)); + arrayData.push_back(value_double(2.78)); + arrayData.push_back(value_string("hello world")); + value_array array1(arrayData); + + TEST(array1.size() == 3); + vector dataReadBack1(array1.vectorValueValue()); + TEST(dataReadBack1[0].type() == value::TYPE_INT); + TEST(static_cast(value_int(dataReadBack1[0])) == 7); + TEST(dataReadBack1[1].type() == value::TYPE_DOUBLE); + TEST(static_cast(value_double(dataReadBack1[1])) == 2.78); + TEST(dataReadBack1[2].type() == value::TYPE_STRING); + TEST(static_cast(value_string(dataReadBack1[2])) == + "hello world"); + + value val1(array1); + TEST(val1.type() == value::TYPE_ARRAY); + value_array array2(val1); + TEST(array2.size() == 3); + try { + value_array array4(value_int(4)); + TEST_FAILED("invalid cast int-array suceeded"); + } catch (error) {} + } +}; + + + +class valueTestSuite : public testSuite { + +public: + virtual string suiteName() { + return "valueTestSuite"; + } + virtual void runtests(unsigned int const indentation) { + + intTestSuite().run(indentation+1); + doubleTestSuite().run(indentation+1); + booleanTestSuite().run(indentation+1); + datetimeTestSuite().run(indentation+1); + stringTestSuite().run(indentation+1); + bytestringTestSuite().run(indentation+1); + nilTestSuite().run(indentation+1); + structTestSuite().run(indentation+1); + arrayTestSuite().run(indentation+1); + } +}; + + +namespace { +string const noElementFoundXml( + "\r\n" + "\r\n" + "\r\n" + "\r\n" + "faultCode\r\n" + "-503\r\n" + "faultString\r\n" + "Call XML not a proper XML-RPC call. " + "Call is not valid XML. no element found" + "\r\n" + "\r\n" + "\r\n" + "\r\n" + ); + +string const sampleAddGoodCallXml( + "\r\n" + "\r\n" + "sample.add\r\n" + "\r\n" + "5\r\n" + "7\r\n" + "\r\n" + "\r\n" + ); + +string const sampleAddGoodResponseXml( + "\r\n" + "\r\n" + "\r\n" + "12\r\n" + "\r\n" + "\r\n" + ); + + +string const sampleAddBadCallXml( + "\r\n" + "\r\n" + "sample.add\r\n" + "\r\n" + "5\r\n" + "\r\n" + "\r\n" + ); + +string const sampleAddBadResponseXml( + "\r\n" + "\r\n" + "\r\n" + "\r\n" + "faultCode\r\n" + "-501\r\n" + "faultString\r\n" + "Not enough parameters\r\n" + "\r\n" + "\r\n" + "\r\n" + ); + + +string const nonexistentMethodCallXml( + "\r\n" + "\r\n" + "nosuchmethod\r\n" + "\r\n" + "5\r\n" + "7\r\n" + "\r\n" + "\r\n" + ); + +string const nonexistentMethodYesDefResponseXml( + "\r\n" + "\r\n" + "\r\n" + "no such method: nosuchmethod" + "\r\n" + "\r\n" + "\r\n" + ); + +string const nonexistentMethodNoDefResponseXml( + "\r\n" + "\r\n" + "\r\n" + "\r\n" + "faultCode\r\n" + "-506\r\n" + "faultString\r\n" + "Method 'nosuchmethod' not defined" + "\r\n" + "\r\n" + "\r\n" + "\r\n" + ); + +} // namespace + + +class paramListTestSuite : public testSuite { + +public: + virtual string suiteName() { + return "paramListTestSuite"; + } + virtual void runtests(unsigned int const) { + + paramList paramList1; + TEST(paramList1.size() == 0); + + paramList1.add(value_int(7)); + paramList1.add(value_boolean(true)); + paramList1.add(value_double(3.14)); + time_t const timeZero(0); + paramList1.add(value_datetime(timeZero)); + time_t const timeFuture(time(NULL)+100); + paramList1.add(value_datetime(timeFuture)); + paramList1.add(value_string("hello world")); + unsigned char bytestringArray[] = {0x10, 0x11, 0x12, 0x13, 0x14}; + vector + bytestringData(&bytestringArray[0], &bytestringArray[4]); + paramList1.add(value_bytestring(bytestringData)); + vector arrayData; + arrayData.push_back(value_int(7)); + arrayData.push_back(value_double(2.78)); + arrayData.push_back(value_string("hello world")); + paramList1.add(value_array(arrayData)); + map structData; + pair member("the_integer", value_int(9)); + structData.insert(member); + paramList1.add(value_struct(structData)); + paramList1.add(value_nil()); + + TEST(paramList1.size() == 10); + + TEST(paramList1.getInt(0) == 7); + TEST(paramList1.getInt(0, 7) == 7); + TEST(paramList1.getInt(0, -5, 7) == 7); + TEST(paramList1.getBoolean(1) == true); + TEST(paramList1.getDouble(2) == 3.14); + TEST(paramList1.getDouble(2, 1) == 3.14); + TEST(paramList1.getDouble(2, 1, 4) == 3.14); + TEST(paramList1.getDatetime_sec(3) == 0); + TEST(paramList1.getDatetime_sec(3, paramList::TC_ANY) == timeZero); + TEST(paramList1.getDatetime_sec(3, paramList::TC_NO_FUTURE) + == timeZero); + TEST(paramList1.getDatetime_sec(4, paramList::TC_NO_PAST) + == timeFuture); + TEST(paramList1.getString(5) == "hello world"); + TEST(paramList1.getBytestring(6)[0] == 0x10); + TEST(paramList1.getArray(7).size() == 3); + TEST(paramList1.getArray(7, 3).size() == 3); + TEST(paramList1.getArray(7, 1, 3).size() == 3); + paramList1.getStruct(8)["the_integer"]; + paramList1.getNil(9); + paramList1.verifyEnd(10); + + paramList paramList2(5); + TEST(paramList2.size() == 0); + } +}; + +class registryRegMethodTestSuite : public testSuite { + +public: + virtual string suiteName() { + return "registryRegMethodTestSuite"; + } + virtual void runtests(unsigned int) { + + xmlrpc_c::registry myRegistry; + + myRegistry.addMethod("sample.add", + xmlrpc_c::methodPtr(new sampleAddMethod)); + + myRegistry.disableIntrospection(); + { + string response; + myRegistry.processCall("", &response); + TEST(response == noElementFoundXml); + } + { + string response; + myRegistry.processCall(sampleAddGoodCallXml, &response); + TEST(response == sampleAddGoodResponseXml); + } + { + string response; + myRegistry.processCall(sampleAddBadCallXml, &response); + TEST(response == sampleAddBadResponseXml); + } + } +}; + + + +class registryDefaultMethodTestSuite : public testSuite { + +public: + virtual string suiteName() { + return "registryDefaultMethodTestSuite"; + } + virtual void runtests(unsigned int) { + + xmlrpc_c::registry myRegistry; + + myRegistry.addMethod("sample.add", methodPtr(new sampleAddMethod)); + + { + string response; + myRegistry.processCall(sampleAddGoodCallXml, &response); + TEST(response == sampleAddGoodResponseXml); + } + { + string response; + myRegistry.processCall(nonexistentMethodCallXml, &response); + TEST(response == nonexistentMethodNoDefResponseXml); + } + // We're actually violating the spirit of setDefaultMethod by + // doing this to a registry that's already been used, but as long + // as it works, it's a convenient way to implement this test. + myRegistry.setDefaultMethod(defaultMethodPtr(new nameMethod)); + + { + string response; + myRegistry.processCall(nonexistentMethodCallXml, &response); + TEST(response == nonexistentMethodYesDefResponseXml); + } + } +}; + + + +class registryTestSuite : public testSuite { + +public: + virtual string suiteName() { + return "registryTestSuite"; + } + virtual void runtests(unsigned int const indentation) { + + registryRegMethodTestSuite().run(indentation+1); + registryDefaultMethodTestSuite().run(indentation+1); + } +}; + + + +//========================================================================= +// Test Driver +//========================================================================= + +int +main(int argc, char**) { + + int retval; + + if (argc-1 > 0) { + cout << "Program takes no arguments" << endl; + exit(1); + } + + bool testsPassed; + + try { + // Add your test suites here. + valueTestSuite().run(0); + paramListTestSuite().run(0); + registryTestSuite().run(0); + serverAbyssTestSuite().run(0); + clientTestSuite().run(0); + + testXmlRpcCpp(); + + testsPassed = true; + } catch (error const& error) { + cout << "Unexpected error thrown: " << error.what() << endl; + testsPassed = false; + } catch (XmlRpcFault const& fault) { + cout << "Unexpected XML-RPC fault when running test suites." << endl + << "Fault #" << fault.getFaultCode() + << ": " << fault.getFaultString() << endl; + testsPassed = false; + } catch (...) { + cout << "Unexpected exception when running test suites." << endl; + testsPassed = false; + } + + if (testsPassed) { + cout << "PASSED" << endl; + retval = 0; + } else { + cout << "FAILED" << endl; + retval = 1; + } + return retval; +} diff --git a/src/cpp/test/testclient.cpp b/src/cpp/test/testclient.cpp new file mode 100644 index 0000000..affd1aa --- /dev/null +++ b/src/cpp/test/testclient.cpp @@ -0,0 +1,643 @@ +/*============================================================================= + testclient +=============================================================================== + Test the client C++ facilities of XML-RPC for C/C++. + + Contrary to what you might expect, we use the server facilities too + because we test of the client using a simulated server, via the + "direct" client XML transport we define herein. +=============================================================================*/ +#include +#include +#include +#include +#include +#include + +#include "xmlrpc-c/girerr.hpp" +using girerr::error; +#include "transport_config.h" +#include "xmlrpc-c/base.hpp" +#include "xmlrpc-c/registry.hpp" +#include "xmlrpc-c/client.hpp" +#include "xmlrpc-c/client_simple.hpp" + +#include "tools.hpp" +#include "testclient.hpp" + +using namespace xmlrpc_c; +using namespace std; + + + +class sampleAddMethod : public method { +public: + sampleAddMethod() { + this->_signature = "i:ii"; + this->_help = "This method adds two integers together"; + } + void + execute(xmlrpc_c::paramList const& paramList, + value * const retvalP) { + + int const addend(paramList.getInt(0)); + int const adder(paramList.getInt(1)); + + paramList.verifyEnd(2); + + *retvalP = value_int(addend + adder); + } +}; + + + +class carriageParm_direct : public carriageParm { +public: + carriageParm_direct(registry * const registryP) : registryP(registryP) {} + + registry * registryP; +}; + + +class clientXmlTransport_direct : public clientXmlTransport { + +public: + void + call(xmlrpc_c::carriageParm * const carriageParmP, + string const& callXml, + string * const responseXmlP) { + + carriageParm_direct * const parmP = + dynamic_cast(carriageParmP); + + if (parmP == NULL) + throw(error("Carriage parameter passed to the direct " + "transport is not type carriageParm_direct")); + + parmP->registryP->processCall(callXml, responseXmlP); + } +}; + + + +class clientDirectAsyncTestSuite : public testSuite { +/*---------------------------------------------------------------------------- + See clientDirectTestSuite for a description of how we use a + clientXmlTransport_direct object to test client functions. + + The object of this class tests the async client functions. With + clientXmlTransport_direct, these are pretty simple because the + transport doesn't even implement an asynchronous interface; it + relies on the base class' emulation of start() using call(). + + Some day, we should add true asynchronous capability to + clientXmlTransport_direct and really test things. +-----------------------------------------------------------------------------*/ +public: + virtual string suiteName() { + return "clientDirectAsyncTestSuite"; + } + virtual void runtests(unsigned int const) { + + registry myRegistry; + + myRegistry.addMethod("sample.add", methodPtr(new sampleAddMethod)); + + carriageParm_direct carriageParmDirect(&myRegistry); + clientXmlTransport_direct transportDirect; + client_xml clientDirect(&transportDirect); + paramList paramListSampleAdd1; + paramListSampleAdd1.add(value_int(5)); + paramListSampleAdd1.add(value_int(7)); + paramList paramListSampleAdd2; + paramListSampleAdd2.add(value_int(30)); + paramListSampleAdd2.add(value_int(-10)); + + rpcPtr const rpcSampleAdd1P("sample.add", paramListSampleAdd1); + rpcSampleAdd1P->start(&clientDirect, &carriageParmDirect); + rpcPtr const rpcSampleAdd2P("sample.add", paramListSampleAdd2); + rpcSampleAdd2P->start(&clientDirect, &carriageParmDirect); + + TEST(rpcSampleAdd1P->isFinished()); + TEST(rpcSampleAdd1P->isSuccessful()); + value_int const result1(rpcSampleAdd1P->getResult()); + TEST(static_cast(result1) == 12); + + TEST(rpcSampleAdd2P->isFinished()); + TEST(rpcSampleAdd1P->isSuccessful()); + value_int const result2(rpcSampleAdd2P->getResult()); + TEST(static_cast(result2) == 20); + + EXPECT_ERROR(clientDirect.finishAsync(timeout());); + EXPECT_ERROR(clientDirect.finishAsync(timeout(50));); + } +}; + + + +class clientDirectTestSuite : public testSuite { +/*---------------------------------------------------------------------------- + The object of this class tests the client facilities by using a + special client XML transport defined above and an XML-RPC server we + build ourselves and run inline. We build the server out of a + xmlrpc_c::registry object and our transport just delivers XML + directly to the registry object and gets the response XML from it + and delivers that back. There's no network or socket or pipeline or + anything -- the transport actually executes the XML-RPC method. +-----------------------------------------------------------------------------*/ +public: + virtual string suiteName() { + return "clientDirectTestSuite"; + } + virtual void runtests(unsigned int const indentation) { + registry myRegistry; + + myRegistry.addMethod("sample.add", methodPtr(new sampleAddMethod)); + + carriageParm_direct carriageParmDirect(&myRegistry); + clientXmlTransport_direct transportDirect; + client_xml clientDirect(&transportDirect); + paramList paramListSampleAdd; + paramListSampleAdd.add(value_int(5)); + paramListSampleAdd.add(value_int(7)); + paramList paramListEmpty; + { + /* Test a successful RPC */ + rpcPtr rpcSampleAddP("sample.add", paramListSampleAdd); + rpcSampleAddP->call(&clientDirect, &carriageParmDirect); + TEST(rpcSampleAddP->isFinished()); + TEST(rpcSampleAddP->isSuccessful()); + value_int const resultDirect(rpcSampleAddP->getResult()); + TEST(static_cast(resultDirect) == 12); + } + { + /* Test a failed RPC */ + rpcPtr const rpcSampleAddP("sample.add", paramListEmpty); + rpcSampleAddP->call(&clientDirect, &carriageParmDirect); + TEST(rpcSampleAddP->isFinished()); + TEST(!rpcSampleAddP->isSuccessful()); + fault const fault0(rpcSampleAddP->getFault()); + TEST(fault0.getCode() == fault::CODE_TYPE); + } + + { + /* Test with an auto object transport */ + client_xml clientDirect( + clientXmlTransportPtr(new clientXmlTransport_direct)); + rpcPtr rpcSampleAddP("sample.add", paramListSampleAdd); + rpcSampleAddP->call(&clientDirect, &carriageParmDirect); + TEST(rpcSampleAddP->isFinished()); + TEST(rpcSampleAddP->isSuccessful()); + EXPECT_ERROR(fault fault0(rpcSampleAddP->getFault());); + value_int const resultDirect(rpcSampleAddP->getResult()); + TEST(static_cast(resultDirect) == 12); + } + { + /* Test with implicit RPC -- success */ + rpcOutcome outcome; + clientDirect.call(&carriageParmDirect, "sample.add", + paramListSampleAdd, &outcome); + TEST(outcome.succeeded()); + value_int const result(outcome.getResult()); + TEST(static_cast(result) == 12); + } + { + /* Test with implicit RPC - failure */ + rpcOutcome outcome; + clientDirect.call(&carriageParmDirect, "nosuchmethod", + paramList(), &outcome); + TEST(!outcome.succeeded()); + TEST(outcome.getFault().getCode() == fault::CODE_NO_SUCH_METHOD); + TEST(outcome.getFault().getDescription().size() > 0); + } + + clientDirectAsyncTestSuite().run(indentation+1); + } +}; + + + +class curlTransportTestSuite : public testSuite { + +public: + virtual string suiteName() { + return "curlTransportTestSuite"; + } + virtual void runtests(unsigned int const) { +#if MUST_BUILD_CURL_CLIENT + clientXmlTransport_curl transport0; + clientXmlTransport_curl transport1("eth0"); + clientXmlTransport_curl transport2("eth0", true); + clientXmlTransport_curl transport3("eth0", true, true); + clientXmlTransport_curl transport4( + clientXmlTransport_curl::constrOpt() + .network_interface("eth0") + .no_ssl_verifypeer(true) + .no_ssl_verifyhost(true) + .user_agent("my user agent") + .ssl_cert("/etc/sslcert") + .sslcerttype("PEM") + .sslcertpasswd("mypass") + .sslkey("/etc/sslkey") + .sslkeytype("DER") + .sslkeypasswd("mykeypass") + .sslengine("mysslengine") + .sslengine_default(true) + .sslversion(XMLRPC_SSLVERSION_SSLv2) + .cainfo("/etc/cainfo") + .capath("/etc/cadir") + .randomfile("/dev/random") + .egdsocket("/tmp/egdsocket") + .ssl_cipher_list("RC4-SHA:DEFAULT") + ); + + clientXmlTransport_curl transport5( + clientXmlTransport_curl::constrOpt() + .no_ssl_verifypeer(false)); + + clientXmlTransport_curl transport6( + clientXmlTransport_curl::constrOpt()); + + clientXmlTransportPtr transport1P(new clientXmlTransport_curl); + clientXmlTransportPtr transport2P; + transport2P = transport1P; +#else + EXPECT_ERROR(clientXmlTransport_curl transport0;); + EXPECT_ERROR(clientXmlTransport_curl transport1("eth0");); + EXPECT_ERROR(clientXmlTransport_curl transport0("eth0", true);); + EXPECT_ERROR(clientXmlTransport_curl transport0("eth0", true, true);); +#endif + } +}; + + + +class libwwwTransportTestSuite : public testSuite { + +public: + virtual string suiteName() { + return "libwwwTransportTestSuite"; + } + virtual void runtests(unsigned int const) { +#if MUST_BUILD_LIBWWW_CLIENT + clientXmlTransport_libwww transport0; + clientXmlTransport_libwww transport1("getbent"); + clientXmlTransport_libwww transport2("getbent", "1.0"); + clientXmlTransportPtr transport1P(new clientXmlTransport_libwww); + clientXmlTransportPtr transport2P; + transport2P = transport1P; +#else + EXPECT_ERROR(clientXmlTransport_libwww transport0;); + EXPECT_ERROR(clientXmlTransport_libwww transport1("getbent");); + EXPECT_ERROR(clientXmlTransport_libwww transport2("getbent", "1.0");); +#endif + } +}; + + + +class wininetTransportTestSuite : public testSuite { + +public: + virtual string suiteName() { + return "wininetTransportTestSuite"; + } + virtual void runtests(unsigned int const) { +#if MUST_BUILD_WININET_CLIENT + clientXmlTransport_wininet transport0; + clientXmlTransport_wininet transport1(true); + clientXmlTransportPtr transport1P(new clientXmlTransport_wininet); + clientXmlTransportPtr transport2P; + transport2P = transport1P; +#else + EXPECT_ERROR(clientXmlTransport_wininet transport0;); + EXPECT_ERROR(clientXmlTransport_wininet transport1(true);); +#endif + } +}; + + + +class ambivalentTransportTestSuite : public testSuite { + +public: + virtual string suiteName() { + return "ambivalentTransportTestSuite"; + } + virtual void runtests(unsigned int const) { + vector const typeList( + clientXmlTransport_http::availableTypes()); + + TEST(typeList.size() > 0); + + clientXmlTransportPtr const transportP( + clientXmlTransport_http::create()); + carriageParm_http0 carriageParm0("http://whatsamatta.edux"); + client_xml client0(transportP); + + rpcOutcome outcome; + + // Fails because there's no such server + EXPECT_ERROR( + client0.call(&carriageParm0, "nosuchmethod", paramList(), + &outcome); + ); + } +}; + + + +class clientXmlTransportTestSuite : public testSuite { + +public: + virtual string suiteName() { + return "clientXmlTransportTestSuite"; + } + virtual void runtests(unsigned int const indentation) { + curlTransportTestSuite().run(indentation + 1); + libwwwTransportTestSuite().run(indentation + 1); + wininetTransportTestSuite().run(indentation + 1); + ambivalentTransportTestSuite().run(indentation + 1); + } +}; + + + +class clientSimpleTestSuite : public testSuite { + +public: + virtual string suiteName() { + return "clientSimpleTestSuite"; + } + virtual void runtests(unsigned int const) { + + clientSimple clientS0; + paramList paramList0; + + value result0; + + // These will fail because there's no such server + EXPECT_ERROR(clientS0.call("http://mf.comm", "biteme", &result0);); + + EXPECT_ERROR( + clientS0.call("http://mf.comm", "biteme", "s", &result0, "hard"); + ); + + EXPECT_ERROR( + clientS0.call("http://mf.comm", "biteme", paramList0, &result0); + ); + } +}; + + + +class clientCurlTestSuite : public testSuite { +/*---------------------------------------------------------------------------- + The object of this class tests the combination of a client with + Curl transport. We assume Curl transports themselves have already + been tested and clients with direct transports have already been tested. + + We don't have an HTTP server, so we test only superficially. + + In the future, we could either start a server or use some server that's + normally avaailble on the Internet. +-----------------------------------------------------------------------------*/ +public: + virtual string suiteName() { + return "clientCurlTestSuite"; + } + virtual void runtests(unsigned int) { +#if MUST_BUILD_CURL_CLIENT + clientXmlTransport_curl transportc0; + client_xml client0(&transportc0); + carriageParm_http0 carriageParmHttp("http://suckthis.com"); + carriageParm_curl0 carriageParmCurl("http://suckthis.com"); + connection connection0(&client0, &carriageParmHttp); + paramList paramList0; + + rpcOutcome outcome0; + + // This fails because server doesn't exist + EXPECT_ERROR( + client0.call(&carriageParmHttp, "blowme", paramList0, &outcome0); + ); + + // This fails because server doesn't exist + EXPECT_ERROR( + client0.call(&carriageParmCurl, "blowme", paramList0, &outcome0); + ); + + rpcPtr rpc0P("blowme", paramList0); + + // This fails because server doesn't exist + EXPECT_ERROR(rpc0P->call(&client0, &carriageParmCurl);); + + rpcPtr rpc1P("blowme", paramList0); + // This fails because server doesn't exist + EXPECT_ERROR(rpc1P->call(connection0);); + +#else + // This fails because there is no Curl transport in the library. + EXPECT_ERROR(clientXmlTransport_curl transportc0;); +#endif + } +}; + + + +class carriageParmTestSuite : public testSuite { + +public: + virtual string suiteName() { + return "carriageParmTestSuite"; + } + virtual void runtests(unsigned int) { + carriageParm_http0 carriageParm1("http://suckthis.com"); + carriageParm_curl0 carriageParm2("http://suckthis.com"); + carriageParm_libwww0 carriageParm3("http://suckthis.com"); + carriageParm_wininet0 carriageParm4("http://suckthis.com"); + + carriageParm_http0Ptr carriageParm_http1P( + new carriageParm_http0("http://suckthis.com")); + + carriageParm_http1P->setBasicAuth("bryanh", "12345"); + + carriageParm_curl0Ptr carriageParm_curl1P( + new carriageParm_curl0("http://suckthis.com")); + + carriageParm_curl1P->setBasicAuth("bryanh", "12345"); + + carriageParm_libwww0Ptr carriageParm_libwww1P( + new carriageParm_libwww0("http://suckthis.com")); + + carriageParm_libwww1P->setBasicAuth("bryanh", "12345"); + + carriageParm_wininet0Ptr carriageParm_wininet1P( + new carriageParm_wininet0("http://suckthis.com")); + + carriageParm_wininet1P->setBasicAuth("bryanh", "12345"); + } +}; + + + +class clientRpcTestSuite : public testSuite { + +public: + virtual string suiteName() { + return "clientRpcTestSuite"; + } + virtual void runtests(unsigned int) { + + registry myRegistry; + + myRegistry.addMethod("sample.add", methodPtr(new sampleAddMethod)); + + carriageParm_direct carriageParm0(&myRegistry); + clientXmlTransport_direct transportDirect; + client_xml client0(&transportDirect); + paramList paramListSampleAdd; + paramListSampleAdd.add(value_int(5)); + paramListSampleAdd.add(value_int(7)); + paramList paramListEmpty; + + { + /* Test a successful RPC */ + rpcPtr rpcSampleAddP("sample.add", paramListSampleAdd); + TEST(!rpcSampleAddP->isFinished()); + // This fails because RPC has not been executed + EXPECT_ERROR(value result(rpcSampleAddP->getResult());); + + rpcSampleAddP->call(&client0, &carriageParm0); + + TEST(rpcSampleAddP->isFinished()); + TEST(rpcSampleAddP->isSuccessful()); + value_int const resultDirect(rpcSampleAddP->getResult()); + TEST(static_cast(resultDirect) == 12); + // This fails because the RPC succeeded + EXPECT_ERROR(fault fault0(rpcSampleAddP->getFault());); + // This fails because the RPC has already been executed + EXPECT_ERROR( + rpcSampleAddP->call(&client0, &carriageParm0);); + // This fails because the RPC has already been executed + EXPECT_ERROR( + rpcSampleAddP->start(&client0, &carriageParm0);); + } + { + /* Test a failed RPC */ + rpcPtr const rpcSampleAddP("sample.add", paramListEmpty); + rpcSampleAddP->call(&client0, &carriageParm0); + TEST(rpcSampleAddP->isFinished()); + TEST(!rpcSampleAddP->isSuccessful()); + fault const fault0(rpcSampleAddP->getFault()); + TEST(fault0.getCode() == fault::CODE_TYPE); + // This fails because the RPC failed + EXPECT_ERROR(value result(rpcSampleAddP->getResult());); + // This fails because the RPC has already been executed + EXPECT_ERROR( + rpcSampleAddP->call(&client0, &carriageParm0);); + // This fails because the RPC has already been executed + EXPECT_ERROR( + rpcSampleAddP->start(&client0, &carriageParm0);); + } + { + /* Test with a connection */ + + connection connection0(&client0, &carriageParm0); + + rpcPtr const rpcSampleAddP("sample.add", paramListSampleAdd); + + rpcSampleAddP->call(connection0); + + TEST(rpcSampleAddP->isFinished()); + value_int const resultDirect(rpcSampleAddP->getResult()); + TEST(static_cast(resultDirect) == 12); + } + } +}; + + + +class clientPtrTestSuite : public testSuite { + +public: + virtual string suiteName() { + return "clientPtrTestSuite"; + } + virtual void runtests(unsigned int) { + registry myRegistry; + + myRegistry.addMethod("sample.add", methodPtr(new sampleAddMethod)); + carriageParm_direct carriageParmDirect(&myRegistry); + clientXmlTransport_direct transportDirect; + + clientPtr clientP(new client_xml(&transportDirect)); + + clientPtr client2P(clientP); + + { + clientPtr client3P; + client3P = client2P; + } + rpcOutcome outcome; + + clientP->call(&carriageParmDirect, "nosuchmethod", + paramList(), &outcome); + TEST(!outcome.succeeded()); + TEST(outcome.getFault().getCode() == fault::CODE_NO_SUCH_METHOD); + } +}; + + + +class serverAccessorTestSuite : public testSuite { + +public: + virtual string suiteName() { + return "serverAccessorTestSuite"; + } + virtual void runtests(unsigned int) { + clientXmlTransportPtr const transportP(new clientXmlTransport_direct); + clientPtr const clientP(new client_xml(transportP)); + registry myRegistry; + carriageParmPtr const carriageParmP( + new carriageParm_direct(&myRegistry)); + + serverAccessor server1(clientP, carriageParmP); + + rpcOutcome outcome; + server1.call("nosuchmethod", paramList(), &outcome); + TEST(!outcome.succeeded()); + TEST(outcome.getFault().getCode() == fault::CODE_NO_SUCH_METHOD); + TEST(outcome.getFault().getDescription().size() > 0); + } +}; + + + +string +clientTestSuite::suiteName() { + return "clientTestSuite"; +} + + + +void +clientTestSuite::runtests(unsigned int const indentation) { + + clientDirectTestSuite().run(indentation+1); + + clientXmlTransportTestSuite().run(indentation+1); + + carriageParmTestSuite().run(indentation+1); + + clientCurlTestSuite().run(indentation+1); + + clientRpcTestSuite().run(indentation+1); + + clientPtrTestSuite().run(indentation+1); + + clientSimpleTestSuite().run(indentation+1); + + serverAccessorTestSuite().run(indentation+1); +} diff --git a/src/cpp/test/testclient.hpp b/src/cpp/test/testclient.hpp new file mode 100644 index 0000000..20c1b9f --- /dev/null +++ b/src/cpp/test/testclient.hpp @@ -0,0 +1,9 @@ +#include "tools.hpp" + +class clientTestSuite : public testSuite { + +public: + virtual std::string suiteName(); + virtual void runtests(unsigned int const indentation); +}; + diff --git a/src/cpp/test/testclient_dummy.cpp b/src/cpp/test/testclient_dummy.cpp new file mode 100644 index 0000000..5bf3018 --- /dev/null +++ b/src/cpp/test/testclient_dummy.cpp @@ -0,0 +1,29 @@ +/*============================================================================= + testclient_dummy +=============================================================================== + This is a substitute for testclient.cpp, for use in a test program that is + not linked with the client libraries. + + It simply passes the test. +=============================================================================*/ + +#include +#include + +#include "tools.hpp" +#include "testclient.hpp" + +using namespace std; + +string +clientTestSuite::suiteName() { + return "clientTestSuite"; +} + + +void +clientTestSuite::runtests(unsigned int const indentation) { + + cout << string((indentation+1)*2, ' ') + << "Running dummy test." << endl; +} diff --git a/src/cpp/test/tools.cpp b/src/cpp/test/tools.cpp new file mode 100644 index 0000000..13728f9 --- /dev/null +++ b/src/cpp/test/tools.cpp @@ -0,0 +1,64 @@ +#include +#include +#include +#include "xmlrpc-c/girerr.hpp" +using girerr::error; +using girerr::throwf; + +#include "tools.hpp" + +using namespace std; + +testSuite::~testSuite() { +} + + + +void +testSuite::run(unsigned int const indentation) { + try { + cout << string(indentation*2, ' ') + << "Running " << suiteName() << endl; + this->runtests(indentation); + } catch (error const& error) { + throwf("%s failed. %s", suiteName().c_str(), error.what()); + } catch (...) { + throw(error(suiteName() + string(" failed. ") + + string("It threw an unexpected type of object"))); + } + cout << string(indentation*2, ' ') + << suiteName() << " tests passed." << endl; +} + + + +// This is a good place to set a breakpoint. +void +logFailedTest(const char * const fileName, + unsigned int const lineNum, + const char * const statement) { + + ostringstream msg; + + msg << endl + << fileName << ":" << lineNum + << ": expected (" << statement << ")" << endl; + + throw(error(msg.str())); +} + + +error +fileLineError(string const filename, + unsigned int const lineNumber, + string const description) { + + ostringstream combined; + + combined << filename << ":" << lineNumber << " " << description; + + return error(combined.str()); +} + + + diff --git a/src/cpp/test/tools.hpp b/src/cpp/test/tools.hpp new file mode 100644 index 0000000..a329b47 --- /dev/null +++ b/src/cpp/test/tools.hpp @@ -0,0 +1,72 @@ +#ifndef TEST_HPP_INCLUDED +#define TEST_HPP_INCLUDED + +#include + +#include "xmlrpc-c/girerr.hpp" +using girerr::error; + +class testSuite { +/*---------------------------------------------------------------------------- + This is a base class for a test suite. Give the suite a name + (to be used in messages about it) and some test code via + virtual methods suiteName() and runtests(), respectively. + + runtests() should throw either an 'error' object or an 'XmlRpcFault' + object if the test fails. It should throw something else if the + test can't run. It should throw nothing if the tests pass. + + You don't normally keep an object of this class around. You don't + even give it a name. You simply refer to a literal object, like so: + + myTestSuite().run(0) +-----------------------------------------------------------------------------*/ +public: + virtual ~testSuite(); + + void run(unsigned int const indentation); + + virtual void runtests(unsigned int const) { + throw(error("test suite does not have a runtests() method")); + }; + virtual std::string suiteName() { + return "unnamed test suite"; + } +}; + + + +void +logFailedTest(const char * const fileName, + unsigned int const lineNum, + const char * const statement); + +error +fileLineError(std::string const filename, + unsigned int const lineNumber, + std::string const description); + +#define TEST(statement) \ + do { \ + if (!(statement)) \ + logFailedTest(__FILE__, __LINE__, #statement); \ + } while (0) + + +#define TEST_PASSED() \ + do { } while (0) + +#define TEST_FAILED(reason) \ + do { \ + logFailedTest(__FILE__, __LINE__, (reason)); \ + } while (0) + +#define EXPECT_ERROR(statement) \ + do { try { statement } catch (error) {break;} \ + throw(fileLineError(__FILE__, __LINE__, "Didn't get expected error")); \ + } while (0) + +#define trickToStraightenOutEmacsIndentation \ +; + +#endif diff --git a/src/cpp/unix.make b/src/cpp/unix.make new file mode 100644 index 0000000..cb7c69a --- /dev/null +++ b/src/cpp/unix.make @@ -0,0 +1,23 @@ +# -*-makefile-*- <-- an Emacs control + +# This is stuff for creating General case Unix shared libraries. +# Some Unix systems can't use this. + +# This is to be included by 'Makefile'. Most of the make variables here +# come from the main make file. + +libxmlrpc_cpp.$(SHLIB_SUFFIX).$(MAJ).$(MIN): XmlRpcCpp.o + $(SHLIB_RULE) + +libxmlrpc++.$(SHLIB_SUFFIX).$(MAJ).$(MIN): $(LIBXMLRPCPP_OBJS) + $(SHLIB_RULE) + +libxmlrpc_server++.$(SHLIB_SUFFIX).$(MAJ).$(MIN): $(LIBXMLRPC_SERVERPP_OBJS) + $(SHLIB_RULE) + +libxmlrpc_server_abyss++.$(SHLIB_SUFFIX).$(MAJ).$(MIN): \ + $(LIBXMLRPC_SERVER_ABYSSPP_OBJS) + $(SHLIB_RULE) + +libxmlrpc_client++.$(SHLIB_SUFFIX).$(MAJ).$(MIN): $(LIBXMLRPC_CLIENTPP_OBJS) + $(SHLIB_RULE) diff --git a/src/cpp/value.cpp b/src/cpp/value.cpp new file mode 100644 index 0000000..29457c0 --- /dev/null +++ b/src/cpp/value.cpp @@ -0,0 +1,768 @@ +/***************************************************************************** + value.cpp +****************************************************************************** + This module provides services for dealing with XML-RPC values. Each + type of XML-RPC value is a C++ class. An object represents a + particular XML-RPC value. + + Everything is based on the C services in libxmlrpc. + + We could make things more efficient by using the internal interfaces + via xmlrpc_int.h. We could make them even more efficient by dumping + libxmlrpc altogether for some or all of these services. + + An xmlrpc_c::value object is really just a handle for a C xmlrpc_value + object. You're not supposed to make a pointer to an xmlrpc_c::value + object, but rather copy the object around. + + Because the C xmlrpc_value object does reference counting, it + disappears automatically when the last handle does. To go pure C++, + we'd have to have a C++ object for the value itself and a separate + handle object, like Boost's shared_ptr<>. + + The C++ is designed so that the user never sees the C interface at + all. Unfortunately, the user can see it if he wants because some + class members had to be declared public so that other components of + the library could see them, but the user is not supposed to access + those members. + +*****************************************************************************/ + +#include +#include +#include +#include + +#include "xmlrpc-c/girerr.hpp" +using girerr::error; +#include "xmlrpc-c/base.h" +#include "xmlrpc-c/base_int.h" +#include "env_wrap.hpp" + +#include "xmlrpc-c/base.hpp" + +using namespace std; +using namespace xmlrpc_c; + +namespace { + +void +throwIfError(env_wrap const& env) { + + if (env.env_c.fault_occurred) + throw(error(env.env_c.fault_string)); +} + + + +class cDatetimeValueWrapper { +public: + xmlrpc_value * valueP; + + cDatetimeValueWrapper(time_t const cppvalue) { + env_wrap env; + + this->valueP = xmlrpc_datetime_new_sec(&env.env_c, cppvalue); + throwIfError(env); + } + ~cDatetimeValueWrapper() { + xmlrpc_DECREF(this->valueP); + } +}; + + +class cStringWrapper { +public: + const char * str; + size_t length; + cStringWrapper(xmlrpc_value * valueP) { + env_wrap env; + + xmlrpc_read_string_lp(&env.env_c, valueP, &length, &str); + throwIfError(env); + } + ~cStringWrapper() { + free((char*)str); + } +}; + + + +} // namespace + + + +namespace xmlrpc_c { + +value::value() { + this->cValueP = NULL; +} + + + +value::value(xmlrpc_value * const valueP) { // default constructor + + this->instantiate(valueP); +} + + + +value::value(xmlrpc_c::value const& value) { // copy constructor + this->cValueP = value.cValue(); +} + + + +xmlrpc_c::value& +value::operator=(xmlrpc_c::value const& value) { + + if (this->cValueP != NULL) + throw(error("Assigning to already instantiated xmlrpc_c::value")); + + this->cValueP = value.cValue(); + return *this; // The result of the (a = b) expression +} + + + +value::~value() { + if (this->cValueP) { + xmlrpc_DECREF(this->cValueP); + } +} + + + +void +value::instantiate(xmlrpc_value * const valueP) { + + xmlrpc_INCREF(valueP); + this->cValueP = valueP; +} + + + +xmlrpc_value * +value::cValue() const { + + if (this->cValueP) { + xmlrpc_INCREF(this->cValueP); // For Caller + } + return this->cValueP; +} + + + +void +value::appendToCArray(xmlrpc_value * const arrayP) const { +/*---------------------------------------------------------------------------- + Append this value to the C array 'arrayP'. +----------------------------------------------------------------------------*/ + env_wrap env; + + xmlrpc_array_append_item(&env.env_c, arrayP, this->cValueP); + + throwIfError(env); +} + + + +void +value::addToCStruct(xmlrpc_value * const structP, + string const key) const { +/*---------------------------------------------------------------------------- + Add this value to the C array 'arrayP' with key 'key'. +----------------------------------------------------------------------------*/ + env_wrap env; + + xmlrpc_struct_set_value_n(&env.env_c, structP, + key.c_str(), key.length(), + this->cValueP); + + throwIfError(env); +} + + + +value::type_t +value::type() const { + /* You'd think we could just cast from xmlrpc_type to + value:type_t, but Gcc warns if we do that. So we have to do this + even messier union nonsense. + */ + union { + xmlrpc_type x; + value::type_t y; + } u; + + u.x = xmlrpc_value_type(this->cValueP); + + return u.y; +} + + + +value_int::value_int(int const cppvalue) { + + class cWrapper { + public: + xmlrpc_value * valueP; + + cWrapper(int const cppvalue) { + env_wrap env; + + this->valueP = xmlrpc_int_new(&env.env_c, cppvalue); + throwIfError(env); + } + ~cWrapper() { + xmlrpc_DECREF(this->valueP); + } + }; + + cWrapper wrapper(cppvalue); + + this->instantiate(wrapper.valueP); +} + + + +value_int::value_int(xmlrpc_c::value const baseValue) { + + if (baseValue.type() != xmlrpc_c::value::TYPE_INT) + throw(error("Not integer type. See type() method")); + else { + this->instantiate(baseValue.cValueP); + } +} + + + +value_int::operator int() const { + + int retval; + env_wrap env; + + xmlrpc_read_int(&env.env_c, this->cValueP, &retval); + throwIfError(env); + + return retval; +} + + + +value_double::value_double(double const cppvalue) { + + class cWrapper { + public: + xmlrpc_value * valueP; + + cWrapper(double const cppvalue) { + env_wrap env; + + this->valueP = xmlrpc_double_new(&env.env_c, cppvalue); + throwIfError(env); + } + ~cWrapper() { + xmlrpc_DECREF(this->valueP); + } + }; + + this->instantiate(cWrapper(cppvalue).valueP); +} + + + +value_double::value_double(xmlrpc_c::value const baseValue) { + + if (baseValue.type() != xmlrpc_c::value::TYPE_DOUBLE) + throw(error("Not double type. See type() method")); + else { + this->instantiate(baseValue.cValueP); + } +} + + + +value_double::operator double() const { + + double retval; + + env_wrap env; + + xmlrpc_read_double(&env.env_c, this->cValueP, &retval); + throwIfError(env); + + return retval; +} + + + +value_boolean::value_boolean(bool const cppvalue) { + + class cWrapper { + public: + xmlrpc_value * valueP; + + cWrapper(xmlrpc_bool const cppvalue) { + env_wrap env; + + this->valueP = xmlrpc_bool_new(&env.env_c, cppvalue); + throwIfError(env); + } + ~cWrapper() { + xmlrpc_DECREF(this->valueP); + } + }; + + cWrapper wrapper(cppvalue); + + this->instantiate(wrapper.valueP); +} + + + +value_boolean::operator bool() const { + + xmlrpc_bool retval; + + env_wrap env; + + xmlrpc_read_bool(&env.env_c, this->cValueP, &retval); + throwIfError(env); + + return (bool)retval; +} + + + +value_boolean::value_boolean(xmlrpc_c::value const baseValue) { + + if (baseValue.type() != xmlrpc_c::value::TYPE_BOOLEAN) + throw(error("Not boolean type. See type() method")); + else { + this->instantiate(baseValue.cValueP); + } +} + + + +value_datetime::value_datetime(string const cppvalue) { + + class cWrapper { + public: + xmlrpc_value * valueP; + + cWrapper(string const cppvalue) { + env_wrap env; + + this->valueP = xmlrpc_datetime_new_str(&env.env_c, + cppvalue.c_str()); + throwIfError(env); + } + ~cWrapper() { + xmlrpc_DECREF(this->valueP); + } + }; + + cWrapper wrapper(cppvalue); + + this->instantiate(wrapper.valueP); +} + + + +value_datetime::value_datetime(time_t const cppvalue) { + + cDatetimeValueWrapper wrapper(cppvalue); + + this->instantiate(wrapper.valueP); +} + + + +value_datetime::value_datetime(struct timeval const& cppvalue) { + + cDatetimeValueWrapper wrapper(cppvalue.tv_sec); + + this->instantiate(wrapper.valueP); +} + + + +value_datetime::value_datetime(struct timespec const& cppvalue) { + + cDatetimeValueWrapper wrapper(cppvalue.tv_sec); + + this->instantiate(wrapper.valueP); +} + + + +value_datetime::value_datetime(xmlrpc_c::value const baseValue) { + + if (baseValue.type() != xmlrpc_c::value::TYPE_DATETIME) + throw(error("Not datetime type. See type() method")); + else { + this->instantiate(baseValue.cValueP); + } +} + + + +value_datetime::operator time_t() const { + + time_t retval; + env_wrap env; + + xmlrpc_read_datetime_sec(&env.env_c, this->cValueP, &retval); + throwIfError(env); + + return retval; +} + + + +value_string::value_string(string const& cppvalue) { + + class cWrapper { + public: + xmlrpc_value * valueP; + + cWrapper(string const cppvalue) { + env_wrap env; + + this->valueP = xmlrpc_string_new(&env.env_c, cppvalue.c_str()); + throwIfError(env); + } + ~cWrapper() { + xmlrpc_DECREF(this->valueP); + } + }; + + cWrapper wrapper(cppvalue); + + this->instantiate(wrapper.valueP); +} + + + +value_string::value_string(xmlrpc_c::value const baseValue) { + + if (baseValue.type() != xmlrpc_c::value::TYPE_STRING) + throw(error("Not string type. See type() method")); + else { + this->instantiate(baseValue.cValueP); + } +} + + + +value_string::operator string() const { + + env_wrap env; + + cStringWrapper adapter(this->cValueP); + + return string(adapter.str, adapter.length); +} + + + +value_bytestring::value_bytestring( + vector const& cppvalue) { + + class cWrapper { + public: + xmlrpc_value * valueP; + + cWrapper(vector const& cppvalue) { + env_wrap env; + + this->valueP = + xmlrpc_base64_new(&env.env_c, cppvalue.size(), &cppvalue[0]); + throwIfError(env); + } + ~cWrapper() { + xmlrpc_DECREF(this->valueP); + } + }; + + cWrapper wrapper(cppvalue); + + this->instantiate(wrapper.valueP); +} + + + +vector +value_bytestring::vectorUcharValue() const { + + class cWrapper { + public: + const unsigned char * contents; + size_t length; + + cWrapper(xmlrpc_value * const valueP) { + env_wrap env; + + xmlrpc_read_base64(&env.env_c, valueP, &length, &contents); + throwIfError(env); + } + ~cWrapper() { + free((void*)contents); + } + }; + + cWrapper wrapper(this->cValueP); + + return vector(&wrapper.contents[0], + &wrapper.contents[wrapper.length]); +} + + + +size_t +value_bytestring::length() const { + + env_wrap env; + size_t length; + + xmlrpc_read_base64_size(&env.env_c, this->cValueP, &length); + throwIfError(env); + + return length; +} + + + +value_bytestring::value_bytestring(xmlrpc_c::value const baseValue) { + + if (baseValue.type() != xmlrpc_c::value::TYPE_BYTESTRING) + throw(error("Not byte string type. See type() method")); + else { + this->instantiate(baseValue.cValueP); + } +} + + + +value_array::value_array(vector const& cppvalue) { + + class cWrapper { + public: + xmlrpc_value * valueP; + + cWrapper() { + env_wrap env; + + this->valueP = xmlrpc_array_new(&env.env_c); + throwIfError(env); + } + ~cWrapper() { + xmlrpc_DECREF(this->valueP); + } + }; + + cWrapper wrapper; + + vector::const_iterator i; + for (i = cppvalue.begin(); i != cppvalue.end(); ++i) + i->appendToCArray(wrapper.valueP); + + this->instantiate(wrapper.valueP); +} + + + +value_array::value_array(xmlrpc_c::value const baseValue) { + + if (baseValue.type() != xmlrpc_c::value::TYPE_ARRAY) + throw(error("Not array type. See type() method")); + else { + this->instantiate(baseValue.cValueP); + } +} + + + +vector +value_array::vectorValueValue() const { + + env_wrap env; + + unsigned int arraySize; + + arraySize = xmlrpc_array_size(&env.env_c, this->cValueP); + throwIfError(env); + + vector retval(arraySize); + + for (unsigned int i = 0; i < arraySize; ++i) { + + class cWrapper { + public: + xmlrpc_value * valueP; + + cWrapper(xmlrpc_value * const arrayP, + unsigned int const index) { + env_wrap env; + + xmlrpc_array_read_item(&env.env_c, arrayP, index, &valueP); + + throwIfError(env); + } + ~cWrapper() { + xmlrpc_DECREF(valueP); + } + }; + + cWrapper wrapper(this->cValueP, i); + + retval[i].instantiate(wrapper.valueP); + } + + return retval; +} + + + +size_t +value_array::size() const { + + env_wrap env; + unsigned int arraySize; + + arraySize = xmlrpc_array_size(&env.env_c, this->cValueP); + throwIfError(env); + + return arraySize; +} + + + +value_struct::value_struct( + map const &cppvalue) { + + class cWrapper { + public: + xmlrpc_value * valueP; + + cWrapper() { + env_wrap env; + + this->valueP = xmlrpc_struct_new(&env.env_c); + throwIfError(env); + } + ~cWrapper() { + xmlrpc_DECREF(this->valueP); + } + }; + + cWrapper wrapper; + + map::const_iterator i; + for (i = cppvalue.begin(); i != cppvalue.end(); ++i) { + xmlrpc_c::value mapvalue(i->second); + string mapkey(i->first); + mapvalue.addToCStruct(wrapper.valueP, mapkey); + } + + this->instantiate(wrapper.valueP); +} + + + +value_struct::value_struct(xmlrpc_c::value const baseValue) { + + if (baseValue.type() != xmlrpc_c::value::TYPE_STRUCT) + throw(error("Not struct type. See type() method")); + else { + this->instantiate(baseValue.cValueP); + } +} + + + +value_struct::operator map() const { + + env_wrap env; + unsigned int structSize; + + structSize = xmlrpc_struct_size(&env.env_c, this->cValueP); + throwIfError(env); + + map retval; + + for (unsigned int i = 0; i < structSize; ++i) { + class cMemberWrapper { + public: + xmlrpc_value * keyP; + xmlrpc_value * valueP; + + cMemberWrapper(xmlrpc_value * const structP, + unsigned int const index) { + + env_wrap env; + + xmlrpc_struct_read_member(&env.env_c, structP, index, + &keyP, &valueP); + + throwIfError(env); + } + ~cMemberWrapper() { + xmlrpc_DECREF(keyP); + xmlrpc_DECREF(valueP); + } + }; + + cMemberWrapper memberWrapper(this->cValueP, i); + + cStringWrapper keyWrapper(memberWrapper.keyP); + + string const key(keyWrapper.str, keyWrapper.length); + + retval[key] = xmlrpc_c::value(memberWrapper.valueP); + } + + return retval; +} + + + +value_nil::value_nil() { + + class cWrapper { + public: + xmlrpc_value * valueP; + + cWrapper() { + env_wrap env; + + this->valueP = xmlrpc_nil_new(&env.env_c); + throwIfError(env); + } + ~cWrapper() { + xmlrpc_DECREF(this->valueP); + } + }; + + cWrapper wrapper; + + this->instantiate(wrapper.valueP); +} + + + +value_nil::value_nil(xmlrpc_c::value const baseValue) { + + if (baseValue.type() != xmlrpc_c::value::TYPE_NIL) + throw(error("Not nil type. See type() method")); + else { + this->instantiate(baseValue.cValueP); + } +} + + + +} // namespace + diff --git a/src/cpp/wininet.cpp b/src/cpp/wininet.cpp new file mode 100644 index 0000000..8a5a121 --- /dev/null +++ b/src/cpp/wininet.cpp @@ -0,0 +1,168 @@ +/*============================================================================= + wininet.cpp +=============================================================================== + This is the Wininet XML transport of the C++ XML-RPC client library for + Xmlrpc-c. +=============================================================================*/ + +#include +#include +#include + +#include "xmlrpc-c/girerr.hpp" +using girerr::error; +using girerr::throwf; +#include "xmlrpc-c/girmem.hpp" +using girmem::autoObjectPtr; +using girmem::autoObject; +#include "env_wrap.hpp" +#include "xmlrpc-c/base.h" +#include "xmlrpc-c/client.h" +#include "xmlrpc-c/transport.h" +#include "xmlrpc-c/base_int.h" + +#include "xmlrpc_wininet_transport.h" + +/* transport_config.h defines MUST_BUILD_WININET_CLIENT */ +#include "transport_config.h" + +#include "xmlrpc-c/client_transport.hpp" + + +using namespace std; +using namespace xmlrpc_c; + + +namespace { + +class globalConstant { +public: + globalConstant(); + ~globalConstant(); +}; + + + +globalConstant::globalConstant() { + + // Not thread safe + + xmlrpc_transport_setup setupFn; + +#if MUST_BUILD_WININET_CLIENT + setupFn = xmlrpc_wininet_transport_ops.setup_global_const; +#else + setupFn = NULL; +#endif + if (setupFn) { + env_wrap env; + + setupFn(&env.env_c); // Not thread safe + + if (env.env_c.fault_occurred) + throwf("Failed to do global initialization " + "of Wininet transport code. %s", env.env_c.fault_string); + } +} + + + +globalConstant::~globalConstant() { + + // Not thread safe + + xmlrpc_transport_teardown teardownFn; + +#if MUST_BUILD_WININET_CLIENT + teardownFn = xmlrpc_wininet_transport_ops.teardown_global_const; +#else + teardownFn = NULL; +#endif + if (teardownFn) + teardownFn(); // not thread safe +} + + + +globalConstant globalConst; + // This object is never accessed. Its whole purpose to to be born and + // to die, which it does automatically as part of C++ program + // program initialization and termination. + +} // namespace + + +namespace xmlrpc_c { + +carriageParm_wininet0::carriageParm_wininet0( + string const serverUrl + ) { + + this->instantiate(serverUrl); +} + + + +carriageParm_wininet0Ptr::carriageParm_wininet0Ptr() { + // Base class constructor will construct pointer that points to nothing +} + + + +carriageParm_wininet0Ptr::carriageParm_wininet0Ptr( + carriageParm_wininet0 * const carriageParmP) { + this->point(carriageParmP); +} + + + +carriageParm_wininet0 * +carriageParm_wininet0Ptr::operator->() const { + + autoObject * const p(this->objectP); + return dynamic_cast(p); +} + + + +#if MUST_BUILD_WININET_CLIENT + +clientXmlTransport_wininet::clientXmlTransport_wininet( + bool const allowInvalidSslCerts + ) { + + struct xmlrpc_wininet_xportparms transportParms; + + transportParms.allowInvalidSSLCerts = allowInvalidSslCerts; + + this->c_transportOpsP = &xmlrpc_wininet_transport_ops; + + env_wrap env; + + xmlrpc_wininet_transport_ops.create( + &env.env_c, 0, "", "", + &transportParms, XMLRPC_WXPSIZE(allowInvalidSSLCerts), + &this->c_transportP); + + if (env.env_c.fault_occurred) + throw(error(env.env_c.fault_string)); +} + +#else // MUST_BUILD_WININET_CLIENT + +clientXmlTransport_wininet::clientXmlTransport_wininet(bool const) { + + throw(error("There is no Wininet client XML transport " + "in this XML-RPC client library")); +} + +#endif + + + +clientXmlTransport_wininet::~clientXmlTransport_wininet() { + + this->c_transportOpsP->destroy(this->c_transportP); +} + +} // namespace diff --git a/src/cpp/xml.cpp b/src/cpp/xml.cpp new file mode 100644 index 0000000..b76339b --- /dev/null +++ b/src/cpp/xml.cpp @@ -0,0 +1,168 @@ +#include + +#include "xmlrpc-c/girerr.hpp" +using girerr::error; +using girerr::throwf; +#include "xmlrpc-c/base.h" +#include "xmlrpc-c/string_int.h" +#include "xmlrpc-c/base.hpp" +#include "env_wrap.hpp" + +#include "xmlrpc-c/xml.hpp" + +using namespace std; +using namespace xmlrpc_c; + + +namespace { + +class cValueWrapper { +/*---------------------------------------------------------------------------- + Use an object of this class to set up to remove a reference to an + xmlrpc_value object (a C object with manual reference management) + at then end of a scope -- even if the scope ends with a throw. +-----------------------------------------------------------------------------*/ +public: + xmlrpc_value * valueP; + cValueWrapper(xmlrpc_value * valueP) : valueP(valueP) {} + ~cValueWrapper() { xmlrpc_DECREF(valueP); } +}; + +xmlrpc_value * +cArrayFromParamList(paramList const& paramList) { + + env_wrap env; + + xmlrpc_value * paramArrayP; + + paramArrayP = xmlrpc_array_new(&env.env_c); + if (!env.env_c.fault_occurred) { + for (unsigned int i = 0; + i < paramList.size() && !env.env_c.fault_occurred; + ++i) { + cValueWrapper const param(paramList[i].cValue()); + + xmlrpc_array_append_item(&env.env_c, paramArrayP, param.valueP); + } + } + if (env.env_c.fault_occurred) { + xmlrpc_DECREF(paramArrayP); + throw(error(env.env_c.fault_string)); + } + return paramArrayP; +} + +} // namespace + + +namespace xmlrpc_c { +namespace xml { + + +void +generateCall(string const& methodName, + paramList const& paramList, + string * const callXmlP) { +/*---------------------------------------------------------------------------- + Generate the XML for an XML-RPC call, given a method name and parameter + list. +-----------------------------------------------------------------------------*/ + class memblockWrapper { + xmlrpc_mem_block * const memblockP; + public: + memblockWrapper(xmlrpc_mem_block * const memblockP) : + memblockP(memblockP) {} + + ~memblockWrapper() { + XMLRPC_MEMBLOCK_FREE(char, memblockP); + } + }; + + xmlrpc_mem_block * callXmlMP; + env_wrap env; + + callXmlMP = XMLRPC_MEMBLOCK_NEW(char, &env.env_c, 0); + if (!env.env_c.fault_occurred) { + memblockWrapper callXmlHolder(callXmlMP); + // Makes callXmlMP get freed at end of scope + + xmlrpc_value * const paramArrayP(cArrayFromParamList(paramList)); + + xmlrpc_serialize_call(&env.env_c, callXmlMP, methodName.c_str(), + paramArrayP); + + *callXmlP = string(XMLRPC_MEMBLOCK_CONTENTS(char, callXmlMP), + XMLRPC_MEMBLOCK_SIZE(char, callXmlMP)); + + xmlrpc_DECREF(paramArrayP); + } + if (env.env_c.fault_occurred) + throw(error(env.env_c.fault_string)); +} + + + +void +parseResponse(string const& responseXml, + rpcOutcome * const outcomeP) { +/*---------------------------------------------------------------------------- + Parse the XML for an XML-RPC response into an XML-RPC result value. +-----------------------------------------------------------------------------*/ + env_wrap env; + + xmlrpc_value * c_resultP; + int faultCode; + const char * faultString; + + xmlrpc_parse_response2(&env.env_c, responseXml.c_str(), responseXml.size(), + &c_resultP, &faultCode, &faultString); + + if (env.env_c.fault_occurred) + throwf("Unable to find XML-RPC response in what server sent back. %s", + env.env_c.fault_string); + else { + if (faultString) { + *outcomeP = + rpcOutcome(fault(faultString, + static_cast(faultCode))); + xmlrpc_strfree(faultString); + } else { + XMLRPC_ASSERT_VALUE_OK(c_resultP); + *outcomeP = rpcOutcome(value(c_resultP)); + xmlrpc_DECREF(c_resultP); + } + } +} + + + +void +parseSuccessfulResponse(string const& responseXml, + value * const resultP) { +/*---------------------------------------------------------------------------- + Same as parseResponse(), but expects the response to indicate success; + throws an error if it doesn't. +-----------------------------------------------------------------------------*/ + rpcOutcome outcome; + + parseResponse(responseXml, &outcome); + + if (!outcome.succeeded()) + throwf("RPC response indicates it failed. %s", + outcome.getFault().getDescription().c_str()); + + *resultP = outcome.getResult(); +} + + + +void +trace(string const& label, + string const& xml) { + + xmlrpc_traceXml(label.c_str(), xml.c_str(), xml.size()); + +} + + +}} // namespace diff --git a/src/registry.c b/src/registry.c new file mode 100644 index 0000000..5497861 --- /dev/null +++ b/src/registry.c @@ -0,0 +1,492 @@ +/* Copyright information is at end of file */ + +#include "xmlrpc_config.h" + +#include +#include +#include + +#include "bool.h" +#include "mallocvar.h" +#include "xmlrpc-c/base_int.h" +#include "xmlrpc-c/string_int.h" +#include "xmlrpc-c/base.h" +#include "xmlrpc-c/server.h" +#include "system_method.h" + +#include "registry.h" + +/*========================================================================= + XML-RPC Server Method Registry +=========================================================================== + A method registry is a list of XML-RPC methods for a server to + implement, along with the details of how to implement each -- most + notably a function pointer for a function that executes the method. + + To build an XML-RPC server, just add a communication facility. + + The registry object consists principally of an xmlrpc_value. That + xmlrpc_value is a struct, with method name as key. Each value in + the struct a "method info" array. A method info array has the + following items: + + 0: cptr: method function ptr + 1: cptr: user data + 2: array: signature list + 3: string: help text. + + The signature list array contains one item for each form of call (a + single method might have multiple forms, e.g. one takes two integer + arguments; another takes a single string). The array for each form + represents a signature. It has an item for each parameter and one + for the result. Item 0 is for the result, the rest are in order of + the parameters. Each item of that array is the name of the XML-RPC + element that represents that type, e.g. "int" or + "dateTime.iso8601". + + Example signature: + + (("int" + "double" + "double" + ) + ("int" + ) + ) + + The signature list array is empty to indicate that there is no signature + information in the registry (it doesn't mean there are no valid forms + of calling the method -- just that the registry declines to state). + + + WARNING: there's a basic problem with using xmlrpc_value objects to + represent the registry: xmlrpc_value objects are defined to be not + thread-safe: you can't use one from two threads at the same time. + But XML-RPC servers are often threaded, with multiple threads + simultaneously executing multiple RPCs. The normal Xmlrpc-c Abyss + server is a good example. + + As a hack to make this work, we use the old, deprecated "get" + functions that don't take a reference in the call dispatching code. + Maintaining the reference count is the only way that the the + thread-unsafety can manifest itself in our application. Since the + registry has at least one reference to each xmlrpc_value as long as + the registry exists, we don't really need the exact reference count, + so the deprecated functions work fine. + +=========================================================================*/ + + + +xmlrpc_registry * +xmlrpc_registry_new(xmlrpc_env * const envP) { + + xmlrpc_registry * registryP; + + XMLRPC_ASSERT_ENV_OK(envP); + + MALLOCVAR(registryP); + + if (registryP == NULL) + xmlrpc_faultf(envP, "Could not allocate memory for registry"); + else { + registryP->_introspection_enabled = true; + registryP->_default_method = NULL; + registryP->_preinvoke_method = NULL; + registryP->_shutdown_server_fn = NULL; + + registryP->_methods = xmlrpc_struct_new(envP); + if (!envP->fault_occurred) { + xmlrpc_installSystemMethods(envP, registryP); + } + if (envP->fault_occurred) + free(registryP); + } + return registryP; +} + + + +void +xmlrpc_registry_free(xmlrpc_registry * const registryP) { + + XMLRPC_ASSERT_PTR_OK(registryP); + XMLRPC_ASSERT(registryP->_methods != XMLRPC_BAD_POINTER); + + xmlrpc_DECREF(registryP->_methods); + + if (registryP->_default_method != NULL) + xmlrpc_DECREF(registryP->_default_method); + + if (registryP->_preinvoke_method != NULL) + xmlrpc_DECREF(registryP->_preinvoke_method); + + free(registryP); +} + + + +void +xmlrpc_registry_add_method_w_doc( + xmlrpc_env * const envP, + xmlrpc_registry * const registryP, + const char * const host ATTR_UNUSED, + const char * const methodName, + xmlrpc_method const method, + void * const userData, + const char * const signatureString, + const char * const help) { + + const char * const helpString = + help ? help : "No help is available for this method."; + + xmlrpc_env env; + xmlrpc_value * signatureListP; + + XMLRPC_ASSERT_ENV_OK(envP); + XMLRPC_ASSERT_PTR_OK(registryP); + XMLRPC_ASSERT(host == NULL); + XMLRPC_ASSERT_PTR_OK(methodName); + XMLRPC_ASSERT_PTR_OK(method); + + xmlrpc_env_init(&env); + + xmlrpc_buildSignatureArray(&env, signatureString, &signatureListP); + if (env.fault_occurred) + xmlrpc_faultf(envP, "Can't interpret signature string '%s'. %s", + signatureString, env.fault_string); + else { + xmlrpc_value * methodInfoP; + + XMLRPC_ASSERT_VALUE_OK(signatureListP); + + methodInfoP = xmlrpc_build_value(envP, "(ppVs)", (void*) method, + userData, signatureListP, helpString); + if (!envP->fault_occurred) { + xmlrpc_struct_set_value(envP, registryP->_methods, + methodName, methodInfoP); + + xmlrpc_DECREF(methodInfoP); + } + xmlrpc_DECREF(signatureListP); + } + xmlrpc_env_clean(&env); +} + + + +void +xmlrpc_registry_add_method(xmlrpc_env *env, + xmlrpc_registry *registry, + const char *host, + const char *method_name, + xmlrpc_method method, + void *user_data) { + + xmlrpc_registry_add_method_w_doc (env, registry, host, method_name, + method, user_data, "?", + "No help is available for this method."); +} + + + +/*========================================================================= +** xmlrpc_registry_set_default_method +**========================================================================= +** See xmlrpc.h for more documentation. +*/ + +void +xmlrpc_registry_set_default_method(xmlrpc_env *env, + xmlrpc_registry *registry, + xmlrpc_default_method handler, + void *user_data) { + xmlrpc_value *method_info; + + XMLRPC_ASSERT_ENV_OK(env); + XMLRPC_ASSERT_PTR_OK(registry); + XMLRPC_ASSERT_PTR_OK(handler); + + /* Error-handling preconditions. */ + method_info = NULL; + + /* Store our method and user data into our hash table. */ + method_info = xmlrpc_build_value(env, "(pp)", (void*) handler, user_data); + XMLRPC_FAIL_IF_FAULT(env); + + /* Dispose of any pre-existing default method and install ours. */ + if (registry->_default_method) + xmlrpc_DECREF(registry->_default_method); + registry->_default_method = method_info; + +cleanup: + if (env->fault_occurred) { + if (method_info) + xmlrpc_DECREF(method_info); + } +} + + + + +void +xmlrpc_registry_set_preinvoke_method(xmlrpc_env *env, + xmlrpc_registry *registry, + xmlrpc_preinvoke_method handler, + void *user_data) { + xmlrpc_value *method_info; + + XMLRPC_ASSERT_ENV_OK(env); + XMLRPC_ASSERT_PTR_OK(registry); + XMLRPC_ASSERT_PTR_OK(handler); + + /* Error-handling preconditions. */ + method_info = NULL; + + /* Store our method and user data into our hash table. */ + method_info = xmlrpc_build_value(env, "(pp)", (void*) handler, user_data); + XMLRPC_FAIL_IF_FAULT(env); + + /* Dispose of any pre-existing preinvoke method and install ours. */ + if (registry->_preinvoke_method) + xmlrpc_DECREF(registry->_preinvoke_method); + registry->_preinvoke_method = method_info; + + cleanup: + if (env->fault_occurred) { + if (method_info) + xmlrpc_DECREF(method_info); + } +} + + + +void +xmlrpc_registry_set_shutdown(xmlrpc_registry * const registryP, + xmlrpc_server_shutdown_fn * const shutdownFn, + void * const context) { + + XMLRPC_ASSERT_PTR_OK(registryP); + XMLRPC_ASSERT_PTR_OK(shutdownFn); + + registryP->_shutdown_server_fn = shutdownFn; + + registryP->_shutdown_context = context; +} + + + +/*========================================================================= +** dispatch_call +**========================================================================= +** An internal method which actually does the dispatch. This may get +** prettified and exported at some point in the future. +*/ + +static void +callPreinvokeMethodIfAny(xmlrpc_env * const envP, + xmlrpc_registry * const registryP, + const char * const methodName, + xmlrpc_value * const paramArrayP) { + + /* Get the preinvoke method, if it is set. */ + if (registryP->_preinvoke_method) { + xmlrpc_preinvoke_method preinvoke_method; + void * user_data; + + xmlrpc_parse_value(envP, registryP->_preinvoke_method, "(pp)", + &preinvoke_method, &user_data); + if (!envP->fault_occurred) + (*preinvoke_method)(envP, methodName, + paramArrayP, user_data); + } +} + + + +static void +callDefaultMethod(xmlrpc_env * const envP, + xmlrpc_value * const defaultMethodInfo, + const char * const methodName, + xmlrpc_value * const paramArrayP, + xmlrpc_value ** const resultPP) { + + xmlrpc_default_method default_method; + void * user_data; + + xmlrpc_parse_value(envP, defaultMethodInfo, "(pp)", + &default_method, &user_data); + + if (!envP->fault_occurred) + *resultPP = (*default_method)(envP, NULL, methodName, + paramArrayP, user_data); +} + + + +static void +callNamedMethod(xmlrpc_env * const envP, + xmlrpc_value * const methodInfo, + xmlrpc_value * const paramArrayP, + xmlrpc_value ** const resultPP) { + + xmlrpc_method method; + void * user_data; + + xmlrpc_parse_value(envP, methodInfo, "(pp*)", &method, &user_data); + if (!envP->fault_occurred) + *resultPP = (*method)(envP, paramArrayP, user_data); +} + + + +void +xmlrpc_dispatchCall(xmlrpc_env * const envP, + xmlrpc_registry * const registryP, + const char * const methodName, + xmlrpc_value * const paramArrayP, + xmlrpc_value ** const resultPP) { + + callPreinvokeMethodIfAny(envP, registryP, methodName, paramArrayP); + if (!envP->fault_occurred) { + xmlrpc_value * methodInfoP; + xmlrpc_env methodLookupEnv; + + xmlrpc_env_init(&methodLookupEnv); + + /* See comments at top of file about why we use the deprecated + xmlrpc_struct_get_value() here + */ + methodInfoP = xmlrpc_struct_get_value(&methodLookupEnv, + registryP->_methods, + methodName); + if (!methodLookupEnv.fault_occurred) + callNamedMethod(envP, methodInfoP, paramArrayP, resultPP); + else if (methodLookupEnv.fault_code == XMLRPC_INDEX_ERROR) { + if (registryP->_default_method) + callDefaultMethod(envP, registryP->_default_method, + methodName, paramArrayP, + resultPP); + else { + /* No matching method, and no default. */ + xmlrpc_env_set_fault_formatted( + envP, XMLRPC_NO_SUCH_METHOD_ERROR, + "Method '%s' not defined", methodName); + } + } else + xmlrpc_faultf(envP, "failed to lookup method in registry's " + "internal method struct. %s", + methodLookupEnv.fault_string); + xmlrpc_env_clean(&methodLookupEnv); + } + /* For backward compatibility, for sloppy users: */ + if (envP->fault_occurred) + *resultPP = NULL; +} + + + +/*========================================================================= +** xmlrpc_registry_process_call +**========================================================================= +** +*/ + +xmlrpc_mem_block * +xmlrpc_registry_process_call(xmlrpc_env * const envP, + xmlrpc_registry * const registryP, + const char * const host ATTR_UNUSED, + const char * const xml_data, + size_t const xml_len) { + + xmlrpc_mem_block * output; + + XMLRPC_ASSERT_ENV_OK(envP); + XMLRPC_ASSERT_PTR_OK(xml_data); + + xmlrpc_traceXml("XML-RPC CALL", xml_data, xml_len); + + /* Allocate our output buffer. + ** If this fails, we need to die in a special fashion. */ + output = XMLRPC_MEMBLOCK_NEW(char, envP, 0); + if (!envP->fault_occurred) { + const char * methodName; + xmlrpc_value * paramArray; + xmlrpc_env fault; + xmlrpc_env parseEnv; + + xmlrpc_env_init(&fault); + xmlrpc_env_init(&parseEnv); + + xmlrpc_parse_call(&parseEnv, xml_data, xml_len, + &methodName, ¶mArray); + + if (parseEnv.fault_occurred) + xmlrpc_env_set_fault_formatted( + &fault, XMLRPC_PARSE_ERROR, + "Call XML not a proper XML-RPC call. %s", + parseEnv.fault_string); + else { + xmlrpc_value * result; + + xmlrpc_dispatchCall(&fault, registryP, methodName, paramArray, + &result); + + if (!fault.fault_occurred) { + xmlrpc_serialize_response(envP, output, result); + + /* A comment here used to say that + xmlrpc_serialize_response() could fail and "leave + stuff in the buffer." Don't know what that means, + but it sounds like something that needs to be + fixed. The old code aborted the program here if + xmlrpc_serialize_repsonse() failed. 04.11.17 + */ + xmlrpc_DECREF(result); + } + xmlrpc_strfree(methodName); + xmlrpc_DECREF(paramArray); + } + if (!envP->fault_occurred && fault.fault_occurred) + xmlrpc_serialize_fault(envP, output, &fault); + + xmlrpc_env_clean(&parseEnv); + xmlrpc_env_clean(&fault); + + if (envP->fault_occurred) + XMLRPC_MEMBLOCK_FREE(char, output); + else + xmlrpc_traceXml("XML-RPC RESPONSE", + XMLRPC_MEMBLOCK_CONTENTS(char, output), + XMLRPC_MEMBLOCK_SIZE(char, output)); + } + return output; +} + + +/* Copyright (C) 2001 by First Peer, Inc. All rights reserved. +** Copyright (C) 2001 by Eric Kidd. All rights reserved. +** Copyright (C) 2001 by Luke Howard. All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +** ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +** OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +** HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +** LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +** OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +** SUCH DAMAGE. */ diff --git a/src/registry.h b/src/registry.h new file mode 100644 index 0000000..6e1fa50 --- /dev/null +++ b/src/registry.h @@ -0,0 +1,30 @@ +#ifndef REGISTRY_H_INCLUDED +#define REGISTRY_H_INCLUDED + +#include "bool.h" +#include "xmlrpc-c/base.h" +#include "xmlrpc-c/server.h" + +struct _xmlrpc_registry { + bool _introspection_enabled; + xmlrpc_value * _methods; + xmlrpc_value * _default_method; + xmlrpc_value * _preinvoke_method; + xmlrpc_server_shutdown_fn * _shutdown_server_fn; + /* Function that can be called to shut down the server that is + using this registry. NULL if none. + */ + void * _shutdown_context; + /* Context for _shutdown_server_fn -- understood only by + that function, passed to it as argument. + */ +}; + +void +xmlrpc_dispatchCall(struct _xmlrpc_env * const envP, + struct _xmlrpc_registry * const registryP, + const char * const methodName, + struct _xmlrpc_value * const paramArrayP, + struct _xmlrpc_value ** const resultPP); + +#endif diff --git a/src/system_method.c b/src/system_method.c new file mode 100644 index 0000000..0487c53 --- /dev/null +++ b/src/system_method.c @@ -0,0 +1,807 @@ +/* Copyright information is at end of file */ + +#include "xmlrpc_config.h" + +#include +#include +#include + +#include "xmlrpc-c/base_int.h" +#include "xmlrpc-c/string_int.h" +#include "xmlrpc-c/base.h" +#include "xmlrpc-c/server.h" +#include "registry.h" + +#include "system_method.h" + + +struct systemMethodReg { +/*---------------------------------------------------------------------------- + Information needed to register a system method +-----------------------------------------------------------------------------*/ + const char * const methodName; + xmlrpc_method const methodFunction; + const char * const signatureString; + const char * const helpText; +}; + + + +void +xmlrpc_registry_disable_introspection(xmlrpc_registry * const registryP) { + + XMLRPC_ASSERT_PTR_OK(registryP); + + registryP->_introspection_enabled = false; +} + + + +static void +translateTypeSpecifierToName(xmlrpc_env * const envP, + char const typeSpecifier, + const char ** const typeNameP) { + + switch (typeSpecifier) { + case 'i': *typeNameP = "int"; break; + case 'b': *typeNameP = "boolean"; break; + case 'd': *typeNameP = "double"; break; + case 's': *typeNameP = "string"; break; + case '8': *typeNameP = "dateTime.iso8601"; break; + case '6': *typeNameP = "base64"; break; + case 'S': *typeNameP = "struct"; break; + case 'A': *typeNameP = "array"; break; + case 'n': *typeNameP = "nil"; break; + default: + xmlrpc_faultf(envP, + "Method registry contains invalid signature " + "data. It contains the type specifier '%c'", + typeSpecifier); + } +} + + + +static void +parseOneTypeSpecifier(xmlrpc_env * const envP, + const char * const startP, + xmlrpc_value * const signatureP, + const char ** const nextP) { +/*---------------------------------------------------------------------------- + Parse one type specifier at 'startP' within a signature string. + + Add the appropriate item for it to the array 'signatureP'. + + Return as *nextP the location the signature string just past the + type specifier, and also past the colon that comes after the + type specifier for a return value. +-----------------------------------------------------------------------------*/ + const char * typeName; + const char * cursorP; + + cursorP = startP; + + translateTypeSpecifierToName(envP, *cursorP, &typeName); + + if (!envP->fault_occurred) { + xmlrpc_value * typeP; + int sigArraySize; + + /* Append the appropriate string to the signature. */ + typeP = xmlrpc_string_new(envP, typeName); + xmlrpc_array_append_item(envP, signatureP, typeP); + xmlrpc_DECREF(typeP); + + ++cursorP; /* move past the type specifier */ + + sigArraySize = xmlrpc_array_size(envP, signatureP); + if (!envP->fault_occurred) { + if (sigArraySize == 1) { + /* We parsed off the result type, so we should now + see the colon that separates the result type from + the parameter types + */ + if (*cursorP != ':') + xmlrpc_faultf(envP, "No colon (':') after " + "the result type specifier"); + else + ++cursorP; + } + } + } + *nextP = cursorP; +} + + + +static void +parseOneSignature(xmlrpc_env * const envP, + const char * const startP, + xmlrpc_value ** const signaturePP, + const char ** const nextP) { +/*---------------------------------------------------------------------------- + Parse one signature from the signature string that starts at 'startP'. + + Return that signature as an array xmlrpc_value pointer + *signaturePP. The array has one element for the return value, + followed by one element for each parameter described in the + signature. That element is a string naming the return value or + parameter type, e.g. "int". + + Return as *nextP the location in the signature string of the next + signature (i.e. right after the next comma). If there is no next + signature (the string ends before any comma), make it point to the + terminating NUL. +-----------------------------------------------------------------------------*/ + xmlrpc_value * signatureP; + + signatureP = xmlrpc_array_new(envP); /* Start with empty array */ + if (!envP->fault_occurred) { + const char * cursorP; + + cursorP = startP; /* start at the beginning */ + + while (!envP->fault_occurred && *cursorP != ',' && *cursorP != '\0') + parseOneTypeSpecifier(envP, cursorP, signatureP, &cursorP); + + if (!envP->fault_occurred) { + if (xmlrpc_array_size(envP, signatureP) < 1) + xmlrpc_faultf(envP, "empty signature (a signature " + "must have at least return value type)"); + if (*cursorP != '\0') { + assert(*cursorP == ','); + ++cursorP; + } + *nextP = cursorP; + } + if (envP->fault_occurred) + xmlrpc_DECREF(signatureP); + else + *signaturePP = signatureP; + } +} + + + +void +xmlrpc_buildSignatureArray(xmlrpc_env * const envP, + const char * const sigListString, + xmlrpc_value ** const resultPP) { +/*---------------------------------------------------------------------------- + Turn the signature string 'sig' (e.g. "ii,s") into an array + as *resultP. The array contains one element for each signature in + the string. (Signatures are separated by commas. The "ii,s" example + is two signatures: "ii" and "s"). Each element is itself an array + as described under parseOneSignature(). +-----------------------------------------------------------------------------*/ + xmlrpc_value * signatureListP; + + signatureListP = xmlrpc_array_new(envP); + if (!envP->fault_occurred) { + if (sigListString == NULL || xmlrpc_streq(sigListString, "?")) { + /* No signatures -- leave the array empty */ + } else { + const char * cursorP; + + cursorP = &sigListString[0]; + + while (!envP->fault_occurred && *cursorP != '\0') { + xmlrpc_value * signatureP; + + parseOneSignature(envP, cursorP, &signatureP, &cursorP); + + /* cursorP now points at next signature in the list or the + terminating NUL. + */ + + if (!envP->fault_occurred) { + xmlrpc_array_append_item(envP, signatureListP, signatureP); + xmlrpc_DECREF(signatureP); + } + } + if (!envP->fault_occurred) { + unsigned int const arraySize = + xmlrpc_array_size(envP, signatureListP); + XMLRPC_ASSERT_ENV_OK(envP); + if (arraySize < 1) + xmlrpc_faultf(envP, "Signature string is empty."); + } + } + if (envP->fault_occurred) + xmlrpc_DECREF(signatureListP); + } + *resultPP = signatureListP; +} + + + +/*========================================================================= + system.multicall +=========================================================================*/ + +static xmlrpc_value * +call_one_method(xmlrpc_env *env, xmlrpc_registry *registry, + xmlrpc_value *method_info) { + + xmlrpc_value *result_val, *result; + char *method_name; + xmlrpc_value *param_array; + + /* Error-handling preconditions. */ + result = result_val = NULL; + + /* Extract our method name and parameters. */ + xmlrpc_parse_value(env, method_info, "{s:s,s:A,*}", + "methodName", &method_name, + "params", ¶m_array); + XMLRPC_FAIL_IF_FAULT(env); + + /* Watch out for a deep recursion attack. */ + if (strcmp(method_name, "system.multicall") == 0) + XMLRPC_FAIL(env, XMLRPC_REQUEST_REFUSED_ERROR, + "Recursive system.multicall strictly forbidden"); + + /* Perform the call. */ + xmlrpc_dispatchCall(env, registry, method_name, param_array, &result_val); + XMLRPC_FAIL_IF_FAULT(env); + + /* Build our one-item result array. */ + result = xmlrpc_build_value(env, "(V)", result_val); + XMLRPC_FAIL_IF_FAULT(env); + + cleanup: + if (result_val) + xmlrpc_DECREF(result_val); + if (env->fault_occurred) { + if (result) + xmlrpc_DECREF(result); + return NULL; + } + return result; +} + + + +static xmlrpc_value * +system_multicall(xmlrpc_env *env, + xmlrpc_value *param_array, + void *user_data) { + + xmlrpc_registry *registry; + xmlrpc_value *methlist, *methinfo, *results, *result; + size_t size, i; + xmlrpc_env env2; + + XMLRPC_ASSERT_ENV_OK(env); + XMLRPC_ASSERT_VALUE_OK(param_array); + XMLRPC_ASSERT_PTR_OK(user_data); + + /* Error-handling preconditions. */ + results = result = NULL; + xmlrpc_env_init(&env2); + + /* Turn our arguments into something more useful. */ + registry = (xmlrpc_registry*) user_data; + xmlrpc_parse_value(env, param_array, "(A)", &methlist); + XMLRPC_FAIL_IF_FAULT(env); + + /* Create an empty result list. */ + results = xmlrpc_build_value(env, "()"); + XMLRPC_FAIL_IF_FAULT(env); + + /* Loop over our input list, calling each method in turn. */ + size = xmlrpc_array_size(env, methlist); + XMLRPC_ASSERT_ENV_OK(env); + for (i = 0; i < size; i++) { + methinfo = xmlrpc_array_get_item(env, methlist, i); + XMLRPC_ASSERT_ENV_OK(env); + + /* Call our method. */ + xmlrpc_env_clean(&env2); + xmlrpc_env_init(&env2); + result = call_one_method(&env2, registry, methinfo); + + /* Turn any fault into a structure. */ + if (env2.fault_occurred) { + XMLRPC_ASSERT(result == NULL); + result = + xmlrpc_build_value(env, "{s:i,s:s}", + "faultCode", (xmlrpc_int32) env2.fault_code, + "faultString", env2.fault_string); + XMLRPC_FAIL_IF_FAULT(env); + } + + /* Append this method result to our master array. */ + xmlrpc_array_append_item(env, results, result); + xmlrpc_DECREF(result); + result = NULL; + XMLRPC_FAIL_IF_FAULT(env); + } + + cleanup: + xmlrpc_env_clean(&env2); + if (result) + xmlrpc_DECREF(result); + if (env->fault_occurred) { + if (results) + xmlrpc_DECREF(results); + return NULL; + } + return results; +} + + + +static struct systemMethodReg const multicall = { + "system.multicall", + &system_multicall, + "A:A", + "Process an array of calls, and return an array of results. Calls should " + "be structs of the form {'methodName': string, 'params': array}. Each " + "result will either be a single-item array containg the result value, or " + "a struct of the form {'faultCode': int, 'faultString': string}. This " + "is useful when you need to make lots of small calls without lots of " + "round trips.", +}; + + +/*========================================================================= + system.listMethods +=========================================================================*/ + + + +static xmlrpc_value * +system_listMethods(xmlrpc_env *env, + xmlrpc_value *param_array, + void *user_data) { + + xmlrpc_registry *registry; + xmlrpc_value *method_names, *method_name, *method_info; + size_t size, i; + + XMLRPC_ASSERT_ENV_OK(env); + XMLRPC_ASSERT_VALUE_OK(param_array); + XMLRPC_ASSERT_PTR_OK(user_data); + + /* Error-handling preconditions. */ + method_names = NULL; + + /* Turn our arguments into something more useful. */ + registry = (xmlrpc_registry*) user_data; + xmlrpc_parse_value(env, param_array, "()"); + XMLRPC_FAIL_IF_FAULT(env); + + /* Make sure we're allowed to introspect. */ + if (!registry->_introspection_enabled) + XMLRPC_FAIL(env, XMLRPC_INTROSPECTION_DISABLED_ERROR, + "Introspection disabled for security reasons"); + + /* Iterate over all the methods in the registry, adding their names + ** to a list. */ + method_names = xmlrpc_build_value(env, "()"); + XMLRPC_FAIL_IF_FAULT(env); + size = xmlrpc_struct_size(env, registry->_methods); + XMLRPC_FAIL_IF_FAULT(env); + for (i = 0; i < size; i++) { + xmlrpc_struct_get_key_and_value(env, registry->_methods, i, + &method_name, &method_info); + XMLRPC_FAIL_IF_FAULT(env); + xmlrpc_array_append_item(env, method_names, method_name); + XMLRPC_FAIL_IF_FAULT(env); + } + + cleanup: + if (env->fault_occurred) { + if (method_names) + xmlrpc_DECREF(method_names); + return NULL; + } + return method_names; +} + +static struct systemMethodReg const listMethods = { + "system.listMethods", + &system_listMethods, + "A:", + "Return an array of all available XML-RPC methods on this server.", +}; + + + +/*========================================================================= + system.methodHelp +=========================================================================*/ + +static xmlrpc_value * +system_methodHelp(xmlrpc_env *env, + xmlrpc_value *param_array, + void *user_data) { + + xmlrpc_registry *registry; + char *method_name; + xmlrpc_value *ignored1, *ignored2, *ignored3, *help; + + XMLRPC_ASSERT_ENV_OK(env); + XMLRPC_ASSERT_VALUE_OK(param_array); + XMLRPC_ASSERT_PTR_OK(user_data); + + /* Turn our arguments into something more useful. */ + registry = (xmlrpc_registry*) user_data; + xmlrpc_parse_value(env, param_array, "(s)", &method_name); + XMLRPC_FAIL_IF_FAULT(env); + + /* Make sure we're allowed to introspect. */ + if (!registry->_introspection_enabled) + XMLRPC_FAIL(env, XMLRPC_INTROSPECTION_DISABLED_ERROR, + "Introspection disabled for security reasons"); + + /* Get our documentation string. */ + xmlrpc_parse_value(env, registry->_methods, "{s:(VVVV*),*}", + method_name, &ignored1, &ignored2, &ignored3, &help); + XMLRPC_FAIL_IF_FAULT(env); + + cleanup: + if (env->fault_occurred) + return NULL; + xmlrpc_INCREF(help); + return help; +} + + +static struct systemMethodReg const methodHelp = { + "system.methodHelp", + &system_methodHelp, + "s:s", + "Given the name of a method, return a help string.", +}; + + + +static void +getMethodInfo(xmlrpc_env * const envP, + xmlrpc_registry * const registryP, + const char * const methodName, + xmlrpc_value ** const methodInfoPP) { +/*---------------------------------------------------------------------------- + Look up the method info for the named method. Method info + is an array (ppss): +-----------------------------------------------------------------------------*/ + xmlrpc_env env; + xmlrpc_value * methodInfoP; + + xmlrpc_env_init(&env); + + /* We can't use xmlrpc_struct_find_value() here because it isn't + thread-safe (it manipulates the reference count) and servers + sometimes call system methods from multiple threads at once. + */ + methodInfoP = xmlrpc_struct_get_value( + &env, registryP->_methods, methodName); + + if (env.fault_occurred) { + if (env.fault_code == XMLRPC_INDEX_ERROR) + xmlrpc_env_set_fault_formatted( + envP, XMLRPC_NO_SUCH_METHOD_ERROR, + "Method '%s' does not exist", methodName); + else + xmlrpc_faultf(envP, "Unable to look up method named '%s' in the " + "registry. %s", methodName, env.fault_string); + } else + *methodInfoPP = methodInfoP; + + xmlrpc_env_clean(&env); +} + + + +/*========================================================================= + system.methodSignature +==========================================================================*/ + +static void +buildNoSigSuppliedResult(xmlrpc_env * const envP, + xmlrpc_value ** const resultPP) { + + xmlrpc_env env; + + xmlrpc_env_init(&env); + + *resultPP = xmlrpc_string_new(&env, "undef"); + if (env.fault_occurred) + xmlrpc_faultf(envP, "Unable to construct 'undef'. %s", + env.fault_string); + + xmlrpc_env_clean(&env); +} + + + +static void +makeSigListCopy(xmlrpc_env * const envP, + xmlrpc_value * const oldP, + xmlrpc_value ** const newPP) { + + xmlrpc_value * newP; + + newP = xmlrpc_array_new(envP); + + if (!envP->fault_occurred) { + unsigned int const size = xmlrpc_array_size(envP, oldP); + if (!envP->fault_occurred) { + unsigned int i; + for (i = 0; i < size; ++i) { + /* We can't use xmlrpc_array_read_item() here because + it isn't thread-safe (it manipulates the reference count) + an servers sometimes call system methods from multiple + threads at once. + */ + xmlrpc_value * const itemP = + xmlrpc_array_get_item(envP, oldP, i); + xmlrpc_array_append_item(envP, newP, itemP); + } + } + } + *newPP = newP; +} + + + +static void +getSignatureList(xmlrpc_env * const envP, + xmlrpc_registry * const registryP, + const char * const methodName, + xmlrpc_value ** const signatureListPP) { +/*---------------------------------------------------------------------------- + Get the signature list array for method named 'methodName' from registry + 'registryP'. + + If there is no signature information for the method in the registry, + return *signatureListPP == NULL. + + Nonexistent method is considered a failure. +-----------------------------------------------------------------------------*/ + xmlrpc_value * methodInfoP; + + getMethodInfo(envP, registryP, methodName, &methodInfoP); + if (!envP->fault_occurred) { + xmlrpc_env env; + xmlrpc_value * signatureListP; + + xmlrpc_env_init(&env); + + /* We can't use xmlrpc_array_read_item() because it isn't thread + safe (it manipulates the reference count) and servers sometimes + run system methods from multiple threads at once. + */ + signatureListP = xmlrpc_array_get_item(&env, methodInfoP, 2); + + if (env.fault_occurred) + xmlrpc_faultf(envP, "Failed to read signature list " + "from method info array. %s", + env.fault_string); + else { + int arraySize; + + arraySize = xmlrpc_array_size(&env, signatureListP); + if (env.fault_occurred) + xmlrpc_faultf(envP, "xmlrpc_array_size() on signature " + "list array failed! %s", env.fault_string); + else { + if (arraySize == 0) + *signatureListPP = NULL; + else { + makeSigListCopy(envP, signatureListP, signatureListPP); + } + } + } + xmlrpc_env_clean(&env); + } +} + + + +static xmlrpc_value * +system_methodSignature(xmlrpc_env * const envP, + xmlrpc_value * const paramArrayP, + void * const userData) { + + xmlrpc_registry * const registryP = (xmlrpc_registry *) userData; + + xmlrpc_value * retvalP; + const char * methodName; + xmlrpc_env env; + + XMLRPC_ASSERT_ENV_OK(envP); + XMLRPC_ASSERT_VALUE_OK(paramArrayP); + XMLRPC_ASSERT_PTR_OK(userData); + + xmlrpc_env_init(&env); + + /* Turn our arguments into something more useful. */ + xmlrpc_decompose_value(&env, paramArrayP, "(s)", &methodName); + if (env.fault_occurred) + xmlrpc_env_set_fault_formatted( + envP, env.fault_code, + "Invalid parameter list. %s", env.fault_string); + else { + if (!registryP->_introspection_enabled) + xmlrpc_env_set_fault(envP, XMLRPC_INTROSPECTION_DISABLED_ERROR, + "Introspection disabled on this server"); + else { + xmlrpc_value * signatureListP; + + getSignatureList(envP, registryP, methodName, &signatureListP); + + if (!envP->fault_occurred) { + if (signatureListP) + retvalP = signatureListP; + else + buildNoSigSuppliedResult(envP, &retvalP); + } + } + xmlrpc_strfree(methodName); + } + xmlrpc_env_clean(&env); + + return retvalP; +} + + + +static struct systemMethodReg const methodSignature = { + "system.methodSignature", + &system_methodSignature, + "A:s", + "Given the name of a method, return an array of legal signatures. " + "Each signature is an array of strings. The first item of each signature " + "is the return type, and any others items are parameter types.", +}; + + + + +/*========================================================================= + system.shutdown +==========================================================================*/ + +static xmlrpc_value * +system_shutdown(xmlrpc_env * const envP, + xmlrpc_value * const paramArrayP, + void * const userData) { + + xmlrpc_registry * const registryP = (xmlrpc_registry *) userData; + + xmlrpc_value * retvalP; + const char * comment; + xmlrpc_env env; + + XMLRPC_ASSERT_ENV_OK(envP); + XMLRPC_ASSERT_VALUE_OK(paramArrayP); + XMLRPC_ASSERT_PTR_OK(userData); + + xmlrpc_env_init(&env); + + retvalP = NULL; /* quiet compiler warning */ + + /* Turn our arguments into something more useful. */ + xmlrpc_decompose_value(&env, paramArrayP, "(s)", &comment); + if (env.fault_occurred) + xmlrpc_env_set_fault_formatted( + envP, env.fault_code, + "Invalid parameter list. %s", env.fault_string); + else { + if (!registryP->_shutdown_server_fn) + xmlrpc_env_set_fault( + envP, 0, "This server program is not capable of " + "shutting down"); + else { + registryP->_shutdown_server_fn( + &env, registryP->_shutdown_context, comment); + + if (env.fault_occurred) + xmlrpc_env_set_fault(envP, env.fault_code, env.fault_string); + else { + retvalP = xmlrpc_int_new(&env, 0); + + if (env.fault_occurred) + xmlrpc_faultf(envP, + "Failed to construct return value. %s", + env.fault_string); + } + } + xmlrpc_strfree(comment); + } + xmlrpc_env_clean(&env); + + return retvalP; +} + + + +static struct systemMethodReg const shutdown = { + "system.shutdown", + &system_shutdown, + "i:s", + "Shut down the server. Return code is always zero.", +}; + + + +/*============================================================================ + Installer of system methods +============================================================================*/ + +static void +registerSystemMethod(xmlrpc_env * const envP, + xmlrpc_registry * const registryP, + struct systemMethodReg const methodReg) { + + xmlrpc_env env; + xmlrpc_env_init(&env); + + xmlrpc_registry_add_method_w_doc( + &env, registryP, NULL, methodReg.methodName, + methodReg.methodFunction, registryP, + methodReg.signatureString, methodReg.helpText); + + if (env.fault_occurred) + xmlrpc_faultf(envP, "Failed to register '%s' system method. %s", + methodReg.methodName, env.fault_string); + + xmlrpc_env_clean(&env); +} + + + +void +xmlrpc_installSystemMethods(xmlrpc_env * const envP, + xmlrpc_registry * const registryP) { +/*---------------------------------------------------------------------------- + Install the built-in methods (system.*) into registry 'registryP'. +-----------------------------------------------------------------------------*/ + if (!envP->fault_occurred) + registerSystemMethod(envP, registryP, listMethods); + + if (!envP->fault_occurred) + registerSystemMethod(envP, registryP, methodSignature); + + if (!envP->fault_occurred) + registerSystemMethod(envP, registryP, methodHelp); + + if (!envP->fault_occurred) + registerSystemMethod(envP, registryP, multicall); + + if (!envP->fault_occurred) + registerSystemMethod(envP, registryP, shutdown); +} + + + +/* Copyright (C) 2001 by First Peer, Inc. All rights reserved. +** Copyright (C) 2001 by Eric Kidd. All rights reserved. +** Copyright (C) 2001 by Luke Howard. All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +** ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +** OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +** HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +** LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +** OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +** SUCH DAMAGE. */ + diff --git a/src/system_method.h b/src/system_method.h new file mode 100644 index 0000000..f9dff5f --- /dev/null +++ b/src/system_method.h @@ -0,0 +1,14 @@ +#ifndef SYSTEM_METHOD_H_INCLUDED +#define SYSTEM_METHOD_H_INCLUDED + + +void +xmlrpc_installSystemMethods(struct _xmlrpc_env * const envP, + struct _xmlrpc_registry * const registryP); + +void +xmlrpc_buildSignatureArray(xmlrpc_env * const envP, + const char * const sigListString, + xmlrpc_value ** const resultPP); + +#endif diff --git a/src/test/.cvsignore b/src/test/.cvsignore new file mode 100644 index 0000000..41bf38d --- /dev/null +++ b/src/test/.cvsignore @@ -0,0 +1,2 @@ +test +cgitest1 diff --git a/src/test/Makefile b/src/test/Makefile new file mode 100644 index 0000000..feefa7b --- /dev/null +++ b/src/test/Makefile @@ -0,0 +1,93 @@ +ifeq ($(SRCDIR)x,x) +SRCDIR = $(CURDIR)/../.. +endif +SUBDIR = src/test +BUILDDIR = $(SRCDIR) +VPATH = .:$(SRCDIR) + +include $(BUILDDIR)/Makefile.config + +XMLRPC_C_CONFIG = $(BUILDDIR)/xmlrpc-c-config.test + +LDADD_CLIENT = \ + $(shell $(XMLRPC_C_CONFIG) client --ldadd) +LDADD_ABYSS_SERVER = \ + $(shell $(XMLRPC_C_CONFIG) abyss-server --ldadd) +LDADD_CGI_SERVER = \ + $(shell $(XMLRPC_C_CONFIG) cgi-server --ldadd) + +default: all + +INCLUDES = -I$(BUILDDIR) -I$(SRCDIR) \ + -I $(SRCDIR)/include -I$(SRCDIR)/lib/util/include \ + +PROGS = test cgitest1 + +all: $(PROGS) + +LDFLAGS = $(LADD) + +TEST_OBJS = \ + test.o \ + cgi.o \ + method_registry.o \ + parse_xml.o \ + serialize.o \ + server_abyss.o \ + value.o \ + xml_data.o \ + +ifeq ($(MUST_BUILD_CLIENT),yes) + TEST_OBJS += client.o + LIBXMLRPC_CLIENT_DEP = $(LIBXMLRPC_CLIENT) +else + TEST_OBJS += client_dummy.o + LIBXMLRPC_CLIENT_DEP = +endif + +include $(SRCDIR)/Makefile.common + +test: $(TEST_OBJS) $(LIBXMLRPC_A) $(LIBXMLRPC_UTIL_A) \ + $(LIBXMLRPC_SERVER_A) $(LIBXMLRPC_SERVER_ABYSS_A) $(LIBXMLRPC_XML) \ + $(LIBXMLRPC_CLIENT_DEP) $(LIBXMLRPC_ABYSS_A) $(CASPRINTF) + $(CCLD) -o $@ $(LDFLAGS) \ + $(TEST_OBJS) $(LDADD_CLIENT) $(LDADD_ABYSS_SERVER) $(CASPRINTF) + +cgitest1:%:%.o $(LIBXMLRPC_SERVER_A) $(LIBXMLRPC_SERVER_CGI_A) \ + $(LIBXMLRPC_A) $(LIBXMLRPC_UTIL_A) $(LIBXMLRPC_XML) + $(CCLD) -o $@ $< $(LDFLAGS) $(LDADD_CGI_SERVER) + +CFLAGS = $(CFLAGS_COMMON) $(CFLAGS_PERSONAL) $(CADD) + +OBJS = $(TEST_OBJS) cgitest1.o + +$(OBJS):%.o:%.c + $(CC) -c $(INCLUDES) $(CFLAGS) $< + +# Note the difference between 'check' and 'runtests'. 'check' means to check +# our own correctness. 'runtests' means to run the tests that check our +# parent's correctness + +.PHONY: check +check: + +.PHONY: runtests +runtests: test cgitest1 + ./test + +.PHONY: install +install: + +.PHONY: clean clean-local distclean +clean: clean-common clean-local +clean-local: + rm -f $(PROGS) + +distclean: clean distclean-common + +.PHONY: dep +dep: dep-common + +include Makefile.depend + + diff --git a/src/test/Makefile.depend b/src/test/Makefile.depend new file mode 100644 index 0000000..e69de29 diff --git a/src/test/cgi.c b/src/test/cgi.c new file mode 100644 index 0000000..52c0c08 --- /dev/null +++ b/src/test/cgi.c @@ -0,0 +1,60 @@ +#include +#include +#include +#include + +#include "xmlrpc_config.h" + +#include "test.h" +#include "cgi.h" + +static const char cgiResponse1[] = + "....Status: 200 OK\n" + "Content-type: text/xml; charset=\"utf-8\"\n" + "Content-length: 141\n" + "\n" + "\r\n" + "\r\n" + "\r\n" + "12\r\n" + "\r\n" + "\r\n"; + + +#define TESTDATA_DIR "data" +#define DIRSEP DIRECTORY_SEPARATOR + +void +test_server_cgi(void) { +/*---------------------------------------------------------------------------- + Here, we pretend to be a web server when someone has requested a POST + to the CGI script "cgitest1". +-----------------------------------------------------------------------------*/ + FILE * cgiOutputP; + + printf("Running CGI tests...\n"); + + cgiOutputP = popen("REQUEST_METHOD=POST " + "CONTENT_TYPE=text/xml " + "CONTENT_LENGTH=211 " + "./cgitest1 " + "<" + TESTDATA_DIR DIRSEP "sample_add_call.xml", + "r"); + + if (cgiOutputP == NULL) + TEST_ERROR("Unable to run 'cgitest' program."); + else { + unsigned char cgiResponse[4096]; + size_t bytesRead; + + bytesRead = fread(cgiResponse, 1, sizeof(cgiResponse), cgiOutputP); + + TEST(bytesRead == strlen(cgiResponse1)); + + TEST(memcmp(cgiResponse, cgiResponse1, bytesRead) == 0); + } + fclose(cgiOutputP); + printf("\n"); + printf("CGI tests done.\n"); +} diff --git a/src/test/cgi.h b/src/test/cgi.h new file mode 100644 index 0000000..4e2de99 --- /dev/null +++ b/src/test/cgi.h @@ -0,0 +1,2 @@ +void +test_server_cgi(void); diff --git a/src/test/cgitest1.c b/src/test/cgitest1.c new file mode 100644 index 0000000..7ce6909 --- /dev/null +++ b/src/test/cgitest1.c @@ -0,0 +1,79 @@ +/*============================================================================ + Act like a CGI script -- read POST data from Standard Input, interpret + it as an XML-RPC call, and write an XML-RPC response to Standard Output. + + This is for use by a test program. +============================================================================*/ + +#include +#include +#include +#include + +#include "xmlrpc_config.h" + +#include "xmlrpc-c/base.h" +#include "xmlrpc-c/server.h" +#include "xmlrpc-c/server_cgi.h" + +#include "test.h" + + +int total_tests; +int total_failures; + + + +static xmlrpc_value * +sample_add(xmlrpc_env * const env, + xmlrpc_value * const param_array, + void * const user_data ATTR_UNUSED) { + + xmlrpc_int32 x, y, z; + + /* Parse our argument array. */ + xmlrpc_decompose_value(env, param_array, "(ii)", &x, &y); + if (env->fault_occurred) + return NULL; + + /* Add our two numbers. */ + z = x + y; + + /* Return our result. */ + return xmlrpc_build_value(env, "i", z); +} + + + +int +main(int argc ATTR_UNUSED, + char ** argv ATTR_UNUSED) { + + xmlrpc_env env; + xmlrpc_registry * registryP; + xmlrpc_value * argArrayP; + + xmlrpc_env_init(&env); + + registryP = xmlrpc_registry_new(&env); + TEST(registryP != NULL); + TEST_NO_FAULT(&env); + + xmlrpc_registry_add_method(&env, registryP, NULL, "sample.add", + sample_add, NULL); + TEST_NO_FAULT(&env); + + argArrayP = xmlrpc_build_value(&env, "(ii)", + (xmlrpc_int32) 25, (xmlrpc_int32) 17); + TEST_NO_FAULT(&env); + + /* The following reads from Standard Input and writes to Standard + Output + */ + xmlrpc_server_cgi_process_call(registryP); + + xmlrpc_DECREF(argArrayP); + xmlrpc_registry_free(registryP); + + return 0; +} diff --git a/src/test/client.c b/src/test/client.c new file mode 100644 index 0000000..3a0c6f7 --- /dev/null +++ b/src/test/client.c @@ -0,0 +1,255 @@ +#include +#include +#include +#include + +#include "xmlrpc_config.h" + +#include "xmlrpc-c/base.h" +#include "xmlrpc-c/client.h" + +#include "test.h" +#include "client.h" + + +static void +testGlobalConst(void) { + + xmlrpc_env env; + xmlrpc_env_init(&env); + + xmlrpc_client_setup_global_const(&env); + TEST_NO_FAULT(&env); + + xmlrpc_client_teardown_global_const(); + + xmlrpc_client_setup_global_const(&env); + TEST_NO_FAULT(&env); + xmlrpc_client_setup_global_const(&env); + TEST_NO_FAULT(&env); + + xmlrpc_client_teardown_global_const(); + xmlrpc_client_teardown_global_const(); + + xmlrpc_env_clean(&env); +} + + + +static void +testCreateDestroy(void) { + + xmlrpc_env env; + xmlrpc_client * clientP; + struct xmlrpc_clientparms clientParms1; + struct xmlrpc_curl_xportparms curlTransportParms1; + + xmlrpc_env_init(&env); + + xmlrpc_client_create(&env, 0, "testprog", "1.0", NULL, 0, &clientP); + TEST_FAULT(&env, XMLRPC_INTERNAL_ERROR); + /* Didn't set up global const */ + + xmlrpc_client_setup_global_const(&env); + TEST_NO_FAULT(&env); + + xmlrpc_client_create(&env, 0, "testprog", "1.0", NULL, 0, &clientP); + TEST_NO_FAULT(&env); + xmlrpc_client_destroy(clientP); + + xmlrpc_client_create(&env, 0, "testprog", "1.0", &clientParms1, 0, + &clientP); + TEST_NO_FAULT(&env); + xmlrpc_client_destroy(clientP); + + clientParms1.transport = "curl"; + xmlrpc_client_create(&env, 0, "testprog", "1.0", + &clientParms1, XMLRPC_CPSIZE(transport), &clientP); + TEST_NO_FAULT(&env); + xmlrpc_client_destroy(clientP); + + clientParms1.transportparmsP = NULL; + xmlrpc_client_create(&env, 0, "testprog", "1.0", + &clientParms1, XMLRPC_CPSIZE(transportparmsP), + &clientP); + TEST_NO_FAULT(&env); + xmlrpc_client_destroy(clientP); + + clientParms1.transportparmsP = (struct xmlrpc_xportparms *)(void *) + &curlTransportParms1; + + xmlrpc_client_create(&env, 0, "testprog", "1.0", + &clientParms1, XMLRPC_CPSIZE(transportparmsP), + &clientP); + TEST_FAULT(&env, XMLRPC_INTERNAL_ERROR); + + clientParms1.transportparm_size = 0; + xmlrpc_client_create(&env, 0, "testprog", "1.0", + &clientParms1, XMLRPC_CPSIZE(transportparm_size), + &clientP); + TEST_NO_FAULT(&env); + xmlrpc_client_destroy(clientP); + + curlTransportParms1.network_interface = "eth0"; + clientParms1.transportparm_size = XMLRPC_CXPSIZE(network_interface); + xmlrpc_client_create(&env, 0, "testprog", "1.0", + &clientParms1, XMLRPC_CPSIZE(transportparm_size), + &clientP); + TEST_NO_FAULT(&env); + xmlrpc_client_destroy(clientP); + + curlTransportParms1.no_ssl_verifypeer = 1; + curlTransportParms1.no_ssl_verifyhost = 1; + clientParms1.transportparm_size = XMLRPC_CXPSIZE(no_ssl_verifyhost); + xmlrpc_client_create(&env, 0, "testprog", "1.0", + &clientParms1, XMLRPC_CPSIZE(transportparm_size), + &clientP); + TEST_NO_FAULT(&env); + xmlrpc_client_destroy(clientP); + + curlTransportParms1.user_agent = "testprog/1.0"; + clientParms1.transportparm_size = XMLRPC_CXPSIZE(user_agent); + xmlrpc_client_create(&env, 0, "testprog", "1.0", + &clientParms1, XMLRPC_CPSIZE(transportparm_size), + &clientP); + TEST_NO_FAULT(&env); + xmlrpc_client_destroy(clientP); + + xmlrpc_client_teardown_global_const(); + + xmlrpc_env_clean(&env); +} + + + +static void +testSynchCall(void) { + + xmlrpc_env env; + xmlrpc_client * clientP; + xmlrpc_value * resultP; + xmlrpc_value * emptyArrayP; + xmlrpc_server_info * noSuchServerInfoP; + + xmlrpc_env_init(&env); + + emptyArrayP = xmlrpc_array_new(&env); + TEST_NO_FAULT(&env); + + xmlrpc_client_setup_global_const(&env); + TEST_NO_FAULT(&env); + + xmlrpc_client_create(&env, 0, "testprog", "1.0", NULL, 0, &clientP); + TEST_NO_FAULT(&env); + + noSuchServerInfoP = xmlrpc_server_info_new(&env, "nosuchserver"); + TEST_NO_FAULT(&env); + + xmlrpc_client_call2(&env, clientP, noSuchServerInfoP, "nosuchmethod", + emptyArrayP, &resultP); + TEST_FAULT(&env, XMLRPC_NETWORK_ERROR); /* No such server */ + + xmlrpc_client_call2f(&env, clientP, "nosuchserver", "nosuchmethod", + &resultP, "(i)", 7); + TEST_FAULT(&env, XMLRPC_NETWORK_ERROR); /* No such server */ + + xmlrpc_server_info_free(noSuchServerInfoP); + + xmlrpc_client_destroy(clientP); + + xmlrpc_DECREF(emptyArrayP); + + xmlrpc_client_teardown_global_const(); + + xmlrpc_env_clean(&env); +} + + + +static void +testInitCleanup(void) { + + xmlrpc_env env; + struct xmlrpc_clientparms clientParms1; + struct xmlrpc_curl_xportparms curlTransportParms1; + + xmlrpc_env_init(&env); + + xmlrpc_client_init2(&env, 0, "testprog", "1.0", NULL, 0); + TEST_NO_FAULT(&env); + xmlrpc_client_cleanup(); + + xmlrpc_client_init2(&env, 0, "testprog", "1.0", &clientParms1, 0); + TEST_NO_FAULT(&env); + xmlrpc_client_cleanup(); + + clientParms1.transport = "curl"; + xmlrpc_client_init2(&env, 0, "testprog", "1.0", + &clientParms1, XMLRPC_CPSIZE(transport)); + TEST_NO_FAULT(&env); + xmlrpc_client_cleanup(); + + clientParms1.transportparmsP = NULL; + xmlrpc_client_init2(&env, 0, "testprog", "1.0", + &clientParms1, XMLRPC_CPSIZE(transportparmsP)); + TEST_NO_FAULT(&env); + xmlrpc_client_cleanup(); + + clientParms1.transportparmsP = (struct xmlrpc_xportparms *)(void *) + &curlTransportParms1; + + /* Fails because we didn't include transportparm_size: */ + xmlrpc_client_init2(&env, 0, "testprog", "1.0", + &clientParms1, XMLRPC_CPSIZE(transportparmsP)); + TEST_FAULT(&env, XMLRPC_INTERNAL_ERROR); + + clientParms1.transportparm_size = 0; + xmlrpc_client_init2(&env, 0, "testprog", "1.0", + &clientParms1, XMLRPC_CPSIZE(transportparm_size)); + TEST_NO_FAULT(&env); + xmlrpc_client_cleanup(); + + curlTransportParms1.network_interface = "eth0"; + clientParms1.transportparm_size = XMLRPC_CXPSIZE(network_interface); + xmlrpc_client_init2(&env, 0, "testprog", "1.0", + &clientParms1, XMLRPC_CPSIZE(transportparm_size)); + TEST_NO_FAULT(&env); + xmlrpc_client_cleanup(); + + curlTransportParms1.no_ssl_verifypeer = 1; + curlTransportParms1.no_ssl_verifyhost = 1; + clientParms1.transportparm_size = XMLRPC_CXPSIZE(no_ssl_verifyhost); + xmlrpc_client_init2(&env, 0, "testprog", "1.0", + &clientParms1, XMLRPC_CPSIZE(transportparm_size)); + TEST_NO_FAULT(&env); + xmlrpc_client_cleanup(); + + curlTransportParms1.user_agent = "testprog/1.0"; + clientParms1.transportparm_size = XMLRPC_CXPSIZE(user_agent); + xmlrpc_client_init2(&env, 0, "testprog", "1.0", + &clientParms1, XMLRPC_CPSIZE(transportparm_size)); + TEST_NO_FAULT(&env); + xmlrpc_client_cleanup(); + + xmlrpc_client_init(0, "testprog", "1.0"); + TEST_NO_FAULT(&env); + xmlrpc_client_cleanup(); + + xmlrpc_env_clean(&env); +} + + + +void +test_client(void) { + + printf("Running client tests."); + + testGlobalConst(); + testCreateDestroy(); + testInitCleanup(); + testSynchCall(); + + printf("\n"); + printf("Client tests done.\n"); +} diff --git a/src/test/client.h b/src/test/client.h new file mode 100644 index 0000000..2727617 --- /dev/null +++ b/src/test/client.h @@ -0,0 +1,2 @@ +void +test_client(void); diff --git a/src/test/client_dummy.c b/src/test/client_dummy.c new file mode 100644 index 0000000..6377fb8 --- /dev/null +++ b/src/test/client_dummy.c @@ -0,0 +1,14 @@ +#include + +#include "client.h" + + + +void +test_client(void) { + + printf("Running dummy client test."); + + printf("\n"); + printf("Client tests done.\n"); +} diff --git a/src/test/data/req_no_params.xml b/src/test/data/req_no_params.xml new file mode 100644 index 0000000..6ed51a4 --- /dev/null +++ b/src/test/data/req_no_params.xml @@ -0,0 +1,9 @@ + + + + + + foo + diff --git a/src/test/data/req_out_of_order.xml b/src/test/data/req_out_of_order.xml new file mode 100644 index 0000000..8b078a4 --- /dev/null +++ b/src/test/data/req_out_of_order.xml @@ -0,0 +1,12 @@ + + + + + 2 + + + 2 + + + add + diff --git a/src/test/data/req_value_name.xml b/src/test/data/req_value_name.xml new file mode 100644 index 0000000..b55d4f0 --- /dev/null +++ b/src/test/data/req_value_name.xml @@ -0,0 +1,14 @@ + + + foo + + + + + 0 + child elements reversed! + + + + + diff --git a/src/test/data/sample_add_call.xml b/src/test/data/sample_add_call.xml new file mode 100644 index 0000000..b11336a --- /dev/null +++ b/src/test/data/sample_add_call.xml @@ -0,0 +1,8 @@ + + +sample.add + +5 +7 + + diff --git a/src/test/eftest_wrapper.sh b/src/test/eftest_wrapper.sh new file mode 100644 index 0000000..31606b7 --- /dev/null +++ b/src/test/eftest_wrapper.sh @@ -0,0 +1,17 @@ +#!/bin/sh + +echo "*** Testing for heap block overruns..." +efrpctest +if ! test $?; then exit 1; fi + +echo "*** Testing for heap block underruns..." +EF_PROTECT_BELOW=1 efrpctest +if ! test $?; then exit 1; fi + +echo "*** Testing for access to freed heap blocks..." +EF_PROTECT_FREE=1 efrpctest +if ! test $?; then exit 1; fi + +echo "*** Testing for single-byte overruns..." +EF_ALIGNMENT=0 efrpctest +if ! test $?; then exit 1; fi diff --git a/src/test/http-req-simple.txt b/src/test/http-req-simple.txt new file mode 100644 index 0000000..00db6a0 --- /dev/null +++ b/src/test/http-req-simple.txt @@ -0,0 +1,11 @@ +POST /cgi-bin/sample-cgi.cgi 1.0 +Host: localhost +Content-Type: text/xml +Content-Length: 141 + + + + system.listMethods + + + diff --git a/src/test/method_registry.c b/src/test/method_registry.c new file mode 100644 index 0000000..b8954f3 --- /dev/null +++ b/src/test/method_registry.c @@ -0,0 +1,524 @@ +#include +#include + +#include "casprintf.h" +#include "girstring.h" + +#include "xmlrpc_config.h" + +#include "xmlrpc-c/base.h" +#include "xmlrpc-c/server.h" + +#include "test.h" +#include "xml_data.h" +#include "method_registry.h" + + +#define FOO_USER_DATA ((void*) 0xF00) +#define BAR_USER_DATA ((void*) 0xBAF) + + + +static xmlrpc_value * +test_foo(xmlrpc_env * const envP, + xmlrpc_value * const paramArrayP, + void * const userData) { + + xmlrpc_int32 x, y; + + TEST_NO_FAULT(envP); + TEST(paramArrayP != NULL); + TEST(userData == FOO_USER_DATA); + + xmlrpc_decompose_value(envP, paramArrayP, "(ii)", &x, &y); + TEST_NO_FAULT(envP); + TEST(x == 25); + TEST(y == 17); + + return xmlrpc_build_value(envP, "i", (xmlrpc_int32) x + y); +} + + + +static xmlrpc_value * +test_bar(xmlrpc_env * const envP, + xmlrpc_value * const paramArrayP, + void * const userData) { + + xmlrpc_int32 x, y; + + TEST_NO_FAULT(envP); + TEST(paramArrayP != NULL); + TEST(userData == BAR_USER_DATA); + + xmlrpc_decompose_value(envP, paramArrayP, "(ii)", &x, &y); + TEST_NO_FAULT(envP); + TEST(x == 25); + TEST(y == 17); + + xmlrpc_env_set_fault(envP, 123, "Test fault"); + + return NULL; +} + + + +static xmlrpc_value * +test_default(xmlrpc_env * const envP, + const char * const host ATTR_UNUSED, + const char * const methodName ATTR_UNUSED, + xmlrpc_value * const paramArrayP, + void * const userData) { + + xmlrpc_int32 x, y; + + TEST_NO_FAULT(envP); + TEST(paramArrayP != NULL); + TEST(userData == FOO_USER_DATA); + + xmlrpc_decompose_value(envP, paramArrayP, "(ii)", &x, &y); + TEST_NO_FAULT(envP); + TEST(x == 25); + TEST(y == 17); + + return xmlrpc_build_value(envP, "i", 2 * (x + y)); +} + + + +static void +doRpc(xmlrpc_env * const envP, + xmlrpc_registry * const registryP, + const char * const methodName, + xmlrpc_value * const argArrayP, + xmlrpc_value ** const resultPP) { +/*---------------------------------------------------------------------------- + Do what an XML-RPC server would do -- pass an XML call to the registry + and get XML back. + + Actually to our caller, we look more like an Xmlrpc-c client. We're + both the client and the server all bound together. +-----------------------------------------------------------------------------*/ + xmlrpc_mem_block * callP; + xmlrpc_mem_block * responseP; + + /* Build a call, and tell the registry to handle it. */ + callP = xmlrpc_mem_block_new(envP, 0); + TEST_NO_FAULT(envP); + xmlrpc_serialize_call(envP, callP, methodName, argArrayP); + TEST_NO_FAULT(envP); + responseP = xmlrpc_registry_process_call(envP, registryP, NULL, + xmlrpc_mem_block_contents(callP), + xmlrpc_mem_block_size(callP)); + TEST_NO_FAULT(envP); + TEST(responseP != NULL); + + /* Parse the response. */ + *resultPP = xmlrpc_parse_response(envP, + xmlrpc_mem_block_contents(responseP), + xmlrpc_mem_block_size(responseP)); + + xmlrpc_mem_block_free(callP); + xmlrpc_mem_block_free(responseP); +} + + + +static const char * const validSigString[] = { + "i:", + "s:d", + "i:bds86SA", + "i:,i:", + "i:dd,s:,A:A", + "i:,", + "b:i,", + "b:i,b:,", + NULL +}; + +static const char * const invalidSigString[] = { + "", + "i", + "q", + "i:q", + "i:ddq", + ",", + ",i:", + "i,", + "b:i,,b:i", + "ii:", + "ii:ii", + NULL +}; + + +static void +test_signature_method(xmlrpc_registry * const registryP) { +/*---------------------------------------------------------------------------- + Test system.methodSignature system method. +-----------------------------------------------------------------------------*/ + xmlrpc_env env; + xmlrpc_value * argArrayP; + xmlrpc_value * resultP; + const char * type0; + const char * type1; + const char * type2; + const char * type3; + const char * type4; + const char * type5; + const char * type6; + const char * type7; + const char * nosigstring; + + xmlrpc_env_init(&env); + + argArrayP = xmlrpc_build_value(&env, "(s)", "test.nosuchmethod"); + doRpc(&env, registryP, "system.methodSignature", argArrayP, &resultP); + TEST_FAULT(&env, XMLRPC_NO_SUCH_METHOD_ERROR); + xmlrpc_DECREF(argArrayP); + + argArrayP = xmlrpc_build_value(&env, "(s)", "test.nosig0"); + + doRpc(&env, registryP, "system.methodSignature", argArrayP, &resultP); + TEST_NO_FAULT(&env); + + xmlrpc_read_string(&env, resultP, &nosigstring); + TEST_NO_FAULT(&env); + + TEST(streq(nosigstring, "undef")); + strfree(nosigstring); + xmlrpc_DECREF(resultP); + xmlrpc_DECREF(argArrayP); + + argArrayP = xmlrpc_build_value(&env, "(s)", "test.validsig0"); + doRpc(&env, registryP, "system.methodSignature", argArrayP, &resultP); + TEST_NO_FAULT(&env); + + xmlrpc_decompose_value(&env, resultP, "((s))", &type0); + TEST_NO_FAULT(&env); + TEST(streq(type0, "int")); + strfree(type0); + xmlrpc_DECREF(resultP); + xmlrpc_DECREF(argArrayP); + + argArrayP = xmlrpc_build_value(&env, "(s)", "test.validsig2"); + doRpc(&env, registryP, "system.methodSignature", argArrayP, &resultP); + TEST_NO_FAULT(&env); + xmlrpc_decompose_value(&env, resultP, "((ssssssss))", + &type0, &type1, &type2, &type3, + &type4, &type5, &type6, &type7); + TEST_NO_FAULT(&env); + TEST(streq(type0, "int")); + TEST(streq(type1, "boolean")); + TEST(streq(type2, "double")); + TEST(streq(type3, "string")); + TEST(streq(type4, "dateTime.iso8601")); + TEST(streq(type5, "base64")); + TEST(streq(type6, "struct")); + TEST(streq(type7, "array")); + strfree(type0); strfree(type1); strfree(type2); strfree(type3); + strfree(type4); strfree(type5); strfree(type6); strfree(type7); + xmlrpc_DECREF(resultP); + xmlrpc_DECREF(argArrayP); + + argArrayP = xmlrpc_build_value(&env, "(s)", "test.validsig3"); + doRpc(&env, registryP, "system.methodSignature", argArrayP, &resultP); + TEST_NO_FAULT(&env); + xmlrpc_decompose_value(&env, resultP, "((s)(s))", &type0, &type1); + + TEST_NO_FAULT(&env); + TEST(streq(type0, "int")); + TEST(streq(type1, "int")); + xmlrpc_DECREF(resultP); + xmlrpc_DECREF(argArrayP); + + xmlrpc_env_clean(&env); +} + + + +static void +test_signature(void) { + + xmlrpc_env env; + xmlrpc_registry * registryP; + uint i; + + xmlrpc_env_init(&env); + + printf(" Running signature tests."); + + registryP = xmlrpc_registry_new(&env); + TEST_NO_FAULT(&env); + + xmlrpc_registry_add_method_w_doc(&env, registryP, NULL, "test.nosig0", + test_foo, FOO_USER_DATA, + NULL, NULL); + TEST_NO_FAULT(&env); + + xmlrpc_registry_add_method_w_doc(&env, registryP, NULL, "test.nosig1", + test_foo, FOO_USER_DATA, + "?", NULL); + TEST_NO_FAULT(&env); + + for (i = 0; validSigString[i]; ++i) { + const char * methodName; + casprintf(&methodName, "test.validsig%u", i); + xmlrpc_registry_add_method_w_doc(&env, registryP, NULL, methodName, + test_foo, FOO_USER_DATA, + validSigString[i], NULL); + TEST_NO_FAULT(&env); + strfree(methodName); + } + + for (i = 0; invalidSigString[i]; ++i) { + const char * methodName; + casprintf(&methodName, "test.invalidsig%u", i); + xmlrpc_registry_add_method_w_doc(&env, registryP, NULL, methodName, + test_foo, FOO_USER_DATA, + invalidSigString[i], NULL); + TEST_FAULT(&env, XMLRPC_INTERNAL_ERROR); + strfree(methodName); + } + + test_signature_method(registryP); + + xmlrpc_registry_free(registryP); + + xmlrpc_env_clean(&env); + + printf("\n"); +} + + + +static void +test_system_multicall(xmlrpc_registry * const registryP) { +/*---------------------------------------------------------------------------- + Test system.multicall +-----------------------------------------------------------------------------*/ + xmlrpc_env env; + xmlrpc_value * multiP; + xmlrpc_int32 foo1_result, foo2_result; + xmlrpc_int32 bar_code, nosuch_code, multi_code, bogus1_code, bogus2_code; + char *bar_string, *nosuch_string, *multi_string; + char *bogus1_string, *bogus2_string; + xmlrpc_value * valueP; + xmlrpc_value * argArrayP; + + xmlrpc_env_init(&env); + + printf(" Running multicall tests."); + + /* Build an argument array for our calls. */ + argArrayP = xmlrpc_build_value(&env, "(ii)", + (xmlrpc_int32) 25, (xmlrpc_int32) 17); + TEST_NO_FAULT(&env); + + multiP = xmlrpc_build_value(&env, + "(({s:s,s:V}{s:s,s:V}{s:s,s:V}" + "{s:s,s:()}s{}{s:s,s:V}))", + "methodName", "test.foo", + "params", argArrayP, + "methodName", "test.bar", + "params", argArrayP, + "methodName", "test.nosuch", + "params", argArrayP, + "methodName", "system.multicall", + "params", + "bogus_entry", + "methodName", "test.foo", + "params", argArrayP); + TEST_NO_FAULT(&env); + doRpc(&env, registryP, "system.multicall", multiP, &valueP); + TEST_NO_FAULT(&env); + xmlrpc_decompose_value(&env, valueP, + "((i){s:i,s:s,*}{s:i,s:s,*}" + "{s:i,s:s,*}{s:i,s:s,*}{s:i,s:s,*}(i))", + &foo1_result, + "faultCode", &bar_code, + "faultString", &bar_string, + "faultCode", &nosuch_code, + "faultString", &nosuch_string, + "faultCode", &multi_code, + "faultString", &multi_string, + "faultCode", &bogus1_code, + "faultString", &bogus1_string, + "faultCode", &bogus2_code, + "faultString", &bogus2_string, + &foo2_result); + xmlrpc_DECREF(valueP); + TEST_NO_FAULT(&env); + TEST(foo1_result == 42); + TEST(bar_code == 123); + TEST(strcmp(bar_string, "Test fault") == 0); + TEST(nosuch_code == XMLRPC_NO_SUCH_METHOD_ERROR); + TEST(multi_code == XMLRPC_REQUEST_REFUSED_ERROR); + TEST(foo2_result == 42); + xmlrpc_DECREF(multiP); + free(bar_string); + free(nosuch_string); + free(multi_string); + free(bogus1_string); + free(bogus2_string); + + xmlrpc_DECREF(argArrayP); + + xmlrpc_env_clean(&env); + + printf("\n"); +} + + + +static void +testCall(xmlrpc_registry * const registryP) { + + xmlrpc_env env; + xmlrpc_env env2; + xmlrpc_value * argArrayP; + xmlrpc_value * valueP; + xmlrpc_int32 i; + + printf(" Running call tests."); + + xmlrpc_env_init(&env); + + /* Build an argument array for our calls. */ + argArrayP = xmlrpc_build_value(&env, "(ii)", + (xmlrpc_int32) 25, (xmlrpc_int32) 17); + TEST_NO_FAULT(&env); + + /* Call test.foo and check the result. */ + doRpc(&env, registryP, "test.foo", argArrayP, &valueP); + TEST_NO_FAULT(&env); + TEST(valueP != NULL); + xmlrpc_decompose_value(&env, valueP, "i", &i); + xmlrpc_DECREF(valueP); + TEST_NO_FAULT(&env); + TEST(i == 42); + + /* Call test.bar and check the result. */ + xmlrpc_env_init(&env2); + doRpc(&env2, registryP, "test.bar", argArrayP, &valueP); + TEST(env2.fault_occurred); + TEST(env2.fault_code == 123); + TEST(env2.fault_string && strcmp(env2.fault_string, "Test fault") == 0); + xmlrpc_env_clean(&env2); + + /* Call a non-existant method and check the result. */ + xmlrpc_env_init(&env2); + doRpc(&env2, registryP, "test.nosuch", argArrayP, &valueP); + TEST(valueP == NULL); + TEST_FAULT(&env2, XMLRPC_NO_SUCH_METHOD_ERROR); + xmlrpc_env_clean(&env2); + + xmlrpc_DECREF(argArrayP); + + xmlrpc_env_clean(&env); + + printf("\n"); +} + + + +static void +testDefaultMethod(xmlrpc_registry * const registryP) { + + xmlrpc_env env; + xmlrpc_value * argArrayP; + xmlrpc_value * valueP; + xmlrpc_int32 i; + + xmlrpc_env_init(&env); + + printf(" Running default method tests."); + + /* Build an argument array for our calls. */ + argArrayP = xmlrpc_build_value(&env, "(ii)", + (xmlrpc_int32) 25, (xmlrpc_int32) 17); + + xmlrpc_registry_set_default_method(&env, registryP, &test_default, + FOO_USER_DATA); + TEST_NO_FAULT(&env); + doRpc(&env, registryP, "test.nosuch", argArrayP, &valueP); + TEST_NO_FAULT(&env); + TEST(valueP != NULL); + xmlrpc_decompose_value(&env, valueP, "i", &i); + xmlrpc_DECREF(valueP); + TEST_NO_FAULT(&env); + TEST(i == 84); + + /* Change the default method. */ + xmlrpc_registry_set_default_method(&env, registryP, &test_default, + BAR_USER_DATA); + TEST_NO_FAULT(&env); + + xmlrpc_DECREF(argArrayP); + + xmlrpc_env_clean(&env); + + printf("\n"); +} + + + +void +test_method_registry(void) { + + xmlrpc_env env, env2; + xmlrpc_value * valueP; + xmlrpc_registry *registryP; + xmlrpc_mem_block *response; + + xmlrpc_env_init(&env); + + printf("Running method registry tests."); + + /* Create a new registry. */ + registryP = xmlrpc_registry_new(&env); + TEST_NO_FAULT(&env); + TEST(registryP != NULL); + + /* Add some test methods. */ + xmlrpc_registry_add_method(&env, registryP, NULL, "test.foo", + test_foo, FOO_USER_DATA); + TEST_NO_FAULT(&env); + xmlrpc_registry_add_method(&env, registryP, NULL, "test.bar", + test_bar, BAR_USER_DATA); + TEST_NO_FAULT(&env); + + printf("\n"); + testCall(registryP); + + test_system_multicall(registryP); + + /* PASS bogus XML data and make sure our parser pukes gracefully. + ** (Because of the way the code is laid out, and the presence of other + ** test suites, this lets us skip tests for invalid XML-RPC data.) */ + xmlrpc_env_init(&env2); + response = xmlrpc_registry_process_call(&env, registryP, NULL, + expat_error_data, + strlen(expat_error_data)); + TEST_NO_FAULT(&env); + TEST(response != NULL); + valueP = xmlrpc_parse_response(&env2, xmlrpc_mem_block_contents(response), + xmlrpc_mem_block_size(response)); + TEST(valueP == NULL); + TEST_FAULT(&env2, XMLRPC_PARSE_ERROR); + xmlrpc_mem_block_free(response); + xmlrpc_env_clean(&env2); + + printf("\n"); + testDefaultMethod(registryP); + + test_signature(); + + /* Test cleanup code (w/memprof). */ + xmlrpc_registry_free(registryP); + + printf("\n"); + + xmlrpc_env_clean(&env); +} + diff --git a/src/test/method_registry.h b/src/test/method_registry.h new file mode 100644 index 0000000..bdc325b --- /dev/null +++ b/src/test/method_registry.h @@ -0,0 +1,7 @@ +#ifndef TEST_METHOD_REGISTRY_H_INCLUDED +#define TEST_METHOD_REGISTRY_H_INCLUDED + +void +test_method_registry(void); + +#endif diff --git a/src/test/parse_xml.c b/src/test/parse_xml.c new file mode 100644 index 0000000..8643efd --- /dev/null +++ b/src/test/parse_xml.c @@ -0,0 +1,388 @@ +#include +#include + +#include "xmlrpc_config.h" + +#include "girstring.h" +#include "casprintf.h" +#include "xmlrpc-c/base.h" +#include "xmlrpc-c/xmlparser.h" + +#include "test.h" +#include "xml_data.h" +#include "parse_xml.h" + + + +static void test_expat (void) +{ + xmlrpc_env env; + xml_element *elem, *array, *data, *value1, *i4; + char *cdata; + size_t size; + + xmlrpc_env_init(&env); + + /* Parse a moderately complex XML document. */ + xml_parse(&env, expat_data, strlen(expat_data), &elem); + TEST_NO_FAULT(&env); + TEST(elem != NULL); + + /* Verify our results. */ + TEST(streq(xml_element_name(elem), "value")); + TEST(xml_element_children_size(elem) == 1); + array = xml_element_children(elem)[0]; + TEST(streq(xml_element_name(array), "array")); + TEST(xml_element_children_size(array) == 1); + data = xml_element_children(array)[0]; + TEST(streq(xml_element_name(data), "data")); + TEST(xml_element_children_size(data) > 1); + value1 = xml_element_children(data)[0]; + TEST(streq(xml_element_name(value1), "value")); + TEST(xml_element_children_size(value1) == 1); + i4 = xml_element_children(value1)[0]; + TEST(streq(xml_element_name(i4), "i4")); + TEST(xml_element_children_size(i4) == 0); + cdata = xml_element_cdata(i4); + size = xml_element_cdata_size(i4); + TEST(size == strlen("2147483647")); + TEST(memcmp(cdata, "2147483647", strlen("2147483647")) == 0); + + /* Test cleanup code (w/memprof). */ + xml_element_free(elem); + + /* Test broken XML */ + xml_parse(&env, expat_error_data, strlen(expat_error_data), &elem); + TEST(env.fault_occurred); + + xmlrpc_env_clean(&env); +} + + + +static void +validateParseResponseResult(xmlrpc_value * const valueP) { + + xmlrpc_env env; + + xmlrpc_value * s; + xmlrpc_int32 int_max; + xmlrpc_int32 int_min; + xmlrpc_int32 int_one; + xmlrpc_bool bool_false; + xmlrpc_bool bool_true; + char * str_hello; + char * str_untagged; + char * datetime; + unsigned char * b64_data; + size_t b64_len; + double negone; + double zero; + double one; + + xmlrpc_env_init(&env); + + xmlrpc_decompose_value( + &env, valueP, "((iibbs68())idddSs)", + &int_max, &int_min, + &bool_false, &bool_true, &str_hello, + &b64_data, &b64_len, &datetime, + &int_one, &negone, &zero, &one, &s, &str_untagged); + + TEST_NO_FAULT(&env); + TEST(int_max == INT_MAX); + TEST(int_min == INT_MIN); + TEST(!bool_false); + TEST(bool_true); + TEST(strlen(str_hello) == strlen("Hello, world! <&>")); + TEST(streq(str_hello, "Hello, world! <&>")); + TEST(b64_len == 11); + TEST(memcmp(b64_data, "base64 data", b64_len) == 0); + TEST(streq(datetime, "19980717T14:08:55")); + TEST(int_one == 1); + TEST(negone == -1.0); + TEST(zero == 0.0); + TEST(one == 1.0); + TEST(streq(str_untagged, "Untagged string")); + free(str_hello); + free(b64_data); + free(datetime); + free(str_untagged); + + { + /* Analyze the contents of our struct. */ + + xmlrpc_value * sval; + int size, sval_int; + + TEST(s != NULL); + size = xmlrpc_struct_size(&env, s); + TEST_NO_FAULT(&env); + TEST(size == 2); + sval = xmlrpc_struct_get_value(&env, s, "ten <&>"); + TEST_NO_FAULT(&env); + xmlrpc_decompose_value(&env, sval, "i", &sval_int); + TEST_NO_FAULT(&env); + TEST(sval_int == 10); + sval = xmlrpc_struct_get_value(&env, s, "twenty"); + TEST_NO_FAULT(&env); + xmlrpc_decompose_value(&env, sval, "i", &sval_int); + TEST_NO_FAULT(&env); + TEST(sval_int == 20); + xmlrpc_DECREF(s); + } + + xmlrpc_env_clean(&env); +} + + + +static void +testParseGoodResponse(void) { + + xmlrpc_env env; + xmlrpc_value * valueP; + int faultCode; + const char * faultString; + + xmlrpc_env_init(&env); + + xmlrpc_parse_response2(&env, good_response_xml, strlen(good_response_xml), + &valueP, &faultCode, &faultString); + + TEST_NO_FAULT(&env); + TEST(faultString == NULL); + + validateParseResponseResult(valueP); + + xmlrpc_DECREF(valueP); + + /* Try it again with old interface */ + + valueP = xmlrpc_parse_response(&env, + good_response_xml, + strlen(good_response_xml)); + TEST_NO_FAULT(&env); + TEST(valueP != NULL); + + validateParseResponseResult(valueP); + + xmlrpc_DECREF(valueP); + + xmlrpc_env_clean(&env); + +} + + + +static void +testParseBadResponse(void) { +/*---------------------------------------------------------------------------- + Test parsing of data that is supposed to be a response, but is not + valid. Either not valid XML or not valid XML-RPC. +-----------------------------------------------------------------------------*/ + unsigned int i; + + { + xmlrpc_env env; + xmlrpc_value * valueP; + int faultCode; + const char * faultString; + + /* First, test some poorly-formed XML data. */ + xmlrpc_env_init(&env); + + xmlrpc_parse_response2(&env, + unparseable_value, strlen(unparseable_value), + &valueP, &faultCode, &faultString); + + TEST_FAULT(&env, XMLRPC_PARSE_ERROR); + xmlrpc_env_clean(&env); + + xmlrpc_env_init(&env); + + /* And again with the old interface */ + valueP = xmlrpc_parse_response(&env, unparseable_value, + strlen(unparseable_value)); + TEST_FAULT(&env, XMLRPC_PARSE_ERROR); + xmlrpc_env_clean(&env); + TEST(valueP == NULL); + } + + /* Try with good XML, but bad XML-RPC. For this test, we test up to + but not including the in a successful RPC response. + */ + + /* Next, check for bogus responses. These are all well-formed XML, but + ** they aren't legal XML-RPC. */ + for (i = 15; bad_responses[i] != NULL; ++i) { + const char * const bad_resp = bad_responses[i]; + xmlrpc_env env; + xmlrpc_value * v; + xml_element *elem; + + xmlrpc_env_init(&env); + + /* First, check to make sure that our test case is well-formed XML. + ** (It's easy to make mistakes when writing the test cases!) */ + xml_parse(&env, bad_resp, strlen(bad_resp), &elem); + TEST_NO_FAULT(&env); + xml_element_free(elem); + + /* Now, make sure the higher-level routine barfs appropriately. */ + v = xmlrpc_parse_response(&env, bad_resp, strlen(bad_resp)); + TEST(env.fault_occurred); + TEST(env.fault_code != 0); /* We use 0 as a code in our bad faults. */ + TEST(v == NULL); + xmlrpc_env_clean(&env); + } + + /* Try with good XML, good XML-RPC response, except that the value + isn't valid XML-RPC + */ + for (i = 0; bad_values[i] != NULL; ++i) { + const char * const bad_resp = bad_values[i]; + xmlrpc_env env; + xmlrpc_value * valueP; + xml_element *elem; + int faultCode; + const char * faultString; + + xmlrpc_env_init(&env); + + /* First, check to make sure that our test case is well-formed XML. + ** (It's easy to make mistakes when writing the test cases!) */ + xml_parse(&env, bad_resp, strlen(bad_resp), &elem); + TEST_NO_FAULT(&env); + xml_element_free(elem); + + /* Now, make sure the higher-level routine barfs appropriately. */ + + xmlrpc_parse_response2(&env, bad_resp, strlen(bad_resp), + &valueP, &faultCode, &faultString); + + TEST_FAULT(&env, XMLRPC_PARSE_ERROR); + xmlrpc_env_clean(&env); + + xmlrpc_env_init(&env); + + /* And again with the old interface */ + + valueP = xmlrpc_parse_response(&env, bad_resp, strlen(bad_resp)); + TEST_FAULT(&env, XMLRPC_PARSE_ERROR); + TEST(valueP == NULL); + xmlrpc_env_clean(&env); + } +} + + + +static void +testParseFaultResponse(void) { +/*---------------------------------------------------------------------------- + Test parsing of a valid response that indicates the RPC failed. +-----------------------------------------------------------------------------*/ + xmlrpc_env env; + + xmlrpc_env_init(&env); + + { + xmlrpc_value * resultP; + int faultCode; + const char * faultString; + + xmlrpc_parse_response2(&env, + serialized_fault, strlen(serialized_fault), + &resultP, &faultCode, &faultString); + + TEST_NO_FAULT(&env); + TEST(faultString != NULL); + TEST(faultCode == 6); + TEST(streq(faultString, "A fault occurred")); + strfree(faultString); + } + /* Now with the old interface */ + { + xmlrpc_value * valueP; + xmlrpc_env fault; + + /* Parse a valid fault. */ + xmlrpc_env_init(&fault); + valueP = xmlrpc_parse_response(&fault, serialized_fault, + strlen(serialized_fault)); + + TEST(fault.fault_occurred); + TEST(fault.fault_code == 6); + TEST(streq(fault.fault_string, "A fault occurred")); + xmlrpc_env_clean(&fault); + } + + xmlrpc_env_clean(&env); +} + + + +static void +test_parse_xml_call(void) { + + xmlrpc_env env; + const char *method_name; + xmlrpc_value *params; + int i1, i2; + const char **bad_call; + xml_element *elem; + + xmlrpc_env_init(&env); + + /* Parse a valid call. */ + xmlrpc_parse_call(&env, serialized_call, strlen(serialized_call), + &method_name, ¶ms); + TEST_NO_FAULT(&env); + TEST(params != NULL); + xmlrpc_decompose_value(&env, params, "(ii)", &i1, &i2); + xmlrpc_DECREF(params); + TEST_NO_FAULT(&env); + TEST(streq(method_name, "gloom&doom")); + TEST(i1 == 10 && i2 == 20); + strfree(method_name); + + /* Test some poorly-formed XML data. */ + xmlrpc_parse_call(&env, unparseable_value, strlen(unparseable_value), + &method_name, ¶ms); + TEST_FAULT(&env, XMLRPC_PARSE_ERROR); + TEST(method_name == NULL && params == NULL); + + /* Next, check for bogus values. These are all well-formed XML, but + they aren't legal XML-RPC. + */ + for (bad_call = bad_calls; *bad_call != NULL; ++bad_call) { + + /* First, check to make sure that our test case is well-formed XML. + ** (It's easy to make mistakes when writing the test cases!) */ + xml_parse(&env, *bad_call, strlen(*bad_call), &elem); + TEST_NO_FAULT(&env); + xml_element_free(elem); + + /* Now, make sure the higher-level routine barfs appropriately. */ + xmlrpc_parse_call(&env, *bad_call, strlen(*bad_call), + &method_name, ¶ms); + TEST_FAULT(&env, XMLRPC_PARSE_ERROR); + TEST(method_name == NULL && params == NULL); + } + xmlrpc_env_clean(&env); +} + + + +void +test_parse_xml(void) { + + printf("Running XML parsing tests.\n"); + test_expat(); + testParseGoodResponse(); + testParseFaultResponse(); + testParseBadResponse(); + test_parse_xml_call(); + printf("\n"); + printf("XML parsing tests done.\n"); +} diff --git a/src/test/parse_xml.h b/src/test/parse_xml.h new file mode 100644 index 0000000..c392886 --- /dev/null +++ b/src/test/parse_xml.h @@ -0,0 +1,2 @@ +void +test_parse_xml(void); diff --git a/src/test/req_no_params.xml b/src/test/req_no_params.xml new file mode 100644 index 0000000..6ed51a4 --- /dev/null +++ b/src/test/req_no_params.xml @@ -0,0 +1,9 @@ + + + + + + foo + diff --git a/src/test/serialize.c b/src/test/serialize.c new file mode 100644 index 0000000..b578434 --- /dev/null +++ b/src/test/serialize.c @@ -0,0 +1,283 @@ +#include +#include +#include + +#include "xmlrpc_config.h" + +#include "xmlrpc-c/base.h" + +#include "test.h" +#include "xml_data.h" +#include "serialize.h" + + + +static void +test_serialize_basic(void) { + + xmlrpc_env env; + xmlrpc_value * v; + xmlrpc_mem_block *output; + size_t size; + + xmlrpc_env_init(&env); + + /* Build a nice, messy value to serialize. We should attempt to use + ** use every data type except double (which doesn't serialize in a + ** portable manner. */ + v = xmlrpc_build_value(&env, "(iibbs68())", + (xmlrpc_int32) INT_MAX, (xmlrpc_int32) INT_MIN, + (xmlrpc_bool) 0, (xmlrpc_bool) 1, + "Hello, world! <&>", + "base64 data", (size_t) 11, + "19980717T14:08:55"); + TEST_NO_FAULT(&env); + + /* Serialize the value. */ + output = XMLRPC_TYPED_MEM_BLOCK_NEW(char, &env, 0); + TEST_NO_FAULT(&env); + xmlrpc_serialize_value(&env, output, v); + TEST_NO_FAULT(&env); + + /* Make sure we serialized the correct value. */ + size = XMLRPC_TYPED_MEM_BLOCK_SIZE(char, output); + TEST(size == strlen(serialized_data)); + TEST(memcmp(XMLRPC_TYPED_MEM_BLOCK_CONTENTS(char, output), + serialized_data, size) == 0); + + /* (Debugging code to display the value.) */ + /* XMLRPC_TYPED_MEM_BLOCK_APPEND(char, &env, output, "\0", 1); + ** TEST_NO_FAULT(&env); + ** printf("%s\n", XMLRPC_TYPED_MEM_BLOCK_CONTENTS(char, output)); */ + + /* Clean up our value. */ + XMLRPC_TYPED_MEM_BLOCK_FREE(char, output); + xmlrpc_DECREF(v); + + xmlrpc_env_clean(&env); +} + + + +static void +test_serialize_double(void) { + + /* Test serialize of a double. */ + + xmlrpc_env env; + xmlrpc_value * v; + xmlrpc_mem_block *output; + char * result; + /* serialized result, as asciiz string */ + size_t resultLength; + /* Length in characters of the serialized result */ + float serializedValue; + char nextChar; + int itemsMatched; + + xmlrpc_env_init(&env); + + /* Build a double to serialize */ + v = xmlrpc_build_value(&env, "d", 3.14159); + TEST_NO_FAULT(&env); + + /* Serialize the value. */ + output = XMLRPC_TYPED_MEM_BLOCK_NEW(char, &env, 0); + TEST_NO_FAULT(&env); + xmlrpc_serialize_value(&env, output, v); + TEST_NO_FAULT(&env); + + /* Make sure we serialized the correct value. Note that because + doubles aren't precise, this might serialize as 3.1415899999 + or something like that. So we check it arithmetically. + */ + resultLength = XMLRPC_TYPED_MEM_BLOCK_SIZE(char, output); + result = malloc(resultLength + 1); + + memcpy(result, XMLRPC_TYPED_MEM_BLOCK_CONTENTS(char, output), + resultLength); + result[resultLength] = '\0'; + + itemsMatched = sscanf(result, + "%f\r\n%c", + &serializedValue, &nextChar); + + TEST(itemsMatched == 1); + TEST(serializedValue - 3.14159 < .000001); + /* We'd like to test more precision, but sscanf doesn't do doubles */ + + free(result); + + /* Clean up our value. */ + XMLRPC_TYPED_MEM_BLOCK_FREE(char, output); + xmlrpc_DECREF(v); + + xmlrpc_env_clean(&env); +} + + + +static void +test_serialize_struct(void) { + + /* Serialize a simple struct. */ + + char const serialized_struct[] = + "\r\n" \ + "<&>\r\n" \ + "10\r\n" \ + ""; + + xmlrpc_env env; + xmlrpc_value * v; + xmlrpc_mem_block *output; + size_t size; + + xmlrpc_env_init(&env); + + v = xmlrpc_build_value(&env, "{s:i}", "<&>", (xmlrpc_int32) 10); + TEST_NO_FAULT(&env); + output = XMLRPC_TYPED_MEM_BLOCK_NEW(char, &env, 0); + TEST_NO_FAULT(&env); + xmlrpc_serialize_value(&env, output, v); + TEST_NO_FAULT(&env); + + /* Make sure we serialized the correct value. */ + size = XMLRPC_TYPED_MEM_BLOCK_SIZE(char, output); + TEST(size == strlen(serialized_struct)); + TEST(memcmp(XMLRPC_TYPED_MEM_BLOCK_CONTENTS(char, output), + serialized_struct, size) == 0); + + /* Clean up our struct. */ + XMLRPC_TYPED_MEM_BLOCK_FREE(char, output); + xmlrpc_DECREF(v); + + xmlrpc_env_clean(&env); +} + + + +static void +test_serialize_methodResponse(void) { + + /* Serialize a methodResponse. */ + + char const serialized_response[] = + XML_PROLOGUE + "\r\n" + "\r\n" + "30\r\n" + "\r\n" + "\r\n"; + + xmlrpc_env env; + xmlrpc_value * v; + xmlrpc_mem_block *output; + size_t size; + + xmlrpc_env_init(&env); + + output = XMLRPC_TYPED_MEM_BLOCK_NEW(char, &env, 0); + TEST_NO_FAULT(&env); + v = xmlrpc_build_value(&env, "i", (xmlrpc_int32) 30); + TEST_NO_FAULT(&env); + xmlrpc_serialize_response(&env, output, v); + TEST_NO_FAULT(&env); + + /* Make sure we serialized the correct value. */ + size = XMLRPC_TYPED_MEM_BLOCK_SIZE(char, output); + TEST(size == strlen(serialized_response)); + TEST(memcmp(XMLRPC_TYPED_MEM_BLOCK_CONTENTS(char, output), + serialized_response, size) == 0); + + /* Clean up our methodResponse. */ + xmlrpc_DECREF(v); + XMLRPC_TYPED_MEM_BLOCK_FREE(char, output); + + xmlrpc_env_clean(&env); +} + + + +static void +test_serialize_methodCall(void) { + + /* Serialize a methodCall. */ + + xmlrpc_env env; + xmlrpc_value * v; + xmlrpc_mem_block *output; + size_t size; + + xmlrpc_env_init(&env); + + output = XMLRPC_TYPED_MEM_BLOCK_NEW(char, &env, 0); + TEST_NO_FAULT(&env); + v = xmlrpc_build_value(&env, "(ii)", (xmlrpc_int32) 10, (xmlrpc_int32) 20); + TEST_NO_FAULT(&env); + xmlrpc_serialize_call(&env, output, "gloom&doom", v); + TEST_NO_FAULT(&env); + + /* Make sure we serialized the correct value. */ + size = XMLRPC_TYPED_MEM_BLOCK_SIZE(char, output); + TEST(size == strlen(serialized_call)); + TEST(memcmp(XMLRPC_TYPED_MEM_BLOCK_CONTENTS(char, output), + serialized_call, size) == 0); + + /* Clean up our methodCall. */ + xmlrpc_DECREF(v); + XMLRPC_TYPED_MEM_BLOCK_FREE(char, output); + + xmlrpc_env_clean(&env); +} + + + +static void +test_serialize_fault(void) { + /* Serialize a fault. */ + + xmlrpc_env env; + xmlrpc_env fault; + xmlrpc_mem_block *output; + size_t size; + + xmlrpc_env_init(&env); + + output = XMLRPC_TYPED_MEM_BLOCK_NEW(char, &env, 0); + TEST_NO_FAULT(&env); + xmlrpc_env_init(&fault); + xmlrpc_env_set_fault(&fault, 6, "A fault occurred"); + xmlrpc_serialize_fault(&env, output, &fault); + TEST_NO_FAULT(&env); + + /* Make sure we serialized the correct value. */ + size = XMLRPC_TYPED_MEM_BLOCK_SIZE(char, output); + TEST(size == strlen(serialized_fault)); + TEST(memcmp(XMLRPC_TYPED_MEM_BLOCK_CONTENTS(char, output), + serialized_fault, size) == 0); + + /* Clean up our fault. */ + xmlrpc_env_clean(&fault); + XMLRPC_TYPED_MEM_BLOCK_FREE(char, output); + + xmlrpc_env_clean(&env); +} + + + +void +test_serialize(void) { + + printf("Running serialize tests."); + + test_serialize_basic(); + test_serialize_double(); + test_serialize_struct(); + test_serialize_methodResponse(); + test_serialize_methodCall(); + test_serialize_fault(); + + printf("\n"); + printf("Serialize tests done.\n"); +} diff --git a/src/test/serialize.h b/src/test/serialize.h new file mode 100644 index 0000000..f01ef58 --- /dev/null +++ b/src/test/serialize.h @@ -0,0 +1,2 @@ +void +test_serialize(void); diff --git a/src/test/server_abyss.c b/src/test/server_abyss.c new file mode 100644 index 0000000..01f879b --- /dev/null +++ b/src/test/server_abyss.c @@ -0,0 +1,92 @@ +#include "unistdx.h" +#include + +#include "xmlrpc_config.h" + +#include "xmlrpc-c/base.h" +#include "xmlrpc-c/server.h" +#include "xmlrpc-c/abyss.h" +#include "xmlrpc-c/server_abyss.h" + +#include "test.h" + +#include "server_abyss.h" + + +static void +testSetHandlers(TServer * const abyssServerP) { + + xmlrpc_env env; + xmlrpc_registry * registryP; + + xmlrpc_env_init(&env); + + registryP = xmlrpc_registry_new(&env); + TEST_NO_FAULT(&env); + TEST(registryP != NULL); + + xmlrpc_server_abyss_set_handler(&env, abyssServerP, "/RPC3", registryP); + TEST_NO_FAULT(&env); + + xmlrpc_server_abyss_set_handlers2(abyssServerP, "/RPC4", registryP); + + xmlrpc_registry_free(registryP); + + { + xmlrpc_registry * registryP; + registryP = xmlrpc_registry_new(&env); + xmlrpc_server_abyss_set_handlers(abyssServerP, registryP); + xmlrpc_registry_free(registryP); + } + xmlrpc_env_clean(&env); +} + + + +static void +testServerParms(void) { + xmlrpc_server_abyss_parms parms; + + parms.port_number = 1000; + parms.log_file_name = "/tmp/xmlrpc_logfile"; + parms.keepalive_timeout = 5; + parms.keepalive_max_conn = 4; + parms.timeout = 50; + parms.dont_advertise = TRUE; + parms.uri_path = "/RPC9"; + parms.chunk_response = TRUE; +}; + + + +void +test_server_abyss(void) { + + xmlrpc_env env; + TServer abyssServer; + + printf("Running Abyss server tests...\n"); + + xmlrpc_env_init(&env); + + ServerCreate(&abyssServer, "testserver", 8080, NULL, NULL); + + testSetHandlers(&abyssServer); + + ServerSetKeepaliveTimeout(&abyssServer, 60); + ServerSetKeepaliveMaxConn(&abyssServer, 10); + ServerSetTimeout(&abyssServer, 0); + ServerSetAdvertise(&abyssServer, FALSE); + + ServerFree(&abyssServer); + + ServerCreateSocket(&abyssServer, "testserver", STDIN_FILENO, + "/home/http", "/tmp/logfile"); + + ServerFree(&abyssServer); + + testServerParms(); + + printf("\n"); + printf("Abyss server tests done.\n"); +} diff --git a/src/test/server_abyss.h b/src/test/server_abyss.h new file mode 100644 index 0000000..2cd5279 --- /dev/null +++ b/src/test/server_abyss.h @@ -0,0 +1,2 @@ +void +test_server_abyss(void); diff --git a/src/test/test.c b/src/test/test.c new file mode 100644 index 0000000..80511f7 --- /dev/null +++ b/src/test/test.c @@ -0,0 +1,741 @@ +/* Copyright information is at the end of the file. */ + +#include +#include +#include +#include +#include + +#include "casprintf.h" + +#include "xmlrpc_config.h" + +#include "xmlrpc-c/base.h" +#include "xmlrpc-c/server.h" + +#include "test.h" +#include "value.h" +#include "serialize.h" +#include "parse_xml.h" +#include "cgi.h" +#include "xml_data.h" +#include "client.h" +#include "server_abyss.h" +#include "method_registry.h" + +/*========================================================================= +** Test Harness +**========================================================================= +** This is a super light-weight test harness. It's vaguely inspired by +** Kent Beck's book on eXtreme Programming (XP)--the output is succinct, +** new tests can be coded quickly, and the whole thing runs in a few +** second's time. +** +** To run the tests, type './rpctest'. +** To check for memory leaks, install RedHat's 'memprof' utility, and +** type 'memprof rpctest'. +** +** If you add new tests to this file, please deallocate any data +** structures you use in the appropriate fashion. This allows us to test +** various destructor code for memory leaks. +*/ + +int total_tests = 0; +int total_failures = 0; + + +/*========================================================================= +** Test Data +**========================================================================= +** Some common test data which need to be allocated at a fixed address, +** or which are inconvenient to allocate inline. +*/ + +static char* test_string_1 = "foo"; +static char* test_string_2 = "bar"; +static int test_int_array_1[5] = {1, 2, 3, 4, 5}; +static int test_int_array_2[3] = {6, 7, 8}; +static int test_int_array_3[8] = {1, 2, 3, 4, 5, 6, 7, 8}; + +/*========================================================================= +** Test Suites +**========================================================================= +*/ + +static void test_env(void) +{ + xmlrpc_env env, env2; + char *s; + + /* Test xmlrpc_env_init. */ + xmlrpc_env_init(&env); + TEST(!env.fault_occurred); + TEST(env.fault_code == 0); + TEST(env.fault_string == NULL); + + /* Test xmlrpc_set_fault. */ + xmlrpc_env_set_fault(&env, 1, test_string_1); + TEST(env.fault_occurred); + TEST(env.fault_code == 1); + TEST(env.fault_string != test_string_1); + TEST(strcmp(env.fault_string, test_string_1) == 0); + + /* Change an existing fault. */ + xmlrpc_env_set_fault(&env, 2, test_string_2); + TEST(env.fault_occurred); + TEST(env.fault_code == 2); + TEST(strcmp(env.fault_string, test_string_2) == 0); + + /* Set a fault with a format string. */ + xmlrpc_env_set_fault_formatted(&env, 3, "a%s%d", "bar", 9); + TEST(env.fault_occurred); + TEST(env.fault_code == 3); + TEST(strcmp(env.fault_string, "abar9") == 0); + + /* Set a fault with an oversized string. */ + s = "12345678901234567890123456789012345678901234567890"; + xmlrpc_env_set_fault_formatted(&env, 4, "%s%s%s%s%s%s", s, s, s, s, s, s); + TEST(env.fault_occurred); + TEST(env.fault_code == 4); + TEST(strlen(env.fault_string) == 255); + + /* Test cleanup code (with help from memprof). */ + xmlrpc_env_clean(&env); + + /* Test cleanup code on in absence of xmlrpc_env_set_fault. */ + xmlrpc_env_init(&env2); + xmlrpc_env_clean(&env2); +} + +static void test_mem_block (void) +{ + xmlrpc_env env; + xmlrpc_mem_block* block; + + xmlrpc_mem_block* typed_heap_block; + xmlrpc_mem_block typed_auto_block; + void** typed_contents; + + xmlrpc_env_init(&env); + + /* Allocate a zero-size block. */ + block = xmlrpc_mem_block_new(&env, 0); + TEST_NO_FAULT(&env); + TEST(block != NULL); + TEST(xmlrpc_mem_block_size(block) == 0); + + /* Grow the block a little bit. */ + xmlrpc_mem_block_resize(&env, block, strlen(test_string_1) + 1); + TEST_NO_FAULT(&env); + TEST(xmlrpc_mem_block_size(block) == strlen(test_string_1) + 1); + + /* Insert a string into the block, and resize it by large amount. + ** We want to cause a reallocation and copy of the block contents. */ + strcpy(xmlrpc_mem_block_contents(block), test_string_1); + xmlrpc_mem_block_resize(&env, block, 10000); + TEST_NO_FAULT(&env); + TEST(xmlrpc_mem_block_size(block) == 10000); + TEST(strcmp(xmlrpc_mem_block_contents(block), test_string_1) == 0); + + /* Test cleanup code (with help from memprof). */ + xmlrpc_mem_block_free(block); + + /* Allocate a bigger block. */ + block = xmlrpc_mem_block_new(&env, 128); + TEST_NO_FAULT(&env); + TEST(block != NULL); + TEST(xmlrpc_mem_block_size(block) == 128); + + /* Test cleanup code (with help from memprof). */ + xmlrpc_mem_block_free(block); + + /* Allocate a "typed" memory block. */ + typed_heap_block = XMLRPC_TYPED_MEM_BLOCK_NEW(void*, &env, 20); + TEST_NO_FAULT(&env); + TEST(typed_heap_block != NULL); + TEST(XMLRPC_TYPED_MEM_BLOCK_SIZE(void*, typed_heap_block) == 20); + typed_contents = XMLRPC_TYPED_MEM_BLOCK_CONTENTS(void*, typed_heap_block); + TEST(typed_contents != NULL); + + /* Resize a typed memory block. */ + XMLRPC_TYPED_MEM_BLOCK_RESIZE(void*, &env, typed_heap_block, 100); + TEST_NO_FAULT(&env); + TEST(XMLRPC_TYPED_MEM_BLOCK_SIZE(void*, typed_heap_block) == 100); + + /* Test cleanup code (with help from memprof). */ + XMLRPC_TYPED_MEM_BLOCK_FREE(void*, typed_heap_block); + + /* Test _INIT and _CLEAN for stack-based memory blocks. */ + XMLRPC_TYPED_MEM_BLOCK_INIT(void*, &env, &typed_auto_block, 30); + TEST(XMLRPC_TYPED_MEM_BLOCK_SIZE(void*, &typed_auto_block) == 30); + XMLRPC_TYPED_MEM_BLOCK_CLEAN(void*, &typed_auto_block); + + /* Test xmlrpc_mem_block_append. */ + block = XMLRPC_TYPED_MEM_BLOCK_NEW(int, &env, 5); + TEST_NO_FAULT(&env); + memcpy(XMLRPC_TYPED_MEM_BLOCK_CONTENTS(int, block), + test_int_array_1, sizeof(test_int_array_1)); + XMLRPC_TYPED_MEM_BLOCK_APPEND(int, &env, block, test_int_array_2, 3); + TEST(XMLRPC_TYPED_MEM_BLOCK_SIZE(int, block) == 8); + TEST(memcmp(XMLRPC_TYPED_MEM_BLOCK_CONTENTS(int, block), + test_int_array_3, sizeof(test_int_array_3)) == 0); + XMLRPC_TYPED_MEM_BLOCK_FREE(int, block); + + xmlrpc_env_clean(&env); +} + +static char *(base64_triplets[]) = { + "", "", "\r\n", + "a", "YQ==", "YQ==\r\n", + "aa", "YWE=", "YWE=\r\n", + "aaa", "YWFh", "YWFh\r\n", + "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" + "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ", + "YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXpBQkNERUZHSElKS0xNTk9QUVJTVFVWV1hZWmFiY" + "2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6QUJDREVGR0hJSktMTU5PUFFSU1RVVldYWVo=", + "YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXpBQkNERUZHSElKS0xNTk9QUVJTVFVWV1hZWmFiY" + "2Rl\r\n" + "ZmdoaWprbG1ub3BxcnN0dXZ3eHl6QUJDREVGR0hJSktMTU5PUFFSU1RVVldYWVo=\r\n", + NULL}; + +static void +test_base64_conversion(void) { + xmlrpc_env env; + char ** triplet; + + xmlrpc_env_init(&env); + + for (triplet = base64_triplets; *triplet != NULL; triplet += 3) { + char * bin_data; + char * nocrlf_ascii_data; + char * ascii_data; + xmlrpc_mem_block * output; + + bin_data = *triplet; + nocrlf_ascii_data = *(triplet + 1); + ascii_data = *(triplet + 2); + + /* Test our encoding routine. */ + output = xmlrpc_base64_encode(&env, + (unsigned char*) bin_data, + strlen(bin_data)); + TEST_NO_FAULT(&env); + TEST(output != NULL); + TEST(xmlrpc_mem_block_size(output) == strlen(ascii_data)); + TEST(memcmp(xmlrpc_mem_block_contents(output), ascii_data, + strlen(ascii_data)) == 0); + xmlrpc_mem_block_free(output); + + /* Test our newline-free encoding routine. */ + output = + xmlrpc_base64_encode_without_newlines(&env, + (unsigned char*) bin_data, + strlen(bin_data)); + TEST_NO_FAULT(&env); + TEST(output != NULL); + TEST(xmlrpc_mem_block_size(output) == strlen(nocrlf_ascii_data)); + TEST(memcmp(xmlrpc_mem_block_contents(output), nocrlf_ascii_data, + strlen(nocrlf_ascii_data)) == 0); + xmlrpc_mem_block_free(output); + + /* Test our decoding routine. */ + output = xmlrpc_base64_decode(&env, ascii_data, strlen(ascii_data)); + TEST_NO_FAULT(&env); + TEST(output != NULL); + TEST(xmlrpc_mem_block_size(output) == strlen(bin_data)); + TEST(memcmp(xmlrpc_mem_block_contents(output), bin_data, + strlen(bin_data)) == 0); + xmlrpc_mem_block_free(output); + } + + /* Now for something broken... */ + { + xmlrpc_env env2; + xmlrpc_mem_block * output; + + xmlrpc_env_init(&env2); + output = xmlrpc_base64_decode(&env2, "====", 4); + TEST(output == NULL); + TEST_FAULT(&env2, XMLRPC_PARSE_ERROR); + xmlrpc_env_clean(&env2); + } + /* Now for something broken in a really sneaky way... */ + { + xmlrpc_env env2; + xmlrpc_mem_block * output; + xmlrpc_env_init(&env2); + output = xmlrpc_base64_decode(&env2, "a==", 4); + TEST(output == NULL); + TEST_FAULT(&env2, XMLRPC_PARSE_ERROR); + xmlrpc_env_clean(&env2); + } + xmlrpc_env_clean(&env); +} + + + +static void test_bounds_checks (void) +{ + xmlrpc_env env; + xmlrpc_value *array; + int i1, i2, i3, i4; + + /* Get an array to work with. */ + xmlrpc_env_init(&env); + array = xmlrpc_build_value(&env, "(iii)", 100, 200, 300); + TEST_NO_FAULT(&env); + xmlrpc_env_clean(&env); + + /* Test xmlrpc_decompose_value with too few values. */ + xmlrpc_env_init(&env); + xmlrpc_decompose_value(&env, array, "(iiii)", &i1, &i2, &i3, &i4); + TEST_FAULT(&env, XMLRPC_INDEX_ERROR); + xmlrpc_env_clean(&env); + + /* Test xmlrpc_decompose_value with too many values. */ + xmlrpc_env_init(&env); + xmlrpc_decompose_value(&env, array, "(ii)", &i1, &i2, &i3, &i4); + TEST_FAULT(&env, XMLRPC_INDEX_ERROR); + xmlrpc_env_clean(&env); + + /* Dispose of our array. */ + xmlrpc_DECREF(array); +} + + + +static void test_nesting_limit (void) +{ + xmlrpc_env env; + xmlrpc_value *val; + + xmlrpc_env_init(&env); + + /* Test with an adequate limit for a result value which is an + array which contains an element which is a struct, whose values + are simple: 3. + */ + xmlrpc_limit_set(XMLRPC_NESTING_LIMIT_ID, 3); + val = xmlrpc_parse_response(&env, + good_response_xml, strlen(good_response_xml)); + TEST_NO_FAULT(&env); + TEST(val != NULL); + xmlrpc_DECREF(val); + + /* Test with an inadequate limit. */ + xmlrpc_limit_set(XMLRPC_NESTING_LIMIT_ID, 2); + val = xmlrpc_parse_response(&env, + good_response_xml, strlen(good_response_xml)); + TEST_FAULT(&env, XMLRPC_PARSE_ERROR); /* BREAKME - Will change. */ + TEST(val == NULL); + + /* Reset the default limit. */ + xmlrpc_limit_set(XMLRPC_NESTING_LIMIT_ID, XMLRPC_NESTING_LIMIT_DEFAULT); + TEST(xmlrpc_limit_get(XMLRPC_NESTING_LIMIT_ID) + == XMLRPC_NESTING_LIMIT_DEFAULT); + + xmlrpc_env_clean(&env); +} + + + +static void +test_xml_size_limit(void) { + + xmlrpc_env env; + const char * methodName; + xmlrpc_value * paramsP; + + /* NOTE - This test suite only verifies the last-ditch size-checking + code. There should also be matching code in all server (and + preferably all client) modules as well. + */ + + /* Set our XML size limit to something ridiculous. */ + xmlrpc_limit_set(XMLRPC_XML_SIZE_LIMIT_ID, 6); + + /* Attempt to parse a call. */ + xmlrpc_env_init(&env); + xmlrpc_parse_call(&env, serialized_call, strlen(serialized_call), + &methodName, ¶msP); + TEST_FAULT(&env, XMLRPC_LIMIT_EXCEEDED_ERROR); + xmlrpc_env_clean(&env); + + { + xmlrpc_value * resultP; + int faultCode; + const char * faultString; + + /* Attempt to parse a response. */ + xmlrpc_env_init(&env); + xmlrpc_parse_response2(&env, + good_response_xml, strlen(good_response_xml), + &resultP, &faultCode, &faultString); + TEST_FAULT(&env, XMLRPC_LIMIT_EXCEEDED_ERROR); + xmlrpc_env_clean(&env); + } + /* Reset the default limit. */ + xmlrpc_limit_set(XMLRPC_XML_SIZE_LIMIT_ID, XMLRPC_XML_SIZE_LIMIT_DEFAULT); +} + + + +/*========================================================================= +** test_sample_files +**========================================================================= +** Read in a bunch of sample test files and make sure we get plausible +** results. +** +** We use these files to test strange-but-legal encodings, illegal-but- +** supported encodings, etc. +*/ + +#define TESTDATA_DIR "data" + +static char *good_requests[] = { + TESTDATA_DIR DIRECTORY_SEPARATOR "req_out_of_order.xml", + TESTDATA_DIR DIRECTORY_SEPARATOR "req_no_params.xml", + TESTDATA_DIR DIRECTORY_SEPARATOR "req_value_name.xml", + NULL +}; + +#define MAX_SAMPLE_FILE_LEN (16 * 1024) + +static char file_buff [MAX_SAMPLE_FILE_LEN]; + +static void +read_file (char *path, char **out_data, size_t *out_size) +{ + FILE *f; + size_t bytes_read; + + /* Open the file. */ + f = fopen(path, "r"); + if (f == NULL) { + /* Since this error is fairly likely to happen, give an + ** informative error message... */ + fflush(stdout); + fprintf(stderr, "Could not open file '%s'. errno=%d (%s)\n", + path, errno, strerror(errno)); + abort(); + } + + /* Read in one buffer full of data, and make sure that everything + ** fit. (We perform a lazy error/no-eof/zero-length-file test using + ** bytes_read.) */ + bytes_read = fread(file_buff, sizeof(char), MAX_SAMPLE_FILE_LEN, f); + TEST(0 < bytes_read && bytes_read < MAX_SAMPLE_FILE_LEN); + + /* Close the file and return our data. */ + fclose(f); + *out_data = file_buff; + *out_size = bytes_read; +} + +static void test_sample_files (void) +{ + xmlrpc_env env; + char **paths, *path; + char *data; + size_t data_len; + const char *method_name; + xmlrpc_value *params; + + xmlrpc_env_init(&env); + + /* Test our good requests. */ + for (paths = good_requests; *paths != NULL; paths++) { + path = *paths; + read_file(path, &data, &data_len); + xmlrpc_parse_call(&env, data, data_len, &method_name, ¶ms); + TEST_NO_FAULT(&env); + strfree(method_name); + xmlrpc_DECREF(params); + } + + xmlrpc_env_clean(&env); +} + + +/*========================================================================= +** test_utf8_coding +**========================================================================= +** We need to test our UTF-8 decoder thoroughly. Most of these test +** cases are taken from the UTF-8-test.txt file by Markus Kuhn +** : +** http://www.cl.cam.ac.uk/~mgk25/ucs/examples/UTF-8-test.txt +*/ + +#if HAVE_UNICODE_WCHAR + +typedef struct { + char *utf8; + wchar_t wcs[16]; +} utf8_and_wcs; + +static utf8_and_wcs good_utf8[] = { + + /* Greek 'kosme'. */ + {"\316\272\341\275\271\317\203\316\274\316\265", + {0x03BA, 0x1F79, 0x03C3, 0x03BC, 0x03B5, 0}}, + + /* First sequences of a given length. */ + /* '\000' is not a legal C string. */ + {"\302\200", {0x0080, 0}}, + {"\340\240\200", {0x0800, 0}}, + + /* Last sequences of a given length. */ + {"\177", {0x007F, 0}}, + {"\337\277", {0x07FF, 0}}, + /* 0xFFFF is not a legal Unicode character. */ + + /* Other boundry conditions. */ + {"\001", {0x0001, 0}}, + {"\355\237\277", {0xD7FF, 0}}, + {"\356\200\200", {0xE000, 0}}, + {"\357\277\275", {0xFFFD, 0}}, + + /* Other random test cases. */ + {"", {0}}, + {"abc", {0x0061, 0x0062, 0x0063, 0}}, + {"[\302\251]", {0x005B, 0x00A9, 0x005D, 0}}, + + {NULL, {0}} +}; + +static char *(bad_utf8[]) = { + + /* Continuation bytes. */ + "\200", "\277", + + /* Lonely start characters. */ + "\300", "\300x", "\300xx", + "\340", "\340x", "\340xx", "\340xxx", + + /* Last byte missing. */ + "\340\200", "\340\200x", "\340\200xx", + "\357\277", "\357\277x", "\357\277xx", + + /* Illegal bytes. */ + "\376", "\377", + + /* Overlong '/'. */ + "\300\257", "\340\200\257", + + /* Overlong ASCII NUL. */ + "\300\200", "\340\200\200", + + /* Maximum overlong sequences. */ + "\301\277", "\340\237\277", + + /* Illegal code positions. */ + "\357\277\276", /* U+FFFE */ + "\357\277\277", /* U+FFFF */ + + /* UTF-16 surrogates (unpaired and paired). */ + "\355\240\200", + "\355\277\277", + "\355\240\200\355\260\200", + "\355\257\277\355\277\277", + + /* Valid UCS-4 characters (we don't handle these yet). + ** On systems with UCS-4 or UTF-16 wchar_t values, we + ** may eventually handle these in some fashion. */ + "\360\220\200\200", + "\370\210\200\200\200", + "\374\204\200\200\200\200", + + NULL +}; +#endif /* HAVE_UNICODE_WCHAR */ + +/* This routine is missing on certain platforms. This implementation +** *appears* to be correct. */ +#if 0 +#ifndef HAVE_WCSNCMP +int wcsncmp(wchar_t *wcs1, wchar_t* wcs2, size_t len) +{ + size_t i; + /* XXX - 'unsigned long' should be 'uwchar_t'. */ + unsigned long c1, c2; + for (i=0; i < len; i++) { + c1 = wcs1[i]; + c2 = wcs2[i]; + /* This clever comparison borrowed from the GNU C Library. */ + if (c1 == 0 || c1 != c2) + return c1 - c2; + } + return 0; +} +#endif /* HAVE_WCSNCMP */ +#endif + +static void +test_utf8_coding(void) { + +#if HAVE_UNICODE_WCHAR + xmlrpc_env env, env2; + utf8_and_wcs *good_data; + char **bad_data; + char *utf8; + wchar_t *wcs; + xmlrpc_mem_block *output; + + xmlrpc_env_init(&env); + + /* Test each of our valid UTF-8 sequences. */ + for (good_data = good_utf8; good_data->utf8 != NULL; good_data++) { + utf8 = good_data->utf8; + wcs = good_data->wcs; + + /* Attempt to validate the UTF-8 string. */ + xmlrpc_validate_utf8(&env, utf8, strlen(utf8)); + TEST_NO_FAULT(&env); + + /* Attempt to decode the UTF-8 string. */ + output = xmlrpc_utf8_to_wcs(&env, utf8, strlen(utf8)); + TEST_NO_FAULT(&env); + TEST(output != NULL); + TEST(wcslen(wcs) == XMLRPC_TYPED_MEM_BLOCK_SIZE(wchar_t, output)); + TEST(0 == + wcsncmp(wcs, XMLRPC_TYPED_MEM_BLOCK_CONTENTS(wchar_t, output), + wcslen(wcs))); + xmlrpc_mem_block_free(output); + + /* Test the UTF-8 encoder, too. */ + output = xmlrpc_wcs_to_utf8(&env, wcs, wcslen(wcs)); + TEST_NO_FAULT(&env); + TEST(output != NULL); + TEST(strlen(utf8) == XMLRPC_TYPED_MEM_BLOCK_SIZE(char, output)); + TEST(0 == + strncmp(utf8, XMLRPC_TYPED_MEM_BLOCK_CONTENTS(char, output), + strlen(utf8))); + xmlrpc_mem_block_free(output); + } + + /* Test each of our illegal UTF-8 sequences. */ + for (bad_data = bad_utf8; *bad_data != NULL; bad_data++) { + utf8 = *bad_data; + + /* Attempt to validate the UTF-8 string. */ + xmlrpc_env_init(&env2); + xmlrpc_validate_utf8(&env2, utf8, strlen(utf8)); + TEST_FAULT(&env2, XMLRPC_INVALID_UTF8_ERROR); + /* printf("Fault: %s\n", env2.fault_string); --Hand-checked */ + xmlrpc_env_clean(&env2); + + /* Attempt to decode the UTF-8 string. */ + xmlrpc_env_init(&env2); + output = xmlrpc_utf8_to_wcs(&env2, utf8, strlen(utf8)); + TEST_FAULT(&env2, XMLRPC_INVALID_UTF8_ERROR); + TEST(output == NULL); + xmlrpc_env_clean(&env2); + } + xmlrpc_env_clean(&env); +#endif /* HAVE_UNICODE_WCHAR */ +} + + + +static void +test_server_cgi_maybe(void) { + +#ifndef WIN32 + + test_server_cgi(); + +#endif +} + + + +static void +test_client_maybe(void) { + +#ifndef WIN32 /* Must get Windows Curl transport working for this to work */ + + test_client(); + +#endif +} + + + +int +main(int argc, + char ** argv ATTR_UNUSED) { + + int retval; + + if (argc-1 > 0) { + fprintf(stderr, "There are no arguments."); + retval = 1; + } else { + /* Add your test suites here. */ + test_env(); + test_mem_block(); + test_base64_conversion(); + printf("\n"); + test_value(); + test_bounds_checks(); + printf("\n"); + test_serialize(); + test_parse_xml(); + test_method_registry(); + test_nesting_limit(); + test_xml_size_limit(); + test_sample_files(); + printf("\n"); + test_server_cgi_maybe(); + test_server_abyss(); + + test_utf8_coding(); + + printf("\n"); + + test_client_maybe(); + + /* Summarize our test run. */ + printf("\nRan %d tests, %d failed, %.1f%% passed\n", + total_tests, total_failures, + 100.0 - (100.0 * total_failures) / total_tests); + + /* Print the final result. */ + if (total_failures == 0) { + printf("OK\n"); + retval = 0; + } else { + retval = 1; + printf("FAILED\n"); + } + } + return retval; +} + + + + +/* Copyright (C) 2001 by First Peer, Inc. All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +** ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +** OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +** HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +** LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +** OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +** SUCH DAMAGE. */ diff --git a/src/test/test.h b/src/test/test.h new file mode 100644 index 0000000..4d5bdb8 --- /dev/null +++ b/src/test/test.h @@ -0,0 +1,75 @@ +#include +#include + +#include "xmlrpc-c/util.h" + +extern int total_tests; +extern int total_failures; + + +/* This is a good place to set a breakpoint. */ +static __inline__ void +test_failure(const char * const file, + unsigned int const line, + const char * const label, + const char * const statement) { + + ++total_failures; + printf("\n%s:%u: test failure: %s (%s)\n", file, line, label, statement); + abort(); +} + + + +#define TEST(statement) \ +do { \ + ++total_tests; \ + if ((statement)) { \ + printf("."); \ + } else { \ + test_failure(__FILE__, __LINE__, "expected", #statement); \ + } \ + } while (0) + +#define TEST_NO_FAULT(env) \ + do { \ + ++total_tests; \ + if (!(env)->fault_occurred) { \ + printf("."); \ + } else { \ + test_failure(__FILE__, __LINE__, "fault occurred", \ + (env)->fault_string); \ + } \ + } while (0) + +static inline void +test_fault(xmlrpc_env * const envP, + int const expectedCode, + const char * const fileName, + unsigned int const lineNumber) { + + ++total_tests; + if (!envP->fault_occurred) + test_failure(fileName, lineNumber, "no fault occurred", ""); + else if (envP->fault_code != expectedCode) + test_failure(fileName, lineNumber, "wrong fault occurred", + envP->fault_string); + else + printf("."); + + xmlrpc_env_clean(envP); + xmlrpc_env_init(envP); +} + + +#define TEST_FAULT(envP, code) \ + do { test_fault(envP, code, __FILE__, __LINE__); } while(0) + +; + +#define TEST_ERROR(reason) \ +do { \ + printf("Unable to test at %s/%u. %s", __FILE__, __LINE__, reason); \ + abort(); \ + } while (0) + diff --git a/src/test/value.c b/src/test/value.c new file mode 100644 index 0000000..8fe1885 --- /dev/null +++ b/src/test/value.c @@ -0,0 +1,1326 @@ +/* Copyright information is at the end of the file. */ + +#include +#include +#include +#include + +#include "casprintf.h" + +#include "xmlrpc_config.h" + +#include "xmlrpc-c/base.h" + +#include "test.h" +#include "value.h" + + + +/*========================================================================= +** Test Data +**========================================================================= +** Some common test data which need to be allocated at a fixed address, +** or which are inconvenient to allocate inline. +*/ +static char* test_string_1 = "foo"; + + + +static void +test_value_alloc_dealloc(void) { + + xmlrpc_value * v; + xmlrpc_env env; + + xmlrpc_env_init(&env); + + /* Test allocation and deallocation (w/memprof). */ + v = xmlrpc_build_value(&env, "i", (xmlrpc_int32) 5); + TEST_NO_FAULT(&env); + TEST(v != NULL); + xmlrpc_INCREF(v); + xmlrpc_DECREF(v); + xmlrpc_DECREF(v); + + xmlrpc_env_clean(&env); +} + + +static void +test_value_integer(void) { + + xmlrpc_value * v; + xmlrpc_env env; + xmlrpc_int32 i; + + xmlrpc_env_init(&env); + + v = xmlrpc_int_new(&env, (xmlrpc_int32) 25); + TEST_NO_FAULT(&env); + TEST(XMLRPC_TYPE_INT == xmlrpc_value_type(v)); + xmlrpc_read_int(&env, v, &i); + TEST_NO_FAULT(&env); + TEST(i == 25); + xmlrpc_DECREF(v); + + v = xmlrpc_build_value(&env, "i", (xmlrpc_int32) 10); + TEST_NO_FAULT(&env); + TEST(v != NULL); + TEST(XMLRPC_TYPE_INT == xmlrpc_value_type(v)); + xmlrpc_decompose_value(&env, v, "i", &i); + xmlrpc_DECREF(v); + TEST_NO_FAULT(&env); + TEST(i == 10); + + xmlrpc_env_clean(&env); +} + + + +static void +test_value_bool(void) { + + xmlrpc_value * v; + xmlrpc_env env; + xmlrpc_bool b; + + /* Test booleans. */ + + xmlrpc_env_init(&env); + + v = xmlrpc_bool_new(&env, (xmlrpc_bool) 1); + TEST_NO_FAULT(&env); + TEST(XMLRPC_TYPE_BOOL == xmlrpc_value_type(v)); + xmlrpc_read_bool(&env, v, &b); + TEST_NO_FAULT(&env); + TEST(b); + xmlrpc_DECREF(v); + + v = xmlrpc_build_value(&env, "b", (xmlrpc_bool) 0); + TEST_NO_FAULT(&env); + TEST(v != NULL); + TEST(XMLRPC_TYPE_BOOL == xmlrpc_value_type(v)); + xmlrpc_decompose_value(&env, v, "b", &b); + xmlrpc_DECREF(v); + TEST_NO_FAULT(&env); + TEST(!b); + + xmlrpc_env_clean(&env); +} + + + +static void +test_value_double(void) { + + xmlrpc_value * v; + xmlrpc_env env; + double d; + + xmlrpc_env_init(&env); + + v = xmlrpc_double_new(&env, -3.25); + TEST_NO_FAULT(&env); + TEST(XMLRPC_TYPE_DOUBLE == xmlrpc_value_type(v)); + xmlrpc_read_double(&env, v, &d); + TEST_NO_FAULT(&env); + TEST(d == -3.25); + xmlrpc_DECREF(v); + + v = xmlrpc_build_value(&env, "d", 1.0); + TEST_NO_FAULT(&env); + TEST(v != NULL); + TEST(XMLRPC_TYPE_DOUBLE == xmlrpc_value_type(v)); + xmlrpc_decompose_value(&env, v, "d", &d); + xmlrpc_DECREF(v); + TEST_NO_FAULT(&env); + TEST(d == 1.0); + + xmlrpc_env_clean(&env); +} + + + +static void +test_value_datetime(void) { + + const char * datestring = "19980717T14:08:55"; + time_t const datetime = 900684535; + + xmlrpc_value * v; + xmlrpc_env env; + const char * ds; + time_t dt; + + xmlrpc_env_init(&env); + + v = xmlrpc_datetime_new_str(&env, datestring); + TEST_NO_FAULT(&env); + TEST(XMLRPC_TYPE_DATETIME == xmlrpc_value_type(v)); + + xmlrpc_read_datetime_str(&env, v, &ds); + TEST_NO_FAULT(&env); + TEST(strcmp(ds, datestring) == 0); + strfree(ds); + + xmlrpc_read_datetime_sec(&env, v, &dt); + TEST_NO_FAULT(&env); + TEST(dt == datetime); + + xmlrpc_DECREF(v); + + v = xmlrpc_datetime_new_sec(&env, datetime); + TEST_NO_FAULT(&env); + TEST(XMLRPC_TYPE_DATETIME == xmlrpc_value_type(v)); + + xmlrpc_read_datetime_str(&env, v, &ds); + TEST_NO_FAULT(&env); + TEST(strcmp(ds, datestring) == 0); + strfree(ds); + + xmlrpc_read_datetime_sec(&env, v, &dt); + TEST_NO_FAULT(&env); + TEST(dt == datetime); + + xmlrpc_DECREF(v); + + v = xmlrpc_build_value(&env, "8", datestring); + TEST_NO_FAULT(&env); + TEST(v != NULL); + TEST(XMLRPC_TYPE_DATETIME == xmlrpc_value_type(v)); + xmlrpc_decompose_value(&env, v, "8", &ds); + xmlrpc_DECREF(v); + TEST_NO_FAULT(&env); + TEST(strcmp(ds, datestring) == 0); + strfree(ds); + + xmlrpc_env_clean(&env); +} + + + +static void +test_value_string_no_null(void) { + + xmlrpc_value * v; + xmlrpc_env env; + const char * str; + size_t len; + + /* Test strings (without '\0' bytes). */ + xmlrpc_env_init(&env); + + v = xmlrpc_string_new(&env, test_string_1); + TEST_NO_FAULT(&env); + TEST(XMLRPC_TYPE_STRING == xmlrpc_value_type(v)); + xmlrpc_read_string(&env, v, &str); + TEST_NO_FAULT(&env); + TEST(strcmp(str, test_string_1) == 0); + xmlrpc_DECREF(v); + strfree(str); + + v = xmlrpc_build_value(&env, "s", test_string_1); + + TEST_NO_FAULT(&env); + TEST(v != NULL); + TEST(XMLRPC_TYPE_STRING == xmlrpc_value_type(v)); + + xmlrpc_decompose_value(&env, v, "s", &str); + TEST_NO_FAULT(&env); + TEST(strcmp(str, test_string_1) == 0); + strfree(str); + + xmlrpc_decompose_value(&env, v, "s#", &str, &len); + TEST_NO_FAULT(&env); + TEST(memcmp(str, test_string_1, strlen(test_string_1)) == 0); + TEST(strlen(str) == strlen(test_string_1)); + strfree(str); + + xmlrpc_DECREF(v); + + xmlrpc_env_clean(&env); +} + + + +static void +test_value_string_null(void) { + + xmlrpc_value * v; + xmlrpc_env env; + xmlrpc_env env2; + const char * str; + size_t len; + + /* Test a string with a '\0' byte. */ + + xmlrpc_env_init(&env); + + v = xmlrpc_string_new_lp(&env, 7, "foo\0bar"); + TEST_NO_FAULT(&env); + TEST(XMLRPC_TYPE_STRING == xmlrpc_value_type(v)); + xmlrpc_read_string_lp(&env, v, &len, &str); + TEST_NO_FAULT(&env); + TEST(len == 7); + TEST(memcmp(str, "foo\0bar", 7) == 0); + xmlrpc_DECREF(v); + strfree(str); + + v = xmlrpc_build_value(&env, "s#", "foo\0bar", (size_t) 7); + TEST_NO_FAULT(&env); + TEST(v != NULL); + TEST(XMLRPC_TYPE_STRING == xmlrpc_value_type(v)); + + xmlrpc_decompose_value(&env, v, "s#", &str, &len); + TEST_NO_FAULT(&env); + TEST(memcmp(str, "foo\0bar", 7) == 0); + TEST(len == 7); + strfree(str); + + /* Test for type error when decoding a string with a zero byte to a + ** regular C string. */ + xmlrpc_env_init(&env2); + xmlrpc_decompose_value(&env2, v, "s", &str); + TEST_FAULT(&env2, XMLRPC_TYPE_ERROR); + xmlrpc_env_clean(&env2); + xmlrpc_DECREF(v); + + xmlrpc_env_clean(&env); +} + + + +#if HAVE_UNICODE_WCHAR + +/* Here is a 3-character, NUL-terminated string, once in UTF-8 chars, + and once in UTF-16 wchar_ts. Note that 2 of the UTF-16 characters + translate directly to UTF-8 bytes because only the lower 7 bits of + each is nonzero, but the middle UTF-16 character translates to two + UTF-8 bytes. +*/ +static char utf8_data[] = "[\xC2\xA9]"; +static wchar_t wcs_data[] = {'[', 0x00A9, ']', 0x0000}; + +static void +test_value_string_wide_build(void) { + + xmlrpc_env env; + xmlrpc_value * valueP; + const wchar_t * wcs; + size_t len; + + xmlrpc_env_init(&env); + + /* Build with build_value w# */ + valueP = xmlrpc_build_value(&env, "w#", wcs_data, 3); + TEST_NO_FAULT(&env); + TEST(valueP != NULL); + + /* Verify it */ + xmlrpc_read_string_w_lp(&env, valueP, &len, &wcs); + TEST_NO_FAULT(&env); + TEST(wcs != NULL); + TEST(len == 3); + TEST(wcs[len] == '\0'); + TEST(0 == wcsncmp(wcs, wcs_data, len)); + free((void*)wcs); + + xmlrpc_DECREF(valueP); + + /* Build with build_value w */ + valueP = xmlrpc_build_value(&env, "w", wcs_data); + TEST_NO_FAULT(&env); + TEST(valueP != NULL); + + /* Verify it */ + xmlrpc_read_string_w_lp(&env, valueP, &len, &wcs); + TEST_NO_FAULT(&env); + TEST(wcs != NULL); + TEST(len == 3); + TEST(wcs[len] == '\0'); + TEST(0 == wcsncmp(wcs, wcs_data, len)); + free((void*)wcs); + + xmlrpc_DECREF(valueP); +} +#endif /* HAVE_UNICODE_WCHAR */ + + +static void +test_value_string_wide(void) { + +#if HAVE_UNICODE_WCHAR + xmlrpc_env env; + xmlrpc_value * valueP; + const wchar_t * wcs; + size_t len; + + xmlrpc_env_init(&env); + + /* Build a string from wchar_t data. */ + valueP = xmlrpc_string_w_new_lp(&env, 3, wcs_data); + TEST_NO_FAULT(&env); + TEST(valueP != NULL); + + /* Extract it as a wchar_t string. */ + xmlrpc_read_string_w_lp(&env, valueP, &len, &wcs); + TEST_NO_FAULT(&env); + TEST(wcs != NULL); + TEST(len == 3); + TEST(wcs[len] == '\0'); + TEST(0 == wcsncmp(wcs, wcs_data, len)); + free((void*)wcs); + + xmlrpc_read_string_w(&env, valueP, &wcs); + TEST_NO_FAULT(&env); + TEST(wcs != NULL); + TEST(wcs[3] == '\0'); + TEST(0 == wcsncmp(wcs, wcs_data, 3)); + free((void*)wcs); + + xmlrpc_decompose_value(&env, valueP, "w#", &wcs, &len); + TEST_NO_FAULT(&env); + TEST(wcs != NULL); + TEST(len == 3); + TEST(wcs[len] == '\0'); + TEST(0 == wcsncmp(wcs, wcs_data, len)); + free((void*)wcs); + + { + /* Extract it as a UTF-8 string. */ + const char * str; + size_t len; + + xmlrpc_read_string_lp(&env, valueP, &len, &str); + TEST_NO_FAULT(&env); + TEST(str != NULL); + TEST(len == 4); + TEST(str[len] == '\0'); + TEST(0 == strncmp(str, utf8_data, len)); + free((void*)str); + } + + xmlrpc_DECREF(valueP); + + /* Build from null-terminated wchar_t string */ + valueP = xmlrpc_string_w_new(&env, wcs_data); + TEST_NO_FAULT(&env); + TEST(valueP != NULL); + + /* Verify it */ + xmlrpc_read_string_w_lp(&env, valueP, &len, &wcs); + TEST_NO_FAULT(&env); + TEST(wcs != NULL); + TEST(len == 3); + TEST(wcs[len] == '\0'); + TEST(0 == wcsncmp(wcs, wcs_data, len)); + free((void*)wcs); + + xmlrpc_DECREF(valueP); + + test_value_string_wide_build(); + + /* Build a string from UTF-8 data. */ + valueP = xmlrpc_string_new(&env, utf8_data); + TEST_NO_FAULT(&env); + TEST(valueP != NULL); + + /* Extract it as a wchar_t string. */ + xmlrpc_read_string_w_lp(&env, valueP, &len, &wcs); + TEST_NO_FAULT(&env); + TEST(wcs != NULL); + TEST(len == 3); + TEST(wcs[len] == 0x0000); + TEST(0 == wcsncmp(wcs, wcs_data, len)); + free((void*)wcs); + xmlrpc_DECREF(valueP); + + /* Test with embedded NUL. We use a length of 4 so that the terminating + NUL actually becomes part of the string. + */ + valueP = xmlrpc_string_w_new_lp(&env, 4, wcs_data); + TEST_NO_FAULT(&env); + TEST(valueP != NULL); + + /* Extract it as a wchar_t string. */ + xmlrpc_read_string_w_lp(&env, valueP, &len, &wcs); + TEST_NO_FAULT(&env); + TEST(wcs != NULL); + TEST(len == 4); + TEST(wcs[len] == '\0'); + TEST(0 == wcsncmp(wcs, wcs_data, len)); + free((void*)wcs); + + xmlrpc_read_string_w(&env, valueP, &wcs); + TEST_FAULT(&env, XMLRPC_TYPE_ERROR); + + xmlrpc_DECREF(valueP); +#endif /* HAVE_UNICODE_WCHAR */ +} + + + +static void +test_value_base64(void) { + + /* Test data. */ + + unsigned char const data1[5] = {'a', '\0', 'b', '\n', 'c'}; + unsigned char const data2[3] = {'a', '\0', 'b'}; + + xmlrpc_value * v; + xmlrpc_env env; + const unsigned char * data; + size_t len; + + xmlrpc_env_init(&env); + + v = xmlrpc_base64_new(&env, sizeof(data1), data1); + TEST_NO_FAULT(&env); + TEST(XMLRPC_TYPE_BASE64 == xmlrpc_value_type(v)); + xmlrpc_read_base64(&env, v, &len, &data); + TEST_NO_FAULT(&env); + TEST(memcmp(data, data1, sizeof(data1)) == 0); + TEST(len == sizeof(data1)); + xmlrpc_DECREF(v); + free((void*)data); + + v = xmlrpc_build_value(&env, "6", data2, sizeof(data2)); + TEST_NO_FAULT(&env); + TEST(XMLRPC_TYPE_BASE64 == xmlrpc_value_type(v)); + xmlrpc_decompose_value(&env, v, "6", &data, &len); + xmlrpc_DECREF(v); + TEST_NO_FAULT(&env); + TEST(len == sizeof(data2)); + TEST(memcmp(data, data1, sizeof(data2)) == 0); + strfree(data); + + xmlrpc_env_clean(&env); +} + + + +static void +test_value_value(void) { + + xmlrpc_value *v, *v2, *v3; + xmlrpc_env env; + + /* Test 'V' with building and parsing. */ + + xmlrpc_env_init(&env); + + v2 = xmlrpc_int_new(&env, (xmlrpc_int32) 5); + TEST_NO_FAULT(&env); + v = xmlrpc_build_value(&env, "V", v2); + TEST_NO_FAULT(&env); + TEST(v == v2); + xmlrpc_decompose_value(&env, v2, "V", &v3); + xmlrpc_DECREF(v); + TEST_NO_FAULT(&env); + TEST(v2 == v3); + xmlrpc_DECREF(v3); + xmlrpc_DECREF(v2); + + xmlrpc_env_clean(&env); +} + + + +static void +test_value_array(void) { + + xmlrpc_value *v; + xmlrpc_env env; + size_t len; + + /* Basic array-building test. */ + + xmlrpc_env_init(&env); + + v = xmlrpc_array_new(&env); + TEST_NO_FAULT(&env); + TEST(XMLRPC_TYPE_ARRAY == xmlrpc_value_type(v)); + len = xmlrpc_array_size(&env, v); + TEST_NO_FAULT(&env); + TEST(len == 0); + xmlrpc_DECREF(v); + + v = xmlrpc_build_value(&env, "()"); + TEST_NO_FAULT(&env); + TEST(XMLRPC_TYPE_ARRAY == xmlrpc_value_type(v)); + len = xmlrpc_array_size(&env, v); + TEST_NO_FAULT(&env); + TEST(len == 0); + xmlrpc_DECREF(v); + + xmlrpc_env_clean(&env); +} + + + +static void +test_value_AS(void) { + + xmlrpc_value *v; + xmlrpc_value *v2; + xmlrpc_value *v3; + xmlrpc_env env; + size_t len; + + /* Test parsing of 'A' and 'S'. */ + + xmlrpc_env_init(&env); + + v = xmlrpc_build_value(&env, "((){})"); + TEST_NO_FAULT(&env); + xmlrpc_decompose_value(&env, v, "(AS)", &v2, &v3); + xmlrpc_DECREF(v); + TEST_NO_FAULT(&env); + TEST(XMLRPC_TYPE_ARRAY == xmlrpc_value_type(v2)); + TEST(XMLRPC_TYPE_STRUCT == xmlrpc_value_type(v3)); + len = xmlrpc_array_size(&env, v2); + TEST_NO_FAULT(&env); + TEST(len == 0); + len = xmlrpc_struct_size(&env, v3); + TEST_NO_FAULT(&env); + TEST(len == 0); + xmlrpc_DECREF(v2); + xmlrpc_DECREF(v3); + + xmlrpc_env_clean(&env); +} + + + +static void +test_value_AS_typecheck(void) { + + xmlrpc_env env; + xmlrpc_env env2; + xmlrpc_value *v; + xmlrpc_value *v2; + + /* Test typechecks for 'A' and 'S'. */ + + xmlrpc_env_init(&env); + + v = xmlrpc_build_value(&env, "s", "foo"); + TEST_NO_FAULT(&env); + xmlrpc_env_init(&env2); + xmlrpc_decompose_value(&env2, v, "A", &v2); + TEST_FAULT(&env2, XMLRPC_TYPE_ERROR); + xmlrpc_env_clean(&env2); + + xmlrpc_env_init(&env2); + xmlrpc_decompose_value(&env2, v, "S", &v2); + TEST_FAULT(&env2, XMLRPC_TYPE_ERROR); + xmlrpc_env_clean(&env2); + xmlrpc_DECREF(v); + xmlrpc_env_clean(&env); +} + + + +static void +test_value_array2(void) { + + xmlrpc_value * arrayP; + xmlrpc_env env; + xmlrpc_int32 i, i1, i2, i3, i4; + xmlrpc_value * itemP; + xmlrpc_value * subarrayP; + size_t len; + + /* A more complex array. */ + + xmlrpc_env_init(&env); + + arrayP = xmlrpc_build_value(&env, "(i(ii)i)", + (xmlrpc_int32) 10, (xmlrpc_int32) 20, + (xmlrpc_int32) 30, (xmlrpc_int32) 40); + TEST_NO_FAULT(&env); + TEST(XMLRPC_TYPE_ARRAY == xmlrpc_value_type(arrayP)); + + len = xmlrpc_array_size(&env, arrayP); + TEST_NO_FAULT(&env); + TEST(len == 3); + + xmlrpc_array_read_item(&env, arrayP, 1, &subarrayP); + TEST_NO_FAULT(&env); + + len = xmlrpc_array_size(&env, subarrayP); + TEST_NO_FAULT(&env); + TEST(len == 2); + + xmlrpc_array_read_item(&env, subarrayP, 0, &itemP); + TEST_NO_FAULT(&env); + xmlrpc_decompose_value(&env, itemP, "i", &i); + xmlrpc_DECREF(itemP); + TEST_NO_FAULT(&env); + TEST(i == 20); + + xmlrpc_DECREF(subarrayP); + + itemP = xmlrpc_array_get_item(&env, arrayP, 0); + TEST_NO_FAULT(&env); + xmlrpc_decompose_value(&env, itemP, "i", &i); + TEST_NO_FAULT(&env); + TEST(i == 10); + + xmlrpc_decompose_value(&env, arrayP, "(i(ii)i)", &i1, &i2, &i3, &i4); + TEST_NO_FAULT(&env); + TEST(i1 == 10 && i2 == 20 && i3 == 30 && i4 == 40); + + xmlrpc_decompose_value(&env, arrayP, "(i(i*)i)", &i1, &i2, &i3); + TEST_NO_FAULT(&env); + TEST(i1 == 10 && i2 == 20 && i3 == 40); + + xmlrpc_decompose_value(&env, arrayP, "(i(ii*)i)", &i1, &i2, &i3, &i4); + TEST_NO_FAULT(&env); + + + /* Test bounds check on xmlrpc_array_get_item. */ + xmlrpc_array_read_item(&env, arrayP, 3, &itemP); + TEST_FAULT(&env, XMLRPC_INDEX_ERROR); + xmlrpc_env_clean(&env); + xmlrpc_env_init(&env); + + xmlrpc_array_get_item(&env, arrayP, 3); + TEST_FAULT(&env, XMLRPC_INDEX_ERROR); + xmlrpc_env_clean(&env); + xmlrpc_env_init(&env); + + xmlrpc_array_get_item(&env, arrayP, -1); + TEST_FAULT(&env, XMLRPC_INDEX_ERROR); + xmlrpc_env_clean(&env); + xmlrpc_env_init(&env); + + xmlrpc_DECREF(arrayP); + + xmlrpc_env_clean(&env); +} + + + +static void +test_value_array_nil(void) { + + xmlrpc_value * arrayP; + xmlrpc_env env; + xmlrpc_int32 i1, i2; + xmlrpc_value * itemP; + size_t len; + + xmlrpc_env_init(&env); + + arrayP = xmlrpc_build_value(&env, "(nini)", + (xmlrpc_int32) 10, (xmlrpc_int32) 20); + TEST_NO_FAULT(&env); + TEST(XMLRPC_TYPE_ARRAY == xmlrpc_value_type(arrayP)); + + len = xmlrpc_array_size(&env, arrayP); + TEST_NO_FAULT(&env); + TEST(len == 4); + + itemP = xmlrpc_array_get_item(&env, arrayP, 0); + TEST_NO_FAULT(&env); + xmlrpc_decompose_value(&env, itemP, "n"); + TEST_NO_FAULT(&env); + + itemP = xmlrpc_array_get_item(&env, arrayP, 1); + TEST_NO_FAULT(&env); + { + int i; + xmlrpc_decompose_value(&env, itemP, "i", &i); + TEST_NO_FAULT(&env); + TEST(i == 10); + } + xmlrpc_decompose_value(&env, arrayP, "(nini)", &i1, &i2); + TEST_NO_FAULT(&env); + TEST(i1 == 10 && i2 == 20); + + /* Test bounds check on xmlrpc_array_get_item. */ + xmlrpc_array_read_item(&env, arrayP, 4, &itemP); + TEST_FAULT(&env, XMLRPC_INDEX_ERROR); + xmlrpc_env_clean(&env); + xmlrpc_env_init(&env); + + xmlrpc_array_get_item(&env, arrayP, 4); + TEST_FAULT(&env, XMLRPC_INDEX_ERROR); + xmlrpc_env_clean(&env); + xmlrpc_env_init(&env); + + xmlrpc_DECREF(arrayP); + + xmlrpc_env_clean(&env); +} + + + +static void +test_value_type_mismatch(void) { + + xmlrpc_value * v; + xmlrpc_env env; + xmlrpc_env env2; + char * str; + + /* Test for one, simple kind of type mismatch error. We assume that + ** if one of these typechecks works, the rest work fine. */ + + xmlrpc_env_init(&env); + + v = xmlrpc_build_value(&env, "i", (xmlrpc_int32) 5); + TEST_NO_FAULT(&env); + xmlrpc_env_init(&env2); + xmlrpc_decompose_value(&env2, v, "s", &str); + xmlrpc_DECREF(v); + TEST_FAULT(&env2, XMLRPC_TYPE_ERROR); + xmlrpc_env_clean(&env2); + + xmlrpc_env_clean(&env); +} + + + +static void +test_value_cptr(void) { + + xmlrpc_value * v; + xmlrpc_env env; + void * ptr; + + /* Test C pointer storage using 'p'. + We don't have cleanup functions (yet). + */ + + xmlrpc_env_init(&env); + + v = xmlrpc_build_value(&env, "p", (void*) 0x00000017); + TEST_NO_FAULT(&env); + TEST(XMLRPC_TYPE_C_PTR == xmlrpc_value_type(v)); + xmlrpc_decompose_value(&env, v, "p", &ptr); + xmlrpc_DECREF(v); + TEST_NO_FAULT(&env); + TEST(ptr == (void*) 0x00000017); + + xmlrpc_env_clean(&env); +} + + + +static void +test_value_nil(void) { + + xmlrpc_value * v; + xmlrpc_env env; + + xmlrpc_env_init(&env); + + v = xmlrpc_nil_new(&env); + TEST_NO_FAULT(&env); + TEST(XMLRPC_TYPE_NIL == xmlrpc_value_type(v)); + xmlrpc_DECREF(v); + + v = xmlrpc_build_value(&env, "n"); + TEST_NO_FAULT(&env); + TEST(XMLRPC_TYPE_NIL == xmlrpc_value_type(v)); + xmlrpc_decompose_value(&env, v, "n"); + xmlrpc_DECREF(v); + TEST_NO_FAULT(&env); + + xmlrpc_env_clean(&env); +} + + + +static void +test_value_invalid_type(void) { + + xmlrpc_value * v; + xmlrpc_env env; + + /* Test invalid type specifier in format string */ + + xmlrpc_env_init(&env); + + v = xmlrpc_build_value(&env, "Q"); + TEST_FAULT(&env, XMLRPC_INTERNAL_ERROR); + + xmlrpc_env_clean(&env); +} + + + +static void +test_value_missing_array_delim(void) { + + xmlrpc_value * v; + xmlrpc_env env; + + /* Test missing close parenthesis on array */ + + xmlrpc_env_init(&env); + v = xmlrpc_build_value(&env, "("); + TEST_FAULT(&env, XMLRPC_INTERNAL_ERROR); + xmlrpc_env_clean(&env); + + xmlrpc_env_init(&env); + v = xmlrpc_build_value(&env, "(i"); + TEST_FAULT(&env, XMLRPC_INTERNAL_ERROR); + xmlrpc_env_clean(&env); +} + + + +static void +test_value_missing_struct_delim(void) { + + xmlrpc_value * v; + xmlrpc_env env; + + /* Test missing closing brace on struct */ + + xmlrpc_env_init(&env); + v = xmlrpc_build_value(&env, "{"); + TEST_FAULT(&env, XMLRPC_INTERNAL_ERROR); + xmlrpc_env_clean(&env); + + xmlrpc_env_init(&env); + v = xmlrpc_build_value(&env, "{s:i", "key1", 7); + TEST_FAULT(&env, XMLRPC_INTERNAL_ERROR); + xmlrpc_env_clean(&env); + + xmlrpc_env_init(&env); + v = xmlrpc_build_value(&env, "{s:i,s:i", "key1", 9, "key2", -4); + TEST_FAULT(&env, XMLRPC_INTERNAL_ERROR); + xmlrpc_env_clean(&env); +} + + + +static void +test_value_invalid_struct(void) { + + xmlrpc_value * v; + xmlrpc_env env; + + /* Note that even though the format strings are invalid, we have + to supply the variable arguments that xmlrpc_build_value() will + be looking for as it tries to parse it. Otherwise, we get wild + memory references and consequent Valgrind flags. + */ + + xmlrpc_env_init(&env); + v = xmlrpc_build_value(&env, "{s:ii", "key1", 9, 9); + TEST_FAULT(&env, XMLRPC_INTERNAL_ERROR); + xmlrpc_env_clean(&env); + + xmlrpc_env_init(&env); + v = xmlrpc_build_value(&env, "{si:", "key1", 9); + TEST_FAULT(&env, XMLRPC_INTERNAL_ERROR); + xmlrpc_env_clean(&env); + + xmlrpc_env_init(&env); + v = xmlrpc_build_value(&env, "{s", "key1"); + TEST_FAULT(&env, XMLRPC_INTERNAL_ERROR); + xmlrpc_env_clean(&env); +} + + + +static void +test_value_parse_value(void) { + + xmlrpc_env env; + xmlrpc_value * valueP; + const char * datestring = "19980717T14:08:55"; + + xmlrpc_env_init(&env); + + valueP = xmlrpc_build_value(&env, "(idb8ss#6(i){s:i}np(i))", + 7, 3.14, (xmlrpc_bool)1, datestring, + "hello world", "a\0b", 3, + "base64 data", strlen("base64 data"), + 15, "member9", 9, &valueP, -5); + + TEST_NO_FAULT(&env); + + { + xmlrpc_int32 i; + xmlrpc_double d; + xmlrpc_bool b; + const char * dt_str; + const char * s1; + const char * s2; + size_t s2_len; + const unsigned char * b64; + size_t b64_len; + xmlrpc_value * arrayP; + xmlrpc_value * structP; + void * cptr; + xmlrpc_value * subvalP; + + xmlrpc_parse_value(&env, valueP, "(idb8ss#6ASnpV)", + &i, &d, &b, &dt_str, &s1, &s2, &s2_len, + &b64, &b64_len, + &arrayP, &structP, &cptr, &subvalP); + + TEST_NO_FAULT(&env); + + TEST(i == 7); + TEST(d == 3.14); + TEST(b == (xmlrpc_bool)1); + TEST(strcmp(dt_str, datestring) == 0); + TEST(strcmp(s1, "hello world") == 0); + TEST(s2_len == 3); + TEST(memcmp(s2, "a\0b", 3) == 0); + TEST(b64_len == strlen("base64 data")); + TEST(memcmp(b64, "base64 data", b64_len) == 0); + TEST(XMLRPC_TYPE_ARRAY == xmlrpc_value_type(arrayP)); + TEST(XMLRPC_TYPE_STRUCT == xmlrpc_value_type(structP)); + TEST(cptr == &valueP); + TEST(XMLRPC_TYPE_ARRAY == xmlrpc_value_type(subvalP)); + + xmlrpc_DECREF(valueP); + } + xmlrpc_env_clean(&env); +} + + + +static void +test_struct_get_element(xmlrpc_value * const structP, + xmlrpc_value * const i1, + xmlrpc_value * const i2, + const char * const weirdKey, + unsigned int const weirdKeyLen) { + + xmlrpc_env env; + xmlrpc_value * valueP; + xmlrpc_value * aasStringP; + xmlrpc_value * bogusKeyStringP; + + xmlrpc_env_init(&env); + + /* build test tools */ + + aasStringP = xmlrpc_build_value(&env, "s", "aas"); + TEST_NO_FAULT(&env); + + bogusKeyStringP = xmlrpc_build_value(&env, "s", "doesn't_exist"); + TEST_NO_FAULT(&env); + + /* "find" interface */ + + xmlrpc_struct_find_value(&env, structP, "aas", &valueP); + TEST_NO_FAULT(&env); + TEST(valueP == i1); + xmlrpc_DECREF(valueP); + + xmlrpc_struct_find_value(&env, structP, "doesn't_exist", &valueP); + TEST_NO_FAULT(&env); + TEST(valueP == NULL); + + xmlrpc_struct_find_value_v(&env, structP, aasStringP, &valueP); + TEST_NO_FAULT(&env); + TEST(valueP == i1); + xmlrpc_DECREF(valueP); + + xmlrpc_struct_find_value_v(&env, structP, bogusKeyStringP, &valueP); + TEST_NO_FAULT(&env); + TEST(valueP == NULL); + + xmlrpc_struct_find_value(&env, i1, "aas", &valueP); + TEST_FAULT(&env, XMLRPC_TYPE_ERROR); + + /* "read" interface */ + + xmlrpc_struct_read_value(&env, structP, "aas", &valueP); + TEST_NO_FAULT(&env); + TEST(valueP == i1); + xmlrpc_DECREF(valueP); + + xmlrpc_struct_read_value(&env, structP, "doesn't_exist", &valueP); + TEST_FAULT(&env, XMLRPC_INDEX_ERROR); + + xmlrpc_struct_read_value_v(&env, structP, aasStringP, &valueP); + TEST_NO_FAULT(&env); + TEST(valueP == i1); + xmlrpc_DECREF(valueP); + + xmlrpc_struct_read_value_v(&env, structP, bogusKeyStringP, &valueP); + TEST_FAULT(&env, XMLRPC_INDEX_ERROR); + + xmlrpc_struct_read_value(&env, i1, "aas", &valueP); + TEST_FAULT(&env, XMLRPC_TYPE_ERROR); + + /* obsolete "get" interface. Note that it does not update the + reference count of the xmlrpc_value it returns. + */ + + valueP = xmlrpc_struct_get_value(&env, structP, "aas"); + TEST_NO_FAULT(&env); + TEST(valueP == i1); + + valueP = xmlrpc_struct_get_value(&env, structP, "doesn't_exist"); + TEST_FAULT(&env, XMLRPC_INDEX_ERROR); + + valueP = xmlrpc_struct_get_value(&env, i1, "foo"); + TEST_FAULT(&env, XMLRPC_TYPE_ERROR); + + valueP = xmlrpc_struct_get_value_n(&env, structP, weirdKey, weirdKeyLen); + TEST_NO_FAULT(&env); + TEST(valueP == i2); + + /* Clean up */ + + xmlrpc_DECREF(aasStringP); + xmlrpc_DECREF(bogusKeyStringP); + + xmlrpc_env_clean(&env); +} + + + +static void +testStructReadout(xmlrpc_value * const structP, + size_t const expectedSize) { + + xmlrpc_env env; + xmlrpc_value * keyP; + xmlrpc_value * valueP; + + unsigned int index; + + xmlrpc_env_init(&env); + + for (index = 0; index < expectedSize; ++index) { + xmlrpc_struct_read_member(&env, structP, index, &keyP, &valueP); + TEST_NO_FAULT(&env); + xmlrpc_DECREF(keyP); + xmlrpc_DECREF(valueP); + } + + xmlrpc_struct_read_member(&env, structP, expectedSize, &keyP, &valueP); + TEST_FAULT(&env, XMLRPC_INDEX_ERROR); + xmlrpc_env_clean(&env); + xmlrpc_env_init(&env); + + for (index = 0; index < expectedSize; ++index) { + xmlrpc_struct_get_key_and_value(&env, structP, index, &keyP, &valueP); + TEST_NO_FAULT(&env); + } + xmlrpc_env_clean(&env); +} + + + +static void +test_struct (void) { + + xmlrpc_env env; + xmlrpc_value *s, *i, *i1, *i2, *i3, *key, *value; + size_t size; + int present; + xmlrpc_int32 ival; + xmlrpc_bool bval; + char *sval; + char const weirdKey[] = {'f', 'o', 'o', '\0', 'b', 'a', 'r'}; + + xmlrpc_env_init(&env); + + /* Create a struct. */ + s = xmlrpc_struct_new(&env); + TEST_NO_FAULT(&env); + TEST(s != NULL); + TEST(XMLRPC_TYPE_STRUCT == xmlrpc_value_type(s)); + size = xmlrpc_struct_size(&env, s); + TEST_NO_FAULT(&env); + TEST(size == 0); + + /* Create some elements to insert into our struct. */ + i1 = xmlrpc_build_value(&env, "s", "Item #1"); + TEST_NO_FAULT(&env); + i2 = xmlrpc_build_value(&env, "s", "Item #2"); + TEST_NO_FAULT(&env); + i3 = xmlrpc_build_value(&env, "s", "Item #3"); + TEST_NO_FAULT(&env); + + /* Insert a single item. */ + xmlrpc_struct_set_value(&env, s, "foo", i1); + TEST_NO_FAULT(&env); + size = xmlrpc_struct_size(&env, s); + TEST_NO_FAULT(&env); + TEST(size == 1); + + /* Insert two more items with conflicting hash codes. (We assume that + ** nobody has changed the hash function.) */ + xmlrpc_struct_set_value(&env, s, "bar", i2); + TEST_NO_FAULT(&env); + xmlrpc_struct_set_value(&env, s, "aas", i3); + TEST_NO_FAULT(&env); + size = xmlrpc_struct_size(&env, s); + TEST_NO_FAULT(&env); + TEST(size == 3); + + /* Replace an existing element with a different element. */ + xmlrpc_struct_set_value(&env, s, "aas", i1); + TEST_NO_FAULT(&env); + size = xmlrpc_struct_size(&env, s); + TEST_NO_FAULT(&env); + TEST(size == 3); + + /* Insert an item with a NUL in the key */ + xmlrpc_struct_set_value_n(&env, s, weirdKey, sizeof(weirdKey), i2); + TEST_NO_FAULT(&env); + size = xmlrpc_struct_size(&env, s); + TEST_NO_FAULT(&env); + TEST(size == 4); + + test_struct_get_element(s, i1, i2, weirdKey, sizeof(weirdKey)); + + /* Replace an existing element with the same element (tricky). */ + xmlrpc_struct_set_value(&env, s, "aas", i1); + TEST_NO_FAULT(&env); + size = xmlrpc_struct_size(&env, s); + TEST_NO_FAULT(&env); + TEST(size == 4); + i = xmlrpc_struct_get_value(&env, s, "aas"); + TEST_NO_FAULT(&env); + TEST(i == i1); + + /* Test for the presence and absence of elements. */ + present = xmlrpc_struct_has_key(&env, s, "aas"); + TEST_NO_FAULT(&env); + TEST(present); + present = xmlrpc_struct_has_key(&env, s, "bogus"); + TEST_NO_FAULT(&env); + TEST(!present); + + /* Make sure our typechecks work correctly. */ + xmlrpc_struct_size(&env, i1); + TEST_FAULT(&env, XMLRPC_TYPE_ERROR); + + xmlrpc_struct_has_key(&env, i1, "foo"); + TEST_FAULT(&env, XMLRPC_TYPE_ERROR); + + xmlrpc_struct_set_value(&env, i1, "foo", i2); + TEST_FAULT(&env, XMLRPC_TYPE_ERROR); + + xmlrpc_struct_set_value_v(&env, s, s, i2); + TEST_FAULT(&env, XMLRPC_TYPE_ERROR); + + /* Test cleanup code (w/memprof). */ + xmlrpc_DECREF(s); + + /* Build a struct using our automagic struct builder. */ + s = xmlrpc_build_value(&env, "{s:s,s:i,s:b}", + "foo", "Hello!", + "bar", (xmlrpc_int32) 1, + "baz", (xmlrpc_bool) 0); + TEST_NO_FAULT(&env); + TEST(s != NULL); + TEST(XMLRPC_TYPE_STRUCT == xmlrpc_value_type(s)); + size = xmlrpc_struct_size(&env, s); + TEST_NO_FAULT(&env); + TEST(size == 3); + present = xmlrpc_struct_has_key(&env, s, "foo"); + TEST_NO_FAULT(&env); + TEST(present); + present = xmlrpc_struct_has_key(&env, s, "bar"); + TEST_NO_FAULT(&env); + TEST(present); + present = xmlrpc_struct_has_key(&env, s, "baz"); + TEST_NO_FAULT(&env); + TEST(present); + i = xmlrpc_struct_get_value(&env, s, "baz"); + TEST_NO_FAULT(&env); + xmlrpc_decompose_value(&env, i, "b", &bval); + TEST_NO_FAULT(&env); + TEST(!bval); + + testStructReadout(s, 3); + + /* Test our automagic struct parser. */ + xmlrpc_decompose_value(&env, s, "{s:b,s:s,s:i,*}", + "baz", &bval, + "foo", &sval, + "bar", &ival); + TEST_NO_FAULT(&env); + TEST(ival == 1); + TEST(!bval); + TEST(strcmp(sval, "Hello!") == 0); + free(sval); + + /* Test automagic struct parser with value of wrong type. */ + xmlrpc_decompose_value(&env, s, "{s:b,s:i,*}", + "baz", &bval, + "foo", &sval); + TEST_FAULT(&env, XMLRPC_TYPE_ERROR); + + /* Test automagic struct parser with bad key. */ + xmlrpc_decompose_value(&env, s, "{s:b,s:i,*}", + "baz", &bval, + "nosuch", &sval); + TEST_FAULT(&env, XMLRPC_INDEX_ERROR); + + /* Test type check. */ + xmlrpc_struct_get_key_and_value(&env, i1, 0, &key, &value); + TEST_FAULT(&env, XMLRPC_TYPE_ERROR); + TEST(key == NULL && value == NULL); + + /* Test bounds checks. */ + xmlrpc_struct_get_key_and_value(&env, s, -1, &key, &value); + TEST_FAULT(&env, XMLRPC_INDEX_ERROR); + TEST(key == NULL && value == NULL); + + xmlrpc_struct_get_key_and_value(&env, s, 3, &key, &value); + TEST_FAULT(&env, XMLRPC_INDEX_ERROR); + TEST(key == NULL && value == NULL); + + /* Test cleanup code (w/memprof). */ + xmlrpc_DECREF(s); + + xmlrpc_DECREF(i1); + xmlrpc_DECREF(i2); + xmlrpc_DECREF(i3); + xmlrpc_env_clean(&env); +} + + + +void +test_value(void) { + + printf("Running value tests."); + + test_value_alloc_dealloc(); + test_value_integer(); + test_value_bool(); + test_value_double(); + test_value_datetime(); + test_value_string_no_null(); + test_value_string_null(); + test_value_string_wide(); + test_value_base64(); + test_value_array(); + test_value_array2(); + test_value_array_nil(); + test_value_value(); + test_value_AS(); + test_value_AS_typecheck(); + test_value_cptr(); + test_value_nil(); + test_value_type_mismatch(); + test_value_invalid_type(); + test_value_missing_array_delim(); + test_value_missing_struct_delim(); + test_value_invalid_struct(); + test_value_parse_value(); + test_struct(); + + printf("\n"); + printf("Value tests done.\n"); +} diff --git a/src/test/value.h b/src/test/value.h new file mode 100644 index 0000000..2789def --- /dev/null +++ b/src/test/value.h @@ -0,0 +1,2 @@ +void +test_value(void); diff --git a/src/test/xml_data.c b/src/test/xml_data.c new file mode 100644 index 0000000..75cacf6 --- /dev/null +++ b/src/test/xml_data.c @@ -0,0 +1,196 @@ +#include + +#include "xml_data.h" + +#define RAW_STRING_DATA \ + "\r\n" \ + "2147483647\r\n" \ + "-2147483648\r\n" \ + "0\r\n" \ + "1\r\n" \ + "Hello, world! <&>\r\n" \ + "\r\n" \ + "YmFzZTY0IGRhdGE=\r\n" \ + "\r\n" \ + "" \ + "19980717T14:08:55" \ + "\r\n" \ + "\r\n" \ + "\r\n" \ + "" + +char const serialized_data[] = RAW_STRING_DATA; + +char const serialized_call[] = + XML_PROLOGUE + "\r\n" + "gloom&doom\r\n" + "\r\n" + "10\r\n" + "20\r\n" + "\r\n" + "\r\n"; + +char const serialized_fault[] = + XML_PROLOGUE + "\r\n" + "\r\n" + "\r\n" + "faultCode\r\n" + "6\r\n" + "faultString\r\n" + "A fault occurred\r\n" + "\r\n" + "\r\n" + "\r\n"; + +char const expat_data[] = XML_PROLOGUE RAW_STRING_DATA "\r\n"; +char const expat_error_data[] = + XML_PROLOGUE \ + "abc\r\n"; + /* Invalid because there's no closing */ + + +char const good_response_xml[] = + XML_PROLOGUE + "\r\n" + "\r\n" + RAW_STRING_DATA "\r\n" + "1\r\n" + "-1.0\r\n" + "0.0\r\n" + "1.0\r\n" + "\r\n" + "ten <&>\r\n" + "10\r\n" + "twenty\r\n" + "20\r\n" + "\r\n" + "Untagged string\r\n" + "\r\n" + "\r\n"; + +#define VALUE_HEADER \ + XML_PROLOGUE"\r\n" +#define VALUE_FOOTER \ + "\r\n" + +#define MEMBER_HEADER \ + VALUE_HEADER"" +#define MEMBER_FOOTER \ + ""VALUE_FOOTER +#define ARBITRARY_VALUE \ + "0" + +char const unparseable_value[] = VALUE_HEADER""VALUE_FOOTER; + +const char * bad_values[] = { + VALUE_HEADER"00"VALUE_FOOTER, + VALUE_HEADER""VALUE_FOOTER, + VALUE_HEADER"4"VALUE_FOOTER, + VALUE_HEADER"2147483648"VALUE_FOOTER, + VALUE_HEADER"-2147483649"VALUE_FOOTER, + VALUE_HEADER" 0"VALUE_FOOTER, + VALUE_HEADER"0 "VALUE_FOOTER, + VALUE_HEADER"2"VALUE_FOOTER, + VALUE_HEADER"-1"VALUE_FOOTER, + VALUE_HEADER" 0.0"VALUE_FOOTER, + VALUE_HEADER"0.0 "VALUE_FOOTER, + VALUE_HEADER""VALUE_FOOTER, + VALUE_HEADER""VALUE_FOOTER, + VALUE_HEADER""VALUE_FOOTER, + VALUE_HEADER""VALUE_FOOTER, + VALUE_HEADER""VALUE_FOOTER, + MEMBER_HEADER MEMBER_FOOTER, + MEMBER_HEADER"a"MEMBER_FOOTER, + MEMBER_HEADER"a"ARBITRARY_VALUE""MEMBER_FOOTER, + MEMBER_HEADER""ARBITRARY_VALUE MEMBER_FOOTER, + MEMBER_HEADER"a"MEMBER_FOOTER, + MEMBER_HEADER""ARBITRARY_VALUE MEMBER_FOOTER, + NULL +}; + +#define RESPONSE_HEADER \ + XML_PROLOGUE"\r\n" +#define RESPONSE_FOOTER \ + "\r\n" + +#define PARAMS_RESP_HEADER \ + RESPONSE_HEADER"" +#define PARAMS_RESP_FOOTER \ + ""RESPONSE_FOOTER + +#define FAULT_HEADER \ + RESPONSE_HEADER"" +#define FAULT_FOOTER \ + ""RESPONSE_FOOTER + +#define FAULT_STRUCT_HEADER \ + FAULT_HEADER"" +#define FAULT_STRUCT_FOOTER \ + ""FAULT_FOOTER + +const char * bad_responses[] = { + XML_PROLOGUE"\r\n", + RESPONSE_HEADER RESPONSE_FOOTER, + RESPONSE_HEADER""RESPONSE_FOOTER, + RESPONSE_HEADER""RESPONSE_FOOTER, + + /* Make sure we insist on only one parameter in a response. */ + PARAMS_RESP_HEADER PARAMS_RESP_FOOTER, + PARAMS_RESP_HEADER + "0" + "0" + PARAMS_RESP_FOOTER, + + /* Test other sorts of bad parameters. */ + PARAMS_RESP_HEADER""PARAMS_RESP_FOOTER, + PARAMS_RESP_HEADER""PARAMS_RESP_FOOTER, + PARAMS_RESP_HEADER""PARAMS_RESP_FOOTER, + PARAMS_RESP_HEADER + ""ARBITRARY_VALUE ARBITRARY_VALUE"" + PARAMS_RESP_FOOTER, + + /* Basic fault tests. */ + FAULT_HEADER FAULT_FOOTER, + FAULT_HEADER""FAULT_FOOTER, + FAULT_HEADER""FAULT_FOOTER, + FAULT_HEADER"1"FAULT_FOOTER, + + /* Make sure we insist on the proper members within the fault struct. */ + FAULT_STRUCT_HEADER + "faultString" + "foo" + FAULT_STRUCT_FOOTER, + FAULT_STRUCT_HEADER + "faultCode" + "0" + FAULT_STRUCT_FOOTER, + FAULT_STRUCT_HEADER + "faultCode" + "0" + "faultString" + "0" + FAULT_STRUCT_FOOTER, + FAULT_STRUCT_HEADER + "faultCode" + "0" + "faultString" + "foo" + FAULT_STRUCT_FOOTER, + NULL}; + +#define CALL_HEADER \ + XML_PROLOGUE"\r\n" +#define CALL_FOOTER \ + "\r\n" + +const char * bad_calls[] = { + XML_PROLOGUE"\r\n", + CALL_HEADER CALL_FOOTER, + CALL_HEADER"m"CALL_FOOTER, + CALL_HEADER""CALL_FOOTER, + CALL_HEADER""CALL_FOOTER, + NULL}; + + diff --git a/src/test/xml_data.h b/src/test/xml_data.h new file mode 100644 index 0000000..4b34238 --- /dev/null +++ b/src/test/xml_data.h @@ -0,0 +1,25 @@ +#ifndef XML_DATA_H_INCLUDED +#define XML_DATA_H_INCLUDED + +#define XML_PROLOGUE "\r\n" + +extern char const serialized_data[]; + +extern char const serialized_call[]; + +extern char const serialized_fault[]; + +extern char const expat_data[]; +extern char const expat_error_data[]; + +extern char const good_response_xml[]; + +extern char const unparseable_value[]; + +extern const char *(bad_values[]); + +extern const char *(bad_responses[]); + +extern const char *(bad_calls[]); + +#endif diff --git a/src/trace.c b/src/trace.c new file mode 100644 index 0000000..1e56acb --- /dev/null +++ b/src/trace.c @@ -0,0 +1,62 @@ +#include +#include +#include +#include + +#include "xmlrpc-c/base_int.h" +#include "xmlrpc-c/string_int.h" + + +static size_t +nextLineSize(const char * const string, + size_t const startPos, + size_t const stringSize) { +/*---------------------------------------------------------------------------- + Return the length of the line that starts at offset 'startPos' in the + string 'string', which is 'stringSize' characters long. + + 'string' in not NUL-terminated. + + A line begins at beginning of string or after a newline character and + runs through the next newline character or end of string. The line + includes the newline character at the end, if any. +-----------------------------------------------------------------------------*/ + size_t i; + + for (i = startPos; i < stringSize && string[i] != '\n'; ++i); + + if (i < stringSize) + ++i; /* Include the newline */ + + return i - startPos; +} + + + +void +xmlrpc_traceXml(const char * const label, + char const xml[], + unsigned int const xmlLength) { + + if (getenv("XMLRPC_TRACE_XML")) { + size_t cursor; /* Index into xml[] */ + + fprintf(stderr, "%s:\n\n", label); + + for (cursor = 0; cursor < xmlLength; ) { + /* Print one line of XML */ + + size_t const lineSize = nextLineSize(xml, cursor, xmlLength); + const char * const xmlPrintableLine = + xmlrpc_makePrintable_lp(&xml[cursor], lineSize); + + fprintf(stderr, "%s\n", xmlPrintableLine); + + cursor += lineSize; + + xmlrpc_strfree(xmlPrintableLine); + } + fprintf(stderr, "\n"); + } +} + diff --git a/src/xmlrpc_array.c b/src/xmlrpc_array.c new file mode 100644 index 0000000..9cba28c --- /dev/null +++ b/src/xmlrpc_array.c @@ -0,0 +1,255 @@ +/* Copyright information is at the end of the file */ + +/*========================================================================= +** XML-RPC Array Functions +**========================================================================= +*/ + +#include "xmlrpc_config.h" + +#include +#include + +#include "xmlrpc-c/util.h" +#include "xmlrpc-c/base.h" +#include "xmlrpc-c/base_int.h" + + + +void +xmlrpc_abort_if_array_bad(xmlrpc_value * const arrayP) { + + if (arrayP == NULL) + abort(); + else if (arrayP->_type != XMLRPC_TYPE_ARRAY) + abort(); + else { + unsigned int const arraySize = + XMLRPC_MEMBLOCK_SIZE(xmlrpc_value*, &arrayP->_block); + xmlrpc_value ** const contents = + XMLRPC_MEMBLOCK_CONTENTS(xmlrpc_value*, &arrayP->_block); + + if (contents == NULL) + abort(); + else { + unsigned int index; + + for (index = 0; index < arraySize; ++index) { + xmlrpc_value * const itemP = contents[index]; + if (itemP == NULL) + abort(); + else if (itemP->_refcount < 1) + abort(); + } + } + } +} + + + +void +xmlrpc_destroyArrayContents(xmlrpc_value * const arrayP) { +/*---------------------------------------------------------------------------- + Dispose of the contents of an array (but not the array value itself). + The value is not valid after this. +-----------------------------------------------------------------------------*/ + unsigned int const arraySize = + XMLRPC_MEMBLOCK_SIZE(xmlrpc_value*, &arrayP->_block); + xmlrpc_value ** const contents = + XMLRPC_MEMBLOCK_CONTENTS(xmlrpc_value*, &arrayP->_block); + + unsigned int index; + + XMLRPC_ASSERT_ARRAY_OK(arrayP); + + /* Release our reference to each item in the array */ + for (index = 0; index < arraySize; ++index) { + xmlrpc_value * const itemP = contents[index]; + xmlrpc_DECREF(itemP); + } + XMLRPC_MEMBLOCK_CLEAN(xmlrpc_value *, &arrayP->_block); +} + + + +int +xmlrpc_array_size(xmlrpc_env * const env, + const xmlrpc_value * const array) { + + int retval; + + /* Suppress a compiler warning about uninitialized variables. */ + retval = 0; + + XMLRPC_ASSERT_ENV_OK(env); + XMLRPC_ASSERT_VALUE_OK(array); + XMLRPC_TYPE_CHECK(env, array, XMLRPC_TYPE_ARRAY); + + retval = XMLRPC_TYPED_MEM_BLOCK_SIZE(xmlrpc_value*, &array->_block); + + cleanup: + if (env->fault_occurred) + return -1; + else + return retval; +} + + + +void +xmlrpc_array_append_item(xmlrpc_env * const envP, + xmlrpc_value * const arrayP, + xmlrpc_value * const valueP) { + + XMLRPC_ASSERT_ENV_OK(envP); + XMLRPC_ASSERT_VALUE_OK(arrayP); + + if (xmlrpc_value_type(arrayP) != XMLRPC_TYPE_ARRAY) + xmlrpc_env_set_fault_formatted( + envP, XMLRPC_TYPE_ERROR, "Value is not an array"); + else { + size_t const size = + XMLRPC_MEMBLOCK_SIZE(xmlrpc_value *, &arrayP->_block); + + XMLRPC_MEMBLOCK_RESIZE(xmlrpc_value *, envP, &arrayP->_block, size+1); + + if (!envP->fault_occurred) { + xmlrpc_value ** const contents = + XMLRPC_MEMBLOCK_CONTENTS(xmlrpc_value*, &arrayP->_block); + xmlrpc_INCREF(valueP); + contents[size] = valueP; + } + } +} + + + +void +xmlrpc_array_read_item(xmlrpc_env * const envP, + const xmlrpc_value * const arrayP, + unsigned int const index, + xmlrpc_value ** const valuePP) { + + XMLRPC_ASSERT_ENV_OK(envP); + XMLRPC_ASSERT_VALUE_OK(arrayP); + XMLRPC_ASSERT_PTR_OK(valuePP); + + if (arrayP->_type != XMLRPC_TYPE_ARRAY) + xmlrpc_env_set_fault_formatted( + envP, XMLRPC_TYPE_ERROR, "Attempt to read array item from " + "a value that is not an array"); + else { + xmlrpc_value ** const contents = + XMLRPC_MEMBLOCK_CONTENTS(xmlrpc_value *, &arrayP->_block); + size_t const size = + XMLRPC_MEMBLOCK_SIZE(xmlrpc_value *, &arrayP->_block); + + if (index >= size) + xmlrpc_env_set_fault_formatted( + envP, XMLRPC_INDEX_ERROR, "Array index %u is beyond end " + "of %u-item array", index, (unsigned int)size); + else { + *valuePP = contents[index]; + xmlrpc_INCREF(*valuePP); + } + } +} + + + +xmlrpc_value * +xmlrpc_array_get_item(xmlrpc_env * const envP, + const xmlrpc_value * const arrayP, + int const indexArg) { + + /* We must maintain the historical thread-safeness of + xmlrpc_array_get_item(). That means we can't call + xmlrpc_read_array(), because it modifies the reference count + of its arguments, thus is not thread-safe. + + The Xmlrpc-c method registry is an example of an application that + relies on thread-safeness of xmlrpc_array_get_item() -- it uses + xmlrpc_value's to represent the registry, and multiple server + threads read the registry simultaneously. + */ + + xmlrpc_value * valueP; + + XMLRPC_ASSERT_ENV_OK(envP); + XMLRPC_ASSERT_VALUE_OK(arrayP); + + valueP = NULL; + + if (indexArg < 0) + xmlrpc_env_set_fault_formatted( + envP, XMLRPC_INDEX_ERROR, "Index %d is negative.", indexArg); + else { + unsigned int const index = indexArg; + + if (arrayP->_type != XMLRPC_TYPE_ARRAY) + xmlrpc_env_set_fault_formatted( + envP, XMLRPC_TYPE_ERROR, "Attempt to read array item from " + "a value that is not an array"); + else { + xmlrpc_value ** const contents = + XMLRPC_MEMBLOCK_CONTENTS(xmlrpc_value *, &arrayP->_block); + size_t const size = + XMLRPC_MEMBLOCK_SIZE(xmlrpc_value *, &arrayP->_block); + + if (index >= size) + xmlrpc_env_set_fault_formatted( + envP, XMLRPC_INDEX_ERROR, "Array index %u is beyond end " + "of %u-item array", index, (unsigned int)size); + else + valueP = contents[index]; + } + } + return valueP; +} + + + +xmlrpc_value * +xmlrpc_array_new(xmlrpc_env * const envP) { +/*---------------------------------------------------------------------------- + Create an empty array xmlrpc_value. +-----------------------------------------------------------------------------*/ + xmlrpc_value * arrayP; + + xmlrpc_createXmlrpcValue(envP, &arrayP); + if (!envP->fault_occurred) { + arrayP->_type = XMLRPC_TYPE_ARRAY; + XMLRPC_MEMBLOCK_INIT(xmlrpc_value*, envP, &arrayP->_block, 0); + if (envP->fault_occurred) + free(arrayP); + } + return arrayP; +} + + + +/* Copyright (C) 2001 by First Peer, Inc. All rights reserved. +** Copyright (C) 2001 by Eric Kidd. All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +** ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +** OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +** HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +** LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +** OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +** SUCH DAMAGE. */ diff --git a/src/xmlrpc_authcookie.c b/src/xmlrpc_authcookie.c new file mode 100644 index 0000000..b29cc92 --- /dev/null +++ b/src/xmlrpc_authcookie.c @@ -0,0 +1,85 @@ +/* Copyright (C) 2002 by jeff@ourexchange.net. All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +** ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +** OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +** HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +** LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +** OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +** SUCH DAMAGE. */ + +#include "xmlrpc_config.h" + +#include +#include +#include + +#include "mallocvar.h" +#include "xmlrpc-c/base.h" + +/***************************************************************************** + I don't see how these were expected to be used. And I probably + broke it somehow at some point by removing code from somewhere else. + But I doubt that, whatever it's supposed to do, environment + variables are the right tool. + + Note that on a platform that doesn't have SETENV, + xmlrpc_authcookie_set() is just a no-op. + + -Bryan 2005.06.10 +****************************************************************************/ + +void +xmlrpc_authcookie_set(xmlrpc_env * const envP, + const char * const username, + const char * const password) { + + char * unencoded; + xmlrpc_mem_block * token; + + XMLRPC_ASSERT_ENV_OK(envP); + XMLRPC_ASSERT_PTR_OK(username); + XMLRPC_ASSERT_PTR_OK(password); + + /* Create unencoded string/hash. */ + + MALLOCARRAY(unencoded,(strlen(username) + strlen(password) + 1 + 1)); + sprintf(unencoded, "%s:%s", username, password); + + /* Create encoded string. */ + token = xmlrpc_base64_encode_without_newlines( + envP, (unsigned char *)unencoded, strlen(unencoded)); + if (!envP->fault_occurred) { + /* Set HTTP_COOKIE_AUTH to the character representation of the + encoded string. + */ +#ifdef HAVE_SETENV + setenv("HTTP_COOKIE_AUTH", + XMLRPC_MEMBLOCK_CONTENTS(char, token), + 1); +#endif + xmlrpc_mem_block_free(token); + } + free(unencoded); +} + + + +char *xmlrpc_authcookie ( void ) { + return getenv("HTTP_COOKIE_AUTH"); +} diff --git a/src/xmlrpc_base64.c b/src/xmlrpc_base64.c new file mode 100644 index 0000000..2f54377 --- /dev/null +++ b/src/xmlrpc_base64.c @@ -0,0 +1,266 @@ +/* Copyright (C) 2001 by First Peer, Inc. All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +** ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +** OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +** HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +** LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +** OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +** SUCH DAMAGE. +** +** There is more copyright information in the bottom half of this file. +** Please see it for more details. */ + + +/*========================================================================= +** XML-RPC Base64 Utilities +**========================================================================= +** This code was swiped from Jack Jansen's code in Python 1.5.2 and +** modified to work with our data types. +*/ + +#include "xmlrpc_config.h" + +#include "xmlrpc-c/base.h" + +#define CRLF "\015\012" +#define CR '\015' +#define LF '\012' + + +/*********************************************************** +Copyright 1991, 1992, 1993, 1994 by Stichting Mathematisch Centrum, +Amsterdam, The Netherlands. + + All Rights Reserved + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +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 names of Stichting Mathematisch +Centrum or CWI or Corporation for National Research Initiatives or +CNRI not be used in advertising or publicity pertaining to +distribution of the software without specific, written prior +permission. + +While CWI is the initial source for this software, a modified version +is made available by the Corporation for National Research Initiatives +(CNRI) at the Internet address ftp://ftp.python.org. + +STICHTING MATHEMATISCH CENTRUM AND CNRI DISCLAIM ALL WARRANTIES WITH +REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH +CENTRUM OR CNRI BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL +DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR +PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER +TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR +PERFORMANCE OF THIS SOFTWARE. + +******************************************************************/ + +static char table_a2b_base64[] = { + -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, + -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, + -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,62, -1,-1,-1,63, + 52,53,54,55, 56,57,58,59, 60,61,-1,-1, -1, 0,-1,-1, /* Note PAD->0 */ + -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10, 11,12,13,14, + 15,16,17,18, 19,20,21,22, 23,24,25,-1, -1,-1,-1,-1, + -1,26,27,28, 29,30,31,32, 33,34,35,36, 37,38,39,40, + 41,42,43,44, 45,46,47,48, 49,50,51,-1, -1,-1,-1,-1 +}; + +#define BASE64_PAD '=' +#define BASE64_MAXBIN 57 /* Max binary chunk size (76 char line) */ +#define BASE64_LINE_SZ 128 /* Buffer size for a single line. */ + +static unsigned char table_b2a_base64[] = +"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + +static xmlrpc_mem_block * +xmlrpc_base64_encode_internal (xmlrpc_env *env, + unsigned char *bin_data, + size_t bin_len, + int want_newlines) +{ + size_t chunk_start, chunk_left; + unsigned char *ascii_data; + int leftbits; + unsigned char this_ch; + unsigned int leftchar; + xmlrpc_mem_block *output; + unsigned char line_buffer[BASE64_LINE_SZ]; + + /* Create a block to hold our lines when we finish them. */ + output = xmlrpc_mem_block_new(env, 0); + XMLRPC_FAIL_IF_FAULT(env); + + /* Deal with empty data blocks gracefully. Yuck. */ + if (bin_len == 0) { + if (want_newlines) + XMLRPC_TYPED_MEM_BLOCK_APPEND(char, env, output, CRLF, 2); + goto cleanup; + } + + /* Process our binary data in line-sized chunks. */ + for (chunk_start=0; chunk_start < bin_len; chunk_start += BASE64_MAXBIN) { + + /* Set up our per-line state. */ + ascii_data = &line_buffer[0]; + chunk_left = bin_len - chunk_start; + if (chunk_left > BASE64_MAXBIN) + chunk_left = BASE64_MAXBIN; + leftbits = 0; + leftchar = 0; + + for(; chunk_left > 0; chunk_left--, bin_data++) { + /* Shift the data into our buffer */ + leftchar = (leftchar << 8) | *bin_data; + leftbits += 8; + + /* See if there are 6-bit groups ready */ + while (leftbits >= 6) { + this_ch = (leftchar >> (leftbits-6)) & 0x3f; + leftbits -= 6; + *ascii_data++ = table_b2a_base64[this_ch]; + } + } + if (leftbits == 2) { + *ascii_data++ = table_b2a_base64[(leftchar&3) << 4]; + *ascii_data++ = BASE64_PAD; + *ascii_data++ = BASE64_PAD; + } else if (leftbits == 4) { + *ascii_data++ = table_b2a_base64[(leftchar&0xf) << 2]; + *ascii_data++ = BASE64_PAD; + } + + /* Append a courtesy CRLF. */ + if (want_newlines) { + *ascii_data++ = CR; + *ascii_data++ = LF; + } + + /* Save our line. */ + XMLRPC_TYPED_MEM_BLOCK_APPEND(char, env, output, line_buffer, + ascii_data - &line_buffer[0]); + XMLRPC_FAIL_IF_FAULT(env); + } + + cleanup: + if (env->fault_occurred) { + if (output) + xmlrpc_mem_block_free(output); + return NULL; + } + return output; +} + + +xmlrpc_mem_block * +xmlrpc_base64_encode (xmlrpc_env *env, unsigned char *bin_data, size_t bin_len) +{ + return xmlrpc_base64_encode_internal(env, bin_data, bin_len, 1); +} + + +xmlrpc_mem_block * +xmlrpc_base64_encode_without_newlines (xmlrpc_env *env, + unsigned char *bin_data, + size_t bin_len) +{ + return xmlrpc_base64_encode_internal(env, bin_data, bin_len, 0); +} + + +xmlrpc_mem_block * +xmlrpc_base64_decode (xmlrpc_env * const env, + const char * const ascii_data, + size_t const ascii_len) { + + unsigned char *bin_data; + int leftbits; + unsigned char this_ch; + unsigned int leftchar; + size_t npad; + size_t bin_len, buffer_size; + xmlrpc_mem_block *output; + const char * next_char; + size_t remaining_len; + + /* Create a block to hold our chunks when we finish them. + ** We overestimate the size now, and fix it later. */ + buffer_size = ((ascii_len+3)/4)*3; + output = xmlrpc_mem_block_new(env, buffer_size); + XMLRPC_FAIL_IF_FAULT(env); + + /* Set up our decoder state. */ + leftbits = 0; + leftchar = 0; + npad = 0; + bin_data = XMLRPC_TYPED_MEM_BLOCK_CONTENTS(unsigned char, output); + bin_len = 0; + + for (remaining_len = ascii_len, next_char = ascii_data; + remaining_len > 0; + --remaining_len, ++next_char) { + + /* Skip some punctuation. */ + this_ch = (*next_char & 0x7f); + if ( this_ch == '\r' || this_ch == '\n' || this_ch == ' ' ) + continue; + if ( this_ch == BASE64_PAD ) + npad++; + this_ch = table_a2b_base64[(*next_char) & 0x7f]; + + /* XXX - We just throw away invalid characters. Is this right? */ + if ( this_ch == (unsigned char) -1 ) continue; + + /* Shift it in on the low end, and see if there's + ** a byte ready for output. */ + leftchar = (leftchar << 6) | (this_ch); + leftbits += 6; + if ( leftbits >= 8 ) { + leftbits -= 8; + XMLRPC_ASSERT(bin_len < buffer_size); + *bin_data++ = (leftchar >> leftbits) & 0xFF; + leftchar &= ((1 << leftbits) - 1); + bin_len++; + } + } + + /* Check that no bits are left. */ + if ( leftbits ) + XMLRPC_FAIL(env, XMLRPC_PARSE_ERROR, "Incorrect Base64 padding"); + + /* Check to make sure we have a sane amount of padding. */ + if (npad > bin_len || npad > 2) + XMLRPC_FAIL(env, XMLRPC_PARSE_ERROR, "Malformed Base64 data"); + + /* Remove any padding and set the correct size. */ + bin_len -= npad; + XMLRPC_TYPED_MEM_BLOCK_RESIZE(char, env, output, bin_len); + XMLRPC_ASSERT(!env->fault_occurred); + + cleanup: + if (env->fault_occurred) { + if (output) + xmlrpc_mem_block_free(output); + return NULL; + } + return output; +} diff --git a/src/xmlrpc_builddecomp.c b/src/xmlrpc_builddecomp.c new file mode 100644 index 0000000..f0e58d7 --- /dev/null +++ b/src/xmlrpc_builddecomp.c @@ -0,0 +1,971 @@ +/* Copyright information is at end of file */ + +#include "xmlrpc_config.h" + +#include +#include +#include +#include + +#include "bool.h" + +#include "xmlrpc-c/base.h" +#include "xmlrpc-c/base_int.h" +#include "xmlrpc-c/string_int.h" + +/* Borrowed from Python 1.5.2. +** MPW pushes 'extended' for float and double types with varargs */ +#ifdef MPW +typedef extended va_double; +#else +typedef double va_double; +#endif + +/* Borrowed from Python 1.5.2. +** Python copies its va_list objects before using them in certain +** tricky fashions. We don't why Python does this, but since we're +** abusing our va_list objects in a similar fashion, we'll copy them +** too. */ +#if VA_LIST_IS_ARRAY +#define VA_LIST_COPY(dest,src) memcpy((dest), (src), sizeof(va_list)) +#else +#define VA_LIST_COPY(dest,src) ((dest) = (src)) +#endif + +/*========================================================================= +** Creating XML-RPC values. +**========================================================================= +** Build new XML-RPC values from a format string. This code is heavily +** inspired by Py_BuildValue from Python 1.5.2. In particular, our +** particular abuse of the va_list data type is copied from the equivalent +** Python code in modsupport.c. Since Python is portable, our code should +** (in theory) also be portable. +*/ + + +static void +getString(xmlrpc_env * const envP, + const char ** const formatP, + va_list * const args, + xmlrpc_value ** const valPP) { + + const char * str; + unsigned int len; + + str = (const char*) va_arg(*args, char*); + if (**formatP == '#') { + (*formatP)++; + len = (size_t) va_arg(*args, size_t); + } else + len = strlen(str); + + *valPP = xmlrpc_string_new_lp(envP, len, str); +} + + + +#if HAVE_UNICODE_WCHAR +static void +mkWideString(xmlrpc_env * const envP, + wchar_t * const wcs, + size_t const wcs_len, + xmlrpc_value ** const valPP) { + + xmlrpc_value * valP; + char *contents; + wchar_t *wcs_contents; + int block_is_inited; + xmlrpc_mem_block *utf8_block; + char *utf8_contents; + size_t utf8_len; + + /* Error-handling preconditions. */ + valP = NULL; + utf8_block = NULL; + block_is_inited = 0; + + /* Initialize our XML-RPC value. */ + valP = (xmlrpc_value*) malloc(sizeof(xmlrpc_value)); + XMLRPC_FAIL_IF_NULL(valP, envP, XMLRPC_INTERNAL_ERROR, + "Could not allocate memory for wide string"); + valP->_refcount = 1; + valP->_type = XMLRPC_TYPE_STRING; + + /* More error-handling preconditions. */ + valP->_wcs_block = NULL; + + /* Build our wchar_t block first. */ + valP->_wcs_block = + XMLRPC_TYPED_MEM_BLOCK_NEW(wchar_t, envP, wcs_len + 1); + XMLRPC_FAIL_IF_FAULT(envP); + wcs_contents = + XMLRPC_TYPED_MEM_BLOCK_CONTENTS(wchar_t, valP->_wcs_block); + memcpy(wcs_contents, wcs, wcs_len * sizeof(wchar_t)); + wcs_contents[wcs_len] = '\0'; + + /* Convert the wcs block to UTF-8. */ + utf8_block = xmlrpc_wcs_to_utf8(envP, wcs_contents, wcs_len + 1); + XMLRPC_FAIL_IF_FAULT(envP); + utf8_contents = XMLRPC_TYPED_MEM_BLOCK_CONTENTS(char, utf8_block); + utf8_len = XMLRPC_TYPED_MEM_BLOCK_SIZE(char, utf8_block); + + /* XXX - We need an extra memcopy to initialize _block. */ + XMLRPC_TYPED_MEM_BLOCK_INIT(char, envP, &valP->_block, utf8_len); + XMLRPC_FAIL_IF_FAULT(envP); + block_is_inited = 1; + contents = XMLRPC_TYPED_MEM_BLOCK_CONTENTS(char, &valP->_block); + memcpy(contents, utf8_contents, utf8_len); + + cleanup: + if (utf8_block) + xmlrpc_mem_block_free(utf8_block); + if (envP->fault_occurred) { + if (valP) { + if (valP->_wcs_block) + xmlrpc_mem_block_free(valP->_wcs_block); + if (block_is_inited) + xmlrpc_mem_block_clean(&valP->_block); + free(valP); + } + } + *valPP = valP; +} +#endif /* HAVE_UNICODE_WCHAR */ + + + +static void +getWideString(xmlrpc_env * const envP ATTR_UNUSED, + const char ** const formatP ATTR_UNUSED, + va_list * const args ATTR_UNUSED, + xmlrpc_value ** const valPP ATTR_UNUSED) { + +#if HAVE_UNICODE_WCHAR + wchar_t *wcs; + size_t len; + + wcs = (wchar_t*) va_arg(*args, wchar_t*); + if (**formatP == '#') { + (*formatP)++; + len = (size_t) va_arg(*args, size_t); + } else + len = wcslen(wcs); + + mkWideString(envP, wcs, len, valPP); + +#endif /* HAVE_UNICODE_WCHAR */ +} + + + +static void +getBase64(xmlrpc_env * const envP, + va_list * const args, + xmlrpc_value ** const valPP) { + + unsigned char * value; + size_t length; + + value = (unsigned char*) va_arg(*args, unsigned char*); + length = (size_t) va_arg(*args, size_t); + + *valPP = xmlrpc_base64_new(envP, length, value); +} + + + +static void +getValue(xmlrpc_env * const envP, + const char** const format, + va_list * args, + xmlrpc_value ** const valPP); + + + +static void +getArray(xmlrpc_env * const envP, + const char ** const formatP, + char const delimiter, + va_list * const args, + xmlrpc_value ** const arrayPP) { + + xmlrpc_value * arrayP; + + arrayP = xmlrpc_array_new(envP); + + /* Add items to the array until we hit our delimiter. */ + + while (**formatP != delimiter && !envP->fault_occurred) { + + xmlrpc_value * itemP; + + if (**formatP == '\0') + xmlrpc_env_set_fault( + envP, XMLRPC_INTERNAL_ERROR, + "format string ended before closing ')'."); + else { + getValue(envP, formatP, args, &itemP); + if (!envP->fault_occurred) { + xmlrpc_array_append_item(envP, arrayP, itemP); + xmlrpc_DECREF(itemP); + } + } + } + if (envP->fault_occurred) + xmlrpc_DECREF(arrayP); + + *arrayPP = arrayP; +} + + + +static void +getStructMember(xmlrpc_env * const envP, + const char ** const formatP, + va_list * const args, + xmlrpc_value ** const keyPP, + xmlrpc_value ** const valuePP) { + + + /* Get the key */ + getValue(envP, formatP, args, keyPP); + if (!envP->fault_occurred) { + if (**formatP != ':') + xmlrpc_env_set_fault( + envP, XMLRPC_INTERNAL_ERROR, + "format string does not have ':' after a " + "structure member key."); + else { + /* Skip over colon that separates key from value */ + (*formatP)++; + + /* Get the value */ + getValue(envP, formatP, args, valuePP); + } + if (envP->fault_occurred) + xmlrpc_DECREF(*keyPP); + } +} + + + +static void +getStruct(xmlrpc_env * const envP, + const char ** const formatP, + char const delimiter, + va_list * const args, + xmlrpc_value ** const structPP) { + + xmlrpc_value * structP; + + structP = xmlrpc_struct_new(envP); + if (!envP->fault_occurred) { + while (**formatP != delimiter && !envP->fault_occurred) { + xmlrpc_value * keyP; + xmlrpc_value * valueP; + + getStructMember(envP, formatP, args, &keyP, &valueP); + + if (!envP->fault_occurred) { + if (**formatP == ',') + (*formatP)++; /* Skip over the comma */ + else if (**formatP == delimiter) { + /* End of the line */ + } else + xmlrpc_env_set_fault( + envP, XMLRPC_INTERNAL_ERROR, + "format string does not have ',' or ')' after " + "a structure member"); + + if (!envP->fault_occurred) + /* Add the new member to the struct. */ + xmlrpc_struct_set_value_v(envP, structP, keyP, valueP); + + xmlrpc_DECREF(valueP); + xmlrpc_DECREF(keyP); + } + } + if (envP->fault_occurred) + xmlrpc_DECREF(structP); + } + *structPP = structP; +} + + + +static void +mkArrayFromVal(xmlrpc_env * const envP, + xmlrpc_value * const value, + xmlrpc_value ** const valPP) { + + if (xmlrpc_value_type(value) != XMLRPC_TYPE_ARRAY) + xmlrpc_env_set_fault(envP, XMLRPC_INTERNAL_ERROR, + "Array format ('A'), non-array xmlrpc_value"); + else + xmlrpc_INCREF(value); + + *valPP = value; +} + + + +static void +mkStructFromVal(xmlrpc_env * const envP, + xmlrpc_value * const value, + xmlrpc_value ** const valPP) { + + if (xmlrpc_value_type(value) != XMLRPC_TYPE_STRUCT) + xmlrpc_env_set_fault(envP, XMLRPC_INTERNAL_ERROR, + "Struct format ('S'), non-struct xmlrpc_value"); + else + xmlrpc_INCREF(value); + + *valPP = value; +} + + + +static void +getValue(xmlrpc_env * const envP, + const char** const formatP, + va_list * const args, + xmlrpc_value ** const valPP) { +/*---------------------------------------------------------------------------- + Get the next value from the list. *formatP points to the specifier + for the next value in the format string (i.e. to the type code + character) and we move *formatP past the whole specifier for the + next value. We read the required arguments from 'args'. We return + the value as *valPP with a reference to it. + + For example, if *formatP points to the "i" in the string "sis", + we read one argument from 'args' and return as *valP an integer whose + value is the argument we read. We advance *formatP to point to the + last 's' and advance 'args' to point to the argument that belongs to + that 's'. +-----------------------------------------------------------------------------*/ + char const formatChar = *(*formatP)++; + + switch (formatChar) { + case 'i': + *valPP = + xmlrpc_int_new(envP, (xmlrpc_int32) va_arg(*args, xmlrpc_int32)); + break; + + case 'b': + *valPP = + xmlrpc_bool_new(envP, (xmlrpc_bool) va_arg(*args, xmlrpc_bool)); + break; + + case 'd': + *valPP = + xmlrpc_double_new(envP, (double) va_arg(*args, va_double)); + break; + + case 's': + getString(envP, formatP, args, valPP); + break; + + case 'w': + getWideString(envP, formatP, args, valPP); + break; + + /* The code 't' is reserved for a better, time_t based + implementation of dateTime conversion. + */ + case '8': + *valPP = + xmlrpc_datetime_new_str(envP, (char*) va_arg(*args, char*)); + break; + + case '6': + getBase64(envP, args, valPP); + break; + + case 'n': + *valPP = + xmlrpc_nil_new(envP); + break; + + case 'p': + /* We might someday want to use the code 'p!' to read in a + cleanup function for this pointer. + */ + *valPP = + xmlrpc_cptr_new(envP, (void*) va_arg(*args, void*)); + break; + + case 'A': + mkArrayFromVal(envP, (xmlrpc_value*) va_arg(*args, xmlrpc_value*), + valPP); + break; + + case 'S': + mkStructFromVal(envP, (xmlrpc_value*) va_arg(*args, xmlrpc_value*), + valPP); + break; + + case 'V': + *valPP = (xmlrpc_value*) va_arg(*args, xmlrpc_value*); + xmlrpc_INCREF(*valPP); + break; + + case '(': + getArray(envP, formatP, ')', args, valPP); + if (!envP->fault_occurred) { + XMLRPC_ASSERT(**formatP == ')'); + (*formatP)++; /* Skip over closing parenthesis */ + } + break; + + case '{': + getStruct(envP, formatP, '}', args, valPP); + if (!envP->fault_occurred) { + XMLRPC_ASSERT(**formatP == '}'); + (*formatP)++; /* Skip over closing brace */ + } + break; + + default: { + const char * const badCharacter = xmlrpc_makePrintableChar(formatChar); + xmlrpc_env_set_fault_formatted( + envP, XMLRPC_INTERNAL_ERROR, + "Unexpected character '%s' in format string", badCharacter); + xmlrpc_strfree(badCharacter); + } + } +} + + + +void +xmlrpc_build_value_va(xmlrpc_env * const envP, + const char * const format, + va_list args, + xmlrpc_value ** const valPP, + const char ** const tailP) { + + const char * formatCursor; + va_list args_copy; + + XMLRPC_ASSERT_ENV_OK(envP); + XMLRPC_ASSERT(format != NULL); + + if (strlen(format) == 0) + xmlrpc_env_set_fault_formatted( + envP, XMLRPC_INTERNAL_ERROR, "Format string is empty."); + else { + formatCursor = &format[0]; + VA_LIST_COPY(args_copy, args); + getValue(envP, &formatCursor, &args_copy, valPP); + + if (!envP->fault_occurred) + XMLRPC_ASSERT_VALUE_OK(*valPP); + + *tailP = formatCursor; + } +} + + + +xmlrpc_value * +xmlrpc_build_value(xmlrpc_env * const envP, + const char * const format, + ...) { + + va_list args; + xmlrpc_value* retval; + const char * suffix; + + va_start(args, format); + xmlrpc_build_value_va(envP, format, args, &retval, &suffix); + va_end(args); + + if (!envP->fault_occurred) { + if (*suffix != '\0') + xmlrpc_env_set_fault_formatted( + envP, XMLRPC_INTERNAL_ERROR, "Junk after the argument " + "specifier: '%s'. There must be exactly one arument.", + suffix); + + if (envP->fault_occurred) + xmlrpc_DECREF(retval); + } + return retval; +} + + + + + +/*========================================================================= +** Parsing XML-RPC values. +**========================================================================= +** Parse an XML-RPC value based on a format string. This code is heavily +** inspired by Py_BuildValue from Python 1.5.2. +*/ + +/* Prototype for recursive invocation: */ + +static void +decomposeValue(xmlrpc_env * const env, + xmlrpc_value * const val, + const char ** const format, + va_list * args, + xmlrpc_bool const oldstyleMemMgmt); + + + +static void +parsearray(xmlrpc_env * const env, + const xmlrpc_value * const array, + const char ** const format, + char const delimiter, + va_list * args, + xmlrpc_bool const oldstyleMemMgmt) { + + int size, i; + xmlrpc_value *item; + + /* Fetch the array size. */ + size = xmlrpc_array_size(env, array); + XMLRPC_FAIL_IF_FAULT(env); + + /* Loop over the items in the array. */ + for (i = 0; i < size; i++) { + /* Bail out if the caller didn't care about the rest of the items. */ + if (**format == '*') + break; + + item = xmlrpc_array_get_item(env, array, i); + XMLRPC_FAIL_IF_FAULT(env); + + XMLRPC_ASSERT(**format != '\0'); + if (**format == delimiter) + XMLRPC_FAIL(env, XMLRPC_INDEX_ERROR, "Too many items in array"); + decomposeValue(env, item, format, args, oldstyleMemMgmt); + XMLRPC_FAIL_IF_FAULT(env); + } + if (**format == '*') + (*format)++; + if (**format != delimiter) + XMLRPC_FAIL(env, XMLRPC_INDEX_ERROR, "Not enough items in array"); + + cleanup: + return; +} + + + +static void +parsestruct(xmlrpc_env * const env, + xmlrpc_value * const strct, + const char ** const format, + char const delimiter, + va_list * args, + xmlrpc_bool const oldstyleMemMgmt) { + + xmlrpc_value *key, *value; + char *keystr; + size_t keylen; + + /* Set up error handling preconditions. */ + key = NULL; + + /* Build the members of our struct. */ + while (**format != '*' && **format != delimiter && **format != '\0') { + + /* Get our key, and skip over the ':' character. Notice the + ** sudden call to getValue--we're going in the opposite direction. */ + getValue(env, format, args, &key); + XMLRPC_FAIL_IF_FAULT(env); + XMLRPC_ASSERT(**format == ':'); + (*format)++; + + /* Look up the value for our key. */ + xmlrpc_parse_value(env, key, "s#", &keystr, &keylen); + XMLRPC_FAIL_IF_FAULT(env); + value = xmlrpc_struct_get_value_n(env, strct, keystr, keylen); + XMLRPC_FAIL_IF_FAULT(env); + + /* Get our value, and skip over the ',' character (if present). */ + decomposeValue(env, value, format, args, oldstyleMemMgmt); + XMLRPC_FAIL_IF_FAULT(env); + XMLRPC_ASSERT(**format == ',' || **format == delimiter); + if (**format == ',') + (*format)++; + + /* Release our reference, and restore our invariant. */ + xmlrpc_DECREF(key); + key = NULL; + } + if (**format == '*') { + (*format)++; + if (**format != delimiter && **format != '\0') + XMLRPC_FAIL(env, XMLRPC_INTERNAL_ERROR, + "* can appear only at the end " + "of a structure format specifier"); + } else { + /* Here we're supposed to fail if he didn't extract all the + members. But we don't know how to determine whether he + specified all the members, so we always fail. + */ + XMLRPC_FAIL(env, XMLRPC_INTERNAL_ERROR, "You must specify '*' as the " + "last member of a structure in a format specifier " + "used for parsing an xmlrpc_value"); + } + XMLRPC_ASSERT(**format == delimiter || **format == '\0'); + +cleanup: + if (key) + xmlrpc_DECREF(key); +} + + +static void +readString(xmlrpc_env * const envP, + const xmlrpc_value * const valueP, + const char ** const stringValueP, + xmlrpc_bool const oldstyleMemMgmt) { + + if (oldstyleMemMgmt) { + xmlrpc_read_string_old(envP, valueP, stringValueP); + } else + xmlrpc_read_string(envP, valueP, stringValueP); +} + + + +static void +readStringLp(xmlrpc_env * const envP, + const xmlrpc_value * const valueP, + size_t * const lengthP, + const char ** const stringValueP, + xmlrpc_bool const oldstyleMemMgmt) { + + if (oldstyleMemMgmt) { + xmlrpc_read_string_lp_old(envP, valueP, lengthP, stringValueP); + } else + xmlrpc_read_string_lp(envP, valueP, lengthP, stringValueP); +} + + + +#if HAVE_UNICODE_WCHAR +static void +readStringW(xmlrpc_env * const envP, + xmlrpc_value * const valueP, + const wchar_t ** const stringValueP, + xmlrpc_bool const oldstyleMemMgmt) { + + if (oldstyleMemMgmt) { + xmlrpc_read_string_w_old(envP, valueP, stringValueP); + } else + xmlrpc_read_string_w(envP, valueP, stringValueP); +} + + + +static void +readStringWLp(xmlrpc_env * const envP, + xmlrpc_value * const valueP, + size_t * const lengthP, + const wchar_t ** const stringValueP, + xmlrpc_bool const oldstyleMemMgmt) { + + if (oldstyleMemMgmt) { + xmlrpc_read_string_w_lp_old(envP, valueP, lengthP, stringValueP); + } else + xmlrpc_read_string_w_lp(envP, valueP, lengthP, stringValueP); +} +#endif + + +static void +readDatetimeStr(xmlrpc_env * const envP, + const xmlrpc_value * const valueP, + const char ** const stringValueP, + xmlrpc_bool const oldstyleMemMgmt) { + + if (oldstyleMemMgmt) + xmlrpc_read_datetime_str_old(envP, valueP, stringValueP); + else + xmlrpc_read_datetime_str(envP, valueP, stringValueP); +} + + + +static void +readBase64(xmlrpc_env * const envP, + const xmlrpc_value * const valueP, + size_t * const lengthP, + const unsigned char ** const byteStringValueP, + xmlrpc_bool const oldstyleMemMgmt) { + + if (oldstyleMemMgmt) + xmlrpc_read_base64_old(envP, valueP, lengthP, byteStringValueP); + else + xmlrpc_read_base64(envP, valueP, lengthP, byteStringValueP); +} + + + +static void +decomposeValue(xmlrpc_env * const envP, + xmlrpc_value * const valueP, + const char ** const format, + va_list * args, + xmlrpc_bool const oldstyleMemMgmt) { + + char formatSpecChar; + + formatSpecChar = *(*format)++; + + switch (formatSpecChar) { + case 'i': { + xmlrpc_int32 * const int32ptr = + (xmlrpc_int32*) va_arg(*args, xmlrpc_int32*); + xmlrpc_read_int(envP, valueP, int32ptr); + } + break; + + case 'b': { + xmlrpc_bool * const boolptr = + (xmlrpc_bool*) va_arg(*args, xmlrpc_bool*); + xmlrpc_read_bool(envP, valueP, boolptr); + } + break; + + case 'd': { + double * const doubleptr = (double*) va_arg(*args, double*); + xmlrpc_read_double(envP, valueP, doubleptr); + } + break; + + case '8': { + /* The code 't' is reserved for a better, time_t based + implementation of dateTime conversion. + */ + const char ** const strptr = (const char**) va_arg(*args, char**); + readDatetimeStr(envP, valueP, strptr, oldstyleMemMgmt); + } + break; + + case 's': { + const char ** const strptr = (const char**) va_arg(*args, char**); + if (**format == '#') { + size_t * const sizeptr = (size_t*) va_arg(*args, size_t**); + (*format)++; + + readStringLp(envP, valueP, sizeptr, strptr, oldstyleMemMgmt); + } else + readString(envP, valueP, strptr, oldstyleMemMgmt); + } + break; + + case 'w': { +#if HAVE_UNICODE_WCHAR + const wchar_t ** const wcsptr = + (const wchar_t**) va_arg(*args, wchar_t**); + if (**format == '#') { + size_t * const sizeptr = (size_t*) va_arg(*args, size_t**); + (*format)++; + readStringWLp(envP, valueP, sizeptr, wcsptr, oldstyleMemMgmt); + } else + readStringW(envP, valueP, wcsptr, oldstyleMemMgmt); +#else + xmlrpc_env_set_fault_formatted( + envP, XMLRPC_INTERNAL_ERROR, + "This XML-RPC For C/C++ library was built without Unicode " + "wide character capability. 'w' isn't available."); +#endif /* HAVE_UNICODE_WCHAR */ + } + break; + + case '6': { + const unsigned char ** const binptr = + (const unsigned char**) va_arg(*args, unsigned char**); + size_t * const sizeptr = (size_t*) va_arg(*args, size_t**); + readBase64(envP, valueP, sizeptr, binptr, oldstyleMemMgmt); + } + break; + + case 'n': { + xmlrpc_read_nil(envP, valueP); + } + break; + + case 'p': { + void ** const voidptrptr = (void**) va_arg(*args, void**); + xmlrpc_read_cptr(envP, valueP, voidptrptr); + } + break; + + case 'V': { + xmlrpc_value ** const valptr = + (xmlrpc_value**) va_arg(*args, xmlrpc_value**); + *valptr = valueP; + if (!oldstyleMemMgmt) + xmlrpc_INCREF(valueP); + } + break; + + case 'A': + if (xmlrpc_value_type(valueP) != XMLRPC_TYPE_ARRAY) + xmlrpc_env_set_fault_formatted( + envP, XMLRPC_TYPE_ERROR, "Non-array type supplied for " + "'A' specifier"); + else { + xmlrpc_value ** const valptr = + (xmlrpc_value**) va_arg(*args, xmlrpc_value**); + *valptr = valueP; + if (!oldstyleMemMgmt) + xmlrpc_INCREF(valueP); + } + break; + + case 'S': + if (xmlrpc_value_type(valueP) != XMLRPC_TYPE_STRUCT) + xmlrpc_env_set_fault_formatted( + envP, XMLRPC_TYPE_ERROR, "Non-struct type supplied for " + "'S' specifier"); + else { + xmlrpc_value ** const valptr = + (xmlrpc_value**) va_arg(*args, xmlrpc_value**); + *valptr = valueP; + if (!oldstyleMemMgmt) + xmlrpc_INCREF(valueP); + } + break; + + case '(': + if (xmlrpc_value_type(valueP) != XMLRPC_TYPE_ARRAY) + xmlrpc_env_set_fault_formatted( + envP, XMLRPC_TYPE_ERROR, "Non-array type supplied for " + "'()' specifier"); + else { + parsearray(envP, valueP, format, ')', args, oldstyleMemMgmt); + (*format)++; + } + break; + + case '{': + if (xmlrpc_value_type(valueP) != XMLRPC_TYPE_STRUCT) + xmlrpc_env_set_fault_formatted( + envP, XMLRPC_TYPE_ERROR, "Non-struct type supplied for " + "'{}' specifier"); + else { + parsestruct(envP, valueP, format, '}', args, oldstyleMemMgmt); + (*format)++; + } + break; + + default: + xmlrpc_env_set_fault_formatted( + envP, XMLRPC_INTERNAL_ERROR, "Invalid format character '%c'", + formatSpecChar); + } +} + + + +void +xmlrpc_decompose_value_va(xmlrpc_env * const envP, + xmlrpc_value * const value, + const char * const format, + va_list args) { + + const char *format_copy; + va_list args_copy; + + XMLRPC_ASSERT_ENV_OK(envP); + XMLRPC_ASSERT_VALUE_OK(value); + XMLRPC_ASSERT(format != NULL); + + format_copy = format; + VA_LIST_COPY(args_copy, args); + decomposeValue(envP, value, &format_copy, &args_copy, false); + if (!envP->fault_occurred) { + XMLRPC_ASSERT(*format_copy == '\0'); + } +} + + + +void +xmlrpc_decompose_value(xmlrpc_env * const envP, + xmlrpc_value * const value, + const char * const format, + ...) { + + va_list args; + + va_start(args, format); + xmlrpc_decompose_value_va(envP, value, format, args); + va_end(args); +} + + + +void +xmlrpc_parse_value_va(xmlrpc_env * const envP, + xmlrpc_value * const value, + const char * const format, + va_list args) { + + const char *format_copy; + va_list args_copy; + + XMLRPC_ASSERT_ENV_OK(envP); + XMLRPC_ASSERT_VALUE_OK(value); + XMLRPC_ASSERT(format != NULL); + + format_copy = format; + VA_LIST_COPY(args_copy, args); + decomposeValue(envP, value, &format_copy, &args_copy, true); + if (!envP->fault_occurred) { + XMLRPC_ASSERT(*format_copy == '\0'); + } +} + + + +void +xmlrpc_parse_value(xmlrpc_env * const envP, + xmlrpc_value * const value, + const char * const format, + ...) { + + va_list args; + + va_start(args, format); + xmlrpc_parse_value_va(envP, value, format, args); + va_end(args); +} + + + +/* Copyright (C) 2001 by First Peer, Inc. All rights reserved. +** Copyright (C) 2001 by Eric Kidd. All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +** ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +** OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +** HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +** LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +** OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +** SUCH DAMAGE. */ diff --git a/src/xmlrpc_client.c b/src/xmlrpc_client.c new file mode 100644 index 0000000..5edaa9f --- /dev/null +++ b/src/xmlrpc_client.c @@ -0,0 +1,1011 @@ +/* Copyright information is at end of file */ + +#include "xmlrpc_config.h" + +#undef PACKAGE +#undef VERSION + +#include +#include +#include +#include +#include +#include +#include + +#include "bool.h" +#include "mallocvar.h" + +#include "xmlrpc-c/base.h" +#include "xmlrpc-c/base_int.h" +#include "xmlrpc-c/string_int.h" +#include "xmlrpc-c/client.h" +#include "xmlrpc-c/client_int.h" +/* transport_config.h defines XMLRPC_DEFAULT_TRANSPORT, + MUST_BUILD_WININET_CLIENT, MUST_BUILD_CURL_CLIENT, + MUST_BUILD_LIBWWW_CLIENT +*/ +#include "transport_config.h" + +#if MUST_BUILD_WININET_CLIENT +#include "xmlrpc_wininet_transport.h" +#endif +#if MUST_BUILD_CURL_CLIENT +#include "xmlrpc_curl_transport.h" +#endif +#if MUST_BUILD_LIBWWW_CLIENT +#include "xmlrpc_libwww_transport.h" +#endif + +struct xmlrpc_client { +/*---------------------------------------------------------------------------- + This represents a client object. +-----------------------------------------------------------------------------*/ + struct xmlrpc_client_transport * transportP; + struct xmlrpc_client_transport_ops clientTransportOps; +}; + + + +typedef struct xmlrpc_call_info { + /* These fields are used when performing asynchronous calls. + ** The _asynch_data_holder contains server_url, method_name and + ** param_array, so it's the only thing we need to free. */ + xmlrpc_value *_asynch_data_holder; + char *server_url; + char *method_name; + xmlrpc_value *param_array; + xmlrpc_response_handler callback; + void *user_data; + + /* The serialized XML data passed to this call. We keep this around + ** for use by our source_anchor field. */ + xmlrpc_mem_block *serialized_xml; +} xmlrpc_call_info; + + + +/*========================================================================= + Global Constant Setup/Teardown +=========================================================================*/ + +static void +callTransportSetup(xmlrpc_env * const envP, + xmlrpc_transport_setup setupFn) { + + if (setupFn) + setupFn(envP); +} + + + +static void +setupTransportGlobalConst(xmlrpc_env * const envP) { + +#if MUST_BUILD_WININET_CLIENT + if (!envP->fault_occurred) + callTransportSetup(envP, + xmlrpc_wininet_transport_ops.setup_global_const); +#endif +#if MUST_BUILD_CURL_CLIENT + if (!envP->fault_occurred) + callTransportSetup(envP, + xmlrpc_curl_transport_ops.setup_global_const); +#endif +#if MUST_BUILD_LIBWWW_CLIENT + if (!envP->fault_occurred) + callTransportSetup(envP, + xmlrpc_libwww_transport_ops.setup_global_const); +#endif +} + + + +static void +callTransportTeardown(xmlrpc_transport_teardown teardownFn) { + + if (teardownFn) + teardownFn(); +} + + + +static void +teardownTransportGlobalConst(void) { + +#if MUST_BUILD_WININET_CLIENT + callTransportTeardown( + xmlrpc_wininet_transport_ops.teardown_global_const); +#endif +#if MUST_BUILD_CURL_CLIENT + callTransportTeardown( + xmlrpc_curl_transport_ops.teardown_global_const); +#endif +#if MUST_BUILD_LIBWWW_CLIENT + callTransportTeardown( + xmlrpc_libwww_transport_ops.teardown_global_const); +#endif +} + + + +static unsigned int constSetupCount = 0; + + +void +xmlrpc_client_setup_global_const(xmlrpc_env * const envP) { +/*---------------------------------------------------------------------------- + Set up pseudo-constant global variables (they'd be constant, except that + the library loader doesn't set them. An explicit call from the loaded + program does). + + This function is not thread-safe. The user is supposed to call it + (perhaps cascaded down from a multitude of higher level libraries) + as part of early program setup, when the program is only one thread. +-----------------------------------------------------------------------------*/ + if (constSetupCount == 0) + setupTransportGlobalConst(envP); + + ++constSetupCount; +} + + + +void +xmlrpc_client_teardown_global_const(void) { +/*---------------------------------------------------------------------------- + Complement to xmlrpc_client_setup_global_const(). + + This function is not thread-safe. The user is supposed to call it + (perhaps cascaded down from a multitude of higher level libraries) + as part of final program cleanup, when the program is only one thread. +-----------------------------------------------------------------------------*/ + assert(constSetupCount > 0); + + --constSetupCount; + + if (constSetupCount == 0) + teardownTransportGlobalConst(); +} + + + +/*========================================================================= + Client Create/Destroy +=========================================================================*/ + +static void +getTransportOps(xmlrpc_env * const envP, + const char * const transportName, + struct xmlrpc_client_transport_ops * const opsP) { + + if (false) { + } +#if MUST_BUILD_WININET_CLIENT + else if (strcmp(transportName, "wininet") == 0) + *opsP = xmlrpc_wininet_transport_ops; +#endif +#if MUST_BUILD_CURL_CLIENT + else if (strcmp(transportName, "curl") == 0) + *opsP = xmlrpc_curl_transport_ops; +#endif +#if MUST_BUILD_LIBWWW_CLIENT + else if (strcmp(transportName, "libwww") == 0) + *opsP = xmlrpc_libwww_transport_ops; +#endif + else + xmlrpc_env_set_fault_formatted( + envP, XMLRPC_INTERNAL_ERROR, + "Unrecognized XML transport name '%s'", transportName); +} + + + +static void +getTransportParmsFromClientParms( + xmlrpc_env * const envP, + const struct xmlrpc_clientparms * const clientparmsP, + unsigned int const parmSize, + const struct xmlrpc_xportparms ** const transportparmsPP, + size_t * const transportparmSizeP) { + + if (parmSize < XMLRPC_CPSIZE(transportparmsP) || + clientparmsP->transportparmsP == NULL) { + + *transportparmsPP = NULL; + *transportparmSizeP = 0; + } else { + *transportparmsPP = clientparmsP->transportparmsP; + if (parmSize < XMLRPC_CPSIZE(transportparm_size)) + xmlrpc_faultf(envP, "Your 'clientparms' argument contains the " + "transportparmsP member, " + "but no transportparms_size member"); + else + *transportparmSizeP = clientparmsP->transportparm_size; + } +} + + + +static void +getTransportInfo(xmlrpc_env * const envP, + const struct xmlrpc_clientparms * const clientparmsP, + unsigned int const parmSize, + const char ** const transportNameP, + const struct xmlrpc_xportparms ** const transportparmsPP, + size_t * const transportparmSizeP) { + + getTransportParmsFromClientParms( + envP, clientparmsP, parmSize, + transportparmsPP, transportparmSizeP); + + if (!envP->fault_occurred) { + if (parmSize < XMLRPC_CPSIZE(transport) || + clientparmsP->transport == NULL) { + + /* He didn't specify a transport class. Use the default */ + + *transportNameP = xmlrpc_client_get_default_transport(envP); + if (*transportparmsPP) + xmlrpc_faultf(envP, + "You specified transport parameters, but did not " + "specify a transport type. Parameters are specific to " + "a particular type."); + } else + *transportNameP = clientparmsP->transport; + } +} + + + +void +xmlrpc_client_create(xmlrpc_env * const envP, + int const flags, + const char * const appname, + const char * const appversion, + const struct xmlrpc_clientparms * const clientparmsP, + unsigned int const parmSize, + xmlrpc_client ** const clientPP) { + + XMLRPC_ASSERT_PTR_OK(clientPP); + + if (constSetupCount == 0) { + xmlrpc_faultf(envP, + "You have not called " + "xmlrpc_client_setup_global_const()."); + /* Impl note: We can't just call it now because it isn't + thread-safe. + */ + } else { + xmlrpc_client * clientP; + + MALLOCVAR(clientP); + + if (clientP == NULL) + xmlrpc_faultf(envP, "Unable to allocate memory for " + "client descriptor."); + else { + const char * transportName; + const struct xmlrpc_xportparms * transportparmsP; + size_t transportparmSize; + + getTransportInfo(envP, clientparmsP, parmSize, &transportName, + &transportparmsP, &transportparmSize); + + if (!envP->fault_occurred) { + getTransportOps(envP, transportName, + &clientP->clientTransportOps); + if (!envP->fault_occurred) { + /* The following call is not thread-safe */ + clientP->clientTransportOps.create( + envP, flags, appname, appversion, + transportparmsP, transportparmSize, + &clientP->transportP); + if (!envP->fault_occurred) + *clientPP = clientP; + } + } + if (envP->fault_occurred) + free(clientP); + } + } +} + + + +void +xmlrpc_client_destroy(xmlrpc_client * const clientP) { + + XMLRPC_ASSERT_PTR_OK(clientP); + + clientP->clientTransportOps.destroy(clientP->transportP); + + free(clientP); +} + + + +/*========================================================================= + Call/Response Utilities +=========================================================================*/ + +static void +makeCallXml(xmlrpc_env * const envP, + const char * const methodName, + xmlrpc_value * const paramArrayP, + xmlrpc_mem_block ** const callXmlPP) { + + XMLRPC_ASSERT_VALUE_OK(paramArrayP); + XMLRPC_ASSERT_PTR_OK(callXmlPP); + + if (methodName == NULL) + xmlrpc_env_set_fault_formatted( + envP, XMLRPC_INTERNAL_ERROR, + "method name argument is NULL pointer"); + else { + xmlrpc_mem_block * callXmlP; + + callXmlP = XMLRPC_MEMBLOCK_NEW(char, envP, 0); + if (!envP->fault_occurred) { + xmlrpc_serialize_call(envP, callXmlP, methodName, paramArrayP); + + *callXmlPP = callXmlP; + + if (envP->fault_occurred) + XMLRPC_MEMBLOCK_FREE(char, callXmlP); + } + } +} + + + +/*========================================================================= + xmlrpc_server_info +=========================================================================*/ + +xmlrpc_server_info * +xmlrpc_server_info_new(xmlrpc_env * const envP, + const char * const serverUrl) { + + xmlrpc_server_info * serverInfoP; + + XMLRPC_ASSERT_ENV_OK(envP); + XMLRPC_ASSERT_PTR_OK(serverUrl); + + /* Allocate our memory blocks. */ + MALLOCVAR(serverInfoP); + if (serverInfoP == NULL) + xmlrpc_faultf(envP, "Couldn't allocate memory for xmlrpc_server_info"); + else { + memset(serverInfoP, 0, sizeof(xmlrpc_server_info)); + + serverInfoP->_server_url = strdup(serverUrl); + if (serverInfoP->_server_url == NULL) + xmlrpc_faultf(envP, "Couldn't allocate memory for server URL"); + else { + serverInfoP->_http_basic_auth = NULL; + if (envP->fault_occurred) + xmlrpc_strfree(serverInfoP->_server_url); + } + if (envP->fault_occurred) + free(serverInfoP); + } + return serverInfoP; +} + + + +xmlrpc_server_info * +xmlrpc_server_info_copy(xmlrpc_env * const envP, + xmlrpc_server_info * const aserverInfoP) { + + xmlrpc_server_info * serverInfoP; + + XMLRPC_ASSERT_ENV_OK(envP); + XMLRPC_ASSERT_PTR_OK(aserverInfoP); + + MALLOCVAR(serverInfoP); + if (serverInfoP == NULL) + xmlrpc_faultf(envP, + "Couldn't allocate memory for xmlrpc_server_info"); + else { + serverInfoP->_server_url = strdup(aserverInfoP->_server_url); + if (serverInfoP->_server_url == NULL) + xmlrpc_faultf(envP, "Couldn't allocate memory for server URL"); + else { + if (aserverInfoP->_http_basic_auth == NULL) + serverInfoP->_http_basic_auth = NULL; + else { + serverInfoP->_http_basic_auth = + strdup(aserverInfoP->_http_basic_auth); + if (serverInfoP->_http_basic_auth == NULL) + xmlrpc_faultf(envP, "Couldn't allocate memory " + "for authentication info"); + } + if (envP->fault_occurred) + xmlrpc_strfree(serverInfoP->_server_url); + } + if (envP->fault_occurred) + free(serverInfoP); + } + return serverInfoP; +} + + + +void +xmlrpc_server_info_free(xmlrpc_server_info * const serverInfoP) { + + XMLRPC_ASSERT_PTR_OK(serverInfoP); + XMLRPC_ASSERT(serverInfoP->_server_url != XMLRPC_BAD_POINTER); + + if (serverInfoP->_http_basic_auth) + free(serverInfoP->_http_basic_auth); + serverInfoP->_http_basic_auth = XMLRPC_BAD_POINTER; + free(serverInfoP->_server_url); + serverInfoP->_server_url = XMLRPC_BAD_POINTER; + free(serverInfoP); +} + + + +/*========================================================================= + Synchronous Call +=========================================================================*/ + +void +xmlrpc_client_transport_call2( + xmlrpc_env * const envP, + xmlrpc_client * const clientP, + const xmlrpc_server_info * const serverP, + xmlrpc_mem_block * const callXmlP, + xmlrpc_mem_block ** const respXmlPP) { + + XMLRPC_ASSERT_PTR_OK(clientP); + XMLRPC_ASSERT_PTR_OK(serverP); + XMLRPC_ASSERT_PTR_OK(callXmlP); + XMLRPC_ASSERT_PTR_OK(respXmlPP); + + clientP->clientTransportOps.call( + envP, clientP->transportP, serverP, callXmlP, + respXmlPP); +} + + + +void +xmlrpc_client_call2(xmlrpc_env * const envP, + struct xmlrpc_client * const clientP, + const xmlrpc_server_info * const serverInfoP, + const char * const methodName, + xmlrpc_value * const paramArrayP, + xmlrpc_value ** const resultPP) { + + xmlrpc_mem_block * callXmlP; + + XMLRPC_ASSERT_ENV_OK(envP); + XMLRPC_ASSERT_PTR_OK(clientP); + XMLRPC_ASSERT_PTR_OK(serverInfoP); + XMLRPC_ASSERT_PTR_OK(paramArrayP); + + makeCallXml(envP, methodName, paramArrayP, &callXmlP); + + if (!envP->fault_occurred) { + xmlrpc_mem_block * respXmlP; + + xmlrpc_traceXml("XML-RPC CALL", + XMLRPC_MEMBLOCK_CONTENTS(char, callXmlP), + XMLRPC_MEMBLOCK_SIZE(char, callXmlP)); + + clientP->clientTransportOps.call( + envP, clientP->transportP, serverInfoP, callXmlP, &respXmlP); + if (!envP->fault_occurred) { + int faultCode; + const char * faultString; + + xmlrpc_traceXml("XML-RPC RESPONSE", + XMLRPC_MEMBLOCK_CONTENTS(char, respXmlP), + XMLRPC_MEMBLOCK_SIZE(char, respXmlP)); + + xmlrpc_parse_response2( + envP, + XMLRPC_MEMBLOCK_CONTENTS(char, respXmlP), + XMLRPC_MEMBLOCK_SIZE(char, respXmlP), + resultPP, &faultCode, &faultString); + + if (!envP->fault_occurred) { + if (faultString) { + xmlrpc_env_set_fault_formatted( + envP, faultCode, + "RPC failed at server. %s", faultString); + xmlrpc_strfree(faultString); + } else + XMLRPC_ASSERT_VALUE_OK(*resultPP); + } + XMLRPC_MEMBLOCK_FREE(char, respXmlP); + } + XMLRPC_MEMBLOCK_FREE(char, callXmlP); + } +} + + + +static void +clientCall2f_va(xmlrpc_env * const envP, + xmlrpc_client * const clientP, + const char * const serverUrl, + const char * const methodName, + const char * const format, + xmlrpc_value ** const resultPP, + va_list args) { + + xmlrpc_value * argP; + xmlrpc_env argenv; + const char * suffix; + + XMLRPC_ASSERT_ENV_OK(envP); + XMLRPC_ASSERT_PTR_OK(serverUrl); + XMLRPC_ASSERT_PTR_OK(methodName); + XMLRPC_ASSERT_PTR_OK(format); + XMLRPC_ASSERT_PTR_OK(resultPP); + + /* Build our argument value. */ + xmlrpc_env_init(&argenv); + xmlrpc_build_value_va(&argenv, format, args, &argP, &suffix); + if (argenv.fault_occurred) + xmlrpc_env_set_fault_formatted( + envP, argenv.fault_code, "Invalid RPC arguments. " + "The format argument must indicate a single array, and the " + "following arguments must correspond to that format argument. " + "The failure is: %s", + argenv.fault_string); + else { + XMLRPC_ASSERT_VALUE_OK(argP); + + if (*suffix != '\0') + xmlrpc_faultf(envP, "Junk after the argument specifier: '%s'. " + "There must be exactly one argument.", + suffix); + else { + xmlrpc_server_info * serverInfoP; + + serverInfoP = xmlrpc_server_info_new(envP, serverUrl); + + if (!envP->fault_occurred) { + /* Perform the actual XML-RPC call. */ + xmlrpc_client_call2(envP, clientP, + serverInfoP, methodName, argP, resultPP); + if (!envP->fault_occurred) + XMLRPC_ASSERT_VALUE_OK(*resultPP); + xmlrpc_server_info_free(serverInfoP); + } + } + xmlrpc_DECREF(argP); + } + xmlrpc_env_clean(&argenv); +} + + + +void +xmlrpc_client_call2f(xmlrpc_env * const envP, + xmlrpc_client * const clientP, + const char * const serverUrl, + const char * const methodName, + xmlrpc_value ** const resultPP, + const char * const format, + ...) { + + va_list args; + + va_start(args, format); + clientCall2f_va(envP, clientP, serverUrl, + methodName, format, resultPP, args); + va_end(args); +} + + + +/*========================================================================= + Asynchronous Call +=========================================================================*/ + +static void +call_info_set_asynch_data(xmlrpc_env * const env, + xmlrpc_call_info * const info, + const char * const server_url, + const char * const method_name, + xmlrpc_value * const argP, + xmlrpc_response_handler responseHandler, + void * const user_data) { + + xmlrpc_value *holder; + + /* Error-handling preconditions. */ + holder = NULL; + + XMLRPC_ASSERT_ENV_OK(env); + XMLRPC_ASSERT_PTR_OK(info); + XMLRPC_ASSERT(info->_asynch_data_holder == NULL); + XMLRPC_ASSERT_PTR_OK(server_url); + XMLRPC_ASSERT_PTR_OK(method_name); + XMLRPC_ASSERT_VALUE_OK(argP); + + /* Install our callback and user_data. + ** (We're not responsible for destroying the user_data.) */ + info->callback = responseHandler; + info->user_data = user_data; + + /* Build an XML-RPC data structure to hold our other data. This makes + ** copies of server_url and method_name, and increments the reference + ** to the argument *argP. */ + holder = xmlrpc_build_value(env, "(ssV)", + server_url, method_name, argP); + XMLRPC_FAIL_IF_FAULT(env); + + /* Parse the newly-allocated structure into our public member variables. + ** This doesn't make any new references, so we can dispose of the whole + ** thing by DECREF'ing the one master reference. Nifty, huh? */ + xmlrpc_parse_value(env, holder, "(ssV)", + &info->server_url, + &info->method_name, + &info->param_array); + XMLRPC_FAIL_IF_FAULT(env); + + /* Hand over ownership of the holder to the call_info struct. */ + info->_asynch_data_holder = holder; + holder = NULL; + + cleanup: + if (env->fault_occurred) { + if (holder) + xmlrpc_DECREF(holder); + } +} + + + +static void +call_info_free(xmlrpc_call_info * const callInfoP) { + + /* Assume the worst.. That only parts of the call_info are valid. */ + + XMLRPC_ASSERT_PTR_OK(callInfoP); + + /* If this has been allocated, we're responsible for destroying it. */ + if (callInfoP->_asynch_data_holder) + xmlrpc_DECREF(callInfoP->_asynch_data_holder); + + /* Now we can blow away the XML data. */ + if (callInfoP->serialized_xml) + xmlrpc_mem_block_free(callInfoP->serialized_xml); + + free(callInfoP); +} + + + +static void +call_info_new(xmlrpc_env * const envP, + const char * const methodName, + xmlrpc_value * const paramArrayP, + xmlrpc_call_info ** const callInfoPP) { +/*---------------------------------------------------------------------------- + Create a call_info object. A call_info object represents an XML-RPC + call. +-----------------------------------------------------------------------------*/ + struct xmlrpc_call_info * callInfoP; + + XMLRPC_ASSERT_PTR_OK(paramArrayP); + XMLRPC_ASSERT_PTR_OK(callInfoPP); + + MALLOCVAR(callInfoP); + if (callInfoP == NULL) + xmlrpc_env_set_fault_formatted( + envP, XMLRPC_INTERNAL_ERROR, + "Couldn't allocate memory for xmlrpc_call_info"); + else { + xmlrpc_mem_block * callXmlP; + + /* Clear contents. */ + memset(callInfoP, 0, sizeof(*callInfoP)); + + makeCallXml(envP, methodName, paramArrayP, &callXmlP); + + if (!envP->fault_occurred) { + xmlrpc_traceXml("XML-RPC CALL", + XMLRPC_MEMBLOCK_CONTENTS(char, callXmlP), + XMLRPC_MEMBLOCK_SIZE(char, callXmlP)); + + callInfoP->serialized_xml = callXmlP; + + *callInfoPP = callInfoP; + + if (envP->fault_occurred) + free(callInfoP); + } + } +} + + + +void +xmlrpc_client_event_loop_finish(xmlrpc_client * const clientP) { + + XMLRPC_ASSERT_PTR_OK(clientP); + + clientP->clientTransportOps.finish_asynch( + clientP->transportP, timeout_no, 0); +} + + + +void +xmlrpc_client_event_loop_finish_timeout(xmlrpc_client * const clientP, + xmlrpc_timeout const timeout) { + + XMLRPC_ASSERT_PTR_OK(clientP); + + clientP->clientTransportOps.finish_asynch( + clientP->transportP, timeout_yes, timeout); +} + + + +static void +asynchComplete(struct xmlrpc_call_info * const callInfoP, + xmlrpc_mem_block * const responseXmlP, + xmlrpc_env const transportEnv) { +/*---------------------------------------------------------------------------- + Complete an asynchronous XML-RPC call request. + + This includes calling the user's RPC completion routine. + + 'transportEnv' describes an error that the transport + encountered in processing the call. If the transport successfully + sent the call to the server and processed the response but the + server failed the call, 'transportEnv' indicates no error, and the + response in *responseXmlP might very well indicate that the server + failed the request. +-----------------------------------------------------------------------------*/ + xmlrpc_env env; + xmlrpc_value * resultP; + + xmlrpc_env_init(&env); + + resultP = NULL; /* Just to quiet compiler warning */ + + if (transportEnv.fault_occurred) + xmlrpc_env_set_fault_formatted( + &env, transportEnv.fault_code, + "Client transport failed to execute the RPC. %s", + transportEnv.fault_string); + + if (!env.fault_occurred) { + int faultCode; + const char * faultString; + + xmlrpc_parse_response2(&env, + XMLRPC_MEMBLOCK_CONTENTS(char, responseXmlP), + XMLRPC_MEMBLOCK_SIZE(char, responseXmlP), + &resultP, &faultCode, &faultString); + + if (!env.fault_occurred) { + if (faultString) { + xmlrpc_env_set_fault_formatted( + &env, faultCode, + "RPC failed at server. %s", faultString); + xmlrpc_strfree(faultString); + } + } + } + /* Call the user's callback function with the result */ + (*callInfoP->callback)(callInfoP->server_url, + callInfoP->method_name, + callInfoP->param_array, + callInfoP->user_data, &env, resultP); + + if (!env.fault_occurred) + xmlrpc_DECREF(resultP); + + call_info_free(callInfoP); + + xmlrpc_env_clean(&env); +} + + + +void +xmlrpc_client_start_rpc(xmlrpc_env * const envP, + struct xmlrpc_client * const clientP, + xmlrpc_server_info * const serverInfoP, + const char * const methodName, + xmlrpc_value * const argP, + xmlrpc_response_handler responseHandler, + void * const userData) { + + xmlrpc_call_info * callInfoP; + + XMLRPC_ASSERT_ENV_OK(envP); + XMLRPC_ASSERT_PTR_OK(clientP); + XMLRPC_ASSERT_PTR_OK(serverInfoP); + XMLRPC_ASSERT_PTR_OK(methodName); + XMLRPC_ASSERT_PTR_OK(responseHandler); + XMLRPC_ASSERT_VALUE_OK(argP); + + call_info_new(envP, methodName, argP, &callInfoP); + if (!envP->fault_occurred) { + call_info_set_asynch_data(envP, callInfoP, + serverInfoP->_server_url, methodName, + argP, responseHandler, userData); + if (!envP->fault_occurred) + clientP->clientTransportOps.send_request( + envP, clientP->transportP, serverInfoP, + callInfoP->serialized_xml, + &asynchComplete, callInfoP); + + if (envP->fault_occurred) + call_info_free(callInfoP); + else { + /* asynchComplete() will free *callInfoP */ + } + } +} + + + +void +xmlrpc_client_start_rpcf(xmlrpc_env * const envP, + xmlrpc_client * const clientP, + const char * const serverUrl, + const char * const methodName, + xmlrpc_response_handler responseHandler, + void * const userData, + const char * const format, + ...) { + + va_list args; + xmlrpc_value * paramArrayP; + const char * suffix; + + XMLRPC_ASSERT_PTR_OK(serverUrl); + XMLRPC_ASSERT_PTR_OK(format); + + /* Build our argument array. */ + va_start(args, format); + xmlrpc_build_value_va(envP, format, args, ¶mArrayP, &suffix); + va_end(args); + if (!envP->fault_occurred) { + if (*suffix != '\0') + xmlrpc_faultf(envP, "Junk after the argument " + "specifier: '%s'. " + "There must be exactly one arument.", + suffix); + else { + xmlrpc_server_info * serverInfoP; + + serverInfoP = xmlrpc_server_info_new(envP, serverUrl); + if (!envP->fault_occurred) { + xmlrpc_client_start_rpc( + envP, clientP, + serverInfoP, methodName, paramArrayP, + responseHandler, userData); + } + xmlrpc_server_info_free(serverInfoP); + } + xmlrpc_DECREF(paramArrayP); + } +} + + + +/*========================================================================= + Miscellaneous +=========================================================================*/ + +void +xmlrpc_server_info_set_basic_auth(xmlrpc_env * const envP, + xmlrpc_server_info * const serverP, + const char * const username, + const char * const password) { + + size_t username_len, password_len, raw_token_len; + char *raw_token; + xmlrpc_mem_block *token; + char *token_data, *auth_type, *auth_header; + size_t token_len, auth_type_len, auth_header_len; + + /* Error-handling preconditions. */ + raw_token = NULL; + token = NULL; + token_data = auth_type = auth_header = NULL; + + XMLRPC_ASSERT_ENV_OK(envP); + XMLRPC_ASSERT_PTR_OK(serverP); + XMLRPC_ASSERT_PTR_OK(username); + XMLRPC_ASSERT_PTR_OK(password); + + /* Calculate some lengths. */ + username_len = strlen(username); + password_len = strlen(password); + raw_token_len = username_len + password_len + 1; + + /* Build a raw token of the form 'username:password'. */ + raw_token = (char*) malloc(raw_token_len + 1); + XMLRPC_FAIL_IF_NULL(raw_token, envP, XMLRPC_INTERNAL_ERROR, + "Couldn't allocate memory for auth token"); + strcpy(raw_token, username); + raw_token[username_len] = ':'; + strcpy(&raw_token[username_len + 1], password); + + /* Encode our raw token using Base64. */ + token = xmlrpc_base64_encode_without_newlines(envP, + (unsigned char*) raw_token, + raw_token_len); + XMLRPC_FAIL_IF_FAULT(envP); + token_data = XMLRPC_TYPED_MEM_BLOCK_CONTENTS(char, token); + token_len = XMLRPC_TYPED_MEM_BLOCK_SIZE(char, token); + + /* Build our actual header value. (I hate string processing in C.) */ + auth_type = "Basic "; + auth_type_len = strlen(auth_type); + auth_header_len = auth_type_len + token_len; + auth_header = (char*) malloc(auth_header_len + 1); + XMLRPC_FAIL_IF_NULL(auth_header, envP, XMLRPC_INTERNAL_ERROR, + "Couldn't allocate memory for auth header"); + memcpy(auth_header, auth_type, auth_type_len); + memcpy(&auth_header[auth_type_len], token_data, token_len); + auth_header[auth_header_len] = '\0'; + + /* Clean up any pre-existing authentication information, and install + ** the new value. */ + if (serverP->_http_basic_auth) + free(serverP->_http_basic_auth); + serverP->_http_basic_auth = auth_header; + + cleanup: + if (raw_token) + free(raw_token); + if (token) + xmlrpc_mem_block_free(token); + if (envP->fault_occurred) { + if (auth_header) + free(auth_header); + } +} + + + +const char * +xmlrpc_client_get_default_transport(xmlrpc_env * const env ATTR_UNUSED) { + + return XMLRPC_DEFAULT_TRANSPORT; +} + + + +/* Copyright (C) 2001 by First Peer, Inc. All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +** ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +** OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +** HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +** LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +** OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +** SUCH DAMAGE. +*/ diff --git a/src/xmlrpc_client_global.c b/src/xmlrpc_client_global.c new file mode 100644 index 0000000..1928b9a --- /dev/null +++ b/src/xmlrpc_client_global.c @@ -0,0 +1,414 @@ +#include + +#include "xmlrpc_config.h" + +#include "bool.h" + +#include +#include +#include +#include + +/*========================================================================= + Global Client +=========================================================================*/ + +static struct xmlrpc_client * globalClientP; +static bool globalClientExists = false; + + +void +xmlrpc_client_init2(xmlrpc_env * const envP, + int const flags, + const char * const appname, + const char * const appversion, + const struct xmlrpc_clientparms * const clientparmsP, + unsigned int const parmSize) { +/*---------------------------------------------------------------------------- + This function is not thread-safe. +-----------------------------------------------------------------------------*/ + if (globalClientExists) + xmlrpc_faultf( + envP, + "Xmlrpc-c global client instance has already been created " + "(need to call xmlrpc_client_cleanup() before you can " + "reinitialize)."); + else { + /* The following call is not thread-safe */ + xmlrpc_client_setup_global_const(envP); + if (!envP->fault_occurred) { + xmlrpc_client_create(envP, flags, appname, appversion, + clientparmsP, parmSize, &globalClientP); + if (!envP->fault_occurred) + globalClientExists = true; + + if (envP->fault_occurred) + xmlrpc_client_teardown_global_const(); + } + } +} + + + +void +xmlrpc_client_init(int const flags, + const char * const appname, + const char * const appversion) { +/*---------------------------------------------------------------------------- + This function is not thread-safe. +-----------------------------------------------------------------------------*/ + struct xmlrpc_clientparms clientparms; + + /* As our interface does not allow for failure, we just fail silently ! */ + + xmlrpc_env env; + xmlrpc_env_init(&env); + + clientparms.transport = NULL; + + /* The following call is not thread-safe */ + xmlrpc_client_init2(&env, flags, + appname, appversion, + &clientparms, XMLRPC_CPSIZE(transport)); + + xmlrpc_env_clean(&env); +} + + + +void +xmlrpc_client_cleanup() { +/*---------------------------------------------------------------------------- + This function is not thread-safe +-----------------------------------------------------------------------------*/ + XMLRPC_ASSERT(globalClientExists); + + xmlrpc_client_destroy(globalClientP); + + globalClientExists = false; + + /* The following call is not thread-safe */ + xmlrpc_client_teardown_global_const(); +} + + + +static void +validateGlobalClientExists(xmlrpc_env * const envP) { + + if (!globalClientExists) + xmlrpc_faultf(envP, + "Xmlrpc-c global client instance " + "has not been created " + "(need to call xmlrpc_client_init2())."); +} + + + +void +xmlrpc_client_transport_call( + xmlrpc_env * const envP, + void * const reserved ATTR_UNUSED, + /* for client handle */ + const xmlrpc_server_info * const serverP, + xmlrpc_mem_block * const callXmlP, + xmlrpc_mem_block ** const respXmlPP) { + + validateGlobalClientExists(envP); + if (!envP->fault_occurred) + xmlrpc_client_transport_call2(envP, globalClientP, serverP, + callXmlP, respXmlPP); +} + + + +static void +clientCall_va(xmlrpc_env * const envP, + const xmlrpc_server_info * const serverInfoP, + const char * const methodName, + const char * const format, + va_list args, + xmlrpc_value ** const resultPP) { + + validateGlobalClientExists(envP); + if (!envP->fault_occurred) { + xmlrpc_value * paramArrayP; + const char * suffix; + + xmlrpc_build_value_va(envP, format, args, ¶mArrayP, &suffix); + + if (!envP->fault_occurred) { + if (*suffix != '\0') + xmlrpc_faultf(envP, "Junk after the argument " + "specifier: '%s'. " + "There must be exactly one arument.", + suffix); + else + xmlrpc_client_call2(envP, globalClientP, serverInfoP, + methodName, paramArrayP, resultPP); + + xmlrpc_DECREF(paramArrayP); + } + } +} + + + +xmlrpc_value * +xmlrpc_client_call(xmlrpc_env * const envP, + const char * const serverUrl, + const char * const methodName, + const char * const format, + ...) { + + xmlrpc_value * resultP; + + xmlrpc_server_info * serverInfoP; + + serverInfoP = xmlrpc_server_info_new(envP, serverUrl); + + if (!envP->fault_occurred) { + va_list args; + va_start(args, format); + + clientCall_va(envP, serverInfoP, methodName, format, args, &resultP); + + va_end(args); + xmlrpc_server_info_free(serverInfoP); + } + + return resultP; +} + + + +xmlrpc_value * +xmlrpc_client_call_server(xmlrpc_env * const envP, + const xmlrpc_server_info * const serverP, + const char * const methodName, + const char * const format, + ...) { + + va_list args; + xmlrpc_value * resultP; + + va_start(args, format); + clientCall_va(envP, serverP, methodName, format, args, &resultP); + va_end(args); + + return resultP; +} + + + +xmlrpc_value * +xmlrpc_client_call_server_params( + xmlrpc_env * const envP, + const xmlrpc_server_info * const serverInfoP, + const char * const methodName, + xmlrpc_value * const paramArrayP) { + + xmlrpc_value * resultP; + + validateGlobalClientExists(envP); + + if (!envP->fault_occurred) + xmlrpc_client_call2(envP, globalClientP, + serverInfoP, methodName, paramArrayP, + &resultP); + + return resultP; +} + + + +xmlrpc_value * +xmlrpc_client_call_params(xmlrpc_env * const envP, + const char * const serverUrl, + const char * const methodName, + xmlrpc_value * const paramArrayP) { + + xmlrpc_value * resultP; + + validateGlobalClientExists(envP); + + if (!envP->fault_occurred) { + xmlrpc_server_info * serverInfoP; + + serverInfoP = xmlrpc_server_info_new(envP, serverUrl); + + if (!envP->fault_occurred) { + xmlrpc_client_call2(envP, globalClientP, + serverInfoP, methodName, paramArrayP, + &resultP); + + xmlrpc_server_info_free(serverInfoP); + } + } + return resultP; +} + + + +void +xmlrpc_client_call_server_asynch_params( + xmlrpc_server_info * const serverInfoP, + const char * const methodName, + xmlrpc_response_handler responseHandler, + void * const userData, + xmlrpc_value * const paramArrayP) { + + xmlrpc_env env; + + xmlrpc_env_init(&env); + + validateGlobalClientExists(&env); + + if (!env.fault_occurred) + xmlrpc_client_start_rpc(&env, globalClientP, + serverInfoP, methodName, paramArrayP, + responseHandler, userData); + + if (env.fault_occurred) { + /* Unfortunately, we have no way to return an error and the + regular callback for a failed RPC is designed to have the + parameter array passed to it. This was probably an oversight + of the original asynch design, but now we have to be as + backward compatible as possible, so we do this: + */ + (*responseHandler)(serverInfoP->_server_url, + methodName, paramArrayP, userData, + &env, NULL); + } + xmlrpc_env_clean(&env); +} + + + +void +xmlrpc_client_call_asynch(const char * const serverUrl, + const char * const methodName, + xmlrpc_response_handler responseHandler, + void * const userData, + const char * const format, + ...) { + + xmlrpc_env env; + + xmlrpc_env_init(&env); + + validateGlobalClientExists(&env); + + if (!env.fault_occurred) { + xmlrpc_value * paramArrayP; + const char * suffix; + va_list args; + + va_start(args, format); + xmlrpc_build_value_va(&env, format, args, ¶mArrayP, &suffix); + va_end(args); + + if (!env.fault_occurred) { + if (*suffix != '\0') + xmlrpc_faultf(&env, "Junk after the argument " + "specifier: '%s'. " + "There must be exactly one arument.", + suffix); + else + xmlrpc_client_call_asynch_params( + serverUrl, methodName, responseHandler, userData, + paramArrayP); + } + } + if (env.fault_occurred) + (*responseHandler)(serverUrl, methodName, NULL, userData, &env, NULL); + + xmlrpc_env_clean(&env); +} + + + +void +xmlrpc_client_call_asynch_params(const char * const serverUrl, + const char * const methodName, + xmlrpc_response_handler responseHandler, + void * const userData, + xmlrpc_value * const paramArrayP) { + xmlrpc_env env; + xmlrpc_server_info * serverInfoP; + + xmlrpc_env_init(&env); + + serverInfoP = xmlrpc_server_info_new(&env, serverUrl); + + if (!env.fault_occurred) { + xmlrpc_client_call_server_asynch_params( + serverInfoP, methodName, responseHandler, userData, paramArrayP); + + xmlrpc_server_info_free(serverInfoP); + } + if (env.fault_occurred) + (*responseHandler)(serverUrl, methodName, paramArrayP, userData, + &env, NULL); + xmlrpc_env_clean(&env); +} + + + +void +xmlrpc_client_call_server_asynch(xmlrpc_server_info * const serverInfoP, + const char * const methodName, + xmlrpc_response_handler responseHandler, + void * const userData, + const char * const format, + ...) { + + xmlrpc_env env; + xmlrpc_value * paramArrayP; + const char * suffix; + va_list args; + + xmlrpc_env_init(&env); + + va_start(args, format); + xmlrpc_build_value_va(&env, format, args, ¶mArrayP, &suffix); + va_end(args); + + if (!env.fault_occurred) { + if (*suffix != '\0') + xmlrpc_faultf(&env, "Junk after the argument " + "specifier: '%s'. " + "There must be exactly one arument.", + suffix); + else + xmlrpc_client_call_server_asynch_params( + serverInfoP, methodName, responseHandler, userData, + paramArrayP); + + xmlrpc_DECREF(paramArrayP); + } + if (env.fault_occurred) + (*responseHandler)(serverInfoP->_server_url, methodName, NULL, + userData, &env, NULL); + + xmlrpc_env_clean(&env); +} + + + +void +xmlrpc_client_event_loop_finish_asynch(void) { + + XMLRPC_ASSERT(globalClientExists); + xmlrpc_client_event_loop_finish(globalClientP); +} + + + +void +xmlrpc_client_event_loop_finish_asynch_timeout( + unsigned long const milliseconds) { + + XMLRPC_ASSERT(globalClientExists); + xmlrpc_client_event_loop_finish_timeout(globalClientP, milliseconds); +} diff --git a/src/xmlrpc_data.c b/src/xmlrpc_data.c new file mode 100644 index 0000000..15889b7 --- /dev/null +++ b/src/xmlrpc_data.c @@ -0,0 +1,852 @@ +/* Copyright information is at end of file */ + +#include "xmlrpc_config.h" + +#include +#include +#include +#include + +#include "bool.h" +#include "mallocvar.h" + +#include "xmlrpc-c/base.h" +#include "xmlrpc-c/base_int.h" + + + +static void +destroyValue(xmlrpc_value * const valueP) { + + /* First, we need to destroy this value's contents, if any. */ + switch (valueP->_type) { + case XMLRPC_TYPE_INT: + break; + + case XMLRPC_TYPE_BOOL: + break; + + case XMLRPC_TYPE_DOUBLE: + break; + + case XMLRPC_TYPE_DATETIME: + xmlrpc_mem_block_clean(&valueP->_block); + break; + + case XMLRPC_TYPE_STRING: + if (valueP->_wcs_block) + xmlrpc_mem_block_free(valueP->_wcs_block); + xmlrpc_mem_block_clean(&valueP->_block); + break; + + case XMLRPC_TYPE_BASE64: + xmlrpc_mem_block_clean(&valueP->_block); + break; + + case XMLRPC_TYPE_ARRAY: + xmlrpc_destroyArrayContents(valueP); + break; + + case XMLRPC_TYPE_STRUCT: + xmlrpc_destroyStruct(valueP); + break; + + case XMLRPC_TYPE_C_PTR: + break; + + case XMLRPC_TYPE_NIL: + break; + + case XMLRPC_TYPE_DEAD: + XMLRPC_ASSERT(false); /* Can't happen, per entry conditions */ + + default: + XMLRPC_ASSERT(false); /* There are no other possible values */ + } + + /* Next, we mark this value as invalid, to help catch refcount + ** errors. */ + valueP->_type = XMLRPC_TYPE_DEAD; + + /* Finally, we destroy the value itself. */ + free(valueP); +} + + + +/*========================================================================= +** Reference Counting +**========================================================================= +** Some simple reference-counting code. The xmlrpc_DECREF routine is in +** charge of destroying values when their reference count equals zero. +*/ + +void +xmlrpc_INCREF (xmlrpc_value * const valueP) { + + XMLRPC_ASSERT_VALUE_OK(valueP); + XMLRPC_ASSERT(valueP->_refcount > 0); + + ++valueP->_refcount; +} + + + +void +xmlrpc_DECREF (xmlrpc_value * const valueP) { + + XMLRPC_ASSERT_VALUE_OK(valueP); + XMLRPC_ASSERT(valueP->_refcount > 0); + XMLRPC_ASSERT(valueP->_type != XMLRPC_TYPE_DEAD); + + valueP->_refcount--; + + /* If we have no more refs, we need to deallocate this value. */ + if (valueP->_refcount == 0) + destroyValue(valueP); +} + + + +/*========================================================================= + Utiltiies +=========================================================================*/ + +const char * +xmlrpc_typeName(xmlrpc_type const type) { + + switch(type) { + + case XMLRPC_TYPE_INT: return "INT"; + case XMLRPC_TYPE_BOOL: return "BOOL"; + case XMLRPC_TYPE_DOUBLE: return "DOUBLE"; + case XMLRPC_TYPE_DATETIME: return "DATETIME"; + case XMLRPC_TYPE_STRING: return "STRING"; + case XMLRPC_TYPE_BASE64: return "BASE64"; + case XMLRPC_TYPE_ARRAY: return "ARRAY"; + case XMLRPC_TYPE_STRUCT: return "STRUCT"; + case XMLRPC_TYPE_C_PTR: return "C_PTR"; + case XMLRPC_TYPE_NIL: return "NIL"; + case XMLRPC_TYPE_DEAD: return "DEAD"; + default: return "???"; + } +} + + + +static void +verifyNoNulls(xmlrpc_env * const envP, + const char * const contents, + unsigned int const len) { +/*---------------------------------------------------------------------------- + Verify that the character array 'contents', which is 'len' bytes long, + does not contain any NUL characters, which means it can be made into + a passable ASCIIZ string just by adding a terminating NUL. + + Fail if the array contains a NUL. +-----------------------------------------------------------------------------*/ + unsigned int i; + + for (i = 0; i < len && !envP->fault_occurred; i++) + if (contents[i] == '\0') + xmlrpc_env_set_fault_formatted( + envP, XMLRPC_TYPE_ERROR, + "String must not contain NUL characters"); +} + + + +#if HAVE_UNICODE_WCHAR + +static void +verifyNoNullsW(xmlrpc_env * const envP, + const wchar_t * const contents, + unsigned int const len) { +/*---------------------------------------------------------------------------- + Same as verifyNoNulls(), but for wide characters. +-----------------------------------------------------------------------------*/ + unsigned int i; + + for (i = 0; i < len && !envP->fault_occurred; i++) + if (contents[i] == '\0') + xmlrpc_env_set_fault_formatted( + envP, XMLRPC_TYPE_ERROR, + "String must not contain NUL characters"); +} +#endif + + + +static void +validateType(xmlrpc_env * const envP, + const xmlrpc_value * const valueP, + xmlrpc_type const expectedType) { + + if (valueP->_type != expectedType) { + xmlrpc_env_set_fault_formatted( + envP, XMLRPC_TYPE_ERROR, "Value of type %s supplied where " + "type %s was expected.", + xmlrpc_typeName(valueP->_type), xmlrpc_typeName(expectedType)); + } +} + + + +/*========================================================================= + Extracting XML-RPC value +=========================================================================== + These routines extract XML-RPC values into ordinary C data types. + + For array and struct values, see the separates files xmlrpc_array.c + and xmlrpc_struct.c. +=========================================================================*/ + +void +xmlrpc_read_int(xmlrpc_env * const envP, + const xmlrpc_value * const valueP, + xmlrpc_int32 * const intValueP) { + + validateType(envP, valueP, XMLRPC_TYPE_INT); + if (!envP->fault_occurred) + *intValueP = valueP->_value.i; +} + + + +void +xmlrpc_read_bool(xmlrpc_env * const envP, + const xmlrpc_value * const valueP, + xmlrpc_bool * const boolValueP) { + + validateType(envP, valueP, XMLRPC_TYPE_BOOL); + if (!envP->fault_occurred) + *boolValueP = valueP->_value.b; +} + + + +void +xmlrpc_read_double(xmlrpc_env * const envP, + const xmlrpc_value * const valueP, + xmlrpc_double * const doubleValueP) { + + validateType(envP, valueP, XMLRPC_TYPE_DOUBLE); + if (!envP->fault_occurred) + *doubleValueP = valueP->_value.d; + +} + + +/* datetime stuff is in xmlrpc_datetime.c */ + +static void +accessStringValue(xmlrpc_env * const envP, + const xmlrpc_value * const valueP, + size_t * const lengthP, + const char ** const contentsP) { + + validateType(envP, valueP, XMLRPC_TYPE_STRING); + if (!envP->fault_occurred) { + unsigned int const size = + XMLRPC_MEMBLOCK_SIZE(char, &valueP->_block); + const char * const contents = + XMLRPC_MEMBLOCK_CONTENTS(char, &valueP->_block); + unsigned int const len = size - 1; + /* The memblock has a null character added to the end */ + + verifyNoNulls(envP, contents, len); + + *lengthP = len; + *contentsP = contents; + } +} + + + +void +xmlrpc_read_string(xmlrpc_env * const envP, + const xmlrpc_value * const valueP, + const char ** const stringValueP) { +/*---------------------------------------------------------------------------- + Read the value of an XML-RPC string as an ASCIIZ string. + + Return the string in newly malloc'ed storage that Caller must free. + + Fail if the string contains null characters (which means it wasn't + really a string, but XML-RPC doesn't seem to understand what a string + is, and such values are possible). +-----------------------------------------------------------------------------*/ + size_t length; + const char * contents; + + accessStringValue(envP, valueP, &length, &contents); + + if (!envP->fault_occurred) { + char * stringValue; + + stringValue = malloc(length+1); + if (stringValue == NULL) + xmlrpc_env_set_fault_formatted( + envP, XMLRPC_INTERNAL_ERROR, "Unable to allocate space " + "for %u-character string", length); + else { + memcpy(stringValue, contents, length); + stringValue[length] = '\0'; + + *stringValueP = stringValue; + } + } +} + + + +void +xmlrpc_read_string_old(xmlrpc_env * const envP, + const xmlrpc_value * const valueP, + const char ** const stringValueP) { + + size_t length; + accessStringValue(envP, valueP, &length, stringValueP); +} + + + +void +xmlrpc_read_string_lp(xmlrpc_env * const envP, + const xmlrpc_value * const valueP, + size_t * const lengthP, + const char ** const stringValueP) { + + validateType(envP, valueP, XMLRPC_TYPE_STRING); + if (!envP->fault_occurred) { + unsigned int const size = + XMLRPC_MEMBLOCK_SIZE(char, &valueP->_block); + const char * const contents = + XMLRPC_MEMBLOCK_CONTENTS(char, &valueP->_block); + + char * stringValue; + + stringValue = malloc(size); + if (stringValue == NULL) + xmlrpc_env_set_fault_formatted( + envP, XMLRPC_INTERNAL_ERROR, "Unable to allocate %u bytes " + "for string.", size); + else { + memcpy(stringValue, contents, size); + *stringValueP = stringValue; + *lengthP = size - 1; /* Size includes terminating NUL */ + } + } +} + + + +void +xmlrpc_read_string_lp_old(xmlrpc_env * const envP, + const xmlrpc_value * const valueP, + size_t * const lengthP, + const char ** const stringValueP) { + + validateType(envP, valueP, XMLRPC_TYPE_STRING); + if (!envP->fault_occurred) { + *lengthP = XMLRPC_MEMBLOCK_SIZE(char, &valueP->_block) - 1; + *stringValueP = XMLRPC_MEMBLOCK_CONTENTS(char, &valueP->_block); + } +} + + + +static __inline__ void +setupWcsBlock(xmlrpc_env * const envP, + xmlrpc_value * const valueP) { +/*---------------------------------------------------------------------------- + Add a wcs block (wchar_t string) to the indicated xmlrpc_value if it + doesn't have one already. +-----------------------------------------------------------------------------*/ + if (!valueP->_wcs_block) { + char * const contents = + XMLRPC_MEMBLOCK_CONTENTS(char, &valueP->_block); + size_t const len = + XMLRPC_MEMBLOCK_SIZE(char, &valueP->_block) - 1; + valueP->_wcs_block = + xmlrpc_utf8_to_wcs(envP, contents, len + 1); + } +} + + + +#if HAVE_UNICODE_WCHAR + +static void +accessStringValueW(xmlrpc_env * const envP, + xmlrpc_value * const valueP, + size_t * const lengthP, + const wchar_t ** const stringValueP) { + + validateType(envP, valueP, XMLRPC_TYPE_STRING); + if (!envP->fault_occurred) { + setupWcsBlock(envP, valueP); + + if (!envP->fault_occurred) { + wchar_t * const wcontents = + XMLRPC_MEMBLOCK_CONTENTS(wchar_t, valueP->_wcs_block); + size_t const len = + XMLRPC_MEMBLOCK_SIZE(wchar_t, valueP->_wcs_block) - 1; + + verifyNoNullsW(envP, wcontents, len); + + *lengthP = len; + *stringValueP = wcontents; + } + } +} + + + +void +xmlrpc_read_string_w(xmlrpc_env * const envP, + xmlrpc_value * const valueP, + const wchar_t ** const stringValueP) { + + size_t length; + const wchar_t * wcontents; + + accessStringValueW(envP, valueP, &length, &wcontents); + + if (!envP->fault_occurred) { + wchar_t * stringValue; + stringValue = malloc((length + 1) * sizeof(wchar_t)); + if (stringValue == NULL) + xmlrpc_env_set_fault_formatted( + envP, XMLRPC_INTERNAL_ERROR, + "Unable to allocate space for %u-byte string", + length); + else { + memcpy(stringValue, wcontents, length * sizeof(wchar_t)); + stringValue[length] = '\0'; + + *stringValueP = stringValue; + } + } +} + + + +void +xmlrpc_read_string_w_old(xmlrpc_env * const envP, + xmlrpc_value * const valueP, + const wchar_t ** const stringValueP) { + + size_t length; + + accessStringValueW(envP, valueP, &length, stringValueP); +} + + + +void +xmlrpc_read_string_w_lp(xmlrpc_env * const envP, + xmlrpc_value * const valueP, + size_t * const lengthP, + const wchar_t ** const stringValueP) { + + validateType(envP, valueP, XMLRPC_TYPE_STRING); + if (!envP->fault_occurred) { + setupWcsBlock(envP, valueP); + + if (!envP->fault_occurred) { + wchar_t * const wcontents = + XMLRPC_MEMBLOCK_CONTENTS(wchar_t, valueP->_wcs_block); + size_t const size = + XMLRPC_MEMBLOCK_SIZE(wchar_t, valueP->_wcs_block); + + wchar_t * stringValue; + + stringValue = malloc(size * sizeof(wchar_t)); + if (stringValue == NULL) + xmlrpc_env_set_fault_formatted( + envP, XMLRPC_INTERNAL_ERROR, + "Unable to allocate space for %u-byte string", + size); + else { + memcpy(stringValue, wcontents, size * sizeof(wchar_t)); + + *lengthP = size - 1; /* size includes terminating NUL */ + *stringValueP = stringValue; + } + } + } +} + + + +void +xmlrpc_read_string_w_lp_old(xmlrpc_env * const envP, + xmlrpc_value * const valueP, + size_t * const lengthP, + const wchar_t ** const stringValueP) { + + validateType(envP, valueP, XMLRPC_TYPE_STRING); + if (!envP->fault_occurred) { + setupWcsBlock(envP, valueP); + + if (!envP->fault_occurred) { + wchar_t * const wcontents = + XMLRPC_MEMBLOCK_CONTENTS(wchar_t, valueP->_wcs_block); + size_t const size = + XMLRPC_MEMBLOCK_SIZE(wchar_t, valueP->_wcs_block); + + *lengthP = size - 1; /* size includes terminatnig NUL */ + *stringValueP = wcontents; + } + } +} +#endif + + + +void +xmlrpc_read_base64(xmlrpc_env * const envP, + const xmlrpc_value * const valueP, + size_t * const lengthP, + const unsigned char ** const byteStringValueP) { + + validateType(envP, valueP, XMLRPC_TYPE_BASE64); + if (!envP->fault_occurred) { + size_t const size = + XMLRPC_MEMBLOCK_SIZE(char, &valueP->_block); + const char * const contents = + XMLRPC_MEMBLOCK_CONTENTS(char, &valueP->_block); + + char * byteStringValue; + + byteStringValue = malloc(size); + if (byteStringValue == NULL) + xmlrpc_env_set_fault_formatted( + envP, XMLRPC_INTERNAL_ERROR, "Unable to allocate %u bytes " + "for byte string.", size); + else { + memcpy(byteStringValue, contents, size); + *byteStringValueP = (const unsigned char *)byteStringValue; + *lengthP = size; + } + } +} + + + +void +xmlrpc_read_base64_old(xmlrpc_env * const envP, + const xmlrpc_value * const valueP, + size_t * const lengthP, + const unsigned char ** const byteStringValueP) { + + validateType(envP, valueP, XMLRPC_TYPE_BASE64); + if (!envP->fault_occurred) { + *lengthP = + XMLRPC_MEMBLOCK_SIZE(char, &valueP->_block); + *byteStringValueP = (const unsigned char *) + XMLRPC_MEMBLOCK_CONTENTS(char, &valueP->_block); + } +} + + + +void +xmlrpc_read_base64_size(xmlrpc_env * const envP, + const xmlrpc_value * const valueP, + size_t * const lengthP) { + + validateType(envP, valueP, XMLRPC_TYPE_BASE64); + if (!envP->fault_occurred) + *lengthP = XMLRPC_MEMBLOCK_SIZE(char, &valueP->_block); +} + + + +void +xmlrpc_read_nil(xmlrpc_env * const envP, + xmlrpc_value * const valueP) { +/*---------------------------------------------------------------------------- + Read out the value of a nil value. It doesn't have one, of course, so + this is essentially a no-op. But it does validate the type and is + necessary to match all the other types. +-----------------------------------------------------------------------------*/ + validateType(envP, valueP, XMLRPC_TYPE_NIL); +} + + + +void +xmlrpc_read_cptr(xmlrpc_env * const envP, + const xmlrpc_value * const valueP, + void ** const ptrValueP) { + + validateType(envP, valueP, XMLRPC_TYPE_C_PTR); + if (!envP->fault_occurred) + *ptrValueP = valueP->_value.c_ptr; +} + + + +xmlrpc_type xmlrpc_value_type (xmlrpc_value* value) +{ + XMLRPC_ASSERT_VALUE_OK(value); + return value->_type; +} + + + +void +xmlrpc_createXmlrpcValue(xmlrpc_env * const envP, + xmlrpc_value ** const valPP) { +/*---------------------------------------------------------------------------- + Create a blank xmlrpc_value to be filled in. + + Set the reference count to 1. +-----------------------------------------------------------------------------*/ + xmlrpc_value * valP; + + MALLOCVAR(valP); + if (!valP) + xmlrpc_env_set_fault(envP, XMLRPC_INTERNAL_ERROR, + "Could not allocate memory for xmlrpc_value"); + else + valP->_refcount = 1; + + *valPP = valP; +} + + + +xmlrpc_value * +xmlrpc_int_new(xmlrpc_env * const envP, + xmlrpc_int32 const value) { + + xmlrpc_value * valP; + + xmlrpc_createXmlrpcValue(envP, &valP); + + if (!envP->fault_occurred) { + valP->_type = XMLRPC_TYPE_INT; + valP->_value.i = value; + } + return valP; +} + + + +xmlrpc_value * +xmlrpc_bool_new(xmlrpc_env * const envP, + xmlrpc_bool const value) { + + xmlrpc_value * valP; + + xmlrpc_createXmlrpcValue(envP, &valP); + + if (!envP->fault_occurred) { + valP->_type = XMLRPC_TYPE_BOOL; + valP->_value.b = value; + } + return valP; +} + + + +xmlrpc_value * +xmlrpc_double_new(xmlrpc_env * const envP, + double const value) { + + xmlrpc_value * valP; + + xmlrpc_createXmlrpcValue(envP, &valP); + + if (!envP->fault_occurred) { + valP->_type = XMLRPC_TYPE_DOUBLE; + valP->_value.d = value; + } + return valP; +} + + + +xmlrpc_value * +xmlrpc_string_new_lp(xmlrpc_env * const envP, + size_t const length, + const char * const value) { + + xmlrpc_value * valP; + + xmlrpc_createXmlrpcValue(envP, &valP); + + if (!envP->fault_occurred) { + valP->_type = XMLRPC_TYPE_STRING; + valP->_wcs_block = NULL; + XMLRPC_MEMBLOCK_INIT(char, envP, &valP->_block, length + 1); + if (!envP->fault_occurred) { + char * const contents = + XMLRPC_MEMBLOCK_CONTENTS(char, &valP->_block); + memcpy(contents, value, length); + contents[length] = '\0'; + } + if (envP->fault_occurred) + free(valP); + } + return valP; +} + + + +xmlrpc_value * +xmlrpc_string_new(xmlrpc_env * const envP, + const char * const value) { + + return xmlrpc_string_new_lp(envP, strlen(value), value); +} + + +#if HAVE_UNICODE_WCHAR +xmlrpc_value * +xmlrpc_string_w_new_lp(xmlrpc_env * const envP, + size_t const length, + const wchar_t * const value) { + + xmlrpc_value * valP; + + /* Initialize our XML-RPC value. */ + xmlrpc_createXmlrpcValue(envP, &valP); + + if (!envP->fault_occurred) { + valP->_type = XMLRPC_TYPE_STRING; + + /* Build our wchar_t block first. */ + valP->_wcs_block = + XMLRPC_MEMBLOCK_NEW(wchar_t, envP, length + 1); + if (!envP->fault_occurred) { + wchar_t * const wcs_contents = + XMLRPC_MEMBLOCK_CONTENTS(wchar_t, valP->_wcs_block); + + xmlrpc_mem_block * utf8P; + + memcpy(wcs_contents, value, length * sizeof(wchar_t)); + wcs_contents[length] = '\0'; + + /* Convert the wcs block to UTF-8. */ + utf8P = xmlrpc_wcs_to_utf8(envP, wcs_contents, length + 1); + if (!envP->fault_occurred) { + char * const utf8_contents = + XMLRPC_MEMBLOCK_CONTENTS(char, utf8P); + size_t const utf8_len = XMLRPC_MEMBLOCK_SIZE(char, utf8P); + + /* XXX - We need an extra memcopy to initialize _block. */ + XMLRPC_MEMBLOCK_INIT(char, envP, &valP->_block, utf8_len); + if (!envP->fault_occurred) { + char * contents; + contents = XMLRPC_MEMBLOCK_CONTENTS(char, &valP->_block); + memcpy(contents, utf8_contents, utf8_len); + } + XMLRPC_MEMBLOCK_FREE(char, utf8P); + } + if (envP->fault_occurred) + XMLRPC_MEMBLOCK_FREE(wchar_t, valP->_wcs_block); + } + if (envP->fault_occurred) + free(valP); + } + return valP; +} + + + +xmlrpc_value * +xmlrpc_string_w_new(xmlrpc_env * const envP, + const wchar_t * const value) { + return xmlrpc_string_w_new_lp(envP, wcslen(value), value); +} +#endif + +xmlrpc_value * +xmlrpc_base64_new(xmlrpc_env * const envP, + size_t const length, + const unsigned char * const value) { + + xmlrpc_value * valP; + + xmlrpc_createXmlrpcValue(envP, &valP); + + if (!envP->fault_occurred) { + valP->_type = XMLRPC_TYPE_BASE64; + + xmlrpc_mem_block_init(envP, &valP->_block, length); + if (!envP->fault_occurred) { + char * const contents = + xmlrpc_mem_block_contents(&valP->_block); + memcpy(contents, value, length); + } + if (envP->fault_occurred) + free(valP); + } + return valP; +} + + + +/* array stuff is in xmlrpc_array.c */ + + + +xmlrpc_value * +xmlrpc_cptr_new(xmlrpc_env * const envP, + void * const value) { + + xmlrpc_value * valP; + + xmlrpc_createXmlrpcValue(envP, &valP); + + if (!envP->fault_occurred) { + valP->_type = XMLRPC_TYPE_C_PTR; + valP->_value.c_ptr = value; + } + return valP; +} + + + +xmlrpc_value * +xmlrpc_nil_new(xmlrpc_env * const envP) { + xmlrpc_value * valP; + + xmlrpc_createXmlrpcValue(envP, &valP); + if (!envP->fault_occurred) + valP->_type = XMLRPC_TYPE_NIL; + + return valP; +} + + + +/* Copyright (C) 2001 by First Peer, Inc. All rights reserved. +** Copyright (C) 2001 by Eric Kidd. All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +** ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +** OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +** HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +** LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +** OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +** SUCH DAMAGE. */ diff --git a/src/xmlrpc_datetime.c b/src/xmlrpc_datetime.c new file mode 100644 index 0000000..bd190d2 --- /dev/null +++ b/src/xmlrpc_datetime.c @@ -0,0 +1,480 @@ +#include "xmlrpc_config.h" + +#include +#include +#include +#include +#include + +#include "bool.h" + +#include "xmlrpc-c/base.h" +#include "xmlrpc-c/base_int.h" + + +/* Future work: the XMLRPC_TYPE_DATETIME xmlrpc_value should store the + datetime as something computation-friendly, not as a string. The + XML-RPC XML parser should parse the string value and reject the XML if + it isn't valid. + + But this file should remain the authority on datetimes, so the XML + parser and builder should call on routines in here to do that. + + time_t won't work because it can't represent times before 1970 or + after 2038. We need to figure out something better. +*/ + + +#ifdef WIN32 + +static const bool win32 = TRUE; +static const __int64 SECS_BETWEEN_EPOCHS = 11644473600; +static const __int64 SECS_TO_100NS = 10000000; /* 10^7 */ + + +void UnixTimeToFileTime(const time_t t, LPFILETIME pft) +{ + // Note that LONGLONG is a 64-bit value + LONGLONG ll; + ll = Int32x32To64(t, SECS_TO_100NS) + SECS_BETWEEN_EPOCHS * SECS_TO_100NS; + pft->dwLowDateTime = (DWORD)ll; + pft->dwHighDateTime = ll >> 32; +} + +void UnixTimeToSystemTime(const time_t t, LPSYSTEMTIME pst) +{ + FILETIME ft; + + UnixTimeToFileTime(t, &ft); + FileTimeToSystemTime(&ft, pst); +} + +static void UnixTimeFromFileTime(xmlrpc_env * const envP, LPFILETIME pft, time_t * const timeValueP) +{ + LONGLONG ll; + + ll = ((LONGLONG)pft->dwHighDateTime << 32) + pft->dwLowDateTime; + /* convert to the Unix epoch */ + ll -= (SECS_BETWEEN_EPOCHS * SECS_TO_100NS); + /* now convert to seconds */ + ll /= SECS_TO_100NS; + + if ( (time_t)ll != ll ) + { + //fail - value is too big for a time_t + xmlrpc_faultf(envP, "Does not indicate a valid date"); + *timeValueP = (time_t)-1; + return; + } + *timeValueP = (time_t)ll; +} + +static void UnixTimeFromSystemTime(xmlrpc_env * const envP, LPSYSTEMTIME pst, time_t * const timeValueP) +{ + FILETIME filetime; + + SystemTimeToFileTime(pst, &filetime); + UnixTimeFromFileTime(envP, &filetime, timeValueP); +} + +#else +static const bool win32 = false; +#endif + + +static void +validateDatetimeType(xmlrpc_env * const envP, + const xmlrpc_value * const valueP) { + + if (valueP->_type != XMLRPC_TYPE_DATETIME) { + xmlrpc_env_set_fault_formatted( + envP, XMLRPC_TYPE_ERROR, "Value of type %s supplied where " + "type %s was expected.", + xmlrpc_typeName(valueP->_type), + xmlrpc_typeName(XMLRPC_TYPE_DATETIME)); + } +} + + + +void +xmlrpc_read_datetime_str(xmlrpc_env * const envP, + const xmlrpc_value * const valueP, + const char ** const stringValueP) { + + validateDatetimeType(envP, valueP); + if (!envP->fault_occurred) { + const char * const contents = + XMLRPC_MEMBLOCK_CONTENTS(char, &valueP->_block); + *stringValueP = strdup(contents); + if (*stringValueP == NULL) + xmlrpc_env_set_fault_formatted( + envP, XMLRPC_INTERNAL_ERROR, "Unable to allocate space " + "for datetime string"); + } +} + + + +void +xmlrpc_read_datetime_str_old(xmlrpc_env * const envP, + const xmlrpc_value * const valueP, + const char ** const stringValueP) { + + validateDatetimeType(envP, valueP); + if (!envP->fault_occurred) { + *stringValueP = XMLRPC_MEMBLOCK_CONTENTS(char, &valueP->_block); + } +} + + + +static void +parseDateNumbers(const char * const t, + unsigned int * const YP, + unsigned int * const MP, + unsigned int * const DP, + unsigned int * const hP, + unsigned int * const mP, + unsigned int * const sP) { + + char year[4+1]; + char month[2+1]; + char day[2+1]; + char hour[2+1]; + char minute[2+1]; + char second[2+1]; + + assert(strlen(t) == 17); + + year[0] = t[ 0]; + year[1] = t[ 1]; + year[2] = t[ 2]; + year[3] = t[ 3]; + year[4] = '\0'; + + month[0] = t[ 4]; + month[1] = t[ 5]; + month[2] = '\0'; + + day[0] = t[ 6]; + day[1] = t[ 7]; + day[2] = '\0'; + + assert(t[ 8] == 'T'); + + hour[0] = t[ 9]; + hour[1] = t[10]; + hour[2] = '\0'; + + assert(t[11] == ':'); + + minute[0] = t[12]; + minute[1] = t[13]; + minute[2] = '\0'; + + assert(t[14] == ':'); + + second[0] = t[15]; + second[1] = t[16]; + second[2] = '\0'; + + *YP = atoi(year); + *MP = atoi(month); + *DP = atoi(day); + *hP = atoi(hour); + *mP = atoi(minute); + *sP = atoi(second); +} + + +#ifdef HAVE_SETENV +xmlrpc_bool const haveSetenv = true; +#else +xmlrpc_bool const haveSetenv = false; +static void +setenv(const char * const name ATTR_UNUSED, + const char * const value ATTR_UNUSED, + int const replace ATTR_UNUSED) { + assert(FALSE); +} +#endif + +static void +makeTimezoneUtc(xmlrpc_env * const envP, + const char ** const oldTzP) { + + const char * const tz = getenv("TZ"); + +#ifdef WIN32 + /* Windows implementation does not exist */ + assert(TRUE); +#endif + + if (haveSetenv) { + if (tz) { + *oldTzP = strdup(tz); + if (*oldTzP == NULL) + xmlrpc_faultf(envP, "Unable to get memory to save TZ " + "environment variable."); + } else + *oldTzP = NULL; + + if (!envP->fault_occurred) + setenv("TZ", "", 1); + } else { + if (tz && strlen(tz) == 0) { + /* Everything's fine. Nothing to change or restore */ + } else { + /* Note that putenv() is not sufficient. You can't restore + the original value with that, because it sets a pointer into + your own storage. + */ + xmlrpc_faultf(envP, "Your TZ environment variable is not a " + "null string and your C library does not have " + "setenv(), so we can't change it."); + } + } +} + + + +static void +restoreTimezone(const char * const oldTz) { + + if (haveSetenv) { + setenv("TZ", oldTz, 1); + free((char*)oldTz); + } +} + + + +static void +mkAbsTimeWin32(xmlrpc_env * const envP ATTR_UNUSED, + struct tm const brokenTime ATTR_UNUSED, + time_t * const timeValueP ATTR_UNUSED) { +#ifdef WIN32 + /* Windows Implementation */ + SYSTEMTIME stbrokenTime; + + stbrokenTime.wHour = brokenTime.tm_hour; + stbrokenTime.wMinute = brokenTime.tm_min; + stbrokenTime.wSecond = brokenTime.tm_sec; + stbrokenTime.wMonth = brokenTime.tm_mon; + stbrokenTime.wDay = brokenTime.tm_mday; + stbrokenTime.wYear = brokenTime.tm_year; + stbrokenTime.wMilliseconds = 0; + + /* When the date string is parsed into the tm structure, it was + modified to decrement the month count by one and convert the + 4 digit year to a two digit year. We undo what the parser + did to make it a true SYSTEMTIME structure, then convert this + structure into a UNIX time_t structure + */ + stbrokenTime.wYear+=1900; + stbrokenTime.wMonth+=1; + + UnixTimeFromSystemTime(envP, &stbrokenTime,timeValueP); +#endif +} + + +static void +mkAbsTimeUnix(xmlrpc_env * const envP ATTR_UNUSED, + struct tm const brokenTime ATTR_UNUSED, + time_t * const timeValueP ATTR_UNUSED) { + +#ifndef WIN32 + time_t mktimeResult; + const char * oldTz; + struct tm mktimeWork; + + /* We use mktime() to create the time_t because it's the + best we have available, but mktime() takes a local time + argument, and we have absolute time. So we fake it out + by temporarily setting the timezone to UTC. + */ + makeTimezoneUtc(envP, &oldTz); + + if (!envP->fault_occurred) { + mktimeWork = brokenTime; + mktimeResult = mktime(&mktimeWork); + + restoreTimezone(oldTz); + + if (mktimeResult == (time_t)-1) + xmlrpc_faultf(envP, "Does not indicate a valid date"); + else + *timeValueP = mktimeResult; + } +#endif +} + + + +static void +mkAbsTime(xmlrpc_env * const envP, + struct tm const brokenTime, + time_t * const timeValueP) { + + if (win32) + mkAbsTimeWin32(envP, brokenTime, timeValueP); + else + mkAbsTimeUnix(envP, brokenTime, timeValueP); +} + + + +static void +validateFormat(xmlrpc_env * const envP, + const char * const t) { + + if (strlen(t) != 17) + xmlrpc_faultf(envP, "%u characters instead of 15.", strlen(t)); + else if (t[8] != 'T') + xmlrpc_faultf(envP, "9th character is '%c', not 'T'", t[8]); + else { + unsigned int i; + + for (i = 0; i < 8 && !envP->fault_occurred; ++i) + if (!isdigit(t[i])) + xmlrpc_faultf(envP, "Not a digit: '%c'", t[i]); + + if (!isdigit(t[9])) + xmlrpc_faultf(envP, "Not a digit: '%c'", t[9]); + if (!isdigit(t[10])) + xmlrpc_faultf(envP, "Not a digit: '%c'", t[10]); + if (t[11] != ':') + xmlrpc_faultf(envP, "Not a colon: '%c'", t[11]); + if (!isdigit(t[12])) + xmlrpc_faultf(envP, "Not a digit: '%c'", t[12]); + if (!isdigit(t[13])) + xmlrpc_faultf(envP, "Not a digit: '%c'", t[13]); + if (t[14] != ':') + xmlrpc_faultf(envP, "Not a colon: '%c'", t[14]); + if (!isdigit(t[15])) + xmlrpc_faultf(envP, "Not a digit: '%c'", t[15]); + if (!isdigit(t[16])) + xmlrpc_faultf(envP, "Not a digit: '%c'", t[16]); + } +} + + + +static void +parseDatetime(xmlrpc_env * const envP, + const char * const t, + time_t * const timeValueP) { +/*---------------------------------------------------------------------------- + Parse a time in the format stored in an xmlrpc_value and return the + time that it represents. + + t[] is the input time string. We return the result as *timeValueP. + + Example of the format we parse: "19980717T14:08:55" + Note that this is not quite ISO 8601. It's a bizarre combination of + two ISO 8601 formats. +-----------------------------------------------------------------------------*/ + validateFormat(envP, t); + + if (!envP->fault_occurred) { + unsigned int Y, M, D, h, m, s; + + parseDateNumbers(t, &Y, &M, &D, &h, &m, &s); + + if (Y < 1900) + xmlrpc_faultf(envP, "Year is too early to represent as " + "a standard Unix time"); + else { + struct tm brokenTime; + + brokenTime.tm_sec = s; + brokenTime.tm_min = m; + brokenTime.tm_hour = h; + brokenTime.tm_mday = D; + brokenTime.tm_mon = M - 1; + brokenTime.tm_year = Y - 1900; + + mkAbsTime(envP, brokenTime, timeValueP); + } + } +} + + + +void +xmlrpc_read_datetime_sec(xmlrpc_env * const envP, + const xmlrpc_value * const valueP, + time_t * const timeValueP) { + + validateDatetimeType(envP, valueP); + if (!envP->fault_occurred) + parseDatetime(envP, + XMLRPC_MEMBLOCK_CONTENTS(char, &valueP->_block), + timeValueP); +} + + + +xmlrpc_value * +xmlrpc_datetime_new_str(xmlrpc_env * const envP, + const char * const value) { + + xmlrpc_value * valP; + + xmlrpc_createXmlrpcValue(envP, &valP); + + if (!envP->fault_occurred) { + valP->_type = XMLRPC_TYPE_DATETIME; + + XMLRPC_TYPED_MEM_BLOCK_INIT( + char, envP, &valP->_block, strlen(value) + 1); + if (!envP->fault_occurred) { + char * const contents = + XMLRPC_TYPED_MEM_BLOCK_CONTENTS(char, &valP->_block); + strcpy(contents, value); + } + if (envP->fault_occurred) + free(valP); + } + return valP; +} + + + +xmlrpc_value * +xmlrpc_datetime_new_sec(xmlrpc_env * const envP, + time_t const value) { + + xmlrpc_value * valP; + + xmlrpc_createXmlrpcValue(envP, &valP); + + if (!envP->fault_occurred) { + struct tm brokenTime; + char timeString[64]; + + valP->_type = XMLRPC_TYPE_DATETIME; + + gmtime_r(&value, &brokenTime); + + /* Note that this format is NOT ISO 8601 -- it's a bizarre + hybrid of two ISO 8601 formats. + */ + strftime(timeString, sizeof(timeString), "%Y%m%dT%H:%M:%S", + &brokenTime); + + XMLRPC_TYPED_MEM_BLOCK_INIT( + char, envP, &valP->_block, strlen(timeString) + 1); + if (!envP->fault_occurred) { + char * const contents = + XMLRPC_TYPED_MEM_BLOCK_CONTENTS(char, &valP->_block); + + strcpy(contents, timeString); + } + if (envP->fault_occurred) + free(valP); + } + return valP; +} diff --git a/src/xmlrpc_expat.c b/src/xmlrpc_expat.c new file mode 100644 index 0000000..b08a35a --- /dev/null +++ b/src/xmlrpc_expat.c @@ -0,0 +1,480 @@ +/* Copyright information is at end of file */ + +#include "xmlrpc_config.h" + +#include +#include +#include + +#include /* Expat */ + +#include "bool.h" + +#include "xmlrpc-c/base.h" +#include "xmlrpc-c/base_int.h" +#include "xmlrpc-c/string_int.h" +#include "xmlrpc-c/xmlparser.h" + +/* Define the contents of our internal structure. */ +struct _xml_element { + struct _xml_element *_parent; + char *_name; + xmlrpc_mem_block _cdata; /* char */ + xmlrpc_mem_block _children; /* xml_element* */ +}; + +/* Check that we're using expat in UTF-8 mode, not wchar_t mode. +** If you need to use expat in wchar_t mode, write a subroutine to +** copy a wchar_t string to a char string & return an error for +** any non-ASCII characters. Then call this subroutine on all +** XML_Char strings passed to our event handlers before using the +** data. */ +/* #if sizeof(char) != sizeof(XML_Char) +** #error expat must define XML_Char to be a regular char. +** #endif +*/ + +#define XMLRPC_ASSERT_ELEM_OK(elem) \ + XMLRPC_ASSERT((elem) != NULL && (elem)->_name != XMLRPC_BAD_POINTER) + + +/*========================================================================= +** xml_element_new +**========================================================================= +** Create a new xml_element. This routine isn't exported, because the +** arguments are implementation-dependent. +*/ + +static xml_element * +xml_element_new (xmlrpc_env * const env, + const char * const name) { + + xml_element *retval; + int name_valid, cdata_valid, children_valid; + + XMLRPC_ASSERT_ENV_OK(env); + XMLRPC_ASSERT(name != NULL); + + /* Set up our error-handling preconditions. */ + retval = NULL; + name_valid = cdata_valid = children_valid = 0; + + /* Allocate our xml_element structure. */ + retval = (xml_element*) malloc(sizeof(xml_element)); + XMLRPC_FAIL_IF_NULL(retval, env, XMLRPC_INTERNAL_ERROR, + "Couldn't allocate memory for XML element"); + + /* Set our parent field to NULL. */ + retval->_parent = NULL; + + /* Copy over the element name. */ + retval->_name = (char*) malloc(strlen(name) + 1); + XMLRPC_FAIL_IF_NULL(retval->_name, env, XMLRPC_INTERNAL_ERROR, + "Couldn't allocate memory for XML element"); + name_valid = 1; + strcpy(retval->_name, name); + + /* Initialize a block to hold our CDATA. */ + XMLRPC_TYPED_MEM_BLOCK_INIT(char, env, &retval->_cdata, 0); + XMLRPC_FAIL_IF_FAULT(env); + cdata_valid = 1; + + /* Initialize a block to hold our child elements. */ + XMLRPC_TYPED_MEM_BLOCK_INIT(xml_element*, env, &retval->_children, 0); + XMLRPC_FAIL_IF_FAULT(env); + children_valid = 1; + + cleanup: + if (env->fault_occurred) { + if (retval) { + if (name_valid) + free(retval->_name); + if (cdata_valid) + xmlrpc_mem_block_clean(&retval->_cdata); + if (children_valid) + xmlrpc_mem_block_clean(&retval->_children); + free(retval); + } + return NULL; + } else { + return retval; + } +} + + +/*========================================================================= +** xml_element_free +**========================================================================= +** Blow away an existing element & all of its child elements. +*/ +void +xml_element_free(xml_element * const elem) { + + xmlrpc_mem_block *children; + int size, i; + xml_element **contents; + + XMLRPC_ASSERT_ELEM_OK(elem); + + free(elem->_name); + elem->_name = XMLRPC_BAD_POINTER; + xmlrpc_mem_block_clean(&elem->_cdata); + + /* Deallocate all of our children recursively. */ + children = &elem->_children; + contents = XMLRPC_TYPED_MEM_BLOCK_CONTENTS(xml_element*, children); + size = XMLRPC_TYPED_MEM_BLOCK_SIZE(xml_element*, children); + for (i = 0; i < size; i++) + xml_element_free(contents[i]); + + xmlrpc_mem_block_clean(&elem->_children); + free(elem); +} + + +/*========================================================================= +** Miscellaneous Accessors +**========================================================================= +** Return the fields of the xml_element. See the header for more +** documentation on each function works. +*/ + + + +const char * +xml_element_name(const xml_element * const elemP) { + + XMLRPC_ASSERT_ELEM_OK(elemP); + return elemP->_name; +} + + + +/* The result of this function is NOT VALID until the end_element handler +** has been called! */ +size_t xml_element_cdata_size (xml_element *elem) +{ + XMLRPC_ASSERT_ELEM_OK(elem); + return XMLRPC_TYPED_MEM_BLOCK_SIZE(char, &elem->_cdata) - 1; +} + +char *xml_element_cdata (xml_element *elem) +{ + XMLRPC_ASSERT_ELEM_OK(elem); + return XMLRPC_TYPED_MEM_BLOCK_CONTENTS(char, &elem->_cdata); +} + + + +size_t +xml_element_children_size(const xml_element * const elemP) { + XMLRPC_ASSERT_ELEM_OK(elemP); + return XMLRPC_TYPED_MEM_BLOCK_SIZE(xml_element *, &elemP->_children); +} + + + +xml_element ** +xml_element_children(const xml_element * const elemP) { + XMLRPC_ASSERT_ELEM_OK(elemP); + return XMLRPC_TYPED_MEM_BLOCK_CONTENTS(xml_element *, &elemP->_children); +} + + + +/*========================================================================= +** Internal xml_element Utility Functions +**========================================================================= +*/ + +static void xml_element_append_cdata (xmlrpc_env *env, + xml_element *elem, + char *cdata, + size_t size) +{ + XMLRPC_ASSERT_ENV_OK(env); + XMLRPC_ASSERT_ELEM_OK(elem); + + XMLRPC_TYPED_MEM_BLOCK_APPEND(char, env, &elem->_cdata, cdata, size); +} + +/* Whether or not this function succeeds, it takes ownership of the 'child' +** argument. +** WARNING - This is the exact opposite of the usual memory ownership +** rules for xmlrpc_value! So please pay attention. */ +static void xml_element_append_child (xmlrpc_env *env, + xml_element *elem, + xml_element *child) +{ + XMLRPC_ASSERT_ENV_OK(env); + XMLRPC_ASSERT_ELEM_OK(elem); + XMLRPC_ASSERT_ELEM_OK(child); + XMLRPC_ASSERT(child->_parent == NULL); + + XMLRPC_TYPED_MEM_BLOCK_APPEND(xml_element*, env, &elem->_children, + &child, 1); + if (!env->fault_occurred) + child->_parent = elem; + else + xml_element_free(child); +} + + +/*========================================================================= +** Our parse context. We pass this around as expat user data. +**========================================================================= +*/ + +typedef struct { + xmlrpc_env env; + xml_element * rootP; + xml_element * currentP; +} parseContext; + + +/*========================================================================= +** Expat Event Handler Functions +**========================================================================= +*/ + +static void +startElement(void * const userData, + XML_Char * const name, + XML_Char ** const atts ATTR_UNUSED) { + + parseContext * const contextP = userData; + + XMLRPC_ASSERT(contextP != NULL); + XMLRPC_ASSERT(name != NULL); + + if (!contextP->env.fault_occurred) { + xml_element * elemP; + + elemP = xml_element_new(&contextP->env, name); + if (!contextP->env.fault_occurred) { + XMLRPC_ASSERT(elemP != NULL); + + /* Insert the new element in the appropriate place. */ + if (!contextP->rootP) { + /* No root yet, so this element must be the root. */ + contextP->rootP = elemP; + contextP->currentP = elemP; + } else { + XMLRPC_ASSERT(contextP->currentP != NULL); + + /* (We need to watch our error handling invariants + very carefully here. Read the docs for + xml_element_append_child. + */ + xml_element_append_child(&contextP->env, contextP->currentP, + elemP); + if (!contextP->env.fault_occurred) + contextP->currentP = elemP; + } + if (contextP->env.fault_occurred) + xml_element_free(elemP); + } + if (contextP->env.fault_occurred) { + /* Having changed *contextP to reflect failure, we are responsible + for undoing everything that has been done so far in this + context. + */ + if (contextP->rootP) + xml_element_free(contextP->rootP); + } + } +} + + + +static void +endElement(void * const userData, + XML_Char * const name ATTR_UNUSED) { + + parseContext * const contextP = userData; + + XMLRPC_ASSERT(contextP != NULL); + XMLRPC_ASSERT(name != NULL); + + if (!contextP->env.fault_occurred) { + /* I think Expat enforces these facts: */ + XMLRPC_ASSERT(xmlrpc_streq(name, contextP->currentP->_name)); + XMLRPC_ASSERT(contextP->currentP->_parent != NULL || + contextP->currentP == contextP->rootP); + + /* Add a trailing NUL to our cdata. */ + xml_element_append_cdata(&contextP->env, contextP->currentP, "\0", 1); + if (!contextP->env.fault_occurred) + /* Pop our "stack" of elements. */ + contextP->currentP = contextP->currentP->_parent; + + if (contextP->env.fault_occurred) { + /* Having changed *contextP to reflect failure, we are responsible + for undoing everything that has been done so far in this + context. + */ + if (contextP->rootP) + xml_element_free(contextP->rootP); + } + } +} + + + +static void +characterData(void * const userData, + XML_Char * const s, + int const len) { + + parseContext * const contextP = userData; + + XMLRPC_ASSERT(contextP != NULL); + XMLRPC_ASSERT(s != NULL); + XMLRPC_ASSERT(len >= 0); + + if (!contextP->env.fault_occurred) { + XMLRPC_ASSERT(contextP->currentP != NULL); + + xml_element_append_cdata(&contextP->env, contextP->currentP, s, len); + } +} + + + +static void +createParser(xmlrpc_env * const envP, + parseContext * const contextP, + XML_Parser * const parserP) { +/*---------------------------------------------------------------------------- + Create an Expat parser to parse our XML. +-----------------------------------------------------------------------------*/ + XML_Parser parser; + + parser = xmlrpc_XML_ParserCreate(NULL); + if (parser == NULL) + xmlrpc_faultf(envP, "Could not create expat parser"); + else { + /* Initialize our parse context. */ + xmlrpc_env_init(&contextP->env); + contextP->rootP = NULL; + contextP->currentP = NULL; + + xmlrpc_XML_SetUserData(parser, contextP); + xmlrpc_XML_SetElementHandler( + parser, + (XML_StartElementHandler) startElement, + (XML_EndElementHandler) endElement); + xmlrpc_XML_SetCharacterDataHandler( + parser, + (XML_CharacterDataHandler) characterData); + + *parserP = parser; + } +} + + + +static void +destroyParser(XML_Parser const parser, + parseContext * const contextP) { + + xmlrpc_env_clean(&contextP->env); + + xmlrpc_XML_ParserFree(parser); +} + + + +void +xml_parse(xmlrpc_env * const envP, + const char * const xmlData, + size_t const xmlDataLen, + xml_element ** const resultPP) { +/*---------------------------------------------------------------------------- + Parse the XML text 'xmlData', of length 'xmlDataLen'. Return the + description of the element that the XML text contains as *resultPP. +-----------------------------------------------------------------------------*/ + /* + This is an Expat driver. + + We set up event-based parser handlers for Expat and set Expat loose + on the XML. Expat walks through the XML, calling our handlers along + the way. Our handlers build up the element description in our + 'context' variable, so that when Expat is finished, our results are + in 'context' and we just have to pluck them out. + + We should allow the user to specify the encoding in 'xmlData', but + we don't. + */ + XML_Parser parser; + parseContext context; + + XMLRPC_ASSERT_ENV_OK(envP); + XMLRPC_ASSERT(xmlData != NULL); + + createParser(envP, &context, &parser); + + if (!envP->fault_occurred) { + bool ok; + + ok = xmlrpc_XML_Parse(parser, xmlData, xmlDataLen, 1); + /* sets 'context', *envP */ + if (!ok) { + /* Expat failed on its own to parse it -- this is not an error + that our handlers detected. + */ + xmlrpc_env_set_fault( + envP, XMLRPC_PARSE_ERROR, + xmlrpc_XML_ErrorString(xmlrpc_XML_GetErrorCode(parser))); + if (!context.env.fault_occurred) { + /* Have to clean up what our handlers built before Expat + barfed. + */ + if (context.rootP) + xml_element_free(context.rootP); + } + } else { + /* Expat got through the XML OK, but when it called our handlers, + they might have detected a problem. They would have noted + such a problem in *contextP. + */ + if (context.env.fault_occurred) + xmlrpc_env_set_fault_formatted( + envP, context.env.fault_code, + "XML doesn't parse. %s", context.env.fault_string); + else { + XMLRPC_ASSERT(context.rootP != NULL); + XMLRPC_ASSERT(context.currentP == NULL); + + *resultPP = context.rootP; + } + } + destroyParser(parser, &context); + } +} + + +/* Copyright (C) 2001 by First Peer, Inc. All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +** ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +** OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +** HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +** LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +** OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +** SUCH DAMAGE. */ diff --git a/src/xmlrpc_libxml2.c b/src/xmlrpc_libxml2.c new file mode 100644 index 0000000..9cba719 --- /dev/null +++ b/src/xmlrpc_libxml2.c @@ -0,0 +1,427 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* Copyright (C) 2001 by First Peer, Inc. All rights reserved. +** Copyright (C) 2002 Ximian, Inc. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +** ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +** OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +** HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +** LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +** OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +** SUCH DAMAGE. */ + +#include "xmlrpc_config.h" + +#include +#include +#include +#ifdef WIN32 +#include +#else +#include +#endif + +#include "xmlrpc-c/base.h" +#include "xmlrpc-c/base_int.h" +#include "xmlrpc-c/xmlparser.h" + +/* Define the contents of our internal structure. */ +struct _xml_element { + struct _xml_element *_parent; + char *_name; + xmlrpc_mem_block _cdata; /* char */ + xmlrpc_mem_block _children; /* xml_element* */ +}; + +#define XMLRPC_ASSERT_ELEM_OK(elem) \ + XMLRPC_ASSERT((elem) != NULL && (elem)->_name != XMLRPC_BAD_POINTER) + + +/*========================================================================= +** xml_element_new +**========================================================================= +** Create a new xml_element. This routine isn't exported, because the +** arguments are implementation-dependent. +*/ + +static xml_element *xml_element_new (xmlrpc_env *env, char *name) +{ + xml_element *retval; + int name_valid, cdata_valid, children_valid; + + XMLRPC_ASSERT_ENV_OK(env); + XMLRPC_ASSERT(name != NULL); + + /* Set up our error-handling preconditions. */ + retval = NULL; + name_valid = cdata_valid = children_valid = 0; + + /* Allocate our xml_element structure. */ + retval = (xml_element*) malloc(sizeof(xml_element)); + XMLRPC_FAIL_IF_NULL(retval, env, XMLRPC_INTERNAL_ERROR, + "Couldn't allocate memory for XML element"); + + /* Set our parent field to NULL. */ + retval->_parent = NULL; + + /* Copy over the element name. */ + retval->_name = (char*) malloc(strlen(name) + 1); + XMLRPC_FAIL_IF_NULL(retval->_name, env, XMLRPC_INTERNAL_ERROR, + "Couldn't allocate memory for XML element"); + name_valid = 1; + strcpy(retval->_name, name); + + /* Initialize a block to hold our CDATA. */ + XMLRPC_TYPED_MEM_BLOCK_INIT(char, env, &retval->_cdata, 0); + XMLRPC_FAIL_IF_FAULT(env); + cdata_valid = 1; + + /* Initialize a block to hold our child elements. */ + XMLRPC_TYPED_MEM_BLOCK_INIT(xml_element*, env, &retval->_children, 0); + XMLRPC_FAIL_IF_FAULT(env); + children_valid = 1; + + cleanup: + if (env->fault_occurred) { + if (retval) { + if (name_valid) + free(retval->_name); + if (cdata_valid) + xmlrpc_mem_block_clean(&retval->_cdata); + if (children_valid) + xmlrpc_mem_block_clean(&retval->_children); + free(retval); + } + return NULL; + } else { + return retval; + } +} + + +/*========================================================================= +** xml_element_free +**========================================================================= +** Blow away an existing element & all of its child elements. +*/ + +void xml_element_free (xml_element *elem) +{ + xmlrpc_mem_block *children; + int size, i; + xml_element **contents; + + XMLRPC_ASSERT_ELEM_OK(elem); + + free(elem->_name); + elem->_name = XMLRPC_BAD_POINTER; + xmlrpc_mem_block_clean(&elem->_cdata); + + /* Deallocate all of our children recursively. */ + children = &elem->_children; + contents = XMLRPC_TYPED_MEM_BLOCK_CONTENTS(xml_element*, children); + size = XMLRPC_TYPED_MEM_BLOCK_SIZE(xml_element*, children); + for (i = 0; i < size; i++) + xml_element_free(contents[i]); + + xmlrpc_mem_block_clean(&elem->_children); + free(elem); +} + + +/*========================================================================= +** Miscellaneous Accessors +**========================================================================= +** Return the fields of the xml_element. See the header for more +** documentation on each function works. +*/ + +const char *xml_element_name (const xml_element * const elem) +{ + XMLRPC_ASSERT_ELEM_OK(elem); + return elem->_name; +} + +/* The result of this function is NOT VALID until the end_element handler +** has been called! */ +size_t xml_element_cdata_size (xml_element *elem) +{ + XMLRPC_ASSERT_ELEM_OK(elem); + return XMLRPC_TYPED_MEM_BLOCK_SIZE(char, &elem->_cdata) - 1; +} + +char *xml_element_cdata (xml_element *elem) +{ + XMLRPC_ASSERT_ELEM_OK(elem); + return XMLRPC_TYPED_MEM_BLOCK_CONTENTS(char, &elem->_cdata); +} + +size_t xml_element_children_size (const xml_element *const elem) +{ + XMLRPC_ASSERT_ELEM_OK(elem); + return XMLRPC_TYPED_MEM_BLOCK_SIZE(xml_element*, &elem->_children); +} + +xml_element **xml_element_children (const xml_element *const elem) +{ + XMLRPC_ASSERT_ELEM_OK(elem); + return XMLRPC_TYPED_MEM_BLOCK_CONTENTS(xml_element*, &elem->_children); +} + + +/*========================================================================= +** Internal xml_element Utility Functions +**========================================================================= +*/ + +static void xml_element_append_cdata (xmlrpc_env *env, + xml_element *elem, + char *cdata, + size_t size) +{ + XMLRPC_ASSERT_ENV_OK(env); + XMLRPC_ASSERT_ELEM_OK(elem); + + XMLRPC_TYPED_MEM_BLOCK_APPEND(char, env, &elem->_cdata, cdata, size); +} + +/* Whether or not this function succeeds, it takes ownership of the 'child' +** argument. +** WARNING - This is the exact opposite of the usual memory ownership +** rules for xmlrpc_value! So please pay attention. */ +static void xml_element_append_child (xmlrpc_env *env, + xml_element *elem, + xml_element *child) +{ + XMLRPC_ASSERT_ENV_OK(env); + XMLRPC_ASSERT_ELEM_OK(elem); + XMLRPC_ASSERT_ELEM_OK(child); + XMLRPC_ASSERT(child->_parent == NULL); + + XMLRPC_TYPED_MEM_BLOCK_APPEND(xml_element*, env, &elem->_children, + &child, 1); + if (!env->fault_occurred) + child->_parent = elem; + else + xml_element_free(child); +} + + +/*========================================================================= +** Our parse context. We pass this around as libxml user data. +**========================================================================= +*/ + +typedef struct { + xmlrpc_env *env; + xml_element *root; + xml_element *current; +} parse_context; + + +/*========================================================================= +** LibXML Event Handler Functions +**========================================================================= +*/ + +static void +start_element (void *user_data, const xmlChar *name, const xmlChar **attrs) +{ + parse_context *context; + xml_element *elem, *new_current; + + XMLRPC_ASSERT(user_data != NULL && name != NULL); + + /* Get our context and see if an error has already occured. */ + context = (parse_context*) user_data; + if (!context->env->fault_occurred) { + + /* Set up our error-handling preconditions. */ + elem = NULL; + + /* Build a new element. */ + elem = xml_element_new(context->env, (char *) name); + XMLRPC_FAIL_IF_FAULT(context->env); + + /* Insert it in the appropriate place. */ + if (!context->root) { + context->root = elem; + context->current = elem; + elem = NULL; + } else { + XMLRPC_ASSERT(context->current != NULL); + + /* (We need to watch our error handling invariants very carefully + ** here. Read the docs for xml_element_append_child. */ + new_current = elem; + xml_element_append_child(context->env, context->current, elem); + elem = NULL; + XMLRPC_FAIL_IF_FAULT(context->env); + context->current = new_current; + } + + cleanup: + if (elem) + xml_element_free(elem); + } +} + +static void +end_element (void *user_data, const xmlChar *name) +{ + parse_context *context; + + XMLRPC_ASSERT(user_data != NULL && name != NULL); + + /* Get our context and see if an error has already occured. */ + context = (parse_context*) user_data; + if (!context->env->fault_occurred) { + + /* XXX - I think expat enforces these facts, but I want to be sure. + ** If one of these assertion ever fails, it should be replaced by a + ** non-assertion runtime error check. */ + XMLRPC_ASSERT(strcmp(name, context->current->_name) == 0); + XMLRPC_ASSERT(context->current->_parent != NULL || + context->current == context->root); + + /* Add a trailing '\0' to our cdata. */ + xml_element_append_cdata(context->env, context->current, "\0", 1); + XMLRPC_FAIL_IF_FAULT(context->env); + + /* Pop our "stack" of elements. */ + context->current = context->current->_parent; + + cleanup: + return; + } +} + +static void character_data (void *user_data, const xmlChar *s, int len) +{ + parse_context *context; + + XMLRPC_ASSERT(user_data != NULL && s != NULL && len >= 0); + + /* Get our context and see if an error has already occured. */ + context = (parse_context*) user_data; + if (!context->env->fault_occurred) { + + XMLRPC_ASSERT(context->current != NULL); + + xml_element_append_cdata(context->env, context->current, (char *) s, len); + XMLRPC_FAIL_IF_FAULT(context->env); + + cleanup: + return; + } +} + + +/*========================================================================= +** LibXML Driver +**========================================================================= +** XXX - We should allow the user to specify the encoding of our xml_data. +*/ + +static xmlSAXHandler sax_handler = { + NULL, /* internalSubset */ + NULL, /* isStandalone */ + NULL, /* hasInternalSubset */ + NULL, /* hasExternalSubset */ + NULL, /* resolveEntity */ + NULL, /* getEntity */ + NULL, /* entityDecl */ + NULL, /* notationDecl */ + NULL, /* attributeDecl */ + NULL, /* elementDecl */ + NULL, /* unparsedEntityDecl */ + NULL, /* setDocumentLocator */ + NULL, /* startDocument */ + NULL, /* endDocument */ + start_element, /* startElement */ + end_element, /* endElement */ + NULL, /* reference */ + character_data, /* characters */ + NULL, /* ignorableWhitespace */ + NULL, /* processingInstruction */ + NULL, /* comment */ + NULL, /* warning */ + NULL, /* error */ + NULL, /* fatalError */ + NULL, /* getParameterEntity */ + NULL, /* cdataBlock */ + NULL, /* externalSubset */ + 1 /* initialized */ + + /* Following are SAX2 fields. Any ifdef here? */ + + ,NULL, /* _private */ + NULL, /* startElementNs */ + NULL, /* endElementNs */ + NULL /* serror */ +}; + + + +void +xml_parse(xmlrpc_env * const envP, + const char * const xmlData, + size_t const xmlDataLen, + xml_element ** const resultPP) { + + parse_context context; + xmlParserCtxt *parser; + int err; + + XMLRPC_ASSERT_ENV_OK(envP); + XMLRPC_ASSERT(xmlData != NULL && xmlDataLen >= 0); + + /* Set up our error-handling preconditions. */ + parser = NULL; + context.root = NULL; + + /* Set up the rest of our parse context. */ + context.env = envP; + context.current = NULL; + + /* Set up our XML parser. */ + parser = xmlCreatePushParserCtxt(&sax_handler, &context, NULL, 0, NULL); + XMLRPC_FAIL_IF_NULL(parser, envP, XMLRPC_INTERNAL_ERROR, + "Could not create expat parser"); + + /* Parse our data. */ + err = xmlParseChunk(parser, xmlData, xmlDataLen, 1); + if (err) + XMLRPC_FAIL(envP, XMLRPC_PARSE_ERROR, "XML parsing failed"); + XMLRPC_FAIL_IF_FAULT(envP); + + /* Perform some sanity checks. */ + XMLRPC_ASSERT(context.root != NULL); + XMLRPC_ASSERT(context.current == NULL); + + *resultPP = context.root; + + cleanup: + if (parser) + xmlFreeParserCtxt(parser); + + if (envP->fault_occurred) { + if (context.root) + xml_element_free(context.root); + } +} diff --git a/src/xmlrpc_parse.c b/src/xmlrpc_parse.c new file mode 100644 index 0000000..3eb2ca8 --- /dev/null +++ b/src/xmlrpc_parse.c @@ -0,0 +1,990 @@ +/* Copyright information is at end of file. */ + +#include "xmlrpc_config.h" + +#include +#include +#include +#include +#include + +#include "bool.h" + +#include "xmlrpc-c/base.h" +#include "xmlrpc-c/base_int.h" +#include "xmlrpc-c/string_int.h" +#include "xmlrpc-c/xmlparser.h" + + +/*========================================================================= +** Data Format +**========================================================================= +** An XML-RPC document consists of a single methodCall or methodResponse +** element. +** +** methodCall methodName, params +** methodResponse (params|fault) +** params param* +** param value +** fault value +** value (i4|int|boolean|string|double|dateTime.iso8601|base64| +** nil|struct|array) +** array data +** data value* +** struct member* +** member name, value +** +** Contain CDATA: methodName, i4, int, boolean, string, double, +** dateTime.iso8601, base64, name +** +** We attempt to validate the structure of the XML document carefully. +** We also try *very* hard to handle malicious data gracefully, and without +** leaking memory. +** +** The CHECK_NAME and CHECK_CHILD_COUNT macros examine an XML element, and +** invoke XMLRPC_FAIL if something looks wrong. +*/ + +#define CHECK_NAME(env,elem,name) \ + do \ + if (!xmlrpc_streq((name), xml_element_name(elem))) \ + XMLRPC_FAIL2(env, XMLRPC_PARSE_ERROR, \ + "Expected element of type <%s>, found <%s>", \ + (name), xml_element_name(elem)); \ + while (0) + +#define CHECK_CHILD_COUNT(env,elem,count) \ + do \ + if (xml_element_children_size(elem) != (count)) \ + XMLRPC_FAIL3(env, XMLRPC_PARSE_ERROR, \ + "Expected <%s> to have %d children, found %d", \ + xml_element_name(elem), (count), \ + xml_element_children_size(elem)); \ + while (0) + +static xml_element * +get_child_by_name (xmlrpc_env *env, xml_element *parent, char *name) +{ + size_t child_count, i; + xml_element **children; + + children = xml_element_children(parent); + child_count = xml_element_children_size(parent); + for (i = 0; i < child_count; i++) { + if (xmlrpc_streq(xml_element_name(children[i]), name)) + return children[i]; + } + + xmlrpc_env_set_fault_formatted(env, XMLRPC_PARSE_ERROR, + "Expected <%s> to have child <%s>", + xml_element_name(parent), name); + return NULL; +} + + +/*========================================================================= +** Number-Parsing Functions +**========================================================================= +** These functions mirror atoi, atof, etc., but provide better +** error-handling. These routines may reset errno to zero. +*/ + +static xmlrpc_int32 +xmlrpc_atoi(xmlrpc_env *env, char *str, size_t strlen, + xmlrpc_int32 min, xmlrpc_int32 max) +{ + long i; + char *end; + + XMLRPC_ASSERT_ENV_OK(env); + XMLRPC_ASSERT_PTR_OK(str); + + /* Suppress compiler warnings. */ + i = 0; + + /* Check for leading white space. */ + if (isspace(str[0])) + XMLRPC_FAIL1(env, XMLRPC_PARSE_ERROR, + "\"%s\" must not contain whitespace", str); + + /* Convert the value. */ + end = str + strlen; + errno = 0; + i = strtol(str, &end, 10); + + /* Look for ERANGE. */ + if (errno != 0) + /* XXX - Do all operating systems have thread-safe strerror? */ + XMLRPC_FAIL3(env, XMLRPC_PARSE_ERROR, + "error parsing \"%s\": %s (%d)", + str, strerror(errno), errno); + + /* Look for out-of-range errors which didn't produce ERANGE. */ + if (i < min || i > max) + XMLRPC_FAIL3(env, XMLRPC_PARSE_ERROR, + "\"%s\" must be in range %d to %d", str, min, max); + + /* Check for unused characters. */ + if (end != str + strlen) + XMLRPC_FAIL1(env, XMLRPC_PARSE_ERROR, + "\"%s\" contained trailing data", str); + + cleanup: + errno = 0; + if (env->fault_occurred) + return 0; + return (xmlrpc_int32) i; +} + + + +static double +xmlrpc_atod(xmlrpc_env *env, char *str, size_t strlen) +{ + double d; + char *end; + + XMLRPC_ASSERT_ENV_OK(env); + XMLRPC_ASSERT_PTR_OK(str); + + /* Suppress compiler warnings. */ + d = 0.0; + + /* Check for leading white space. */ + if (isspace(str[0])) + XMLRPC_FAIL1(env, XMLRPC_PARSE_ERROR, + "\"%s\" must not contain whitespace", str); + + /* Convert the value. */ + end = str + strlen; + errno = 0; + d = strtod(str, &end); + + /* Look for ERANGE. */ + if (errno != 0) + /* XXX - Do all operating systems have thread-safe strerror? */ + XMLRPC_FAIL3(env, XMLRPC_PARSE_ERROR, + "error parsing \"%s\": %s (%d)", + str, strerror(errno), errno); + + /* Check for unused characters. */ + if (end != str + strlen) + XMLRPC_FAIL1(env, XMLRPC_PARSE_ERROR, + "\"%s\" contained trailing data", str); + + cleanup: + errno = 0; + if (env->fault_occurred) + return 0.0; + return d; +} + + +/*========================================================================= +** make_string +**========================================================================= +** Make an XML-RPC string. +** +** SECURITY: We validate our UTF-8 first. This incurs a performance +** penalty, but ensures that we will never pass maliciously malformed +** UTF-8 data back up to the user layer, where it could wreak untold +** damange. Don't comment out this check unless you know *exactly* what +** you're doing. (Win32 developers who remove this check are *begging* +** to wind up on BugTraq, because many of the Win32 filesystem routines +** rely on an insecure UTF-8 decoder.) +** +** XXX - This validation is redundant if the user chooses to convert +** UTF-8 data into a wchar_t string. +*/ + +static xmlrpc_value * +make_string(xmlrpc_env * const envP, + char * const cdata, + size_t const cdata_size) { +#if HAVE_UNICODE_WCHAR + xmlrpc_validate_utf8(envP, cdata, cdata_size); +#endif + + if (envP->fault_occurred) + return NULL; + return xmlrpc_build_value(envP, "s#", cdata, cdata_size); +} + + + +/* Forward declaration for recursion */ +static xmlrpc_value * +convert_value(xmlrpc_env * const envP, + unsigned int const maxRecursion, + xml_element * const elemP); + + + +static void +convertBase64(xmlrpc_env * const envP, + const char * const cdata, + size_t const cdata_size, + xmlrpc_value ** const valuePP) { + + xmlrpc_mem_block *decoded; + + decoded = xmlrpc_base64_decode(envP, cdata, cdata_size); + if (!envP->fault_occurred) { + unsigned char * const asciiData = + XMLRPC_MEMBLOCK_CONTENTS(unsigned char, decoded); + size_t const asciiLen = + XMLRPC_MEMBLOCK_SIZE(unsigned char, decoded); + + *valuePP = xmlrpc_build_value(envP, "6", asciiData, asciiLen); + + XMLRPC_MEMBLOCK_FREE(unsigned char, decoded); + } +} + + + +/*========================================================================= +** convert_array +**========================================================================= +** Convert an XML element representing an array into an xmlrpc_value. +*/ + +static xmlrpc_value * +convert_array(xmlrpc_env * const envP, + unsigned int const maxRecursion, + xml_element * const elemP) { + + xml_element *data, **values, *value; + xmlrpc_value *array, *item; + int size, i; + + XMLRPC_ASSERT_ENV_OK(envP); + XMLRPC_ASSERT(elemP != NULL); + + /* Set up our error-handling preconditions. */ + array = item = NULL; + + /* Allocate an array to hold our values. */ + array = xmlrpc_build_value(envP, "()"); + XMLRPC_FAIL_IF_FAULT(envP); + + /* We don't need to check our element name--our callers do that. */ + CHECK_CHILD_COUNT(envP, elemP, 1); + data = xml_element_children(elemP)[0]; + CHECK_NAME(envP, data, "data"); + + /* Iterate over our children. */ + values = xml_element_children(data); + size = xml_element_children_size(data); + for (i = 0; i < size; i++) { + value = values[i]; + item = convert_value(envP, maxRecursion-1, value); + XMLRPC_FAIL_IF_FAULT(envP); + + xmlrpc_array_append_item(envP, array, item); + xmlrpc_DECREF(item); + item = NULL; + XMLRPC_FAIL_IF_FAULT(envP); + } + + cleanup: + if (item) + xmlrpc_DECREF(item); + if (envP->fault_occurred) { + if (array) + xmlrpc_DECREF(array); + return NULL; + } + return array; +} + + + +/*========================================================================= +** convert_struct +**========================================================================= +** Convert an XML element representing a struct into an xmlrpc_value. +*/ + +static xmlrpc_value * +convert_struct(xmlrpc_env * const envP, + unsigned int const maxRecursion, + xml_element * const elemP) { + + xmlrpc_value *strct, *key, *value; + xml_element **members, *member, *name_elemP, *value_elemP; + int size, i; + char *cdata; + size_t cdata_size; + + XMLRPC_ASSERT_ENV_OK(envP); + XMLRPC_ASSERT(elemP != NULL); + + /* Set up our error-handling preconditions. */ + strct = key = value = NULL; + + /* Allocate an array to hold our members. */ + strct = xmlrpc_struct_new(envP); + XMLRPC_FAIL_IF_FAULT(envP); + + /* Iterate over our children, extracting key/value pairs. */ + /* We don't need to check our element name--our callers do that. */ + members = xml_element_children(elemP); + size = xml_element_children_size(elemP); + for (i = 0; i < size; i++) { + member = members[i]; + CHECK_NAME(envP, member, "member"); + CHECK_CHILD_COUNT(envP, member, 2); + + /* Get our key. */ + name_elemP = get_child_by_name(envP, member, "name"); + XMLRPC_FAIL_IF_FAULT(envP); + CHECK_CHILD_COUNT(envP, name_elemP, 0); + cdata = xml_element_cdata(name_elemP); + cdata_size = xml_element_cdata_size(name_elemP); + key = make_string(envP, cdata, cdata_size); + XMLRPC_FAIL_IF_FAULT(envP); + + /* Get our value. */ + value_elemP = get_child_by_name(envP, member, "value"); + XMLRPC_FAIL_IF_FAULT(envP); + value = convert_value(envP, maxRecursion-1, value_elemP); + XMLRPC_FAIL_IF_FAULT(envP); + + /* Add the key/value pair to our struct. */ + xmlrpc_struct_set_value_v(envP, strct, key, value); + XMLRPC_FAIL_IF_FAULT(envP); + + /* Release our references & memory, and restore our invariants. */ + xmlrpc_DECREF(key); + key = NULL; + xmlrpc_DECREF(value); + value = NULL; + } + + cleanup: + if (key) + xmlrpc_DECREF(key); + if (value) + xmlrpc_DECREF(value); + if (envP->fault_occurred) { + if (strct) + xmlrpc_DECREF(strct); + return NULL; + } + return strct; +} + + + +static xmlrpc_value * +convert_value(xmlrpc_env * const envP, + unsigned int const maxRecursion, + xml_element * const elemP) { +/*---------------------------------------------------------------------------- + Compute the xmlrpc_value represented by the XML element 'elem'. + Return that xmlrpc_value. + + We call convert_array() and convert_struct(), which may ultimately + call us recursively. Don't recurse any more than 'maxRecursion' + times. +-----------------------------------------------------------------------------*/ + int child_count; + xmlrpc_value * retval; + + XMLRPC_ASSERT_ENV_OK(envP); + XMLRPC_ASSERT(elemP != NULL); + + /* Error-handling preconditions. + ** If we haven't changed any of these from their default state, we're + ** allowed to tail-call xmlrpc_build_value. */ + retval = NULL; + + /* Assume we'll need to recurse, make sure we're allowed */ + if (maxRecursion < 1) + XMLRPC_FAIL(envP, XMLRPC_PARSE_ERROR, + "Nested data structure too deep."); + + /* Validate our structure, and see whether we have a child element. */ + CHECK_NAME(envP, elemP, "value"); + child_count = xml_element_children_size(elemP); + + if (child_count == 0) { + /* We have no type element, so treat the value as a string. */ + char * const cdata = xml_element_cdata(elemP); + size_t const cdata_size = xml_element_cdata_size(elemP); + retval = make_string(envP, cdata, cdata_size); + } else { + /* We should have a type tag inside our value tag. */ + xml_element * child; + const char * child_name; + + CHECK_CHILD_COUNT(envP, elemP, 1); + child = xml_element_children(elemP)[0]; + + /* Parse our value-containing element. */ + child_name = xml_element_name(child); + if (xmlrpc_streq(child_name, "struct")) { + retval = convert_struct(envP, maxRecursion, child); + } else if (xmlrpc_streq(child_name, "array")) { + CHECK_CHILD_COUNT(envP, child, 1); + retval = convert_array(envP, maxRecursion, child); + } else { + char * cdata; + size_t cdata_size; + + CHECK_CHILD_COUNT(envP, child, 0); + cdata = xml_element_cdata(child); + cdata_size = xml_element_cdata_size(child); + if (xmlrpc_streq(child_name, "i4") || + xmlrpc_streq(child_name, "int")) { + xmlrpc_int32 const i = + xmlrpc_atoi(envP, cdata, strlen(cdata), + XMLRPC_INT32_MIN, XMLRPC_INT32_MAX); + XMLRPC_FAIL_IF_FAULT(envP); + retval = xmlrpc_build_value(envP, "i", i); + } else if (xmlrpc_streq(child_name, "string")) { + retval = make_string(envP, cdata, cdata_size); + } else if (xmlrpc_streq(child_name, "boolean")) { + xmlrpc_int32 const i = + xmlrpc_atoi(envP, cdata, strlen(cdata), 0, 1); + XMLRPC_FAIL_IF_FAULT(envP); + retval = xmlrpc_build_value(envP, "b", (xmlrpc_bool) i); + } else if (xmlrpc_streq(child_name, "double")) { + double const d = xmlrpc_atod(envP, cdata, strlen(cdata)); + XMLRPC_FAIL_IF_FAULT(envP); + retval = xmlrpc_build_value(envP, "d", d); + } else if (xmlrpc_streq(child_name, "dateTime.iso8601")) { + retval = xmlrpc_build_value(envP, "8", cdata); + } else if (xmlrpc_streq(child_name, "nil")) { + retval = xmlrpc_build_value(envP, "n"); + } else if (xmlrpc_streq(child_name, "base64")) { + /* No more tail calls once we do this! */ + + convertBase64(envP, cdata, cdata_size, &retval); + if (envP->fault_occurred) + /* Just for cleanup code: */ + retval = NULL; + } else { + XMLRPC_FAIL1(envP, XMLRPC_PARSE_ERROR, + "Unknown value type -- XML element is named " + "<%s>", child_name); + } + } + } + + cleanup: + if (envP->fault_occurred) { + if (retval) + xmlrpc_DECREF(retval); + retval = NULL; + } + return retval; +} + + + +/*========================================================================= +** convert_params +**========================================================================= +** Convert an XML element representing a list of params into an +** xmlrpc_value (of type array). +*/ + +static xmlrpc_value * +convert_params(xmlrpc_env * const envP, + const xml_element * const elemP) { +/*---------------------------------------------------------------------------- + Convert an XML element representing a list of parameters (i.e. a + element) to an xmlrpc_value of type array. Note that an + array is normally represented in XML by a element. We use + type xmlrpc_value to represent the parameter list just for convenience. +-----------------------------------------------------------------------------*/ + xmlrpc_value *array, *item; + int size, i; + xml_element **params, *param, *value; + + XMLRPC_ASSERT_ENV_OK(envP); + XMLRPC_ASSERT(elemP != NULL); + + /* Set up our error-handling preconditions. */ + array = item = NULL; + + /* Allocate an array to hold our parameters. */ + array = xmlrpc_build_value(envP, "()"); + XMLRPC_FAIL_IF_FAULT(envP); + + /* We're responsible for checking our own element name. */ + CHECK_NAME(envP, elemP, "params"); + + /* Iterate over our children. */ + size = xml_element_children_size(elemP); + params = xml_element_children(elemP); + for (i = 0; i < size; ++i) { + unsigned int const maxNest = xmlrpc_limit_get(XMLRPC_NESTING_LIMIT_ID); + + param = params[i]; + CHECK_NAME(envP, param, "param"); + CHECK_CHILD_COUNT(envP, param, 1); + + value = xml_element_children(param)[0]; + item = convert_value(envP, maxNest, value); + XMLRPC_FAIL_IF_FAULT(envP); + + xmlrpc_array_append_item(envP, array, item); + xmlrpc_DECREF(item); + item = NULL; + XMLRPC_FAIL_IF_FAULT(envP); + } + + cleanup: + if (envP->fault_occurred) { + if (array) + xmlrpc_DECREF(array); + if (item) + xmlrpc_DECREF(item); + return NULL; + } + return array; +} + + + +static void +parseCallXml(xmlrpc_env * const envP, + const char * const xmlData, + size_t const xmlLen, + xml_element ** const callElemPP) { + + xml_element * callElemP; + xmlrpc_env env; + + xmlrpc_env_init(&env); + xml_parse(&env, xmlData, xmlLen, &callElemP); + if (env.fault_occurred) + xmlrpc_env_set_fault_formatted( + envP, env.fault_code, "Call is not valid XML. %s", + env.fault_string); + else { + if (!xmlrpc_streq(xml_element_name(callElemP), "methodCall")) + xmlrpc_env_set_fault_formatted( + envP, XMLRPC_PARSE_ERROR, + "XML-RPC call should be a element. " + "Instead, we have a <%s> element.", + xml_element_name(callElemP)); + + if (!envP->fault_occurred) + *callElemPP = callElemP; + + if (envP->fault_occurred) + xml_element_free(callElemP); + } + xmlrpc_env_clean(&env); +} + + + +static void +parseMethodNameElement(xmlrpc_env * const envP, + xml_element * const nameElemP, + const char ** const methodNameP) { + + XMLRPC_ASSERT(xmlrpc_streq(xml_element_name(nameElemP), "methodName")); + + if (xml_element_children_size(nameElemP) > 0) + xmlrpc_env_set_fault_formatted( + envP, XMLRPC_PARSE_ERROR, + "A element should not have children. " + "This one has %u of them.", xml_element_children_size(nameElemP)); + else { + const char * const cdata = xml_element_cdata(nameElemP); + + xmlrpc_validate_utf8(envP, cdata, strlen(cdata)); + + if (!envP->fault_occurred) { + *methodNameP = strdup(cdata); + if (*methodNameP == NULL) + xmlrpc_faultf(envP, + "Could not allocate memory for method name"); + } + } +} + + + +static void +parseCallChildren(xmlrpc_env * const envP, + xml_element * const callElemP, + const char ** const methodNameP, + xmlrpc_value ** const paramArrayPP ) { +/*---------------------------------------------------------------------------- + Parse the children of a XML element *callElemP. They should + be and . +-----------------------------------------------------------------------------*/ + size_t const callChildCount = xml_element_children_size(callElemP); + + xml_element * nameElemP; + + XMLRPC_ASSERT(xmlrpc_streq(xml_element_name(callElemP), "methodCall")); + + nameElemP = get_child_by_name(envP, callElemP, "methodName"); + + if (!envP->fault_occurred) { + parseMethodNameElement(envP, nameElemP, methodNameP); + + if (!envP->fault_occurred) { + /* Convert our parameters. */ + if (callChildCount > 1) { + xml_element * paramsElemP; + + paramsElemP = get_child_by_name(envP, callElemP, "params"); + + if (!envP->fault_occurred) + *paramArrayPP = convert_params(envP, paramsElemP); + } else { + /* Workaround for Ruby XML-RPC and old versions of + xmlrpc-epi. Future improvement: Instead of looking + at child count, we should just check for existence + of . + */ + *paramArrayPP = xmlrpc_array_new(envP); + } + if (!envP->fault_occurred) { + if (callChildCount > 2) + xmlrpc_env_set_fault_formatted( + envP, XMLRPC_PARSE_ERROR, + " has extraneous children, other than " + " and . Total child count = %u", + callChildCount); + + if (envP->fault_occurred) + xmlrpc_DECREF(*paramArrayPP); + } + if (envP->fault_occurred) + xmlrpc_strfree(*methodNameP); + } + } +} + + + +/*========================================================================= +** xmlrpc_parse_call +**========================================================================= +** Given some XML text, attempt to parse it as an XML-RPC call. Return +** a newly allocated xmlrpc_call structure (or NULL, if an error occurs). +** The two output variables will contain either valid values (which +** must free() and xmlrpc_DECREF(), respectively) or NULLs (if an error +** occurs). +*/ + +void +xmlrpc_parse_call(xmlrpc_env * const envP, + const char * const xmlData, + size_t const xmlLen, + const char ** const methodNameP, + xmlrpc_value ** const paramArrayPP) { + + XMLRPC_ASSERT_ENV_OK(envP); + XMLRPC_ASSERT(xmlData != NULL); + XMLRPC_ASSERT(methodNameP != NULL && paramArrayPP != NULL); + + /* SECURITY: Last-ditch attempt to make sure our content length is + legal. XXX - This check occurs too late to prevent an attacker + from creating an enormous memory block, so you should try to + enforce it *before* reading any data off the network. + */ + if (xmlLen > xmlrpc_limit_get(XMLRPC_XML_SIZE_LIMIT_ID)) + xmlrpc_env_set_fault_formatted( + envP, XMLRPC_LIMIT_EXCEEDED_ERROR, + "XML-RPC request too large. Max allowed is %u bytes", + xmlrpc_limit_get(XMLRPC_XML_SIZE_LIMIT_ID)); + else { + xml_element * callElemP; + parseCallXml(envP, xmlData, xmlLen, &callElemP); + if (!envP->fault_occurred) { + parseCallChildren(envP, callElemP, methodNameP, paramArrayPP); + + xml_element_free(callElemP); + } + } + if (envP->fault_occurred) { + *methodNameP = NULL; + *paramArrayPP = NULL; + } +} + + + +static void +interpretFaultValue(xmlrpc_env * const envP, + xmlrpc_value * const faultVP, + int * const faultCodeP, + const char ** const faultStringP) { + + if (faultVP->_type != XMLRPC_TYPE_STRUCT) + xmlrpc_env_set_fault( + envP, XMLRPC_PARSE_ERROR, + " element of response contains is not " + "of structure type"); + else { + xmlrpc_value * faultCodeVP; + xmlrpc_env fvEnv; + + xmlrpc_env_init(&fvEnv); + + xmlrpc_struct_read_value(&fvEnv, faultVP, "faultCode", &faultCodeVP); + if (!fvEnv.fault_occurred) { + xmlrpc_read_int(&fvEnv, faultCodeVP, faultCodeP); + if (!fvEnv.fault_occurred) { + xmlrpc_value * faultStringVP; + + xmlrpc_struct_read_value(&fvEnv, faultVP, "faultString", + &faultStringVP); + if (!fvEnv.fault_occurred) { + xmlrpc_read_string(&fvEnv, faultStringVP, faultStringP); + xmlrpc_DECREF(faultStringVP); + } + } + xmlrpc_DECREF(faultCodeVP); + } + if (fvEnv.fault_occurred) + xmlrpc_env_set_fault_formatted( + envP, XMLRPC_PARSE_ERROR, + "Invalid struct for value. %s", fvEnv.fault_string); + + xmlrpc_env_clean(&fvEnv); + } +} + + + +static void +parseFaultElement(xmlrpc_env * const envP, + const xml_element * const faultElement, + int * const faultCodeP, + const char ** const faultStringP) { + + unsigned int const maxRecursion = + xmlrpc_limit_get(XMLRPC_NESTING_LIMIT_ID); + + XMLRPC_ASSERT(xmlrpc_streq(xml_element_name(faultElement), "fault")); + + if (xml_element_children_size(faultElement) != 1) + xmlrpc_env_set_fault_formatted( + envP, XMLRPC_PARSE_ERROR, + " element should have 1 child, but it has %u.", + xml_element_children_size(faultElement)); + else { + xml_element * const faultValueP = + xml_element_children(faultElement)[0]; + + xmlrpc_value * faultVP; + + faultVP = convert_value(envP, maxRecursion, faultValueP); + + if (!envP->fault_occurred) { + interpretFaultValue(envP, faultVP, faultCodeP, faultStringP); + + xmlrpc_DECREF(faultVP); + } + } +} + + + +static void +parseParamsElement(xmlrpc_env * const envP, + const xml_element * const paramsElementP, + xmlrpc_value ** const resultPP) { + + xmlrpc_value * paramsVP; + xmlrpc_env env; + + xmlrpc_env_init(&env); + + XMLRPC_ASSERT(xmlrpc_streq(xml_element_name(paramsElementP), "params")); + + paramsVP = convert_params(envP, paramsElementP); + + if (!envP->fault_occurred) { + int arraySize; + xmlrpc_env sizeEnv; + + XMLRPC_ASSERT_ARRAY_OK(paramsVP); + + xmlrpc_env_init(&sizeEnv); + + arraySize = xmlrpc_array_size(&sizeEnv, paramsVP); + /* Since it's a valid array, as asserted above, can't fail */ + XMLRPC_ASSERT(!sizeEnv.fault_occurred); + + if (arraySize != 1) + xmlrpc_env_set_fault_formatted( + &env, XMLRPC_PARSE_ERROR, + "Contains %d items. It should have 1.", + arraySize); + else { + xmlrpc_array_read_item(envP, paramsVP, 0, resultPP); + } + xmlrpc_DECREF(paramsVP); + xmlrpc_env_clean(&sizeEnv); + } + if (env.fault_occurred) + xmlrpc_env_set_fault_formatted( + envP, env.fault_code, + "Invalid element. %s", env.fault_string); + + xmlrpc_env_clean(&env); +} + + + +static void +parseMethodResponseElt(xmlrpc_env * const envP, + const xml_element * const methodResponseEltP, + xmlrpc_value ** const resultPP, + int * const faultCodeP, + const char ** const faultStringP) { + + XMLRPC_ASSERT(xmlrpc_streq(xml_element_name(methodResponseEltP), + "methodResponse")); + + if (xml_element_children_size(methodResponseEltP) == 1) { + xml_element * const child = + xml_element_children(methodResponseEltP)[0]; + + if (xmlrpc_streq(xml_element_name(child), "params")) { + /* It's a successful response */ + parseParamsElement(envP, child, resultPP); + *faultStringP = NULL; + } else if (xmlrpc_streq(xml_element_name(child), "fault")) { + /* It's a failure response */ + parseFaultElement(envP, child, faultCodeP, faultStringP); + } else + xmlrpc_env_set_fault_formatted( + envP, XMLRPC_PARSE_ERROR, + " must contain or , " + "but contains <%s>.", xml_element_name(child)); + } else + xmlrpc_env_set_fault_formatted( + envP, XMLRPC_PARSE_ERROR, + " has %u children, should have 1.", + xml_element_children_size(methodResponseEltP)); +} + + + +void +xmlrpc_parse_response2(xmlrpc_env * const envP, + const char * const xmlData, + size_t const xmlDataLen, + xmlrpc_value ** const resultPP, + int * const faultCodeP, + const char ** const faultStringP) { +/*---------------------------------------------------------------------------- + Given some XML text, attempt to parse it as an XML-RPC response. + + If the response is a regular, valid response, return a new reference + to the appropriate value as *resultP and return NULL as + *faultStringP and nothing as *faultCodeP. + + If the response valid, but indicates a failure of the RPC, return the + fault string in newly malloc'ed space as *faultStringP and the fault + code as *faultCodeP and nothing as *resultP. + + If the XML text is not a valid response or something prevents us from + parsing it, return a description of the error as *envP and nothing else. +-----------------------------------------------------------------------------*/ + xml_element * response; + + XMLRPC_ASSERT_ENV_OK(envP); + XMLRPC_ASSERT(xmlData != NULL); + + /* SECURITY: Last-ditch attempt to make sure our content length is legal. + ** XXX - This check occurs too late to prevent an attacker from creating + ** an enormous memory block, so you should try to enforce it + ** *before* reading any data off the network. */ + if (xmlDataLen > xmlrpc_limit_get(XMLRPC_XML_SIZE_LIMIT_ID)) + xmlrpc_env_set_fault_formatted( + envP, XMLRPC_LIMIT_EXCEEDED_ERROR, + "XML-RPC response too large. Our limit is %u characters. " + "We got %u characters", + xmlrpc_limit_get(XMLRPC_XML_SIZE_LIMIT_ID), xmlDataLen); + else { + xml_parse(envP, xmlData, xmlDataLen, &response); + if (!envP->fault_occurred) { + /* Pick apart and verify our structure. */ + if (xmlrpc_streq(xml_element_name(response), "methodResponse")) { + parseMethodResponseElt(envP, response, + resultPP, faultCodeP, faultStringP); + } else + xmlrpc_env_set_fault_formatted( + envP, XMLRPC_PARSE_ERROR, + "XML-RPC response must consist of a " + " element. This has a <%s> instead.", + xml_element_name(response)); + + xml_element_free(response); + } + } +} + + + +xmlrpc_value * +xmlrpc_parse_response(xmlrpc_env * const envP, + const char * const xmlData, + size_t const xmlDataLen) { +/*---------------------------------------------------------------------------- + This exists for backward compatibility. It is like + xmlrpc_parse_response2(), except that it merges the concepts of a + failed RPC and an error in executing the RPC. +-----------------------------------------------------------------------------*/ + xmlrpc_value * retval; + xmlrpc_value * result; + const char * faultString; + int faultCode; + + xmlrpc_parse_response2(envP, xmlData, xmlDataLen, + &result, &faultCode, &faultString); + + if (envP->fault_occurred) + retval = NULL; + else { + if (faultString) { + xmlrpc_env_set_fault(envP, faultCode, faultString); + xmlrpc_strfree(faultString); + retval = NULL; + } else + retval = result; /* transfer reference */ + } + return retval; +} + + + +/* Copyright (C) 2001 by First Peer, Inc. All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +** ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +** OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +** HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +** LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +** OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +** SUCH DAMAGE. */ diff --git a/src/xmlrpc_serialize.c b/src/xmlrpc_serialize.c new file mode 100644 index 0000000..53223ca --- /dev/null +++ b/src/xmlrpc_serialize.c @@ -0,0 +1,611 @@ +/* Copyright information is at end of file */ + +#include "xmlrpc_config.h" + +#include +#include +#include +#include +#include + +#include "xmlrpc-c/base.h" +#include "xmlrpc-c/base_int.h" + +#define CRLF "\015\012" +#define SMALL_BUFFER_SZ (128) +#define XML_PROLOGUE ""CRLF + + +/*========================================================================= +** format_out +**========================================================================= +** A lightweight print routine for use with various serialization +** functions. Only use this routine for printing small objects--it uses +** a fixed-size internal buffer and returns an error on overflow. +** In particular, do NOT use this routine to print XML-RPC string values! +*/ + +static void +format_out(xmlrpc_env *env, + xmlrpc_mem_block *output, + char *format_string, + ...) { + + va_list args; + char buffer[SMALL_BUFFER_SZ]; + int count; + + XMLRPC_ASSERT_ENV_OK(env); + + va_start(args, format_string); + + /* We assume that this function is present and works correctly. Right. */ + count = vsnprintf(buffer, SMALL_BUFFER_SZ, format_string, args); + + /* Old C libraries return -1 if vsnprintf overflows its buffer. + ** New C libraries return the number of characters which *would* have + ** been printed if the error did not occur. This is impressively vile. + ** Thank the C99 committee for this bright idea. But wait! We also + ** need to keep track of the trailing NULL. */ + if (count < 0 || count >= (SMALL_BUFFER_SZ - 1)) + XMLRPC_FAIL(env, XMLRPC_INTERNAL_ERROR, + "format_out overflowed internal buffer"); + + /* Append our new data to our output. */ + XMLRPC_TYPED_MEM_BLOCK_APPEND(char, env, output, buffer, count); + XMLRPC_FAIL_IF_FAULT(env); + +cleanup: + va_end(args); +} + + + +static void +assertValidUtf8(const char * const str ATTR_UNUSED, + size_t const len ATTR_UNUSED) { +/*---------------------------------------------------------------------------- + Assert that the string 'str' of length 'len' is valid UTF-8. +-----------------------------------------------------------------------------*/ +#if !defined NDEBUG + /* Check the assertion; if it's false, issue a message to + Standard Error, but otherwise ignore it. + */ + xmlrpc_env env; + + xmlrpc_env_init(&env); + xmlrpc_validate_utf8(&env, str, len); + if (env.fault_occurred) + fprintf(stderr, "*** xmlrpc-c WARNING ***: %s (%s)\n", + "Xmlrpc-c sending corrupted UTF-8 data to network", + env.fault_string); + xmlrpc_env_clean(&env); +#endif +} + + + +static size_t +escapedSize(const char * const chars, + size_t const len) { + + size_t size; + size_t i; + + size = 0; + for (i = 0; i < len; ++i) { + if (chars[i] == '<') + size += 4; /* < */ + else if (chars[i] == '>') + size += 4; /* > */ + else if (chars[i] == '&') + size += 5; /* & */ + else + size += 1; + } + return size; +} + + + +static void +escapeForXml(xmlrpc_env * const envP, + const char * const chars, + size_t const len, + xmlrpc_mem_block ** const outputPP) { +/*---------------------------------------------------------------------------- + Escape & and < in a UTF-8 string so as to make it suitable for the + content of an XML element. I.e. turn them into entity references + & and <. Also change > to >, even though not required + for XML, for symmetry. +-----------------------------------------------------------------------------*/ + xmlrpc_mem_block * outputP; + size_t outputSize; + + XMLRPC_ASSERT_ENV_OK(envP); + XMLRPC_ASSERT(chars != NULL); + + assertValidUtf8(chars, len); + + /* Note that in UTF-8, any byte that has high bit of zero is a + character all by itself (every byte of a multi-byte UTF-8 character + has the high bit set). Also, the Unicode code points < 128 are + identical to the ASCII ones. + */ + + outputSize = escapedSize(chars, len); + + outputP = XMLRPC_MEMBLOCK_NEW(char, envP, outputSize); + if (!envP->fault_occurred) { + char * p; + size_t i; + p = XMLRPC_MEMBLOCK_CONTENTS(char, outputP); /* Start at beginning */ + + for (i = 0; i < len; i++) { + if (chars[i] == '<') { + memcpy(p, "<", 4); + p += 4; + } else if (chars[i] == '>') { + memcpy(p, ">", 4); + p += 4; + } else if (chars[i] == '&') { + memcpy(p, "&", 5); + p += 5; + } else { + *p = chars[i]; + p += 1; + } + } + *outputPP = outputP; + assert(p == XMLRPC_MEMBLOCK_CONTENTS(char, outputP) + outputSize); + + if (envP->fault_occurred) + XMLRPC_MEMBLOCK_FREE(char, outputP); + } +} + + + +static void +serializeUtf8MemBlock(xmlrpc_env * const envP, + xmlrpc_mem_block * const outputP, + xmlrpc_mem_block * const inputP) { +/*---------------------------------------------------------------------------- + Append the characters in *inputP to the XML stream in *outputP. + + *inputP contains Unicode characters in UTF-8. + + We assume *inputP ends with a NUL character that marks end of + string, and we ignore that. (There might also be NUL characters + inside the string, though). +-----------------------------------------------------------------------------*/ + xmlrpc_mem_block * escapedP; + + XMLRPC_ASSERT_ENV_OK(envP); + XMLRPC_ASSERT(outputP != NULL); + XMLRPC_ASSERT(inputP != NULL); + + escapeForXml(envP, + XMLRPC_MEMBLOCK_CONTENTS(const char, inputP), + XMLRPC_MEMBLOCK_SIZE(const char, inputP) - 1, + /* -1 is for the terminating NUL */ + &escapedP); + if (!envP->fault_occurred) { + const char * const contents = + XMLRPC_MEMBLOCK_CONTENTS(const char, escapedP); + size_t const size = XMLRPC_MEMBLOCK_SIZE(char, escapedP); + + XMLRPC_MEMBLOCK_APPEND(char, envP, outputP, contents, size); + + XMLRPC_MEMBLOCK_FREE(const char, escapedP); + } +} + + + +static void +xmlrpc_serialize_base64_data(xmlrpc_env * const envP, + xmlrpc_mem_block * const output, + unsigned char * const data, + size_t const len) { +/*---------------------------------------------------------------------------- + Encode the 'len' bytes at 'data' in base64 ASCII and append the result to + 'output'. +-----------------------------------------------------------------------------*/ + xmlrpc_mem_block * encoded; + + encoded = xmlrpc_base64_encode(envP, data, len); + if (!envP->fault_occurred) { + unsigned char * const contents = + XMLRPC_MEMBLOCK_CONTENTS(unsigned char, encoded); + size_t const size = + XMLRPC_MEMBLOCK_SIZE(unsigned char, encoded); + + XMLRPC_MEMBLOCK_APPEND(char, envP, output, contents, size); + + XMLRPC_MEMBLOCK_FREE(char, encoded); + } +} + + + +/*========================================================================= +** xmlrpc_serialize_struct +**========================================================================= +** Dump the contents of a struct. +*/ + +static void +xmlrpc_serialize_struct(xmlrpc_env *env, + xmlrpc_mem_block *output, + xmlrpc_value *strct) { + + size_t size; + size_t i; + xmlrpc_value *key, *value; + + format_out(env, output, ""CRLF); + XMLRPC_FAIL_IF_FAULT(env); + + size = xmlrpc_struct_size(env, strct); + XMLRPC_FAIL_IF_FAULT(env); + for (i = 0; i < size; i++) { + xmlrpc_struct_get_key_and_value(env, strct, i, &key, &value); + XMLRPC_FAIL_IF_FAULT(env); + format_out(env, output, ""); + XMLRPC_FAIL_IF_FAULT(env); + serializeUtf8MemBlock(env, output, &key->_block); + XMLRPC_FAIL_IF_FAULT(env); + format_out(env, output, ""CRLF); + XMLRPC_FAIL_IF_FAULT(env); + xmlrpc_serialize_value(env, output, value); + XMLRPC_FAIL_IF_FAULT(env); + format_out(env, output, ""CRLF); + XMLRPC_FAIL_IF_FAULT(env); + } + + format_out(env, output, ""); + XMLRPC_FAIL_IF_FAULT(env); + +cleanup: + return; +} + + + +/*========================================================================= +** xmlrpc_serialize_value +**========================================================================= +** Dump a value in the appropriate fashion. +*/ + +void +xmlrpc_serialize_value(xmlrpc_env *env, + xmlrpc_mem_block *output, + xmlrpc_value *value) { + + xmlrpc_value *item; + size_t size; + unsigned char* contents; + size_t i; + + XMLRPC_ASSERT_ENV_OK(env); + XMLRPC_ASSERT(output != NULL); + XMLRPC_ASSERT_VALUE_OK(value); + + /* Print our ubiquitous header. */ + format_out(env, output, ""); + XMLRPC_FAIL_IF_FAULT(env); + + switch (value->_type) { + + case XMLRPC_TYPE_INT: + /* XXX - We assume that '%i' is the appropriate format specifier + ** for an xmlrpc_int32 value. We should add some test cases to + ** make sure this works. */ + format_out(env, output, "%i", value->_value.i); + break; + + case XMLRPC_TYPE_BOOL: + /* XXX - We assume that '%i' is the appropriate format specifier + ** for an xmlrpc_bool value. */ + format_out(env, output, "%i", + (value->_value.b) ? 1 : 0); + break; + + case XMLRPC_TYPE_DOUBLE: + /* We must output a number of the form [+-]?\d*.\d*. */ + format_out(env, output, "%f", value->_value.d); + break; + + case XMLRPC_TYPE_STRING: + format_out(env, output, ""); + XMLRPC_FAIL_IF_FAULT(env); + serializeUtf8MemBlock(env, output, &value->_block); + XMLRPC_FAIL_IF_FAULT(env); + format_out(env, output, ""); + break; + + case XMLRPC_TYPE_ARRAY: + format_out(env, output, ""CRLF); + XMLRPC_FAIL_IF_FAULT(env); + + /* Serialize each item. */ + size = xmlrpc_array_size(env, value); + XMLRPC_FAIL_IF_FAULT(env); + for (i = 0; i < size; i++) { + item = xmlrpc_array_get_item(env, value, i); + XMLRPC_FAIL_IF_FAULT(env); + xmlrpc_serialize_value(env, output, item); + XMLRPC_FAIL_IF_FAULT(env); + format_out(env, output, CRLF); + XMLRPC_FAIL_IF_FAULT(env); + } + + format_out(env, output, ""); + break; + + case XMLRPC_TYPE_STRUCT: + xmlrpc_serialize_struct(env, output, value); + break; + + case XMLRPC_TYPE_BASE64: + format_out(env, output, ""CRLF); + XMLRPC_FAIL_IF_FAULT(env); + contents = XMLRPC_TYPED_MEM_BLOCK_CONTENTS(unsigned char, + &value->_block); + size = XMLRPC_TYPED_MEM_BLOCK_SIZE(unsigned char, &value->_block); + xmlrpc_serialize_base64_data(env, output, contents, size); + XMLRPC_FAIL_IF_FAULT(env); + format_out(env, output, ""); + break; + + case XMLRPC_TYPE_DATETIME: + format_out(env, output, ""); + XMLRPC_FAIL_IF_FAULT(env); + serializeUtf8MemBlock(env, output, &value->_block); + XMLRPC_FAIL_IF_FAULT(env); + format_out(env, output, ""); + break; + + case XMLRPC_TYPE_C_PTR: + xmlrpc_env_set_fault_formatted( + env, XMLRPC_INTERNAL_ERROR, + "Tried to serialize a C pointer value."); + break; + + case XMLRPC_TYPE_NIL: + format_out(env, output, ""); + XMLRPC_FAIL_IF_FAULT(env); + break; + + case XMLRPC_TYPE_DEAD: + xmlrpc_env_set_fault_formatted( + env, XMLRPC_INTERNAL_ERROR, + "Tried to serialize a deaad value."); + break; + + default: + xmlrpc_env_set_fault_formatted( + env, XMLRPC_INTERNAL_ERROR, + "Invalid xmlrpc_value type: %d", value->_type); + } + XMLRPC_FAIL_IF_FAULT(env); + + /* Print our ubiquitous footer. */ + format_out(env, output, ""); + XMLRPC_FAIL_IF_FAULT(env); + + cleanup: + return; +} + + + +/*========================================================================= +** xmlrpc_serialize_params +**========================================================================= +** Serialize a list as a set of parameters. +*/ + +void +xmlrpc_serialize_params(xmlrpc_env *env, + xmlrpc_mem_block *output, + xmlrpc_value *param_array) { + + size_t size, i; + xmlrpc_value *item; + + XMLRPC_ASSERT_ENV_OK(env); + XMLRPC_ASSERT(output != NULL); + XMLRPC_ASSERT_VALUE_OK(param_array); + + format_out(env, output, ""CRLF); + XMLRPC_FAIL_IF_FAULT(env); + + /* Dump each parameter. */ + size = xmlrpc_array_size(env, param_array); + XMLRPC_FAIL_IF_FAULT(env); + for (i = 0; i < size; i++) { + format_out(env, output, ""); + XMLRPC_FAIL_IF_FAULT(env); + item = xmlrpc_array_get_item(env, param_array, i); + XMLRPC_FAIL_IF_FAULT(env); + xmlrpc_serialize_value(env, output, item); + XMLRPC_FAIL_IF_FAULT(env); + format_out(env, output, ""CRLF); + XMLRPC_FAIL_IF_FAULT(env); + } + + format_out(env, output, ""CRLF); + XMLRPC_FAIL_IF_FAULT(env); + + cleanup: + return; +} + + + +/*========================================================================= +** xmlrpc_serialize_call +**========================================================================= +** Serialize an XML-RPC call. +*/ + +void +xmlrpc_serialize_call(xmlrpc_env * const env, + xmlrpc_mem_block * const output, + const char * const method_name, + xmlrpc_value * const param_array) { + + xmlrpc_mem_block * encodedP; + char *contents; + size_t size; + + XMLRPC_ASSERT_ENV_OK(env); + XMLRPC_ASSERT(output != NULL); + XMLRPC_ASSERT(method_name != NULL); + XMLRPC_ASSERT_VALUE_OK(param_array); + + /* Set up our error-handling preconditions. */ + encodedP = NULL; + + /* Dump our header. */ + format_out(env, output, XML_PROLOGUE); + XMLRPC_FAIL_IF_FAULT(env); + format_out(env, output, ""CRLF""); + XMLRPC_FAIL_IF_FAULT(env); + + /* Dump the method name. */ + escapeForXml(env, method_name, strlen(method_name), &encodedP); + XMLRPC_FAIL_IF_FAULT(env); + contents = XMLRPC_MEMBLOCK_CONTENTS(char, encodedP); + size = XMLRPC_MEMBLOCK_SIZE(char, encodedP); + XMLRPC_MEMBLOCK_APPEND(char, env, output, contents, size); + XMLRPC_FAIL_IF_FAULT(env); + + /* Dump our parameters and footer. */ + format_out(env, output, ""CRLF); + XMLRPC_FAIL_IF_FAULT(env); + xmlrpc_serialize_params(env, output, param_array); + XMLRPC_FAIL_IF_FAULT(env); + format_out(env, output, ""CRLF); + XMLRPC_FAIL_IF_FAULT(env); + + cleanup: + if (encodedP) + XMLRPC_MEMBLOCK_FREE(char, encodedP); +} + + + +/*========================================================================= +** xmlrpc_serialize_response +**========================================================================= +** Serialize the (non-fault) response to an XML-RPC call. +*/ + +void +xmlrpc_serialize_response (xmlrpc_env *env, + xmlrpc_mem_block *output, + xmlrpc_value *value) { + + XMLRPC_ASSERT_ENV_OK(env); + XMLRPC_ASSERT(output != NULL); + XMLRPC_ASSERT_VALUE_OK(value); + + format_out(env, output, XML_PROLOGUE); + XMLRPC_FAIL_IF_FAULT(env); + format_out(env, output, ""CRLF""CRLF""); + XMLRPC_FAIL_IF_FAULT(env); + + xmlrpc_serialize_value(env, output, value); + XMLRPC_FAIL_IF_FAULT(env); + + format_out(env, output, + ""CRLF""CRLF""CRLF); + XMLRPC_FAIL_IF_FAULT(env); + + cleanup: + return; +} + + + +/*========================================================================= +** xmlrpc_serialize_fault +**========================================================================= +** Serialize an XML-RPC fault. +** +** If this function fails, it will set up the first env argument. You'll +** need to take some other drastic action to produce a serialized fault +** of your own. (This function should only fail in an out-of-memory +** situation, AFAIK.) +*/ + +void +xmlrpc_serialize_fault(xmlrpc_env *env, + xmlrpc_mem_block *output, + xmlrpc_env *fault) { + + xmlrpc_value *strct; + + XMLRPC_ASSERT_ENV_OK(env); + XMLRPC_ASSERT(output != NULL); + XMLRPC_ASSERT(fault != NULL && fault->fault_occurred); + + /* Set up our error-handling preconditions. */ + strct = NULL; + + /* Build a fault structure. */ + strct = xmlrpc_build_value(env, "{s:i,s:s}", + "faultCode", (xmlrpc_int32) fault->fault_code, + "faultString", fault->fault_string); + XMLRPC_FAIL_IF_FAULT(env); + + /* Output our header. */ + format_out(env, output, XML_PROLOGUE); + XMLRPC_FAIL_IF_FAULT(env); + format_out(env, output, ""CRLF""CRLF); + XMLRPC_FAIL_IF_FAULT(env); + + /* Serialize our fault structure. */ + xmlrpc_serialize_value(env, output, strct); + XMLRPC_FAIL_IF_FAULT(env); + + /* Output our footer. */ + format_out(env, output, CRLF""CRLF""CRLF); + XMLRPC_FAIL_IF_FAULT(env); + + cleanup: + if (strct) + xmlrpc_DECREF(strct); +} + + + + +/* Copyright (C) 2001 by First Peer, Inc. All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +** ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +** OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +** HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +** LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +** OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +** SUCH DAMAGE. */ diff --git a/src/xmlrpc_server_abyss.c b/src/xmlrpc_server_abyss.c new file mode 100644 index 0000000..310a8c1 --- /dev/null +++ b/src/xmlrpc_server_abyss.c @@ -0,0 +1,1201 @@ +/* Copyright information is at the end of the file */ + +#include "xmlrpc_config.h" + +#include +#include +#include +#include +#include +#include +#include +#ifdef _WIN32 +# include +#else +# include +# include +# include +#endif + +#include "mallocvar.h" +#include "xmlrpc-c/abyss.h" + +#include "xmlrpc-c/base.h" +#include "xmlrpc-c/server.h" +#include "xmlrpc-c/base_int.h" +#include "xmlrpc-c/string_int.h" +#include "xmlrpc-c/server_abyss.h" + + +/*========================================================================= +** die_if_fault_occurred +**========================================================================= +** If certain kinds of out-of-memory errors occur during server setup, +** we want to quit and print an error. +*/ + +static void die_if_fault_occurred(xmlrpc_env *env) { + if (env->fault_occurred) { + fprintf(stderr, "Unexpected XML-RPC fault: %s (%d)\n", + env->fault_string, env->fault_code); + exit(1); + } +} + + + +static void +addAuthCookie(xmlrpc_env * const envP, + TSession * const abyssSessionP, + const char * const authCookie) { + + const char * cookieResponse; + + xmlrpc_asprintf(&cookieResponse, "auth=%s", authCookie); + + if (cookieResponse == xmlrpc_strsol) + xmlrpc_faultf(envP, "Insufficient memory to generate cookie " + "response header."); + else { + ResponseAddField(abyssSessionP, "Set-Cookie", cookieResponse); + + xmlrpc_strfree(cookieResponse); + } +} + + + +static void +sendXmlData(xmlrpc_env * const envP, + TSession * const abyssSessionP, + const char * const body, + size_t const len, + bool const chunked) { +/*---------------------------------------------------------------------------- + Generate an HTTP response containing body 'body' of length 'len' + characters. + + This is meant to run in the context of an Abyss URI handler for + Abyss session 'abyssSessionP'. +-----------------------------------------------------------------------------*/ + const char * http_cookie = NULL; + /* This used to set http_cookie to getenv("HTTP_COOKIE"), but + that doesn't make any sense -- environment variables are not + appropriate for this. So for now, cookie code is disabled. + - Bryan 2004.10.03. + */ + + /* Various bugs before Xmlrpc-c 1.05 caused the response to be not + chunked in the most basic case, but chunked if the client explicitly + requested keepalive. I think it's better not to chunk, because + it's simpler, so I removed this in 1.05. I don't know what the + purpose of chunking would be, and an original comment suggests + the author wasn't sure chunking was a good idea. + + In 1.06 we added the user option to chunk. + */ + if (chunked) + ResponseChunked(abyssSessionP); + + ResponseStatus(abyssSessionP, 200); + + if (http_cookie) + /* There's an auth cookie, so pass it back in the response. */ + addAuthCookie(envP, abyssSessionP, http_cookie); + + if ((size_t)(uint32_t)len != len) + xmlrpc_faultf(envP, "XML-RPC method generated a response too " + "large for Abyss to send"); + else { + uint32_t const abyssLen = (uint32_t)len; + + ResponseContentType(abyssSessionP, "text/xml; charset=\"utf-8\""); + ResponseContentLength(abyssSessionP, abyssLen); + + ResponseWriteStart(abyssSessionP); + ResponseWriteBody(abyssSessionP, body, abyssLen); + ResponseWriteEnd(abyssSessionP); + } +} + + + +static void +sendError(TSession * const abyssSessionP, + unsigned int const status) { +/*---------------------------------------------------------------------------- + Send an error response back to the client. + +-----------------------------------------------------------------------------*/ + ResponseStatus(abyssSessionP, (uint16_t) status); + ResponseError(abyssSessionP); +} + + + +static void +traceChunkRead(TSession * const abyssSessionP) { + + fprintf(stderr, "XML-RPC handler got a chunk of %u bytes\n", + (unsigned int)SessionReadDataAvail(abyssSessionP)); +} + + + +static void +refillBufferFromConnection(xmlrpc_env * const envP, + TSession * const abyssSessionP, + const char * const trace) { +/*---------------------------------------------------------------------------- + Get the next chunk of data from the connection into the buffer. +-----------------------------------------------------------------------------*/ + abyss_bool succeeded; + + succeeded = SessionRefillBuffer(abyssSessionP); + + if (!succeeded) + xmlrpc_env_set_fault_formatted( + envP, XMLRPC_TIMEOUT_ERROR, "Timed out waiting for " + "client to send its POST data"); + else { + if (trace) + traceChunkRead(abyssSessionP); + } +} + + + +static void +getBody(xmlrpc_env * const envP, + TSession * const abyssSessionP, + size_t const contentSize, + const char * const trace, + xmlrpc_mem_block ** const bodyP) { +/*---------------------------------------------------------------------------- + Get the entire body, which is of size 'contentSize' bytes, from the + Abyss session and return it as the new memblock *bodyP. + + The first chunk of the body may already be in Abyss's buffer. We + retrieve that before reading more. +-----------------------------------------------------------------------------*/ + xmlrpc_mem_block * body; + + if (trace) + fprintf(stderr, "XML-RPC handler processing body. " + "Content Size = %u bytes\n", (unsigned)contentSize); + + body = xmlrpc_mem_block_new(envP, 0); + if (!envP->fault_occurred) { + size_t bytesRead; + const char * chunkPtr; + size_t chunkLen; + + bytesRead = 0; + + while (!envP->fault_occurred && bytesRead < contentSize) { + SessionGetReadData(abyssSessionP, contentSize - bytesRead, + &chunkPtr, &chunkLen); + bytesRead += chunkLen; + + assert(bytesRead <= contentSize); + + XMLRPC_MEMBLOCK_APPEND(char, envP, body, chunkPtr, chunkLen); + if (bytesRead < contentSize) + refillBufferFromConnection(envP, abyssSessionP, trace); + } + if (envP->fault_occurred) + xmlrpc_mem_block_free(body); + else + *bodyP = body; + } +} + + + +static void +storeCookies(TSession * const httpRequestP, + unsigned int * const httpErrorP) { +/*---------------------------------------------------------------------------- + Get the cookie settings from the HTTP headers and remember them for + use in responses. +-----------------------------------------------------------------------------*/ + const char * const cookie = RequestHeaderValue(httpRequestP, "cookie"); + if (cookie) { + /* + Setting the value in an environment variable doesn't make + any sense. So for now, cookie code is disabled. + -Bryan 04.10.03. + + setenv("HTTP_COOKIE", cookie, 1); + */ + } + /* TODO: parse HTTP_COOKIE to find auth pair, if there is one */ + + *httpErrorP = 0; +} + + + + +static void +validateContentType(TSession * const httpRequestP, + unsigned int * const httpErrorP) { +/*---------------------------------------------------------------------------- + If the client didn't specify a content-type of "text/xml", return + "400 Bad Request". We can't allow the client to default this header, + because some firewall software may rely on all XML-RPC requests + using the POST method and a content-type of "text/xml". +-----------------------------------------------------------------------------*/ + const char * const content_type = + RequestHeaderValue(httpRequestP, "content-type"); + + if (content_type == NULL) + *httpErrorP = 400; + else { + const char * const sempos = strchr(content_type, ';'); + unsigned int baselen; + /* Length of the base portion of the content type, e.g. + "text/xml" int "text/xml;charset=utf-8" + */ + + if (sempos) + baselen = sempos - content_type; + else + baselen = strlen(content_type); + + if (!xmlrpc_strneq(content_type, "text/xml", baselen)) + *httpErrorP = 400; + else + *httpErrorP = 0; + } +} + + + +static void +processContentLength(TSession * const httpRequestP, + size_t * const inputLenP, + unsigned int * const httpErrorP) { +/*---------------------------------------------------------------------------- + Make sure the content length is present and non-zero. This is + technically required by XML-RPC, but we only enforce it because we + don't want to figure out how to safely handle HTTP < 1.1 requests + without it. If the length is missing, return "411 Length Required". +-----------------------------------------------------------------------------*/ + const char * const content_length = + RequestHeaderValue(httpRequestP, "content-length"); + + if (content_length == NULL) + *httpErrorP = 411; + else { + if (content_length[0] == '\0') + *httpErrorP = 400; + else { + unsigned long contentLengthValue; + char * tail; + + contentLengthValue = strtoul(content_length, &tail, 10); + + if (*tail != '\0') + /* There's non-numeric crap in the length */ + *httpErrorP = 400; + else if (contentLengthValue < 1) + *httpErrorP = 400; + else if ((unsigned long)(size_t)contentLengthValue + != contentLengthValue) + *httpErrorP = 400; + else { + *httpErrorP = 0; + *inputLenP = (size_t)contentLengthValue; + } + } + } +} + + + +static void +traceHandlerCalled(TSession * const abyssSessionP) { + + const char * methodDesc; + const TRequestInfo * requestInfoP; + + fprintf(stderr, "xmlrpc_server_abyss URI path handler called.\n"); + + SessionGetRequestInfo(abyssSessionP, &requestInfoP); + + fprintf(stderr, "URI = '%s'\n", requestInfoP->uri); + + switch (requestInfoP->method) { + case m_unknown: methodDesc = "unknown"; break; + case m_get: methodDesc = "get"; break; + case m_put: methodDesc = "put"; break; + case m_head: methodDesc = "head"; break; + case m_post: methodDesc = "post"; break; + case m_delete: methodDesc = "delete"; break; + case m_trace: methodDesc = "trace"; break; + case m_options: methodDesc = "m_options"; break; + default: methodDesc = "?"; + } + fprintf(stderr, "HTTP method = '%s'\n", methodDesc); + + if (requestInfoP->query) + fprintf(stderr, "query (component of URL)='%s'\n", + requestInfoP->query); + else + fprintf(stderr, "URL has no query component\n"); +} + + + +static void +processCall(TSession * const abyssSessionP, + size_t const contentSize, + xmlrpc_registry * const registryP, + bool const wantChunk, + const char * const trace) { +/*---------------------------------------------------------------------------- + Handle an RPC request. This is an HTTP request that has the proper form + to be one of our RPCs. + + Its content length is 'contentSize' bytes. +-----------------------------------------------------------------------------*/ + xmlrpc_env env; + + if (trace) + fprintf(stderr, + "xmlrpc_server_abyss URI path handler processing RPC.\n"); + + xmlrpc_env_init(&env); + + if (contentSize > xmlrpc_limit_get(XMLRPC_XML_SIZE_LIMIT_ID)) + xmlrpc_env_set_fault_formatted( + &env, XMLRPC_LIMIT_EXCEEDED_ERROR, + "XML-RPC request too large (%d bytes)", contentSize); + else { + xmlrpc_mem_block *body; + /* Read XML data off the wire. */ + getBody(&env, abyssSessionP, contentSize, trace, &body); + if (!env.fault_occurred) { + xmlrpc_mem_block * output; + /* Process the RPC. */ + output = xmlrpc_registry_process_call( + &env, registryP, NULL, + XMLRPC_MEMBLOCK_CONTENTS(char, body), + XMLRPC_MEMBLOCK_SIZE(char, body)); + if (!env.fault_occurred) { + /* Send out the result. */ + sendXmlData(&env, abyssSessionP, + XMLRPC_MEMBLOCK_CONTENTS(char, output), + XMLRPC_MEMBLOCK_SIZE(char, output), + wantChunk); + + XMLRPC_MEMBLOCK_FREE(char, output); + } + XMLRPC_MEMBLOCK_FREE(char, body); + } + } + if (env.fault_occurred) { + if (env.fault_code == XMLRPC_TIMEOUT_ERROR) + sendError(abyssSessionP, 408); /* 408 Request Timeout */ + else + sendError(abyssSessionP, 500); /* 500 Internal Server Error */ + } + + xmlrpc_env_clean(&env); +} + + + +/**************************************************************************** + Abyss handlers (to be registered with and called by Abyss) +****************************************************************************/ + +static const char * trace_abyss; + + + +struct uriHandlerXmlrpc { +/*---------------------------------------------------------------------------- + This is the part of an Abyss HTTP request handler (aka URI handler) + that is specific to the Xmlrpc-c handler. +-----------------------------------------------------------------------------*/ + xmlrpc_registry * registryP; + const char * uriPath; /* malloc'ed */ + bool chunkResponse; + /* The handler should chunk its response whenever possible */ +}; + + + +static void +termUriHandler(void * const arg) { + + struct uriHandlerXmlrpc * const uriHandlerXmlrpcP = arg; + + xmlrpc_strfree(uriHandlerXmlrpcP->uriPath); + free(uriHandlerXmlrpcP); +} + + + +static void +handleXmlrpcReq(URIHandler2 * const this, + TSession * const abyssSessionP, + abyss_bool * const handledP) { +/*---------------------------------------------------------------------------- + Our job is to look at this HTTP request that the Abyss server is + trying to process and see if we can handle it. If it's an XML-RPC + call for this XML-RPC server, we handle it. If it's not, we refuse + it and Abyss can try some other handler. + + Our return code is TRUE to mean we handled it; FALSE to mean we didn't. + + Note that failing the request counts as handling it, and not handling + it does not mean we failed it. + + This is an Abyss HTTP Request handler -- type URIHandler2. +-----------------------------------------------------------------------------*/ + struct uriHandlerXmlrpc * const uriHandlerXmlrpcP = this->userdata; + + const TRequestInfo * requestInfoP; + + if (trace_abyss) + traceHandlerCalled(abyssSessionP); + + SessionGetRequestInfo(abyssSessionP, &requestInfoP); + + /* Note that requestInfoP->uri is not the whole URI. It is just + the "file name" part of it. + */ + if (strcmp(requestInfoP->uri, uriHandlerXmlrpcP->uriPath) != 0) + /* It's for the path (e.g. "/RPC2") that we're supposed to + handle. + */ + *handledP = FALSE; + else { + *handledP = TRUE; + + /* We understand only the POST HTTP method. For anything else, return + "405 Method Not Allowed". + */ + if (requestInfoP->method != m_post) + sendError(abyssSessionP, 405); + else { + unsigned int httpError; + storeCookies(abyssSessionP, &httpError); + if (httpError) + sendError(abyssSessionP, httpError); + else { + unsigned int httpError; + validateContentType(abyssSessionP, &httpError); + if (httpError) + sendError(abyssSessionP, httpError); + else { + unsigned int httpError; + size_t contentSize; + + processContentLength(abyssSessionP, + &contentSize, &httpError); + if (httpError) + sendError(abyssSessionP, httpError); + else + processCall(abyssSessionP, contentSize, + uriHandlerXmlrpcP->registryP, + uriHandlerXmlrpcP->chunkResponse, + trace_abyss); + } + } + } + } + if (trace_abyss) + fprintf(stderr, "xmlrpc_server_abyss URI path handler returning.\n"); +} + + + +/*========================================================================= +** xmlrpc_server_abyss_default_handler +**========================================================================= +** This handler returns a 404 Not Found for all requests. See the header +** for more documentation. +*/ + +static xmlrpc_bool +xmlrpc_server_abyss_default_handler(TSession * const sessionP) { + + if (trace_abyss) + fprintf(stderr, "xmlrpc_server_abyss default handler called.\n"); + + sendError(sessionP, 404); + + return TRUE; +} + + + +static void +sigchld(int const signalClass ATTR_UNUSED) { +/*---------------------------------------------------------------------------- + This is a signal handler for a SIGCHLD signal (which informs us that + one of our child processes has terminated). + + The only child processes we have are those that belong to the Abyss + server (and then only if the Abyss server was configured to use + forking as a threading mechanism), so we respond by passing the + signal on to the Abyss server. +-----------------------------------------------------------------------------*/ +#ifndef WIN32 + bool childrenLeft; + bool error; + + assert(signalClass == SIGCHLD); + + error = false; + childrenLeft = true; /* initial assumption */ + + /* Reap defunct children until there aren't any more. */ + while (childrenLeft && !error) { + int status; + pid_t pid; + + pid = waitpid((pid_t) -1, &status, WNOHANG); + + if (pid == 0) + childrenLeft = false; + else if (pid < 0) { + /* because of ptrace */ + if (errno != EINTR) + error = true; + } else + ServerHandleSigchld(pid); + } +#endif /* WIN32 */ +} + + +struct signalHandlers { + struct sigaction pipe; + struct sigaction chld; +}; + + + +static void +setupSignalHandlers(struct signalHandlers * const oldHandlersP) { +#ifndef WIN32 + struct sigaction mysigaction; + + sigemptyset(&mysigaction.sa_mask); + mysigaction.sa_flags = 0; + + /* This signal indicates connection closed in the middle */ + mysigaction.sa_handler = SIG_IGN; + sigaction(SIGPIPE, &mysigaction, &oldHandlersP->pipe); + + /* This signal indicates a child process (request handler) has died */ + mysigaction.sa_handler = sigchld; + sigaction(SIGCHLD, &mysigaction, &oldHandlersP->chld); +#endif +} + + + +static void +restoreSignalHandlers(struct signalHandlers const oldHandlers) { +#ifndef WIN32 + + sigaction(SIGPIPE, &oldHandlers.pipe, NULL); + sigaction(SIGCHLD, &oldHandlers.chld, NULL); + +#endif +} + + + +static void +runServerDaemon(TServer * const serverP, + runfirstFn const runfirst, + void * const runfirstArg) { + + struct signalHandlers oldHandlers; + + setupSignalHandlers(&oldHandlers); + + ServerUseSigchld(serverP); + + ServerDaemonize(serverP); + + /* We run the user supplied runfirst after forking, but before accepting + connections (helpful when running with threads) + */ + if (runfirst) + runfirst(runfirstArg); + + ServerRun(serverP); + + restoreSignalHandlers(oldHandlers); +} + + + +static void +setHandler(xmlrpc_env * const envP, + TServer * const srvP, + const char * const uriPath, + xmlrpc_registry * const registryP, + bool const chunkResponse) { + + struct uriHandlerXmlrpc * uriHandlerXmlrpcP; + URIHandler2 uriHandler; + abyss_bool success; + + trace_abyss = getenv("XMLRPC_TRACE_ABYSS"); + + MALLOCVAR_NOFAIL(uriHandlerXmlrpcP); + + uriHandlerXmlrpcP->registryP = registryP; + uriHandlerXmlrpcP->uriPath = strdup(uriPath); + uriHandlerXmlrpcP->chunkResponse = chunkResponse; + + uriHandler.handleReq2 = handleXmlrpcReq; + uriHandler.handleReq1 = NULL; + uriHandler.userdata = uriHandlerXmlrpcP; + uriHandler.init = NULL; + uriHandler.term = &termUriHandler; + + ServerAddHandler2(srvP, &uriHandler, &success); + + if (!success) + xmlrpc_faultf(envP, "Abyss failed to register the Xmlrpc-c request " + "handler. ServerAddHandler2() failed."); + + if (envP->fault_occurred) + free(uriHandlerXmlrpcP); +} + + + +void +xmlrpc_server_abyss_set_handler(xmlrpc_env * const envP, + TServer * const srvP, + const char * const uriPath, + xmlrpc_registry * const registryP) { + + setHandler(envP, srvP, uriPath, registryP, false); +} + + + +static void +setHandlers(TServer * const srvP, + const char * const uriPath, + xmlrpc_registry * const registryP, + bool const chunkResponse) { + + xmlrpc_env env; + + xmlrpc_env_init(&env); + + trace_abyss = getenv("XMLRPC_TRACE_ABYSS"); + + setHandler(&env, srvP, uriPath, registryP, chunkResponse); + + if (env.fault_occurred) + abort(); + + ServerDefaultHandler(srvP, xmlrpc_server_abyss_default_handler); + + xmlrpc_env_clean(&env); +} + + + +void +xmlrpc_server_abyss_set_handlers2(TServer * const srvP, + const char * const uriPath, + xmlrpc_registry * const registryP) { + + setHandlers(srvP, uriPath, registryP, false); +} + + + +void +xmlrpc_server_abyss_set_handlers(TServer * const srvP, + xmlrpc_registry * const registryP) { + + setHandlers(srvP, "/RPC2", registryP, false); +} + + + +static void +oldHighLevelAbyssRun(xmlrpc_env * const envP ATTR_UNUSED, + const xmlrpc_server_abyss_parms * const parmsP, + unsigned int const parmSize) { +/*---------------------------------------------------------------------------- + This is the old deprecated interface, where the caller of the + xmlrpc_server_abyss API supplies an Abyss configuration file and + we use it to daemonize (fork into the background, chdir, set uid, etc.) + and run the Abyss server. + + The new preferred interface, implemented by normalLevelAbyssRun(), + instead lets Caller set up the process environment himself and pass + Abyss parameters in memory. That's a more conventional and + flexible API. +-----------------------------------------------------------------------------*/ + TServer server; + runfirstFn runfirst; + void * runfirstArg; + + DateInit(); + + ServerCreate(&server, "XmlRpcServer", 8080, DEFAULT_DOCS, NULL); + + ConfReadServerFile(parmsP->config_file_name, &server); + + setHandlers(&server, "/RPC2", parmsP->registryP, false); + + ServerInit(&server); + + if (parmSize >= XMLRPC_APSIZE(runfirst_arg)) { + runfirst = parmsP->runfirst; + runfirstArg = parmsP->runfirst_arg; + } else { + runfirst = NULL; + runfirstArg = NULL; + } + runServerDaemon(&server, runfirst, runfirstArg); + + ServerFree(&server); +} + + + +static void +setAdditionalServerParms(const xmlrpc_server_abyss_parms * const parmsP, + unsigned int const parmSize, + TServer * const serverP) { + + /* The following ought to be parameters on ServerCreate(), but it + looks like plugging them straight into the TServer structure is + the only way to set them. + */ + + if (parmSize >= XMLRPC_APSIZE(keepalive_timeout) && + parmsP->keepalive_timeout > 0) + ServerSetKeepaliveTimeout(serverP, parmsP->keepalive_timeout); + if (parmSize >= XMLRPC_APSIZE(keepalive_max_conn) && + parmsP->keepalive_max_conn > 0) + ServerSetKeepaliveMaxConn(serverP, parmsP->keepalive_max_conn); + if (parmSize >= XMLRPC_APSIZE(timeout) && + parmsP->timeout > 0) + ServerSetTimeout(serverP, parmsP->timeout); + if (parmSize >= XMLRPC_APSIZE(dont_advertise)) + ServerSetAdvertise(serverP, !parmsP->dont_advertise); +} + + + +static void +extractServerCreateParms( + xmlrpc_env * const envP, + const xmlrpc_server_abyss_parms * const parmsP, + unsigned int const parmSize, + abyss_bool * const socketBoundP, + unsigned int * const portNumberP, + TOsSocket * const socketFdP, + const char ** const logFileNameP) { + + + if (parmSize >= XMLRPC_APSIZE(socket_bound)) + *socketBoundP = parmsP->socket_bound; + else + *socketBoundP = FALSE; + + if (*socketBoundP) { + if (parmSize < XMLRPC_APSIZE(socket_handle)) + xmlrpc_faultf(envP, "socket_bound is true, but server parameter " + "structure does not contain socket_handle (it's too " + "short)"); + else + *socketFdP = parmsP->socket_handle; + } else { + if (parmSize >= XMLRPC_APSIZE(port_number)) + *portNumberP = parmsP->port_number; + else + *portNumberP = 8080; + + if (*portNumberP > 0xffff) + xmlrpc_faultf(envP, + "TCP port number %u exceeds the maximum possible " + "TCP port number (65535)", + *portNumberP); + } + if (!envP->fault_occurred) { + if (parmSize >= XMLRPC_APSIZE(log_file_name) && + parmsP->log_file_name) + *logFileNameP = strdup(parmsP->log_file_name); + else + *logFileNameP = NULL; + } +} + + + +static void +createServerBoundSocket(xmlrpc_env * const envP, + TOsSocket const socketFd, + const char * const logFileName, + TServer * const serverP, + TSocket ** const socketPP) { + + TSocket * socketP; + const char * error; + + SocketUnixCreateFd(socketFd, &socketP); + + if (!socketP) + xmlrpc_faultf(envP, "Unable to create Abyss socket out of " + "file descriptor %d.", socketFd); + else { + ServerCreateSocket2(serverP, socketP, &error); + if (error) { + xmlrpc_faultf(envP, "Abyss failed to create server. %s", + error); + xmlrpc_strfree(error); + } else { + *socketPP = socketP; + + ServerSetName(serverP, "XmlRpcServer"); + + if (logFileName) + ServerSetLogFileName(serverP, logFileName); + } + if (envP->fault_occurred) + SocketDestroy(socketP); + } +} + + + +static void +createServer(xmlrpc_env * const envP, + const xmlrpc_server_abyss_parms * const parmsP, + unsigned int const parmSize, + TServer * const serverP, + TSocket ** const socketPP) { +/*---------------------------------------------------------------------------- + Create a bare server. It will need further setup before it is ready + to use. +-----------------------------------------------------------------------------*/ + abyss_bool socketBound; + unsigned int portNumber; + TOsSocket socketFd; + const char * logFileName; + + extractServerCreateParms(envP, parmsP, parmSize, + &socketBound, &portNumber, &socketFd, + &logFileName); + + if (!envP->fault_occurred) { + if (socketBound) + createServerBoundSocket(envP, socketFd, logFileName, + serverP, socketPP); + else { + ServerCreate(serverP, "XmlRpcServer", portNumber, DEFAULT_DOCS, + logFileName); + + *socketPP = NULL; + } + if (logFileName) + xmlrpc_strfree(logFileName); + } +} + + + +static bool +chunkResponseParm(const xmlrpc_server_abyss_parms * const parmsP, + unsigned int const parmSize) { + + return + parmSize >= XMLRPC_APSIZE(chunk_response) && + parmsP->chunk_response; +} + + + +static const char * +uriPathParm(const xmlrpc_server_abyss_parms * const parmsP, + unsigned int const parmSize) { + + const char * uriPath; + + if (parmSize >= XMLRPC_APSIZE(uri_path) && parmsP->uri_path) + uriPath = parmsP->uri_path; + else + uriPath = "/RPC2"; + + return uriPath; +} + + + +static xmlrpc_server_shutdown_fn shutdownAbyss; + +static void +shutdownAbyss(xmlrpc_env * const envP, + void * const context, + const char * const comment ATTR_UNUSED) { +/*---------------------------------------------------------------------------- + Tell Abyss to wrap up whatever it's doing and shut down. + + This is a server shutdown function to be registered in the method + registry, for use by the 'system.shutdown' system method. + + After we return, Abyss will finish up the system.shutdown and any + other connections that are in progress, then the call to + ServerRun() etc. will return. But Abyss may be stuck waiting for + something, such as the next HTTP connection. In that case, until it + gets what it's waiting for, it won't even know it's supposed t shut + down. In particular, a caller of system.shutdown may have to execute + one more RPC in order for the shutdown to happen. +-----------------------------------------------------------------------------*/ + TServer * const serverP = context; + + xmlrpc_env_init(envP); + + ServerTerminate(serverP); +} + + + +static void +normalLevelAbyssRun(xmlrpc_env * const envP, + const xmlrpc_server_abyss_parms * const parmsP, + unsigned int const parmSize) { + + TServer server; + TSocket * socketP; + + DateInit(); + + createServer(envP, parmsP, parmSize, &server, &socketP); + + if (!envP->fault_occurred) { + struct signalHandlers oldHandlers; + + setAdditionalServerParms(parmsP, parmSize, &server); + + setHandlers(&server, uriPathParm(parmsP, parmSize), parmsP->registryP, + chunkResponseParm(parmsP, parmSize)); + + ServerInit(&server); + + setupSignalHandlers(&oldHandlers); + + ServerUseSigchld(&server); + + if (0) + /* Too much of a security risk. In 1.07, there is a server + parameter to enable this. + */ + xmlrpc_registry_set_shutdown(parmsP->registryP, + &shutdownAbyss, &server); + + ServerRun(&server); + + restoreSignalHandlers(oldHandlers); + + ServerFree(&server); + + if (socketP) + SocketDestroy(socketP); + } +} + + + +void +xmlrpc_server_abyss(xmlrpc_env * const envP, + const xmlrpc_server_abyss_parms * const parmsP, + unsigned int const parmSize) { + + XMLRPC_ASSERT_ENV_OK(envP); + + if (parmSize < XMLRPC_APSIZE(registryP)) + xmlrpc_faultf(envP, + "You must specify members at least up through " + "'registryP' in the server parameters argument. " + "That would mean the parameter size would be >= %lu " + "but you specified a size of %u", + XMLRPC_APSIZE(registryP), parmSize); + else { + if (parmsP->config_file_name) + oldHighLevelAbyssRun(envP, parmsP, parmSize); + else + normalLevelAbyssRun(envP, parmsP, parmSize); + } +} + + + +/*========================================================================= + XML-RPC Server Method Registry + + This is an old deprecated form of the server facilities that uses + global variables. +=========================================================================*/ + +/* These global variables must be treated as read-only after the + server has started. +*/ + +static TServer globalSrv; + /* When you use the old interface (xmlrpc_server_abyss_init(), etc.), + this is the Abyss server to which they refer. Obviously, there can be + only one Abyss server per program using this interface. + */ + +static xmlrpc_registry * builtin_registryP; + + + +void +xmlrpc_server_abyss_init_registry(void) { + + /* This used to just create the registry and Caller would be + responsible for adding the handlers that use it. + + But that isn't very modular -- the handlers and registry go + together; there's no sense in using the built-in registry and + not the built-in handlers because if you're custom building + something, you can just make your own regular registry. So now + we tie them together, and we don't export our handlers. + */ + xmlrpc_env env; + + xmlrpc_env_init(&env); + builtin_registryP = xmlrpc_registry_new(&env); + die_if_fault_occurred(&env); + xmlrpc_env_clean(&env); + + setHandlers(&globalSrv, "/RPC2", builtin_registryP, false); +} + + + +xmlrpc_registry * +xmlrpc_server_abyss_registry(void) { + + /* This is highly deprecated. If you want to mess with a registry, + make your own with xmlrpc_registry_new() -- don't mess with the + internal one. + */ + return builtin_registryP; +} + + + +/* A quick & easy shorthand for adding a method. */ +void +xmlrpc_server_abyss_add_method(char * const method_name, + xmlrpc_method const method, + void * const user_data) { + xmlrpc_env env; + + xmlrpc_env_init(&env); + xmlrpc_registry_add_method(&env, builtin_registryP, NULL, method_name, + method, user_data); + die_if_fault_occurred(&env); + xmlrpc_env_clean(&env); +} + + + +void +xmlrpc_server_abyss_add_method_w_doc(char * const method_name, + xmlrpc_method const method, + void * const user_data, + char * const signature, + char * const help) { + + xmlrpc_env env; + xmlrpc_env_init(&env); + xmlrpc_registry_add_method_w_doc( + &env, builtin_registryP, NULL, method_name, + method, user_data, signature, help); + die_if_fault_occurred(&env); + xmlrpc_env_clean(&env); +} + + + +void +xmlrpc_server_abyss_init(int const flags ATTR_UNUSED, + const char * const config_file) { + + DateInit(); + MIMETypeInit(); + + ServerCreate(&globalSrv, "XmlRpcServer", 8080, DEFAULT_DOCS, NULL); + + ConfReadServerFile(config_file, &globalSrv); + + xmlrpc_server_abyss_init_registry(); + /* Installs /RPC2 handler and default handler that use the + built-in registry. + */ + + ServerInit(&globalSrv); +} + + + +void +xmlrpc_server_abyss_run_first(runfirstFn const runfirst, + void * const runfirstArg) { + + runServerDaemon(&globalSrv, runfirst, runfirstArg); +} + + + +void +xmlrpc_server_abyss_run(void) { + runServerDaemon(&globalSrv, NULL, NULL); +} + + + +/* +** Copyright (C) 2001 by First Peer, Inc. All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +** ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +** OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +** HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +** LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +** OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +** SUCH DAMAGE. +** +** There is more copyright information in the bottom half of this file. +** Please see it for more details. +*/ diff --git a/src/xmlrpc_server_cgi.c b/src/xmlrpc_server_cgi.c new file mode 100644 index 0000000..4079542 --- /dev/null +++ b/src/xmlrpc_server_cgi.c @@ -0,0 +1,323 @@ +/* Copyright (C) 2001 by Eric Kidd. All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +** ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +** OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +** HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +** LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +** OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +** SUCH DAMAGE. */ + + +#include "xmlrpc_config.h" + +#include +#include +#include + +/* Windows NT stdout binary mode fix. */ +#ifdef _WIN32 +#include +#include +#endif + +#include "xmlrpc-c/base.h" +#include "xmlrpc-c/server.h" +#include "xmlrpc-c/server_cgi.h" + + +/*========================================================================= +** Output Routines +**========================================================================= +** These routines send various kinds of responses to the server. +*/ + +static void +send_xml(const char * const xml_data, + size_t const xml_len) { +#ifdef _WIN32 + _setmode(_fileno(stdout), _O_BINARY); +#endif + /* Send our CGI headers back to the server. + ** XXX - Coercing 'size_t' to 'unsigned long' might be unsafe under + ** really weird circumstances. */ + fprintf(stdout, "Status: 200 OK\n"); + /* Handle authentication cookie being sent back. */ + if (getenv("HTTP_COOKIE_AUTH") != NULL) + fprintf(stdout, "Set-Cookie: auth=%s\n", getenv("HTTP_COOKIE_AUTH")); + fprintf(stdout, "Content-type: text/xml; charset=\"utf-8\"\n"); + fprintf(stdout, "Content-length: %ld\n\n", (unsigned long) xml_len); + + /* Blast out our data. */ + fwrite(xml_data, sizeof(char), xml_len, stdout); +} + + + +static void +send_error(int const code, + const char * const message, + xmlrpc_env * const env) { + +#ifdef _WIN32 + _setmode(_fileno(stdout), _O_BINARY); +#endif + /* Send an error header. */ + fprintf(stdout, "Status: %d %s\n", code, message); + fprintf(stdout, "Content-type: text/html\n\n"); + + /* Send an error message. */ + fprintf(stdout, "%d %s\n", code, message); + fprintf(stdout, "

%d %s

\n", code, message); + fprintf(stdout, "

An error occurred processing your request.

\n"); + + /* Print out the XML-RPC fault, if present. */ + if (env && env->fault_occurred) + fprintf(stdout, "

XML-RPC Fault #%d: %s

\n", + env->fault_code, env->fault_string); +} + + +/*========================================================================= +** die_if_fault_occurred +**========================================================================= +** Certain kinds of errors aren't worth the trouble of generating +** an XML-RPC fault. For these, we just send status 500 to our web server +** and log the fault to our server log. +*/ + +static void +die_if_fault_occurred(xmlrpc_env * const env) { + if (env->fault_occurred) { + fprintf(stderr, "Unexpected XML-RPC fault: %s (%d)\n", + env->fault_string, env->fault_code); + send_error(500, "Internal Server Error", env); + exit(1); + } +} + + +/*========================================================================= +** Initialization, Cleanup & Method Registry +**========================================================================= +** These are all related, so we group them together. +*/ + +static xmlrpc_registry * globalRegistryP; + +/*========================================================================= +** get_body +**========================================================================= +** Slurp the body of the request into an xmlrpc_mem_block. +*/ + +static xmlrpc_mem_block * +get_body(xmlrpc_env * const env, + size_t const length) { + + xmlrpc_mem_block *result; + char *contents; + size_t count; + + XMLRPC_ASSERT_ENV_OK(env); + + /* Error-handling preconditions. */ + result = NULL; + +#ifdef _WIN32 + /* Fix from Jeff Stewart: NT opens stdin and stdout in text mode + by default, badly confusing our length calculations. So we need + to set the file handle to binary. + */ + _setmode(_fileno(stdin), _O_BINARY); +#endif + /* XXX - Puke if length is too big. */ + + /* Allocate our memory block. */ + result = xmlrpc_mem_block_new(env, length); + XMLRPC_FAIL_IF_FAULT(env); + contents = XMLRPC_TYPED_MEM_BLOCK_CONTENTS(char, result); + + /* Get our data off the network. + ** XXX - Coercing 'size_t' to 'unsigned long' might be unsafe under + ** really weird circumstances. */ + count = fread(contents, sizeof(char), length, stdin); + if (count < length) + XMLRPC_FAIL2(env, XMLRPC_INTERNAL_ERROR, + "Expected %ld bytes, received %ld", + (unsigned long) length, (unsigned long) count); + + cleanup: + if (env->fault_occurred) { + if (result) + xmlrpc_mem_block_free(result); + return NULL; + } + return result; +} + + + +void +xmlrpc_server_cgi_process_call(xmlrpc_registry * const registryP) { +/*---------------------------------------------------------------------------- + Get the XML-RPC call from Standard Input and environment variables, + parse it, find the right method, call it, prepare an XML-RPC + response with the result, and write it to Standard Output. +-----------------------------------------------------------------------------*/ + xmlrpc_env env; + char *method, *type, *length_str; + int length; + xmlrpc_mem_block *input, *output; + char *input_data, *output_data; + size_t input_size, output_size; + int code; + char *message; + + /* Error-handling preconditions. */ + xmlrpc_env_init(&env); + input = output = NULL; + + /* Set up a default error message. */ + code = 500; message = "Internal Server Error"; + + /* Get our HTTP information from the environment. */ + method = getenv("REQUEST_METHOD"); + type = getenv("CONTENT_TYPE"); + length_str = getenv("CONTENT_LENGTH"); + + /* Perform some sanity checks. */ + if (!method || 0 != strcmp(method, "POST")) { + code = 405; message = "Method Not Allowed"; + XMLRPC_FAIL(&env, XMLRPC_INTERNAL_ERROR, "Expected HTTP method POST"); + } + if (!type || 0 != strcmp(type, "text/xml")) { + code = 400; message = "Bad Request"; + XMLRPC_FAIL(&env, XMLRPC_INTERNAL_ERROR, "Expected text/xml content"); + } + if (!length_str) { + code = 411; message = "Length Required"; + XMLRPC_FAIL(&env, XMLRPC_INTERNAL_ERROR, "Content-length required"); + } + + /* Get our content length. */ + length = atoi(length_str); + if (length <= 0) { + code = 400; message = "Bad Request"; + XMLRPC_FAIL(&env, XMLRPC_INTERNAL_ERROR, "Content-length must be > 0"); + } + + /* SECURITY: Make sure our content length is legal. + ** XXX - We can cast 'input_len' because we know it's >= 0, yes? */ + if ((size_t) length > xmlrpc_limit_get(XMLRPC_XML_SIZE_LIMIT_ID)) { + code = 400; message = "Bad Request"; + XMLRPC_FAIL(&env, XMLRPC_LIMIT_EXCEEDED_ERROR, + "XML-RPC request too large"); + } + + /* Get our body. */ + input = get_body(&env, length); + XMLRPC_FAIL_IF_FAULT(&env); + input_data = XMLRPC_TYPED_MEM_BLOCK_CONTENTS(char, input); + input_size = XMLRPC_TYPED_MEM_BLOCK_SIZE(char, input); + + /* Process our call. */ + output = xmlrpc_registry_process_call(&env, registryP, NULL, + input_data, input_size); + XMLRPC_FAIL_IF_FAULT(&env); + output_data = XMLRPC_TYPED_MEM_BLOCK_CONTENTS(char, output); + output_size = XMLRPC_TYPED_MEM_BLOCK_SIZE(char, output); + + /* Send our data. */ + send_xml(output_data, output_size); + + cleanup: + if (input) + xmlrpc_mem_block_free(input); + if (output) + xmlrpc_mem_block_free(output); + + if (env.fault_occurred) + send_error(code, message, &env); + + xmlrpc_env_clean(&env); +} + + + +void +xmlrpc_cgi_init(int const flags ATTR_UNUSED) { + xmlrpc_env env; + + xmlrpc_env_init(&env); + globalRegistryP = xmlrpc_registry_new(&env); + die_if_fault_occurred(&env); + xmlrpc_env_clean(&env); +} + + + +void +xmlrpc_cgi_cleanup(void) { + xmlrpc_registry_free(globalRegistryP); +} + + + +xmlrpc_registry * +xmlrpc_cgi_registry(void) { + return globalRegistryP; +} + + + +void +xmlrpc_cgi_add_method(const char * const method_name, + xmlrpc_method const method, + void * const user_data) { + xmlrpc_env env; + xmlrpc_env_init(&env); + xmlrpc_registry_add_method(&env, globalRegistryP, NULL, method_name, + method, user_data); + die_if_fault_occurred(&env); + xmlrpc_env_clean(&env); +} + + + +void +xmlrpc_cgi_add_method_w_doc(const char * const method_name, + xmlrpc_method const method, + void * const user_data, + const char * const signature, + const char * const help) { + xmlrpc_env env; + xmlrpc_env_init(&env); + xmlrpc_registry_add_method_w_doc(&env, globalRegistryP, NULL, method_name, + method, user_data, signature, help); + die_if_fault_occurred(&env); + xmlrpc_env_clean(&env); +} + + + +void +xmlrpc_cgi_process_call(void) { + + xmlrpc_server_cgi_process_call(globalRegistryP); +} diff --git a/src/xmlrpc_server_w32httpsys.c b/src/xmlrpc_server_w32httpsys.c new file mode 100644 index 0000000..f899d1f --- /dev/null +++ b/src/xmlrpc_server_w32httpsys.c @@ -0,0 +1,924 @@ +/* Copyright (C) 2005 by Steven A. Bone, sbone@pobox.com. All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +** ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +** OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +** HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +** LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +** OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +** SUCH DAMAGE. */ + +/* COMPILATION NOTE: + Note that the Platform SDK headers and + link libraries for Windows XP SP2 or newer are required to compile + xmlrpc-c for this module. If you are not using this server, it is + safe to exclude the xmlrpc_server_w32httpsys.c file from the xmlrpc + project and these dependencies will not be required. You can get the + latest platform SDK at + http://www.microsoft.com/msdownload/platformsdk/sdkupdate/ + Be sure after installation to choose the program to "register the PSDK + directories with Visual Studio" so the newer headers are found. +*/ + +#ifndef UNICODE +#define UNICODE +#endif + +#ifndef _UNICODE +#define _UNICODE +#endif + +#include "xmlrpc-c/base.h" +#include "xmlrpc-c/server.h" +#include "xmlrpc-c/server_w32httpsys.h" +#include "version.h" + +#if MUST_BUILD_HTTP_SYS_SERVER > 0 + +/* See compilation note above if this header is not found! */ +#include +#include +#include + +#pragma comment( lib, "httpapi" ) + + +/* XXX - This variable is *not* currently threadsafe. Once the server has +** been started, it must be treated as read-only. */ +static xmlrpc_registry *global_registryP; + +//set TRUE if you want a log +static BOOL g_bDebug; +//set log filename +static char g_fLogFile[MAX_PATH]; +//do you want OutputDebugString() to be called? +static BOOL g_bDebugString; + +// +// Macros. +// +#define INITIALIZE_HTTP_RESPONSE( resp, status, reason ) \ + do \ + { \ + RtlZeroMemory( (resp), sizeof(*(resp)) ); \ + (resp)->StatusCode = (status); \ + (resp)->pReason = (reason); \ + (resp)->ReasonLength = (USHORT) strlen(reason); \ + } while (FALSE) + + +#define ADD_KNOWN_HEADER(Response, HeaderId, RawValue) \ + do \ + { \ + (Response).Headers.KnownHeaders[(HeaderId)].pRawValue = (RawValue); \ + (Response).Headers.KnownHeaders[(HeaderId)].RawValueLength = \ + (USHORT) strlen(RawValue); \ + } while(FALSE) + +#define ALLOC_MEM(cb) HeapAlloc(GetProcessHeap(), 0, (cb)) +#define FREE_MEM(ptr) HeapFree(GetProcessHeap(), 0, (ptr)) + +// +// Prototypes for Internal Functions. +// +DWORD +DoReceiveRequests( + HANDLE hReqQueue, + const xmlrpc_server_httpsys_parms * const parmsP + ); + +DWORD +SendHttpResponse( + IN HANDLE hReqQueue, + IN PHTTP_REQUEST pRequest, + IN USHORT StatusCode, + IN PSTR pReason, + IN PSTR pEntity + ); + +DWORD +SendHttpResponseAuthRequired( + IN HANDLE hReqQueue, + IN PHTTP_REQUEST pRequest + ); + +void +processRPCCall( + xmlrpc_env * const envP, + IN HANDLE hReqQueue, + IN PHTTP_REQUEST pRequest + ); + +__inline void TraceA(const char *format, ...); +__inline void TraceW(const wchar_t *format, ...); + + +// +// External Function Implementation. +// + +void +xmlrpc_server_httpsys( + xmlrpc_env * const envP, + const xmlrpc_server_httpsys_parms * const parmsP, + unsigned int const parm_size + ) +{ + ULONG retCode; + HANDLE hReqQueue = NULL; + HTTPAPI_VERSION HttpApiVersion = HTTPAPI_VERSION_1; + WCHAR wszURL[35]; + + XMLRPC_ASSERT_ENV_OK(envP); + + if (parm_size < XMLRPC_HSSIZE(authfn)) + { + xmlrpc_env_set_fault_formatted( + envP, XMLRPC_INTERNAL_ERROR, + "You must specify members at least up through " + "'authfn' in the server parameters argument. " + "That would mean the parameter size would be >= %u " + "but you specified a size of %u", + XMLRPC_HSSIZE(authfn), parm_size); + return; + } + + //Set logging options + if (parmsP->logLevel>0) + g_bDebug=TRUE; + else + g_bDebug=FALSE; + + if (parmsP->logLevel>1) + g_bDebugString=TRUE; + else + g_bDebugString=FALSE; + + if (!parmsP->logFile) + g_bDebug=FALSE; + else + StringCchPrintfA(g_fLogFile,MAX_PATH,parmsP->logFile); + + //construct the URL we are listening on + if (parmsP->useSSL!=0) + StringCchPrintf(wszURL,35,L"https://+:%u/RPC2",parmsP->portNum); + else + StringCchPrintf(wszURL,35,L"http://+:%u/RPC2",parmsP->portNum); + + global_registryP = parmsP->registryP; + + // Initialize HTTP APIs. + retCode = HttpInitialize( + HttpApiVersion, + HTTP_INITIALIZE_SERVER, // Flags + NULL // Reserved + ); + if (retCode != NO_ERROR) + { + xmlrpc_env_set_fault_formatted( + envP, XMLRPC_INTERNAL_ERROR, + "HttpInitialize failed with %lu \n ", + retCode); + return; + } + + // Create a Request Queue Handle + retCode = HttpCreateHttpHandle( + &hReqQueue, // Req Queue + 0 // Reserved + ); + if (retCode != NO_ERROR) + { + xmlrpc_env_set_fault_formatted( + envP, XMLRPC_INTERNAL_ERROR, + "HttpCreateHttpHandle failed with %lu \n ", + retCode); + goto CleanUp; + } + + retCode = HttpAddUrl( + hReqQueue, // Req Queue + wszURL, // Fully qualified URL + NULL // Reserved + ); + + if (retCode != NO_ERROR) + { + xmlrpc_env_set_fault_formatted( + envP, XMLRPC_INTERNAL_ERROR, + "HttpAddUrl failed with %lu \n ", + retCode); + goto CleanUp; + } + + TraceW( L"we are listening for requests on the following url: %ws\n", wszURL); + + // Loop while receiving requests + for(;;) + { + TraceW( L"Calling DoReceiveRequests()\n"); + retCode = DoReceiveRequests(hReqQueue, parmsP); + if(NO_ERROR == retCode) + { + TraceW( L"DoReceiveRequests() returned NO_ERROR, breaking"); + break; + } + } + +CleanUp: + + TraceW( L"Tearing down the server.\n", wszURL); + + // Call HttpRemoveUrl for the URL that we added. + HttpRemoveUrl( hReqQueue, wszURL ); + + // Close the Request Queue handle. + if(hReqQueue) + CloseHandle(hReqQueue); + + // Call HttpTerminate. + HttpTerminate(HTTP_INITIALIZE_SERVER, NULL); + return; +} + +// +// Internal Function Implementations. +// + +__inline void TraceA(const char *format, ...) +{ + if(g_bDebug) + { + if (format) + { + va_list arglist; + char str[4096]; + + va_start(arglist, format); + if (g_fLogFile) + { + FILE *fout = fopen(g_fLogFile, "a+t"); + if (fout) + { + vfprintf(fout, format, arglist); + fclose(fout); + } + } + + StringCchVPrintfA(str,4096, format, arglist); + printf(str); + + if (g_bDebugString) + { + + OutputDebugStringA(str); + } + + va_end(arglist); + } + } +} + +__inline void TraceW(const wchar_t *format, ...) +{ + if(g_bDebug) + { + if (format) + { + va_list arglist; + wchar_t str[4096]; + + va_start(arglist, format); + if (g_fLogFile) + { + FILE *fout = fopen(g_fLogFile, "a+t"); + if (fout) + { + vfwprintf(fout, format, arglist); + fclose(fout); + } + } + + StringCchVPrintfW(str, 4096, format, arglist); + wprintf(str); + + if (g_bDebugString) + { + OutputDebugStringW(str); + } + + va_end(arglist); + } + } +} + +/* + * This is a blocking function that merely sits on the request queue + * for our URI and processes them one at a time. Once a request comes + * in, we check it for content-type, content-length, and verb. As long + * as the initial validations are done, we pass the request to the + * processRPCCall() function, which collects the body of the request + * and processes it. If we get an error back other than network type, + * we are responsible for notifing the client. + */ +DWORD +DoReceiveRequests( + IN HANDLE hReqQueue, + const xmlrpc_server_httpsys_parms * const parmsP + ) +{ + ULONG result; + HTTP_REQUEST_ID requestId; + DWORD bytesRead; + PHTTP_REQUEST pRequest; + PCHAR pRequestBuffer; + ULONG RequestBufferLength; + xmlrpc_env env; + char szHeaderBuf[255]; + long lContentLength; + + // Allocate a 2K buffer. Should be good for most requests, we'll grow + // this if required. We also need space for a HTTP_REQUEST structure. + RequestBufferLength = sizeof(HTTP_REQUEST) + 2048; + pRequestBuffer = (PCHAR) ALLOC_MEM( RequestBufferLength ); + if (pRequestBuffer == NULL) + { + return ERROR_NOT_ENOUGH_MEMORY; + } + + pRequest = (PHTTP_REQUEST)pRequestBuffer; + + // Wait for a new request -- This is indicated by a NULL request ID. + HTTP_SET_NULL_ID( &requestId ); + for(;;) + { + RtlZeroMemory(pRequest, RequestBufferLength); + + result = HttpReceiveHttpRequest( + hReqQueue, // Req Queue + requestId, // Req ID + 0, // Flags + pRequest, // HTTP request buffer + RequestBufferLength,// req buffer length + &bytesRead, // bytes received + NULL // LPOVERLAPPED + ); + + if(NO_ERROR == result) + { + // Got a request with a filled buffer. + switch(pRequest->Verb) + { + case HttpVerbPOST: + + TraceW(L"Got a POST request for %ws \n",pRequest->CookedUrl.pFullUrl); + + //Check if we need use authorization. + if(parmsP->authfn) + { + xmlrpc_env_init(&env); + if(pRequest->Headers.KnownHeaders[HttpHeaderAuthorization].RawValueLength<6) + { + xmlrpc_env_set_fault( &env, XMLRPC_REQUEST_REFUSED_ERROR, + "Authorization header too short."); + } + else + { + //unencode the headers + if(_strnicmp("basic ",pRequest->Headers.KnownHeaders[HttpHeaderAuthorization].pRawValue,6)!=0) + { + xmlrpc_env_set_fault( &env, XMLRPC_REQUEST_REFUSED_ERROR, + "Authorization header is not of type basic."); + } + else + { + xmlrpc_mem_block * decoded; + + decoded = xmlrpc_base64_decode(&env,pRequest->Headers.KnownHeaders[HttpHeaderAuthorization].pRawValue+6,pRequest->Headers.KnownHeaders[HttpHeaderAuthorization].RawValueLength-6); + if(!env.fault_occurred) + { + char *pDecodedStr; + char *pUser; + char *pPass; + char *pColon; + + pDecodedStr = (char*)malloc(decoded->_size+1); + memcpy(pDecodedStr,decoded->_block,decoded->_size); + pDecodedStr[decoded->_size]='\0'; + pUser = pPass = pDecodedStr; + pColon=strchr(pDecodedStr,':'); + if(pColon) + { + *pColon='\0'; + pPass=pColon+1; + //The authfn should set env to fail if auth is denied. + parmsP->authfn(&env,pUser,pPass); + } + else + { + xmlrpc_env_set_fault( &env, XMLRPC_REQUEST_REFUSED_ERROR, + "Decoded auth not of the correct format."); + } + free(pDecodedStr); + } + if(decoded) + XMLRPC_MEMBLOCK_FREE(char, decoded); + } + } + if(env.fault_occurred) + { + //request basic authorization, as the user did not provide it. + xmlrpc_env_clean(&env); + TraceW(L"POST request did not provide valid authorization header."); + result = SendHttpResponseAuthRequired( hReqQueue, pRequest); + break; + } + xmlrpc_env_clean(&env); + } + + //Check content type to make sure it is text/xml. + memcpy(szHeaderBuf,pRequest->Headers.KnownHeaders[HttpHeaderContentType].pRawValue,pRequest->Headers.KnownHeaders[HttpHeaderContentType].RawValueLength); + szHeaderBuf[pRequest->Headers.KnownHeaders[HttpHeaderContentType].RawValueLength]='\0'; + if (_stricmp(szHeaderBuf,"text/xml")!=0) + { + //We only handle text/xml data. Anything else is not valid. + TraceW(L"POST request had an unsupported content-type: %s \n", szHeaderBuf); + result = SendHttpResponse( + hReqQueue, + pRequest, + 400, + "Bad Request", + NULL + ); + break; + } + + //Check content length to make sure it exists and is not too big. + memcpy(szHeaderBuf,pRequest->Headers.KnownHeaders[HttpHeaderContentLength].pRawValue,pRequest->Headers.KnownHeaders[HttpHeaderContentLength].RawValueLength); + szHeaderBuf[pRequest->Headers.KnownHeaders[HttpHeaderContentLength].RawValueLength]='\0'; + lContentLength = atol(szHeaderBuf); + if (lContentLength<=0) + { + //Make sure a content length was supplied. + TraceW(L"POST request did not include a content-length \n", szHeaderBuf); + result = SendHttpResponse( + hReqQueue, + pRequest, + 411, + "Length Required", + NULL + ); + break; + } + if((size_t) lContentLength > xmlrpc_limit_get(XMLRPC_XML_SIZE_LIMIT_ID)) + { + //Content-length is too big for us to handle + TraceW(L"POST request content-length is too big for us to handle: %d bytes \n", lContentLength); + result = SendHttpResponse( + hReqQueue, + pRequest, + 500, + "content-length too large", + NULL + ); + break; + } + + //our initial validations of POST, content-type, and content-length + //all check out. Collect and pass the complete buffer to the + //XMLRPC-C library + + xmlrpc_env_init(&env); + processRPCCall(&env,hReqQueue, pRequest); + if (env.fault_occurred) + { + //if we fail and it is anything other than a network error, + //we should return a failure response to the client. + if (env.fault_code != XMLRPC_NETWORK_ERROR) + { + if (env.fault_string) + result = SendHttpResponse( + hReqQueue, + pRequest, + 500, + env.fault_string, + NULL + ); + else + result = SendHttpResponse( + hReqQueue, + pRequest, + 500, + "Unknown Error", + NULL + ); + } + } + + xmlrpc_env_clean(&env); + break; + + default: + //We only handle POST data. Anything else is not valid. + TraceW(L"Got an unsupported Verb request for URI %ws \n", pRequest->CookedUrl.pFullUrl); + + result = SendHttpResponse( + hReqQueue, + pRequest, + 405, + "Method Not Allowed", + NULL + ); + break; + } + if(result != NO_ERROR) + { + break; + } + + // Reset the Request ID so that we pick up the next request. + HTTP_SET_NULL_ID( &requestId ); + } + else if(result == ERROR_MORE_DATA) + { + // The input buffer was too small to hold the request headers + // We have to allocate more buffer & call the API again. + // + // When we call the API again, we want to pick up the request + // that just failed. This is done by passing a RequestID. + // This RequestID is picked from the old buffer. + requestId = pRequest->RequestId; + + // Free the old buffer and allocate a new one. + RequestBufferLength = bytesRead; + FREE_MEM( pRequestBuffer ); + pRequestBuffer = (PCHAR) ALLOC_MEM( RequestBufferLength ); + + if (pRequestBuffer == NULL) + { + result = ERROR_NOT_ENOUGH_MEMORY; + break; + } + + pRequest = (PHTTP_REQUEST)pRequestBuffer; + + } + else if(ERROR_CONNECTION_INVALID == result && + !HTTP_IS_NULL_ID(&requestId)) + { + // The TCP connection got torn down by the peer when we were + // trying to pick up a request with more buffer. We'll just move + // onto the next request. + HTTP_SET_NULL_ID( &requestId ); + } + else + { + break; + } + + } // for(;;) +Cleanup: + + if(pRequestBuffer) + { + FREE_MEM( pRequestBuffer ); + } + + return result; +} + +/* + * SendHttpResponse sends a text/html content type back with + * the user specified status code and reason. Used for returning + * errors to clients. + */ +DWORD +SendHttpResponse( + IN HANDLE hReqQueue, + IN PHTTP_REQUEST pRequest, + IN USHORT StatusCode, + IN PSTR pReason, + IN PSTR pEntityString + ) +{ + HTTP_RESPONSE response; + HTTP_DATA_CHUNK dataChunk; + DWORD result; + DWORD bytesSent; + CHAR szServerHeader[20]; + + // Initialize the HTTP response structure. + INITIALIZE_HTTP_RESPONSE(&response, StatusCode, pReason); + + ADD_KNOWN_HEADER(response, HttpHeaderContentType, "text/html"); + + StringCchPrintfA(szServerHeader,20, "xmlrpc-c %s",XMLRPC_C_VERSION); + ADD_KNOWN_HEADER(response, HttpHeaderServer, szServerHeader); + + if(pEntityString) + { + // Add an entity chunk + dataChunk.DataChunkType = HttpDataChunkFromMemory; + dataChunk.FromMemory.pBuffer = pEntityString; + dataChunk.FromMemory.BufferLength = (ULONG) strlen(pEntityString); + + response.EntityChunkCount = 1; + response.pEntityChunks = &dataChunk; + } + + // Since we are sending all the entity body in one call, we don't have + // to specify the Content-Length. + result = HttpSendHttpResponse( + hReqQueue, // ReqQueueHandle + pRequest->RequestId, // Request ID + 0, // Flags + &response, // HTTP response + NULL, // pReserved1 + &bytesSent, // bytes sent (OPTIONAL) + NULL, // pReserved2 (must be NULL) + 0, // Reserved3 (must be 0) + NULL, // LPOVERLAPPED (OPTIONAL) + NULL // pReserved4 (must be NULL) + ); + + if(result != NO_ERROR) + { + TraceW(L"HttpSendHttpResponse failed with %lu \n", result); + } + + return result; +} + +/* + * SendHttpResponseAuthRequired sends a 401 status code requesting authorization + */ +DWORD +SendHttpResponseAuthRequired( + IN HANDLE hReqQueue, + IN PHTTP_REQUEST pRequest + ) +{ + HTTP_RESPONSE response; + DWORD result; + DWORD bytesSent; + CHAR szServerHeader[20]; + + // Initialize the HTTP response structure. + INITIALIZE_HTTP_RESPONSE(&response, 401, "Authentication Required"); + + // Add the WWW_Authenticate header. + ADD_KNOWN_HEADER(response, HttpHeaderWwwAuthenticate, "Basic realm=\"xmlrpc\""); + + StringCchPrintfA(szServerHeader,20, "xmlrpc-c %s",XMLRPC_C_VERSION); + ADD_KNOWN_HEADER(response, HttpHeaderServer, szServerHeader); + + // Since we are sending all the entity body in one call, we don't have + // to specify the Content-Length. + result = HttpSendHttpResponse( + hReqQueue, // ReqQueueHandle + pRequest->RequestId, // Request ID + 0, // Flags + &response, // HTTP response + NULL, // pReserved1 + &bytesSent, // bytes sent (OPTIONAL) + NULL, // pReserved2 (must be NULL) + 0, // Reserved3 (must be 0) + NULL, // LPOVERLAPPED (OPTIONAL) + NULL // pReserved4 (must be NULL) + ); + + if(result != NO_ERROR) + { + TraceW(L"SendHttpResponseAuthRequired failed with %lu \n", result); + } + + return result; +} + +/* + * processRPCCall() is called after some validations. The assumption is that + * the request is an HTTP post of content-type text/xml with a content-length + * that is less than the maximum the library can handle. + * + * The caller should check the error status, and if the error was other than + * a network type, respond back to the client to let them know the call failed. + */ +void +processRPCCall( + xmlrpc_env * const envP, + IN HANDLE hReqQueue, + IN PHTTP_REQUEST pRequest + ) +{ + HTTP_RESPONSE response; + DWORD result; + DWORD bytesSent; + PUCHAR pEntityBuffer; + ULONG EntityBufferLength; + ULONG BytesRead; +#define MAX_ULONG_STR ((ULONG) sizeof("4294967295")) + CHAR szContentLength[MAX_ULONG_STR]; + CHAR szServerHeader[20]; + HTTP_DATA_CHUNK dataChunk; + ULONG TotalBytesRead = 0; + xmlrpc_mem_block * body; + xmlrpc_mem_block * output; + + BytesRead = 0; + body = NULL; + output = NULL; + + // Allocate some space for an entity buffer. + EntityBufferLength = 2048; + pEntityBuffer = (PUCHAR) ALLOC_MEM( EntityBufferLength ); + if (pEntityBuffer == NULL) + { + xmlrpc_env_set_fault_formatted( + envP, XMLRPC_INTERNAL_ERROR, + "Out of Memory"); + goto Done; + } + + // NOTE: If we had passed the HTTP_RECEIVE_REQUEST_FLAG_COPY_BODY + // flag with HttpReceiveHttpRequest(), the entity would have + // been a part of HTTP_REQUEST (using the pEntityChunks field). + // Since we have not passed that flag, we can be assured that + // there are no entity bodies in HTTP_REQUEST. + if(pRequest->Flags & HTTP_REQUEST_FLAG_MORE_ENTITY_BODY_EXISTS) + { + //Allocate some space for an XMLRPC memory block. + body = xmlrpc_mem_block_new(envP, 0); + if (envP->fault_occurred) + goto Done; + + // The entity body can be sent over multiple calls. Let's collect all + // of these in a buffer and send the buffer to the xmlrpc-c library + do + { + // Read the entity chunk from the request. + BytesRead = 0; + result = HttpReceiveRequestEntityBody( + hReqQueue, + pRequest->RequestId, + 0, + pEntityBuffer, + EntityBufferLength, + &BytesRead, + NULL + ); + switch(result) + { + case NO_ERROR: + if(BytesRead != 0) + { + XMLRPC_TYPED_MEM_BLOCK_APPEND(char, envP, body, + pEntityBuffer, BytesRead); + if(envP->fault_occurred) + goto Done; + } + break; + + case ERROR_HANDLE_EOF: + // We have read the last request entity body. We can now + // process the suppossed XMLRPC data. + if(BytesRead != 0) + { + XMLRPC_TYPED_MEM_BLOCK_APPEND(char, envP, body, + pEntityBuffer, BytesRead); + if(envP->fault_occurred) + goto Done; + } + + // We will send the response over multiple calls. + // This is achieved by passing the + // HTTP_SEND_RESPONSE_FLAG_MORE_DATA flag. + + // NOTE: Since we are accumulating the TotalBytesRead in + // a ULONG, this will not work for entity bodies that + // are larger than 4 GB. For supporting large entity + // bodies, we would have to use a ULONGLONG. + TraceA("xmlrpc_server RPC2 handler processing RPC request.\n"); + + // Process the RPC. + output = xmlrpc_registry_process_call( + envP, global_registryP, NULL, + XMLRPC_MEMBLOCK_CONTENTS(char, body), + XMLRPC_MEMBLOCK_SIZE(char, body)); + if (envP->fault_occurred) + goto Done; + + // Initialize the HTTP response structure. + INITIALIZE_HTTP_RESPONSE(&response, 200, "OK"); + + //Add the content-length + StringCchPrintfA(szContentLength,MAX_ULONG_STR, "%lu", + XMLRPC_MEMBLOCK_SIZE(char, output)); + ADD_KNOWN_HEADER( + response, + HttpHeaderContentLength, + szContentLength ); + + //Add the content-type + ADD_KNOWN_HEADER(response, HttpHeaderContentType, "text/xml"); + + StringCchPrintfA(szServerHeader,20, "xmlrpc-c %s",XMLRPC_C_VERSION); + ADD_KNOWN_HEADER(response, HttpHeaderServer, szServerHeader); + + //send the response + result = HttpSendHttpResponse( + hReqQueue, // ReqQueueHandle + pRequest->RequestId, // Request ID + HTTP_SEND_RESPONSE_FLAG_MORE_DATA, + &response, // HTTP response + NULL, // pReserved1 + &bytesSent, // bytes sent (optional) + NULL, // pReserved2 + 0, // Reserved3 + NULL, // LPOVERLAPPED + NULL // pReserved4 + ); + if(result != NO_ERROR) + { + TraceW(L"HttpSendHttpResponse failed with %lu \n", result); + xmlrpc_env_set_fault_formatted( + envP, XMLRPC_NETWORK_ERROR, + "HttpSendHttpResponse failed with %lu", result); + goto Done; + } + + // Send entity body from a memory chunk. + dataChunk.DataChunkType = HttpDataChunkFromMemory; + dataChunk.FromMemory.BufferLength = (ULONG)XMLRPC_MEMBLOCK_SIZE(char, output); + dataChunk.FromMemory.pBuffer = XMLRPC_MEMBLOCK_CONTENTS(char, output); + + result = HttpSendResponseEntityBody( + hReqQueue, + pRequest->RequestId, + 0, // This is the last send. + 1, // Entity Chunk Count. + &dataChunk, + NULL, + NULL, + 0, + NULL, + NULL + ); + if(result != NO_ERROR) + { + TraceW(L"HttpSendResponseEntityBody failed with %lu \n", result); + xmlrpc_env_set_fault_formatted( + envP, XMLRPC_NETWORK_ERROR, + "HttpSendResponseEntityBody failed with %lu", result); + goto Done; + } + goto Done; + break; + default: + TraceW(L"HttpReceiveRequestEntityBody failed with %lu \n", result); + xmlrpc_env_set_fault_formatted( + envP, XMLRPC_NETWORK_ERROR, + "HttpReceiveRequestEntityBody failed with %lu", result); + goto Done; + } + } while(TRUE); + } + else + { + // This request does not have an entity body. + TraceA("Received a bad request (no body in HTTP post).\n"); + xmlrpc_env_set_fault_formatted( + envP, XMLRPC_PARSE_ERROR, + "Bad POST request (no body)"); + goto Done; + } + +Done: + + if(pEntityBuffer) + FREE_MEM(pEntityBuffer); + + if(output) + XMLRPC_MEMBLOCK_FREE(char, output); + + if(body) + XMLRPC_MEMBLOCK_FREE(char, body); + + return; +} + +#endif /* #if MUST_BUILD_HTTP_SYS_SERVER <> 0 */ \ No newline at end of file diff --git a/src/xmlrpc_struct.c b/src/xmlrpc_struct.c new file mode 100644 index 0000000..7fabb04 --- /dev/null +++ b/src/xmlrpc_struct.c @@ -0,0 +1,610 @@ +/* Copyright (C) 2001 by First Peer, Inc. All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +** ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +** OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +** HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +** LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +** OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +** SUCH DAMAGE. */ + +#include "xmlrpc_config.h" + +#include +#include +#include + +#include "xmlrpc-c/base.h" +#include "xmlrpc-c/base_int.h" + +#define KEY_ERROR_BUFFER_SZ (32) + + +void +xmlrpc_destroyStruct(xmlrpc_value * const structP) { + + _struct_member * const members = + XMLRPC_MEMBLOCK_CONTENTS(_struct_member, &structP->_block); + size_t const size = + XMLRPC_MEMBLOCK_SIZE(_struct_member, &structP->_block); + + unsigned int i; + + for (i = 0; i < size; ++i) { + xmlrpc_DECREF(members[i].key); + xmlrpc_DECREF(members[i].value); + } + XMLRPC_MEMBLOCK_CLEAN(_struct_member, &structP->_block); +} + + + +/*========================================================================= +** xmlrpc_struct_new +**========================================================================= +** Create a new value. The corresponding destructor code +** currently lives in xmlrpc_DECREF. +** +** We store the individual members in an array of _struct_member. This +** contains a key, a hash code, and a value. We look up keys by doing +** a linear search of the hash codes. +*/ + +xmlrpc_value * +xmlrpc_struct_new(xmlrpc_env * const envP) { + + xmlrpc_value * valP; + + XMLRPC_ASSERT_ENV_OK(envP); + + xmlrpc_createXmlrpcValue(envP, &valP); + if (!envP->fault_occurred) { + valP->_type = XMLRPC_TYPE_STRUCT; + + XMLRPC_MEMBLOCK_INIT(_struct_member, envP, &valP->_block, 0); + + if (envP->fault_occurred) + free(valP); + } + return valP; +} + + + +/*========================================================================= +** xmlrpc_struct_size +**========================================================================= +** Return the number of key-value pairs contained in the struct. If the +** value is not a struct, return -1 and set a fault. +*/ + +int +xmlrpc_struct_size(xmlrpc_env* env, xmlrpc_value* strct) +{ + int retval; + + /* Suppress a compiler warning about uninitialized variables. */ + retval = 0; + + XMLRPC_ASSERT_ENV_OK(env); + XMLRPC_ASSERT_VALUE_OK(strct); + + XMLRPC_TYPE_CHECK(env, strct, XMLRPC_TYPE_STRUCT); + retval = XMLRPC_MEMBLOCK_SIZE(_struct_member, &strct->_block); + + cleanup: + if (env->fault_occurred) + return -1; + return retval; +} + + + +/*========================================================================= +** get_hash +**========================================================================= +** A mindlessly simple hash function. Please feel free to write something +** more clever if this produces bad results. +*/ + +static unsigned char +get_hash(const char * const key, + size_t const key_len) { + + unsigned char retval; + size_t i; + + XMLRPC_ASSERT(key != NULL); + + retval = 0; + for (i = 0; i < key_len; i++) + retval += key[i]; + return retval; +} + + + +/*========================================================================= +** find_member +**========================================================================= +** Get the index of the member with the specified key, or -1 if no such +** member exists. +*/ + +static int +find_member(xmlrpc_value * const strctP, + const char * const key, + size_t const key_len) { + + size_t size, i; + unsigned char hash; + _struct_member *contents; + xmlrpc_value *keyval; + char *keystr; + size_t keystr_size; + + XMLRPC_ASSERT_VALUE_OK(strctP); + XMLRPC_ASSERT(key != NULL); + + /* Look for our key. */ + hash = get_hash(key, key_len); + size = XMLRPC_MEMBLOCK_SIZE(_struct_member, &strctP->_block); + contents = XMLRPC_MEMBLOCK_CONTENTS(_struct_member, &strctP->_block); + for (i = 0; i < size; i++) { + if (contents[i].key_hash == hash) { + keyval = contents[i].key; + keystr = XMLRPC_MEMBLOCK_CONTENTS(char, &keyval->_block); + keystr_size = XMLRPC_MEMBLOCK_SIZE(char, &keyval->_block)-1; + if (key_len == keystr_size && memcmp(key, keystr, key_len) == 0) + return i; + } + } + return -1; +} + + + +/*========================================================================= +** xmlrpc_struct_has_key +**========================================================================= +*/ + +int +xmlrpc_struct_has_key(xmlrpc_env * const envP, + xmlrpc_value * const strctP, + const char * const key) { + + XMLRPC_ASSERT(key != NULL); + return xmlrpc_struct_has_key_n(envP, strctP, key, strlen(key)); +} + + + +int +xmlrpc_struct_has_key_n(xmlrpc_env * const envP, + xmlrpc_value * const strctP, + const char * const key, + size_t const key_len) { + int index; + + /* Suppress a compiler warning about uninitialized variables. */ + index = 0; + + XMLRPC_ASSERT_ENV_OK(envP); + XMLRPC_ASSERT_VALUE_OK(strctP); + XMLRPC_ASSERT(key != NULL); + + XMLRPC_TYPE_CHECK(envP, strctP, XMLRPC_TYPE_STRUCT); + index = find_member(strctP, key, key_len); + + cleanup: + if (envP->fault_occurred) + return 0; + return (index >= 0); +} + + + +/*========================================================================= +** xmlrpc_struct_find_value... +**========================================================================= +** These functions look up a specified key value in a specified struct. +** If it exists, they return the value of the struct member. If not, +** they return a NULL to indicate such. +*/ + +/* It would be a nice extension to be able to look up a key that is + not a text string. +*/ + +void +xmlrpc_struct_find_value(xmlrpc_env * const envP, + xmlrpc_value * const structP, + const char * const key, + xmlrpc_value ** const valuePP) { +/*---------------------------------------------------------------------------- + Given a key, retrieve a value from the struct. If the key is not + present, return NULL as *valuePP. +-----------------------------------------------------------------------------*/ + XMLRPC_ASSERT_ENV_OK(envP); + XMLRPC_ASSERT_VALUE_OK(structP); + XMLRPC_ASSERT_PTR_OK(key); + + if (structP->_type != XMLRPC_TYPE_STRUCT) + xmlrpc_env_set_fault_formatted( + envP, XMLRPC_TYPE_ERROR, "Value is not a struct. It is type #%d", + structP->_type); + else { + int index; + + /* Get our member index. */ + index = find_member(structP, key, strlen(key)); + if (index < 0) + *valuePP = NULL; + else { + _struct_member * const members = + XMLRPC_MEMBLOCK_CONTENTS(_struct_member, &structP->_block); + *valuePP = members[index].value; + + XMLRPC_ASSERT_VALUE_OK(*valuePP); + + xmlrpc_INCREF(*valuePP); + } + } +} + + + +static void +findValueVNoRef(xmlrpc_env * const envP, + xmlrpc_value * const structP, + xmlrpc_value * const keyP, + xmlrpc_value ** const valuePP) { +/*---------------------------------------------------------------------------- + Same as xmlrpc_find_value_v(), except we don't increment the reference + count on the xmlrpc_value we return. +-----------------------------------------------------------------------------*/ + XMLRPC_ASSERT_ENV_OK(envP); + XMLRPC_ASSERT_VALUE_OK(structP); + XMLRPC_ASSERT_VALUE_OK(keyP); + + if (structP->_type != XMLRPC_TYPE_STRUCT) + xmlrpc_env_set_fault_formatted( + envP, XMLRPC_TYPE_ERROR, "Value is not a struct. It is type #%d", + structP->_type); + else { + if (keyP->_type != XMLRPC_TYPE_STRING) + xmlrpc_env_set_fault_formatted( + envP, XMLRPC_TYPE_ERROR, "Key value is not a string. " + "It is type #%d", + keyP->_type); + else { + int index; + + /* Get our member index. */ + index = find_member(structP, + XMLRPC_MEMBLOCK_CONTENTS(char, &keyP->_block), + XMLRPC_MEMBLOCK_SIZE(char, &keyP->_block)-1); + if (index < 0) + *valuePP = NULL; + else { + _struct_member * const members = + XMLRPC_MEMBLOCK_CONTENTS(_struct_member, &structP->_block); + *valuePP = members[index].value; + + XMLRPC_ASSERT_VALUE_OK(*valuePP); + } + } + } +} + + + +void +xmlrpc_struct_find_value_v(xmlrpc_env * const envP, + xmlrpc_value * const structP, + xmlrpc_value * const keyP, + xmlrpc_value ** const valuePP) { +/*---------------------------------------------------------------------------- + Given a key, retrieve a value from the struct. If the key is not + present, return NULL as *valuePP. +-----------------------------------------------------------------------------*/ + findValueVNoRef(envP, structP, keyP, valuePP); + + if (!envP->fault_occurred && *valuePP) + xmlrpc_INCREF(*valuePP); +} + + + +/*========================================================================= +** xmlrpc_struct_read_value... +**========================================================================= +** These fail if no member with the specified key exists. +** Otherwise, they are the same as xmlrpc_struct_find_value... +*/ + +void +xmlrpc_struct_read_value_v(xmlrpc_env * const envP, + xmlrpc_value * const structP, + xmlrpc_value * const keyP, + xmlrpc_value ** const valuePP) { + + xmlrpc_struct_find_value_v(envP, structP, keyP, valuePP); + + if (!envP->fault_occurred) { + if (*valuePP == NULL) { + xmlrpc_env_set_fault_formatted( + envP, XMLRPC_INDEX_ERROR, "No member of struct has key '%.*s'", + (int)XMLRPC_MEMBLOCK_SIZE(char, &keyP->_block), + XMLRPC_MEMBLOCK_CONTENTS(char, &keyP->_block)); + } + } +} + + + +void +xmlrpc_struct_read_value(xmlrpc_env * const envP, + xmlrpc_value * const structP, + const char * const key, + xmlrpc_value ** const valuePP) { + + xmlrpc_struct_find_value(envP, structP, key, valuePP); + + if (!envP->fault_occurred) { + if (*valuePP == NULL) { + xmlrpc_env_set_fault_formatted( + envP, XMLRPC_INDEX_ERROR, "No member of struct has key '%s'", + key); + /* We should fix the error message to format the key for display */ + } + } +} + + + +/*========================================================================= +** xmlrpc_struct_get_value... +**========================================================================= +** These are for backward compatibility. They used to be the only ones. +** They're deprecated because they don't acquire a reference to the +** value they return. +*/ + +xmlrpc_value * +xmlrpc_struct_get_value_n(xmlrpc_env * const envP, + xmlrpc_value * const structP, + const char * const key, + size_t const keyLen) { + + xmlrpc_value * retval; + xmlrpc_value * keyP; + + keyP = xmlrpc_build_value(envP, "s#", key, keyLen); + if (!envP->fault_occurred) { + /* We cannot use xmlrpc_find_value_v here because + some legacy code uses xmlrpc_struct_get_value() from multiple + simultaneous threads and xmlrpc_find_value isn't thread safe + due to its manipulation of the reference count. + */ + findValueVNoRef(envP, structP, keyP, &retval); + + if (!envP->fault_occurred) { + if (retval == NULL) { + xmlrpc_env_set_fault_formatted( + envP, XMLRPC_INDEX_ERROR, + "No member of struct has key '%.*s'", + (int)keyLen, key); + /* We should fix the error message to format the key + for display */ + } + } + xmlrpc_DECREF(keyP); + } + return retval; +} + + + +xmlrpc_value * +xmlrpc_struct_get_value(xmlrpc_env * const envP, + xmlrpc_value * const strctP, + const char * const key) { + + XMLRPC_ASSERT(key != NULL); + return xmlrpc_struct_get_value_n(envP, strctP, key, strlen(key)); +} + + + +/*========================================================================= +** xmlrpc_struct_set_value +**========================================================================= +*/ + +void +xmlrpc_struct_set_value(xmlrpc_env * const envP, + xmlrpc_value * const strctP, + const char * const key, + xmlrpc_value * const valueP) { + + XMLRPC_ASSERT(key != NULL); + xmlrpc_struct_set_value_n(envP, strctP, key, strlen(key), valueP); +} + + + +void +xmlrpc_struct_set_value_n(xmlrpc_env * const envP, + xmlrpc_value * const strctP, + const char * const key, + size_t const keyLen, + xmlrpc_value * const valueP) { + + XMLRPC_ASSERT_ENV_OK(envP); + XMLRPC_ASSERT(key != NULL); + + if (xmlrpc_value_type(strctP) != XMLRPC_TYPE_STRUCT) + xmlrpc_env_set_fault_formatted( + envP, XMLRPC_TYPE_ERROR, + "Trying to set value in something not a struct. " + "Type is %d; struct is %d", + xmlrpc_value_type(strctP), XMLRPC_TYPE_STRUCT); + else { + xmlrpc_value * keyvalP; + + /* Get the key as an xmlrpc_value */ + keyvalP = xmlrpc_build_value(envP, "s#", key, keyLen); + if (!envP->fault_occurred) + xmlrpc_struct_set_value_v(envP, strctP, keyvalP, valueP); + + xmlrpc_DECREF(keyvalP); + } +} + + + +void +xmlrpc_struct_set_value_v(xmlrpc_env * const envP, + xmlrpc_value * const strctP, + xmlrpc_value * const keyvalP, + xmlrpc_value * const valueP) { + + char *key; + size_t key_len; + int index; + _struct_member *members, *member, new_member; + xmlrpc_value *old_value; + + XMLRPC_ASSERT_ENV_OK(envP); + XMLRPC_ASSERT_VALUE_OK(strctP); + XMLRPC_ASSERT_VALUE_OK(keyvalP); + XMLRPC_ASSERT_VALUE_OK(valueP); + + XMLRPC_TYPE_CHECK(envP, strctP, XMLRPC_TYPE_STRUCT); + XMLRPC_TYPE_CHECK(envP, keyvalP, XMLRPC_TYPE_STRING); + + key = XMLRPC_MEMBLOCK_CONTENTS(char, &keyvalP->_block); + key_len = XMLRPC_MEMBLOCK_SIZE(char, &keyvalP->_block) - 1; + index = find_member(strctP, key, key_len); + + if (index >= 0) { + /* Change the value of an existing member. (But be careful--the + ** original and new values might be the same object, so watch + ** the order of INCREF and DECREF calls!) */ + members = XMLRPC_MEMBLOCK_CONTENTS(_struct_member, &strctP->_block); + member = &members[index]; + + /* Juggle our references. */ + old_value = member->value; + member->value = valueP; + xmlrpc_INCREF(member->value); + xmlrpc_DECREF(old_value); + } else { + /* Add a new member. */ + new_member.key_hash = get_hash(key, key_len); + new_member.key = keyvalP; + new_member.value = valueP; + XMLRPC_MEMBLOCK_APPEND(_struct_member, envP, &strctP->_block, + &new_member, 1); + XMLRPC_FAIL_IF_FAULT(envP); + xmlrpc_INCREF(keyvalP); + xmlrpc_INCREF(valueP); + } + +cleanup: + return; +} + + + +/* Note that the order of keys and values is undefined, and may change + when you modify the struct. +*/ + +void +xmlrpc_struct_read_member(xmlrpc_env * const envP, + xmlrpc_value * const structP, + unsigned int const index, + xmlrpc_value ** const keyvalP, + xmlrpc_value ** const valueP) { + + XMLRPC_ASSERT_ENV_OK(envP); + XMLRPC_ASSERT_VALUE_OK(structP); + XMLRPC_ASSERT_PTR_OK(keyvalP); + XMLRPC_ASSERT_PTR_OK(valueP); + + if (structP->_type != XMLRPC_TYPE_STRUCT) + xmlrpc_env_set_fault_formatted( + envP, XMLRPC_TYPE_ERROR, "Attempt to read a struct member " + "of something that is not a struct"); + else { + _struct_member * const members = + XMLRPC_MEMBLOCK_CONTENTS(_struct_member, &structP->_block); + size_t const size = + XMLRPC_MEMBLOCK_SIZE(_struct_member, &structP->_block); + + if (index >= size) + xmlrpc_env_set_fault_formatted( + envP, XMLRPC_INDEX_ERROR, "Index %u is beyond the end of " + "the %u-member structure", index, (unsigned int)size); + else { + _struct_member * const memberP = &members[index]; + *keyvalP = memberP->key; + xmlrpc_INCREF(memberP->key); + *valueP = memberP->value; + xmlrpc_INCREF(memberP->value); + } + } +} + + + +void +xmlrpc_struct_get_key_and_value(xmlrpc_env * const envP, + xmlrpc_value * const structP, + int const index, + xmlrpc_value ** const keyvalP, + xmlrpc_value ** const valueP) { +/*---------------------------------------------------------------------------- + Same as xmlrpc_struct_read_member(), except doesn't take a reference + to the returned value. + + This is obsolete. +-----------------------------------------------------------------------------*/ + XMLRPC_ASSERT_ENV_OK(envP); + XMLRPC_ASSERT_VALUE_OK(structP); + XMLRPC_ASSERT_PTR_OK(keyvalP); + XMLRPC_ASSERT_PTR_OK(valueP); + + if (index < 0) + xmlrpc_env_set_fault_formatted( + envP, XMLRPC_INDEX_ERROR, "Index %d is negative.", index); + else { + xmlrpc_struct_read_member(envP, structP, index, keyvalP, valueP); + if (!envP->fault_occurred) { + xmlrpc_DECREF(*keyvalP); + xmlrpc_DECREF(*valueP); + } + } + if (envP->fault_occurred) { + *keyvalP = NULL; + *valueP = NULL; + } +} diff --git a/src/xmlrpc_utf8.c b/src/xmlrpc_utf8.c new file mode 100644 index 0000000..daec5ce --- /dev/null +++ b/src/xmlrpc_utf8.c @@ -0,0 +1,386 @@ +/* Copyright (C) 2001 by Eric Kidd. All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +** ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +** OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +** HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +** LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +** OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +** SUCH DAMAGE. */ + + +/*========================================================================= +** XML-RPC UTF-8 Utilities +**========================================================================= +** Routines for validating, encoding and decoding UTF-8 data. We try to +** be very, very strict about invalid UTF-8 data. +** +** All of the code in this file assumes that your machine represents +** wchar_t as a 16-bit (or wider) character containing UCS-2 data. If this +** assumption is incorrect, you may need to replace this file. +** +** For lots of information on Unicode and UTF-8 decoding, see: +** http://www.cl.cam.ac.uk/~mgk25/unicode.html +*/ + +#include "xmlrpc_config.h" + +#include "xmlrpc-c/base.h" + +#if HAVE_UNICODE_WCHAR + +/*========================================================================= +** Tables and Constants +**========================================================================= +** We use a variety of tables and constants to help decode and validate +** UTF-8 data. +*/ + +/* The number of bytes in a UTF-8 sequence starting with the character used +** as the array index. A zero entry indicates an illegal initial byte. +** This table was generated using a Perl script and information from the +** UTF-8 standard. +** +** Fredrik Lundh's UTF-8 decoder Python 2.0 uses a similar table. But +** since Python 2.0 has the icky CNRI license, I regenerated this +** table from scratch and wrote my own decoder. */ +static unsigned char utf8_seq_length[256] = { + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 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, 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, + 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, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 6, 6, 0, 0 +}; + +/* The minimum legal character value for a UTF-8 sequence of the given +** length. We have to check this to avoid accepting "overlong" UTF-8 +** sequences, which use more bytes than necessary to encode a given +** character. Such sequences are commonly used by evil people to bypass +** filters and security checks. This table is based on the UTF-8-test.txt +** file by Markus Kuhn . */ +static wchar_t utf8_min_char_for_length[4] = { + 0, /* Length 0: Not used (meaningless) */ + 0x0000, /* Length 1: Not used (special-cased) */ + 0x0080, /* Length 2 */ + 0x0800 /* Length 3 */ + +#if 0 + /* These are only useful on systems where wchar_t is 32-bits wide + ** and supports full UCS-4. */ + 0x00010000, /* Length 4 */ + 0x00200000, /* Length 5 */ + 0x04000000 /* Length 6 */ +#endif +}; + +/* This is the maximum legal 16-byte (UCS-2) character. Again, this +** information is based on UTF-8-test.txt. */ +#define UCS2_MAX_LEGAL_CHARACTER (0xFFFD) + +/* First and last UTF-16 surrogate characters. These are *not* legal UCS-2 +** characters--they're used to code for UCS-4 characters when using +** UTF-16. They should never appear in decoded UTF-8 data! Again, these +** could hypothetically be used to bypass security measures on some machines. +** Based on UTF-8-test.txt. */ +#define UTF16_FIRST_SURROGATE (0xD800) +#define UTF16_LAST_SURROGATE (0xDFFF) + +/* Is the character 'c' a UTF-8 continuation character? */ +#define IS_CONTINUATION(c) (((c) & 0xC0) == 0x80) + +/* Maximum number of bytes needed to encode a supported character. */ +#define MAX_ENCODED_BYTES (3) + + +/*========================================================================= +** decode_utf8 +**========================================================================= +** Internal routine which decodes (or validates) a UTF-8 string. +** To validate, set io_buff and out_buff_len to NULL. To decode, allocate +** a sufficiently large buffer, pass it as io_buff, and pass a pointer as +** as out_buff_len. The data will be written to the buffer, and the +** length to out_buff_len. +** +** We assume that wchar_t holds a single UCS-2 character in native-endian +** byte ordering. +*/ + +static void +decode_utf8(xmlrpc_env * const env, + const char * const utf8_data, + size_t const utf8_len, + wchar_t * const io_buff, + size_t * const out_buff_len) { + + size_t i, length, out_pos; + char init, con1, con2; + wchar_t wc; + + XMLRPC_ASSERT_ENV_OK(env); + XMLRPC_ASSERT_PTR_OK(utf8_data); + XMLRPC_ASSERT((!io_buff && !out_buff_len) || + (io_buff && out_buff_len)); + + /* Suppress GCC warning about possibly undefined variable. */ + wc = 0; + + i = 0; + out_pos = 0; + while (i < utf8_len) { + init = utf8_data[i]; + if ((init & 0x80) == 0x00) { + /* Convert ASCII character to wide character. */ + wc = init; + i++; + } else { + /* Look up the length of this UTF-8 sequence. */ + length = utf8_seq_length[(unsigned char) init]; + + /* Check to make sure we have enough bytes to convert. */ + if (i + length > utf8_len) + XMLRPC_FAIL(env, XMLRPC_INVALID_UTF8_ERROR, + "Truncated UTF-8 sequence"); + + /* Decode a multibyte UTF-8 sequence. */ + switch (length) { + case 0: + XMLRPC_FAIL(env, XMLRPC_INVALID_UTF8_ERROR, + "Invalid UTF-8 initial byte"); + + case 2: + /* 110xxxxx 10xxxxxx */ + con1 = utf8_data[i+1]; + if (!IS_CONTINUATION(con1)) + XMLRPC_FAIL(env, XMLRPC_INVALID_UTF8_ERROR, + "UTF-8 sequence too short"); + wc = ((((wchar_t) (init & 0x1F)) << 6) | + (((wchar_t) (con1 & 0x3F)))); + break; + + case 3: + /* 1110xxxx 10xxxxxx 10xxxxxx */ + con1 = utf8_data[i+1]; + con2 = utf8_data[i+2]; + if (!IS_CONTINUATION(con1) || !IS_CONTINUATION(con2)) + XMLRPC_FAIL(env, XMLRPC_INVALID_UTF8_ERROR, + "UTF-8 sequence too short"); + wc = ((((wchar_t) (init & 0x0F)) << 12) | + (((wchar_t) (con1 & 0x3F)) << 6) | + (((wchar_t) (con2 & 0x3F)))); + break; + + case 4: + /* 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx */ + case 5: + /* 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx */ + case 6: + /* 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx */ + XMLRPC_FAIL(env, XMLRPC_INVALID_UTF8_ERROR, + "UCS-4 characters not supported"); + + default: + XMLRPC_ASSERT("Error in UTF-8 decoder tables"); + } + + /* Advance to the end of the sequence. */ + i += length; + + /* Check for illegal UCS-2 characters. */ + if (wc > UCS2_MAX_LEGAL_CHARACTER) + XMLRPC_FAIL(env, XMLRPC_INVALID_UTF8_ERROR, + "UCS-2 characters > U+FFFD are illegal"); + + /* Check for UTF-16 surrogates. */ + if (UTF16_FIRST_SURROGATE <= wc && wc <= UTF16_LAST_SURROGATE) + XMLRPC_FAIL(env, XMLRPC_INVALID_UTF8_ERROR, + "UTF-16 surrogates may not appear in UTF-8 data"); + + /* Check for overlong sequences. */ + if (wc < utf8_min_char_for_length[length]) + XMLRPC_FAIL(env, XMLRPC_INVALID_UTF8_ERROR, + "Overlong UTF-8 sequence not allowed"); + } + + /* If we have a buffer, write our character to it. */ + if (io_buff) { + io_buff[out_pos++] = wc; + } + } + + /* Record the number of characters we found. */ + if (out_buff_len) + *out_buff_len = out_pos; + + cleanup: + if (env->fault_occurred) { + if (out_buff_len) + *out_buff_len = 0; + } +} + + + +/*========================================================================= +** xmlrpc_validate_utf8 +**========================================================================= +** Make sure that a UTF-8 string is valid. +*/ + +void +xmlrpc_validate_utf8 (xmlrpc_env * const env, + const char * const utf8_data, + size_t const utf8_len) { + + decode_utf8(env, utf8_data, utf8_len, NULL, NULL); +} + + + +xmlrpc_mem_block * +xmlrpc_utf8_to_wcs(xmlrpc_env * const envP, + const char * const utf8_data, + size_t const utf8_len) { +/*---------------------------------------------------------------------------- + Decode UTF-8 string to a "wide character string". This function + returns an xmlrpc_mem_block with an element type of wchar_t. Don't + try to intepret the block in a bytewise fashion--it won't work in + any useful or portable fashion. +-----------------------------------------------------------------------------*/ + xmlrpc_mem_block *output; + size_t wcs_length; + + /* Allocate a memory block large enough to hold any possible output. + We assume that each byte of the input may decode to a whcar_t. + */ + output = XMLRPC_MEMBLOCK_NEW(wchar_t, envP, utf8_len); + if (!envP->fault_occurred) { + /* Decode the UTF-8 data. */ + decode_utf8(envP, utf8_data, utf8_len, + XMLRPC_MEMBLOCK_CONTENTS(wchar_t, output), + &wcs_length); + if (!envP->fault_occurred) { + /* We can't have overrun our buffer. */ + XMLRPC_ASSERT(wcs_length <= utf8_len); + + /* Correct the length of the memory block. */ + XMLRPC_MEMBLOCK_RESIZE(wchar_t, envP, output, wcs_length); + } + if (envP->fault_occurred) + xmlrpc_mem_block_free(output); + } + if (envP->fault_occurred) + output = NULL; + + return output; +} + + + +/*========================================================================= +** xmlrpc_utf8_to_wcs +**========================================================================= +** Encode a "wide character string" as UTF-8. +*/ + +xmlrpc_mem_block *xmlrpc_wcs_to_utf8 (xmlrpc_env *env, + wchar_t *wcs_data, + size_t wcs_len) +{ + size_t estimate, bytes_used, i; + xmlrpc_mem_block *output; + unsigned char *buffer; + wchar_t wc; + + XMLRPC_ASSERT_ENV_OK(env); + XMLRPC_ASSERT_PTR_OK(wcs_data); + + /* Error-handling preconditions. */ + output = NULL; + + /* Allocate a memory block large enough to hold any possible output. + ** We assume that every wchar might encode to the maximum length. */ + estimate = wcs_len * MAX_ENCODED_BYTES; + output = XMLRPC_TYPED_MEM_BLOCK_NEW(char, env, estimate); + XMLRPC_FAIL_IF_FAULT(env); + + /* Output our characters. */ + buffer = (unsigned char*) XMLRPC_TYPED_MEM_BLOCK_CONTENTS(char, output); + bytes_used = 0; + for (i = 0; i < wcs_len; i++) { + wc = wcs_data[i]; + if (wc <= 0x007F) { + buffer[bytes_used++] = wc & 0x7F; + } else if (wc <= 0x07FF) { + /* 110xxxxx 10xxxxxx */ + buffer[bytes_used++] = 0xC0 | (wc >> 6); + buffer[bytes_used++] = 0x80 | (wc & 0x3F); + } else if (wc <= 0xFFFF) { + /* 1110xxxx 10xxxxxx 10xxxxxx */ + buffer[bytes_used++] = 0xE0 | (wc >> 12); + buffer[bytes_used++] = 0x80 | ((wc >> 6) & 0x3F); + buffer[bytes_used++] = 0x80 | (wc & 0x3F); + } else { + XMLRPC_FAIL(env, XMLRPC_INTERNAL_ERROR, + "Don't know how to encode UCS-4 characters yet"); + } + } + + /* Make sure we didn't overrun our buffer. */ + XMLRPC_ASSERT(bytes_used <= estimate); + + /* Correct the length of the memory block. */ + XMLRPC_TYPED_MEM_BLOCK_RESIZE(char, env, output, bytes_used); + XMLRPC_FAIL_IF_FAULT(env); + + cleanup: + if (env->fault_occurred) { + if (output) + xmlrpc_mem_block_free(output); + return NULL; + } + return output; +} + + + +#else /* HAVE_UNICODE_WCHAR */ + +xmlrpc_mem_block * +xmlrpc_utf8_to_wcs(xmlrpc_env * const envP, + const char * const utf8_data ATTR_UNUSED, + size_t const utf8_len ATTR_UNUSED) { + + xmlrpc_faultf(envP, "INTERNAL ERROR: xmlrpc_utf8_to_wcs() called " + "on a system that doesn't do Unicode!"); + + return NULL; +} +#endif /* HAVE_UNICODE_WCHAR */ + + diff --git a/stamp-h.in b/stamp-h.in new file mode 100644 index 0000000..9788f70 --- /dev/null +++ b/stamp-h.in @@ -0,0 +1 @@ +timestamp diff --git a/tools/.cvsignore b/tools/.cvsignore new file mode 100644 index 0000000..f3c7a7c --- /dev/null +++ b/tools/.cvsignore @@ -0,0 +1 @@ +Makefile diff --git a/tools/Makefile b/tools/Makefile new file mode 100644 index 0000000..8f4ee60 --- /dev/null +++ b/tools/Makefile @@ -0,0 +1,33 @@ +SUBDIR=tools +ifeq ($(SRCDIR)x,x) +SRCDIR = $(CURDIR)/.. +BUILDDIR = $(SRCDIR) +endif + +include $(SRCDIR)/Makefile.config + +SUBDIRS = binmode-rpc-kit turbocharger + +ifeq ($(MUST_BUILD_CLIENT),yes) + SUBDIRS += xmlrpc xmlrpc_transport +endif + +ifeq ($(ENABLE_CPLUSPLUS),yes) + SUBDIRS += xml-rpc-api2cpp +endif + +.PHONY: all clean distclean install check dep + +all: $(SUBDIRS:%=%/all) + +clean: $(SUBDIRS:%=%/clean) + +distclean: $(SUBDIRS:%=%/distclean) + +install: $(SUBDIRS:%=%/install) + +check: + +dep: $(SUBDIRS:%=%/dep) + +include $(SRCDIR)/Makefile.common diff --git a/tools/Makefile.common b/tools/Makefile.common new file mode 100644 index 0000000..2bac178 --- /dev/null +++ b/tools/Makefile.common @@ -0,0 +1,36 @@ +# -*-makefile-*- <-- an Emacs control + +CLIENT_LDLIBS = -L$(BUILDDIR)/src/.libs -lxmlrpc_client -lxmlrpc + +ifeq ($(MUST_BUILD_LIBWWW_CLIENT),yes) + CLIENT_LDLIBS += $(shell libwww-config --libs) +endif +ifeq ($(MUST_BUILD_CURL_CLIENT),yes) + CLIENT_LDLIBS += $(shell curl-config --libs) +endif +ifeq ($(MUST_BUILD_WININET_CLIENT),yes) + CLIENT_LDLIBS += $(shell wininet-config --libs) +endif + +CLIENT_LDLIBS += $(LDLIBS_XML) + +CLIENT_LDLIBS += -L$(BUILDDIR)/lib/libutil/.libs -lxmlrpc_util + + +UTIL_DIR = $(BUILDDIR)/lib/util + +BUILDABLE_UTILS = cmdline_parser.o getoptx.o + +$(BUILDABLE_UTILS:%=$(UTIL_DIR)/%): FORCE + $(MAKE) -C $(dir $@) $(notdir $@) + +include $(SRCDIR)/Makefile.common + +.PHONY: install +install: install-common + +.PHONY: check +check: + +.PHONY: FORCE +FORCE: diff --git a/tools/binmode-rpc-kit/COPYING b/tools/binmode-rpc-kit/COPYING new file mode 100644 index 0000000..9a97cb3 --- /dev/null +++ b/tools/binmode-rpc-kit/COPYING @@ -0,0 +1,24 @@ +Copyright (C) 2001 by Eric Kidd. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. +3. The name of the author may not be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +SUCH DAMAGE. diff --git a/tools/binmode-rpc-kit/Makefile b/tools/binmode-rpc-kit/Makefile new file mode 100644 index 0000000..e5df68d --- /dev/null +++ b/tools/binmode-rpc-kit/Makefile @@ -0,0 +1,5 @@ +all: +clean: +distclean: +install: +dep: diff --git a/tools/binmode-rpc-kit/README b/tools/binmode-rpc-kit/README new file mode 100644 index 0000000..029b5b1 --- /dev/null +++ b/tools/binmode-rpc-kit/README @@ -0,0 +1,31 @@ +Binmode RPC Implementor's Kit +============================= + +Version: 0.1 +Author: Eric Kidd +Date: 31 January 2001 + +The Binmode RPC Implementor's Kit was created as part the xmlrpc-c project. + + http://xmlrpc-c.sourceforge.net/ + +The following files are included: + + README This file + COPYING A standard disclaimer, etc. + binmode-rpc-rfc.txt The current draft of the standard + oct2bin A Perl script for turning the notation used by + the standard into actual binary data. + binmode-rpc2xml-rpc A script which translates a Binmode RPC packet + back into XML. You can use this for dumping wire + messages. (It also catches the most obvious ways + to misimplement the standard, so try it on your + output data.) + examples/ Examples and counter-examples from the standard in + machine-readable format. + +If you have any questions, please ask on the xmlrpc-c-devel mailing list: + + http://xmlrpc-c.sourceforge.net/lists.php + +Thank you for investigating Binmode RPC. Share and enjoy! diff --git a/tools/binmode-rpc-kit/binmode-rpc-rfc.txt b/tools/binmode-rpc-kit/binmode-rpc-rfc.txt new file mode 100644 index 0000000..b59208a --- /dev/null +++ b/tools/binmode-rpc-kit/binmode-rpc-rfc.txt @@ -0,0 +1,338 @@ +This is a draft, and subject to change. Please do not implement it +yet. Thank you! + +Examples can be found at the bottom of the file. + +Thank you for your feedback! + +Eric Kidd +eric.kidd@pobox.com +30 January 2001 + + +The Binmode RPC Protocol +======================== + +Binmode RPC is an ultra-lightweight RPC protocol designed for 100% +compatibility with XML-RPC . It emphasizes +simplicity, dynamically-typed data, and extreme ease of implementation. + +Two XML-RPC implementations that support 'binmode-rpc' may negotiate away +the XML part of XML-RPC, and replace it with a simple binary protocol. + +Design goals: + + * The complete specification should fit in a 350-line text file. :-) + * The protocol should be easy to implement. + * The protocol should provide a high degree of compression. + * The protocol should be very fast--faster than zlib compression. + * The protocol must be implementable in portable ANSI C, with no + './configure' checks. + * The protocol must not contain any options, variant encodings + or similar hair. If you want DCE/RPC, you know where to find it. + * All protocol operations must be performed at the byte level + (except for UTF-8 encoding and decoding). + * The protocol must be semi-readable in a hex dump or Emacs buffer. + * The protocol must efficiently encode boxcarred calls that are + implemented using 'system.multicall'. + * The protocol must support an efficient encoding for + frequently-repeated string values. + + * The protocol must never be sent to clients or servers which + don't support it. + * There must be a way for clients and servers to active the protocol + if both ends of the connection support it. + + +The X-XML-RPC-Extensions Header +------------------------------- + +(First, we'll need a mechanism for unobtrusively announcing the presence of +non-standard capabilities.) + +An XML-RPC implementation MAY advertise additional, non-standard +capabilities using the 'X-XML-RPC-Extensions' header. + +Rationale: The 'X-XML-RPC-Extensions' header should be available to CGI +scripts in the environment variable HTTP_X_XML_RPC_EXTENSIONS. + +If present, this header MUST contain a comma-separated list of +keywords. Parameter information MAY be included, if desired, in the +standard fashion used by HTTP 1.1 'Accept-Encoding' headers. + + X-XML-RPC-Extensions: binmode-rpc + X-XML-RPC-Extensions: binmode-rpc, x-telepathic-transport + X-XML-RPC-Extensions: binmode-rpc,x-telepathic-transport + X-XML-RPC-Extensions: binmode-rpc, x-telepathic-transport;speed=low + +If a client sends the X-XML-RPC-Extensions header in a request, the server +MAY use any of the specified extensions in its response. + +Rationale: No client may be sent non-standard data without first having +advertised the ability to accept it. + +If the server includes the X-XML-RPC-Extensions header in a response, the +client MAY use any of the specified extensions in further requests to that +URL. The client MUST NOT assume that the same extensions are available for +any other URL on the same server. + +Rationale: No server may be sent non-standard data without first having +advertised the ability to accept it. Furthermore, this permission is +URL-specific, since different XML-RPC implementations may be located at +different URLs on a single server. + +The client SHOULD NOT cache extension information about a particular server +for an excessive length of time (typically beyond a single program +invocation). If the client does cache this information indefinitely, it +SHOULD be able to cope if an extension is disabled. + +Rationale: The XML-RPC implementation used on the server may be changed by +the administrator. + + +The 'binmode-rpc' Extension +----------------------- + +A client or server which sends the 'binmode-rpc' extension MUST accept +message bodies of type 'application/x-binmode-rpc' in addition to the +regular 'text/xml'. + +All servers which accept the binmode-rpc extension MUST also support +standard XML-RPC, as described by . + + +The 'application/x-binmode-rpc' Format +-------------------------------------- + +All documents of the type 'application/x-binmode-rpc' MUST begin with the +following byte sequence (represented here as a C string): + + 'binmode-rpc:' + +This MUST be followed by a Call or a Response, encoded as described below: + + Call := 'C' String Array + +A Call consists of a single octet with the ASCII value 'C', followed by a +String containing the method name and an Array containing the parameters. + + Response := 'R' (Value|Fault) + +A Response MUST contain either a Value or a Fault. + + Fault := 'F' Struct + +A Fault contains a regular Struct (with members as specified by the the +XML-RPC specification). + +Trailing data at the end of an 'application/x-binmode-rpc' document MUST be +ignored. + + +Byte-Order of Integers +---------------------- + +(The following integer types don't correspond directly to XML-RPC +integers--instead, they'll be used to *build* more complicated types.) + + SignedLSB := a four-octet, signed, twos'-complement integer, + least-significant byte (LSB) first + UnsignedLSB := a four-octet, unsigned integer, LSB first + +Raw integer data is encoded in little-endian format. + +Rationale: A fixed, mandatory byte ordering is easier to implement than +approaches which allow multiple byte orderings, and little-endian CPUs +outnumber big-endian CPUs at the time of writing. + + +Values +------ + + Value := (Integer|Boolean|Double|DateTimeISO8601Binary|Array|Struct| + String|Other) + + Integer := 'I' SignedLSB + Boolean := ('t'|'f') + + Double := 'D' SizeOctet AsciiChar... + DateTimeISO8601 := '8' SizeOctet AsciiChar... + +These two types are encoded with an unsigned size octet followed by the +specified number of ASCII characters. The values are encoded in the fashion +described by the XML-RPC specification. + +Rationale: In both these cases, we're punting. Binary floating point +formats are highly non-portable, and cannot be easily manipulated by most +programming languages. XML-RPC values lack timezone +information, and are therefore difficult to convert to a binary format. + + Binary := 'B' UnsignedLSB Octet... + +This corresponds to the XML-RPC type, but without any encoding. +The UnsignedLSB specifies the number of octets of data. + + Array := 'A' UnsignedLSB Value... + +The UnsignedLSB specifies the number of values in the array. + + Struct := 'S' UnsignedLSB (String,Value)... + +The UnsignedLSB specifies the number of String,Value pairs in the struct. +The strings are keys; the values may be of any type. + + Other := 'O' String Binary + +Future XML-RPC types (if any) may be sent a String containing the type name +and a Binary block (as above) containing type-specific data. +Implementations MUST NOT encode any of the standard types using this +construct. Implementations MAY signal an error if data of type Other is +encountered. + +Rationale: This is allowed to cause an error because most applications +won't understand the contents anyway. But if new types are added, dumb +gateways will be able to manipulate them in encapsulated format (if they so +desire). + + +Strings +------- + + String := (RegularString|RecordedString|RecalledString) + +We have three types of strings. + + RegularString := 'U' StringData + StringData := UnsignedLSB Utf8Octet... + +Strings are encoded in UTF-8 format. The UnsignedLSB specifies the number +of UTF-8 octets. Implementations SHOULD raise an error if they encounter +invalid UTF-8 data (e.g., ISO Latin 1 characters). + +Rationale: Technically speaking, XML-RPC is limited to plain ASCII +characters, and may not contain 8-bit or 16-bit characters in any coding +system. But since XML-RPC is based on XML, adding Unicode is a trivial +enhancement to the basic protocol, and *somebody* will make it sooner or +later. When that day arrives, we want to be able to encode Unicode +characters. + +Implements MUST encode UTF-8 characters using the minimum number of octets. +Implementations SHOULD raise an error if they encounter any UTF-8 +characters encoded using more than the minimum number of octets. + +Rationale: Overlong UTF-8 encodings are sometimes used to bypass string +validation in security code. They serve no legitimate purpose, either. So +to improve the overall security of the Universe, we work hard to discourage +them. + +UTF-8 & Unicode FAQ: http://www.cl.cam.ac.uk/~mgk25/unicode.html + + RecordedString := '>' CodebookPosition StringData + RecalledString := '<' CodebookPosition + CodebookPosition := UnsignedOctet + +The 'binmode' format supports a 256-entry "codebook" of strings. At the +start of a data stream, the codebook is empty. When the decoder +encounters a RecordedString, it MUST store it into the specified codebook +position (and then proceed to decode it as a regular string). + +When the decoder encounters a RecalledString, it MUST look it up in the +specified codebook position. If that codebook position has been set, the +implementation MUST use the string value found in the codebook. If the +position has not been set, the implementation MUST stop decoding and raise +an error. It is legal to change a codebook position once it has been set; +the most recent value applies. + +A RecordedString or a RecalledString may be used anywhere a RegularString +may be used. + +Rationale: XML-RPC data tends to contain large numbers of identical +strings. (These are typically the names of members or the names of +methods in a multicall.) To get any kind of reasonable data compression, +it's necessary to have some way of compressing these values. The codebook +mechanism is relatively simple and uncomplicated. + +Implementations MAY choose not to use this feature when encoding data, but +MUST understand it when decoding data. + +Rationale: On the decoding end of things, this feature is trivial to +implement, and must be present for the sake of interoperability. On the +encoding end of things, however, making effective use of this feature is +slightly trickier, so implementations are allowed (but not encouraged) to +omit it. + + +Compliance +---------- + +Implementations MUST implement all features of this protocol correctly, +particularly on the decoding end. In the case of this protocol, a 95% correct +implementation is 100% broken. Yes, this statement is redundant. ;-) + + +Examples +-------- + +Non-ASCII octets are specified as in C strings. Continued lines are +indicated by a trailing '\'; these should be joined together as one +sequence of bytes. + +binmode-rpc:CU\003\0\0\0addA\002\0\0\0I\002\0\0\0I\002\0\0\0 + +binmode-rpc:RI\004\0\0\0 + +binmode-rpc:RFS\002\0\0\0 \ +U\011\0\0\0faultCodeI\001\0\0\0 \ +U\013\0\0\0faultStringU\021\0\0\0An error occurred + +binmode-rpc:RA\006\0\0\0 \ +>\000\003\0\0\0foo \ +>\001\003\0\0\0bar \ +<\000 \ +>\000\003\0\0\0baz \ +<\000 \ +<\001 + +(This deserializes to ['foo', 'bar', 'foo', 'baz', 'baz', 'bar'].) + +binmode-rpc:RU\042\0\0\0Copyright \302\251 1995 J. Random Hacker + +(This is based on an example in the Unicode/UTF-8 FAQ (see above).) + +binmode-rpc:RA\010\0\0\0 \ +I\006\0\0\0 \ +tf \ +D\0042.75 \ +8\02119980717T14:08:55 \ +U\003\0\0\0foo \ +B\003\0\0\0abc \ +S\002\0\0\0U\003\0\0\0runt + +Counter-Examples +---------------- + +The following specimens are illegal, and SHOULD be rejected by a compliant +implementation. Please test your code. + +* A different format name: + + binmode-rpc2:RI\004\0\0\0 + +* A built-in type incorrectly encoded using 'O': + + binmode-rpc:ROU\006\0\0\0stringB\003\0\0\0xyz + +* A recall of an unrecorded string: + + binmode-rpc:R<\002 + +* ISO Latin 1 data in a string. (UTF-8 required!) + + binmode-rpc:RU\041\0\0\0Copyright \251 1995 J. Random Hacker + +* UTF-8 character encoded with too many octets (based on an example in the + Unicode/UTF-8 FAQ): + + binmode-rpc:RU\041\0\0\0Bad linefeed: \300\212 (too many bytes) + +A compliant implementation MUST NOT send any of these sequences. diff --git a/tools/binmode-rpc-kit/binmode-rpc2xml-rpc b/tools/binmode-rpc-kit/binmode-rpc2xml-rpc new file mode 100755 index 0000000..2625629 --- /dev/null +++ b/tools/binmode-rpc-kit/binmode-rpc2xml-rpc @@ -0,0 +1,552 @@ +#!/usr/bin/perl -w + +use strict; + +# Some constants. +my $crlf = "\015\012"; + +# Try to load our external libraries, but fail gracefully. +eval { + require Frontier::Client; + require MIME::Base64; +}; +if ($@) { + print STDERR <<"EOD"; +This script requires Ken MacLeod\'s Frontier::RPC2 module. You can get this +from CPAN or from his website at http://bitsko.slc.ut.us/~ken/xml-rpc/ . + +For installation instructions, see the XML-RPC HOWTO at: + http://www.linuxdoc.org/HOWTO/XML-RPC-HOWTO/index.html + +This script also requires MIME::Base64. You can get this from CPAN. +EOD + exit 1; +} + +# Parse our command-line arguments. +if (@ARGV != 0) { + print STDERR "Usage: binmode-rpc2xml-rpc < data.binmode > data.xml\n"; + exit 1; +} + +# Perform our I/O in binary mode (hence the name of the protocol). +binmode STDIN; # Because we're reading raw binary data. +binmode STDOUT; # Because we want our XML left unmolested. + +# Just suck all our input into one string and glom it together. +my $binmode_data = join('', ); + +# Check for the mandatory header. +unless ($binmode_data =~ /^binmode-rpc:/) { + die "$0: No 'binmode-rpc:' header present, stopping"; +} + +# Set our decoding-position counter to point just past the header, and +# our end pointer to just beyond the end of the entire message. +my $position = length('binmode-rpc:'); +my $end = length($binmode_data); + +# Set our starting output indentation to zero (for the pretty-printer). +my $indentation = 0; + +# Build an empty codebook of strings. +my @codebook; + +# Begin the hard work. +decode_call_or_response(); + +# Print a warning if there's leftover data. +if ($position != $end) { + printf STDERR "binmode-rpc2xml-rpc: warning: Trailing data ignored\n"; +} + +# We're done! +exit (0); + + +#-------------------------------------------------------------------------- +# Pretty-printing +#-------------------------------------------------------------------------- + +sub escape_string ($) { + my ($string) = @_; + $string =~ s/&/&/g; + $string =~ s/= 0) { + die "Perl can't handle 32-bit unsigned integers portably, stopping"; + } + return $integer; +} + +sub read_signed_lsb () { + die "Unexpected end of input" unless ($position + 4 <= $end); + my $integer = unpack('V', substr($binmode_data, $position, 4)); + $position += 4; + die "Weird error decoding integer" unless (defined $integer); + return $integer; +} + +sub read_data ($) { + my ($length) = @_; + die "Unexpected end of input" unless ($position + $length <= $end); + my $data = unpack("a$length", substr($binmode_data, $position, $length)); + $position += $length; + die "Weird error decoding data" unless (defined $data); + die "Wrong data length" unless (length($data) == $length); + return $data; +} + +sub read_data_w_byte_length () { + my $length = read_byte(); + return read_data($length); +} + +sub read_data_w_unsigned_lsb_length () { + my $length = read_unsigned_lsb(); + return read_data($length) +} + +sub read_string_data () { + my $string = read_data_w_unsigned_lsb_length(); + validate_utf8($string); + return $string; +} + + +#-------------------------------------------------------------------------- +# High-level input routines +#-------------------------------------------------------------------------- +# These use the low-level input routines to read data from the buffer, +# and then convert it into Frontier::RPC2 objects. + +sub read_value () { + my $type = read_character(); + #print STDERR "DEBUG: Reading from '$type'\n"; + if ($type eq 'I') { + return _read_int_value(); + } elsif ($type eq 't') { + return Frontier::RPC2::Boolean->new(1); + } elsif ($type eq 'f') { + return Frontier::RPC2::Boolean->new(0); + } elsif ($type eq 'D') { + return _read_double_value(); + } elsif ($type eq '8') { + return _read_dateTime_value(); + } elsif ($type eq 'B') { + return _read_base64_value(); + } elsif ($type eq 'A') { + return _read_array_value(); + } elsif ($type eq 'S') { + return _read_struct_value(); + } elsif ($type eq 'U') { + return _read_regular_string_value(); + } elsif ($type eq '>') { + return _read_recorded_string_value(); + } elsif ($type eq '<') { + return _read_recalled_string_value(); + } elsif ($type eq 'O') { + die "Type 'O' Binmode RPC data not supported"; + } else { + die "Type '$type' Binmode RPC data does not exist"; + } +} + +sub read_value_and_typecheck ($) { + my ($wanted_type) = @_; + my $value = read_value(); + my $value_type = ref($value); + die "$0: Expected $wanted_type, got $value_type, stopping" + unless ($wanted_type eq $value_type); + return $value; +} + +sub _read_int_value () { + return Frontier::RPC2::Integer->new(read_signed_lsb); +} + +sub _read_double_value () { + return Frontier::RPC2::Double->new(read_data_w_byte_length); +} + +sub _read_dateTime_value () { + return Frontier::RPC2::DateTime::ISO8601->new(read_data_w_byte_length); +} + +sub _read_base64_value () { + my $binary = read_data_w_unsigned_lsb_length; + my $encoded = MIME::Base64::encode_base64($binary, $crlf); + return Frontier::RPC2::Base64->new($encoded); +} + +sub _read_array_value () { + my $size = read_unsigned_lsb; + my @values; + for (my $i = 0; $i < $size; $i++) { + push @values, read_value; + } + return \@values; +} + +sub _read_struct_value () { + my $size = read_unsigned_lsb; + my %struct; + for (my $i = 0; $i < $size; $i++) { + my $key = read_value_and_typecheck('Frontier::RPC2::String'); + $struct{$key->value} = read_value; + } + return \%struct; +} + +sub _read_regular_string_value () { + return Frontier::RPC2::String->new(read_string_data); +} + +sub _read_recorded_string_value () { + my $codebook_entry = read_byte; + my $string = Frontier::RPC2::String->new(read_string_data); + $codebook[$codebook_entry] = $string; + return $string; +} + +sub _read_recalled_string_value () { + my $codebook_entry = read_byte; + my $string = $codebook[$codebook_entry]; + unless (defined $string) { + die "$0: Attempted to use undefined codebook position $codebook_entry"; + } + return $string; +} + + +#-------------------------------------------------------------------------- +# High-level output routines +#-------------------------------------------------------------------------- +# We don't use Frontier::RPC2's output routines, because we're looking +# for maximum readability. This is a debugging tool, after all. + +sub print_xml_header () { + print_xml_line ''; +} + +sub get_escaped_string ($) { + my ($value) = @_; + return escape_string($value->value); +} + +sub print_simple_value ($$) { + my ($tag, $value) = @_; + my $string = get_escaped_string($value); + print_xml_line "<$tag>$string"; +} + +sub print_value ($) { + my ($value) = @_; + my $type = ref($value); + if ($type eq 'Frontier::RPC2::Integer') { + print_simple_value("int", $value); + } elsif ($type eq 'Frontier::RPC2::Double') { + print_simple_value("double", $value); + } elsif ($type eq 'Frontier::RPC2::Boolean') { + print_simple_value("boolean", $value); + } elsif ($type eq 'Frontier::RPC2::String') { + print_simple_value("string", $value); + } elsif ($type eq 'Frontier::RPC2::DateTime::ISO8601') { + print_simple_value("dateTime.iso8601", $value); + } elsif ($type eq 'Frontier::RPC2::Base64') { + print_base64_data($value); + } elsif ($type eq 'ARRAY') { + print_array_value($value); + } elsif ($type eq 'HASH') { + print_struct_value($value); + } else { + die "Unxpected type '$type', stopping"; + } +} + +sub print_params ($) { + my ($params) = @_; + + die "Wanted array" unless (ref($params) eq 'ARRAY'); + + print_xml_line ''; + push_indentation_level; + + foreach my $item (@$params) { + print_xml_line ''; + push_indentation_level; + print_value($item); + pop_indentation_level; + print_xml_line ''; + } + + pop_indentation_level; + print_xml_line ''; +} + +sub print_base64_data ($) { + my ($value) = @_; + print_xml_line ''; + push_indentation_level; + print_xml_line ''; + print $value->value; + print_xml_line ''; + pop_indentation_level; + print_xml_line ''; +} + +sub print_array_value ($) { + my ($array) = @_; + + print_xml_line ''; + push_indentation_level; + print_xml_line ''; + push_indentation_level; + print_xml_line ''; + push_indentation_level; + + foreach my $item (@$array) { + print_value($item); + } + + pop_indentation_level; + print_xml_line ''; + pop_indentation_level; + print_xml_line ''; + pop_indentation_level; + print_xml_line ''; +} + +sub print_struct_value ($) { + my ($struct) = @_; + + print_xml_line ''; + push_indentation_level; + print_xml_line ''; + push_indentation_level; + + for my $key (keys %$struct) { + print_xml_line ''; + push_indentation_level; + + my $name = escape_string($key); + print_xml_line "$name"; + print_value($struct->{$key}); + + pop_indentation_level; + print_xml_line ''; + } + + pop_indentation_level; + print_xml_line ''; + pop_indentation_level; + print_xml_line ''; +} + + +#-------------------------------------------------------------------------- +# High-level decoder routines +#-------------------------------------------------------------------------- +# These routines convert Binmode RPC data into the corresponding XML-RPC +# documents. + +sub decode_call_or_response () { + my $type = read_character(); + if ($type eq 'C') { + decode_call(); + } elsif ($type eq 'R') { + decode_response(); + } else { + die "$0: Unknown binmode-rpc request type '$type', stopping"; + } +} + +sub decode_call () { + my $namevalue = read_value_and_typecheck('Frontier::RPC2::String'); + my $params = read_value_and_typecheck('ARRAY'); + + print_xml_header; + print_xml_line ''; + push_indentation_level; + + my $name = get_escaped_string($namevalue); + print_xml_line "$name"; + + print_params($params); + + pop_indentation_level; + print_xml_line ''; +} + +sub decode_response () { + my $maybe_fault = peek_character; + if ($maybe_fault eq 'F') { + read_character; + my $fault = read_value_and_typecheck('HASH'); + print_xml_header; + + print_xml_line ''; + push_indentation_level; + print_xml_line ''; + push_indentation_level; + + print_value $fault; + + pop_indentation_level; + print_xml_line ''; + pop_indentation_level; + print_xml_line ''; + } else { + my $value = read_value; + print_xml_header; + print_xml_line ''; + push_indentation_level; + print_params [$value]; + pop_indentation_level; + print_xml_line ''; + } +} + + +#-------------------------------------------------------------------------- +# UTF-8 Validation +#-------------------------------------------------------------------------- +# This is based on the UTF-8 section of the Secure Programs HOWTO. +# http://new.linuxnow.com/docs/content/HOWTO/Secure-Programs-HOWTO/ +# This code *hasn't* been stress-tested for correctness yet; please see: +# http://www.cl.cam.ac.uk/~mgk25/ucs/examples/UTF-8-test.txt +# This is not yet good enough to be used as part of a UTF-8 decoder or +# security validator, but it's OK to make sure nobody is sending Latin-1. + +BEGIN { + + use vars qw{@illegal_initial_bytes @sequence_length_info}; + + # Bytes are represented as data/mask pairs. + @illegal_initial_bytes = + (# 10xxxxxx illegal as initial byte of char (80..BF) + [0x80, 0xC0], + # 1100000x illegal, overlong (C0..C1 80..BF) + [0xC0, 0xFE], + # 11100000 100xxxxx illegal, overlong (E0 80..9F) + [0xE0, 0xFF, 0x80, 0xE0], + # 11110000 1000xxxx illegal, overlong (F0 80..8F) + [0xF0, 0xFF, 0x80, 0xF0], + # 11111000 10000xxx illegal, overlong (F8 80..87) + [0xF8, 0xFF, 0x80, 0xF8], + # 11111100 100000xx illegal, overlong (FC 80..83) + [0xFC, 0xFF, 0x80, 0xFC], + # 1111111x illegal; prohibited by spec + [0xFE, 0xFE]); + + # Items are byte, mask, sequence length. + @sequence_length_info = + (# 110xxxxx 10xxxxxx + [0xC0, 0xE0, 2], + # 1110xxxx 10xxxxxx 10xxxxxx + [0xE0, 0xF0, 3], + # 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx + [0xF0, 0xF8, 4], + # 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx + [0xF8, 0xFC, 5], + # 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx + [0xFC, 0xFE, 6]); +} + +sub validate_utf8 ($) { + my ($string) = @_; + my $end = length($string); + + my $i = 0; + while ($i < $end) { + my $byte = ord(substr($string, $i, 1)); + #print STDERR "Checking byte $byte\n"; + + # Check for illegal bytes at the start of this sequence. + NEXT_CANDIDATE: + foreach my $illegal_byte_info (@illegal_initial_bytes) { + my $offset = 0; + for (my $j = 0; $j < @$illegal_byte_info; $j += 2) { + my $pattern = $illegal_byte_info->[$j]; + my $mask = $illegal_byte_info->[$j+1]; + my $data = ord(substr($string, $i+$offset, 1)); + #print STDERR " B: $byte P: $pattern M: $mask D: $data\n"; + next NEXT_CANDIDATE unless ($data & $mask) == $pattern; + $offset++; + } + die "Illegal UTF-8 sequence (" . substr($string, $i, 2) . ")"; + } + + # Find the length of the sequence, and make sure we have enough data. + my $length = 1; + foreach my $length_info (@sequence_length_info) { + my ($pattern, $mask, $length_candidate) = @$length_info; + if (($byte & $mask) == $pattern) { + $length = $length_candidate; + last; + } + } + die "$0: Unexpected end of UTF-8 sequence, stopping" + unless $i + $length <= $end; + + # Verify the sequence is well-formed. + $i++, $length--; + while ($length > 0) { + die "$0: Malformed UTF-8 sequence, stopping" + unless (ord(substr($string, $i, 1)) & 0xC0) == 0x80; + $i++, $length--; + } + } + #printf STDERR "DEBUG: Verified $i bytes\n"; +} diff --git a/tools/binmode-rpc-kit/examples/good-1.binmode b/tools/binmode-rpc-kit/examples/good-1.binmode new file mode 100644 index 0000000000000000000000000000000000000000..53c57403f0ee1f99275b5f73d4271ab0f75dc541 GIT binary patch literal 80 zcmYew%*)MBN!2YXNVW=ciyB>>_P5YYet literal 0 HcmV?d00001 diff --git a/tools/binmode-rpc-kit/examples/good-1.xml b/tools/binmode-rpc-kit/examples/good-1.xml new file mode 100644 index 0000000..3f9feaa --- /dev/null +++ b/tools/binmode-rpc-kit/examples/good-1.xml @@ -0,0 +1,32 @@ + + + + + + + + 6 + 1 + 0 + 2.75 + 19980717T14:08:55 + foo + + +YWJj + + + + + + run + 1 + + + + + + + + + diff --git a/tools/binmode-rpc-kit/examples/good-2.binmode b/tools/binmode-rpc-kit/examples/good-2.binmode new file mode 100644 index 0000000000000000000000000000000000000000..8fd69ef786cf153bc0e10e1ef57125ad9125c1eb GIT binary patch literal 36 icmYew%*)MBN!2YXNVakgWoBStNK8p_WCGHjZ~_3f3I`|v literal 0 HcmV?d00001 diff --git a/tools/binmode-rpc-kit/examples/good-2.xml b/tools/binmode-rpc-kit/examples/good-2.xml new file mode 100644 index 0000000..ab1db1a --- /dev/null +++ b/tools/binmode-rpc-kit/examples/good-2.xml @@ -0,0 +1,12 @@ + + + add + + + 2 + + + 2 + + + diff --git a/tools/binmode-rpc-kit/examples/good-3.binmode b/tools/binmode-rpc-kit/examples/good-3.binmode new file mode 100644 index 0000000000000000000000000000000000000000..a0633e8bebffd4e7599104b7106bf87e03264a24 GIT binary patch literal 18 ZcmYew%*)MBN!2YXNVW>{WMN=n002FH1u6gl literal 0 HcmV?d00001 diff --git a/tools/binmode-rpc-kit/examples/good-3.xml b/tools/binmode-rpc-kit/examples/good-3.xml new file mode 100644 index 0000000..4262551 --- /dev/null +++ b/tools/binmode-rpc-kit/examples/good-3.xml @@ -0,0 +1,8 @@ + + + + + 4 + + + diff --git a/tools/binmode-rpc-kit/examples/good-4.binmode b/tools/binmode-rpc-kit/examples/good-4.binmode new file mode 100644 index 0000000000000000000000000000000000000000..3d95e779985110d395aed59bba23863553b5b088 GIT binary patch literal 76 zcmYew%*)MBN!2YXNVW=c3ua + + + + + + faultString + An error occurred + + + faultCode + 1 + + + + + diff --git a/tools/binmode-rpc-kit/examples/good-5.binmode b/tools/binmode-rpc-kit/examples/good-5.binmode new file mode 100644 index 0000000000000000000000000000000000000000..e869c55d25f5071094ef2ed711c22b51518feba4 GIT binary patch literal 51 xcmYew%*)MBN!2YXNVW=cWMg1puw!5bl4<$*c8nlKQeu$}R4gg6%7(#)5db=K3R3_8 literal 0 HcmV?d00001 diff --git a/tools/binmode-rpc-kit/examples/good-5.xml b/tools/binmode-rpc-kit/examples/good-5.xml new file mode 100644 index 0000000..601ff3d --- /dev/null +++ b/tools/binmode-rpc-kit/examples/good-5.xml @@ -0,0 +1,19 @@ + + + + + + + + foo + bar + foo + baz + baz + bar + + + + + + diff --git a/tools/binmode-rpc-kit/examples/good-6.binmode b/tools/binmode-rpc-kit/examples/good-6.binmode new file mode 100644 index 0000000000000000000000000000000000000000..8a7c6214e77f9493a124c79abdab8c611fb54772 GIT binary patch literal 52 zcmYew%*)MBN!2YXNVW + + + + Copyright © 1995 J. Random Hacker + + + diff --git a/tools/binmode-rpc-kit/examples/invalid-1.binmode b/tools/binmode-rpc-kit/examples/invalid-1.binmode new file mode 100644 index 0000000000000000000000000000000000000000..4076dbb69a1f31f25e7378dfe56bc3a089dc0d9a GIT binary patch literal 19 acmYew%*)MBN!2YXNH($x@?>FPU;qF^Uj{4`pLuU??sr%FIi5Vg@oRDysmr$O+B> literal 0 HcmV?d00001 diff --git a/tools/binmode-rpc-kit/examples/invalid-3.binmode b/tools/binmode-rpc-kit/examples/invalid-3.binmode new file mode 100644 index 0000000..ad5e883 --- /dev/null +++ b/tools/binmode-rpc-kit/examples/invalid-3.binmode @@ -0,0 +1 @@ +binmode-rpc:R< \ No newline at end of file diff --git a/tools/binmode-rpc-kit/examples/invalid-4.binmode b/tools/binmode-rpc-kit/examples/invalid-4.binmode new file mode 100644 index 0000000000000000000000000000000000000000..69aa2f464d31fc15b046650c42c766ffba2a497b GIT binary patch literal 51 zcmYew%*)MBN!2YXNVW out.binmode". + +binmode STDOUT; + +while (<>) { + s/\\(\d\d\d)/chr(oct($1))/ge; + s/\\0/chr(0)/ge; + s/\\\\/\\/g; + print $_; +} diff --git a/tools/interop-server/interop-cgi.c b/tools/interop-server/interop-cgi.c new file mode 100644 index 0000000..d079267 --- /dev/null +++ b/tools/interop-server/interop-cgi.c @@ -0,0 +1,215 @@ +/* A CGI which implements all of the test functions need for an interop +** endpoint. */ + +#include +#include +#include + +#include "xmlrpc-c/base.h" +#include "xmlrpc-c/cgi.h" + +#include "version.h" + +#include "config.h" /* information about this build environment */ + + +/*========================================================================= +** Toolkit Identification +**========================================================================= +*/ + +static xmlrpc_value * +whichToolkit(xmlrpc_env * const env, + xmlrpc_value * const param_array, + void * const user_data ATTR_UNUSED) { + + xmlrpc_value * retval; + + /* Parse our argument array. */ + xmlrpc_parse_value(env, param_array, "()"); + if (env->fault_occurred) + retval = NULL; + else { + struct utsname utsname; + + int rc; + rc = uname(&utsname); + if (rc != 0) { + xmlrpc_env_set_fault_formatted(env, XMLRPC_INTERNAL_ERROR, + "uname() failed. errno=%d (%s)", + errno, strerror(errno)); + retval = NULL; + } else { + /* Assemble our result. */ + retval = xmlrpc_build_value(env, "{s:s,s:s,s:s,s:s}", + "toolkitDocsUrl", + "http://xmlrpc-c.sourceforge.net/", + "toolkitName", PACKAGE, + "toolkitVersion", XMLRPC_C_VERSION"+", + "toolkitOperatingSystem", + utsname.sysname); + } + } + return retval; +} + + + +static char whichToolkit_help[] = +"Identify the toolkit used to implement this server. The operating system " +"information is based on where the toolkit was compiled, not where it's " +"currently running."; + + +/*========================================================================= +** noInParams +**========================================================================= +** Test a method with no parameters. +*/ + +static xmlrpc_value * +noInParams(xmlrpc_env * const env, + xmlrpc_value * const param_array, + void * const user_data ATTR_UNUSED) { + + /* Parse our argument array. */ + xmlrpc_parse_value(env, param_array, "()"); + if (env->fault_occurred) + return NULL; + + /* Assemble our result. */ + return xmlrpc_build_value(env, "i", (xmlrpc_int32) 0); +} + +static char noInParams_help[] = +"A method with no parameters. Returns an arbitrary int."; + + +/*========================================================================= +** Echo Tests +**========================================================================= +** We're lazy--we only implement one actual echo method, but we hook it +** up to lots of different names. +*/ + +static xmlrpc_value * +echoValue(xmlrpc_env * const env, + xmlrpc_value * const param_array, + void * const user_data ATTR_UNUSED) { + + xmlrpc_value *val; + + /* Parse our argument array. */ + xmlrpc_parse_value(env, param_array, "(V)", &val); + if (env->fault_occurred) + return NULL; + + /* Create a new reference (because both our parameter list and our + ** return value will be DECREF'd when we return). */ + xmlrpc_INCREF(val); + + /* Return our result. */ + return val; +} + +static char echoValue_help[] = +"Echo an arbitrary XML-RPC value of any type."; + +static char echoString_help[] = +"Echo an arbitrary XML-RPC string."; + +static char echoInteger_help[] = +"Echo an arbitrary XML-RPC integer."; + +static char echoBoolean_help[] = +"Echo an arbitrary XML-RPC boolean value."; + +static char echoFloat_help[] = +"Echo an arbitrary XML-RPC float."; + +static char echoStruct_help[] = +"Echo an arbitrary XML-RPC struct."; + +static char echoDate_help[] = +"Echo an arbitrary XML-RPC date/time value."; + +static char echoBase64_help[] = +"Echo an arbitrary XML-RPC Base64 value."; + +static char echoStringArray_help[] = +"Echo an array of arbitrary XML-RPC strings."; + +static char echoIntegerArray_help[] = +"Echo an array of arbitrary XML-RPC integers."; + +static char echoFloatArray_help[] = +"Echo an array of arbitrary XML-RPC floats."; + +static char echoStructArray_help[] = +"Echo an array of arbitrary XML-RPC structs."; + + +/*========================================================================= +** Server Setup +**========================================================================= +** Set up and run our server. +*/ + +int +main(int const argc ATTR_UNUSED, + char ** const argv ATTR_UNUSED) { + + /* Process our request. */ + xmlrpc_cgi_init(XMLRPC_CGI_NO_FLAGS); + + /* Add a method to identify our toolkit. */ + xmlrpc_cgi_add_method_w_doc("interopEchoTests.whichToolkit", + &whichToolkit, NULL, + "S:", whichToolkit_help); + + /* Add a whole bunch of test methods. */ + xmlrpc_cgi_add_method_w_doc("interopEchoTests.noInParams", + &noInParams, NULL, + "i:", noInParams_help); + xmlrpc_cgi_add_method_w_doc("interopEchoTests.echoValue", + &echoValue, NULL, + "?", echoValue_help); + xmlrpc_cgi_add_method_w_doc("interopEchoTests.echoString", + &echoValue, NULL, + "s:s", echoString_help); + xmlrpc_cgi_add_method_w_doc("interopEchoTests.echoInteger", + &echoValue, NULL, + "i:i", echoInteger_help); + xmlrpc_cgi_add_method_w_doc("interopEchoTests.echoBoolean", + &echoValue, NULL, + "b:b", echoBoolean_help); + xmlrpc_cgi_add_method_w_doc("interopEchoTests.echoFloat", + &echoValue, NULL, + "d:d", echoFloat_help); + xmlrpc_cgi_add_method_w_doc("interopEchoTests.echoStruct", + &echoValue, NULL, + "S:S", echoStruct_help); + xmlrpc_cgi_add_method_w_doc("interopEchoTests.echoDate", + &echoValue, NULL, + "8:8", echoDate_help); + xmlrpc_cgi_add_method_w_doc("interopEchoTests.echoBase64", + &echoValue, NULL, + "6:6", echoBase64_help); + xmlrpc_cgi_add_method_w_doc("interopEchoTests.echoStringArray", + &echoValue, NULL, + "A:A", echoStringArray_help); + xmlrpc_cgi_add_method_w_doc("interopEchoTests.echoIntegerArray", + &echoValue, NULL, + "A:A", echoIntegerArray_help); + xmlrpc_cgi_add_method_w_doc("interopEchoTests.echoFloatArray", + &echoValue, NULL, + "A:A", echoFloatArray_help); + xmlrpc_cgi_add_method_w_doc("interopEchoTests.echoStructArray", + &echoValue, NULL, + "A:A", echoStructArray_help); + + xmlrpc_cgi_process_call(); + xmlrpc_cgi_cleanup(); + + return 0; +} diff --git a/tools/turbocharger/.cvsignore b/tools/turbocharger/.cvsignore new file mode 100644 index 0000000..f3c7a7c --- /dev/null +++ b/tools/turbocharger/.cvsignore @@ -0,0 +1 @@ +Makefile diff --git a/tools/turbocharger/Makefile b/tools/turbocharger/Makefile new file mode 100644 index 0000000..8772c35 --- /dev/null +++ b/tools/turbocharger/Makefile @@ -0,0 +1,5 @@ +all: +clean: +distclean: +install: +dep: \ No newline at end of file diff --git a/tools/turbocharger/README b/tools/turbocharger/README new file mode 100644 index 0000000..4613bfd --- /dev/null +++ b/tools/turbocharger/README @@ -0,0 +1,37 @@ +XML-RPC Turbocharger (Experimental) +=================================== + +This a hacked copy of mod_gzip. In addition to the usual "gzip" encoding, +it also handles "deflate" encoding. + +When used in conjuction with the xmlrpc-c client, this should reduce your +outbound XML-RPC network traffic by an amazing amount--compression ratios +of 10:1 and 30:1 are not unheard of. If you're clever, you should be able +to use this with just about any Apache-based XML-RPC server. + +You can find the standard distribution of mod_gzip here: + + http://www.remotecommunications.com/apache/mod_gzip/ + +The hacked distribution is installed and used in exactly the same fashion +as the regular distribution. There's one extra logging directive available: + + %{mod_gzip_compression_format}n Compression format chosen by client. + +Go read the mod_gzip documentation; it should all make sense. + +If you want to discuss the XML-RPC Turbocharger, please sign up for the +xmlrpc-c-devel mailing list at: + + http://xmlrpc-c.sourceforge.net/ + +This code is highly experimental, and may do some strange things. You'll +probably need to screw around with mod_gzip for a while until you get +everything to work. Don't run this on your production web server, OK? + +Eric Kidd +eric.kidd@pobox.com + +P.S. The Turbocharger appears to dump core in mod_gzip decides to serialize +a large response to disk. Do you see what I mean by "experimental" and +"don't run this on your production web server"? :-) diff --git a/tools/turbocharger/mod_gzip.c b/tools/turbocharger/mod_gzip.c new file mode 100644 index 0000000..490d8ac --- /dev/null +++ b/tools/turbocharger/mod_gzip.c @@ -0,0 +1,9843 @@ +/* ==================================================================== + * Copyright (c) 1995-2000 The Apache Group. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the Apache Group + * for use in the Apache HTTP server project (http://www.apache.org/)." + * + * 4. The names "Apache Server" and "Apache Group" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * apache@apache.org. + * + * 5. Products derived from this software may not be called "Apache" + * nor may "Apache" appear in their names without prior written + * permission of the Apache Group. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the Apache Group + * for use in the Apache HTTP server project (http://www.apache.org/)." + * + * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE APACHE GROUP OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Group and was originally based + * on public domain software written at the National Center for + * Supercomputing Applications, University of Illinois, Urbana-Champaign. + * For more information on the Apache Group and the Apache HTTP server + * project, please see . + * + */ + +/* + * mod_gzip.c + * + * Apache gzip compression module. + * + * This module adds 'on the fly' compression of HTTP content to + * any Apache Web Server. It uses the IETF Content-encoding standard(s). + * + * It will compress both static files and the output of any CGI + * program inclding shell scripts, perl scripts, executables, + * PHP used as CGI, etc. + * + * There is NO client-side software required for using this module + * other than any fully HTTP 1.1 compliant user agent. + * + * Any fully HTTP 1.1 compliant user agent will be able to receive and + * automatically decode the compressed content. + * + * All fully HTTP 1.1 compliant user agents that are capable of receiving + * gzip encoded data will indicate their ability to do so by adding the + * standard "Accept-Encoding: gzip" field to the inbound request header. + * + * This module may be compiled as a stand-alone external 'plug-in' + * or be compiled into the Apache core server as a 'built-in' module. + * + * Sponsor: Remote Communications, Inc. http://www.RemoteCommunications.com/ + * Authors: Konstantin Balashov, Alex Kosobrukhov and Kevin Kiley. + * Contact: info@RemoteCommunications.com + * + * Initial public release date: 13-Oct-2000 + * + * Miscellaneous release notes: + * + * THIS IS A COMPLETELY SELF-CONTAINED MODULE. MOD_GZIP.C IS THE + * ONY SOURCE CODE FILE THERE IS AND THERE ARE NO MODULE SPECIFIC + * HEADER FILES OR THE NEED FOR ANY 3RD PARTY COMPRESSION LIBRARIES. + * ALL OF THE COMPRESSION CODE NEEDED BY THIS MODULE IS CONTAINED + * WITHIN THIS SINGLE SOURCE FILE. + * + * Many standard compression libraries are not designed or optimized + * for use as real-time compression codecs nor are they guaranteed + * to be 'thread-safe'. The internal compression code used by mod_gzip + * is all of those things. It is a highly-optimized and thread-safe + * implementation of the standard LZ77 + Huffman compression + * technique that has come to be known as GZIP. + * + * MOD_GZIP LOG FORMATS... + * + * mod_gzip makes a number of statistical items for each transaction + * available through the use of Apache's 'LogFormat' directives which + * can be specified in the httpd.conf Apache config file + * + * mod_gzip uses the standard Apache NOTES interface to allow compression + * information to be added to the Apache Web Server log files. + * + * Standard NOTES may be added to Apache logs using the following syntax + * in any LogFormat directive... + * * %...{Foobar}n: The contents of note "Foobar" from another module. + * + * Additional notes about logging compression information... + * + * The Apache LogFormat directive is unable to actually display + * the 'percent' symbol since it is used exclusively as a 'pickup' + * character in the formatting string and cannot be 'escaped' so + * all logging of compression ratios cannot use the PERCENT symbol. + * Use ASCII 'pct.' designation instead for all PERCENTAGE values. + * + * Example: This will display the compression ratio percentage along + * with the standard CLF ( Common Log Format ) information... + * + * Available 'mod_gzip' compression information 'notes'... + * + * %{mod_gzip_result}n - A short 'result' message. Could be OK or DECLINED, etc. + * %{mod_gzip_input_size}n - The size ( in bytes ) of the requested object. + * %{mod_gzip_output_size}n - The size ( in bytes ) of the compressed version. + * %{mod_gzip_compression_ration}n - The compression rate achieved. + * + * LogFormat "%h %l %u %t \"%r\" %>s %b mod_gzip: %{mod_gzip_compression_ratio}npct." common_with_mod_gzip_info1 + * LogFormat "%h %l %u %t \"%r\" %>s %b mod_gzip: %{mod_gzip_result}n In:%{mod_gzip_input_size}n Out:%{mod_gzip_output_size}n:%{mod_gzip_compression_ratio}npct." common_with_mod_gzip_info2 + * + * If you create your own custom 'LogFormat' lines don't forget that + * the entire LogFormat line must be encased in quote marks or you + * won't get the right results. The visible effect of there not being + * and end-quote on a LogFormat line is that the NAME you are choosing + * for the LogFormat line is the only thing that will appear in the + * log file that tries to use the unbalanced line. + * + * Also... when using the %{mod_gzip_xxxxx}n note references in your + * LogFormat line don't forget to add the lowercase letter 'n' after + * the closing bracket to indicate that this is a module 'note' value. + * + * Once a LogFormat directive has been added to your httpd.conf file + * which displays whatever level of compression information desired + * simply use the 'name' associated with that LogFormat line in + * the 'CustomLog' directive for 'access.log'. + * + * Example: The line below simply changes the default access.log format + * for Apache to the special mog_gzip information record defined above... + * CustomLog logs/access.log common + * + * CustomLog logs/access.log common_with_mod_gzip_info2 + * + * Using the 'common_with_mod_gzip_info1' LogFormat line for Apache's + * normal access.log file produces the following results in the access.log + * file when a gigantic 679,188 byte online CD music collection HTML + * document called 'music.htm' is requested and the Server delivers the + * file via mod_gzip compressed 93 percent down to only 48,951 bytes... + * + * 216.20.10.1 [12/Oct...] "GET /music.htm HTTP/1.1" 200 48951 mod_gzip: 93pct. + * + * The line below shows what will appear in the Apache access.log file + * if the more detailed 'common_with_mod_gzip_info2' LogFormat line is used. + * The line has been intentionally 'wrapped' for better display below + * but would normally appear as a single line entry in access.log. + * + * 216.20.10.1 [12/Oct...] "GET /music.htm HTTP/1.1" 200 48951 + * mod_gzip: OK In:679188 Out:48951:93pct. + * + * The 'OK' result string shows that the compression was successful. + * The 'In:' value is the size (in bytes) of the requested file and + * the 'Out:' value is the size (in bytes) after compression followed + * by a colon and a number showing that the document was compressed + * 93 percent before being returned to the user. + * + * Please NOTE that if you add any ASCII strings to your LogFormat + * string then they will appear in your log file regardless of + * whether this module was actually 'called' to process the + * transaction or not. If the module was not called to handle the + * transaction then the places where the statistical information + * associated with the 'NOTES' references would normally appear + * will be filled in with 'dashes' to denote 'no value available'. + * + * MOD_GZIP RUNTIME DEBUG... + * + * If you set your default Apache logging level to 'LogLevel debug' + * in your httpd.conf file then this module will add certain + * diagnostic debug messages to your error log for each and every + * transaction that is actually passed to the module. + * + * If Apache does not 'call' this module to handle a particular + * transaction then no special log information will appear in + * your error log(s) for that transaction. + * + * MOD_GZIP CONFIGURATION DIRECTIVES... + * + * The section that follows is a sample mod_gzip configuration + * section that will provide basic compression of all static + * TEXT and HTML files as well as dynamic compression of most + * standard CGI including Shell scripts, Perl, PHP, etc. + * + * The configuration directives themselves are documented in more + * detail in the README and INSTALL files that accompany this module. + * + * You should be able to simply 'cut and paste' the follwing section + * directly into the BOTTOM of your current httpd.conf Apache + * configuration file and be able to start using mod_gzip immediately. + * + +# +# MOD_GZIP Configuration Directives +# +# All you should have to do to get up and running using +# mod_gzip with some basic STATIC and DYNAMIC compression +# capabilites is copy the mod_gzip dynamic library to your +# ../modules directory and then add this entire example +# configuration section to the BOTTOM of your httpd.conf file. +# +# Add this entire section including all lines down to where +# it says '# End of MOD_GZIP Configuration Directives'. +# +# The LoadModule command is included here for clarity +# but you may want to move it the the BOTTOM of your +# current LoadModule list in httpd.conf. +# +# Change the 'mod_gzip_temp_dir' to the name of a directory +# on your machine where temporary workfiles can be created +# and destroyed. This directory MUST be readable/writable +# by the Server itself while it is running. If the directory +# does not exist you must create it yourself with the right +# permissions before running the Server. +# +# If no 'mod_gzip_temp_dir' is specified then the default location +# for temporary workfiles will be 'ServerRoot' directory. +# +# The special mod_gzip log formats are, of course, optional. +# +# You must, of course, load the right module name for your OS +# so make sure the correct 'LoadModule' command is uncommented +# directly below... + +# Load Win32 module... +LoadModule gzip_module modules/ApacheModuleGzip.dll + +# Load UNIX module... +# LoadModule gzip_module modules/mod_gzip.so + +LogFormat "%h %l %u %t \"%r\" %>s %b mod_gzip: %{mod_gzip_compression_ratio}npct." common_with_mod_gzip_info1 +LogFormat "%h %l %u %t \"%r\" %>s %b mod_gzip: %{mod_gzip_result}n In:%{mod_gzip_input_size}n Out:%{mod_gzip_output_size}n:%{mod_gzip_compression_ratio}npct." common_with_mod_gzip_info2 + +# NOTE: This 'CustomLog' directive shows how to set your access.log file +# to use the mod_gzip format but please remember that for every 'CustomLog' +# directive that Apache finds in httpd.conf there will be corresponding +# line of output in the access.log file. If you only want ONE line of +# results in access.log for each transaction then be sure to comment out +# any other 'CustomLog' directives so that this is the only one. + +CustomLog logs/access.log common_with_mod_gzip_info2 + +# Runtime control directives... + +mod_gzip_on Yes +mod_gzip_do_cgi Yes +mod_gzip_do_static_files Yes +mod_gzip_minimum_file_size 300 +mod_gzip_maximum_inmem_size 60000 +mod_gzip_keep_workfiles No +mod_gzip_temp_dir "C:/Program Files/Apache Group/Apache/temp" + +# Item lists... +# +# Item names can be any one of the following... +# +# cgi-script - A valid 'handler' name +# text/* - A valid MIME type name ( '*' wildcard allowed ) +# .phtml - A valid file type extension + +# Dynamic items... +# +# NOTE: FOR NOW ALL DYNAMIC ITEMS SHOULD BE +# DECLARED BEFORE ANY STATIC ITEMS TO PREVENT +# PICKUP CONFLICTS. IF YOU USE !cgi-script +# BE SURE IT IS DECLARED BEFORE ANY text/* +# MIME TYPE ENTRIES. +# +# The items listed here are the types of dynamic +# output that will be compressed... +# +# Dynamic items MUST have the "!" BANG character +# on the front of the item name. +# +mod_gzip_item_include !cgi-script +mod_gzip_item_include !.php +mod_gzip_item_include !.php3 +mod_gzip_item_include !.phtml + +# Static items... +# +# The items listed here are the types of static +# files that will be compressed... +# +# NOTE: FOR NOW ALL STATIC INCLUDES MUST +# COME AFTER DYNAMIC INCLUDES TO PREVENT +# PICKUP CONFLICTS +# +mod_gzip_item_include text/* + +# Uncomment this line to compress graphics +# when graphics compression is allowed... +#mod_gzip_item_include image/* + + +# Exclusions... MIME types and FILE types... +# +# The items listed here will be EXCLUDED from +# any attempt to apply compression... +# +mod_gzip_item_exclude .js +mod_gzip_item_exclude .css + +# Exclusions... HTTP support levels... +# +# By specifying a certain minimum level of HTTP support +# certain older user agents ( browsers ) can be +# automatically excluded from receiving compressed data. +# +# The item value should be in the same HTTP numeric format +# that Apache uses to designate HTTP version levels. +# +# 1001 = HTTP/1.1 +# +# So 'mod_gzip_min_http 1001' means that a requesting +# user agent ( browser ) must report a minimum HTTP support +# level of 1.1 or it will not receive any compressed data. +# +mod_gzip_min_http 1001 + +# Debugging... +# +# If your Apache 'LogLevel' is set to 'debug' then +# mod_gzip will add some diagnostic and compression +# information to your error.log file for each request +# that is processed by mod_gzip. +# +# LogLevel debug + +# End of MOD_GZIP Configuration Directives + + * End of inline comments + */ + +#include +/* + * Apache headers... + */ + +#define CORE_PRIVATE + +#include "httpd.h" +#include "http_config.h" +#include "http_core.h" +#include "http_log.h" +#include "http_main.h" +#include "http_protocol.h" +#include "util_script.h" + +/* + * Add this header for ap_server_root[ MAX_STRING_LEN ] global... + * + * #include "http_conf_globals.h" + * + * ...or just include what we need from http_conf_globals.h + * since that is, in fact, only 1 item at this time. + */ +extern API_VAR_EXPORT char ap_server_root[ MAX_STRING_LEN ]; + +/* + * Add this header to get 'ap_update_mtime()' prototype... + * + * #include "http_request.h" + * + * ...or just include what we need from http_request.h since + * that is, in fact, only 1 item at this time. + */ +extern API_EXPORT(time_t) +ap_update_mtime(request_rec *r, time_t dependency_mtime); + +/* + * Version information... + * + * Since this product is 'married' to the ASF Apache Web Server + * the version numbers should always 'match' the changing + * version numbers of Apache itself so users can be sure + * they have the 'right' module. This allows us to move the + * version numbers either backwards or forwards in case issues + * arise which require specific versions of mod_gzip for + * specific versions of Apache. + * + * The original code was first tested against the Apache 1.3.14 + * release but should be compatible with the entire 1.3.x series. + * If earlier 1.3.x versions of Apache required special versions + * then the mod_gzip version number will still match the Apache + * version number ( As in... mod_gzip v1.3.12.1, if needed ). + * + * If a special version is required for Apache 2.0 then the + * version number(s) will change to match release numbers in + * that series. ( As in... mod_gzip v 2.0.1.1, etc. ). + * + * The first 3 numbers of the version are always the equivalent + * Apache release numbers. The fourth number is always the actual + * mod_gzip 'build' number for that version of Apache. + */ + +char mod_gzip_version[] = "1.3.14.5"; /* Global version string */ + +/* + * Declare the NAME by which this module will be known. + * This is the NAME that will be used in LoadModule command(s). + */ +extern module MODULE_VAR_EXPORT gzip_module; + +/* + * Allow this module to 'read' config information from + * ( and interact with ) the 'real' mod_cgi module... + */ +extern module cgi_module; + +/* + * Some compile-time code inclusion switches... + */ + +/* + * Turn MOD_GZIP_ALLOWS_INTERNAL_COMMANDS switch ON to allow + * information requests to be sent via any standard browser. + */ + +#define MOD_GZIP_ALLOWS_INTERNAL_COMMANDS + +/* + * Turn MOD_GZIP_USES_APACHE_LOGS switch ON to include the + * code that can update Apache logs with compression information. + */ + +#define MOD_GZIP_USES_APACHE_LOGS + + /* + * Turn MOD_GZIP_USES_AP_SEND_MMAP switch ON to use the + * ap_send_mmap() method for transmitting data. If this + * switch is OFF then the default is to use ap_rwrite(). + * This might need to be platform specific at some point. + */ + +#define MOD_GZIP_USES_AP_SEND_MMAP + +/* + * Turn MOD_GZIP_DEBUG1 switch ON for verbose diags. + * This is normally OFF by default and should only be + * used for diagnosing problems. The log output is + * VERY detailed and the log files will be HUGE. + */ + +/* +#define MOD_GZIP_DEBUG1 +*/ + +/* + * Some useful instance globals... + */ + +#ifndef MOD_GZIP_MAX_PATH_LEN +#define MOD_GZIP_MAX_PATH_LEN 512 +#endif + +char mod_gzip_temp_dir[ MOD_GZIP_MAX_PATH_LEN + 2 ]; + +long mod_gzip_iusn = 0; /* Instance Unique Sequence Number */ + +long mod_gzip_maximum_inmem_size = 60000L; +long mod_gzip_minimum_file_size = 300L; + +#ifdef WIN32 +char mod_gzip_dirsep[]="\\"; /* Dir separator is a backslash for Windows */ +#else /* !WIN32 */ +char mod_gzip_dirsep[]="/"; /* Dir separator is a forward slash for UNIX */ +#endif /* WIN32 */ + +/* + * The Compressed Object Cache control structure... + */ + +#define MOD_GZIP_SEC_ONE_DAY 86400 /* Total seconds in one day */ +#define MOD_GZIP_SEC_ONE_HR 3600 /* Total seconds in one hour */ + +#define MOD_GZIP_DEFAULT_CACHE_SPACE 5 +#define MOD_GZIP_DEFAULT_CACHE_MAXEXPIRE MOD_GZIP_SEC_ONE_DAY +#define MOD_GZIP_DEFAULT_CACHE_EXPIRE MOD_GZIP_SEC_ONE_HR +#define MOD_GZIP_DEFAULT_CACHE_LMFACTOR (0.1) +#define MOD_GZIP_DEFAULT_CACHE_COMPLETION (0.9) + +struct mod_gzip_cache_conf { + + const char *root; /* The location of the cache directory */ + off_t space; /* Maximum cache size (in 1024 bytes) */ + char space_set; + time_t maxexpire; /* Maximum time to keep cached files (secs) */ + char maxexpire_set; + time_t defaultexpire; /* Default time to keep cached file (secs) */ + char defaultexpire_set; + double lmfactor; /* Factor for estimating expires date */ + char lmfactor_set; + time_t gcinterval; /* Garbage collection interval (secs) */ + char gcinterval_set; + int dirlevels; /* Number of levels of subdirectories */ + char dirlevels_set; + int dirlength; /* Length of subdirectory names */ + char dirlength_set; +}; + +/* + * The Inclusion/Exclusion map item structure... + */ + +#define MOD_GZIP_IMAP_MAXNAMES 256 +#define MOD_GZIP_IMAP_MAXNAMELEN 90 + +#define MOD_GZIP_IMAP_ISMIME 1 +#define MOD_GZIP_IMAP_ISEXT 2 +#define MOD_GZIP_IMAP_ISHANDLER 3 + +#define MOD_GZIP_IMAP_STATIC1 9001 +#define MOD_GZIP_IMAP_DYNAMIC1 9002 +#define MOD_GZIP_IMAP_DECLINED1 9003 + +typedef struct { + + int include; /* 1=Include 0=Exclude */ + int type; /* _ISMIME, _ISEXT, _ISHANDLER, etc. */ + int action; /* _STATIC1, _DYNAMIC1, etc. */ + + char name[ MOD_GZIP_IMAP_MAXNAMELEN + 2 ]; + +} mod_gzip_imap; + +/* + * The primary module configuration record... + */ + +typedef struct { + + struct mod_gzip_cache_conf cache; /* Compressed Object Cache control */ + + int req; /* 1=mod_gzip handles requests 0=No */ + char req_set; /* Mirrors the 'req' flag */ + int do_static_files; /* 1=Yes 0=No */ + int do_cgi; /* 1=Yes 0=No */ + int keep_workfiles; /* 1=Keep workfiles 0=No */ + int min_http; /* Minimum HTTP level ( 1001=HTTP/1.1 ) */ + long minimum_file_size; /* Minimum size in bytes for compression attempt */ + long maximum_inmem_size; /* Maximum size in bytes for im-memory compress */ + + /* Inclusion/Exclusion list(s)... */ + + int imap_total_entries; + + mod_gzip_imap imap[ MOD_GZIP_IMAP_MAXNAMES + 1 ]; + +} mod_gzip_conf; + +/* + * The GZP request control structure... + */ + +#define GZIP_FORMAT (0) +#define DEFLATE_FORMAT (1) + +typedef struct _GZP_CONTROL { + + int decompress; /* 0=Compress 1=Decompress */ + + int compression_format; /* GZIP_FORMAT or DEFLATE_FORMAT */ + + /* Input control... */ + + int input_ismem; /* Input source is memory buffer, not file */ + char *input_ismem_ibuf; /* Pointer to input memory buffer */ + long input_ismem_ibuflen; /* Total length of input data */ + + char input_filename[ MOD_GZIP_MAX_PATH_LEN + 2 ]; /* Input file name */ + + /* Output control... */ + + int output_ismem; /* Output source is memory buffer, not file */ + char *output_ismem_obuf; /* Pointer to output memory buffer */ + long output_ismem_obuflen; /* Maximum length of output data buffer */ + + char output_filename[ MOD_GZIP_MAX_PATH_LEN + 2 ]; /* Output file name */ + + /* Results... */ + + int result_code; /* Result code */ + long bytes_out; /* Total number of compressed output bytes */ + +} GZP_CONTROL; + +/* + * Forward prototypes for internal routines... + */ + +int gzp_main( GZP_CONTROL *gzp ); /* Primary GZP API entry point */ + +int mod_gzip_request_handler( request_rec *r ); +int mod_gzip_cgi_handler( request_rec *r ); +int mod_gzip_static_file_handler( request_rec *r ); +int mod_gzip_prepare_for_dynamic_call( request_rec *r ); +int mod_gzip_imap_show_items( mod_gzip_conf *mgc ); +int mod_gzip_get_action_flag( request_rec *r, mod_gzip_conf *conf ); +int mod_gzip_ismatch( char *s1, char *s2, int len1, int haswilds ); + +FILE *mod_gzip_open_output_file( +request_rec *r, +char *output_filename, +int *rc +); + +int mod_gzip_create_unique_filename( +mod_gzip_conf *mgc, +char *target, +int targetmaxlen +); + +int mod_gzip_encode_and_transmit( +request_rec *r, +char *source, +int source_is_a_file, +long input_size, +int nodecline +); + + +#ifdef MOD_GZIP_ALLOWS_INTERNAL_COMMANDS + +int mod_gzip_send_html_command_response( +request_rec *r, /* Request record */ +char *tmp, /* Response to send */ +char *ctype /* Content type string */ +); + +#endif /* MOD_GZIP_ALLOWS_INTERNAL_COMMANDS */ + +/* + * Module routines... + */ + +#ifdef MOD_GZIP_DEBUG1 + +void mod_gzip_printf( const char *fmt, ... ) +{ + int l; + FILE *log; + + va_list ap; + + char logname[256]; + char log_line[4096]; + + /* Start... */ + + /* If UNIX then mod_gzip_dirsep = '/' Backward slash */ + /* If WIN32 then mod_gzip_dirsep = '\' Forward slash */ + + #ifdef FUTURE_USE + /* + For now we need both startup and runtime diags in the same + log so it all goes to ServerRoot. 'mod_gzip_temp_dir' name + isn't even valid until late in the startup process so we + have to write to ServerRoot anyway until temp dir is known. + */ + if ( strlen(mod_gzip_temp_dir) ) /* Use temp directory ( if specified )... */ + { + sprintf( logname, "%s%smod_gzip.log", mod_gzip_temp_dir, mod_gzip_dirsep ); + } + else /* Just use 'ap_server_root' Apache ServerRoot directory... */ + { + sprintf( logname, "%s%smod_gzip.log", ap_server_root, mod_gzip_dirsep ); + } + #endif /* FUTURE_USE */ + + /* Just use ServerRoot for now... */ + sprintf( logname, "%s%smod_gzip.log", ap_server_root, mod_gzip_dirsep ); + + log = fopen( logname,"a" ); + + if ( !log ) /* Log file did not open... */ + { + /* Just turn and burn... */ + + return; /* Void return */ + } + + /* Get the variable parameter list... */ + + va_start( ap, fmt ); + + l = vsprintf(log_line, fmt, ap); + + /* See if we need to add LF... */ + + if ( l > 0 ) + { + if ( log_line[l-1] != '\n' ) + { + log_line[l]='\n'; + l++; + } + + log_line[l+1] = 0; + } + + fprintf( log, "%s", log_line ); + + fclose( log ); + + va_end(ap); /* End session */ + + return; /* Void return */ + +}/* End of log_d() */ + +void mod_gzip_hexdump( char *buffer, int buflen ) +{ + int i,o1,o2,o3; + + int len1; + int len2; + + char ch1; + char ch2; + char s[40]; + char l1[129]; + char l2[129]; + char l3[300]; + + long offset1=0L; + + /* Start... */ + + o1=0; + o2=0; + o3=0; + + l1[0] = 0; + l2[0] = 0; + l3[0] = 0; + + offset1 = 0; + + for ( i=0; i 126) ch2 = DUMPIT_LAPOSTROPHE; + else if ( ch1 == 37 ) ch2 = DUMPIT_ASTERISK; /* Mask PERCENT for UNIX */ + else if ( ch1 == 92 ) ch2 = DUMPIT_ASTERISK; /* Mask BACKSLASH for UNIX */ + else ch2 = ch1; + + /* ENDIF on MASK_ALL_NON_PRINTABLE_CHARS */ + #endif + + l2[o2++] = ch2; + + sprintf( s, "%02X", ch1 ); + + if ( strlen(s) > 2 ) s[2]=0; /* Prevent overflow */ + + len1 = strlen(s); + len2 = strlen(l1); + + if ( strlen(l1) < (sizeof(l1) - (len1+1)) ) + { + strcat( l1, s ); + strcat( l1, " " ); + } + + if ( o2 >= 16 ) + { + l2[o2]=0; + + mod_gzip_printf( "%6lu| %-49.49s| %-16.16s |\n", offset1, l1, l2 ); + + offset1 += o2; + + o1=0; + o2=0; + o3=0; + + l1[0] = 0; + l2[0] = 0; + l3[0] = 0; + } + + }/* End 'for( i=0; i 0 ) + { + l2[o2]=0; + + mod_gzip_printf( "%6lu| %-49.49s| %-16.16s |\n", offset1, l1, l2 ); + + offset1 += o2; + + o1 = o2 = o3 = 0; + + l1[0] = 0; + l2[0] = 0; + l3[0] = 0; + } + +}/* End of mod_gzip_hexdump() */ + +#endif /* MOD_GZIP_DEBUG1 */ + +static void mod_gzip_init( server_rec *server, pool *p ) +{ + /* + * The module initialization procedure... + */ + + FILE *fh1; + char filename[ 512 ]; + + #ifdef MOD_GZIP_DEBUG1 + char cn[]="mod_gzip_init()"; + #endif + + mod_gzip_conf *mgc; + + /* Start... */ + + #ifdef MOD_GZIP_DEBUG1 + mod_gzip_printf( "%s: Entry...\n", cn ); + #endif + + /* + * Set some instance specific globals... + * + * The default 'temp' dir, lacking an httpd.conf config file + * override, is the Apache 'ServerRoot'. Don't assume that /logs + * dir exists because some Apache installations just use syslog + * or stderr as their log output target. + * + * On most Apache installations 'ServerRoot' is automatically + * readable/writable by the Server while it is running. + * + * On systems where it is not there MUST be an override + * in the httpd.conf file. + * + * See the comments regarding the 'mod_gzip_temp_dir' directive + * in the httpd.conf configuration file. + */ + + mgc = ( mod_gzip_conf * ) + ap_get_module_config(server->module_config, &gzip_module); + + /* Make sure we can read/write the temp directory... */ + + sprintf( filename, "%s%smod_gzip.id", mgc->cache.root, mod_gzip_dirsep ); + + fh1 = fopen( filename, "wb" ); + + if ( !fh1 ) /* Write an ERROR to console and to log(s)... */ + { + fprintf( stderr, "mod_gzip: Cannot read/write dir/file [%s]\n",filename); + fprintf( stderr, "mod_gzip: Make sure the directory exists and that the Server\n"); + fprintf( stderr, "mod_gzip: has read/write permission(s) for the directory.\n"); + fprintf( stderr, "mod_gzip: See the 'mod_gzip_temp_dir' configuration notes.\n"); + + /* This is a startup ERROR and has to be fixed... */ + + ap_log_error( "",0,APLOG_NOERRNO|APLOG_ERR, server, + "mod_gzip: Cannot read/write dir/file [%s]", filename); + ap_log_error( "",0,APLOG_NOERRNO|APLOG_ERR, server, + "mod_gzip: Make sure the directory exists and that the Server"); + ap_log_error( "",0,APLOG_NOERRNO|APLOG_ERR, server, + "mod_gzip: has read/write permission(s) for the directory."); + ap_log_error( "",0,APLOG_NOERRNO|APLOG_ERR, server, + "mod_gzip: See the 'mod_gzip_temp_dir' configuration notes."); + } + else /* File opened OK... just add some data and close it... */ + { + /* + * Since this is just a MARK file we could simply wipe + * it out but might as well print the actual version + * number into it and leave it there in case there is + * any question about which version is actually running. + */ + + fprintf( fh1, "mod_gzip version %s\n", mod_gzip_version ); + fclose( fh1 ); + } + + #ifdef MOD_GZIP_DEBUG1 + mod_gzip_imap_show_items( (mod_gzip_conf *) mgc ); /* Show item list */ + mod_gzip_printf( "%s: Exit > return( void ) >\n", cn ); + mod_gzip_printf( "\n" ); /* Separator for log file */ + #endif + +}/* End of mod_gzip_init() */ + +int mod_gzip_strnicmp( char *s1, char *s2, int len1 ) +{ + /* Behaves just like strnicmp() but IGNORES differences */ + /* between FORWARD or BACKWARD slashes in a STRING... */ + /* Also uses straight pointers and avoids stdlib calls. */ + + int i; + char ch1; + char ch2; + + /* WARNING! We MUST have a check for 'NULL' on the pointer(s) */ + /* themselves or we might GP ( like NETSCAPE does ) */ + /* if a 'NULL' pointer is passed to this routine... */ + + if ( ( s1 == 0 ) || ( s2 == 0 ) ) + { + /* SAFETY! If pointer itself if NULL */ + /* don't enter LOOP or NETSCAPE will GP... */ + + return( 1 ); /* Return '1' for NOMATCH... */ + } + + for ( i=0; i 96 ) ch1 -= 32; + if ( ch2 > 96 ) ch2 -= 32; + + if ( ch1 == '/' ) ch1 = '\\'; + if ( ch2 == '/' ) ch2 = '\\'; + + if ( ch1 != ch2 ) return( 1 ); /* No match! */ + + s1++; + s2++; + + }/* End 'i' loop */ + + /* If we make it to here then everything MATCHED! */ + + return( 0 ); /* MATCH! */ + +}/* End mod_gzip_strnicmp() */ + +extern API_VAR_EXPORT module *top_module; + +struct _table { + array_header a; +#ifdef MAKE_TABLE_PROFILE + void *creator; +#endif +}; +typedef struct _table _table; + +const char *mod_gzip_isscript( request_rec *r, _table *t, const char *key) +{ + /* + * Get a 'handler' name for a MIME type right out of + * the Apache 'Action' table(s)... + * + * Example: + * + * If "key" is "applications/x-httpd-php3" + * then this search will return "/php3/php.exe" + * or whatever the equivalent PHP executable + * pathname is as specified by an 'Action' statement + * in the httpd.conf configuration file. + * + * This pathname might still have 'aliases' in it + * so we will have to consult with mod_alias + * following this call and get any aliases converted. + */ + + table_entry *elts = + (table_entry *) t->a.elts; + int i; + + char cn[]="mod_gzip_isscript()"; + + /* + * Start... + */ + + #ifdef MOD_GZIP_DEBUG1 + mod_gzip_printf( "%s: Entry...\n",cn); + mod_gzip_printf( "%s: key=[%s]\n",cn,key ); + #endif + + if ( key == NULL ) + { + #ifdef MOD_GZIP_DEBUG1 + mod_gzip_printf( "%s: 'key' has no length\n",cn); + mod_gzip_printf( "%s: Exit > return( NULL ) >\n",cn); + #endif + + if ( r->server->loglevel == APLOG_DEBUG ) + { + ap_log_error( "",0,APLOG_NOERRNO|APLOG_DEBUG, r->server, + "%s: Search key is NULL.",cn); + } + + return NULL; + } + + for (i = 0; i < t->a.nelts; ++i) + { + #ifdef MOD_GZIP_DEBUG1 + mod_gzip_printf( + "%s: i=%4.4d Comparing [%s] with elts.key[%s].val[%s]\n", + cn, i, key, elts[i].key, elts[i].val ); + #endif + + if ( r->server->loglevel == APLOG_DEBUG ) + { + ap_log_error( "",0,APLOG_NOERRNO|APLOG_DEBUG, r->server, + "%s: i=%4.4d Comparing [%s] with elts.key[%s].val[%s]", + cn, i, key, elts[i].key, elts[i].val ); + } + + if (!strcasecmp(elts[i].key, key)) + { + #ifdef MOD_GZIP_DEBUG1 + mod_gzip_printf( "%s: MATCH FOUND!",cn); + mod_gzip_printf( "%s: Exit > return(%s) >\n",cn,elts[i].val); + #endif + + if ( r->server->loglevel == APLOG_DEBUG ) + { + ap_log_error( "",0,APLOG_NOERRNO|APLOG_DEBUG, r->server, + "%s: MATCH FOUND...",cn); + } + + return elts[i].val; + } + + }/* End 'i' loop */ + + if ( r->server->loglevel == APLOG_DEBUG ) + { + ap_log_error( "",0,APLOG_NOERRNO|APLOG_DEBUG, r->server, + "%s: NO MATCH FOUND...",cn); + } + + #ifdef MOD_GZIP_DEBUG1 + mod_gzip_printf( "%s: NO MATCH FOUND!\n",cn); + mod_gzip_printf( "%s: Exit > return( NULL ) >\n",cn); + #endif + + return NULL; + +}/* End of 'mod_gzip_isscript()' */ + +typedef struct { + table *action_types; /* Added with Action... */ + char *scripted[METHODS]; /* Added with Script... */ + array_header *xmethods; /* Added with Script -- extension methods */ +} mod_actions_local_config; + +int mod_gzip_run_mod_action( request_rec *r ) +{ + module *modp; + int count=0; + int pass=0; + + mod_actions_local_config *mod_actions_conf; + + const char *t=0; + const char *action=0; + + #ifdef MOD_GZIP_DEBUG1 + char cn[]="mod_gzip_run_mod_action()"; + #endif + + #ifdef MOD_GZIP_FUTURE_USE + const handler_rec *handp; + #endif + + /* Currently 9 possible 'event' handlers. */ + /* Actual content handler in a module is 'extra'. */ + #define MOD_GZIP_NMETHODS 9 + + /* + * Start... + */ + + #ifdef MOD_GZIP_DEBUG1 + mod_gzip_printf( "%s: Entry...\n",cn); + mod_gzip_printf( "%s: *IN: r->uri =[%s]\n", cn, r->uri ); + mod_gzip_printf( "%s: *IN: r->unparsed_uri=[%s]\n", cn, r->unparsed_uri ); + mod_gzip_printf( "%s: *IN: r->filename =[%s]\n", cn, r->filename ); + mod_gzip_printf( "%s: r->content_type =[%s]\n", cn,r->content_type); + mod_gzip_printf( "%s: r->handler =[%s]\n", cn,r->handler); + #endif + + for ( modp = top_module; modp; modp = modp->next ) + { + /* modp->name list will look like this... */ + /*--------------------*/ + /* 00 [mod_gzip.c] */ + /* 01 [mod_isapi.c] */ + /* 02 [mod_setenv.c] */ + /* 02 [mod_actions.c] */ + /* ............... */ + /* ............... */ + /* 18 [mod_so.c] */ + /* 19 [http_core.c] <- Always bottom of list (last one called) */ + /*--------------------*/ + + #ifdef MOD_GZIP_DEBUG1 + mod_gzip_printf( "%s: count=%4.4d modp = %10.10ld modp->name=[%s]\n", + cn,count,(long)modp, modp->name ); + #endif + + if ( mod_gzip_strnicmp( (char *) modp->name, "mod_actions.c", 13 ) == 0 ) + { + + /* Module information... */ + + #ifdef MOD_GZIP_DEBUG1 + mod_gzip_printf( "%s: ++++++++++ MODULE FOUND!...\n",cn); + mod_gzip_printf( "%s: ++++++++++ modp->module_index = %d\n",cn,(int)modp->module_index); + #endif + + /* Get a pointer to the module configuration data... */ + + mod_actions_conf = (mod_actions_local_config *) + ap_get_module_config(r->per_dir_config, modp ); + + /* Get script name... */ + + /* Make 2 passes if necessary. If we don't find a */ + /* program name associated with MIME type first */ + /* then punt and look for a program name associated */ + /* with the r->handler name such as [php-script] */ + + for ( pass = 0; pass < 2; pass++ ) + { + if ( pass == 0 ) /* Check r->content_type first */ + { + /* This is the first pass... */ + + /* Set 'action' search key to 'r->content_type' */ + /* so we search for [application/x-httpd-php3] */ + + action = r->content_type; + } + else if ( pass == 1 ) /* Try r->handler */ + { + /* This is the second pass... */ + + /* Set 'action' search key to 'r->handler' */ + /* so we search for [php-script] */ + + action = r->handler; + } + + #ifdef MOD_GZIP_DEBUG1 + mod_gzip_printf( "%s: ++++++++++ pass =%d\n", cn,pass); + mod_gzip_printf( "%s: ++++++++++ t =[%s]\n",cn,t); + mod_gzip_printf( "%s: ++++++++++ r->content_type =[%s]\n",cn,r->content_type); + mod_gzip_printf( "%s: ++++++++++ r->handler =[%s]\n",cn,r->handler); + mod_gzip_printf( "%s: ++++++++++ action =[%s]\n",cn,action); + mod_gzip_printf( "%s: ++++++++++ r->filename =[%s]\n",cn,r->filename); + mod_gzip_printf( "%s: ++++++++++ r->uri =[%s]\n",cn,r->uri); + mod_gzip_printf( "%s: ++++++++++ Call mod_gzip_isscript()...\n",cn); + #endif + + t = + mod_gzip_isscript( + r, + (_table *) mod_actions_conf->action_types, + action ? action : ap_default_type(r) + ); + + #ifdef MOD_GZIP_DEBUG1 + mod_gzip_printf( "%s: ++++++++++ Back mod_gzip_isscript()...\n",cn); + mod_gzip_printf( "%s: ++++++++++ t =[%s]\n",cn,t); + mod_gzip_printf( "%s: ++++++++++ action =[%s]\n",cn,action); + #endif + + if ( t ) + { + /* + * If a program name was found then make it r->filename + * and r->uri will become the input name for the program + */ + + r->filename = ap_pstrdup(r->pool,t); + + break; + } + + }/* End 'for( pass )' loop */ + + #ifdef MOD_GZIP_DEBUG1 + mod_gzip_printf( "%s: ++++++++++ r->filename=[%s]\n",cn,r->filename); + mod_gzip_printf( "%s: ++++++++++ r->uri =[%s]\n",cn,r->uri); + #endif + + /* If a handler was found we are DONE... */ + + if ( t ) + { + #ifdef MOD_GZIP_DEBUG1 + mod_gzip_printf( "%s: Handler was found...\n",cn); + mod_gzip_printf( "%s: Exit > return( OK ) >\n",cn); + #endif + + return OK; + } + + #ifdef MOD_GZIP_FUTURE_USE + + #ifdef MOD_GZIP_DEBUG1 + mod_gzip_printf( "%s: ++++++++++ METHODS\n",cn); + mod_gzip_printf( "%s: ++++++++++ modp->translate_handler = %ld\n",cn,(long)modp->translate_handler); + mod_gzip_printf( "%s: ++++++++++ modp->ap_check_user_id = %ld\n",cn,(long)modp->ap_check_user_id); + mod_gzip_printf( "%s: ++++++++++ modp->auth_checker = %ld\n",cn,(long)modp->auth_checker); + mod_gzip_printf( "%s: ++++++++++ modp->access_checker = %ld\n",cn,(long)modp->access_checker); + mod_gzip_printf( "%s: ++++++++++ modp->type_checker = %ld\n",cn,(long)modp->type_checker); + mod_gzip_printf( "%s: ++++++++++ modp->fixer_upper = %ld\n",cn,(long)modp->fixer_upper); + mod_gzip_printf( "%s: ++++++++++ modp->logger = %ld\n",cn,(long)modp->logger); + mod_gzip_printf( "%s: ++++++++++ modp->header_parser = %ld\n",cn,(long)modp->header_parser); + mod_gzip_printf( "%s: .......... CONTENT HANDLERS\n",cn); + #endif /* MOD_GZIP_DEBUG1 */ + + if ( !modp->handlers ) + { + #ifdef MOD_GZIP_DEBUG1 + mod_gzip_printf( "%s: .......... NO CONTENT HANDLERS!\n",cn); + #endif + } + else /* There are some handlers... */ + { + for ( handp = modp->handlers; handp->content_type; ++handp ) + { + #ifdef MOD_GZIP_DEBUG1 + mod_gzip_printf( "%s: .......... handp->content_type = [%s]\n", + cn,handp->content_type); + mod_gzip_printf( "%s: .......... handp->handler = %ld\n",cn,(long)handp->handler); + #endif + + }/* End 'handp' loop */ + + }/* End 'else' */ + + #endif /* MOD_GZIP_FUTURE_USE */ + + #ifdef MOD_GZIP_DEBUG1 + mod_gzip_printf( "%s: No handler was found...\n",cn); + mod_gzip_printf( "%s: Exit > return( DECLINED ) >\n",cn); + #endif + + return DECLINED; + + }/* 'if ( mod_gzip_strnicmp( (char *) modp->name, "mod_actions.c", 13 ) == 0 )' */ + + count++; + + }/* End 'modp' loop... */ + + #ifdef MOD_GZIP_DEBUG1 + mod_gzip_printf( "%s: No handler found...\n",cn); + mod_gzip_printf( "%s: Exit > return( DECLINED ) > ERROR >\n",cn); + #endif + + return DECLINED; + +}/* End of mod_gzip_run_mod_action() */ + + +int mod_gzip_run_mod_alias( request_rec *r ) +{ + /* + * This calls 'translate_alias_redir()' routine in mod_alias.c + * which will search/replace keywords in the URI with the correct + * 'ScriptAlias' value(s) from the httpd.conf configuration file. + * + * 'translate_alias_redir()' is the name of routine registered + * by mod_alias.c module as the 'translate' hook. + */ + + module *modp; + int count=0; + int rc; + + #ifdef MOD_GZIP_DEBUG1 + char cn[]="mod_gzip_run_mod_alias()"; + #endif + + const handler_rec *handp; + + /* Currently 9 possible 'event' handlers. */ + /* Actual content handler in a module is 'extra'. */ + #define MOD_GZIP_NMETHODS 9 + + char *save_filename = 0; + char *save_uri = 0; + + char nothing[256]; + + /* + * Start... + */ + + #ifdef MOD_GZIP_DEBUG1 + mod_gzip_printf( "%s: Entry...\n",cn); + mod_gzip_printf( "%s: *IN: r->uri =[%s]\n", cn, r->uri ); + mod_gzip_printf( "%s: *IN: r->unparsed_uri=[%s]\n", cn, r->unparsed_uri ); + mod_gzip_printf( "%s: *IN: r->filename =[%s]\n", cn, r->filename ); + #endif + + for ( modp = top_module; modp; modp = modp->next ) + { + /* modp->name list will look like this... */ + /*--------------------*/ + /* 00 [mod_gzip.c] */ + /* 01 [mod_isapi.c] */ + /* 02 [mod_setenv.c] */ + /* 02 [mod_actions.c] */ + /* ............... */ + /* ............... */ + /* 18 [mod_so.c] */ + /* 19 [http_core.c] <- Always bottom of list (last one called) */ + /*--------------------*/ + + #ifdef MOD_GZIP_DEBUG1 + mod_gzip_printf( "%s: count=%4.4d modp = %10.10ld modp->name=[%s]\n", + cn,count,(long)modp, modp->name ); + #endif + + /* + There are only 3 modules that normally have + 'translate' handlers registered... + + mod_alias + mod_userdir + http_core + */ + + if ( ( mod_gzip_strnicmp( (char *) modp->name, "mod_alias.c", 11 ) == 0 ) || + ( mod_gzip_strnicmp( (char *) modp->name, "mod_userdir.c", 13 ) == 0 ) || + ( mod_gzip_strnicmp( (char *) modp->name, "http_core.c", 11 ) == 0 ) ) + { + + /* Module information... */ + + #ifdef MOD_GZIP_DEBUG1 + + mod_gzip_printf( "%s: ++++++++++ MODULE FOUND!...\n",cn); + mod_gzip_printf( "%s: ++++++++++ modp->module_index = %d\n",cn,(int)modp->module_index); + + mod_gzip_printf( "%s: ++++++++++ METHODS\n",cn); + mod_gzip_printf( "%s: ++++++++++ modp->translate_handler = %ld\n",cn,(long)modp->translate_handler); + mod_gzip_printf( "%s: ++++++++++ modp->ap_check_user_id = %ld\n",cn,(long)modp->ap_check_user_id); + mod_gzip_printf( "%s: ++++++++++ modp->auth_checker = %ld\n",cn,(long)modp->auth_checker); + mod_gzip_printf( "%s: ++++++++++ modp->access_checker = %ld\n",cn,(long)modp->access_checker); + mod_gzip_printf( "%s: ++++++++++ modp->type_checker = %ld\n",cn,(long)modp->type_checker); + mod_gzip_printf( "%s: ++++++++++ modp->fixer_upper = %ld\n",cn,(long)modp->fixer_upper); + mod_gzip_printf( "%s: ++++++++++ modp->logger = %ld\n",cn,(long)modp->logger); + mod_gzip_printf( "%s: ++++++++++ modp->header_parser = %ld\n",cn,(long)modp->header_parser); + mod_gzip_printf( "%s: .......... CONTENT HANDLERS\n",cn); + + #endif /* MOD_GZIP_DEBUG1 */ + + if ( !modp->handlers ) + { + #ifdef MOD_GZIP_DEBUG1 + mod_gzip_printf( "%s: .......... NO CONTENT HANDLERS!\n",cn); + #endif + } + else /* There are some handlers... */ + { + for ( handp = modp->handlers; handp->content_type; ++handp ) + { + #ifdef MOD_GZIP_DEBUG1 + mod_gzip_printf( "%s: .......... handp->content_type = [%s]\n", + cn,handp->content_type); + mod_gzip_printf( "%s: .......... handp->handler = %ld\n",cn,(long)handp->handler); + #endif + + }/* End 'handp' loop */ + + }/* End 'else' */ + + if ( modp->translate_handler ) + { + #ifdef MOD_GZIP_DEBUG1 + mod_gzip_printf( "%s: modp->translate_handler is VALID...\n",cn); + #endif + + /* + There are only 3 modules that normally have + 'translate' handlers registered... + + mod_alias <- Will translate /php3/xxx to c:/php3017/xx + mod_userdir + http_core + */ + + /* + * This calls 'translate_alias_redir()' routine in mod_alias.c + * which will search/replace keywords in the URI with the correct + * 'ScriptAlias' value(s) from the httpd.conf configuration file. + * + * 'translate_alias_redir()' is the name of routine registered + * by mod_alias.c module as the 'translate' hook. + * + * The 'translate_alias_redir()' function in mod_alias.c + * is really simple. All it does is check to make sure + * that r->uri has some value and, if it does, it calls + * another routine in mod_alias.c named 'try_alias_list()' + * which replaces any 'ScriptAlias' phrases with their + * real values and copies the result to r->filename. + * + * We must make sure the phrase we want translated is + * in r->uri and check for results in r->filename. + */ + + /* + * Calling mod_alias.c translate handler will correctly + * translate 'ScriptAlias' phrases such as... + * + * URI value... + * /php3/php3.exe + * becomes... + * c:/php3017/php3.exe + */ + + save_filename = r->filename; + save_uri = r->uri; + nothing[0] = 0; + + r->filename = nothing; + r->uri = save_filename; /* Phrase to translate */ + + #ifdef MOD_GZIP_DEBUG1 + mod_gzip_printf( "%s: r->filename = [%s]\n",cn,r->filename); + mod_gzip_printf( "%s: r->uri = [%s]\n",cn,r->uri); + mod_gzip_printf( "%s: Call (modp->translate_handler)(r)...\n",cn); + #endif + + /* Call the actual translate routine in mod_action module... */ + + rc = (modp->translate_handler)( (request_rec *) r ); + + #ifdef MOD_GZIP_DEBUG1 + mod_gzip_printf( "%s: Back (modp->translate_handler)(r)...\n",cn); + mod_gzip_printf( "%s: r->filename = [%s]\n",cn,r->filename); + mod_gzip_printf( "%s: r->uri = [%s]\n",cn,r->uri); + #endif + + /* + * If there was a successful translation then the return + * code will be OK and the translated URI will be sitting + * in r->filename. If there were no phrase replacements + * then the return code will be DECLINED. + */ + + #ifdef MOD_GZIP_DEBUG1 + + if ( rc == OK ) + { + mod_gzip_printf( "%s: rc = %d = OK\n",cn, rc ); + } + else if ( rc == DECLINED ) + { + mod_gzip_printf( "%s: rc = %d = DECLINED\n",cn, rc ); + } + else if ( rc == DONE ) /* -2 means 'totally done' */ + { + mod_gzip_printf( "%s: rc = %d = DONE\n",cn, rc ); + } + else /* Probably an HTTP ERROR value... */ + { + mod_gzip_printf( "%s: rc = %d = HTTP_ERROR?\n",cn, rc ); + } + + #endif /* MOD_GZIP_DEBUG */ + + /* + * Evaluate the results... + */ + + if ( rc == OK ) /* There was a phrase translation... */ + { + #ifdef MOD_GZIP_DEBUG1 + mod_gzip_printf( "%s: There was a phrase translation...\n",cn ); + mod_gzip_printf( "%s: Keeping new 'r->filename'\n",cn ); + #endif + + /* Do NOT restore 'r->filename' to original value... */ + /* Just fall-through and continue... */ + } + else /* No phrases were replaced... */ + { + #ifdef MOD_GZIP_DEBUG1 + mod_gzip_printf( "%s: There were NO phrases translated...\n",cn ); + mod_gzip_printf( "%s: Restoring 'r->filename' to original value...\n",cn ); + #endif + + /* Restore 'r->filename' to original value... */ + + r->filename = save_filename; + } + + /* Always 'restore' URI to original value... */ + + r->uri = save_uri; + + /* Turn and burn... */ + + #ifdef MOD_GZIP_DEBUG1 + mod_gzip_printf( "%s: Exit > return( rc=%d ) >\n",cn,rc); + #endif + + return rc; + } + else /* modp->translate_handler is NULL... */ + { + #ifdef MOD_GZIP_DEBUG1 + mod_gzip_printf( "%s: modp->translate_handler is NOT VALID.\n",cn); + #endif + } + + }/* 'if ( mod_gzip_strnicmp( (char *) modp->name, "mod_actions.c", 13 ) == 0 )' */ + + count++; + + }/* End 'modp' loop... */ + + #ifdef MOD_GZIP_DEBUG1 + mod_gzip_printf( "%s: No handler found...\n",cn); + mod_gzip_printf( "%s: Exit > return( DECLINED ) > ERROR >\n",cn); + #endif + + return DECLINED; + +}/* End of mod_gzip_run_mod_alias() */ + + +static int mod_gzip_handler( request_rec *r ) +{ + /* + * The primary module request handler... + */ + + int rc=0; + char cn[]="mod_gzip_handler()"; + int access_status=0; + int access_status2=0; + + /* + * Start... + */ + + if ( r->server->loglevel == APLOG_DEBUG ) + { + /* + * If the user has 'LogLevel debug' set in httpd.conf then + * it's ok to go ahead and strike some diagnostic information + * to the Apache log(s). + * + * APLOG_MARK is what supplies __FILE__ and __LINE__ info and + * it is actually defined in HTTP_LOG.H as... + * + * define APLOG_MARK __FILE__,__LINE__ + * + * Sometimes the original __FILE__ name is very long and is + * fairly useless information cluttering up the logs when + * there is only 1 possible source file name so + * to NOT use it just supply 2 dummy parameters instead. + * + * The first parameter can be a custom message instead of + * the __FILE__ string that would normally be substituted. + */ + + ap_log_error( "",0,APLOG_NOERRNO|APLOG_DEBUG, r->server, + "%s: Entry point...",cn); + + ap_log_error( "",0,APLOG_NOERRNO|APLOG_DEBUG, r->server, + "%s: r->the_request = [%s]",cn,r->the_request); + + ap_log_error( "",0,APLOG_NOERRNO|APLOG_DEBUG, r->server, + "%s: r->protocol = [%s]",cn,r->protocol); + + ap_log_error( "",0,APLOG_NOERRNO|APLOG_DEBUG, r->server, + "%s: r->proto_num = %d",cn,(int)r->proto_num); + + ap_log_error( "",0,APLOG_NOERRNO|APLOG_DEBUG, r->server, + "%s: r->filename = [%s]",cn,r->filename); + + ap_log_error( "",0,APLOG_NOERRNO|APLOG_DEBUG, r->server, + "%s: r->uri = [%s]",cn,r->uri); + + ap_log_error( "",0,APLOG_NOERRNO|APLOG_DEBUG, r->server, + "%s: r->content_type = [%s]",cn,r->content_type); + + ap_log_error( "",0,APLOG_NOERRNO|APLOG_DEBUG, r->server, + "%s: r->handler = [%s]",cn,r->handler); + + }/* End 'if( r->server->loglevel == APLOG_DEBUG )' */ + + #ifdef MOD_GZIP_DEBUG1 + mod_gzip_printf( "\n" ); + mod_gzip_printf( "%s: ```` Entry...\n",cn); + mod_gzip_printf( "%s: -------------------------------------------------------------\n",cn); + mod_gzip_printf( "%s: *IN: r->uri =[%s]\n", cn, r->uri ); + mod_gzip_printf( "%s: *IN: r->unparsed_uri =[%s]\n", cn, r->unparsed_uri ); + mod_gzip_printf( "%s: *IN: r->filename =[%s]\n", cn, r->filename ); + mod_gzip_printf( "%s: *IN: r->path_info =[%s]\n", cn, r->path_info ); + mod_gzip_printf( "%s: *IN: r->args =[%s]\n", cn, r->args ); + mod_gzip_printf( "%s: *IN: r->header_only =[%s]\n", cn, r->header_only ); + mod_gzip_printf( "%s: *IN: r->protocol =[%s]\n", cn, r->protocol ); + mod_gzip_printf( "%s: *IN: r->proto_num =%d\n", cn, r->proto_num ); + mod_gzip_printf( "%s: *IN: r->hostname =[%s]\n", cn, r->hostname ); + mod_gzip_printf( "%s: *IN: r->the_request =[%s]\n", cn, r->the_request ); + mod_gzip_printf( "%s: *IN: r->assbackwards =%d\n", cn, r->assbackwards ); + mod_gzip_printf( "%s: *IN: r->status_line =[%s]\n", cn, r->status_line ); + mod_gzip_printf( "%s: *IN: r->status =%d\n", cn, r->status ); + mod_gzip_printf( "%s: *IN: r->method =[%s]\n", cn, r->method ); + mod_gzip_printf( "%s: *IN: r->method_number =%d\n", cn, r->method_number ); + mod_gzip_printf( "%s: *IN: r->content_type =[%s]\n", cn, r->content_type ); + mod_gzip_printf( "%s: *IN: r->handler =[%s]\n", cn, r->handler ); + mod_gzip_printf( "%s: *IN: r->content_encoding =[%s]\n", cn, r->content_encoding ); + mod_gzip_printf( "%s: *IN: r->content_language =[%s]\n", cn, r->content_language ); + mod_gzip_printf( "%s: -------------------------------------------------------------\n",cn); + mod_gzip_printf( "%s: *IN: r->parsed_uri.scheme =[%s]\n", cn, r->parsed_uri.scheme ); + mod_gzip_printf( "%s: *IN: r->parsed_uri.hostinfo =[%s]\n", cn, r->parsed_uri.hostinfo ); + mod_gzip_printf( "%s: *IN: r->parsed_uri.user =[%s]\n", cn, r->parsed_uri.user ); + mod_gzip_printf( "%s: *IN: r->parsed_uri.password =[%s]\n", cn, r->parsed_uri.password ); + mod_gzip_printf( "%s: *IN: r->parsed_uri.hostname =[%s]\n", cn, r->parsed_uri.hostname ); + mod_gzip_printf( "%s: *IN: r->parsed_uri.port_str =[%s]\n", cn, r->parsed_uri.port_str ); + mod_gzip_printf( "%s: *IN: r->parsed_uri.port =%u\n", cn, r->parsed_uri.port ); + mod_gzip_printf( "%s: *IN: r->parsed_uri.path =[%s]\n", cn, r->parsed_uri.path ); + mod_gzip_printf( "%s: *IN: r->parsed_uri.query =[%s]\n", cn, r->parsed_uri.query ); + mod_gzip_printf( "%s: *IN: r->parsed_uri.fragment =[%s]\n", cn, r->parsed_uri.fragment ); + mod_gzip_printf( "%s: -------------------------------------------------------------\n",cn); + + #endif /* MOD_GZIP_DEBUG1 */ + + /* + * Call the real transaction handler.... + */ + + #ifdef MOD_GZIP_DEBUG1 + mod_gzip_printf( "%s: Call mod_gzip_request_handler()...\n", cn ); + #endif + + rc = mod_gzip_request_handler( (request_rec *) r ); + + #ifdef MOD_GZIP_DEBUG1 + mod_gzip_printf( "%s: Back mod_gzip_request_handler()... rc=%d\n",cn,rc); + #endif + + if ( r->server->loglevel == APLOG_DEBUG ) + { + /* + * If LogLevel is 'debug' then show the final return code + * value in the log(s)... + */ + + if ( rc == OK ) + { + ap_log_error( "",0,APLOG_NOERRNO|APLOG_DEBUG, r->server, + "%s: Exit: return( rc = %d = OK )", cn, rc ); + } + else if ( rc == DECLINED ) + { + ap_log_error( "",0,APLOG_NOERRNO|APLOG_DEBUG, r->server, + "%s: Exit: return( rc = %d = DECLINED )", cn, rc ); + } + else /* It's probably an HTTP error code... */ + { + ap_log_error( "",0,APLOG_NOERRNO|APLOG_DEBUG, r->server, + "%s: Exit: return( rc = %d = HTTP ERROR CODE? )", cn, rc ); + } + + }/* End 'if( r->server->loglevel == APLOG_DEBUG )' */ + + #ifdef MOD_GZIP_DEBUG1 + + if ( rc == OK ) + { + mod_gzip_printf( "%s: rc = %d OK\n", cn, (int) rc); + } + else if ( rc == DECLINED ) + { + mod_gzip_printf( "%s: rc = %d DECLINED\n", cn, (int) rc ); + } + else /* It's probably an HTTP error code... */ + { + mod_gzip_printf( "%s: rc = %d ( HTTP ERROR CODE? )\n", cn, (int) rc ); + } + + mod_gzip_printf( "%s: Exit > return( rc = %d ) >\n",cn,rc ); + + #endif /* MOD_GZIP_DEBUG1 */ + + return rc; + +}/* End of mod_gzip_handler() */ + +typedef struct { + table *action_types; /* Added with Action... */ + char *scripted[METHODS]; /* Added with Script... */ + array_header *xmethods; /* Added with Script -- extension methods */ +} action_dir_config2; + +extern module action_module; + +int mod_gzip_request_handler( request_rec *r ) +{ + /* + * Process a new request... + */ + + int rc = 0; + int loglevel = 0; + int do_command = 0; + int process = 0; + int action_flag = 0; + long compression_ratio = 0; + + const char* has_encoding = 0; + const char* accept_encoding = 0; + + #ifdef MOD_GZIP_ALLOWS_INTERNAL_COMMANDS + char tmp[4096]; /* Scratch buffer for HTML output */ + #endif + + #ifdef MOD_GZIP_DEBUG1 + char cn[]="mod_gzip_request_handler()"; + const char* the_type = 0; + #endif + + #ifdef MOD_GZIP_USES_APACHE_LOGS + char log_info[40]; /* Scratch buffer */ + #endif + + void *modconf = r->server->module_config; + + mod_gzip_conf *conf = 0; /* Pointer to our own config data */ + + /* + * Start... + * + * Establish a local pointer to module configuration data... + */ + + conf = (mod_gzip_conf *) + ap_get_module_config(modconf, &gzip_module); + + /* + * Get the current Apache log level... + */ + + loglevel = r->server->loglevel; + + #ifdef MOD_GZIP_USES_APACHE_LOGS + + /* + * If the MOD_GZIP_USES_APACHE_LOGS compile-time switch is ON + * then the Apache log module interface code is being included. + * + * Reset the module 'notes' that are used by mod_gzip to + * add entries to Apache standard log files... + * + * See the note farther below about how to add mod_gzip + * compression information to any standard Apache log file. + */ + + /* Default for 'mod_result' message is 'DECLINED:NOP'... */ + + ap_table_setn( r->notes,"mod_gzip_result",ap_pstrdup(r->pool,"DECLINED:NOP")); + + /* Default for in/out size is 'n/a'... 'Not available'...*/ + + sprintf( log_info, "n/a" ); + + ap_table_setn( r->notes,"mod_gzip_input_size",ap_pstrdup(r->pool,log_info)); + ap_table_setn( r->notes,"mod_gzip_output_size",ap_pstrdup(r->pool,log_info)); + + /* Default for compression ratio is '0' percent... */ + + ap_table_setn( r->notes,"mod_gzip_compression_ratio",ap_pstrdup(r->pool,"0")); + + #endif /* MOD_GZIP_USES_APACHE_LOGS */ + + #ifdef MOD_GZIP_DEBUG1 + + /* Request info... */ + + mod_gzip_printf( "%s: Entry...\n",cn); + mod_gzip_printf( "%s: mod_gzip_version =[%s]\n", cn, mod_gzip_version); + mod_gzip_printf( "%s: conf->req = %d\n", cn, (int) conf->req); + mod_gzip_printf( "%s: conf->cache.root =[%s]\n", cn, conf->cache.root); + mod_gzip_printf( "%s: *IN: r->uri =[%s]\n", cn, r->uri); + mod_gzip_printf( "%s: *IN: r->unparsed_uri=[%s]\n", cn, r->unparsed_uri); + mod_gzip_printf( "%s: *IN: r->filename =[%s]\n", cn, r->filename); + mod_gzip_printf( "%s: *IN: r->handler =[%s]\n", cn, r->handler); + mod_gzip_printf( "%s: r->finfo.st_size = %ld\n", cn, (long) r->finfo.st_size); + + /* NOTE: The r->headers_out content type value has not normally */ + /* been set at this point but grab a pointer to it and show */ + /* it just to make sure. The r->content_type value, however, */ + /* normally WILL have some value at this point. */ + + the_type = ap_table_get( r->headers_out,"Content-type" ); + + mod_gzip_printf( "%s: r->headers_out, Content-type = [%s]\n",cn,the_type); + mod_gzip_printf( "%s: r->content_type = [%s]\n",cn,r->content_type ); + + /* The r->handler ASCII name string is the all-important */ + /* jump table name for the module that will handle the */ + /* transaction. If this is a CGI jump then it will normally */ + /* have a value of 'cgi-script' at this point. */ + + mod_gzip_printf( "%s: r->handler = [%s]\n",cn,r->handler ); + + /* Server info... */ + + mod_gzip_printf( "%s: r->server->path = [%s]\n",cn,r->server->path ); + mod_gzip_printf( "%s: r->server->pathlen = %d\n", cn,r->server->pathlen); + mod_gzip_printf( "%s: r->server->server_admin = [%s]\n",cn,r->server->server_admin); + mod_gzip_printf( "%s: r->server->server_hostname = [%s]\n",cn,r->server->server_hostname); + mod_gzip_printf( "%s: r->server->error_fname = [%s]\n",cn,r->server->error_fname); + + /* Environment info... */ + + mod_gzip_printf( "%s: DOCUMENT_ROOT = [%s]\n",cn,ap_document_root(r)); + + #endif /* MOD_GZIP_DEBUG1 */ + + /* + * Check the 'master' request control switch and see if mod_gzip + * is ON (ENABLED) or OFF (DISABLED)... + */ + + if ( conf->req != 1 ) + { + /* mod_gzip is currently DISABLED so DECLINE the processing... */ + + #ifdef MOD_GZIP_DEBUG1 + mod_gzip_printf( "%s: conf->req = %d = OFF\n",cn,conf->req); + mod_gzip_printf( "%s: The module is currently DISABLED\n",cn); + mod_gzip_printf( "%s: Exit > return( DECLINED ) >\n",cn); + #endif + + #ifdef MOD_GZIP_USES_APACHE_LOGS + + /* Each 'DECLINE' condition provides a short ':WHYTAG' for logs */ + + ap_table_setn( + r->notes,"mod_gzip_result",ap_pstrdup(r->pool,"DECLINED:DISABLED")); + + #endif /* MOD_GZIP_USES_APACHE_LOGS */ + + return DECLINED; + + }/* End 'if( conf->req != 1 )' */ + + /* + * Check for a default HTTP support level ( if used ). + * If no value for conf->min_http was supplied in the + * httpd.conf file then the default value will be 0 + * so that ALL levels of HTTP will be OK... + */ + + #ifdef MOD_GZIP_DEBUG1 + mod_gzip_printf( "%s: *HTTP CHECK:conf->min_http = %d\n", cn, conf->min_http ); + mod_gzip_printf( "%s: *HTTP CHECK:r->proto_num = %d\n", cn, r->proto_num ); + mod_gzip_printf( "%s: *HTTP CHECK:r->protocol = [%s]\n", cn, r->protocol ); + #endif + + if ( r->proto_num < conf->min_http ) + { + /* The HTTPx/x version number does not meet the minimum requirement */ + + #ifdef MOD_GZIP_DEBUG1 + mod_gzip_printf( "%s: Request HTTP level does not meet minimum requirement\n",cn); + mod_gzip_printf( "%s: Exit > return( DECLINED ) >\n",cn); + #endif + + #ifdef MOD_GZIP_USES_APACHE_LOGS + + /* Each 'DECLINE' condition provides a short ':WHYTAG' for logs */ + + sprintf( log_info, "DECLINED:%s:%d", r->protocol, r->proto_num ); + + ap_table_setn( + r->notes,"mod_gzip_result",ap_pstrdup(r->pool,log_info)); + + #endif /* MOD_GZIP_USES_APACHE_LOGS */ + + return DECLINED; + + }/* End 'if ( r->proto_num < conf->min_http )' */ + + else /* Protocol level is OK... */ + { + #ifdef MOD_GZIP_DEBUG1 + mod_gzip_printf( "%s: Request HTTP level is OK...\n",cn); + #endif + } + + #ifdef MOD_GZIP_ALLOWS_INTERNAL_COMMANDS + + /* + * Internal command pickups... + * + * If this module was compiled with the + * MOD_GZIP_ALLOWS_INTERNAL_COMMANDS switch ON + * then the first thing we do is check for valid + * URL-based internal commands. + * + * Rather than check for all possible commands each time + * just do 1 quick check for the command prefix and set + * a flag to indicate if there is any need to enter the + * actual command handler... + */ + + if ( strstr( r->filename, "mod_gzip_command_" ) ) + { + do_command = 1; /* Process the command */ + } + + #ifdef MOD_GZIP_DEBUG1 + mod_gzip_printf( "%s: do_command = %d\n",cn,do_command); + #endif + + if ( do_command ) + { + /* Determine the exact command and respond... */ + + if ( strstr( r->filename, "mod_gzip_command_version" ) ) + { + /*------------------------------------------------------*/ + /* Command: 'mod_gzip_command_version' */ + /* Purpose: Return the current mod_gzip version number. */ + /* Comment: Allows anyone to query any Apache Server at */ + /* any URL with a browser and discover if */ + /* mod_gzip is in use at that site. */ + /*------------------------------------------------------*/ + + #ifdef MOD_GZIP_DEBUG1 + mod_gzip_printf( "%s: 'mod_gzip_command_version' seen...\n",cn); + #endif + + /* NOTE: mod_gzip command results are not sent compressed */ + + /* Build the response buffer... */ + + sprintf( tmp, + "
"
+          "mod_gzip is available on this Server\r\n"
+          "mod_gzip version = %s\r\n"
+          "
", + mod_gzip_version + ); + + /* For all mod_gzip commands that are intercepted we */ + /* simply return OK. */ + + return( mod_gzip_send_html_command_response( r, tmp, "text/html" )); + } + else if ( strstr( r->filename, "mod_gzip_command_showstats" ) ) + { + /*------------------------------------------------------*/ + /* Command: 'mod_gzip_command_showstats' */ + /* Purpose: Display compression statistics. */ + /* Comment: Allows anyone to query any Apache Server at */ + /* any URL with a browser and get a report */ + /* about compression results. */ + /*------------------------------------------------------*/ + + #ifdef MOD_GZIP_DEBUG1 + mod_gzip_printf( "%s: 'mod_gzip_command_showstats' seen...\n",cn); + #endif + + /* NOTE: mod_gzip command results are not sent compressed */ + + /* Build the response buffer... */ + + /* NOTE: This command has been temporarily removed */ + + sprintf( tmp, + "
"
+          "mod_gzip is available on this Server\r\n"
+          "mod_gzip version = %s\r\n\r\n"
+          "The 'mod_gzip_command_showstats' command has been temporarily removed.\r\n"
+          "
", + mod_gzip_version + ); + + /* For all mod_gzip commands that are intercepted we */ + /* simply return OK. */ + + return( mod_gzip_send_html_command_response( r, tmp, "text/html" )); + } + else if ( strstr( r->filename, "mod_gzip_command_resetstats" ) ) + { + /*------------------------------------------------------*/ + /* Command: 'mod_gzip_command_resetstats' */ + /* Purpose: Resets the compression statistics. */ + /* Comment: Allows the compression statistics to be */ + /* reset using only a browser. */ + /*------------------------------------------------------*/ + + #ifdef MOD_GZIP_DEBUG1 + mod_gzip_printf( "%s: 'mod_gzip_command_resetstats' seen...\n",cn); + #endif + + /* NOTE: mod_gzip command results are not sent compressed */ + + /* Build the response buffer... */ + + /* NOTE: This command has been temporarily removed */ + + sprintf( tmp, + "
"
+          "mod_gzip is available on this Server\r\n"
+          "mod_gzip version = %s\r\n\r\n"
+          "The 'mod_gzip_command_resetstats' command has been temporarily removed.\r\n"
+          "
", + mod_gzip_version + ); + + /* For all mod_gzip commands that are intercepted we */ + /* simply return OK. */ + + return( mod_gzip_send_html_command_response( r, tmp, "text/html" )); + } + else /* Unrecognized command... */ + { + /* The command prefix was 'seen' and the 'do_command' flag */ + /* was TRUE but either the command was mis-typed or there */ + /* is no such command available. This is not an ERROR and */ + /* we should simply fall-through and assume that the URL */ + /* is valid for the local Server. A 404 will be returned */ + /* if there is no object that actually matches the name. */ + } + + }/* End 'if( do_command )' */ + + #endif /* MOD_GZIP_ALLOWS_INTERNAL_COMMANDS */ + + /* + * Sanity checks... + */ + + /* + * If the requested file already contains the .gz designation + * then we must assume it is pre-compressed and let the + * default logic take care of sending the file. This module + * doesn't really care if a .gz file was actually requested + * or if it is the source target because of a successful + * Server side 'negotiation'. Doesn't matter. + */ + + if ( ( r->filename ) && ( strstr( r->filename, ".gz" ) ) ) + { + #ifdef MOD_GZIP_DEBUG1 + mod_gzip_printf( "%s: r->filename already contains '.gz'.\n",cn); + mod_gzip_printf( "%s: Pre-compression is assumed.\n",cn); + mod_gzip_printf( "%s: Exit > return( DECLINED ) >\n",cn); + #endif + + #ifdef MOD_GZIP_USES_APACHE_LOGS + + /* Each 'DECLINE' condition provides a short ':WHYTAG' for logs */ + + ap_table_setn( + r->notes,"mod_gzip_result",ap_pstrdup(r->pool,"DECLINED:HAS.GZ")); + + if ( r->server->loglevel == APLOG_DEBUG ) + { + ap_log_error( "",0,APLOG_NOERRNO|APLOG_DEBUG, r->server, + "mod_gzip: Files with .gz file extension are skipped."); + } + + #endif /* MOD_GZIP_USES_APACHE_LOGS */ + + return DECLINED; + } + else /* r->filename doesn not contain '.gz' designator... */ + { + #ifdef MOD_GZIP_DEBUG1 + mod_gzip_printf( "%s: r->filename does NOT contain '.gz'.\n",cn); + mod_gzip_printf( "%s: Assuming OK to proceed...\n",cn); + #endif + } + + /* + * For now just block all attempts to compress 'image/*' MIME + * type even if user is trying to do so. Too many issues with + * broken browsers when it comes to decoding compressed images. + * + * WARNING: Don't submit r->content_type to strstr() it if is + * NULL or the API call will GP fault. Go figure. + */ + + if ( ( r->content_type ) && ( strstr( r->content_type, "image/" ) ) ) + { + #ifdef MOD_GZIP_DEBUG1 + mod_gzip_printf( "%s: r->content_type contains 'image/'.\n",cn); + mod_gzip_printf( "%s: Image compression is temporaily BLOCKED\n",cn); + mod_gzip_printf( "%s: Exit > return( DECLINED ) >\n",cn); + #endif + + #ifdef MOD_GZIP_USES_APACHE_LOGS + + /* Each 'DECLINE' condition provides a short ':WHYTAG' for logs */ + + ap_table_setn( + r->notes,"mod_gzip_result",ap_pstrdup(r->pool,"DECLINED:IMAGE")); + + if ( r->server->loglevel == APLOG_DEBUG ) + { + ap_log_error( "",0,APLOG_NOERRNO|APLOG_DEBUG, r->server, + "mod_gzip: Graphics image compression option is temporarily disabled."); + } + + #endif /* MOD_GZIP_USES_APACHE_LOGS */ + + return DECLINED; + } + + /* + * Safeguard against situations where some other module or + * filter has gotten to this request BEFORE us and has already + * added the 'Content-encoding: gzip' field to the output header. + * It must be assumed that whoever added the header prior to this + * point also took care of the compression itself. + * + * If the output header already contains "Content-encoding: gzip" + * then simply DECLINE the processing and let the default chain + * take care of it... + */ + + has_encoding = ap_table_get( r->headers_out, "Content-encoding" ); + + #ifdef MOD_GZIP_DEBUG1 + mod_gzip_printf( "%s: has_encoding = [%s]\n",cn,has_encoding); + #endif + + if ( has_encoding ) /* 'Content-encoding' field is present... */ + { + #ifdef MOD_GZIP_DEBUG1 + mod_gzip_printf( "%s: Output header already contains 'Content-encoding:' field\n",cn); + mod_gzip_printf( "%s: Checking for 'gzip' designator...\n",cn); + #endif + + if ( strstr( has_encoding, "gzip" ) || + strstr( has_encoding, "deflate" ) ) + { + #ifdef MOD_GZIP_DEBUG1 + mod_gzip_printf( "%s: 'Content-encoding:' field contains 'gzip' or 'deflate' designator...\n",cn); + mod_gzip_printf( "%s: Pre-compression is assumed.\n",cn); + mod_gzip_printf( "%s: Exit > return( DECLINED ) >\n",cn); + #endif + + #ifdef MOD_GZIP_USES_APACHE_LOGS + + /* Each 'DECLINE' condition provides a short ':WHYTAG' for logs */ + + ap_table_setn( + r->notes,"mod_gzip_result",ap_pstrdup(r->pool,"DECLINED:HAS_CE:GZIP")); + + if ( r->server->loglevel == APLOG_DEBUG ) + { + ap_log_error( "",0,APLOG_NOERRNO|APLOG_DEBUG, r->server, + "mod_gzip: Header already has 'Content-encoding: gzip'"); + } + + #endif /* MOD_GZIP_USES_APACHE_LOGS */ + + return DECLINED; + } + else /* 'gzip' designator not found... */ + { + #ifdef MOD_GZIP_DEBUG1 + mod_gzip_printf( "%s: 'Content-encoding:' field does NOT contain 'gzip' or 'deflate' designator...\n",cn); + mod_gzip_printf( "%s: Assuming OK to proceed...\n",cn); + #endif + } + + }/* End 'if( has_encoding )' */ + + else /* Output header does NOT contain 'Content-encoding:' field... */ + { + #ifdef MOD_GZIP_DEBUG1 + mod_gzip_printf( "%s: Output header does NOT contain 'Content-encoding:' field.\n",cn); + mod_gzip_printf( "%s: Assuming OK to proceed...\n",cn); + #endif + } + + /* + * Basic sanity checks completed and we are still here. + * + * Now we must determine if the User-Agent is capable of receiving + * compressed data... + * + * There are, currently, many reasons why it is actually never + * enough to simply trust the 'Accept-encoding: foo, bar' + * request header field when it comes to actually determining + * if a User-agent is capable of receiving content or transfer + * encodings. + * + * Some of them are... + * + * 1. There have been several major releases of popular browsers + * that actually send the 'Accept-encoding:' request field but + * are, in reality, unable to perform the specified decoding(s). + * In some cases the result will be that the browser screen + * simply fills with garbage ( the binary compressed data + * itself ) but in some cases the browser will actually crash. + * + * 2. There have been other major releases of browsers that are + * specifying multiple 'Accept-encoding' techniques with no + * 'Q' values whatsoever and they are actually only able to + * handle one of the multiple types specified. There is no + * way to know which type is 'real' other than by using other + * empiricial data extracted from the 'User-agent' field + * or other inbound request headers. + * + * 3. Same as 1 and 2 but relates to SIZE. Some major browser + * releases can handle the encoded content but only up to + * a certain 'SIZE' limit and then they will fail. There + * is no way for a User-agent to specify this limitation + * via HTTP so empirical header analysis is the only option. + * + * 4. The HTTP specification has no way for a Server to distinguish + * from the 'Accept encoding: foo, bar' input request field + * whether the user agent can only support the specified encodings + * as either a Content-encoding OR a Transfer-encoding, but + * not both. There is also no way of knowing if the user + * agent is able to handle any of the specified types being + * used as both a Content-encoding AND a Transfer-encoding + * for the same message body. All the Server can do is assume + * that the encodings are valid in any/all combinations + * and that the user agent can 'Accept' them as either + * 'Content' encodings and/or 'Transfer' encodings under + * any and all circumstances. This blanket assumption will + * cause problems with some release versions of some browsers + * because the assumed 'do all' capability is simply not a + * reality. + * + * 5. Many browsers ( such as Netscape 4.75 for UNIX ) are unable + * to handle Content-encoding only for specific kinds of HTML + * transactions such as Style Sheets even though the browser + * says it is HTTP 1.1 compliant and is suppying the standard + * 'Accept-encoding: gzip' field. According to the IETF + * specifications any user-agent that says it can accept + * encodings should be able to do so for all types of HTML + * transactions but this is simply not the current reality. + * Some will, some won't... even if they say they can. + * + * This version of this module takes the 'What, me worry' approach + * and simply uses the accepted method of relying solely on the + * 'Accept-encoding: foo, bar' field and also assumes this means + * that the User-agent can accept the specified encodings as + * either Content-encodings (CE) and/or Transfer-encodings (TE) + * under all circumstances and in any combinations that the + * Server decides to send. + * + * It also assumes that the caller has no preference and should + * be able to decode any of the specified encodings equally well. + * Most user-agents sending the 'Accept-encoding:' field do NOT + * supply any 'Q' values to help with determining preferences. + */ + + accept_encoding = ap_table_get( r->headers_in, "Accept-Encoding" ); + + #ifdef MOD_GZIP_DEBUG1 + + if ( accept_encoding ) + { + mod_gzip_printf( "%s: 'Accept Encoding:' field seen.\n",cn); + } + else + { + mod_gzip_printf( "%s: 'Accept Encoding' field NOT seen.\n",cn); + } + + #endif /* MOD_GZIP_DEBUG1 */ + + /* If Accept-Encoding is applicable to this request...*/ + + if ( accept_encoding ) + { + /* ...and if it has the right 'gzip' indicator... */ + /* We record the compression format in a request note, so we + * can get it again later, and so it can potentially be logged. + */ + if ( strstr( accept_encoding, "gzip" ) ) + { + process = 1; /* ...set the 'process' flag TRUE */ + ap_table_setn( r->notes,"mod_gzip_compression_format", + ap_pstrdup(r->pool,"gzip")); + + } + else if ( strstr( accept_encoding, "deflate" ) ) + { + process = 1; /* ...set the 'process' flag TRUE */ + ap_table_setn( r->notes,"mod_gzip_compression_format", + ap_pstrdup(r->pool,"deflate")); + } + + }/* End 'if( accept_encoding )' */ + + #ifdef MOD_GZIP_DEBUG1 + mod_gzip_printf( "%s: 'process' flag = %d\n",cn,process); + #endif + + if ( !process ) /* Request does not meet criteria for processing... */ + { + #ifdef MOD_GZIP_DEBUG1 + mod_gzip_printf( "%s: No 'gzip' capability specified by user-agent.\n",cn); + mod_gzip_printf( "%s: 'process' flag is FALSE.\n",cn); + mod_gzip_printf( "%s: This request will not be processed.\n",cn); + mod_gzip_printf( "%s: Exit > return( DECLINED ) >\n",cn); + #endif + + #ifdef MOD_GZIP_USES_APACHE_LOGS + + /* Each 'DECLINE' condition provides a short ':WHYTAG' for logs */ + + ap_table_setn( + r->notes,"mod_gzip_result",ap_pstrdup(r->pool,"DECLINED:NO_GZIP")); + + if ( r->server->loglevel == APLOG_DEBUG ) + { + ap_log_error( "",0,APLOG_NOERRNO|APLOG_DEBUG, r->server, + "mod_gzip: The inbound request header does not have 'Accept-encoding: gzip'"); + } + + #endif /* MOD_GZIP_USES_APACHE_LOGS */ + + return DECLINED; + } + else /* 'gzip' designator was seen in 'Accept-Encoding:' field */ + { + #ifdef MOD_GZIP_DEBUG1 + mod_gzip_printf( "%s: 'gzip' or 'deflate' capability specified by user-agent.\n",cn); + mod_gzip_printf( "%s: Assuming OK to proceed...\n",cn); + #endif + } + + /* + * Handle the transaction... + * + * At this point the inbound header analysis has been completed + * and we are assuming that the user agent is capable of accepting + * the content encodings we can provide. + * + * We must now 'do the right thing' based on what type of + * request it actually is... + */ + + #ifdef MOD_GZIP_DEBUG1 + mod_gzip_printf( "%s: r->handler = [%s]\n",cn,r->handler); + mod_gzip_printf( "%s: r->content_type = [%s]\n",cn,r->content_type); + mod_gzip_printf( "%s: Call mod_gzip_get_action_flag()...\n",cn); + #endif + + action_flag = + mod_gzip_get_action_flag( + (request_rec *) r, + (mod_gzip_conf *) conf + ); + + #ifdef MOD_GZIP_DEBUG1 + mod_gzip_printf( "%s: Back mod_gzip_get_action_flag()...\n",cn); + mod_gzip_printf( "%s: action_flag = %d\n",cn,action_flag); + mod_gzip_printf( "%s: conf->do_static_files = %d\n",cn,(int)conf->do_static_files); + mod_gzip_printf( "%s: conf->do_cgi = %d\n",cn,(int)conf->do_cgi); + #endif + + /* + * Perform the right 'action' for this transaction... + */ + + if ( action_flag == MOD_GZIP_IMAP_DECLINED1 ) + { + /* + * If the transaction is to be DECLINED then just set the final + * return code to DECLINED, fall through, and return. + */ + + #ifdef MOD_GZIP_DEBUG1 + mod_gzip_printf( "%s: action_flag = MOD_GZIP_IMAP_DECLINED1\n",cn); + #endif + + if ( r->server->loglevel == APLOG_DEBUG ) + { + ap_log_error( "",0,APLOG_NOERRNO|APLOG_DEBUG, r->server, + "mod_gzip: action_flag = MOD_GZIP_IMAP_DECLINED1 "); + } + + rc = DECLINED; + } + else if ( action_flag == MOD_GZIP_IMAP_DYNAMIC1 ) + { + #ifdef MOD_GZIP_DEBUG1 + mod_gzip_printf( "%s: action_flag = MOD_GZIP_IMAP_DYNAMIC1\n",cn); + #endif + + if ( r->server->loglevel == APLOG_DEBUG ) + { + ap_log_error( "",0,APLOG_NOERRNO|APLOG_DEBUG, r->server, + "mod_gzip: action_flag = MOD_GZIP_IMAP_DYNAMIC1 "); + } + + /* + * Check the flag that can control whether or not the + * CGI dynamic output handler is ever called... + */ + + if ( conf->do_cgi != 1 ) /* CGI handler is OFF for now... */ + { + if ( r->server->loglevel == APLOG_DEBUG ) + { + ap_log_error( "",0,APLOG_NOERRNO|APLOG_DEBUG, r->server, + "mod_gzip: Calls to CGI handler currently DISABLED "); + } + + #ifdef MOD_GZIP_USES_APACHE_LOGS + /* Update the result string for Apache log(s)... */ + ap_table_setn( + r->notes,"mod_gzip_result",ap_pstrdup(r->pool,"DECLINED:CGI_OFF")); + #endif + + rc = DECLINED; /* Just set final return code and fall through */ + + }/* End 'if( conf->do_cgi == 0 )' */ + + else /* It's OK to call the handler... */ + { + if ( r->server->loglevel == APLOG_DEBUG ) + { + ap_log_error( "",0,APLOG_NOERRNO|APLOG_DEBUG, r->server, + "mod_gzip: Calling cgi_handler for r->uri=[%s]",r->uri); + } + + /* Take care of some business BEFORE calling the */ + /* dynamic handler... */ + + mod_gzip_prepare_for_dynamic_call( r ); + + /* PHP NOTE */ + /* r->path_info must be set before ap_add_cgi_vars() */ + /* is called from within the upcoming hander or we */ + /* won't get PATH_INFO or PATH_TRANSLATED environment */ + /* variables set and PHP.EXE will return 'No input file' */ + /* error message since it depends on both of these being */ + /* set. r->path_info must be set to r->uri */ + + #ifdef MOD_GZIP_DEBUG1 + mod_gzip_printf( "%s: 1 r->uri = [%s]\n", cn, r->uri ); + mod_gzip_printf( "%s: 1 r->path_info = [%s]\n", cn, r->path_info ); + mod_gzip_printf( "%s: Setting r->path_info to r->uri for CGI...\n", cn ); + #endif + + r->path_info = r->uri; + + #ifdef MOD_GZIP_DEBUG1 + mod_gzip_printf( "%s: 2 r->uri = [%s]\n", cn, r->uri ); + mod_gzip_printf( "%s: 2 r->path_info = [%s]\n", cn, r->path_info ); + #endif + + /* Call the actual handler... */ + + #ifdef MOD_GZIP_DEBUG1 + mod_gzip_printf( "%s: Call mod_gzip_cgi_handler()...\n",cn); + #endif + + rc = mod_gzip_cgi_handler( (request_rec *) r ); + + #ifdef MOD_GZIP_DEBUG1 + mod_gzip_printf( "%s: Back mod_gzip_cgi_handler()... rc=%d\n",cn,rc); + #endif + + }/* End 'else' - OK to call handler */ + } + else if ( action_flag == MOD_GZIP_IMAP_STATIC1 ) + { + #ifdef MOD_GZIP_DEBUG1 + mod_gzip_printf( "%s: action_flag = MOD_GZIP_IMAP_STATIC1\n",cn); + #endif + + if ( r->server->loglevel == APLOG_DEBUG ) + { + ap_log_error( "",0,APLOG_NOERRNO|APLOG_DEBUG, r->server, + "mod_gzip: action_flag = MOD_GZIP_IMAP_STATIC1 "); + } + + /* + * Check the flag that can control whether or not the + * static handler is ever called... + */ + + if ( conf->do_static_files != 1 ) /* Static handler is OFF for now... */ + { + if ( r->server->loglevel == APLOG_DEBUG ) + { + ap_log_error( "",0,APLOG_NOERRNO|APLOG_DEBUG, r->server, + "mod_gzip: Calls to static handler currently DISABLED "); + } + + #ifdef MOD_GZIP_USES_APACHE_LOGS + /* Update the result string for Apache log(s)... */ + ap_table_setn( + r->notes,"mod_gzip_result",ap_pstrdup(r->pool,"DECLINED:STATIC_OFF")); + #endif + + rc = DECLINED; /* Just set final return code and fall through */ + + }/* End 'if( conf->do_static == 0 )' */ + + else /* It's OK to call the handler... */ + { + if ( r->server->loglevel == APLOG_DEBUG ) + { + ap_log_error( "",0,APLOG_NOERRNO|APLOG_DEBUG, r->server, + "mod_gzip: Calling static_handler for r->uri=[%s]",r->uri); + } + + #ifdef MOD_GZIP_DEBUG1 + mod_gzip_printf( "%s: Call mod_gzip_static_file_handler()...\n",cn); + #endif + + rc = mod_gzip_static_file_handler( (request_rec *) r ); + + #ifdef MOD_GZIP_DEBUG1 + mod_gzip_printf( "%s: Back mod_gzip_static_file_handler()... rc=%d\n",cn,rc); + #endif + + }/* End 'else' - OK to call the handler */ + } + else /* Safety catch... No pickup for the 'action' flag... */ + { + if ( r->server->loglevel == APLOG_DEBUG ) + { + ap_log_error( "",0,APLOG_NOERRNO|APLOG_DEBUG, r->server, + "mod_gzip: action_flag = MOD_GZIP_IMAP_????? Unknown value"); + } + + if ( r->server->loglevel == APLOG_DEBUG ) + { + ap_log_error( "",0,APLOG_NOERRNO|APLOG_DEBUG, r->server, + "mod_gzip: No pickup for specified 'action' flag."); + } + + #ifdef MOD_GZIP_DEBUG1 + mod_gzip_printf( "%s: action_flag = MOD_GZIP_??? Unknown value\n",cn); + #endif + + rc = DECLINED; + } + + /* + * Record results to logs, if applicable, and return... + * + * The 'r->notes' values that can be used to disply result + * information in the standard Apache log files should have + * already been updated by the handler that was actually + * used to process the transaction. + */ + + #ifdef MOD_GZIP_DEBUG1 + + if ( rc == OK ) + { + mod_gzip_printf( "%s: Exit > return( rc=%d OK ) >\n",cn,rc); + } + else if ( rc == DECLINED ) + { + mod_gzip_printf( "%s: Exit > return( rc=%d DECLINED ) >\n",cn,rc); + } + else /* HTTP ERROR VALUE... */ + { + mod_gzip_printf( "%s: Exit > return( rc=%d HTTP_ERROR ) >\n",cn,rc); + } + + #endif /* MOD_GZIP_DEBUG1 */ + + return rc; /* Could be OK or DECLINED or HTTP_ERROR */ + +}/* End of mod_gzip_request_handler() */ + +int mod_gzip_prepare_for_dynamic_call( request_rec *r ) +{ + int rc; + + #ifdef MOD_GZIP_DEBUG1 + char cn[]="mod_gzip_prepare_for_dynamic_call()"; + #endif + + /* + * Start... + */ + + #ifdef MOD_GZIP_DEBUG1 + mod_gzip_printf( "%s: Entry...\n",cn); + #endif + + /* + * mod_gzip can run other modules directly... + */ + + /* + * First run mod_action and see it there's a SCRIPT + * for this mime type... + */ + + #ifdef MOD_GZIP_DEBUG1 + mod_gzip_printf( "%s: 1 ***: r->uri =[%s]\n", cn, r->uri ); + mod_gzip_printf( "%s: 1 ***: r->unparsed_uri=[%s]\n", cn, r->unparsed_uri ); + mod_gzip_printf( "%s: 1 ***: r->filename =[%s]\n", cn, r->filename ); + mod_gzip_printf( "%s: 1 ***: r->content_type=[%s]\n", cn, r->content_type ); + mod_gzip_printf( "%s: 1 ***: r->handler =[%s]\n", cn, r->handler ); + mod_gzip_printf( "%s: Call mod_gzip_run_mod_action(r)...\n",cn); + #endif + + rc = mod_gzip_run_mod_action( (request_rec *) r ); + + #ifdef MOD_GZIP_DEBUG1 + + mod_gzip_printf( "%s: Back mod_gzip_run_mod_action(r)...\n",cn); + + if ( rc == OK ) + { + mod_gzip_printf( "%s: rc = %d = OK\n",cn, rc ); + } + else if ( rc == DECLINED ) + { + mod_gzip_printf( "%s: rc = %d = DECLINED\n",cn, rc ); + } + else if ( rc == DONE ) /* -2 means 'totally done' */ + { + mod_gzip_printf( "%s: rc = %d = DONE\n",cn, rc ); + } + else /* Probably an HTTP ERROR value... */ + { + mod_gzip_printf( "%s: rc = %d = HTTP_ERROR?\n",cn, rc ); + } + + mod_gzip_printf( "%s: 2 ***: r->uri =[%s]\n", cn, r->uri ); + mod_gzip_printf( "%s: 2 ***: r->unparsed_uri=[%s]\n", cn, r->unparsed_uri ); + mod_gzip_printf( "%s: 2 ***: r->filename =[%s]\n", cn, r->filename ); + mod_gzip_printf( "%s: 2 ***: r->content_type=[%s]\n", cn, r->content_type ); + mod_gzip_printf( "%s: 2 ***: r->handler =[%s]\n", cn, r->handler ); + + #endif /* MOD_GZIP_DEBUG1 */ + + /* + * Now run mod_alias and get any aliases converted + * to real pathnames... + */ + + #ifdef MOD_GZIP_DEBUG1 + mod_gzip_printf( "%s: Call mod_gzip_run_mod_alias(r)...\n",cn); + #endif + + rc = mod_gzip_run_mod_alias( (request_rec *) r ); + + #ifdef MOD_GZIP_DEBUG1 + mod_gzip_printf( "%s: Back mod_gzip_run_mod_alias(r)...\n",cn); + + if ( rc == OK ) + { + mod_gzip_printf( "%s: rc = %d = OK\n",cn, rc ); + } + else if ( rc == DECLINED ) + { + mod_gzip_printf( "%s: rc = %d = DECLINED\n",cn, rc ); + } + else if ( rc == DONE ) /* -2 means 'totally done' */ + { + mod_gzip_printf( "%s: rc = %d = DONE\n",cn, rc ); + } + else /* Probably an HTTP ERROR value... */ + { + mod_gzip_printf( "%s: rc = %d = HTTP_ERROR?\n",cn, rc ); + } + + mod_gzip_printf( "%s: 3 ***: r->uri =[%s]\n", cn, r->uri ); + mod_gzip_printf( "%s: 3 ***: r->unparsed_uri=[%s]\n", cn, r->unparsed_uri ); + mod_gzip_printf( "%s: 3 ***: r->filename =[%s]\n", cn, r->filename ); + mod_gzip_printf( "%s: 3 ***: r->content_type=[%s]\n", cn, r->content_type ); + mod_gzip_printf( "%s: 3 ***: r->handler =[%s]\n", cn, r->handler ); + + #endif /* MOD_GZIP_DEBUG1 */ + + return OK; + +}/* End of mod_gzip_prepare_for_dynamic_call() */ + + +int mod_gzip_static_file_handler( request_rec *r ) +{ + int rc = 0; + long input_size = 0; + FILE* ifh1 = 0; + + #ifdef MOD_GZIP_DEBUG1 + char cn[]="mod_gzip_static_file_handler()"; + #endif + + /* + * Start... + */ + + #ifdef MOD_GZIP_DEBUG1 + mod_gzip_printf( "%s: Processing file [%s]\n",cn,r->filename); + mod_gzip_printf( "%s: r->finfo.st_size = %ld\n", + cn, (long) r->finfo.st_size); + #endif + + /* + * If there is a valid file size already associated with + * the request then we can assume the core stat() call succeeded + * and that r->filename actually exists. We shouldn't need + * to waste a call to 'fopen()' just to find out for ourselves + * if the file exists. + * + * If the inbound file size was '0' then we need to do some + * verifications of our own before we give up since the + * absence of size might just be a simple bug in the parent code. + */ + + if ( r->finfo.st_size > 0 ) + { + #ifdef MOD_GZIP_DEBUG1 + mod_gzip_printf( "%s: Source file length already known...\n",cn); + #endif + + input_size = (long) r->finfo.st_size; + } + else /* Do our own checking... */ + { + /* + * See if the requested source file exists... + * Be SURE to open the file in BINARY mode... + */ + + ifh1 = fopen( r->filename, "rb" ); + + if ( !ifh1 ) /* The file cannot be found or opened... */ + { + #ifdef MOD_GZIP_DEBUG1 + mod_gzip_printf( "%s: The requested source file was NOT FOUND.\n",cn); + mod_gzip_printf( "%s: Exit > return( HTTP_NOT_FOUND ) >\n",cn); + #endif + + #ifdef MOD_GZIP_USES_APACHE_LOGS + + /* HTTP ERROR conditions provides a short ':WHYTAG' for logs */ + + ap_table_setn( + r->notes,"mod_gzip_result",ap_pstrdup(r->pool,"DECLINED:HTTP_NOT_FOUND")); + + #endif /* MOD_GZIP_USES_APACHE_LOGS */ + + return HTTP_NOT_FOUND; + } + else /* The file was found and opened OK... */ + { + #ifdef MOD_GZIP_DEBUG1 + mod_gzip_printf( "%s: The requested source file is now OPEN...\n",cn); + #endif + } + + /* + * Move the current file pointer to the end of the file... + */ + + if ( fseek( ifh1, 0, SEEK_END ) ) + { + #ifdef MOD_GZIP_DEBUG1 + mod_gzip_printf( "%s: ERROR: fseek() call failed...\n",cn); + #endif + + fclose( ifh1 ); /* FILE is still open so CLOSE it... */ + + /* fseek() failure could be a platform issue so log the event... */ + + ap_log_error( APLOG_MARK,APLOG_NOERRNO|APLOG_ERR, r->server, + "mod_gzip: fseek() failed for r->filename=[%s]",r->filename ); + + /* Return DECLINED and let default logic finish the request... */ + + #ifdef MOD_GZIP_DEBUG1 + mod_gzip_printf( "%s: Exit > return( DECLINED ) >\n",cn); + #endif + + #ifdef MOD_GZIP_USES_APACHE_LOGS + + /* Each 'DECLINE' condition provides a short ':WHYTAG' for logs */ + + ap_table_setn( + r->notes,"mod_gzip_result",ap_pstrdup(r->pool,"DECLINED:FSEEK_FAIL")); + + #endif /* MOD_GZIP_USES_APACHE_LOGS */ + + return DECLINED; + } + + /* + * Get the current SIZE of the requested file... + */ + + input_size = (long) ftell( ifh1 ); + + if ( input_size == -1l ) + { + #ifdef MOD_GZIP_DEBUG1 + mod_gzip_printf( "%s: ERROR: ftell() call failed...\n",cn); + #endif + + fclose( ifh1 ); /* FILE is still open so CLOSE it... */ + + /* ftell() failure could be a platform issue so log the event... */ + + ap_log_error( APLOG_MARK,APLOG_NOERRNO|APLOG_ERR, r->server, + "mod_gzip: ftell() failed for r->filename=[%s]", r->filename ); + + /* Return DECLINED and let default logic finish the request... */ + + #ifdef MOD_GZIP_DEBUG1 + mod_gzip_printf( "%s: Exit > return( DECLINED ) >\n",cn); + #endif + + #ifdef MOD_GZIP_USES_APACHE_LOGS + + /* Each 'DECLINE' condition provides a short ':WHYTAG' for logs */ + + ap_table_setn( + r->notes,"mod_gzip_result",ap_pstrdup(r->pool,"DECLINED:FTELL_FAIL")); + + #endif /* MOD_GZIP_USES_APACHE_LOGS */ + + return DECLINED; + } + + /* + * Once we have the length just close the file... + */ + + if ( fclose( ifh1 ) == EOF ) + { + #ifdef MOD_GZIP_DEBUG1 + mod_gzip_printf( "%s: ERROR: fclose() following ftell() call failed...\n",cn); + #endif + + /* fclose() failure could be a platform issue so log the event... */ + + ap_log_error( APLOG_MARK,APLOG_NOERRNO|APLOG_ERR, r->server, + "mod_gzip: fclose() failed for r->filename=[%s]",r->filename ); + + /* Return DECLINED and let default logic finish the request... */ + + #ifdef MOD_GZIP_DEBUG1 + mod_gzip_printf( "%s: Exit > return( DECLINED ) >\n",cn); + #endif + + #ifdef MOD_GZIP_USES_APACHE_LOGS + + /* Each 'DECLINE' condition provides a short ':WHYTAG' for logs */ + + ap_table_setn( + r->notes,"mod_gzip_result",ap_pstrdup(r->pool,"DECLINED:FCLOSE_FAIL")); + + #endif /* MOD_GZIP_USES_APACHE_LOGS */ + + return DECLINED; + } + + }/* End 'else' */ + + /* + * We have the static filename and the length. + * That's pretty much all we need at this point so + * go ahead and encode/transmit the object... + */ + + #ifdef MOD_GZIP_DEBUG1 + mod_gzip_printf( "%s: Call mod_gzip_encode_and_transmit()...\n",cn); + #endif + + rc = + mod_gzip_encode_and_transmit( + (request_rec *) r, /* request_rec */ + (char *) r->filename, /* source ( Filename or Memory buffer ) */ + (int ) 1, /* 1=Source is a file 0=Memory buffer */ + (long ) input_size, /* input_size */ + (int ) 0 /* nodecline flag 0=Ok to DECLINE 1=No */ + ); + + #ifdef MOD_GZIP_DEBUG1 + mod_gzip_printf( "%s: Back mod_gzip_encode_and_transmit()...\n",cn); + #endif + + /* + * The encode/transmit path should have already updated + * any relevant 'r->note' values ( if used ) for the transaction + * to reflect the results of the operation. + * + * Just return the result code and finish the transaction. + */ + + #ifdef MOD_GZIP_DEBUG1 + if ( rc == OK ) + { + mod_gzip_printf( "%s: Exit > return( rc = %d OK ) >\n",cn,rc); + } + else if ( rc == DECLINED ) + { + mod_gzip_printf( "%s: Exit > return( rc = %d DECLINED ) >\n",cn,rc); + } + else /* HTTP ERROR */ + { + mod_gzip_printf( "%s: Exit > return( rc = %d HTTP_ERROR ) >\n",cn,rc); + } + #endif /* MOD_GZIP_DEBUG1 */ + + return( rc ); + +}/* End of mod_gzip_static_file_handler() */ + +int mod_gzip_create_unique_filename( +mod_gzip_conf *mgc, +char *target, +int targetmaxlen +) +{ + /* + * Creates a unique work file name. + */ + + long process_id = 0; /* Current Process ID */ + long thread_id = 0; /* Current thread ID */ + + #ifdef MOD_GZIP_DEBUG1 + char cn[]="mod_gzip_create_unique_filename()"; + #endif + + /* Start... */ + + #ifdef WIN32 + process_id = (long) GetCurrentProcessId(); + thread_id = (long) GetCurrentThreadId(); + #else /* !WIN32 */ + process_id = (long) getpid(); + thread_id = (long) process_id; /* TODO: Add pthreads call */ + #endif /* WIN32 */ + + #ifdef MOD_GZIP_DEBUG1 + mod_gzip_printf( "%s: Entry...\n",cn ); + mod_gzip_printf( "%s: target = %ld\n",cn,(long)target); + mod_gzip_printf( "%s: targetmaxlen = %ld\n",cn,(long)targetmaxlen); + mod_gzip_printf( "%s: process_id = %ld\n",cn,(long)process_id ); + mod_gzip_printf( "%s: thread_id = %ld\n",cn,(long)thread_id ); + mod_gzip_printf( "%s: mod_gzip_iusn = %ld\n",cn,(long)mod_gzip_iusn ); + #endif + + /* + * Sanity checks... + */ + + if ( ( !target ) || ( targetmaxlen == 0 ) ) + { + #ifdef MOD_GZIP_DEBUG1 + mod_gzip_printf( "%s: Invalid target or targetmaxlen value.\n",cn); + mod_gzip_printf( "%s: Exit > return( 1 ) > ERROR >\n",cn ); + #endif + + return 1; + } + + /* + * Use the PROCESS + THREAD ID's and the current IUSN + * ( Instance Unique Sequence Number ) transaction ID to + * create a one-time only unique output workfile name... + */ + + sprintf( + target, + "%s%s_%ld_%ld_%ld.wrk", + mgc->cache.root, /* Either ServerRoot or Config specified dir. */ + mod_gzip_dirsep, /* Forward slash for UNIX, backslash for WIN32 */ + (long) process_id, /* Current process ID */ + (long) thread_id, /* Current thread ID */ + (long) mod_gzip_iusn /* Instance Unique Sequence Number */ + ); + + mod_gzip_iusn++; /* Increment Instance Unique Sequence Number */ + + if ( mod_gzip_iusn > 999999999L ) mod_gzip_iusn = 1; /* Wrap */ + + #ifdef MOD_GZIP_DEBUG1 + mod_gzip_printf( "%s: target = [%s]\n",cn,target); + mod_gzip_printf( "%s: Exit > return( 0 ) >\n",cn ); + #endif + + return 0; + +}/* End of mod_gzip_create_unique_filename() */ + + +#ifdef MOD_GZIP_ALLOWS_INTERNAL_COMMANDS + +int mod_gzip_send_html_command_response( +request_rec *r, /* Request record */ +char *tmp, /* Response to send */ +char *ctype /* Content type string */ +) +{ + /* Generic command response transmitter... */ + + int tmplen=0; + char content_length[20]; + + #ifdef MOD_GZIP_DEBUG1 + char cn[]="mod_gzip_send_html_command_response()"; + #endif + + /* Start... */ + + #ifdef MOD_GZIP_DEBUG1 + mod_gzip_printf( "%s: Entry...\n",cn); + mod_gzip_printf( "%s: ctype=[%s]\n",cn,ctype); + #endif + + /* Add the length of the response to the output header... */ + /* The third parameter to ap_table_set() MUST be a string. */ + + tmplen = strlen( tmp ); + + sprintf( content_length, "%d", tmplen ); + + #ifdef MOD_GZIP_DEBUG1 + mod_gzip_printf( "%s: content_length = [%s]\n",cn,content_length); + #endif + + ap_table_set( r->headers_out, "Content-Length", content_length ); + + /* Make sure the content type matches this response... */ + + r->content_type = ctype; /* Actual type passed by caller */ + + #ifdef MOD_GZIP_DEBUG1 + mod_gzip_printf( "%s: r->content_type = [%s]\n",cn,r->content_type); + #endif + + /* Start a timer... */ + + #ifdef MOD_GZIP_DEBUG1 + mod_gzip_printf( "%s: Call ap_soft_timeout()...\n",cn); + #endif + + ap_soft_timeout( "mod_gzip_send_html_command", r ); + + #ifdef MOD_GZIP_DEBUG1 + mod_gzip_printf( "%s: Back ap_soft_timeout()...\n",cn); + #endif + + #ifdef MOD_GZIP_COMMANDS_USE_LAST_MODIFIED + + /* Be sure to update the modifcation 'time' to current */ + /* time before calling 'ap_set_last_modified()'. All that */ + /* call does is set the r->xxxx value into the output */ + /* header. It doesn't actually update the time itself. */ + + #ifdef MOD_GZIP_DEBUG1 + mod_gzip_printf( "%s: Call ap_update_mtime(r,r-finfo.st_mtime)...\n",cn); + #endif + + ap_update_mtime( r, r->finfo.st_mtime ); + + #ifdef MOD_GZIP_DEBUG1 + mod_gzip_printf( "%s: Back ap_update_mtime(r,r-finfo.st_mtime)...\n",cn); + #endif + + /* Update the 'Last modified' stamp in output header... */ + + #ifdef MOD_GZIP_DEBUG1 + mod_gzip_printf( "%s: Call ap_set_last_modified()...\n",cn); + #endif + + ap_set_last_modified(r); + + /* TODO: Add 'no-cache' option(s) to mod_gzip command responses */ + /* so user doesn't have hit reload to get fresh data. */ + + #ifdef MOD_GZIP_DEBUG1 + mod_gzip_printf( "%s: Back ap_set_last_modified()...\n",cn); + #endif + + #endif /* MOD_GZIP_COMMANDS_USE_LAST_MODIFIED */ + + /* Send the HTTP response header... */ + + #ifdef MOD_GZIP_DEBUG1 + mod_gzip_printf( "%s: Call ap_send_http_header()...\n",cn); + #endif + + ap_send_http_header(r); + + #ifdef MOD_GZIP_DEBUG1 + mod_gzip_printf( "%s: Back ap_send_http_header()...\n",cn); + #endif + + /* Send the response BODY... */ + + #ifdef MOD_GZIP_DEBUG1 + mod_gzip_printf( "%s: Sending response...\n%s\n",cn,tmp); + #endif + + #ifdef MOD_GZIP_USES_AP_SEND_MMAP + + /* Use ap_send_mmap() call to send the data... */ + + ap_send_mmap( tmp, r, 0, tmplen ); + + #else /* !MOD_GZIP_USES_AP_SEND_MMAP */ + + /* Use ap_rwrite() call to send the data... */ + + ap_rwrite( tmp, tmplen, r ); + + #endif /* MOD_GZIP_USES_AP_SEND_MMAP */ + + /* Clean up and exit... */ + + #ifdef MOD_GZIP_DEBUG1 + mod_gzip_printf( "%s: Call ap_kill_timeout()...\n",cn); + #endif + + ap_kill_timeout(r); + + #ifdef MOD_GZIP_DEBUG1 + mod_gzip_printf( "%s: Back ap_kill_timeout()...\n",cn); + mod_gzip_printf( "%s: Exit > return( OK ) >\n",cn); + #endif + + return OK; + +}/* End of mod_gzip_send_html_command_response() */ + +#endif /* MOD_GZIP_ALLOWS_INTERNAL_COMMANDS */ + +static void * +mod_gzip_create_config( pool *p, server_rec *s ) +{ + int i; + + mod_gzip_conf *ps = 0; + + #ifdef MOD_GZIP_DEBUG1 + char cn[]="mod_gzip_create_config()"; + #endif + + /* + * Set all the configuration default values... + */ + + #ifdef MOD_GZIP_DEBUG1 + mod_gzip_printf( "%s: Entry\n", cn ); + #endif + + /* + * Allocate a new config structure... + */ + + ps = ( mod_gzip_conf * ) ap_pcalloc( p, sizeof( mod_gzip_conf ) ); + + /* + * Set all default values... + */ + + ps->req = 1; /* Default is ON */ + ps->req_set = 1; /* Default is ON */ + ps->do_static_files = 1; /* Default is ON */ + ps->do_cgi = 1; /* Default is ON */ + ps->keep_workfiles = 0; /* 1=Keep workfiles 0=No */ + ps->min_http = 0; /* 1001=HTTP/1.1 Default=All HTTP levels */ + + ps->minimum_file_size = (long) mod_gzip_minimum_file_size; + /* Minimum file size in bytes */ + ps->maximum_inmem_size = (long) mod_gzip_maximum_inmem_size; + /* Maximum size for in-memory compression */ + + /* Compressed object cache control variables... */ + + /* Using these default values the compressed object cache + /* can have 2^18 directories (256,000) */ + + ps->cache.root = ap_server_root; /* Default DIR is ServerRoot */ + + ps->cache.space = MOD_GZIP_DEFAULT_CACHE_SPACE; + ps->cache.space_set = 0; + ps->cache.maxexpire = MOD_GZIP_DEFAULT_CACHE_MAXEXPIRE; + ps->cache.maxexpire_set = 0; + ps->cache.defaultexpire = MOD_GZIP_DEFAULT_CACHE_EXPIRE; + ps->cache.defaultexpire_set = 0; + ps->cache.lmfactor = MOD_GZIP_DEFAULT_CACHE_LMFACTOR; + ps->cache.lmfactor_set = 0; + ps->cache.gcinterval = -1; + ps->cache.gcinterval_set = 0; + ps->cache.dirlevels = 3; + ps->cache.dirlevels_set = 0; + ps->cache.dirlength = 1; + ps->cache.dirlength_set = 0; + + /* Initialize the include/exclude item map list... */ + + /* For now all init values are ZERO but don't use */ + /* memset() since this may not always be the case. */ + + ps->imap_total_entries = 0; + + for ( i=0; iimap[i].include = 0; + ps->imap[i].type = 0; + ps->imap[i].action = 0; + ps->imap[i].name[0] = 0; + + }/* End 'i' loop */ + + #ifdef MOD_GZIP_DEBUG1 + mod_gzip_printf( "%s: ps->imap_total_entries = %d\n", cn, ps->imap_total_entries ); + mod_gzip_printf( "%s: Exit > return( ps ) >\n", cn ); + #endif + + return ps; + +}/* End of mod_gzip_create_config() */ + +static void * +mod_gzip_merge_config( pool *p, void *basev, void *overridesv ) +{ + mod_gzip_conf *ps = ap_pcalloc(p, sizeof(mod_gzip_conf)); + mod_gzip_conf *base = (mod_gzip_conf *) basev; + mod_gzip_conf *overrides = (mod_gzip_conf *) overridesv; + + ps->req = (overrides->req_set == 0) ? base->req : overrides->req; + ps->cache.root = (overrides->cache.root == NULL) ? base->cache.root : overrides->cache.root; + ps->cache.space = (overrides->cache.space_set == 0) ? base->cache.space : overrides->cache.space; + ps->cache.maxexpire = (overrides->cache.maxexpire_set == 0) ? base->cache.maxexpire : overrides->cache.maxexpire; + ps->cache.defaultexpire = (overrides->cache.defaultexpire_set == 0) ? base->cache.defaultexpire : overrides->cache.defaultexpire; + ps->cache.lmfactor = (overrides->cache.lmfactor_set == 0) ? base->cache.lmfactor : overrides->cache.lmfactor; + ps->cache.gcinterval = (overrides->cache.gcinterval_set == 0) ? base->cache.gcinterval : overrides->cache.gcinterval; + ps->cache.dirlevels = (overrides->cache.dirlevels_set == 0) ? base->cache.dirlevels : overrides->cache.dirlevels; + ps->cache.dirlength = (overrides->cache.dirlength_set == 0) ? base->cache.dirlength : overrides->cache.dirlength; + + return ps; + +}/* End of mod_gzip_merge_config() */ + +/* + * Module configuration directive handlers... + */ + +static const char * +mod_gzip_set_on(cmd_parms *parms, void *dummy, char *arg) +{ + mod_gzip_conf *mgc; + + #ifdef MOD_GZIP_DEBUG1 + char cn[]="mod_gzip_set_on()"; + #endif + + /* Start... */ + + #ifdef MOD_GZIP_DEBUG1 + mod_gzip_printf( "%s: Entry\n", cn ); + mod_gzip_printf( "%s: arg=[%s]\n", cn, arg ); + #endif + + mgc = ( mod_gzip_conf * ) + ap_get_module_config(parms->server->module_config, &gzip_module); + + if ( ( arg[0] == 'Y' )||( arg[0] == 'y' ) ) + { + /* Set the master 'request control' switches ON... */ + + mgc->req = 1; /* Yes */ + mgc->req_set = 1; /* Yes */ + } + else /* Set the master 'request control' switches OFF... */ + { + mgc->req = 0; /* No */ + mgc->req_set = 0; /* No */ + } + + #ifdef MOD_GZIP_DEBUG1 + mod_gzip_printf( "%s: mgc->req = %ld\n", cn, (long) mgc->req ); + mod_gzip_printf( "%s: mgc->req_set = %ld\n", cn, (long) mgc->req_set ); + #endif + + return NULL; +} + +static const char * +mod_gzip_set_keep_workfiles(cmd_parms *parms, void *dummy, char *arg) +{ + mod_gzip_conf *mgc; + + #ifdef MOD_GZIP_DEBUG1 + char cn[]="mod_gzip_set_keep_workfiles()"; + #endif + + /* Start... */ + + #ifdef MOD_GZIP_DEBUG1 + mod_gzip_printf( "%s: Entry\n", cn ); + mod_gzip_printf( "%s: arg=[%s]\n", cn, arg ); + #endif + + mgc = ( mod_gzip_conf * ) + ap_get_module_config(parms->server->module_config, &gzip_module); + + if ( ( arg[0] == 'Y' )||( arg[0] == 'y' ) ) + { + mgc->keep_workfiles = 1; /* Yes */ + } + else + { + mgc->keep_workfiles = 0; /* No */ + } + + #ifdef MOD_GZIP_DEBUG1 + mod_gzip_printf( "%s: mgc->keep_workfiles = %ld\n", cn, + (long) mgc->keep_workfiles ); + #endif + + return NULL; +} + +static const char * +mod_gzip_set_min_http(cmd_parms *parms, void *dummy, char *arg) +{ + mod_gzip_conf *mgc; + + #ifdef MOD_GZIP_DEBUG1 + char cn[]="mod_gzip_set_min_http()"; + #endif + + /* Start... */ + + #ifdef MOD_GZIP_DEBUG1 + mod_gzip_printf( "%s: Entry\n", cn ); + mod_gzip_printf( "%s: arg=[%s]\n", cn, arg ); + #endif + + mgc = ( mod_gzip_conf * ) + ap_get_module_config(parms->server->module_config, &gzip_module); + + mgc->min_http = (int) atoi( arg ); + + #ifdef MOD_GZIP_DEBUG1 + mod_gzip_printf( "%s: mgc->min_http = %ld\n", cn, + (long) mgc->min_http ); + #endif + + return NULL; +} + + +static const char * +mod_gzip_imap_add_item( mod_gzip_conf *mgc, char *arg, int flag1 ) +{ + int x; + char *p1; + int ch1; + int this_type=0; + int this_action=0; + int this_include=flag1; + + #ifdef MOD_GZIP_DEBUG1 + char cn[]="mod_gzip_imap_add_item()"; + #endif + + /* Start... */ + + #ifdef MOD_GZIP_DEBUG1 + + mod_gzip_printf( "%s: Entry\n", cn ); + mod_gzip_printf( "%s: 1 arg=[%s]\n", cn, arg ); + + if ( flag1 == 1 ) + { + mod_gzip_printf( "%s: flag1 = %d = INCLUDE\n", cn, flag1 ); + } + else if ( flag1 == 0 ) + { + mod_gzip_printf( "%s: flag1 = %d = EXCLUDE\n", cn, flag1 ); + } + else + { + mod_gzip_printf( "%s: flag1 = %d = ??? Unknown value\n", cn, flag1 ); + } + + mod_gzip_printf( "%s: MOD-GZIP_IMAP_MAXNAMES = %d\n", + cn, MOD_GZIP_IMAP_MAXNAMES ); + + mod_gzip_printf( "%s: mgc->imap_total_entries = %d\n", + cn, mgc->imap_total_entries ); + + #endif /* MOD_GZIP_DEBUG1 */ + + /* + * Parse the config line... + */ + + p1 = arg; + while((*p1!=0)&&(*p1<33)) p1++; + ch1 = *p1; + + this_type = MOD_GZIP_IMAP_ISHANDLER; + this_action = MOD_GZIP_IMAP_DYNAMIC1; + + if ( ch1 == '!' ) + { + arg++; + p1 = arg; + while((*p1!=0)&&(*p1<33)) p1++; + ch1 = *p1; + } + else + { + this_action = MOD_GZIP_IMAP_STATIC1; + } + + if ( ch1 == '.' ) + { + this_type = MOD_GZIP_IMAP_ISEXT; + } + else + { + p1 = arg; + while (*p1!=0) + { + if ( *p1 == '/' ) + { + this_type = MOD_GZIP_IMAP_ISMIME; + } + p1++; + } + } + + /* + * Safety checks... + */ + + if ( ( this_type != MOD_GZIP_IMAP_ISMIME ) && + ( this_type != MOD_GZIP_IMAP_ISEXT ) && + ( this_type != MOD_GZIP_IMAP_ISHANDLER ) ) + { + #ifdef MOD_GZIP_DEBUG1 + mod_gzip_printf( "%s: this_type = %d = MOD_GZIP_IMAP_IS??? Unknown type\n",cn,this_type); + mod_gzip_printf( "%s: return( mod_gzip: ERROR: Unrecognized item 'type'\n",cn); + #endif + + return( "mod_gzip: ERROR: Unrecognized item 'type'" ); + } + + if ( ( this_action != MOD_GZIP_IMAP_DYNAMIC1 ) && + ( this_action != MOD_GZIP_IMAP_STATIC1 ) ) + { + #ifdef MOD_GZIP_DEBUG1 + mod_gzip_printf( "%s: this_action = %d = MOD_GZIP_IMAP_??? Unknown action\n",cn,this_action); + mod_gzip_printf( "%s: return( mod_gzip: ERROR: Unrecognized item 'action'\n",cn); + #endif + + return( "mod_gzip: ERROR: Unrecognized item 'action'" ); + } + + /* + * Wildcards... + */ + + if ( this_type != MOD_GZIP_IMAP_ISMIME ) + { + /* + * Wildcards are only allowed in MIME strings such as 'image/*' + */ + + p1 = arg; + while (*p1!=0) + { + if ( *p1 == '*' ) + { + return( "mod_gzip: ERROR: Wildcards are only allowed in MIME strings." ); + } + p1++; + } + } + + /* + * If there is room for a new record then add it... + */ + + if ( mgc->imap_total_entries < MOD_GZIP_IMAP_MAXNAMES ) + { + if ( strlen( arg ) < MOD_GZIP_IMAP_MAXNAMELEN ) + { + x = mgc->imap_total_entries; + + p1 = arg; + while((*p1!=0)&&(*p1<33)) p1++; + + strcpy( mgc->imap[x].name, p1 ); + + mgc->imap[x].include = this_include; + mgc->imap[x].type = this_type; + mgc->imap[x].action = this_action; + + mgc->imap_total_entries++; /* Increase onboard items */ + } + else /* ERROR: Name is too long */ + { + #ifdef MOD_GZIP_DEBUG1 + mod_gzip_printf( "%s: return( mod_gzip: ERROR: Item name is too long\n",cn); + #endif + + return( "mod_gzip: ERROR: Item name is too long" ); + } + } + else /* ERROR: INDEX is FULL */ + { + #ifdef MOD_GZIP_DEBUG1 + mod_gzip_printf( "%s: return( mod_gzip: ERROR: Item index is full\n",cn); + #endif + + return( "mod_gzip: ERROR: Item index is full" ); + } + + #ifdef MOD_GZIP_DEBUG1 + mod_gzip_printf( "%s: Exit > return( NULL ) >\n",cn); + #endif + + return NULL; + +}/* End of mod_gzip_imap_add_item() */ + +#ifdef MOD_GZIP_DEBUG1 + +int mod_gzip_imap_show_items( mod_gzip_conf *mgc ) +{ + /* + * DEBUG only. Show the complete include/exclude list. + * This is normally called from mod_gzip_init() + * after all the configuration routines have executed. + */ + + int i; + int x; + char cn[]="mod_gzip_imap_show_items()"; + + /* Start... */ + + mod_gzip_printf( "\n"); + mod_gzip_printf( "%s: Entry\n", cn ); + + mod_gzip_printf( "%s: mgc->imap_total_entries= %d\n", cn, + (long) mgc->imap_total_entries ); + + for ( i=0; iimap_total_entries; i++ ) + { + x = i; /* Work variable */ + + mod_gzip_printf( "\n"); + mod_gzip_printf( "%s: mgc->imap[%3.3d].include = %d\n", cn,x,mgc->imap[x].include); + mod_gzip_printf( "%s: mgc->imap[%3.3d].type = %d\n", cn,x,mgc->imap[x].type); + + if ( mgc->imap[x].type == MOD_GZIP_IMAP_ISMIME ) + { + mod_gzip_printf( "%s: mgc->imap[%3.3d].type = MOD_GZIP_IMAP_ISMIME\n",cn,x); + } + else if ( mgc->imap[x].type == MOD_GZIP_IMAP_ISEXT ) + { + mod_gzip_printf( "%s: mgc->imap[%3.3d].type = MOD_GZIP_IMAP_ISEXT\n",cn,x); + } + else if ( mgc->imap[x].type == MOD_GZIP_IMAP_ISHANDLER ) + { + mod_gzip_printf( "%s: mgc->imap[%3.3d].type = MOD_GZIP_IMAP_ISHANDLER\n",cn,x); + } + else /* Unrecognized item type... */ + { + mod_gzip_printf( "%s: mgc->imap[%3.3d].type = MOD_GZIP_IMAP_IS??? Unknown type\n",cn,x); + } + + mod_gzip_printf( "%s: mgc->imap[%3.3d].action = %d\n", cn,x,mgc->imap[x].action); + + if ( mgc->imap[x].action == MOD_GZIP_IMAP_DYNAMIC1 ) + { + mod_gzip_printf( "%s: mgc->imap[%3.3d].action = MOD_GZIP_IMAP_DYNAMIC1\n",cn,x); + } + else if ( mgc->imap[x].action == MOD_GZIP_IMAP_STATIC1 ) + { + mod_gzip_printf( "%s: mgc->imap[%3.3d].action = MOD_GZIP_IMAP_STATIC1\n",cn,x); + } + else /* Unrecognized action type... */ + { + mod_gzip_printf( "%s: mgc->imap[%3.3d].action = MOD_GZIP_IMAP_??? Unknown action\n",cn,x); + } + + mod_gzip_printf( "%s: mgc->imap[%3.3d].name = [%s]\n",cn,x,mgc->imap[x].name); + + }/* End 'i' loop */ + + mod_gzip_printf( "\n"); + + return 0; + +}/* End of mod_gzip_imap_show_items() */ + +#endif /* MOD_GZIP_DEBUG1 */ + +static const char * +mod_gzip_set_item_include(cmd_parms *parms, void *dummy, char *arg) +{ + mod_gzip_conf *mgc; + + #ifdef MOD_GZIP_DEBUG1 + char cn[]="mod_gzip_set_item_include()"; + #endif + + /* Start... */ + + #ifdef MOD_GZIP_DEBUG1 + mod_gzip_printf( "%s: Entry\n", cn ); + mod_gzip_printf( "%s: arg=[%s]\n", cn, arg ); + #endif + + mgc = ( mod_gzip_conf * ) + ap_get_module_config(parms->server->module_config, &gzip_module); + + /* Pass pre-determined pointer to config structure... */ + /* Pass '1' for parm 3 to INCLUDE this item... */ + + return( mod_gzip_imap_add_item( mgc, arg, 1 ) ); +} + +static const char * +mod_gzip_set_item_exclude(cmd_parms *parms, void *dummy, char *arg) +{ + mod_gzip_conf *mgc; + + #ifdef MOD_GZIP_DEBUG1 + char cn[]="mod_gzip_set_item_exclude()"; + #endif + + /* Start... */ + + #ifdef MOD_GZIP_DEBUG1 + mod_gzip_printf( "%s: Entry\n", cn ); + mod_gzip_printf( "%s: arg=[%s]\n", cn, arg ); + #endif + + mgc = ( mod_gzip_conf * ) + ap_get_module_config(parms->server->module_config, &gzip_module); + + /* Pass pre-determined pointer to config structure... */ + /* Pass '0' for parm 3 to EXCLUDE this item... */ + + return( mod_gzip_imap_add_item( mgc, arg, 0 ) ); +} + +static const char * +mod_gzip_set_temp_dir(cmd_parms *parms, void *dummy, char *arg) +{ + mod_gzip_conf *mgc; + + char cn[]="mod_gzip_set_temp_dir()"; + + /* Start... */ + + #ifdef MOD_GZIP_DEBUG1 + mod_gzip_printf( "%s: Entry\n", cn ); + mod_gzip_printf( "%s: arg=[%s]\n", cn, arg ); + #endif + + mgc = ( mod_gzip_conf * ) + ap_get_module_config(parms->server->module_config, &gzip_module); + + mgc->cache.root = arg; /* For now temp dir is used as cache root */ + + strcpy( mod_gzip_temp_dir, arg ); + mgc->cache.root = mod_gzip_temp_dir; + + #ifdef MOD_GZIP_DEBUG1 + mod_gzip_printf( "%s: mgc->cache.root=[%s]\n", cn, mgc->cache.root ); + #endif + + return NULL; +} + +static const char * +mod_gzip_set_minimum_file_size(cmd_parms *parms, void *dummy, char *arg) +{ + mod_gzip_conf *mgc; + long lval; + + #ifdef MOD_GZIP_DEBUG1 + char cn[]="mod_gzip_set_minimum_file_size()"; + #endif + + /* Start... */ + + #ifdef MOD_GZIP_DEBUG1 + mod_gzip_printf( "%s: Entry\n", cn ); + mod_gzip_printf( "%s: arg=[%s]\n", cn, arg ); + #endif + + mgc = ( mod_gzip_conf * ) + ap_get_module_config(parms->server->module_config, &gzip_module); + + lval = (long) atol(arg); + + /* 300 bytes is the minimum at all times */ + if ( lval < 300L ) lval = 300L; + + mgc->minimum_file_size = (long) lval; /* Set config */ + mod_gzip_minimum_file_size = (long) lval; /* Set global */ + + #ifdef MOD_GZIP_DEBUG1 + mod_gzip_printf( "%s: ....mgc->minimum_file_size = %ld\n", cn, + (long) mgc->minimum_file_size ); + mod_gzip_printf( "%s: mod_gzip_minimum_file_size = %ld\n", cn, + (long) mod_gzip_minimum_file_size ); + #endif + + return NULL; +} + +static const char * +mod_gzip_set_maximum_inmem_size(cmd_parms *parms, void *dummy, char *arg) +{ + mod_gzip_conf *mgc; + long lval=0; + + #ifdef MOD_GZIP_DEBUG1 + char cn[]="mod_gzip_set_maximum_inmem_size()"; + #endif + + /* Start... */ + + #ifdef MOD_GZIP_DEBUG1 + mod_gzip_printf( "%s: Entry\n", cn ); + mod_gzip_printf( "%s: arg=[%s]\n", cn, arg ); + #endif + + mgc = ( mod_gzip_conf * ) + ap_get_module_config(parms->server->module_config, &gzip_module); + + lval = (long) atol(arg); + + /* 60000 bytes is the current maximum since a malloc() call is used */ + if ( lval > 60000L ) lval = 60000L; + + mgc->maximum_inmem_size = (long) lval; /* Set config */ + mod_gzip_maximum_inmem_size = (long) lval; /* Set global */ + + #ifdef MOD_GZIP_DEBUG1 + mod_gzip_printf( "%s: ....mgc->maximum_inmem_size = %ld\n", cn, + (long) mgc->maximum_inmem_size ); + mod_gzip_printf( "%s: mod_gzip_maximum_inmem_size = %ld\n", cn, + (long) mod_gzip_maximum_inmem_size ); + #endif + + return NULL; +} + +static const char * +mod_gzip_set_do_static_files(cmd_parms *parms, void *dummy, char *arg) +{ + mod_gzip_conf *mgc; + + #ifdef MOD_GZIP_DEBUG1 + char cn[]="mod_gzip_set_do_static_files()"; + #endif + + /* Start... */ + + #ifdef MOD_GZIP_DEBUG1 + mod_gzip_printf( "%s: Entry\n", cn ); + mod_gzip_printf( "%s: arg=[%s]\n", cn, arg ); + #endif + + mgc = ( mod_gzip_conf * ) + ap_get_module_config(parms->server->module_config, &gzip_module); + + if ( ( arg[0] == 'Y' )||( arg[0] == 'y' ) ) + { + mgc->do_static_files = 1; /* Yes */ + } + else + { + mgc->do_static_files = 0; /* No */ + } + + #ifdef MOD_GZIP_DEBUG1 + mod_gzip_printf( "%s: mgc->do_static_files = %ld\n", cn, + (long) mgc->do_static_files ); + #endif + + return NULL; +} + +static const char * +mod_gzip_set_do_cgi(cmd_parms *parms, void *dummy, char *arg) +{ + mod_gzip_conf *mgc; + + #ifdef MOD_GZIP_DEBUG1 + char cn[]="mod_gzip_set_do_cgi()"; + #endif + + /* Start... */ + + #ifdef MOD_GZIP_DEBUG1 + mod_gzip_printf( "%s: Entry\n", cn ); + mod_gzip_printf( "%s: arg=[%s]\n", cn, arg ); + #endif + + mgc = ( mod_gzip_conf * ) + ap_get_module_config(parms->server->module_config, &gzip_module); + + if ( ( arg[0] == 'Y' )||( arg[0] == 'y' ) ) + { + mgc->do_cgi = 1; /* Yes */ + } + else + { + mgc->do_cgi = 0; /* No */ + } + + #ifdef MOD_GZIP_DEBUG1 + mod_gzip_printf( "%s: mgc->do_cgi = %ld\n", cn, + (long) mgc->do_cgi ); + #endif + + return NULL; +} + +static const handler_rec mod_gzip_handlers[] = +{ + /* + * This is where we associate an ASCII NAME for our 'handler' + * which is what gets set into the r->handler field for a + * request and allows the function name associated with the + * ASCII name to be called and handle the request... + */ + + /* Add a 'name' and some types to our handler... */ + + {"mod_gzip_handler", mod_gzip_handler}, + {CGI_MAGIC_TYPE, mod_gzip_handler}, + {"cgi-script", mod_gzip_handler}, + {"*", mod_gzip_handler}, + {NULL} +}; + + +static const command_rec mod_gzip_cmds[] = +{ + /* + * Define our httpd.conf configuration diectives and + * the local routines that are responsible for processing + * those directives when the time comes... + */ + + {"mod_gzip_on", mod_gzip_set_on, NULL, RSRC_CONF, TAKE1, + "Yes=mod_gzip will handle requests No=mod_gzip runs in 'passthrough' mode"}, + + {"mod_gzip_do_static_files", mod_gzip_set_do_static_files, NULL, RSRC_CONF, TAKE1, + "'Yes' means mod_gzip will compress static files."}, + + {"mod_gzip_do_cgi", mod_gzip_set_do_cgi, NULL, RSRC_CONF, TAKE1, + "'Yes' means mod_gzip will compress dynamic CGI script output."}, + + {"mod_gzip_keep_workfiles", mod_gzip_set_keep_workfiles, NULL, RSRC_CONF, TAKE1, + "On=Keep work files Off=No"}, + + {"mod_gzip_min_http", mod_gzip_set_min_http, NULL, RSRC_CONF, TAKE1, + "Minimum HTTP support level to receive compression. 1001=HTTP/1.1"}, + + {"mod_gzip_minimum_file_size", mod_gzip_set_minimum_file_size, NULL, RSRC_CONF, TAKE1, + "The minimum size ( in bytes ) before compression will be attempted"}, + + {"mod_gzip_maximum_inmem_size", mod_gzip_set_maximum_inmem_size, NULL, RSRC_CONF, TAKE1, + "The maximum size ( in bytes ) to use for in-memory compression."}, + + {"mod_gzip_temp_dir", mod_gzip_set_temp_dir, NULL, RSRC_CONF, TAKE1, + "The directory to use for work files and compression cache"}, + + {"mod_gzip_item_include", mod_gzip_set_item_include, NULL, RSRC_CONF, TAKE1, + "Add the item the inclusion list"}, + + {"mod_gzip_item_exclude", mod_gzip_set_item_exclude, NULL, RSRC_CONF, TAKE1, + "Add the item the exclusion list"}, + + {NULL} +}; + +/* + * The actual module 'jump' table... + * + * If one of the fixed 'call' points has a valid function + * address then Apache will 'call' into it at the appropriate time. + * + * When the compressed object cache is engaged we will need to + * simply add some handlers for the URI detection and translation + * call point(s). + */ + +module MODULE_VAR_EXPORT gzip_module = +{ + STANDARD_MODULE_STUFF, + mod_gzip_init, /* initializer */ + NULL, /* create per-directory config structure */ + NULL, /* merge per-directory config structures */ + mod_gzip_create_config, /* create per-server config structure */ + mod_gzip_merge_config, /* merge per-server config structures */ + mod_gzip_cmds, /* command table */ + mod_gzip_handlers, /* handlers */ + NULL, /* translate_handler */ + NULL, /* check_user_id */ + NULL, /* check auth */ + NULL, /* check access */ + NULL, /* type_checker */ + NULL, /* pre-run fixups */ + NULL, /* logger */ + NULL, /* header parser */ + NULL, /* child_init */ + NULL, /* child_exit */ + NULL /* post read-request */ +}; + +#ifdef NETWARE +int main(int argc, char *argv[]) +{ + ExitThread(TSR_THREAD, 0); +} +#endif + +FILE *mod_gzip_open_output_file( +request_rec *r, +char *output_filename, +int *rc +) +{ + FILE *ifh; + + #ifdef MOD_GZIP_DEBUG1 + char cn[]="mod_gzip_open_output_file():::"; + #endif + + /* + * Start... + */ + + #ifdef MOD_GZIP_DEBUG1 + mod_gzip_printf( "%s: Entry...\n",cn); + mod_gzip_printf( "%s: output_filename=[%s]\n",cn,output_filename); + #endif + + ifh = fopen( output_filename, "rb" ); /* Open in BINARY mode */ + + if ( !ifh ) /* The file failed to open... */ + { + #ifdef MOD_GZIP_DEBUG1 + mod_gzip_printf( "%s: ERROR: Cannot open file [%s]\n", + cn,output_filename); + #endif + + /* + * The workfile was created OK but now will not re-open. + * This is worth a strike in the ERROR log. + */ + + ap_log_error( APLOG_MARK,APLOG_NOERRNO|APLOG_ERR, r->server, + "mod_gzip: Cannot re-open output_filename=[%s]", + output_filename ); + + /* Return DECLINED and let default logic finish the request... */ + + #ifdef MOD_GZIP_DEBUG1 + mod_gzip_printf( "%s: Exit > return( NULL ) >\n",cn); + #endif + + #ifdef MOD_GZIP_USES_APACHE_LOGS + + /* Each 'DECLINE' condition provides a short ':WHYTAG' for logs */ + + ap_table_setn( + r->notes,"mod_gzip_result",ap_pstrdup(r->pool,"DECLINED:WORK_OPENFAIL")); + + #endif /* MOD_GZIP_USES_APACHE_LOGS */ + + *rc = DECLINED; /* Update caller's result code... */ + + return NULL; + + }/* End 'if ( !ifh )' */ + + #ifdef MOD_GZIP_DEBUG1 + mod_gzip_printf( "%s: File is now open...\n",cn); + mod_gzip_printf( "%s: Exit > return( FILE *ifh ) >\n",cn); + #endif + + *rc = OK; /* Update caller's result code */ + + return ifh; /* Return the file handle */ + +}/* End of mod_gzip_open_output_file() */ + +int mod_gzip_encode_and_transmit( +request_rec *r, +char *source, +int source_is_a_file, +long input_size, +int nodecline +) +{ + GZP_CONTROL gzc; + GZP_CONTROL* gzp = &gzc; + + int rc = 0; + FILE *ifh = 0; + int bytesread = 0; + long output_size = 0; + long compression_ratio = 0; + char* gz1_ismem_obuf = 0; + int finalize_stats = 1; + + int gz1_ismem_obuf_was_allocated = 0; + + char content_length[20]; /* For Content-length updates */ + + #define MOD_GZIP_LARGE_BUFFER_SIZE 8192 + + char tmp[ MOD_GZIP_LARGE_BUFFER_SIZE + 2 ]; /* Scratch buffer */ + + char *actual_content_encoding_name = "gzip"; /* Adjustable */ + const char *compression_format; + + #ifdef MOD_GZIP_DEBUG1 + char cn[]="mod_gzip_encode_and_transmit()"; + #endif + + void *modconf = r->server->module_config; + + #ifdef MOD_GZIP_USES_APACHE_LOGS + char log_info[40]; /* Scratch buffer */ + #endif + + /* + * Start... + * + * Establish a local pointer to module configuration data... + */ + + mod_gzip_conf *conf = + (mod_gzip_conf *) ap_get_module_config( modconf, &gzip_module ); + + #ifdef MOD_GZIP_DEBUG1 + + mod_gzip_printf( "%s: Entry...\n", cn); + mod_gzip_printf( "%s: source_is_a_file = %d\n", cn, source_is_a_file); + mod_gzip_printf( "%s: nodecline = %d\n", cn, nodecline); + + if ( source_is_a_file ) /* Show the filename... */ + { + mod_gzip_printf( "%s: source = [%s]\n", cn, source); + } + else /* Don't try to print the memory buffer... */ + { + mod_gzip_printf( "%s: source = MEMORY BUFFER\n", cn ); + } + + mod_gzip_printf( "%s: input_size = %ld\n", cn,(long)input_size); + + #endif /* MOD_GZIP_DEBUG1 */ + + + #ifdef MOD_GZIP_USES_APACHE_LOGS + + /* This routine 'assumes' that the final result is 'OK' */ + /* and lets the remainder of the processing set the result */ + /* string to some other value, if necessary. */ + + /* Since we are now using the 'nodecline' flag and might */ + /* have to 'stand and deliver' then this allows the right */ + /* result code to appear in the log files even if we */ + /* cannot DECLINE the processing. */ + + ap_table_setn( + r->notes,"mod_gzip_result",ap_pstrdup(r->pool,"OK")); + + /* We can also update the 'input' size right away since it is known */ + + sprintf( log_info,"%d", (int) input_size ); + ap_table_setn( r->notes,"mod_gzip_input_size",ap_pstrdup(r->pool,log_info)); + + #endif /* MOD_GZIP_USES_APACHE_LOGS */ + + /* + * If the source has no length then DECLINE the processing... + */ + + if ( input_size < 1 ) + { + #ifdef MOD_GZIP_DEBUG1 + mod_gzip_printf( "%s: ERROR: Input source has no valid length.\n",cn); + mod_gzip_printf( "%s: This request will not be processed...\n",cn); + #endif + + /* An existing request object with no length is worth a warning... */ + + ap_log_error( APLOG_MARK,APLOG_NOERRNO|APLOG_WARNING, r->server, + "mod_gzip: r->filename=[%s] has no length",r->filename ); + + #ifdef MOD_GZIP_DEBUG1 + mod_gzip_printf( "%s: Exit > return( DECLINED ) >\n",cn); + #endif + + #ifdef MOD_GZIP_USES_APACHE_LOGS + + /* Each 'DECLINE' condition provides a short ':WHYTAG' for logs */ + + ap_table_setn( + r->notes,"mod_gzip_result",ap_pstrdup(r->pool,"DECLINED:NO_I_LEN")); + + #endif /* MOD_GZIP_USES_APACHE_LOGS */ + + return DECLINED; + } + + /* + * If we're only supposed to send header information (HEAD request) + * then all we need to do is call ap_send_http_header() at this point + * and then return 'OK'... + */ + + if ( r->header_only ) + { + #ifdef MOD_GZIP_DEBUG1 + mod_gzip_printf( "%s: HEAD request only... ignore body data...\n",cn); + #endif + + /* + * Set outbound response header fields... + * + * NOTE: If this is just a HEAD request then + * there is no need to make the API call... + * + * ap_update_mtime( r, r->finfo.st_mtime ); + * + * ...and update the actual time. Use the time + * that's currently associated with the object. + */ + + ap_set_last_modified(r); + ap_set_etag(r); + ap_table_setn(r->headers_out, "Accept-Ranges", "bytes"); + + /* Start a timer for this transaction... */ + + ap_soft_timeout( "mod_gzip: HEAD request handler", r ); + + #ifdef MOD_GZIP_DEBUG1 + mod_gzip_printf( "%s: r->content_type=[%s]\n",cn,r->content_type); + mod_gzip_printf( "%s: Call ap_send_http_header()...\n",cn); + #endif + + ap_send_http_header(r); + + #ifdef MOD_GZIP_DEBUG1 + mod_gzip_printf( "%s: Back ap_send_http_header()...\n",cn); + mod_gzip_printf( "%s: Call ap_kill_timeout()...\n",cn); + #endif + + ap_kill_timeout(r); + + #ifdef MOD_GZIP_DEBUG1 + mod_gzip_printf( "%s: Back ap_kill_timeout()...\n",cn); + mod_gzip_printf( "%s: Exit > return( OK ) >\n",cn); + #endif + + #ifdef MOD_GZIP_USES_APACHE_LOGS + + /* Return OK but distinguish it from a 'GET' request in logs... */ + + ap_table_setn( + r->notes,"mod_gzip_result",ap_pstrdup(r->pool,"OK:HEAD_ONLY")); + + #endif /* MOD_GZIP_USES_APACHE_LOGS */ + + return OK; + + }/* End 'if( r->header_only )' */ + + /* + * See if the source meets the MINUMUM SIZE requirement... + * + * Default to 300 bytes as a minimum size requirement for it + * to even be worth a compression attempt. This works well as a + * minimum for both GZIP and ZLIB which are both LZ77 based and, + * as such, always have the potential to actually increase the + * size of the file. + * + * The value is a module global that can be adjusted 'on the fly' + * as load conditions change or as required for other reasons. + */ + + #ifdef MOD_GZIP_DEBUG1 + mod_gzip_printf( "%s: conf->minimum_file_size = %ld\n", + cn, (long) conf->minimum_file_size ); + #endif + + if ( input_size < (long) conf->minimum_file_size ) + { + #ifdef MOD_GZIP_DEBUG1 + mod_gzip_printf( "%s: Source does not meet the minimum size requirement...\n",cn); + mod_gzip_printf( "%s: nodecline = %d\n",cn,nodecline); + #endif + + /* Set the 'mod_gzip_result' note value to something */ + /* that indicates this was too small... */ + + #ifdef MOD_GZIP_USES_APACHE_LOGS + + /* Each 'DECLINE' condition provides a short ':WHYTAG' for logs */ + + ap_table_setn( + r->notes,"mod_gzip_result",ap_pstrdup(r->pool,"DECLINED:TOO_SMALL")); + + #endif /* MOD_GZIP_USES_APACHE_LOGS */ + + /* Is it OK to DECLINE?... */ + + if ( nodecline ) /* We have been told NOT to DECLINE */ + { + #ifdef MOD_GZIP_DEBUG1 + mod_gzip_printf( "%s: DECLINE is NOT allowed...\n",cn); + #endif + + /* Skip the compression phase and just set the output */ + /* control skid up to send the real input data... */ + + output_size = input_size; + + if ( source_is_a_file ) /* Source is a workfile... */ + { + #ifdef MOD_GZIP_DEBUG1 + mod_gzip_printf( "%s: Force send - source = FILE[%s]\n", + cn,source); + #endif + + strcpy( gzp->output_filename, source ); + gzp->output_ismem = 0; /* Output is a disk file */ + gz1_ismem_obuf = 0; /* Make sure this is NULL */ + gzp->output_ismem_obuf = 0; /* Not used for this method */ + gzp->output_ismem_obuflen = 0; /* Not used for this method */ + + ifh = mod_gzip_open_output_file( r, gzp->output_filename, &rc ); + + if ( !ifh ) /* The file failed to open... */ + { + /* We really MUST decline... */ + /* Logs have already been updated... */ + + return( rc ); + } + } + else /* Source is just a memory buffer... */ + { + #ifdef MOD_GZIP_DEBUG1 + mod_gzip_printf( "%s: Force send - source = MEMORY BUFFER\n",cn); + #endif + + gzp->output_ismem = 1; + gz1_ismem_obuf = source; + + gz1_ismem_obuf_was_allocated = 0; /* No 'free' is required */ + } + + #ifdef MOD_GZIP_DEBUG1 + mod_gzip_printf( "%s: No compression attempt was made.\n",cn); + mod_gzip_printf( "%s: Advancing directly to transmit phase...\n",cn); + #endif + + goto mod_gzip_encode_and_transmit_send_start; /* Jump */ + } + else /* It's OK to DECLINE the processing... */ + { + #ifdef MOD_GZIP_DEBUG1 + mod_gzip_printf( "%s: DECLINE is allowed...\n",cn); + mod_gzip_printf( "%s: Exit > return( DECLINED ) >\n",cn); + #endif + + return DECLINED; + } + } + else /* The source is larger than the minimum size requirement... */ + { + #ifdef MOD_GZIP_DEBUG1 + mod_gzip_printf( "%s: Source meets the minimum size requirement.\n",cn); + mod_gzip_printf( "%s: Assuming OK to proceed...\n",cn); + #endif + } + + /* + * We must now encode the requested object... + * + * Statistically speaking, most 'text/*' pages are + * less than 60k. XML documents are an exception. + * + * If the size of the requested object is less than 60k + * then go ahead and compress the source directly to a + * small memory buffer. If the requested object is greater + * than 60k then go ahead and swap the results to an output + * disk file and then send the contents of the result file. + * + * We can't ever allocate all the memory we want inside of + * a Server task thread so there must always be this kind + * of 'decision' making about when we can compress to + * a memory buffer ( Less than 60k ) and when we must + * compress to DISK. ( Greater than 60k ). + * + * There is a trade-off here between running the risk of + * too many tasks stealing away all the heap space and + * still maintaining performance. Given all the variables + * involved such as the true efficiency of the compression + * algorithm(s) and the speed of the CPU and the amount of + * memory/disk space available there is no 'real' answer to + * this dilemma other than relying on statistical data + * and empirical observations. The 60k limit on in-memory + * compression seems to strike a good balance and performs + * incredibly well under the heaviest of loads. + * + * At all times, the greatest benefit being gained is the + * appreciable reduction of data that must actually be + * sent by the TCP/IP sub-system and the reduced usage + * of those resources to perform the transmission task(s), + * + * The key, then, is to always strive for a balance where + * the time and resource usage it takes to compress a + * deliverable object will always be less than the processor + * burden that would otherwise be realized by handing the + * full, uncompressed object to the TCP/IP sub-system which + * always extend the time that the thread and all its + * locked resources must be maintained as well as the + * overhead for keeping a connection active any longer + * than is absolutely necessary. + * + * As long as the resource usage it takes to accomplish + * a significant reduction in the amount of data that + * must actually be processed by the remainder of the + * HTTP task thread and the TCP/IP sub-system itself + * is always less than the processor burden seen by + * NOT doing so then we are always 'ahead of the game'. + */ + + /* + * See if the object size exceeds the current MAXIMUM size + * to use for in-memory compression... + * + * See notes above about a range of 60k or so being the best + * value for heavy load conditions. + * + * This number is currently a global so it can be changed + * 'on the fly' and can 'breathe' as the load changes. + * It should probably become a thread specific variable + * so each task can have its 'own' max value depending + * on current load conditions. + */ + + #ifdef MOD_GZIP_DEBUG1 + mod_gzip_printf( "%s: conf->maximum_inmem_size = %ld\n", + cn, (long) conf->maximum_inmem_size ); + #endif + + /* + * Set up the INPUT target... + */ + + /* The size and type of the input source is always known */ + /* and was passed by the caller... */ + + if ( source_is_a_file ) + { + #ifdef MOD_GZIP_DEBUG1 + mod_gzip_printf( "%s: Input source is file[%s]\n",cn,source); + #endif + + strcpy( gzp->input_filename, source ); + + gzp->input_ismem = 0; /* Input is a disk file */ + gzp->input_ismem_ibuf = 0; /* Source buffer */ + gzp->input_ismem_ibuflen = 0; /* Length of data */ + } + else + { + #ifdef MOD_GZIP_DEBUG1 + mod_gzip_printf( "%s: Input source is a MEMORY BUFFER\n",cn); + #endif + + *gzp->input_filename = 0; /* Not used */ + + gzp->input_ismem = 1; /* Input is a memory buffer */ + gzp->input_ismem_ibuf = source; /* Source buffer */ + gzp->input_ismem_ibuflen = input_size; /* Length of data */ + } + + /* + * Set up the OUTPUT target... + */ + + gzp->decompress = 0; /* Perform encoding */ + + /* Recover the compression format we're supposed to use. */ + compression_format = ap_table_get(r->notes, "mod_gzip_compression_format"); + if (compression_format && strcmp(compression_format, "deflate") == 0) + { + actual_content_encoding_name = "deflate"; + gzp->compression_format = DEFLATE_FORMAT; + } + else + { + gzp->compression_format = GZIP_FORMAT; + } + + if ( input_size <= (long) conf->maximum_inmem_size ) + { + /* The input source is small enough to compress directly */ + /* to an in-memory output buffer... */ + + #ifdef MOD_GZIP_DEBUG1 + mod_gzip_printf( "%s: Input source is small enough for in-memory compression.\n",cn); + #endif + + *gzp->output_filename = 0; /* Not used */ + gzp->output_ismem = 1; /* Output is a memory buffer */ + + /* + * Allocate a memory buffer to hold compressed output. + * + * For now this is borrowed from the heap for only + * the lifetime of this function call. If the stack + * can handle the current in-memory MAXSIZE then + * that will work just as well. + * + * Add at least 1000 bytes in case the compression + * algorithm(s) actually expands the source ( which is + * not likely but is always a possibility when using + * any LZ77 based compression such as GZIP or ZLIB ) + */ + + gz1_ismem_obuf = (char *) malloc( input_size + 1000 ); + + if ( !gz1_ismem_obuf ) + { + /* + * There wasn't enough memory left for another + * in-memory compression buffer so default to using + * an output disk file instead... + */ + + #ifdef MOD_GZIP_DEBUG1 + mod_gzip_printf( "%s: ERROR: Cannot allocate GZP memory...\n",cn); + mod_gzip_printf( "%s: Defaulting to output file method... \n",cn); + #endif + + gzp->output_ismem = 0; /* Switch to using a disk file */ + } + + else /* We got the memory we need for in-memory compression... */ + { + /* Set the local flag which tells the exit logic */ + /* that 'gz1_ismem_obuf' was actually allocated */ + /* and not simply set to 'source' so that the */ + /* allocation can be 'freed' on exit... */ + + gz1_ismem_obuf_was_allocated = 1; /* 'free' is required */ + + /* Compression codecs require a 'clean' buffer so */ + /* we need to spend the cycles for a memset() call. */ + + memset( gz1_ismem_obuf, 0, ( input_size + 1000 ) ); + + /* Set OUTPUT buffer control variables... */ + + gzp->output_ismem_obuf = gz1_ismem_obuf; + gzp->output_ismem_obuflen = input_size + 1000; + } + + }/* End 'if ( input_size <= conf->maximum_inmem_size )' */ + + /* + * If we are unable ( or it is unadvisable ) to use + * an in-memory output buffer at this time then the + * 'gzp->output_ismem' flag will still be ZERO at this point. + */ + + if ( gzp->output_ismem != 1 ) + { + /* + * The input source is NOT small enough to compress to an + * in-memory output buffer or it is unadvisable to do + * so at this time so just use an output file... + */ + + #ifdef MOD_GZIP_DEBUG1 + mod_gzip_printf( "%s: Input source too big for in-memory compression.\n",cn); + #endif + + /* + * Create the GZP output target name... + */ + + mod_gzip_create_unique_filename( + (mod_gzip_conf *) conf, + (char *) gzp->output_filename, + MOD_GZIP_MAX_PATH_LEN + ); + + /* + * COMPRESSION OBJECT CACHE + * + * TODO: Obviously one place to add the compression cache + * logic is right here. If there is already a pre-compressed + * version of the requested entity sitting in the special + * compression cache and it is 'fresh' then go ahead and + * send it as the actual response. Add a CRC/MD5 checksum + * to the stored compression object(s) so we can quickly + * determine if the compressed object is 'fresh'. Relying + * on Content-length and/or modification time/date won't handle + * all possible expiration scenarios for compressed objects. + */ + + gzp->output_ismem = 0; /* Output is a disk file */ + + gz1_ismem_obuf = 0; /* Make sure this is NULL */ + + /* Set OUTPUT buffer control variables... */ + + gzp->output_ismem_obuf = 0; /* Not used for this method */ + gzp->output_ismem_obuflen = 0; /* Not used for this method */ + + }/* End 'else' */ + + #ifdef MOD_GZIP_DEBUG1 + mod_gzip_printf( "%s: gzp->decompress = %d\n" ,cn,gzp->decompress); + mod_gzip_printf( "%s: gzp->compression_format = %d\n",cn,gzp->compression_format); + mod_gzip_printf( "%s: gzp->input_ismem = %d\n", cn,gzp->input_ismem); + mod_gzip_printf( "%s: gzp->output_ismem = %d\n", cn,gzp->output_ismem); + mod_gzip_printf( "%s: gzp->input_filename = [%s]\n",cn,gzp->input_filename); + mod_gzip_printf( "%s: gzp->output_filename = [%s]\n",cn,gzp->output_filename); + mod_gzip_printf( "%s: Call gzp_main()...\n",cn); + #endif + + rc = gzp_main( gzp ); /* Perform the compression... */ + + output_size = (long) gzp->bytes_out; + + #ifdef MOD_GZIP_DEBUG1 + mod_gzip_printf( "%s: Back gzp_main()...\n",cn); + mod_gzip_printf( "%s: input_size = %ld\n",cn,(long)input_size); + mod_gzip_printf( "%s: output_size = %ld\n",cn,(long)output_size); + mod_gzip_printf( "%s: gzp->bytes_out = %ld\n",cn,(long)gzp->bytes_out); + mod_gzip_printf( "%s: Bytes saved = %ld\n",cn, + (long)input_size-gzp->bytes_out ); + #endif + + /* Compute the compresion ratio for access.log and */ + /* internal statistics update... */ + + compression_ratio = 0; /* Reset */ + + /* Prevent 'Divide by zero' error... */ + + if ( ( input_size > 0 ) && + ( output_size > 0 ) ) + { + compression_ratio = 100 - (int) + ( output_size * 100L / input_size ); + } + + #ifdef MOD_GZIP_DEBUG1 + mod_gzip_printf( "%s: Compression ratio = %ld percent\n",cn, + (long) compression_ratio ); + #endif + + /* + * Update the logs with output size information + * as soon as it is known in case there was an + * error or we must DECLINE. At least the logs + * will then show the sizes and the results. + */ + + #ifdef MOD_GZIP_USES_APACHE_LOGS + + sprintf( log_info,"%d", (int) output_size ); + ap_table_setn( r->notes,"mod_gzip_output_size",ap_pstrdup(r->pool,log_info)); + + sprintf( log_info,"%d", (int) compression_ratio ); + ap_table_setn( r->notes,"mod_gzip_compression_ratio",ap_pstrdup(r->pool,log_info)); + + #endif /* MOD_GZIP_USES_APACHE_LOGS */ + + /* + * Evaluate the compression result(s)... + * + * If the compression pass failed then the output length + * will be ZERO bytes... + */ + + if ( output_size < 1 ) + { + #ifdef MOD_GZIP_DEBUG1 + mod_gzip_printf( "%s: Compressed version has no length.\n",cn); + mod_gzip_printf( "%s: Sending the original version uncompressed...\n",cn); + #endif + + finalize_stats = 0; /* Don't update stats again */ + + if ( r->server->loglevel == APLOG_DEBUG ) + { + ap_log_error( "",0,APLOG_NOERRNO|APLOG_DEBUG, r->server, + "mod_gzip: gzp_main(ERR): r->uri=[%s] input_size=%ld output_size=%ld gzp->output_filename=[%s]", + r->uri,(long)input_size,(long)output_size,gzp->output_filename); + } + + /* + * NOTE: It's perfectly possible that we have made it all + * the way to here and the straight execution of the + * compressor is the first time there has been a check for + * the actual existence of the requested object. This will + * be especially true for STATIC requests. + * + * The compressor itself will fail if/when it can't find + * the input target so 'DECLINED:NO_O_LEN' could simply + * means the file was not found. In these cases the Apache + * logs should also contain the correct '404 Not Found' code. + */ + + #ifdef MOD_GZIP_USES_APACHE_LOGS + + /* Each 'DECLINE' condition provides a short ':WHYTAG' for logs */ + + ap_table_setn( + r->notes,"mod_gzip_result",ap_pstrdup(r->pool,"DECLINED:NO_O_LEN")); + + #endif /* MOD_GZIP_USES_APACHE_LOGS */ + + /* Is it OK to DECLINE?... */ + + if ( nodecline ) /* We have been told NOT to DECLINE... */ + { + #ifdef MOD_GZIP_DEBUG1 + mod_gzip_printf( "%s: DECLINE is NOT allowed...\n",cn); + #endif + + /* Just set the output control skid */ + /* to send the real input data... */ + + output_size = input_size; + + if ( source_is_a_file ) /* Source is a workfile... */ + { + strcpy( gzp->output_filename, source ); + + gzp->output_ismem = 0; /* Output is a disk file */ + gz1_ismem_obuf = 0; /* Make sure this is NULL */ + gzp->output_ismem_obuf = 0; /* Not used for this method */ + gzp->output_ismem_obuflen = 0; /* Not used for this method */ + + ifh = mod_gzip_open_output_file( r, gzp->output_filename, &rc ); + + if ( !ifh ) /* We really must DECLINE... */ + { + return( rc ); + } + } + else /* Source is just a memory buffer... */ + { + gzp->output_ismem = 1; + gz1_ismem_obuf = source; + } + + #ifdef MOD_GZIP_DEBUG1 + mod_gzip_printf( "%s: Advancing directly to transmit phase...\n",cn); + #endif + + goto mod_gzip_encode_and_transmit_send_start; /* Jump */ + } + else /* It's OK to DECLINE the processing... */ + { + #ifdef MOD_GZIP_DEBUG1 + mod_gzip_printf( "%s: DECLINE is allowed...\n",cn); + mod_gzip_printf( "%s: Exit > return( DECLINED ) >\n",cn); + #endif + + /* Free the local memory buffer allocation ( if necessary )... */ + + if ( gz1_ismem_obuf ) + { + /* The pointer may have been 'borrowed' and was */ + /* not actually 'allocated' so check the flag... */ + + if ( gz1_ismem_obuf_was_allocated ) + { + free( gz1_ismem_obuf ); + + gz1_ismem_obuf = 0; + gz1_ismem_obuf_was_allocated = 0; + + }/* End 'if( gz1_ismem_obuf_was_allocated )' */ + + }/* End 'if( gz1_ismem_obuf )' */ + + /* Return... */ + + return DECLINED; + } + + }/* End 'if( output_size < 1 )' */ + + /* + * If we reach this point then the compressed version has + * a valid length. Time to see if it it's worth sending. + * + * If the original source is SMALLER than the COMPRESSED + * version ( not likely but possible with LZ77 ) then + * just punt and send the original source... + */ + + if ( output_size > input_size ) + { + #ifdef MOD_GZIP_DEBUG1 + mod_gzip_printf( "%s: Compressed version is larger than original.\n",cn); + mod_gzip_printf( "%s: Sending the original version uncompressed...\n",cn); + #endif + + finalize_stats = 0; /* Don't update stats again */ + + #ifdef MOD_GZIP_USES_APACHE_LOGS + + /* Each 'DECLINE' condition provides a short ':WHYTAG' for logs */ + + ap_table_setn( + r->notes,"mod_gzip_result",ap_pstrdup(r->pool,"DECLINED:ORIGINAL_SMALLER")); + + #endif /* MOD_GZIP_USES_APACHE_LOGS */ + + /* Is it OK to DECLINE?... */ + + if ( nodecline ) /* We have been told NOT to DECLINE... */ + { + #ifdef MOD_GZIP_DEBUG1 + mod_gzip_printf( "%s: DECLINE is NOT allowed...\n",cn); + #endif + + /* Just set the output control skid */ + /* to send the real input data... */ + + output_size = input_size; + + if ( source_is_a_file ) /* Source is a workfile... */ + { + strcpy( gzp->output_filename, source ); + + gzp->output_ismem = 0; /* Output is a disk file */ + gz1_ismem_obuf = 0; /* Make sure this is NULL */ + gzp->output_ismem_obuf = 0; /* Not used for this method */ + gzp->output_ismem_obuflen = 0; /* Not used for this method */ + + ifh = mod_gzip_open_output_file( r, gzp->output_filename, &rc ); + + if ( !ifh ) /* We really must DECLINE... */ + { + return( rc ); + } + } + else /* Source is just a memory buffer... */ + { + gzp->output_ismem = 1; + gz1_ismem_obuf = source; + + gz1_ismem_obuf_was_allocated = 0; /* No 'free' is required */ + } + + #ifdef MOD_GZIP_DEBUG1 + mod_gzip_printf( "%s: Advancing directly to transmit phase...\n",cn); + #endif + + goto mod_gzip_encode_and_transmit_send_start; /* Jump */ + } + else /* It's OK to DECLINE the processing... */ + { + #ifdef MOD_GZIP_DEBUG1 + mod_gzip_printf( "%s: DECLINE is allowed...\n",cn); + mod_gzip_printf( "%s: Exit > return( DECLINED ) >\n",cn); + #endif + + /* Free the local memory buffer allocation ( if necessary )... */ + + if ( gz1_ismem_obuf ) + { + /* The pointer may have been 'borrowed' and was */ + /* not actually 'allocated' so check the flag... */ + + if ( gz1_ismem_obuf_was_allocated ) + { + free( gz1_ismem_obuf ); + + gz1_ismem_obuf = 0; + gz1_ismem_obuf_was_allocated = 0; + + }/* End 'if( gz1_ismem_obuf_was_allocated )' */ + + }/* End 'if( gz1_ismem_obuf )' */ + + /* Return... */ + + return DECLINED; + } + } + else /* Compressed version is smaller than original... */ + { + #ifdef MOD_GZIP_DEBUG1 + mod_gzip_printf( "%s: Compressed version is smaller than original.\n",cn); + mod_gzip_printf( "%s: Sending the compressed version...\n",cn); + #endif + } + + /* + * If an output workfile was used then make SURE it is going + * to reopen before beginning the transmit phase. + * + * If we begin the transmit phase before discovering a problem + * re-opening the workfile then we have lost the chance to + * DECLINE the processing and allow the default logic to + * deliver the requested object. + * + * This only matters for 'static' files or times when the + * 'nodecline' flag is FALSE and it is actually OK to DECLINE. + */ + + if ( !gzp->output_ismem ) /* Workfile was used... */ + { + #ifdef MOD_GZIP_DEBUG1 + mod_gzip_printf( "%s: Opening compressed output file [%s]...\n", + cn, gzp->output_filename ); + #endif + + ifh = mod_gzip_open_output_file( r, gzp->output_filename, &rc ); + + if ( !ifh ) /* The file failed to open... */ + { + #ifdef MOD_GZIP_DEBUG1 + mod_gzip_printf( "%s: ERROR: Cannot re-open file [%s]\n", + cn,gzp->output_filename); + #endif + + /* We really must DECLINE... */ + /* Logs have already been updated... */ + + #ifdef MOD_GZIP_DEBUG1 + mod_gzip_printf( "%s: Exit > return( DECLINED ) >\n",cn); + #endif + + return DECLINED; + + }/* End 'if ( !ifh )' */ + + #ifdef MOD_GZIP_DEBUG1 + mod_gzip_printf( "%s: Workile re-opened OK...\n",cn); + #endif + + }/* End 'if ( !gzp->output_ismem )' */ + + /* + * IMPORTANT + * + * If we have made it to here then all is well and only + * now can we set the encoding for this response... + * + * We must do this 'above' any jump points that might + * be sending the 'untouched' data or the browser will + * get confused regarding the actual content. + */ + + r->content_encoding = actual_content_encoding_name; + + #ifdef MOD_GZIP_DEBUG1 + mod_gzip_printf( "%s: r->content_encoding is now [%s]\n", + cn, r->content_encoding ); + #endif + + /* + * Begin the transmission phase... + * + * Even if the 'nodecline' flag is TRUE if we encounter + * any fatal errors at this point we must 'DECLINE'. + */ + + mod_gzip_encode_and_transmit_send_start: ; /* <<-- Jump point */ + + #ifdef MOD_GZIP_DEBUG1 + mod_gzip_printf( "%s: Starting transmit phase...\n",cn); + #endif + + /* + * We are ready to send content so update the "Content-length:" + * response field and send the HTTP header. We don't need to + * worry about setting the "Content-type:" field since we are + * simply accepting the value that was passed to us as indicated + * by the inbound r->content_type string. The "Content-type:" + * field never changes even when multiple encodings have been + * applied to the content itself. + * + * This version does not make any attempt to use 'Chunked' + * transfer encoding since there are so many user agents that + * do not support it and when Content-length is known prior + * to header transmission ( as is always the case with this + * code ) then there is simply no reason to even think about + * using the slower and more problematic 'Chunked' encoding + * transfer method. + */ + + /* + * Set relevant outbound response header fields... + * + * Be sure to call ap_update_mtime() before calling + * ap_set_last_modified() to be sure the 'current' + * time is actually updated in outbound response header. + */ + + ap_update_mtime( r, r->finfo.st_mtime ); + ap_set_last_modified(r); + ap_set_etag(r); + ap_table_setn(r->headers_out, "Accept-Ranges", "bytes"); + + /* + * Start a timer for this transaction... + */ + + ap_soft_timeout( "mod_gzip: Encoded data transmit", r ); + + /* + * Return the length of the compressed output in + * the response header. + * + * See notes above about there never being a requirement + * to use 'Chunked' transfer encoding since the content + * length is always 'known' prior to transmission. + */ + + sprintf( content_length, "%ld", output_size ); + ap_table_set (r->headers_out, "Content-Length", content_length ); + + #ifdef MOD_GZIP_DEBUG1 + mod_gzip_printf( "%s: output_size = %ld\n",cn,(long)output_size); + mod_gzip_printf( "%s: r->content_type = [%s]\n",cn,r->content_type); + mod_gzip_printf( "%s: Call ap_send_http_header()...\n",cn); + #endif + + ap_send_http_header(r); + + #ifdef MOD_GZIP_DEBUG1 + mod_gzip_printf( "%s: Back ap_send_http_header()...\n",cn); + #endif + + /* + * Send the response... + * + * If the requested object was small enough to fit into + * our special in-memory output space then send the result + * directly from memory. If the requested object exceeded + * the minimum size for in-memory compression then an output + * file was used so re-open and send the results file... + */ + + if ( gzp->output_ismem ) + { + /* Send the in-memory output buffer... */ + + #ifdef MOD_GZIP_DEBUG1 + + mod_gzip_printf( "%s: Sending the in-memory output buffer...\n",cn); + mod_gzip_printf( "%s: output_size = %ld\n",cn,(long)output_size); + + /* Turn this 'on' for VERY verbose diagnostics... + #define MOD_GZIP_DUMP_JUST_BEFORE_SENDING + */ + #ifdef MOD_GZIP_DUMP_JUST_BEFORE_SENDING + mod_gzip_hexdump( gz1_ismem_obuf, output_size ); + #endif + + #endif /* MOD_GZIP_DEBUG1 */ + + /* This module can use either ap_send_mmap() or ap_rwrite()... */ + + #ifdef MOD_GZIP_USES_AP_SEND_MMAP + + /* Use ap_send_mmap() call to send the data... */ + + #ifdef MOD_GZIP_DEBUG1 + mod_gzip_printf( "%s: Call ap_send_mmap( gz1_ismem_obuf, bytes=%ld )...\n", + cn, (long)output_size ); + #endif + + ap_send_mmap( gz1_ismem_obuf, r, 0, output_size ); + + #ifdef MOD_GZIP_DEBUG1 + mod_gzip_printf( "%s: Back ap_send_mmap( gz1_ismem_obuf, bytes=%ld )...\n", + cn, (long)output_size ); + #endif + + #else /* !MOD_GZIP_USES_AP_SEND_MMAP */ + + /* Use ap_rwrite() call to send the data... */ + + #ifdef MOD_GZIP_DEBUG1 + mod_gzip_printf( "%s: Call ap_rwrite( gz1_ismem_obuf, bytes=%ld )...\n", + cn, (long)output_size ); + #endif + + ap_rwrite( gz1_ismem_obuf, output_size, r ); + + #ifdef MOD_GZIP_DEBUG1 + mod_gzip_printf( "%s: Back ap_rwrite( gz1_ismem_obuf, bytes=%ld )...\n", + cn, (long)output_size ); + #endif + + #endif /* MOD_GZIP_USES_AP_SEND_MMAP */ + + /* Stop the timer... */ + + #ifdef MOD_GZIP_DEBUG1 + mod_gzip_printf( "%s: Call ap_kill_timeout()...\n",cn); + #endif + + ap_kill_timeout(r); + + #ifdef MOD_GZIP_DEBUG1 + mod_gzip_printf( "%s: Back ap_kill_timeout()...\n",cn); + #endif + + /* Free the local memory buffer allocation ( if necessary )... */ + + if ( gz1_ismem_obuf ) + { + /* The pointer may have been 'borrowed' and was */ + /* not actually 'allocated' so check the flag... */ + + if ( gz1_ismem_obuf_was_allocated ) + { + free( gz1_ismem_obuf ); + + gz1_ismem_obuf = 0; + gz1_ismem_obuf_was_allocated = 0; + + }/* End 'if( gz1_ismem_obuf_was_allocated )' */ + + }/* End 'if( gz1_ismem_obuf )' */ + } + else /* Output workfile was used so send the contents... */ + { + /* + * NOTE: The workfile was already 're-opened' up above + * before the transmit phase began so that we still had + * the chance to return DECLINED if, for some reason, the + * workfile could not be re-opened. + */ + + #ifdef MOD_GZIP_DEBUG1 + mod_gzip_printf( "%s: sizeof( tmp ) = %d\n",cn,sizeof(tmp)); + mod_gzip_printf( "%s: Transmit buffer size = %d\n",cn,sizeof(tmp)); + mod_gzip_printf( "%s: Sending compressed output file...\n",cn); + #endif + + for (;;) + { + bytesread = fread( tmp, 1, sizeof( tmp ), ifh ); + + #ifdef MOD_GZIP_DEBUG1 + mod_gzip_printf( "%s: Back fread(): bytesread=%d\n",cn,bytesread); + #endif + + if ( bytesread < 1 ) break; /* File is exhausted... We are done...*/ + + /* This module can use either ap_send_mmap() or ap_rwrite()... */ + + #ifdef MOD_GZIP_USES_AP_SEND_MMAP + + /* Use ap_send_mmap() call to send the data... */ + + ap_send_mmap( tmp, r, 0, bytesread ); + + #else /* !MOD_GZIP_USES_AP_SEND_MMAP */ + + /* Use ap_rwrite() call to send the data... */ + + ap_rwrite( tmp, bytesread, r ); + + #endif /* MOD_GZIP_USES_AP_SEND_MMAP */ + } + + #ifdef MOD_GZIP_DEBUG1 + mod_gzip_printf( "%s: Done Sending compressed output file...\n",cn); + mod_gzip_printf( "%s: Closing workfile [%s]...\n", + cn, gzp->output_filename ); + #endif + + fclose( ifh ); /* Close the input file */ + + /* Stop the timer before attempting to delete the workfile... */ + + #ifdef MOD_GZIP_DEBUG1 + mod_gzip_printf( "%s: Call ap_kill_timeout()...\n",cn); + #endif + + ap_kill_timeout(r); + + #ifdef MOD_GZIP_DEBUG1 + mod_gzip_printf( "%s: Back ap_kill_timeout()...\n",cn); + #endif + + /* Delete the workfile if 'keep' flag is OFF... */ + + #ifdef MOD_GZIP_DEBUG1 + mod_gzip_printf( "%s: conf->keep_workfiles = %d\n", + cn, conf->keep_workfiles ); + #endif + + if ( !conf->keep_workfiles ) /* Default is OFF */ + { + #ifdef MOD_GZIP_DEBUG1 + mod_gzip_printf( "%s: Deleting workfile [%s]...\n", + cn, gzp->output_filename ); + #endif + + #ifdef WIN32 + DeleteFile( gzp->output_filename ); + #else /* !WIN32 */ + unlink( gzp->output_filename ); + #endif /* WIN32 */ + } + else /* Keep all work files... */ + { + #ifdef MOD_GZIP_DEBUG1 + mod_gzip_printf( "%s: Keeping workfile [%s]...\n", + cn, gzp->output_filename ); + #endif + } + + }/* End 'else' that sends compressed workfile */ + + /* + * The compressed object has been sent... + */ + + #ifdef MOD_GZIP_USES_APACHE_LOGS + + if ( finalize_stats ) + { + sprintf( log_info,"%d", (int) output_size ); + ap_table_setn( r->notes,"mod_gzip_output_size",ap_pstrdup(r->pool,log_info)); + + sprintf( log_info,"%d", (int) compression_ratio ); + ap_table_setn( r->notes,"mod_gzip_compression_ratio",ap_pstrdup(r->pool,log_info)); + + } + #endif /* MOD_GZIP_USES_APACHE_LOGS */ + + if ( r->server->loglevel == APLOG_DEBUG ) + { + /* + * If LogLevel is 'debug' then show the compression results + * in the log(s)... + */ + + ap_log_error( "",0,APLOG_NOERRNO|APLOG_DEBUG, r->server, + "mod_gzip: r->uri=[%s] OK: Bytes In:%ld Out:%ld Compression: %ld pct.", + r->uri, + (long) input_size, + (long) output_size, + (long) compression_ratio + ); + + }/* End 'if( r->server->loglevel == APLOG_DEBUG )' */ + + /* + * Return OK to the Server to indicate SUCCESS... + */ + + #ifdef MOD_GZIP_DEBUG1 + mod_gzip_printf( "%s: Exit > return( OK ) >\n",cn); + #endif + + return OK; + +}/* End of mod_gzip_encode_and_transmit() */ + +int mod_gzip_ismatch( char *s1, char *s2, int len1, int haswilds ) +{ + /* Behaves just like strncmp() but IGNORES differences */ + /* between FORWARD or BACKWARD slashes in a STRING, allows */ + /* wildcard matches, and can ignore length value. */ + /* It uses pointers and is faster than using lib calls. */ + + /* Unlike strncmp() this routine returns TRUE (1) if the */ + /* strings match and FALSE (0) if they do not... */ + + int i; + int l1; + int l2; + int distance; + char ch1; + char ch2; + + /* WARNING! We MUST have a check for 'NULL' on the pointer(s) */ + /* themselves or we might GP */ + + if ( ( s1 == 0 ) || ( s2 == 0 ) ) + { + /* SAFETY! If pointer itself if NULL */ + /* don't enter LOOP... */ + + return( 0 ); /* Return FALSE for NOMATCH... */ + } + + distance = len1; /* Default to value passed... */ + + /* If no length was given then the 2 strings must already */ + /* have the same length or this is a 'no match'... */ + /* Exception to this is if wildcards are present. */ + + if ( len1 == 0 ) + { + l1 = strlen( s1 ); + l2 = strlen( s2 ); + + /* If either string had a valid pointer but is EMPTY */ + /* then this is an automatic 'no match'... */ + + if ((l1==0)||(l2==0)) + { + return( 0 ); /* Return FALSE for NOMATCH... */ + } + + if ( l1 != l2 ) + { + if ( haswilds == 0 ) + { + return( 0 ); /* Return FALSE for NOMATCH... */ + } + } + + /* If the lengths ARE equal then this is a possible */ + /* match. Use the smaller of the 2 values for scan...*/ + + if ( l1 < l2 ) distance = l1; + else distance = l2; + } + + /* Final check... if distance is still 0 then this */ + /* is an automatic 'no match'... */ + + if ( distance == 0 ) + { + return( 0 ); /* Return FALSE for NOMATCH... */ + } + + /* Do the deed... */ + + for ( i=0; icontent_type ) clen = strlen( r->content_type ); + if ( r->handler ) hlen = strlen( r->handler ); + + if ( r->filename ) + { + flen = strlen( r->filename ); + p1 = r->filename; + while(*p1!=0){if (*p1=='.') file_extension=p1; p1++;} + if ( file_extension ) file_extension_len = strlen( file_extension ); + } + + #ifdef MOD_GZIP_DEBUG1 + + mod_gzip_printf( "%s: Entry...\n",cn); + mod_gzip_printf( "%s: r->content_type = [%s]\n",cn,r->content_type); + mod_gzip_printf( "%s: clen = %d\n", cn,clen); + mod_gzip_printf( "%s: r->handler = [%s]\n",cn,r->handler); + mod_gzip_printf( "%s: hlen = %d\n", cn,hlen); + mod_gzip_printf( "%s: r->filename = [%s]\n",cn,r->filename); + mod_gzip_printf( "%s: flen = %d\n", cn,flen); + mod_gzip_printf( "%s: file_extension = [%s]\n",cn,file_extension); + mod_gzip_printf( "%s: file_extension_len = %d\n", cn,file_extension_len); + + #endif /* MOD_GZIP_DEBUG1 */ + + /* + * Sanity checks... + */ + + if ( ( hlen == 0 ) && ( clen == 0 ) ) + { + /* + * If the header analysis and/or negotiation phase has + * determined this to be a CGI script then the r->content_type + * field will be (null) but r->handler will contain "cgi-script". + * or "php-script" or the like. + * + * If the analysis has determined this is a static file + * then r->handler will be (null) but the r->content_type + * field will be "text/html" or "text/plain" or whatever. + * + * Both the r->content_type field and the r->handler + * field are empty. Ignore this one... + */ + + #ifdef MOD_GZIP_DEBUG1 + mod_gzip_printf( "%s: Both hlen and clen are ZERO...\n",cn); + mod_gzip_printf( "%s: Exit > return( MOD_GZIP_IMAP_DECLINED1 ) >\n",cn); + #endif + + if ( r->server->loglevel == APLOG_DEBUG ) + { + ap_log_error( "",0,APLOG_NOERRNO|APLOG_DEBUG, r->server, + "mod_gzip: There is no valid r->handler or r->content_length "); + } + + return( MOD_GZIP_IMAP_DECLINED1 ); + } + + /* + * Perform 2 passes at the Include/Exclude list... + * + * The first pass is the higher-priority EXCLUSION check. + * The second pass is the lower-priority INCLUSION check. + */ + + for ( pass=0; pass<2; pass++ ) + { + + pass_result = 0; /* Reset result */ + + if ( pass == 0 ) /* EXCLUSION CHECK */ + { + filter_value = 0; + + #ifdef MOD_GZIP_DEBUG1 + mod_gzip_printf( "%s: EXCLUSION CHECK...\n",cn); + #endif + } + else if ( pass == 1 ) /* INCLUSION CHECK */ + { + filter_value = 1; + + #ifdef MOD_GZIP_DEBUG1 + mod_gzip_printf( "%s: INCLUSION CHECK...\n",cn); + #endif + } + + #ifdef MOD_GZIP_DEBUG1 + mod_gzip_printf( "%s: pass = %d\n", cn, pass ); + mod_gzip_printf( "%s: filter_value = %d\n", cn, filter_value ); + mod_gzip_printf( "%s: mgc->imap_total_entries = %d\n", cn, + (int) mgc->imap_total_entries ); + #endif + + for ( x=0; ximap_total_entries; x++ ) + { + if ( r->server->loglevel == APLOG_DEBUG ) + { + /* Show the lookups in the Apache ERROR log if DEBUG is on */ + + ap_log_error( "",0,APLOG_NOERRNO|APLOG_DEBUG, r->server, + "mod_gzip: mgc->imap[%3.3d] = i%2.2d t%4.4d a%4.4d n[%s]", + x, + mgc->imap[x].include, + mgc->imap[x].type, + mgc->imap[x].action, + mgc->imap[x].name + ); + } + + #ifdef MOD_GZIP_DEBUG1 + + mod_gzip_printf( "%s: --------------------------------------------\n",cn); + mod_gzip_printf( "%s: r->handler = [%s]\n",cn,r->handler); + mod_gzip_printf( "%s: r->content_type = [%s]\n",cn,r->content_type); + mod_gzip_printf( "%s: r->filename = [%s]\n",cn,r->filename); + mod_gzip_printf( "%s: file_extension = [%s]\n",cn,file_extension); + mod_gzip_printf( "%s: mgc->imap[%3.3d].include = %d\n",cn,x,mgc->imap[x].include); + mod_gzip_printf( "%s: mgc->imap[%3.3d].type = %d\n",cn,x,mgc->imap[x].type); + + if ( mgc->imap[x].type == MOD_GZIP_IMAP_ISMIME ) + { + mod_gzip_printf( "%s: mgc->imap[%3.3d].type = MOD_GZIP_IMAP_ISMIME\n",cn,x); + } + else if ( mgc->imap[x].type == MOD_GZIP_IMAP_ISEXT ) + { + mod_gzip_printf( "%s: mgc->imap[%3.3d].type = MOD_GZIP_IMAP_ISEXT\n",cn,x); + } + else if ( mgc->imap[x].type == MOD_GZIP_IMAP_ISHANDLER ) + { + mod_gzip_printf( "%s: mgc->imap[%3.3d].type = MOD_GZIP_IMAP_ISHANDLER\n",cn,x); + } + else /* Unrecognized item type... */ + { + mod_gzip_printf( "%s: mgc->imap[%3.3d].type = MOD_GZIP_IMAP_IS??? Unknown type\n",cn,x); + } + + mod_gzip_printf( "%s: mgc->imap[%3.3d].action = %d\n", cn,x,mgc->imap[x].action); + + if ( mgc->imap[x].action == MOD_GZIP_IMAP_DYNAMIC1 ) + { + mod_gzip_printf( "%s: mgc->imap[%3.3d].action = MOD_GZIP_IMAP_DYNAMIC1\n",cn,x); + } + else if ( mgc->imap[x].action == MOD_GZIP_IMAP_STATIC1 ) + { + mod_gzip_printf( "%s: mgc->imap[%3.3d].action = MOD_GZIP_IMAP_STATIC1\n",cn,x); + } + else /* Unrecognized action type... */ + { + mod_gzip_printf( "%s: mgc->imap[%3.3d].action = MOD_GZIP_IMAP_??? Unknown action\n",cn,x); + } + + mod_gzip_printf( "%s: mgc->imap[%3.3d].name = [%s]\n",cn,x,mgc->imap[x].name); + + #endif /* MOD_GZIP_DEBUG1 */ + + /* 'filter_value' mirrors 'pass' value for now but this might */ + /* not always be true. First pass is EXCLUDE and second is INCLUDE */ + + if ( mgc->imap[x].include == filter_value ) + { + #ifdef MOD_GZIP_DEBUG1 + mod_gzip_printf( "%s: This record matches filter_value %d\n", + cn, filter_value ); + mod_gzip_printf( "%s: The record will be checked...\n",cn); + #endif + + /* + * Set work values for this record... + */ + + this_type = mgc->imap[x].type; + this_action = mgc->imap[x].action; + this_name = mgc->imap[x].name; + + /* + * If the header analysis and/or negotiation phase has + * determined this to be a CGI script then the r->content_type + * field will be (null) but r->handler will contain "cgi-script". + * + * If the analysis has determined this is a static file + * then r->handler will be (null) but the r->content_type + * field will be "text/html" or "text/plain" or whatever. + */ + + if ( hlen > 0 ) /* r->handler field has a value... */ + { + #ifdef MOD_GZIP_DEBUG1 + mod_gzip_printf( "%s: hlen has value...\n",cn); + #endif + + if ( this_type == MOD_GZIP_IMAP_ISHANDLER ) + { + #ifdef MOD_GZIP_DEBUG1 + mod_gzip_printf( "%s: this_type = ISHANDLER\n",cn); + mod_gzip_printf( "%s: Call mod_gzip_ismatch(%s,%s,0,0)...\n", + cn, this_name, r->handler ); + #endif + + /* mod_gzip_ismatch()... */ + + /* The 2 strings must match exactly so */ + /* pass '0' for parm 3... */ + + /* Wildcard matches are not allowed for */ + /* handler strings like 'cgi-script' so */ + /* Fourth parm should be 0.. */ + + if ( mod_gzip_ismatch( + this_name, (char *)r->handler,0,0) ) + { + pass_result = 1; /* We found a match */ + action_flag = this_action; /* What to do */ + break; /* Stop now */ + } + + }/* End 'if ( this_type == MOD_GZIP_IMAP_ISHANDLER )' */ + + }/* End 'if( hlen > 0 )' */ + + if ( clen > 0 ) /* r->content_type field has a value... */ + { + #ifdef MOD_GZIP_DEBUG1 + mod_gzip_printf( "%s: clen has value...\n",cn); + #endif + + if ( this_type == MOD_GZIP_IMAP_ISMIME ) + { + #ifdef MOD_GZIP_DEBUG1 + mod_gzip_printf( "%s: this_type = ISMIME\n",cn); + mod_gzip_printf( "%s: Wildcards matches are OK for MIME types.\n",cn); + mod_gzip_printf( "%s: Call mod_gzip_ismatch(%s,%s,0,1)...\n", + cn, this_name, r->content_type ); + #endif + + /* mod_gzip_ismatch()... */ + + /* Wildcard matches are ALLOWED for */ + /* MIME type strings like 'cgi-script' */ + /* so fourth parm should be 1... */ + + if ( mod_gzip_ismatch( + this_name, (char *)r->content_type, 0, 1 ) ) + { + pass_result = 1; /* We found a match */ + action_flag = this_action; /* What to do */ + break; /* Stop now */ + } + + }/* End 'if ( this_type == MOD_GZIP_IMAP_ISMIME )' */ + + }/* End 'if( clen > 0 )' */ + + if ( flen > 0 ) /* r->filename field has a value... */ + { + #ifdef MOD_GZIP_DEBUG1 + mod_gzip_printf( "%s: flen has value...\n",cn); + #endif + + if ( this_type == MOD_GZIP_IMAP_ISEXT ) + { + #ifdef MOD_GZIP_DEBUG1 + mod_gzip_printf( "%s: this_type = ISEXT\n",cn); + #endif + + if ( file_extension_len > 0 ) /* There is a file extension */ + { + #ifdef MOD_GZIP_DEBUG1 + mod_gzip_printf( "%s: file_extension_len has value...\n",cn); + mod_gzip_printf( "%s: Call mod_gzip_ismatch(%s,%s,0,0)...\n", + cn, this_name, file_extension ); + #endif + + /* mod_gzip_ismatch()... */ + + /* The 2 strings must match exactly so */ + /* pass '0' for parm 3... */ + + /* Wildcard matches are not allowed for */ + /* file extensions like '.html' so */ + /* Fourth parm should be 0.. */ + + if ( mod_gzip_ismatch( + this_name, file_extension, 0, 0 ) ) + { + pass_result = 1; /* We found a match */ + action_flag = this_action; /* What to do */ + break; /* Stop now */ + } + + }/* End 'if( file_extension_len > 0 )' */ + + }/* End 'if( this_type == MOD_GZIP)IMAP_ISEXT )' */ + + }/* End 'if( flen > 0 )' */ + + }/* End 'if ( mgc->imap[x].include == filter )' */ + + else /* The record did not match the current 'filter' value... */ + { + #ifdef MOD_GZIP_DEBUG1 + mod_gzip_printf( "%s: This record does NOT match filter_value %d\n", + cn, filter_value ); + mod_gzip_printf( "%s: The record has been SKIPPED...\n",cn); + #endif + } + + }/* End 'x' loop that looks at 'filtered' records... */ + + #ifdef MOD_GZIP_DEBUG1 + mod_gzip_printf( "%s: --------------------------------------------\n",cn); + mod_gzip_printf( "%s: pass_result = %d\n",cn,pass_result); + #endif + + if ( pass_result ) /* We are done... */ + { + if ( pass == 0 ) item_is_excluded = 1; + else item_is_included = 1; + + break; /* Break out of 'pass' loop now... */ + } + + }/* End 'pass' loop */ + + #ifdef MOD_GZIP_DEBUG1 + mod_gzip_printf( "%s: item_is_excluded = %d\n",cn,item_is_excluded); + mod_gzip_printf( "%s: item_is_included = %d\n",cn,item_is_included); + mod_gzip_printf( "%s: action_flag = %d\n",cn,action_flag); + #endif + + if ( item_is_excluded ) + { + #ifdef MOD_GZIP_DEBUG1 + mod_gzip_printf( "%s: The item is excluded...\n",cn); + mod_gzip_printf( "%s: Exit > return( MOD_GZIP_IMAP_DECLINED1 ) >\n",cn); + #endif + + if ( r->server->loglevel == APLOG_DEBUG ) + { + ap_log_error( "",0,APLOG_NOERRNO|APLOG_DEBUG, r->server, + "mod_gzip: This item is EXCLUDED as per httpd.conf"); + } + + return( MOD_GZIP_IMAP_DECLINED1 ); + } + + else if ( item_is_included ) + { + #ifdef MOD_GZIP_DEBUG1 + mod_gzip_printf( "%s: The item is included...\n",cn); + mod_gzip_printf( "%s: Exit > return( action_flag = %d ) >\n",cn,action_flag); + #endif + + if ( r->server->loglevel == APLOG_DEBUG ) + { + ap_log_error( "",0,APLOG_NOERRNO|APLOG_DEBUG, r->server, + "mod_gzip: This item is INCLUDED as per httpd.conf"); + } + + return( action_flag ); /* STATIC1 or DYNAMIC1 */ + } + + /* + * Default action is to DECLINE processing... + */ + + #ifdef MOD_GZIP_DEBUG1 + mod_gzip_printf( "%s: Exit > return( MOD_GZIP_IMAP_DECLINED1 ) >\n",cn); + #endif + + if ( r->server->loglevel == APLOG_DEBUG ) + { + ap_log_error( "",0,APLOG_NOERRNO|APLOG_DEBUG, r->server, + "mod_gzip: This item was NOT FOUND in any mod_gzip httpd item record."); + ap_log_error( "",0,APLOG_NOERRNO|APLOG_DEBUG, r->server, + "mod_gzip: This item will NOT be processed."); + } + + return( MOD_GZIP_IMAP_DECLINED1 ); + +}/* End of mod_gzip_get_action_flag() */ + +/*--------------------------------------------------------------------------*/ +/* ALL SOURCE CODE BELOW THIS POINT IS COMPRESSION SPECIFIC... */ +/*--------------------------------------------------------------------------*/ + +#define USE_GATHER +extern MODULE_VAR_EXPORT int ap_suexec_enabled; +extern API_EXPORT(void) +ap_internal_redirect_handler(const char *new_uri, request_rec *); +long mod_gzip_ap_send_fb( +BUFF *fb, +request_rec *r, +int *final_return_code +); +long mod_gzip_ap_send_fb_length( +BUFF *fb, +request_rec *r, +long length, +int *final_return_code +); +#define DEFAULT_LOGBYTES 10385760 +#define DEFAULT_BUFBYTES 1024 +static int mod_gzip_cgi_child(void *child_stuff, child_info *pinfo); +typedef struct { + char *logname; + long logbytes; + int bufbytes; +} cgi_server_conf; +struct mod_gzip_cgi_child_stuff { +#ifdef TPF + TPF_FORK_CHILD t; +#endif + request_rec *r; + int nph; + int debug; + char *argv0; +}; +static int is_scriptaliased( request_rec *r ) +{ + const char *t = ap_table_get(r->notes, "alias-forced-type"); + return t && (!strcasecmp(t, "cgi-script")); +} +static int log_scripterror(request_rec *r, cgi_server_conf * conf, int ret, + int show_errno, char *error) +{ + FILE *f; + struct stat finfo; + ap_log_rerror(APLOG_MARK, show_errno|APLOG_ERR, r, + "%s: %s", error, r->filename); + if (!conf->logname || + ((stat(ap_server_root_relative(r->pool, conf->logname), &finfo) == 0) + && (finfo.st_size > conf->logbytes)) || + ((f = ap_pfopen(r->pool, ap_server_root_relative(r->pool, conf->logname), + "a")) == NULL)) { + return ret; + } + fprintf(f, "%%%% [%s] %s %s%s%s %s\n", ap_get_time(), r->method, r->uri, + r->args ? "?" : "", r->args ? r->args : "", r->protocol); + fprintf(f, "%%%% %d %s\n", ret, r->filename); + fprintf(f, "%%error\n%s\n", error); + ap_pfclose(r->pool, f); + return ret; +} +static int log_script(request_rec *r, cgi_server_conf * conf, int ret, + char *dbuf, const char *sbuf, BUFF *script_in, BUFF *script_err) +{ + array_header *hdrs_arr = ap_table_elts(r->headers_in); + table_entry *hdrs = (table_entry *) hdrs_arr->elts; + char argsbuffer[HUGE_STRING_LEN]; + FILE *f; + int i; + struct stat finfo; + if (!conf->logname || + ((stat(ap_server_root_relative(r->pool, conf->logname), &finfo) == 0) + && (finfo.st_size > conf->logbytes)) || + ((f = ap_pfopen(r->pool, ap_server_root_relative(r->pool, conf->logname), + "a")) == NULL)) { + while (ap_bgets(argsbuffer, HUGE_STRING_LEN, script_in) > 0) + continue; +#if defined(WIN32) || defined(NETWARE) + while (ap_bgets(argsbuffer, HUGE_STRING_LEN, script_err) > 0) { + ap_log_rerror(APLOG_MARK, APLOG_ERR | APLOG_NOERRNO, r, + "%s", argsbuffer); + } +#else + while (ap_bgets(argsbuffer, HUGE_STRING_LEN, script_err) > 0) + continue; +#endif + return ret; + } + fprintf(f, "%%%% [%s] %s %s%s%s %s\n", ap_get_time(), r->method, r->uri, + r->args ? "?" : "", r->args ? r->args : "", r->protocol); + fprintf(f, "%%%% %d %s\n", ret, r->filename); + fputs("%request\n", f); + for (i = 0; i < hdrs_arr->nelts; ++i) { + if (!hdrs[i].key) + continue; + fprintf(f, "%s: %s\n", hdrs[i].key, hdrs[i].val); + } + if ((r->method_number == M_POST || r->method_number == M_PUT) + && *dbuf) { + fprintf(f, "\n%s\n", dbuf); + } + fputs("%response\n", f); + hdrs_arr = ap_table_elts(r->err_headers_out); + hdrs = (table_entry *) hdrs_arr->elts; + for (i = 0; i < hdrs_arr->nelts; ++i) { + if (!hdrs[i].key) + continue; + fprintf(f, "%s: %s\n", hdrs[i].key, hdrs[i].val); + } + if (sbuf && *sbuf) + fprintf(f, "%s\n", sbuf); + if (ap_bgets(argsbuffer, HUGE_STRING_LEN, script_in) > 0) { + fputs("%stdout\n", f); + fputs(argsbuffer, f); + while (ap_bgets(argsbuffer, HUGE_STRING_LEN, script_in) > 0) + fputs(argsbuffer, f); + fputs("\n", f); + } + if (ap_bgets(argsbuffer, HUGE_STRING_LEN, script_err) > 0) { + fputs("%stderr\n", f); + fputs(argsbuffer, f); + while (ap_bgets(argsbuffer, HUGE_STRING_LEN, script_err) > 0) + fputs(argsbuffer, f); + fputs("\n", f); + } + ap_bclose( script_in ); + ap_bclose( script_err ); + ap_pfclose(r->pool, f); + return ret; +} +int mod_gzip_cgi_handler( request_rec *r ) +{ + int bytesread; + int retval, nph, dbpos = 0; + char *argv0, *dbuf = NULL; + BUFF *script_out, *script_in, *script_err; + char argsbuffer[HUGE_STRING_LEN]; + int is_included = !strcmp(r->protocol, "INCLUDED"); + void *sconf = r->server->module_config; + int final_result = DECLINED; + #define MOD_GZIP_ENGAGED + #ifdef MOD_GZIP_ENGAGED + cgi_server_conf conf_local; + cgi_server_conf *conf = &conf_local; + char cgi_logname[]=""; + #else + cgi_server_conf *conf = + (cgi_server_conf *) ap_get_module_config(sconf, &cgi_module); + #endif + const char *location; + struct mod_gzip_cgi_child_stuff cld; + #ifdef MOD_GZIP_ENGAGED + conf->logname = cgi_logname; + conf->logbytes = (long) 60000L; + conf->bufbytes = (int) 20000; + #endif + if ( r->method_number == M_OPTIONS ) + { + r->allowed |= (1 << M_GET); + r->allowed |= (1 << M_POST); + return DECLINED; + } + if ((argv0 = strrchr(r->filename, '/')) != NULL) + { + argv0++; + } + else + { + argv0 = r->filename; + } + nph = !(strncmp(argv0, "nph-", 4)); + if ( !(ap_allow_options(r) & OPT_EXECCGI) && !is_scriptaliased(r) ) + { + return log_scripterror(r, conf, FORBIDDEN, APLOG_NOERRNO, + "Options ExecCGI is off in this directory"); + } + if ( nph && is_included ) + { + return log_scripterror(r, conf, FORBIDDEN, APLOG_NOERRNO, + "attempt to include NPH CGI script"); + } + #if defined(OS2) || defined(WIN32) + if ( r->finfo.st_mode == 0 ) + { + struct stat statbuf; + char *newfile; + newfile = ap_pstrcat(r->pool, r->filename, ".EXE", NULL); + if ((stat(newfile, &statbuf) != 0) || (!S_ISREG(statbuf.st_mode))) + { + return log_scripterror(r, conf, NOT_FOUND, 0, + "script not found or unable to stat"); + } + else + { + r->filename = newfile; + } + } + #else + if ( r->finfo.st_mode == 0 ) + { + return log_scripterror(r, conf, NOT_FOUND, APLOG_NOERRNO, + "script not found or unable to stat"); + } + #endif + if ( S_ISDIR( r->finfo.st_mode ) ) + { + return log_scripterror(r, conf, FORBIDDEN, APLOG_NOERRNO, + "attempt to invoke directory as script"); + } + if ( !ap_suexec_enabled ) + { + if ( !ap_can_exec( &r->finfo ) ) + { + return log_scripterror(r, conf, FORBIDDEN, APLOG_NOERRNO, + "file permissions deny server execution"); + } + } + if ((retval = ap_setup_client_block(r, REQUEST_CHUNKED_ERROR))) + { + return retval; + } + ap_add_common_vars(r); + cld.argv0 = argv0; + cld.r = r; + cld.nph = nph; + cld.debug = conf->logname ? 1 : 0; + #ifdef TPF + cld.t.filename = r->filename; + cld.t.subprocess_env = r->subprocess_env; + cld.t.prog_type = FORK_FILE; + #endif + #ifdef CHARSET_EBCDIC + ap_bsetflag( r->connection->client, B_EBCDIC2ASCII, 1 ); + #endif + if ( !ap_bspawn_child( + r->main ? r->main->pool : r->pool, + mod_gzip_cgi_child, + (void *) &cld, + kill_after_timeout, + &script_out, + &script_in, + &script_err + ) + ) + { + ap_log_rerror(APLOG_MARK, APLOG_ERR, r, + "couldn't spawn child process: %s", r->filename); + return HTTP_INTERNAL_SERVER_ERROR; + } + else + { + } + if ( ap_should_client_block(r) ) + { + int dbsize, len_read; + if ( conf->logname ) + { + dbuf = ap_pcalloc( r->pool, conf->bufbytes + 1 ); + dbpos = 0; + } + ap_hard_timeout("copy script args", r); + for (;;) + { + len_read = + ap_get_client_block( r, argsbuffer, HUGE_STRING_LEN ); + if ( len_read < 1 ) + { + break; + } + if (conf->logname) + { + if ((dbpos + len_read) > conf->bufbytes) + { + dbsize = conf->bufbytes - dbpos; + } + else + { + dbsize = len_read; + } + memcpy(dbuf + dbpos, argsbuffer, dbsize); + dbpos += dbsize; + } + ap_reset_timeout(r); + if ( ap_bwrite(script_out, argsbuffer, len_read) < len_read ) + { + while ( len_read= + ap_get_client_block(r, argsbuffer, HUGE_STRING_LEN) > 0) + { + } + break; + } + else + { + } + } + ap_bflush( script_out ); + ap_kill_timeout(r); + } + else + { + } + ap_bclose( script_out ); + if ( script_in && !nph ) + { + char sbuf[MAX_STRING_LEN]; + int ret; + if ((ret = ap_scan_script_header_err_buff(r, script_in, sbuf))) + { + return log_script(r, conf, ret, dbuf, sbuf, script_in, script_err); + } + #ifdef CHARSET_EBCDIC + ap_checkconv(r); + #endif + location = ap_table_get( r->headers_out, "Location" ); + if ( location && location[0] == '/' && r->status == 200 ) + { + ap_hard_timeout("read from script", r); + while ( ap_bgets(argsbuffer, HUGE_STRING_LEN, script_in) > 0 ) + { + continue; + } + while (ap_bgets(argsbuffer, HUGE_STRING_LEN, script_err) > 0) + { + continue; + } + ap_kill_timeout(r); + r->method = ap_pstrdup(r->pool, "GET"); + r->method_number = M_GET; + ap_table_unset( r->headers_in, "Content-Length" ); + ap_internal_redirect_handler( location, r ); + return OK; + } + else if ( location && r->status == 200 ) + { + return REDIRECT; + } + #ifdef USE_GATHER + if ( r->header_only ) + { + ap_send_http_header(r); + } + else + { + } + #else /* !USE_GATHER */ + ap_send_http_header(r); + #endif /* USE_GATHER */ + if (!r->header_only) + { + mod_gzip_ap_send_fb( script_in, r, &final_result ); + } + ap_bclose( script_in ); + ap_soft_timeout("soaking script stderr", r); + for (;;) + { + bytesread = ap_bgets( argsbuffer, HUGE_STRING_LEN, script_err ); + if ( bytesread < 1 ) + { + break; + } + } + ap_kill_timeout(r); + ap_bclose( script_err ); + } + else + { + } + if ( script_in && nph ) + { + #ifdef RUSSIAN_APACHE + if (ra_charset_active(r)) + { + r->ra_codep=NULL; + } + #endif + mod_gzip_ap_send_fb( script_in, r, &final_result ); + } + else + { + } + #ifdef ORIGINAL + return OK; + #endif + return final_result; +} +static int mod_gzip_cgi_child(void *child_stuff, child_info *pinfo) +{ + struct mod_gzip_cgi_child_stuff *cld = (struct mod_gzip_cgi_child_stuff *) child_stuff; + request_rec *r = cld->r; + char *argv0 = cld->argv0; + int child_pid; + +/* WARNING! If the following DEBUG_CGI switch is ON you may need to */ +/* run Apache with the -X switch or the dynamic compression */ +/* of some CGI output ( most notable Zope ) will start to fail. */ +/* This DEBUG_CGI switch should NEVER be on for production runs. */ +/* +#define DEBUG_CGI +*/ + +#ifdef DEBUG_CGI +#ifdef OS2 + FILE *dbg = fopen("con", "w"); +#else + #ifdef WIN32 + FILE *dbg = fopen("c:\\script.dbg", "a" ); + #else + FILE *dbg = fopen("/dev/tty", "w"); + #endif +#endif + int i; +#endif + char **env; + RAISE_SIGSTOP(CGI_CHILD); +#ifdef DEBUG_CGI + fprintf(dbg, "Attempting to exec %s as %sCGI child (argv0 = %s)\n", + r->filename, cld->nph ? "NPH " : "", argv0); +#endif + ap_add_cgi_vars(r); + env = ap_create_environment(r->pool, r->subprocess_env); +#ifdef DEBUG_CGI + fprintf(dbg, "Environment: \n"); + for (i = 0; env[i]; ++i) + fprintf(dbg, "'%s'\n", env[i]); +#endif +#ifndef WIN32 + #ifdef DEBUG_CGI + fprintf(dbg, "Call ap_chdir_file(r->filename=[%s]\n",r->filename); + #endif + ap_chdir_file(r->filename); + #ifdef DEBUG_CGI + fprintf(dbg, "Back ap_chdir_file(r->filename=[%s]\n",r->filename); + #endif +#endif + if (!cld->debug) + ap_error_log2stderr(r->server); +#ifdef TPF + #ifdef DEBUG_CGI + #ifdef WIN32 + fprintf(dbg, "TPF defined... return( 0 ) now...\n"); + if ( dbg ) { fclose(dbg); dbg=0; } + #endif + #endif + return (0); +#else + #ifdef DEBUG_CGI + fprintf(dbg, "Call ap_cleanup_for_exec()...\n"); + #endif + ap_cleanup_for_exec(); + #ifdef DEBUG_CGI + fprintf(dbg, "Back ap_cleanup_for_exec()...\n"); + fprintf(dbg, "Call ap_call_exec()...\n"); + #endif + child_pid = ap_call_exec(r, pinfo, argv0, env, 0); + #ifdef DEBUG_CGI + fprintf(dbg, "Back ap_call_exec()...\n"); + #endif +#if defined(WIN32) || defined(OS2) + #ifdef DEBUG_CGI + #ifdef WIN32 + fprintf(dbg, "WIN32 or OS2 defined... return( child_pid ) now...\n"); + if ( dbg ) { fclose(dbg); dbg=0; } + #endif + #endif + return (child_pid); +#else + ap_log_error(APLOG_MARK, APLOG_ERR, NULL, "exec of %s failed", r->filename); + exit(0); + #ifdef DEBUG_CGI + #ifdef WIN32 + if ( dbg ) { fclose(dbg); dbg=0; } + #endif + #endif + return (0); +#endif +#endif +} +#define MOD_GZIP_SET_BYTES_SENT(r) \ + do { if (r->sent_bodyct) \ + ap_bgetopt (r->connection->client, BO_BYTECT, &r->bytes_sent); \ + } while (0) +long mod_gzip_ap_send_fb( BUFF *fb, request_rec *r, int *final_return_code ) +{ + long lrc; + int return_code=DECLINED; + lrc = (long ) mod_gzip_ap_send_fb_length( fb, r, -1, &return_code ); + *final_return_code = return_code; + return lrc; +} +#ifdef USE_TPF_SELECT +#define mod_gzip_ap_select(_a, _b, _c, _d, _e) \ + tpf_select(_a, _b, _c, _d, _e) +#elif defined(SELECT_NEEDS_CAST) +#define mod_gzip_ap_select(_a, _b, _c, _d, _e) \ + select((_a), (int *)(_b), (int *)(_c), (int *)(_d), (_e)) +#else +#define mod_gzip_ap_select(_a, _b, _c, _d, _e) \ + select(_a, _b, _c, _d, _e) +#endif +long mod_gzip_ap_send_fb_length( +BUFF *fb, +request_rec *r, +long length, +int *final_return_code +) +{ + char cn[]="mod_gzip_ab_send_fb_length()"; + char buf[IOBUFSIZE]; + long total_bytes_sent = 0; + register int n; + register int len; + register int fd; + fd_set fds; + int rc; + #ifndef USE_GATHER + register int w; + register int o; + #endif + #ifdef USE_GATHER + int gather_on = 0; + int gather_todisk = 0; + int gather_origin = 0; + char *gather_bufstart = 0; + char *gather_source = 0; + char *gather_buf = 0; + int gather_bufmaxlen = 60000; + int gather_byteswritten = 0; + int gather_length = 0; + int gather_maxlen = 0; + long gather_totlen = 0; + FILE *gather_fh1 = 0; + char gather_filename[ MOD_GZIP_MAX_PATH_LEN + 2 ]; + #endif + void *modconf = r->server->module_config; + mod_gzip_conf *conf; + *final_return_code = DECLINED; + conf = (mod_gzip_conf *) ap_get_module_config( modconf, &gzip_module ); + if ( length == 0 ) + { + return 0; + } + ap_bsetflag( fb, B_RD, 0 ); + #ifndef TPF + ap_bnonblock( fb, B_RD ); + #endif + fd = ap_bfileno( fb, B_RD ); + #ifdef CHECK_FD_SETSIZE + if ( fd >= FD_SETSIZE ) + { + ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_WARNING, NULL, + "send body: filedescriptor (%u) larger than FD_SETSIZE (%u) " + "found, you probably need to rebuild Apache with a " + "larger FD_SETSIZE", fd, FD_SETSIZE); + return 0; + } + else + { + } + #else + #endif + ap_soft_timeout("send body", r); + FD_ZERO( &fds ); + #ifdef USE_GATHER + gather_on = 0; + if ( (long) conf->maximum_inmem_size < (long) gather_bufmaxlen ) + { + gather_maxlen = (int) conf->maximum_inmem_size; + } + else + { + gather_maxlen = (int) gather_bufmaxlen; + } + gather_bufstart = malloc( (int)(gather_maxlen + 2) ); + if ( gather_bufstart ) + { + gather_on = 1; + gather_buf = gather_bufstart; + gather_source = gather_bufstart; + gather_origin = 0; + } + else + { + } + #endif + while( !r->connection->aborted ) + { + #ifdef NDELAY_PIPE_RETURNS_ZERO + int afterselect = 0; + #endif + if ( (length > 0) && (total_bytes_sent + IOBUFSIZE) > length ) + { + len = length - total_bytes_sent; + } + else + { + len = IOBUFSIZE; + } + do { + n = ap_bread( fb, buf, len ); + #ifdef NDELAY_PIPE_RETURNS_ZERO + if ((n > 0) || (n == 0 && afterselect)) + { + break; + } + #else + if (n >= 0) + { + break; + } + #endif + if ( r->connection->aborted ) + { + break; + } + if ( n < 0 && errno != EAGAIN ) + { + break; + } + if ( ap_bflush( r->connection->client ) < 0 ) + { + ap_log_rerror(APLOG_MARK, APLOG_INFO, r, + "client stopped connection before send body completed"); + ap_bsetflag( r->connection->client, B_EOUT, 1 ); + r->connection->aborted = 1; + break; + } + #ifdef WIN32 + FD_SET( (unsigned) fd, &fds ); + #else + FD_SET( fd, &fds ); + #endif + #ifdef FUTURE_USE + mod_gzip_ap_select(fd + 1, &fds, NULL, NULL, NULL); + #endif + #ifdef NDELAY_PIPE_RETURNS_ZERO + afterselect = 1; + #endif + } while ( !r->connection->aborted ); + if ( n < 1 || r->connection->aborted ) + { + break; + } + #ifdef USE_GATHER + if ( gather_on ) + { + if ( ( gather_length + n ) >= gather_maxlen ) + { + if ( !gather_fh1 ) + { + mod_gzip_create_unique_filename( + (mod_gzip_conf *) conf, + (char *) gather_filename, + sizeof( gather_filename ) + ); + gather_fh1 = fopen( gather_filename, "wb" ); + if ( gather_fh1 ) + { + gather_source = gather_filename; + gather_origin = 1; + } + else + { + gather_on = 0; + } + } + if ( ( gather_fh1 ) && ( gather_length > 0 ) ) + { + gather_byteswritten = + fwrite( gather_bufstart, 1, gather_length, gather_fh1 ); + if ( gather_byteswritten != gather_length ) + { + gather_on = 0; + } + } + if ( ( gather_fh1 ) && ( n > 0 ) ) + { + gather_byteswritten = + fwrite( buf, 1, n, gather_fh1 ); + if ( gather_byteswritten != n ) + { + gather_on = 0; + } + } + gather_buf = gather_bufstart; + gather_length = 0; + } + else + { + if ( gather_on ) + { + memcpy( gather_buf, buf, n ); + gather_buf += n; + gather_length += n; + } + } + gather_totlen += n; + } + #endif + #ifdef FUTURE_USE + o = 0; + while ( n && !r->connection->aborted ) + { + #ifdef RUSSIAN_APACHE + unsigned char *newbuf,*p; + int newlen=0; + if ( ra_charset_active(r) ) + { + if ( ra_flag( r, RA_WIDE_CHARS_SC ) ) + { + ra_data_server2client(r,&buf[o],n,&newbuf,&newlen); + p=newbuf; + while( newlen > 0 ) + { + w = ap_bwrite( r->connection->client, p, newlen ); + if(w<=0) goto RECODE_DONE; + newlen-=w; + p+=w; + } + w=n; + } + else + { + unsigned char *t = r->ra_codep->cp_otabl_p; + unsigned char *b = (unsigned char *)&buf[o]; + unsigned char *end = b+n; + while( b < end ) + { + *b = t[*b]; + b++; + } + w = ap_bwrite( r->connection->client, &buf[o], n ); + } + } + else + { + w = ap_bwrite( r->connection->client, &buf[o], n ); + } + RECODE_DONE:; + #else + w = ap_bwrite( r->connection->client, &buf[o], n ); + #endif + if ( w > 0 ) + { + ap_reset_timeout(r); + total_bytes_sent += w; + n -= w; + o += w; + } + else if ( w < 0 ) + { + if ( !r->connection->aborted ) + { + ap_log_rerror(APLOG_MARK, APLOG_INFO, r, + "client stopped connection before send body completed"); + ap_bsetflag(r->connection->client, B_EOUT, 1); + r->connection->aborted = 1; + } + break; + } + } + #endif + } + ap_kill_timeout(r); + MOD_GZIP_SET_BYTES_SENT(r); + #ifdef USE_GATHER + if ( gather_fh1 ) + { + if ( gather_length > 0 ) + { + gather_byteswritten = + fwrite( gather_bufstart, 1, gather_length, gather_fh1 ); + if ( gather_byteswritten != gather_length ) + { + gather_on = 0; + } + } + fclose( gather_fh1 ); + gather_fh1 = 0; + } + if ( gather_totlen > 0 ) + { + rc = + mod_gzip_encode_and_transmit( + (request_rec *) r, + (char *) gather_source, + (int ) gather_origin, + (long ) gather_totlen, + (int ) 1 + ); + *final_return_code = rc; + } + if ( gather_bufstart ) + { + free( gather_bufstart ); + gather_bufstart = 0; + } + gather_on = 0; + #endif + return total_bytes_sent; +} + +/*--------------------------------------------------------------------------*/ +/* COMPRESSION SUPPORT ROUTINES */ +/*--------------------------------------------------------------------------*/ + +#define BIG_MEM + +typedef unsigned uns; +typedef unsigned int uni; +typedef unsigned char uch; +typedef unsigned short ush; +typedef unsigned long ulg; +typedef int gz1_file_t; + +#ifdef __STDC__ + typedef void *voidp; +#else + typedef char *voidp; +#endif + +#if defined(__MSDOS__) && !defined(MSDOS) +# define MSDOS +#endif + +#if defined(__OS2__) && !defined(OS2) +# define OS2 +#endif + +#if defined(OS2) && defined(MSDOS) +# undef MSDOS +#endif + +#ifdef MSDOS +# ifdef __GNUC__ +# define near +# else +# define MAXSEG_64K +# ifdef __TURBOC__ +# define NO_OFF_T +# ifdef __BORLANDC__ +# define DIRENT +# else +# define NO_UTIME +# endif +# else +# define HAVE_SYS_UTIME_H +# define NO_UTIME_H +# endif +# endif +# define PATH_SEP2 '\\' +# define PATH_SEP3 ':' +# define MAX_PATH_LEN 128 +# define NO_MULTIPLE_DOTS +# define MAX_EXT_CHARS 3 +# define Z_SUFFIX "z" +# define NO_CHOWN +# define PROTO +# define STDC_HEADERS +# define NO_SIZE_CHECK +# define casemap(c) tolow(c) +# include +# undef OS_CODE +# define OS_CODE 0x00 +# define SET_BINARY_MODE(fd) setmode(fd, O_BINARY) +# if !defined(NO_ASM) && !defined(ASMV) +# define ASMV +# endif +#else +# define near +#endif + +#ifdef OS2 +# define PATH_SEP2 '\\' +# define PATH_SEP3 ':' +# define MAX_PATH_LEN 260 +# ifdef OS2FAT +# define NO_MULTIPLE_DOTS +# define MAX_EXT_CHARS 3 +# define Z_SUFFIX "z" +# define casemap(c) tolow(c) +# endif +# define NO_CHOWN +# define PROTO +# define STDC_HEADERS +# include +# undef OS_CODE +# define OS_CODE 0x06 +# define SET_BINARY_MODE(fd) setmode(fd, O_BINARY) +# ifdef _MSC_VER +# define HAVE_SYS_UTIME_H +# define NO_UTIME_H +# define MAXSEG_64K +# undef near +# define near _near +# endif +# ifdef __EMX__ +# define HAVE_SYS_UTIME_H +# define NO_UTIME_H +# define DIRENT +# define EXPAND(argc,argv) \ + {_response(&argc, &argv); _wildcard(&argc, &argv);} +# endif +# ifdef __BORLANDC__ +# define DIRENT +# endif +# ifdef __ZTC__ +# define NO_DIR +# define NO_UTIME_H +# include +# define EXPAND(argc,argv) \ + {response_expand(&argc, &argv);} +# endif +#endif + +#ifdef WIN32 +# define HAVE_SYS_UTIME_H +# define NO_UTIME_H +# define PATH_SEP2 '\\' +# define PATH_SEP3 ':' +# undef MAX_PATH_LEN +# define MAX_PATH_LEN 260 +# define NO_CHOWN +# define PROTO +# define STDC_HEADERS +# define SET_BINARY_MODE(fd) setmode(fd, O_BINARY) +# include +# ifdef NTFAT +# define NO_MULTIPLE_DOTS +# define MAX_EXT_CHARS 3 +# define Z_SUFFIX "z" +# define casemap(c) tolow(c) +# endif +# undef OS_CODE + +# define OS_CODE 0x00 + +#endif + +#ifdef MSDOS +# ifdef __TURBOC__ +# include +# define DYN_ALLOC + void * fcalloc (unsigned items, unsigned size); + void fcfree (void *ptr); +# else +# define fcalloc(nitems,itemsize) halloc((long)(nitems),(itemsize)) +# define fcfree(ptr) hfree(ptr) +# endif +#else +# ifdef MAXSEG_64K +# define fcalloc(items,size) calloc((items),(size)) +# else +# define fcalloc(items,size) malloc((size_t)(items)*(size_t)(size)) +# endif +# define fcfree(ptr) free(ptr) +#endif + +#if defined(VAXC) || defined(VMS) +# define PATH_SEP ']' +# define PATH_SEP2 ':' +# define SUFFIX_SEP ';' +# define NO_MULTIPLE_DOTS +# define Z_SUFFIX "-gz" +# define RECORD_IO 1 +# define casemap(c) tolow(c) +# undef OS_CODE +# define OS_CODE 0x02 +# define OPTIONS_VAR "GZIP_OPT" +# define STDC_HEADERS +# define NO_UTIME +# define EXPAND(argc,argv) vms_expand_args(&argc,&argv); +# include +# define unlink delete +# ifdef VAXC +# define NO_FCNTL_H +# include +# endif +#endif + +#ifdef AMIGA +# define PATH_SEP2 ':' +# define STDC_HEADERS +# undef OS_CODE +# define OS_CODE 0x01 +# define ASMV +# ifdef __GNUC__ +# define DIRENT +# define HAVE_UNISTD_H +# else +# define NO_STDIN_FSTAT +# define SYSDIR +# define NO_SYMLINK +# define NO_CHOWN +# define NO_FCNTL_H +# include +# define direct dirent + extern void _expand_args(int *argc, char ***argv); +# define EXPAND(argc,argv) _expand_args(&argc,&argv); +# undef O_BINARY +# endif +#endif + +#if defined(ATARI) || defined(atarist) +# ifndef STDC_HEADERS +# define STDC_HEADERS +# define HAVE_UNISTD_H +# define DIRENT +# endif +# define ASMV +# undef OS_CODE +# define OS_CODE 0x05 +# ifdef TOSFS +# define PATH_SEP2 '\\' +# define PATH_SEP3 ':' +# define MAX_PATH_LEN 128 +# define NO_MULTIPLE_DOTS +# define MAX_EXT_CHARS 3 +# define Z_SUFFIX "z" +# define NO_CHOWN +# define casemap(c) tolow(c) +# define NO_SYMLINK +# endif +#endif + +#ifdef MACOS +# define PATH_SEP ':' +# define DYN_ALLOC +# define PROTO +# define NO_STDIN_FSTAT +# define NO_CHOWN +# define NO_UTIME +# define chmod(file, mode) (0) +# define OPEN(name, flags, mode) open(name, flags) +# undef OS_CODE +# define OS_CODE 0x07 +# ifdef MPW +# define isatty(fd) ((fd) <= 2) +# endif +#endif + +#ifdef __50SERIES +# define PATH_SEP '>' +# define STDC_HEADERS +# define NO_MEMORY_H +# define NO_UTIME_H +# define NO_UTIME +# define NO_CHOWN +# define NO_STDIN_FSTAT +# define NO_SIZE_CHECK +# define NO_SYMLINK +# define RECORD_IO 1 +# define casemap(c) tolow(c) +# define put_char(c) put_byte((c) & 0x7F) +# define get_char(c) ascii2pascii(get_byte()) +# undef OS_CODE +# define OS_CODE 0x0F +# ifdef SIGTERM +# undef SIGTERM +# endif +#endif + +#if defined(pyr) && !defined(NOMEMCPY) +# define NOMEMCPY +#endif + +#ifdef TOPS20 +# undef OS_CODE +# define OS_CODE 0x0a +#endif + +#ifndef unix +# define NO_ST_INO +#endif + +#ifndef OS_CODE +# undef OS_CODE +# define OS_CODE 0x03 +#endif + +#ifndef PATH_SEP +# define PATH_SEP '/' +#endif + +#ifndef casemap +# define casemap(c) (c) +#endif + +#ifndef OPTIONS_VAR +# define OPTIONS_VAR "GZIP" +#endif + +#ifndef Z_SUFFIX +# define Z_SUFFIX ".gz" +#endif + +#ifdef MAX_EXT_CHARS +# define MAX_SUFFIX MAX_EXT_CHARS +#else +# define MAX_SUFFIX 30 +#endif + +#ifndef MIN_PART +# define MIN_PART 3 +#endif + +#ifndef EXPAND +# define EXPAND(argc,argv) +#endif + +#ifndef RECORD_IO +# define RECORD_IO 0 +#endif + +#ifndef SET_BINARY_MODE +# define SET_BINARY_MODE(fd) +#endif + +#ifndef OPEN +# define OPEN(name, flags, mode) open(name, flags, mode) +#endif + +#ifndef get_char +# define get_char() get_byte() +#endif + +#ifndef put_char +# define put_char(c) put_byte(c) +#endif + +#ifndef O_BINARY +#define O_BINARY 0 +#endif + +#define OK 0 +#define LZ1_ERROR 1 +#define WARNING 2 +#define STORED 0 +#define COMPRESSED 1 +#define PACKED 2 +#define LZHED 3 +#define DEFLATED 8 +#define MAX_METHODS 9 + +#ifndef O_CREAT +#include +#ifndef O_CREAT +#define O_CREAT FCREAT +#endif +#ifndef O_EXCL +#define O_EXCL FEXCL +#endif +#endif + +#ifndef S_IRUSR +#define S_IRUSR 0400 +#endif +#ifndef S_IWUSR +#define S_IWUSR 0200 +#endif +#define RW_USER (S_IRUSR | S_IWUSR) + +#ifndef MAX_PATH_LEN +#define MAX_PATH_LEN 256 +#endif + +#ifndef SEEK_END +#define SEEK_END 2 +#endif + +#define PACK_MAGIC "\037\036" +#define GZIP_MAGIC "\037\213" +#define OLD_GZIP_MAGIC "\037\236" +#define LZH_MAGIC "\037\240" +#define PKZIP_MAGIC "\120\113\003\004" +#define ASCII_FLAG 0x01 +#define CONTINUATION 0x02 +#define EXTRA_FIELD 0x04 +#define ORIG_NAME 0x08 +#define COMMENT 0x10 +#define ENCRYPTED 0x20 +#define RESERVED 0xC0 +#define UNKNOWN 0xffff +#define BINARY 0 +#define ASCII 1 + +#ifndef WSIZE +#define WSIZE 0x8000 +#endif + +#ifndef INBUFSIZ +#ifdef SMALL_MEM +#define INBUFSIZ 0x2000 +#else +#define INBUFSIZ 0x8000 +#endif +#endif +#define INBUF_EXTRA 64 + +#ifndef OUTBUFSIZ +#ifdef SMALL_MEM +#define OUTBUFSIZ 8192 +#else +#define OUTBUFSIZ 0x4000 +#endif +#endif +#define OUTBUF_EXTRA 2048 + +#ifndef DIST_BUFSIZE +#ifdef SMALL_MEM +#define DIST_BUFSIZE 0x2000 +#else +#define DIST_BUFSIZE 0x8000 +#endif +#endif + +#ifndef BITS +#define BITS 16 +#endif + +#define LZW_MAGIC "\037\235" + +#define MIN_MATCH 3 +#define MAX_MATCH 258 + +#define MIN_LOOKAHEAD (MAX_MATCH+MIN_MATCH+1) +#define MAX_DIST (WSIZE-MIN_LOOKAHEAD) + +#ifdef SMALL_MEM +#define HASH_BITS 13 +#endif +#ifdef MEDIUM_MEM +#define HASH_BITS 14 +#endif +#ifndef HASH_BITS +#define HASH_BITS 15 +#endif + +#define HASH_SIZE (unsigned)(1<block_start >= 0L ? (char*)&gz1->window[(unsigned)gz1->block_start] : \ + (char*)NULL, (long)gz1->strstart - gz1->block_start, (eof)) + +#ifdef DYN_ALLOC +# define ALLOC(type, array, size) { \ + array = (type*)fcalloc((size_t)(((size)+1L)/2), 2*sizeof(type)); \ + if (array == NULL) error("insufficient memory"); \ + } +# define FREE(array) {if (array != NULL) fcfree(array), array=NULL;} +#else +# define ALLOC(type, array, size) +# define FREE(array) +#endif + +#define GZ1_MAX(a,b) (a >= b ? a : b) + +#define tolow(c) (isupper(c) ? (c)-'A'+'a' : (c)) + +#define smaller(tree, n, m) \ + (tree[n].fc.freq < tree[m].fc.freq || \ + (tree[n].fc.freq == tree[m].fc.freq && gz1->depth[n] <= gz1->depth[m])) + +#define send_code(c, tree) send_bits(gz1,tree[c].fc.code, tree[c].dl.len) + +#define put_byte(c) {gz1->outbuf[gz1->outcnt++]=(uch)(c); if (gz1->outcnt==OUTBUFSIZ)\ + flush_outbuf(gz1);} + +#define put_short(w) \ +{ if (gz1->outcnt < OUTBUFSIZ-2) { \ + gz1->outbuf[gz1->outcnt++] = (uch) ((w) & 0xff); \ + gz1->outbuf[gz1->outcnt++] = (uch) ((ush)(w) >> 8); \ + } else { \ + put_byte((uch)((w) & 0xff)); \ + put_byte((uch)((ush)(w) >> 8)); \ + } \ +} + +#define put_long(n) { \ + put_short((n) & 0xffff); \ + put_short(((ulg)(n)) >> 16); \ +} + +#ifdef CRYPT + +# define NEXTBYTE() \ + (decrypt ? (cc = get_byte(), zdecode(cc), cc) : get_byte()) +#else +# define NEXTBYTE() (uch)get_byte() +#endif + +#define NEEDBITS(n) {while(k<(n)){b|=((ulg)NEXTBYTE())<>=(n);k-=(n);} + +#define SH(p) ((ush)(uch)((p)[0]) | ((ush)(uch)((p)[1]) << 8)) +#define LG(p) ((ulg)(SH(p)) | ((ulg)(SH((p)+2)) << 16)) + +#define put_ubyte(c) {gz1->window[gz1->outcnt++]=(uch)(c); if (gz1->outcnt==WSIZE)\ + flush_window(gz1);} + +#define WARN(msg) { if (gz1->exit_code == OK) gz1->exit_code = WARNING; } + +#define get_byte() (gz1->inptr < gz1->insize ? gz1->inbuf[gz1->inptr++] : fill_inbuf(gz1,0)) +#define try_byte() (gz1->inptr < gz1->insize ? gz1->inbuf[gz1->inptr++] : fill_inbuf(gz1,1)) + +#define d_code(dist) \ + ((dist) < 256 ? gz1->dist_code[dist] : gz1->dist_code[256+((dist)>>7)]) + +typedef struct config { + ush good_length; + ush max_lazy; + ush nice_length; + ush max_chain; +} config; + +config configuration_table[10] = { + + {0, 0, 0, 0}, + {4, 4, 8, 4}, + {4, 5, 16, 8}, + {4, 6, 32, 32}, + {4, 4, 16, 16}, + {8, 16, 32, 32}, + {8, 16, 128, 128}, + {8, 32, 128, 256}, + {32, 128, 258, 1024}, + {32, 258, 258, 4096}}; + +typedef struct ct_data { + + union { + ush freq; + ush code; + } fc; + union { + ush dad; + ush len; + } dl; + +} ct_data; + +typedef struct tree_desc { + ct_data *dyn_tree; + ct_data *static_tree; + int *extra_bits; + int extra_base; + int elems; + int max_length; + int max_code; +} tree_desc; + +struct huft { + uch e; + uch b; + union { + ush n; + struct huft *t; + } v; +}; + +uch bl_order[BL_CODES] + = {16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15}; + +int extra_lbits[LENGTH_CODES] + = {0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0}; + +int extra_dbits[D_CODES] + = {0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13}; + +int extra_blbits[BL_CODES] + = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,7}; + +ulg crc_32_tab[] = { + 0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L, + 0x706af48fL, 0xe963a535L, 0x9e6495a3L, 0x0edb8832L, 0x79dcb8a4L, + 0xe0d5e91eL, 0x97d2d988L, 0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L, + 0x90bf1d91L, 0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL, + 0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L, 0x136c9856L, + 0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL, 0x14015c4fL, 0x63066cd9L, + 0xfa0f3d63L, 0x8d080df5L, 0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L, + 0xa2677172L, 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL, + 0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L, 0x32d86ce3L, + 0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L, 0x26d930acL, 0x51de003aL, + 0xc8d75180L, 0xbfd06116L, 0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L, + 0xb8bda50fL, 0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L, + 0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL, 0x76dc4190L, + 0x01db7106L, 0x98d220bcL, 0xefd5102aL, 0x71b18589L, 0x06b6b51fL, + 0x9fbfe4a5L, 0xe8b8d433L, 0x7807c9a2L, 0x0f00f934L, 0x9609a88eL, + 0xe10e9818L, 0x7f6a0dbbL, 0x086d3d2dL, 0x91646c97L, 0xe6635c01L, + 0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL, 0x6c0695edL, + 0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L, 0x65b0d9c6L, 0x12b7e950L, + 0x8bbeb8eaL, 0xfcb9887cL, 0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L, + 0xfbd44c65L, 0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L, + 0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL, 0x4369e96aL, + 0x346ed9fcL, 0xad678846L, 0xda60b8d0L, 0x44042d73L, 0x33031de5L, + 0xaa0a4c5fL, 0xdd0d7cc9L, 0x5005713cL, 0x270241aaL, 0xbe0b1010L, + 0xc90c2086L, 0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL, + 0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L, 0x59b33d17L, + 0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL, 0xedb88320L, 0x9abfb3b6L, + 0x03b6e20cL, 0x74b1d29aL, 0xead54739L, 0x9dd277afL, 0x04db2615L, + 0x73dc1683L, 0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L, + 0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L, 0xf00f9344L, + 0x8708a3d2L, 0x1e01f268L, 0x6906c2feL, 0xf762575dL, 0x806567cbL, + 0x196c3671L, 0x6e6b06e7L, 0xfed41b76L, 0x89d32be0L, 0x10da7a5aL, + 0x67dd4accL, 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L, + 0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L, 0xd1bb67f1L, + 0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL, 0xd80d2bdaL, 0xaf0a1b4cL, + 0x36034af6L, 0x41047a60L, 0xdf60efc3L, 0xa867df55L, 0x316e8eefL, + 0x4669be79L, 0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L, + 0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL, 0xc5ba3bbeL, + 0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L, 0xc2d7ffa7L, 0xb5d0cf31L, + 0x2cd99e8bL, 0x5bdeae1dL, 0x9b64c2b0L, 0xec63f226L, 0x756aa39cL, + 0x026d930aL, 0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x05005713L, + 0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L, 0x92d28e9bL, + 0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L, 0x86d3d2d4L, 0xf1d4e242L, + 0x68ddb3f8L, 0x1fda836eL, 0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L, + 0x18b74777L, 0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL, + 0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L, 0xa00ae278L, + 0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, 0xa7672661L, 0xd06016f7L, + 0x4969474dL, 0x3e6e77dbL, 0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L, + 0x37d83bf0L, 0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L, + 0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L, 0xbad03605L, + 0xcdd70693L, 0x54de5729L, 0x23d967bfL, 0xb3667a2eL, 0xc4614ab8L, + 0x5d681b02L, 0x2a6f2b94L, 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL, + 0x2d02ef8dL +}; + +typedef struct _GZ1 { + long compression_format; + + long versionid1; + int state; + int done; + int deflate1_initialized; + unsigned deflate1_hash_head; + unsigned deflate1_prev_match; + int deflate1_flush; + int deflate1_match_available; + unsigned deflate1_match_length; + + char ifname[MAX_PATH_LEN]; + char ofname[MAX_PATH_LEN]; + + struct stat istat; + gz1_file_t zfile; + + int input_ismem; + char *input_ptr; + long input_bytesleft; + + int output_ismem; + char *output_ptr; + uns output_maxlen; + + int compr_level; + long time_stamp; + long ifile_size; + int ifd; + int ofd; + int part_nb; + int last_member; + int save_orig_name; + long header_bytes; + long bytes_in; + long bytes_out; + uns insize; + uns inptr; + uns outcnt; + uns ins_h; + long block_start; + uns good_match; + uni max_lazy_match; + uni prev_length; + uns max_chain_length; + uns strstart; + uns match_start; + int eofile; + uns lookahead; + ush *file_type; + int *file_method; + ulg opt_len; + ulg static_len; + ulg compressed_len; + ulg input_len; + uns last_flags; + uch flags; + uns last_lit; + uns last_dist; + uch flag_bit; + int heap_len; + int heap_max; + ulg bb; + uns bk; + ush bi_buf; + int bi_valid; + uns hufts; + int decrypt; + int ascii; + int msg_done; + int abortflag; + int decompress; + int do_lzw; + int to_stdout; + int force; + int verbose; + int quiet; + int list; + int test; + int ext_header; + int pkzip; + int method; + int level; + int no_time; + int no_name; + int exit_code; + int lbits; + int dbits; + ulg window_size; + ulg crc; + ulg adler; + + uch dist_code[512]; + uch length_code[MAX_MATCH-MIN_MATCH+1]; + int heap[2*L_CODES+1]; + uch depth[2*L_CODES+1]; + int base_length[LENGTH_CODES]; + int base_dist[D_CODES]; + ush bl_count[MAX_BITS+1]; + uch flag_buf[(LIT_BUFSIZE/8)]; + + #ifdef DYN_ALLOC + uch *inbuf; + uch *outbuf; + ush *d_buf; + uch *window; + #else + uch inbuf [INBUFSIZ +INBUF_EXTRA]; + uch outbuf[OUTBUFSIZ+OUTBUF_EXTRA]; + ush d_buf [DIST_BUFSIZE]; + uch window[2L*WSIZE]; + #endif + + #ifdef FULL_SEARCH + #define nice_match MAX_MATCH + #else + int nice_match; + #endif + + #ifdef CRYPT + uch cc; + #endif + + ct_data static_ltree[L_CODES+2]; + ct_data static_dtree[D_CODES]; + ct_data dyn_dtree[(2*D_CODES+1)]; + ct_data dyn_ltree[HEAP_SIZE]; + ct_data bl_tree[2*BL_CODES+1]; + + tree_desc l_desc; + tree_desc d_desc; + tree_desc bl_desc; + + #ifndef MAXSEG_64K + + ush prev2[1L<prev2 + #define head (gz1->prev2+WSIZE) + + #else + + ush * prev2; + ush * tab_prefix1; + + #define prev gz1->prev2 + #define head gz1->tab_prefix1 + + #endif + +} GZ1; +typedef GZ1 *PGZ1; +int gz1_size = sizeof( GZ1 ); + +/* Declare some local function protypes... */ + +/* Any routine name that can/might conflict with */ +/* other modules or object code should simply have */ +/* the standard prefix 'gz1_' added to the front. */ +/* This will only usually be any kind of problem at all */ +/* if the code is being compiled directly into the parent */ +/* instead of being built as a standalone DLL or DSO library. */ + +PGZ1 gz1_init ( void ); +int gz1_cleanup ( PGZ1 gz1 ); +ulg gz1_deflate ( PGZ1 gz1 ); +ulg gz1_deflate_fast( PGZ1 gz1 ); + +/* The rest of the routines should not need the 'gz1_' prefix. */ +/* No conflicts reported at this time. */ + +int inflate ( PGZ1 gz1 ); +int inflate_dynamic( PGZ1 gz1 ); +int inflate_stored ( PGZ1 gz1 ); +int inflate_fixed ( PGZ1 gz1 ); +void fill_window ( PGZ1 gz1 ); +void flush_outbuf ( PGZ1 gz1 ); +void flush_window ( PGZ1 gz1 ); +void bi_windup ( PGZ1 gz1 ); +void set_file_type ( PGZ1 gz1 ); +void init_block ( PGZ1 gz1 ); +int build_bl_tree ( PGZ1 gz1 ); +void read_error ( PGZ1 gz1 ); +void write_error ( PGZ1 gz1 ); +int get_header ( PGZ1 gz1, int in ); +int inflate_block ( PGZ1 gz1, int *e ); +int fill_inbuf ( PGZ1 gz1, int eof_ok ); +char *gz1_basename ( PGZ1 gz1, char *fname ); +int longest_match ( PGZ1 gz1, unsigned cur_match ); +void bi_init ( PGZ1 gz1, gz1_file_t zipfile ); +int file_read ( PGZ1 gz1, char *buf, unsigned size ); +void write_buf ( PGZ1 gz1, int fd, voidp buf, unsigned cnt ); + +void error( char *msg ); + +/* XXX - Precomputed zlib header. If you change the window size or + * compression level from the defaults, this will break badly. The + * algorithm to build this is fairly complex; you can find it in + * the file deflate.c from the zlib distribution. + */ +#define ZLIB_HEADER "\170Âœ" + +ulg adler32(ulg adler, uch *buf, unsigned len); + +int zip( +PGZ1 gz1, +int in, +int out +); + +ulg flush_block( +PGZ1 gz1, +char *buf, +ulg stored_len, +int eof +); + +void copy_block( +PGZ1 gz1, +char *buf, +unsigned len, +int header +); + +int ct_tally( +PGZ1 gz1, +int dist, +int lc +); + +void send_bits( +PGZ1 gz1, +int value, +int length +); + +void send_tree( +PGZ1 gz1, +ct_data *tree, +int max_code +); + +void send_all_trees( +PGZ1 gz1, +int lcodes, +int dcodes, +int blcodes +); + +void ct_init( +PGZ1 gz1, +ush *attr, +int *methodp +); + +void lm_init( +PGZ1 gz1, +int pack_level, +ush *flags +); + +void build_tree( +PGZ1 gz1, +tree_desc *desc +); + +void compress_block( +PGZ1 gz1, +ct_data *ltree, +ct_data *dtree +); + +void gen_bitlen( +PGZ1 gz1, +tree_desc *desc +); + +void pqdownheap( +PGZ1 gz1, +ct_data *tree, +int k +); + +int huft_build( +PGZ1 gz1, +unsigned *b, +unsigned n, +unsigned s, +ush *d, +ush *e, +struct huft **t, +int *m +); + +ulg updcrc( +PGZ1 gz1, +uch *s, +unsigned n +); + +int inflate_codes( +PGZ1 gz1, +struct huft *tl, +struct huft *td, +int bl, +int bd +); + +void gen_codes( +PGZ1 gz1, +ct_data *tree, +int max_code +); + +void scan_tree( +PGZ1 gz1, +ct_data *tree, +int max_code +); + +unsigned bi_reverse( +PGZ1 gz1, +unsigned code, +int len +); + +int huft_free( +PGZ1 gz1, +struct huft *t +); + +PGZ1 gz1_init() +{ + PGZ1 gz1=0; + + gz1 = (PGZ1) malloc( gz1_size ); + + if ( !gz1 ) + { + return 0; + } + + memset( gz1, 0, gz1_size ); + + ALLOC(uch, gz1->inbuf, INBUFSIZ +INBUF_EXTRA); + + if ( !gz1->inbuf ) + { + free( gz1 ); + return 0; + } + + ALLOC(uch, gz1->outbuf, OUTBUFSIZ+OUTBUF_EXTRA); + + if ( !gz1->outbuf ) + { + FREE( gz1->inbuf ); + free( gz1 ); + return 0; + } + + ALLOC(ush, gz1->d_buf, DIST_BUFSIZE); + + if ( !gz1->d_buf ) + { + FREE( gz1->outbuf ); + FREE( gz1->inbuf ); + free( gz1 ); + return 0; + } + + ALLOC(uch, gz1->window, 2L*WSIZE); + + if ( !gz1->window ) + { + FREE( gz1->d_buf ); + FREE( gz1->outbuf ); + FREE( gz1->inbuf ); + free( gz1 ); + return 0; + } + + #ifndef MAXSEG_64K + + #else + + ALLOC(ush, gz1->prev2, 1L<<(BITS-1) ); + + if ( !gz1->prev2 ) + { + FREE( gz1->window ); + FREE( gz1->d_buf ); + FREE( gz1->outbuf ); + FREE( gz1->inbuf ); + free( gz1 ); + return 0; + } + + ALLOC(ush, gz1->tab_prefix1, 1L<<(BITS-1) ); + + if ( !gz1->tab_prefix1 ) + { + FREE( gz1->prev2 ); + FREE( gz1->window ); + FREE( gz1->d_buf ); + FREE( gz1->outbuf ); + FREE( gz1->inbuf ); + free( gz1 ); + return 0; + } + + #endif + + gz1->method = DEFLATED; + gz1->level = 6; + gz1->no_time = -1; + gz1->no_name = -1; + gz1->exit_code = OK; + gz1->lbits = 9; + gz1->dbits = 6; + + gz1->window_size = (ulg)2*WSIZE; + gz1->crc = (ulg)0xffffffffL; + + gz1->d_desc.dyn_tree = (ct_data *) gz1->dyn_dtree; + gz1->d_desc.static_tree = (ct_data *) gz1->static_dtree; + gz1->d_desc.extra_bits = (int *) extra_dbits; + gz1->d_desc.extra_base = (int ) 0; + gz1->d_desc.elems = (int ) D_CODES; + gz1->d_desc.max_length = (int ) MAX_BITS; + gz1->d_desc.max_code = (int ) 0; + + gz1->l_desc.dyn_tree = (ct_data *) gz1->dyn_ltree; + gz1->l_desc.static_tree = (ct_data *) gz1->static_ltree; + gz1->l_desc.extra_bits = (int *) extra_lbits; + gz1->l_desc.extra_base = (int ) LITERALS+1; + gz1->l_desc.elems = (int ) L_CODES; + gz1->l_desc.max_length = (int ) MAX_BITS; + gz1->l_desc.max_code = (int ) 0; + + gz1->bl_desc.dyn_tree = (ct_data *) gz1->bl_tree; + gz1->bl_desc.static_tree = (ct_data *) 0; + gz1->bl_desc.extra_bits = (int *) extra_blbits; + gz1->bl_desc.extra_base = (int ) 0; + gz1->bl_desc.elems = (int ) BL_CODES; + gz1->bl_desc.max_length = (int ) MAX_BL_BITS; + gz1->bl_desc.max_code = (int ) 0; + + return (PGZ1) gz1; + +} + +int gz1_cleanup( PGZ1 gz1 ) +{ + + #ifndef MAXSEG_64K + + #else + + FREE( gz1->tab_prefix1 ); + FREE( gz1->prev2 ); + #endif + + FREE( gz1->window ); + FREE( gz1->d_buf ); + FREE( gz1->outbuf ); + FREE( gz1->inbuf ); + + free( gz1 ); + gz1 = 0; + + return 0; +} + +int (*read_buf)(PGZ1 gz1, char *buf, unsigned size); + +void error( char *msg ) +{ + msg = msg; +} + +int (*work)( PGZ1 gz1, int infile, int outfile ) = 0; + +#ifdef __BORLANDC__ +#pragma argsused +#endif + +int get_header( PGZ1 gz1, int in ) +{ + uch flags; + char magic[2]; + ulg stamp; + unsigned len; + unsigned part; + + if ( gz1->force && gz1->to_stdout ) + { + magic[0] = (char)try_byte(); + magic[1] = (char)try_byte(); + } + else + { + magic[0] = (char)get_byte(); + magic[1] = (char)get_byte(); + } + + gz1->method = -1; + gz1->header_bytes = 0; + gz1->last_member = RECORD_IO; + gz1->part_nb++; + + if ( memcmp(magic, GZIP_MAGIC, 2 ) == 0 || + memcmp(magic, OLD_GZIP_MAGIC, 2 ) == 0 ) + { + gz1->method = (int)get_byte(); + + if ( gz1->method != DEFLATED ) + { + gz1->exit_code = LZ1_ERROR; + + return -1; + } + + return -1; + + if ((flags & ENCRYPTED) != 0) + { + gz1->exit_code = LZ1_ERROR; + return -1; + } + + if ((flags & CONTINUATION) != 0) + { + gz1->exit_code = LZ1_ERROR; + if ( gz1->force <= 1) return -1; + } + + if ((flags & RESERVED) != 0) + { + gz1->exit_code = LZ1_ERROR; + if ( gz1->force <= 1) + return -1; + } + + stamp = (ulg)get_byte(); + stamp |= ((ulg)get_byte()) << 8; + stamp |= ((ulg)get_byte()) << 16; + stamp |= ((ulg)get_byte()) << 24; + + if ( stamp != 0 && !gz1->no_time ) + { + gz1->time_stamp = stamp; + } + + (void)get_byte(); + (void)get_byte(); + + if ((flags & CONTINUATION) != 0) + { + part = (unsigned) get_byte(); + part |= ((unsigned) get_byte())<<8; + } + + if ((flags & EXTRA_FIELD) != 0) + { + len = (unsigned) get_byte(); + len |= ((unsigned) get_byte())<<8; + + while (len--) (void)get_byte(); + } + + if ((flags & COMMENT) != 0) + { + while (get_char() != 0) ; + } + + if ( gz1->part_nb == 1 ) + { + gz1->header_bytes = gz1->inptr + 2*sizeof(long); + } + } + + return gz1->method; +} + +int fill_inbuf( PGZ1 gz1, int eof_ok ) +{ + int len; + int bytes_to_copy; + + gz1->insize = 0; + errno = 0; + + do { + if ( gz1->input_ismem ) + { + if ( gz1->input_bytesleft > 0 ) + { + bytes_to_copy = INBUFSIZ - gz1->insize; + + if ( bytes_to_copy > gz1->input_bytesleft ) + { + bytes_to_copy = gz1->input_bytesleft; + } + + memcpy( + (char*)gz1->inbuf+gz1->insize, + gz1->input_ptr, + bytes_to_copy + ); + + gz1->input_ptr += bytes_to_copy; + gz1->input_bytesleft -= bytes_to_copy; + + len = bytes_to_copy; + } + else + { + len = 0; + } + } + else + { + len = + read( + gz1->ifd, + (char*)gz1->inbuf+gz1->insize, + INBUFSIZ-gz1->insize + ); + } + + if (len == 0 || len == EOF) break; + + gz1->insize += len; + + } while( gz1->insize < INBUFSIZ ); + + if ( gz1->insize == 0 ) + { + if( eof_ok ) return EOF; + read_error( gz1 ); + } + + gz1->bytes_in += (ulg) gz1->insize; + gz1->inptr = 1; + + return gz1->inbuf[0]; +} + +ulg updcrc( +PGZ1 gz1, +uch *s, +unsigned n +) +{ + register ulg c; + + if ( s == NULL ) + { + c = 0xffffffffL; + } + else + { + c = gz1->crc; + + if ( n ) + { + do{ + c = crc_32_tab[((int)c ^ (*s++)) & 0xff] ^ (c >> 8); + + } while( --n ); + } + } + + gz1->crc = c; + + return( c ^ 0xffffffffL ); +} + +void read_error( PGZ1 gz1 ) +{ + gz1->abortflag = 1; +} + +void mod_gzip_strlwr( char *s ) +{ + char *p1=s; + + if ( s == 0 ) return; + + while ( *p1 != 0 ) + { + if ( *p1 > 96 ) *p1 = *p1 - 32; + p1++; + } +} + +#ifdef __BORLANDC__ +#pragma argsused +#endif + +char *gz1_basename( PGZ1 gz1, char *fname ) +{ + char *p; + + if ((p = strrchr(fname, PATH_SEP)) != NULL) fname = p+1; + + #ifdef PATH_SEP2 + if ((p = strrchr(fname, PATH_SEP2)) != NULL) fname = p+1; + #endif + + #ifdef PATH_SEP3 + if ((p = strrchr(fname, PATH_SEP3)) != NULL) fname = p+1; + #endif + + #ifdef SUFFIX_SEP + if ((p = strrchr(fname, SUFFIX_SEP)) != NULL) *p = '\0'; + #endif + + if (casemap('A') == 'a') mod_gzip_strlwr(fname); + + return fname; +} + +void write_buf( PGZ1 gz1, int fd, voidp buf, unsigned cnt ) +{ + unsigned n; + + if ( gz1->output_ismem ) + { + if ( ( gz1->bytes_out + cnt ) < gz1->output_maxlen ) + { + memcpy( gz1->output_ptr, buf, cnt ); + gz1->output_ptr += cnt; + } + else + { + write_error( gz1 ); + } + } + else + { + while ((n = write(fd, buf, cnt)) != cnt) + { + if (n == (unsigned)(-1)) + { + write_error( gz1 ); + } + cnt -= n; + buf = (voidp)((char*)buf+n); + } + } +} + +void write_error( PGZ1 gz1 ) +{ + gz1->abortflag = 1; +} + +#ifdef __TURBOC__ +#ifndef BC55 + +static ush ptr_offset = 0; + +void * fcalloc( +unsigned items, +unsigned size +) +{ + void * buf = farmalloc((ulg)items*size + 16L); + + if (buf == NULL) return NULL; + + if (ptr_offset == 0) + { + ptr_offset = (ush)((uch*)buf-0); + } + else if (ptr_offset != (ush)((uch*)buf-0)) + { + error("inconsistent ptr_offset"); + } + + *((ush*)&buf+1) += (ptr_offset + 15) >> 4; + *(ush*)&buf = 0; + + return buf; +} + +void fcfree( void *ptr ) +{ + *((ush*)&ptr+1) -= (ptr_offset + 15) >> 4; + *(ush*)&ptr = ptr_offset; + + farfree(ptr); +} + +#endif +#endif + +int zip( +PGZ1 gz1, +int in, +int out +) +{ + uch flags = 0; + ush attr = 0; + ush deflate_flags = 0; + + gz1->ifd = in; + gz1->ofd = out; + gz1->outcnt = 0; + + gz1->method = DEFLATED; + + put_byte(GZIP_MAGIC[0]); + put_byte(GZIP_MAGIC[1]); + put_byte(DEFLATED); + + if ( gz1->save_orig_name ) + { + flags |= ORIG_NAME; + } + + put_byte(flags); + put_long(gz1->time_stamp); + + gz1->crc = -1; + + updcrc( gz1, NULL, 0 ); + + bi_init( gz1, out ); + ct_init( gz1, &attr, &gz1->method ); + lm_init( gz1, gz1->level, &deflate_flags ); + + put_byte((uch)deflate_flags); + + put_byte(OS_CODE); + + if ( gz1->save_orig_name ) + { + char *p = gz1_basename( gz1, gz1->ifname ); + + do { + put_char(*p); + + } while (*p++); + } + + gz1->header_bytes = (long)gz1->outcnt; + + (void) gz1_deflate( gz1 ); + + put_long( gz1->crc ); + put_long( gz1->bytes_in ); + + gz1->header_bytes += 2*sizeof(long); + + flush_outbuf( gz1 ); + + return OK; +} + +ulg gz1_deflate( PGZ1 gz1 ) +{ + unsigned hash_head; + unsigned prev_match; + int flush; + int match_available = 0; + register unsigned match_length = MIN_MATCH-1; +#ifdef DEBUG + long isize; +#endif + + if (gz1->compr_level <= 3) + { + return gz1_deflate_fast(gz1); + } + + while (gz1->lookahead != 0) + { + gz1->ins_h = + (((gz1->ins_h)<window[gz1->strstart+MIN_MATCH-1])) & HASH_MASK; + + prev[ gz1->strstart & WMASK ] = hash_head = head[ gz1->ins_h ]; + + head[ gz1->ins_h ] = gz1->strstart; + + gz1->prev_length = match_length, prev_match = gz1->match_start; + match_length = MIN_MATCH-1; + + if (hash_head != NIL && gz1->prev_length < gz1->max_lazy_match && + gz1->strstart - hash_head <= MAX_DIST) { + + match_length = longest_match( gz1, hash_head ); + + if (match_length > gz1->lookahead) match_length = gz1->lookahead; + + if (match_length == MIN_MATCH && gz1->strstart-gz1->match_start > TOO_FAR){ + + match_length--; + } + } + + if (gz1->prev_length >= MIN_MATCH && match_length <= gz1->prev_length) { + + flush = ct_tally(gz1,gz1->strstart-1-prev_match, gz1->prev_length - MIN_MATCH); + + gz1->lookahead -= ( gz1->prev_length - 1 ); + gz1->prev_length -= 2; + + do { + gz1->strstart++; + + gz1->ins_h = + (((gz1->ins_h)<window[ gz1->strstart + MIN_MATCH-1])) & HASH_MASK; + + prev[ gz1->strstart & WMASK ] = hash_head = head[gz1->ins_h]; + + head[ gz1->ins_h ] = gz1->strstart; + + } while (--gz1->prev_length != 0); + match_available = 0; + match_length = MIN_MATCH-1; + gz1->strstart++; + if (flush) FLUSH_BLOCK(0), gz1->block_start = gz1->strstart; + + } else if (match_available) { + + if (ct_tally( gz1, 0, gz1->window[gz1->strstart-1] )) { + FLUSH_BLOCK(0), gz1->block_start = gz1->strstart; + } + gz1->strstart++; + gz1->lookahead--; + } else { + + match_available = 1; + gz1->strstart++; + gz1->lookahead--; + } + + while (gz1->lookahead < MIN_LOOKAHEAD && !gz1->eofile) fill_window(gz1); + } + if (match_available) ct_tally( gz1, 0, gz1->window[gz1->strstart-1] ); + + return FLUSH_BLOCK(1); + + return 0; +} + +void flush_outbuf( PGZ1 gz1 ) +{ + if ( gz1->outcnt == 0 ) + { + return; + } + + write_buf( gz1, gz1->ofd, (char *)gz1->outbuf, gz1->outcnt ); + + gz1->bytes_out += (ulg)gz1->outcnt; + gz1->outcnt = 0; +} + +void lm_init( +PGZ1 gz1, +int pack_level, +ush *flags +) +{ + register unsigned j; + + if ( pack_level < 1 || pack_level > 9 ) + { + error("bad pack level"); + } + + gz1->compr_level = pack_level; + + #if defined(MAXSEG_64K) && HASH_BITS == 15 + for (j = 0; j < HASH_SIZE; j++) head[j] = NIL; + #else + memset( (char*)head, 0, (HASH_SIZE*sizeof(*head)) ); + #endif + + gz1->max_lazy_match = configuration_table[pack_level].max_lazy; + gz1->good_match = configuration_table[pack_level].good_length; + #ifndef FULL_SEARCH + gz1->nice_match = configuration_table[pack_level].nice_length; + #endif + gz1->max_chain_length = configuration_table[pack_level].max_chain; + + if ( pack_level == 1 ) + { + *flags |= FAST; + } + else if ( pack_level == 9 ) + { + *flags |= SLOW; + } + + gz1->strstart = 0; + gz1->block_start = 0L; + #ifdef ASMV + match_init(); + #endif + + gz1->lookahead = read_buf(gz1,(char*)gz1->window, + sizeof(int) <= 2 ? (unsigned)WSIZE : 2*WSIZE); + + if (gz1->lookahead == 0 || gz1->lookahead == (unsigned)EOF) + { + gz1->eofile = 1, gz1->lookahead = 0; + return; + } + + gz1->eofile = 0; + + while (gz1->lookahead < MIN_LOOKAHEAD && !gz1->eofile) + { + fill_window(gz1); + } + + gz1->ins_h = 0; + + for ( j=0; jins_h = + (((gz1->ins_h)<window[j])) & HASH_MASK; + } +} + +void fill_window( PGZ1 gz1 ) +{ + register unsigned n, m; + + unsigned more = + (unsigned)( gz1->window_size - (ulg)gz1->lookahead - (ulg)gz1->strstart ); + + if ( more == (unsigned)EOF) + { + more--; + } + else if ( gz1->strstart >= WSIZE+MAX_DIST ) + { + memcpy((char*)gz1->window, (char*)gz1->window+WSIZE, (unsigned)WSIZE); + + gz1->match_start -= WSIZE; + gz1->strstart -= WSIZE; + + gz1->block_start -= (long) WSIZE; + + for ( n = 0; n < HASH_SIZE; n++ ) + { + m = head[n]; + head[n] = (ush)(m >= WSIZE ? m-WSIZE : NIL); + } + + for ( n = 0; n < WSIZE; n++ ) + { + m = prev[n]; + + prev[n] = (ush)(m >= WSIZE ? m-WSIZE : NIL); + } + + more += WSIZE; + } + + if ( !gz1->eofile ) + { + n = read_buf(gz1,(char*)gz1->window+gz1->strstart+gz1->lookahead, more); + + if ( n == 0 || n == (unsigned)EOF ) + { + gz1->eofile = 1; + } + else + { + gz1->lookahead += n; + } + } +} + +ulg gz1_deflate_fast( PGZ1 gz1 ) +{ + unsigned hash_head; + int flush; + unsigned match_length = 0; + + gz1->prev_length = MIN_MATCH-1; + + while (gz1->lookahead != 0) + { + gz1->ins_h = + (((gz1->ins_h)<window[ gz1->strstart + MIN_MATCH-1])) & HASH_MASK; + + prev[ gz1->strstart & WMASK ] = hash_head = head[ gz1->ins_h ]; + + head[ gz1->ins_h ] = gz1->strstart; + + if (hash_head != NIL && gz1->strstart - hash_head <= MAX_DIST) { + + match_length = longest_match( gz1, hash_head ); + + if (match_length > gz1->lookahead) match_length = gz1->lookahead; + } + if (match_length >= MIN_MATCH) { + + flush = ct_tally(gz1,gz1->strstart-gz1->match_start, match_length - MIN_MATCH); + + gz1->lookahead -= match_length; + + if (match_length <= gz1->max_lazy_match ) + { + match_length--; + + do { + gz1->strstart++; + + gz1->ins_h = + (((gz1->ins_h)<window[ gz1->strstart + MIN_MATCH-1])) & HASH_MASK; + + prev[ gz1->strstart & WMASK ] = hash_head = head[ gz1->ins_h ]; + + head[ gz1->ins_h ] = gz1->strstart; + + } while (--match_length != 0); + gz1->strstart++; + } else { + gz1->strstart += match_length; + match_length = 0; + gz1->ins_h = gz1->window[gz1->strstart]; + + gz1->ins_h = + (((gz1->ins_h)<window[gz1->strstart+1])) & HASH_MASK; + +#if MIN_MATCH != 3 + Call UPDATE_HASH() MIN_MATCH-3 more times +#endif + } + } else { + + flush = ct_tally(gz1, 0, gz1->window[gz1->strstart]); + gz1->lookahead--; + gz1->strstart++; + } + if (flush) FLUSH_BLOCK(0), gz1->block_start = gz1->strstart; + + while (gz1->lookahead < MIN_LOOKAHEAD && !gz1->eofile) fill_window(gz1); + } + + return FLUSH_BLOCK(1); +} + +void ct_init( +PGZ1 gz1, +ush *attr, +int *methodp +) +{ + #ifdef DD1 + int i,ii; + #endif + + int n; + int bits; + int length; + int code; + int dist; + + gz1->file_type = attr; + gz1->file_method = methodp; + gz1->compressed_len = gz1->input_len = 0L; + + if ( gz1->static_dtree[0].dl.len != 0 ) + { + return; + } + + length = 0; + + for ( code = 0; code < LENGTH_CODES-1; code++ ) + { + gz1->base_length[code] = length; + + for ( n = 0; n < (1<length_code[length++] = (uch)code; + } + } + + gz1->length_code[length-1] = (uch)code; + + dist = 0; + + for ( code = 0 ; code < 16; code++ ) + { + gz1->base_dist[code] = dist; + + for ( n = 0; n < (1<dist_code[dist++] = (uch)code; + } + } + + dist >>= 7; + + for ( ; code < D_CODES; code++ ) + { + gz1->base_dist[code] = dist << 7; + + for ( n = 0; n < (1<<(extra_dbits[code]-7)); n++ ) + { + gz1->dist_code[256 + dist++] = (uch)code; + } + } + + for ( bits = 0; bits <= MAX_BITS; bits++ ) + { + gz1->bl_count[bits] = 0; + } + + n = 0; + + while (n <= 143) gz1->static_ltree[n++].dl.len = 8, gz1->bl_count[8]++; + while (n <= 255) gz1->static_ltree[n++].dl.len = 9, gz1->bl_count[9]++; + while (n <= 279) gz1->static_ltree[n++].dl.len = 7, gz1->bl_count[7]++; + while (n <= 287) gz1->static_ltree[n++].dl.len = 8, gz1->bl_count[8]++; + + gen_codes(gz1,(ct_data *)gz1->static_ltree, L_CODES+1); + + for ( n = 0; n < D_CODES; n++ ) + { + gz1->static_dtree[n].dl.len = 5; + gz1->static_dtree[n].fc.code = bi_reverse( gz1, n, 5 ); + } + + init_block( gz1 ); +} + +ulg flush_block( +PGZ1 gz1, +char *buf, +ulg stored_len, +int eof +) +{ + ulg opt_lenb; + ulg static_lenb; + int max_blindex; + + gz1->flag_buf[gz1->last_flags] = gz1->flags; + + if (*gz1->file_type == (ush)UNKNOWN) set_file_type(gz1); + + build_tree( gz1, (tree_desc *)(&gz1->l_desc) ); + build_tree( gz1, (tree_desc *)(&gz1->d_desc) ); + + max_blindex = build_bl_tree( gz1 ); + + opt_lenb = (gz1->opt_len+3+7)>>3; + static_lenb = (gz1->static_len+3+7)>>3; + gz1->input_len += stored_len; + + if (static_lenb <= opt_lenb) opt_lenb = static_lenb; + +#ifdef FORCE_METHOD + + if ( level == 1 && eof && gz1->compressed_len == 0L ) +#else + if (stored_len <= opt_lenb && eof && gz1->compressed_len == 0L && 0 ) +#endif + { + if (buf == (char*)0) error ("block vanished"); + + copy_block( gz1, buf, (unsigned)stored_len, 0 ); + + gz1->compressed_len = stored_len << 3; + *gz1->file_method = STORED; + +#ifdef FORCE_METHOD + } else if (level == 2 && buf != (char*)0) { +#else + } else if (stored_len+4 <= opt_lenb && buf != (char*)0) { + +#endif + + send_bits(gz1,(STORED_BLOCK<<1)+eof, 3); + gz1->compressed_len = (gz1->compressed_len + 3 + 7) & ~7L; + gz1->compressed_len += (stored_len + 4) << 3; + + copy_block(gz1, buf, (unsigned)stored_len, 1); + +#ifdef FORCE_METHOD + } else if (level == 3) { +#else + } else if (static_lenb == opt_lenb) { +#endif + send_bits(gz1,(STATIC_TREES<<1)+eof, 3); + + compress_block( + gz1, + (ct_data *)gz1->static_ltree, + (ct_data *)gz1->static_dtree + ); + + gz1->compressed_len += 3 + gz1->static_len; + } + else + { + send_bits(gz1,(DYN_TREES<<1)+eof, 3); + + send_all_trees( + gz1, + gz1->l_desc.max_code+1, + gz1->d_desc.max_code+1, + max_blindex+1 + ); + + compress_block( + gz1, + (ct_data *)gz1->dyn_ltree, + (ct_data *)gz1->dyn_dtree + ); + + gz1->compressed_len += 3 + gz1->opt_len; + } + + init_block( gz1 ); + + if ( eof ) + { + bi_windup( gz1 ); + + gz1->compressed_len += 7; + } + + return gz1->compressed_len >> 3; +} + +#ifdef __BORLANDC__ +#pragma argsused +#endif + +unsigned bi_reverse( +PGZ1 gz1, +unsigned code, +int len +) +{ + register unsigned res = 0; + + do { + res |= code & 1; + code >>= 1, res <<= 1; + + } while (--len > 0); + + return res >> 1; +} + +void set_file_type( PGZ1 gz1 ) +{ + int n = 0; + unsigned ascii_freq = 0; + unsigned bin_freq = 0; + + while (n < 7) bin_freq += gz1->dyn_ltree[n++].fc.freq; + while (n < 128) ascii_freq += gz1->dyn_ltree[n++].fc.freq; + while (n < LITERALS) bin_freq += gz1->dyn_ltree[n++].fc.freq; + + *gz1->file_type = bin_freq > (ascii_freq >> 2) ? BINARY : ASCII; +} + +void init_block( PGZ1 gz1 ) +{ + int n; + + for (n = 0; n < L_CODES; n++) gz1->dyn_ltree[n].fc.freq = 0; + for (n = 0; n < D_CODES; n++) gz1->dyn_dtree[n].fc.freq = 0; + for (n = 0; n < BL_CODES; n++) gz1->bl_tree[n].fc.freq = 0; + + gz1->dyn_ltree[END_BLOCK].fc.freq = 1; + + gz1->opt_len = 0L; + gz1->static_len = 0L; + gz1->last_lit = 0; + gz1->last_dist = 0; + gz1->last_flags = 0; + gz1->flags = 0; + gz1->flag_bit = 1; +} + +void bi_init( PGZ1 gz1, gz1_file_t zipfile ) +{ + gz1->zfile = zipfile; + gz1->bi_buf = 0; + gz1->bi_valid = 0; + + if ( gz1->zfile != NO_FILE ) + { + read_buf = file_read; + } +} + +int ct_tally( +PGZ1 gz1, +int dist, +int lc +) +{ + int dcode; + + gz1->inbuf[gz1->last_lit++] = (uch)lc; + + if ( dist == 0 ) + { + gz1->dyn_ltree[lc].fc.freq++; + } + else + { + dist--; + + gz1->dyn_ltree[gz1->length_code[lc]+LITERALS+1].fc.freq++; + gz1->dyn_dtree[d_code(dist)].fc.freq++; + gz1->d_buf[gz1->last_dist++] = (ush)dist; + gz1->flags |= gz1->flag_bit; + } + + gz1->flag_bit <<= 1; + + if ( (gz1->last_lit & 7) == 0 ) + { + gz1->flag_buf[gz1->last_flags++] = gz1->flags; + gz1->flags = 0, gz1->flag_bit = 1; + } + + if ( gz1->level > 2 && (gz1->last_lit & 0xfff) == 0) + { + ulg out_length = (ulg) ( gz1->last_lit * 8L ); + ulg in_length = (ulg) ( gz1->strstart - gz1->block_start ); + + for ( dcode = 0; dcode < D_CODES; dcode++ ) + { + out_length += (ulg) ((gz1->dyn_dtree[dcode].fc.freq)*(5L+extra_dbits[dcode])); + } + + out_length >>= 3; + + if ( gz1->last_dist < gz1->last_lit/2 && out_length < in_length/2 ) + { + return 1; + } + } + + return( gz1->last_lit == LIT_BUFSIZE-1 || gz1->last_dist == DIST_BUFSIZE ); +} + +void compress_block( +PGZ1 gz1, +ct_data *ltree, +ct_data *dtree +) +{ + unsigned dist; + int lc; + unsigned lx = 0; + unsigned dx = 0; + unsigned fx = 0; + uch flag = 0; + unsigned code; + int extra; + + if (gz1->last_lit != 0) do { + if ((lx & 7) == 0) flag = gz1->flag_buf[fx++]; + lc = gz1->inbuf[lx++]; + if ((flag & 1) == 0) { + send_code(lc, ltree); + } else { + + code = gz1->length_code[lc]; + send_code(code+LITERALS+1, ltree); + extra = extra_lbits[code]; + if (extra != 0) { + lc -= gz1->base_length[code]; + send_bits(gz1,lc, extra); + } + dist = gz1->d_buf[dx++]; + + code = d_code(dist); + + send_code(code, dtree); + extra = extra_dbits[code]; + if (extra != 0) { + dist -= gz1->base_dist[code]; + send_bits(gz1,dist, extra); + } + } + flag >>= 1; + } while (lx < gz1->last_lit); + + send_code(END_BLOCK, ltree); +} + +#ifndef ASMV + +int longest_match( PGZ1 gz1, unsigned cur_match ) +{ + unsigned chain_length = gz1->max_chain_length; + register uch *scan = gz1->window + gz1->strstart; + register uch *match; + register int len; + int best_len = gz1->prev_length; + unsigned limit = gz1->strstart > (unsigned)MAX_DIST ? gz1->strstart - (unsigned)MAX_DIST : NIL; + +#if HASH_BITS < 8 || MAX_MATCH != 258 + error: Code too clever +#endif + +#ifdef UNALIGNED_OK + + register uch *strend = gz1->window + gz1->strstart + MAX_MATCH - 1; + register ush scan_start = *(ush*)scan; + register ush scan_end = *(ush*)(scan+best_len-1); +#else + register uch *strend = gz1->window + gz1->strstart + MAX_MATCH; + register uch scan_end1 = scan[best_len-1]; + register uch scan_end = scan[best_len]; +#endif + + if (gz1->prev_length >= gz1->good_match) { + chain_length >>= 2; + } + + do { + match = gz1->window + cur_match; + +#if (defined(UNALIGNED_OK) && MAX_MATCH == 258) + + if (*(ush*)(match+best_len-1) != scan_end || + *(ush*)match != scan_start) continue; + + scan++, match++; + do { + } while (*(ush*)(scan+=2) == *(ush*)(match+=2) && + *(ush*)(scan+=2) == *(ush*)(match+=2) && + *(ush*)(scan+=2) == *(ush*)(match+=2) && + *(ush*)(scan+=2) == *(ush*)(match+=2) && + scan < strend); + + if (*scan == *match) scan++; + + len = (MAX_MATCH - 1) - (int)(strend-scan); + scan = strend - (MAX_MATCH-1); +#else + if (match[best_len] != scan_end || + match[best_len-1] != scan_end1 || + *match != *scan || + *++match != scan[1]) continue; + + scan += 2, match++; + + do { + } while (*++scan == *++match && *++scan == *++match && + *++scan == *++match && *++scan == *++match && + *++scan == *++match && *++scan == *++match && + *++scan == *++match && *++scan == *++match && + scan < strend); + + len = MAX_MATCH - (int)(strend - scan); + scan = strend - MAX_MATCH; +#endif + if (len > best_len) { + gz1->match_start = cur_match; + best_len = len; + if (len >= gz1->nice_match) break; +#ifdef UNALIGNED_OK + scan_end = *(ush*)(scan+best_len-1); +#else + scan_end1 = scan[best_len-1]; + scan_end = scan[best_len]; +#endif + } + } while ((cur_match = prev[cur_match & WMASK]) > limit + && --chain_length != 0); + + return best_len; +} +#endif + +void send_bits( +PGZ1 gz1, +int value, +int length +) +{ + if ( gz1->bi_valid > (int) BUFSIZE - length ) + { + gz1->bi_buf |= (value << gz1->bi_valid); + + put_short(gz1->bi_buf); + + gz1->bi_buf = (ush)value >> (BUFSIZE - gz1->bi_valid); + gz1->bi_valid += length - BUFSIZE; + } + else + { + gz1->bi_buf |= value << gz1->bi_valid; + gz1->bi_valid += length; + } +} + +void build_tree( +PGZ1 gz1, +tree_desc *desc +) +{ + int elems = desc->elems; + ct_data *tree = desc->dyn_tree; + ct_data *stree = desc->static_tree; + + int n; + int m; + int max_code = -1; + int node = elems; + int new1; + + gz1->heap_len = 0, gz1->heap_max = HEAP_SIZE; + + for (n = 0; n < elems; n++) { + if (tree[n].fc.freq != 0) { + gz1->heap[++gz1->heap_len] = max_code = n; + gz1->depth[n] = 0; + } else { + tree[n].dl.len = 0; + } + } + + while (gz1->heap_len < 2) { + new1 = gz1->heap[++gz1->heap_len] = (max_code < 2 ? ++max_code : 0); + tree[new1].fc.freq = 1; + gz1->depth[new1] = 0; + gz1->opt_len--; if (stree) gz1->static_len -= stree[new1].dl.len; + } + desc->max_code = max_code; + + for (n = gz1->heap_len/2; n >= 1; n--) pqdownheap(gz1, tree, n); + + do { + n = gz1->heap[SMALLEST]; + gz1->heap[SMALLEST] = gz1->heap[gz1->heap_len--]; + pqdownheap(gz1, tree, SMALLEST); + m = gz1->heap[SMALLEST]; + gz1->heap[--gz1->heap_max] = n; + gz1->heap[--gz1->heap_max] = m; + tree[node].fc.freq = tree[n].fc.freq + tree[m].fc.freq; + gz1->depth[node] = (uch) (GZ1_MAX(gz1->depth[n], gz1->depth[m]) + 1); + tree[n].dl.dad = tree[m].dl.dad = (ush)node; + gz1->heap[SMALLEST] = node++; + pqdownheap(gz1, tree, SMALLEST); + + } while (gz1->heap_len >= 2); + + gz1->heap[--gz1->heap_max] = gz1->heap[SMALLEST]; + + gen_bitlen(gz1,(tree_desc *)desc); + + gen_codes(gz1,(ct_data *)tree, max_code); +} + +int build_bl_tree( PGZ1 gz1 ) +{ + int max_blindex; + + scan_tree( gz1, (ct_data *)gz1->dyn_ltree, gz1->l_desc.max_code ); + scan_tree( gz1, (ct_data *)gz1->dyn_dtree, gz1->d_desc.max_code ); + + build_tree( gz1, (tree_desc *)(&gz1->bl_desc) ); + + for ( max_blindex = BL_CODES-1; max_blindex >= 3; max_blindex-- ) + { + if (gz1->bl_tree[bl_order[max_blindex]].dl.len != 0) break; + } + + gz1->opt_len += 3*(max_blindex+1) + 5+5+4; + + return max_blindex; +} + +void gen_codes( +PGZ1 gz1, +ct_data *tree, +int max_code +) +{ + ush next_code[MAX_BITS+1]; + ush code = 0; + int bits; + int n; + + for ( bits = 1; bits <= MAX_BITS; bits++ ) + { + next_code[bits] = code = (code + gz1->bl_count[bits-1]) << 1; + } + + for ( n = 0; n <= max_code; n++ ) + { + int len = tree[n].dl.len; + if (len == 0) continue; + + tree[n].fc.code = bi_reverse( gz1, next_code[len]++, len ); + } + + return; +} + +void gen_bitlen( +PGZ1 gz1, +tree_desc *desc +) +{ + ct_data *tree = desc->dyn_tree; + int *extra = desc->extra_bits; + int base = desc->extra_base; + int max_code = desc->max_code; + int max_length = desc->max_length; + ct_data *stree = desc->static_tree; + int h; + int n, m; + int bits; + int xbits; + ush f; + int overflow = 0; + + for (bits = 0; bits <= MAX_BITS; bits++) gz1->bl_count[bits] = 0; + + tree[gz1->heap[gz1->heap_max]].dl.len = 0; + + for (h = gz1->heap_max+1; h < HEAP_SIZE; h++) { + n = gz1->heap[h]; + bits = tree[tree[n].dl.dad].dl.len + 1; + if (bits > max_length) bits = max_length, overflow++; + tree[n].dl.len = (ush)bits; + + if (n > max_code) continue; + + gz1->bl_count[bits]++; + xbits = 0; + if (n >= base) xbits = extra[n-base]; + f = tree[n].fc.freq; + gz1->opt_len += (ulg)f * (bits + xbits); + if (stree) gz1->static_len += (ulg)f * (stree[n].dl.len + xbits); + } + if (overflow == 0) return; + + do { + bits = max_length-1; + while (gz1->bl_count[bits] == 0) bits--; + gz1->bl_count[bits]--; + gz1->bl_count[bits+1] += 2; + gz1->bl_count[max_length]--; + + overflow -= 2; + } while (overflow > 0); + + for (bits = max_length; bits != 0; bits--) { + n = gz1->bl_count[bits]; + while (n != 0) { + m = gz1->heap[--h]; + if (m > max_code) continue; + if (tree[m].dl.len != (unsigned) bits) { + gz1->opt_len += ((long)bits-(long)tree[m].dl.len)*(long)tree[m].fc.freq; + tree[m].dl.len = (ush)bits; + } + n--; + } + } +} + +void copy_block( +PGZ1 gz1, +char *buf, +unsigned len, +int header +) +{ + #ifdef CRYPT + int t; + #endif + + bi_windup( gz1 ); + + if ( header ) + { + put_short((ush)len); + put_short((ush)~len); + } + + while( len-- ) + { + #ifdef CRYPT + if (key) zencode(*buf, t); + #endif + + put_byte(*buf++); + } +} + +int file_read( PGZ1 gz1, char *buf, unsigned size ) +{ + unsigned len = 0; + unsigned bytes_to_copy = 0; + + if ( gz1->input_ismem ) + { + if ( gz1->input_bytesleft > 0 ) + { + bytes_to_copy = size; + + if ( bytes_to_copy > (unsigned) gz1->input_bytesleft ) + { + bytes_to_copy = (unsigned) gz1->input_bytesleft; + } + + memcpy( buf, gz1->input_ptr, bytes_to_copy ); + + gz1->input_ptr += bytes_to_copy; + gz1->input_bytesleft -= bytes_to_copy; + + len = bytes_to_copy; + } + else + { + len = 0; + } + } + else + { + len = read( gz1->ifd, buf, size ); + } + + if ( len == (unsigned)(-1) || len == 0 ) + { + gz1->crc = gz1->crc ^ 0xffffffffL; + /* XXX - Do we need to do something with Adler CRC's here? + * I don't think so--they don't seem to need postprocessing. */ + return (int)len; + } + + if (gz1->compression_format != DEFLATE_FORMAT) + { + updcrc( gz1, (uch*)buf, len ); + } + else + { + gz1->adler = adler32(gz1->adler, (uch*)buf, len); + } + + gz1->bytes_in += (ulg)len; + + return (int)len; +} + +void bi_windup( PGZ1 gz1 ) +{ + if ( gz1->bi_valid > 8 ) + { + put_short(gz1->bi_buf); + } + else if ( gz1->bi_valid > 0 ) + { + put_byte(gz1->bi_buf); + } + + gz1->bi_buf = 0; + gz1->bi_valid = 0; +} + +void send_all_trees( +PGZ1 gz1, +int lcodes, +int dcodes, +int blcodes +) +{ + int rank; + + send_bits(gz1,lcodes-257, 5); + send_bits(gz1,dcodes-1, 5); + send_bits(gz1,blcodes-4, 4); + + for ( rank = 0; rank < blcodes; rank++ ) + { + send_bits(gz1,gz1->bl_tree[bl_order[rank]].dl.len, 3 ); + } + + send_tree(gz1,(ct_data *)gz1->dyn_ltree, lcodes-1); + send_tree(gz1,(ct_data *)gz1->dyn_dtree, dcodes-1); +} + +void send_tree( +PGZ1 gz1, +ct_data *tree, +int max_code +) +{ + int n; + int prevlen = -1; + int curlen; + int nextlen = tree[0].dl.len; + int count = 0; + int max_count = 7; + int min_count = 4; + + if (nextlen == 0) max_count = 138, min_count = 3; + + for ( n = 0; n <= max_code; n++ ) + { + curlen = nextlen; + nextlen = tree[n+1].dl.len; + + if (++count < max_count && curlen == nextlen) + { + continue; + } + else if (count < min_count) + { + do { send_code(curlen, gz1->bl_tree); } while (--count != 0); + } + else if (curlen != 0) + { + if ( curlen != prevlen ) + { + send_code(curlen, gz1->bl_tree); count--; + } + + send_code( REP_3_6, gz1->bl_tree ); send_bits(gz1,count-3, 2); + } + else if (count <= 10) + { + send_code(REPZ_3_10, gz1->bl_tree); send_bits(gz1,count-3, 3); + } + else + { + send_code(REPZ_11_138, gz1->bl_tree); send_bits(gz1,count-11, 7); + } + + count = 0; + prevlen = curlen; + + if (nextlen == 0) + { + max_count = 138, min_count = 3; + } + else if (curlen == nextlen) + { + max_count = 6, min_count = 3; + } + else + { + max_count = 7, min_count = 4; + } + } +} + +void scan_tree( +PGZ1 gz1, +ct_data *tree, +int max_code +) +{ + int n; + int prevlen = -1; + int curlen; + int nextlen = tree[0].dl.len; + int count = 0; + int max_count = 7; + int min_count = 4; + + if (nextlen == 0) max_count = 138, min_count = 3; + + tree[max_code+1].dl.len = (ush)0xffff; + + for ( n = 0; n <= max_code; n++ ) + { + curlen = nextlen; + nextlen = tree[n+1].dl.len; + + if ( ++count < max_count && curlen == nextlen ) + { + continue; + } + else if ( count < min_count ) + { + gz1->bl_tree[curlen].fc.freq += count; + } + else if ( curlen != 0 ) + { + if ( curlen != prevlen ) gz1->bl_tree[curlen].fc.freq++; + gz1->bl_tree[REP_3_6].fc.freq++; + } + else if ( count <= 10 ) + { + gz1->bl_tree[REPZ_3_10].fc.freq++; + } + else + { + gz1->bl_tree[REPZ_11_138].fc.freq++; + } + + count = 0; + prevlen = curlen; + + if ( nextlen == 0 ) + { + max_count = 138; + min_count = 3; + } + else if (curlen == nextlen) + { + max_count = 6; + min_count = 3; + } + else + { + max_count = 7; + min_count = 4; + } + } +} + +void pqdownheap( +PGZ1 gz1, +ct_data *tree, +int k +) +{ + int v = gz1->heap[k]; + int j = k << 1; + + while( j <= gz1->heap_len ) + { + if (j < gz1->heap_len && smaller(tree, gz1->heap[j+1], gz1->heap[j])) j++; + + if (smaller(tree, v, gz1->heap[j])) break; + + gz1->heap[k] = gz1->heap[j]; k = j; + + j <<= 1; + } + + gz1->heap[k] = v; +} + + +#define GZS_ZIP1 1 +#define GZS_ZIP2 2 +#define GZS_DEFLATE1 3 +#define GZS_DEFLATE2 4 + +int gzs_fsp ( PGZ1 gz1 ); +int gzs_zip1 ( PGZ1 gz1 ); +int gzs_zip2 ( PGZ1 gz1 ); +int gzs_deflate1( PGZ1 gz1 ); +int gzs_deflate2( PGZ1 gz1 ); + +int gzp_main( GZP_CONTROL *gzp ) +{ + PGZ1 gz1 = 0; + int rc = 0; + int final_exit_code = 0; + int ofile_flags = O_RDWR | O_CREAT | O_TRUNC | O_BINARY; + + gzp->result_code = 0; + gzp->bytes_out = 0; + + gz1 = (PGZ1) gz1_init(); + + if ( gz1 == 0 ) + { + return 0; + } + + gz1->decompress = gzp->decompress; + gz1->compression_format = gzp->compression_format; + + strcpy( gz1->ifname, gzp->input_filename ); + strcpy( gz1->ofname, gzp->output_filename ); + + gz1->input_ismem = gzp->input_ismem; + gz1->input_ptr = gzp->input_ismem_ibuf; + gz1->input_bytesleft = gzp->input_ismem_ibuflen; + + gz1->output_ismem = gzp->output_ismem; + gz1->output_ptr = gzp->output_ismem_obuf; + gz1->output_maxlen = gzp->output_ismem_obuflen; + + if ( gz1->no_time < 0 ) gz1->no_time = gz1->decompress; + if ( gz1->no_name < 0 ) gz1->no_name = gz1->decompress; + + work = zip; + + if ( !gz1->input_ismem ) + { + errno = 0; + + rc = stat( gz1->ifname, &gz1->istat ); + + if ( rc != 0 ) + { + gz1_cleanup( gz1 ); + + return 0; + } + + gz1->ifile_size = gz1->istat.st_size; + + gz1->ifd = + OPEN( + gz1->ifname, + gz1->ascii && !gz1->decompress ? O_RDONLY : O_RDONLY | O_BINARY, + RW_USER + ); + + if ( gz1->ifd == -1 ) + { + gz1_cleanup( gz1 ); + + return 0; + } + } + + if ( !gz1->output_ismem ) + { + if ( gz1->ascii && gz1->decompress ) + { + ofile_flags &= ~O_BINARY; + } + + gz1->ofd = OPEN( gz1->ofname, ofile_flags, RW_USER ); + + if ( gz1->ofd == -1 ) + { + if ( gz1->ifd ) + { + close( gz1->ifd ); + gz1->ifd = 0; + } + + gz1_cleanup( gz1 ); + + return 0; + } + } + + gz1->outcnt = 0; + gz1->insize = 0; + gz1->inptr = 0; + gz1->bytes_in = 0L; + gz1->bytes_out = 0L; + gz1->part_nb = 0; + + if ( gz1->decompress ) + { + gz1->method = get_header( gz1, gz1->ifd ); + + if ( gz1->method < 0 ) + { + if ( gz1->ifd ) + { + close( gz1->ifd ); + gz1->ifd = 0; + } + + if ( gz1->ofd ) + { + close( gz1->ofd ); + gz1->ofd = 0; + } + + return 0; + } + } + + gz1->save_orig_name = 0; + + gz1->state = GZS_ZIP1; + + for (;;) + { + gzs_fsp( gz1 ); + + if ( gz1->done == 1 ) break; + } + + if ( gz1->ifd ) + { + close( gz1->ifd ); + gz1->ifd = 0; + } + + if ( gz1->ofd ) + { + close( gz1->ofd ); + gz1->ofd = 0; + } + + gzp->result_code = gz1->exit_code; + gzp->bytes_out = gz1->bytes_out; + + final_exit_code = (int) gz1->exit_code; + + gz1_cleanup( gz1 ); + + return final_exit_code; +} + +int gzs_fsp( PGZ1 gz1 ) +{ + int rc=0; + + switch( gz1->state ) + { + case GZS_ZIP1: + + rc = gzs_zip1( gz1 ); + + break; + + case GZS_ZIP2: + + rc = gzs_zip2( gz1 ); + + break; + + case GZS_DEFLATE1: + + rc = gzs_deflate1( gz1 ); + + break; + + case GZS_DEFLATE2: + + rc = gzs_deflate2( gz1 ); + + break; + + default: + + gz1->done = 1; + + break; + } + + return( rc ); +} + + +int gzs_zip1( PGZ1 gz1 ) +{ + uch flags = 0; + ush attr = 0; + ush deflate_flags = 0; + + gz1->outcnt = 0; + + gz1->method = DEFLATED; + + if (gz1->compression_format != DEFLATE_FORMAT) + { + put_byte(GZIP_MAGIC[0]); + put_byte(GZIP_MAGIC[1]); + put_byte(DEFLATED); + } + else + { + /* Yes, I know RFC 1951 doesn't mention any header at the start of + * a deflated document, but zlib absolutely requires one. And since nearly + * all "deflate" implementations use zlib, we need to play along with this + * brain damage. */ + put_byte(ZLIB_HEADER[0]); + put_byte(ZLIB_HEADER[1]); + } + + if ( gz1->save_orig_name ) + { + flags |= ORIG_NAME; + } + + if (gz1->compression_format != DEFLATE_FORMAT) + { + put_byte(flags); + put_long(gz1->time_stamp); + + gz1->crc = -1; + updcrc( gz1, NULL, 0 ); + } + else + { + /* Deflate compression uses an Adler32 CRC, not a CRC32. */ + gz1->adler = 1L; + } + + gz1->state = GZS_ZIP2; + + return 0; +} + +int gzs_zip2( PGZ1 gz1 ) +{ + uch flags = 0; + ush attr = 0; + ush deflate_flags = 0; + + bi_init( gz1, gz1->ofd ); + ct_init( gz1, &attr, &gz1->method ); + lm_init( gz1, gz1->level, &deflate_flags ); + + if (gz1->compression_format != DEFLATE_FORMAT) + { + put_byte((uch)deflate_flags); + put_byte(OS_CODE); + if ( gz1->save_orig_name ) + { + char *p = gz1_basename( gz1, gz1->ifname ); + + do { + put_char(*p); + + } while (*p++); + } + } + + gz1->header_bytes = (long)gz1->outcnt; + + gz1->state = GZS_DEFLATE1; + + return 0; +} + +int gzs_deflate1( PGZ1 gz1 ) +{ + if ( !gz1->deflate1_initialized ) + { + gz1->deflate1_match_available = 0; + gz1->deflate1_match_length = MIN_MATCH-1; + gz1->deflate1_initialized = 1; + } + + if ( gz1->compr_level <= 3 ) + { + gz1->done = 1; + + return 0; + } + + if ( gz1->lookahead == 0 ) + { + if ( gz1->deflate1_match_available ) + { + ct_tally( gz1, 0, gz1->window[gz1->strstart-1] ); + } + + gz1->state = GZS_DEFLATE2; + + return (int) FLUSH_BLOCK(1); + } + + #ifdef STAY_HERE_FOR_A_CERTAIN_AMOUNT_OF_ITERATIONS + + while( iterations < max_iterations_per_yield ) + { + #endif + + gz1->ins_h = + (((gz1->ins_h)<window[gz1->strstart+MIN_MATCH-1])) & HASH_MASK; + + prev[ gz1->strstart & WMASK ] = gz1->deflate1_hash_head = head[ gz1->ins_h ]; + + head[ gz1->ins_h ] = gz1->strstart; + + gz1->prev_length = gz1->deflate1_match_length, gz1->deflate1_prev_match = gz1->match_start; + gz1->deflate1_match_length = MIN_MATCH-1; + + if ( gz1->deflate1_hash_head != NIL && gz1->prev_length < gz1->max_lazy_match && + gz1->strstart - gz1->deflate1_hash_head <= MAX_DIST) + { + gz1->deflate1_match_length = longest_match( gz1, gz1->deflate1_hash_head ); + + if ( gz1->deflate1_match_length > gz1->lookahead ) + { + gz1->deflate1_match_length = gz1->lookahead; + } + + if (gz1->deflate1_match_length == MIN_MATCH && gz1->strstart-gz1->match_start > TOO_FAR) + { + gz1->deflate1_match_length--; + } + } + + if ( gz1->prev_length >= MIN_MATCH && gz1->deflate1_match_length <= gz1->prev_length ) + { + gz1->deflate1_flush = + ct_tally(gz1,gz1->strstart-1-gz1->deflate1_prev_match, gz1->prev_length - MIN_MATCH); + + gz1->lookahead -= ( gz1->prev_length - 1 ); + gz1->prev_length -= 2; + + do { + gz1->strstart++; + + gz1->ins_h = + (((gz1->ins_h)<window[ gz1->strstart + MIN_MATCH-1])) & HASH_MASK; + + prev[ gz1->strstart & WMASK ] = gz1->deflate1_hash_head = head[gz1->ins_h]; + + head[ gz1->ins_h ] = gz1->strstart; + + } while (--gz1->prev_length != 0); + + gz1->deflate1_match_available = 0; + gz1->deflate1_match_length = MIN_MATCH-1; + + gz1->strstart++; + + if (gz1->deflate1_flush) FLUSH_BLOCK(0), gz1->block_start = gz1->strstart; + } + + else + { + if ( gz1->deflate1_match_available ) + { + if ( ct_tally( gz1, 0, gz1->window[gz1->strstart-1] ) ) + { + FLUSH_BLOCK(0), gz1->block_start = gz1->strstart; + } + + gz1->strstart++; + gz1->lookahead--; + } + else + { + gz1->deflate1_match_available = 1; + gz1->strstart++; + gz1->lookahead--; + } + + while (gz1->lookahead < MIN_LOOKAHEAD && !gz1->eofile ) + { + fill_window(gz1); + } + } + + return 0; +} + +int gzs_deflate2( PGZ1 gz1 ) +{ + #if !defined(NO_SIZE_CHECK) && !defined(RECORD_IO) + if (gz1->ifile_size != -1L && gz1->isize != (ulg)gz1->ifile_size) + { + } + #endif + + if (gz1->compression_format != DEFLATE_FORMAT) + { + put_long( gz1->crc ); + put_long( gz1->bytes_in ); + gz1->header_bytes += 2*sizeof(long); + } + else + { + /* Append an Adler32 CRC to our deflated data. + * Yes, I know RFC 1951 doesn't mention any CRC at the end of a + * deflated document, but zlib absolutely requires one. And since nearly + * all "deflate" implementations use zlib, we need to play along with this + * brain damage. */ + put_byte( (gz1->adler >> 24) ); + put_byte( (gz1->adler >> 16) & 0xFF ); + put_byte( (gz1->adler >> 8) & 0xFF ); + put_byte( (gz1->adler ) & 0xFF ); + gz1->header_bytes += 4*sizeof(uch); + } + + flush_outbuf( gz1 ); + + gz1->done = 1; + + return OK; +} + + +/* ========================================================================= + adler32 -- compute the Adler-32 checksum of a data stream + Copyright (C) 1995-1998 Mark Adler + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + + Modified by Eric Kidd to play nicely with mod_gzip. + */ + +#define BASE 65521L /* largest prime smaller than 65536 */ +#define NMAX 5552 +/* NMAX is the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1 */ + +#define DO1(buf,i) {s1 += buf[i]; s2 += s1;} +#define DO2(buf,i) DO1(buf,i); DO1(buf,i+1); +#define DO4(buf,i) DO2(buf,i); DO2(buf,i+2); +#define DO8(buf,i) DO4(buf,i); DO4(buf,i+4); +#define DO16(buf) DO8(buf,0); DO8(buf,8); + +ulg adler32(ulg adler, uch *buf, unsigned len) +{ + unsigned long s1 = adler & 0xffff; + unsigned long s2 = (adler >> 16) & 0xffff; + int k; + + if (buf == NULL) return 1L; + + while (len > 0) { + k = len < NMAX ? len : NMAX; + len -= k; + while (k >= 16) { + DO16(buf); + buf += 16; + k -= 16; + } + if (k != 0) do { + s1 += *buf++; + s2 += s1; + } while (--k); + s1 %= BASE; + s2 %= BASE; + } + return (s2 << 16) | s1; +} + + +/* END OF FILE */ + + diff --git a/tools/turbocharger/mod_gzip.c.diff b/tools/turbocharger/mod_gzip.c.diff new file mode 100644 index 0000000..a2c5000 --- /dev/null +++ b/tools/turbocharger/mod_gzip.c.diff @@ -0,0 +1,365 @@ +--- mod_gzip.c-old Fri Jan 26 10:50:05 2001 ++++ mod_gzip.c Fri Jan 26 15:08:26 2001 +@@ -575,10 +575,15 @@ + * The GZP request control structure... + */ + ++#define GZIP_FORMAT (0) ++#define DEFLATE_FORMAT (1) ++ + typedef struct _GZP_CONTROL { + + int decompress; /* 0=Compress 1=Decompress */ + ++ int compression_format; /* GZIP_FORMAT or DEFLATE_FORMAT */ ++ + /* Input control... */ + + int input_ismem; /* Input source is memory buffer, not file */ +@@ -2209,10 +2214,11 @@ + mod_gzip_printf( "%s: Checking for 'gzip' designator...\n",cn); + #endif + +- if ( strstr( has_encoding, "gzip" ) ) ++ if ( strstr( has_encoding, "gzip" ) || ++ strstr( has_encoding, "deflate" ) ) + { + #ifdef MOD_GZIP_DEBUG1 +- mod_gzip_printf( "%s: 'Content-encoding:' field contains 'gzip' designator...\n",cn); ++ mod_gzip_printf( "%s: 'Content-encoding:' field contains 'gzip' or 'deflate' designator...\n",cn); + mod_gzip_printf( "%s: Pre-compression is assumed.\n",cn); + mod_gzip_printf( "%s: Exit > return( DECLINED ) >\n",cn); + #endif +@@ -2237,7 +2243,7 @@ + else /* 'gzip' designator not found... */ + { + #ifdef MOD_GZIP_DEBUG1 +- mod_gzip_printf( "%s: 'Content-encoding:' field does NOT contain 'gzip' designator...\n",cn); ++ mod_gzip_printf( "%s: 'Content-encoding:' field does NOT contain 'gzip' or 'deflate' designator...\n",cn); + mod_gzip_printf( "%s: Assuming OK to proceed...\n",cn); + #endif + } +@@ -2347,10 +2353,21 @@ + if ( accept_encoding ) + { + /* ...and if it has the right 'gzip' indicator... */ +- ++ /* We record the compression format in a request note, so we ++ * can get it again later, and so it can potentially be logged. ++ */ + if ( strstr( accept_encoding, "gzip" ) ) + { + process = 1; /* ...set the 'process' flag TRUE */ ++ ap_table_setn( r->notes,"mod_gzip_compression_format", ++ ap_pstrdup(r->pool,"gzip")); ++ ++ } ++ else if ( strstr( accept_encoding, "deflate" ) ) ++ { ++ process = 1; /* ...set the 'process' flag TRUE */ ++ ap_table_setn( r->notes,"mod_gzip_compression_format", ++ ap_pstrdup(r->pool,"deflate")); + } + + }/* End 'if( accept_encoding )' */ +@@ -2388,7 +2405,7 @@ + else /* 'gzip' designator was seen in 'Accept-Encoding:' field */ + { + #ifdef MOD_GZIP_DEBUG1 +- mod_gzip_printf( "%s: 'gzip' capability specified by user-agent.\n",cn); ++ mod_gzip_printf( "%s: 'gzip' or 'deflate' capability specified by user-agent.\n",cn); + mod_gzip_printf( "%s: Assuming OK to proceed...\n",cn); + #endif + } +@@ -4093,7 +4110,8 @@ + + char tmp[ MOD_GZIP_LARGE_BUFFER_SIZE + 2 ]; /* Scratch buffer */ + +- char actual_content_encoding_name[] = "gzip"; /* Adjustable */ ++ char *actual_content_encoding_name = "gzip"; /* Adjustable */ ++ const char *compression_format; + + #ifdef MOD_GZIP_DEBUG1 + char cn[]="mod_gzip_encode_and_transmit()"; +@@ -4470,6 +4488,18 @@ + + gzp->decompress = 0; /* Perform encoding */ + ++ /* Recover the compression format we're supposed to use. */ ++ compression_format = ap_table_get(r->notes, "mod_gzip_compression_format"); ++ if (compression_format && strcmp(compression_format, "deflate") == 0) ++ { ++ actual_content_encoding_name = "deflate"; ++ gzp->compression_format = DEFLATE_FORMAT; ++ } ++ else ++ { ++ gzp->compression_format = GZIP_FORMAT; ++ } ++ + if ( input_size <= (long) conf->maximum_inmem_size ) + { + /* The input source is small enough to compress directly */ +@@ -4591,6 +4621,7 @@ + + #ifdef MOD_GZIP_DEBUG1 + mod_gzip_printf( "%s: gzp->decompress = %d\n" ,cn,gzp->decompress); ++ mod_gzip_printf( "%s: gzp->compression_format = %d\n",cn,gzp->compression_format); + mod_gzip_printf( "%s: gzp->input_ismem = %d\n", cn,gzp->input_ismem); + mod_gzip_printf( "%s: gzp->output_ismem = %d\n", cn,gzp->output_ismem); + mod_gzip_printf( "%s: gzp->input_filename = [%s]\n",cn,gzp->input_filename); +@@ -7256,6 +7287,8 @@ + }; + + typedef struct _GZ1 { ++ long compression_format; ++ + long versionid1; + int state; + int done; +@@ -7345,6 +7378,7 @@ + int dbits; + ulg window_size; + ulg crc; ++ ulg adler; + + uch dist_code[512]; + uch length_code[MAX_MATCH-MIN_MATCH+1]; +@@ -7449,6 +7483,15 @@ + + void error( char *msg ); + ++/* XXX - Precomputed zlib header. If you change the window size or ++ * compression level from the defaults, this will break badly. The ++ * algorithm to build this is fairly complex; you can find it in ++ * the file deflate.c from the zlib distribution. ++ */ ++#define ZLIB_HEADER "\170Âœ" ++ ++ulg adler32(ulg adler, uch *buf, unsigned len); ++ + int zip( + PGZ1 gz1, + int in, +@@ -9088,10 +9131,20 @@ + if ( len == (unsigned)(-1) || len == 0 ) + { + gz1->crc = gz1->crc ^ 0xffffffffL; ++ /* XXX - Do we need to do something with Adler CRC's here? ++ * I don't think so--they don't seem to need postprocessing. */ + return (int)len; + } + +- updcrc( gz1, (uch*)buf, len ); ++ if (gz1->compression_format != DEFLATE_FORMAT) ++ { ++ updcrc( gz1, (uch*)buf, len ); ++ } ++ else ++ { ++ gz1->adler = adler32(gz1->adler, (uch*)buf, len); ++ } ++ + gz1->bytes_in += (ulg)len; + + return (int)len; +@@ -9288,6 +9341,7 @@ + gz1->heap[k] = v; + } + ++ + #define GZS_ZIP1 1 + #define GZS_ZIP2 2 + #define GZS_DEFLATE1 3 +@@ -9317,6 +9371,7 @@ + } + + gz1->decompress = gzp->decompress; ++ gz1->compression_format = gzp->compression_format; + + strcpy( gz1->ifname, gzp->input_filename ); + strcpy( gz1->ofname, gzp->output_filename ); +@@ -9489,6 +9544,7 @@ + return( rc ); + } + ++ + int gzs_zip1( PGZ1 gz1 ) + { + uch flags = 0; +@@ -9499,21 +9555,40 @@ + + gz1->method = DEFLATED; + +- put_byte(GZIP_MAGIC[0]); +- put_byte(GZIP_MAGIC[1]); +- put_byte(DEFLATED); ++ if (gz1->compression_format != DEFLATE_FORMAT) ++ { ++ put_byte(GZIP_MAGIC[0]); ++ put_byte(GZIP_MAGIC[1]); ++ put_byte(DEFLATED); ++ } ++ else ++ { ++ /* Yes, I know RFC 1951 doesn't mention any header at the start of ++ * a deflated document, but zlib absolutely requires one. And since nearly ++ * all "deflate" implementations use zlib, we need to play along with this ++ * brain damage. */ ++ put_byte(ZLIB_HEADER[0]); ++ put_byte(ZLIB_HEADER[1]); ++ } + + if ( gz1->save_orig_name ) + { + flags |= ORIG_NAME; + } + +- put_byte(flags); +- put_long(gz1->time_stamp); +- +- gz1->crc = -1; ++ if (gz1->compression_format != DEFLATE_FORMAT) ++ { ++ put_byte(flags); ++ put_long(gz1->time_stamp); + +- updcrc( gz1, NULL, 0 ); ++ gz1->crc = -1; ++ updcrc( gz1, NULL, 0 ); ++ } ++ else ++ { ++ /* Deflate compression uses an Adler32 CRC, not a CRC32. */ ++ gz1->adler = 1L; ++ } + + gz1->state = GZS_ZIP2; + +@@ -9529,18 +9604,20 @@ + bi_init( gz1, gz1->ofd ); + ct_init( gz1, &attr, &gz1->method ); + lm_init( gz1, gz1->level, &deflate_flags ); +- put_byte((uch)deflate_flags); +- +- put_byte(OS_CODE); + +- if ( gz1->save_orig_name ) ++ if (gz1->compression_format != DEFLATE_FORMAT) + { +- char *p = gz1_basename( gz1, gz1->ifname ); ++ put_byte((uch)deflate_flags); ++ put_byte(OS_CODE); ++ if ( gz1->save_orig_name ) ++ { ++ char *p = gz1_basename( gz1, gz1->ifname ); + +- do { +- put_char(*p); ++ do { ++ put_char(*p); + +- } while (*p++); ++ } while (*p++); ++ } + } + + gz1->header_bytes = (long)gz1->outcnt; +@@ -9674,10 +9751,25 @@ + } + #endif + +- put_long( gz1->crc ); +- put_long( gz1->bytes_in ); +- +- gz1->header_bytes += 2*sizeof(long); ++ if (gz1->compression_format != DEFLATE_FORMAT) ++ { ++ put_long( gz1->crc ); ++ put_long( gz1->bytes_in ); ++ gz1->header_bytes += 2*sizeof(long); ++ } ++ else ++ { ++ /* Append an Adler32 CRC to our deflated data. ++ * Yes, I know RFC 1951 doesn't mention any CRC at the end of a ++ * deflated document, but zlib absolutely requires one. And since nearly ++ * all "deflate" implementations use zlib, we need to play along with this ++ * brain damage. */ ++ put_byte( (gz1->adler >> 24) ); ++ put_byte( (gz1->adler >> 16) & 0xFF ); ++ put_byte( (gz1->adler >> 8) & 0xFF ); ++ put_byte( (gz1->adler ) & 0xFF ); ++ gz1->header_bytes += 4*sizeof(uch); ++ } + + flush_outbuf( gz1 ); + +@@ -9685,6 +9777,67 @@ + + return OK; + } ++ ++ ++/* ========================================================================= ++ adler32 -- compute the Adler-32 checksum of a data stream ++ Copyright (C) 1995-1998 Mark Adler ++ ++ This software is provided 'as-is', without any express or implied ++ warranty. In no event will the authors be held liable for any damages ++ arising from the use of this software. ++ ++ Permission is granted to anyone to use this software for any purpose, ++ including commercial applications, and to alter it and redistribute it ++ freely, subject to the following restrictions: ++ ++ 1. The origin of this software must not be misrepresented; you must not ++ claim that you wrote the original software. If you use this software ++ in a product, an acknowledgment in the product documentation would be ++ appreciated but is not required. ++ 2. Altered source versions must be plainly marked as such, and must not be ++ misrepresented as being the original software. ++ 3. This notice may not be removed or altered from any source distribution. ++ ++ Modified by Eric Kidd to play nicely with mod_gzip. ++ */ ++ ++#define BASE 65521L /* largest prime smaller than 65536 */ ++#define NMAX 5552 ++/* NMAX is the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1 */ ++ ++#define DO1(buf,i) {s1 += buf[i]; s2 += s1;} ++#define DO2(buf,i) DO1(buf,i); DO1(buf,i+1); ++#define DO4(buf,i) DO2(buf,i); DO2(buf,i+2); ++#define DO8(buf,i) DO4(buf,i); DO4(buf,i+4); ++#define DO16(buf) DO8(buf,0); DO8(buf,8); ++ ++ulg adler32(ulg adler, uch *buf, unsigned len) ++{ ++ unsigned long s1 = adler & 0xffff; ++ unsigned long s2 = (adler >> 16) & 0xffff; ++ int k; ++ ++ if (buf == NULL) return 1L; ++ ++ while (len > 0) { ++ k = len < NMAX ? len : NMAX; ++ len -= k; ++ while (k >= 16) { ++ DO16(buf); ++ buf += 16; ++ k -= 16; ++ } ++ if (k != 0) do { ++ s1 += *buf++; ++ s2 += s1; ++ } while (--k); ++ s1 %= BASE; ++ s2 %= BASE; ++ } ++ return (s2 << 16) | s1; ++} ++ + + /* END OF FILE */ + diff --git a/tools/xml-rpc-api2cpp/.cvsignore b/tools/xml-rpc-api2cpp/.cvsignore new file mode 100644 index 0000000..c194ee8 --- /dev/null +++ b/tools/xml-rpc-api2cpp/.cvsignore @@ -0,0 +1 @@ +xml-rpc-api2cpp diff --git a/tools/xml-rpc-api2cpp/DataType.cpp b/tools/xml-rpc-api2cpp/DataType.cpp new file mode 100644 index 0000000..59854ba --- /dev/null +++ b/tools/xml-rpc-api2cpp/DataType.cpp @@ -0,0 +1,195 @@ +#include +#include +#include + +#include "xmlrpc-c/oldcppwrapper.hpp" +#include "DataType.hpp" + +using namespace std; + + + +//========================================================================= +// abstract class DataType +//========================================================================= +// Instances of DataType know how generate code fragments for manipulating +// a specific XML-RPC data type. + +string DataType::defaultParameterBaseName (int position) const { + ostringstream name_stream; + name_stream << typeName() << position << ends; + string name(name_stream.str()); + return name; +} + + +//========================================================================= +// class RawDataType +//========================================================================= +// We want to manipulate some XML-RPC data types as XmlRpcValue objects. + +class RawDataType : public DataType { +public: + RawDataType (const string& type_name) : DataType(type_name) {} + + virtual string parameterFragment (const string& base_name) const; + virtual string inputConversionFragment (const string& base_name) const; + virtual string returnTypeFragment () const; + virtual string outputConversionFragment (const string& var_name) const; +}; + +string RawDataType::parameterFragment (const string& base_name) const { + return "XmlRpcValue /*" + typeName() + "*/ " + base_name; +} + +string RawDataType::inputConversionFragment (const string& base_name) const { + return base_name; +} + +string RawDataType::returnTypeFragment () const { + return "XmlRpcValue /*" + typeName() + "*/"; +} + +string RawDataType::outputConversionFragment (const string& var_name) const { + return var_name; +} + + +//========================================================================= +// class SimpleDataType +//========================================================================= +// Other types can be easily converted to and from a single native type. + +class SimpleDataType : public DataType { + string mNativeType; + string mMakerFunc; + string mGetterFunc; + +public: + SimpleDataType (const string& type_name, + const string& native_type, + const string& maker_func, + const string& getter_func); + + virtual string parameterFragment (const string& base_name) const; + virtual string inputConversionFragment (const string& base_name) const; + virtual string returnTypeFragment () const; + virtual string outputConversionFragment (const string& var_name) const; +}; + +SimpleDataType::SimpleDataType (const string& type_name, + const string& native_type, + const string& maker_func, + const string& getter_func) + : DataType(type_name), + mNativeType(native_type), + mMakerFunc(maker_func), + mGetterFunc(getter_func) +{ +} + +string SimpleDataType::parameterFragment (const string& base_name) const { + return mNativeType + " " + base_name; +} + +string SimpleDataType::inputConversionFragment (const string& base_name) const +{ + return mMakerFunc + "(" + base_name + ")"; +} + +string SimpleDataType::returnTypeFragment () const { + return mNativeType; +} + +string SimpleDataType::outputConversionFragment (const string& var_name) const +{ + return var_name + "." + mGetterFunc + "()"; +} + + +//========================================================================= +// class VoidDataType +//========================================================================= +// Some XML-RPC servers declare functions as void. Such functions have +// an arbitrary return value which we should ignore. + +class VoidDataType : public DataType { +public: + VoidDataType () : DataType("void") {} + + virtual string parameterFragment (const string& base_name) const; + virtual string inputConversionFragment (const string& base_name) const; + virtual string returnTypeFragment () const; + virtual string outputConversionFragment (const string& var_name) const; +}; + +string VoidDataType::parameterFragment (const string&) const { + throw domain_error("Can't handle functions with 'void' arguments'"); + +} + +string VoidDataType::inputConversionFragment (const string&) const { + throw domain_error("Can't handle functions with 'void' arguments'"); +} + +string VoidDataType::returnTypeFragment () const { + return "void"; +} + +string VoidDataType::outputConversionFragment (const string&) const { + return "/* Return value ignored. */"; +} + + +//========================================================================= +// function findDataType +//========================================================================= +// Given the name of an XML-RPC data type, try to find a corresponding +// DataType object. + +SimpleDataType intType ("int", "XmlRpcValue::int32", + "XmlRpcValue::makeInt", + "getInt"); +SimpleDataType boolType ("bool", "bool", + "XmlRpcValue::makeBool", + "getBool"); +SimpleDataType doubleType ("double", "double", + "XmlRpcValue::makeDouble", + "getDouble"); +SimpleDataType stringType ("string", "string", + "XmlRpcValue::makeString", + "getString"); + +RawDataType dateTimeType ("dateTime"); +RawDataType base64Type ("base64"); +RawDataType structType ("struct"); +RawDataType arrayType ("array"); + +VoidDataType voidType; + +const DataType& findDataType (const string& name) { + if (name == "int" || name == "i4") + return intType; + else if (name == "boolean") + return boolType; + else if (name == "double") + return doubleType; + else if (name == "string") + return stringType; + else if (name == "dateTime.iso8601") + return dateTimeType; + else if (name == "base64") + return base64Type; + else if (name == "struct") + return structType; + else if (name == "array") + return arrayType; + else if (name == "void") + return voidType; + else + throw domain_error("Unknown XML-RPC type " + name); + + // This code should never be executed. + XMLRPC_ASSERT(0); + return intType; +} diff --git a/tools/xml-rpc-api2cpp/DataType.hpp b/tools/xml-rpc-api2cpp/DataType.hpp new file mode 100644 index 0000000..b5cab35 --- /dev/null +++ b/tools/xml-rpc-api2cpp/DataType.hpp @@ -0,0 +1,43 @@ +#include +#include + +class DataType { + std::string mTypeName; + + DataType(DataType const&) { assert(false); } + + DataType& operator= (DataType const&) { + assert(false); + return *this; + } + +public: + DataType(const std::string& type_name) : mTypeName(type_name) {} + + virtual ~DataType () {} + + // Return the name for this XML-RPC type. + virtual std::string + typeName() const { return mTypeName; } + + // Given a parameter position, calculate a unique base name for all + // parameter-related variables. + virtual std::string + defaultParameterBaseName(int position) const; + + // Virtual functions for processing parameters. + virtual std::string + parameterFragment(std::string const& base_name) const = 0; + + virtual std::string + inputConversionFragment(std::string const& base_name) const = 0; + + // Virtual functions for processing return values. + virtual std::string + returnTypeFragment () const = 0; + + virtual std::string + outputConversionFragment(std::string const& var_name) const = 0; +}; + +const DataType& findDataType(const std::string& name); diff --git a/tools/xml-rpc-api2cpp/Makefile b/tools/xml-rpc-api2cpp/Makefile new file mode 100644 index 0000000..e857094 --- /dev/null +++ b/tools/xml-rpc-api2cpp/Makefile @@ -0,0 +1,67 @@ +ifeq ($(SRCDIR)x,x) +SRCDIR = $(CURDIR)/../.. +endif +# BLDDIR is for use in places where a symbolic link won't work. +# BUILDDIR is for places in Makefile.common that can use the 'blddir' +# symbolic link (but in other directories, doesn't). +BLDDIR = $(SRCDIR) +BUILDDIR = blddir + +default: all + +include $(BLDDIR)/Makefile.config + +include ../Makefile.common + +INCLUDES = -I$(SRCDIR) -I$(SRCDIR)/include + +CXXFLAGS = $(INCLUDES) $(CXXFLAGS_COMMON) $(CFLAGS_PERSONAL) $(CADD) + +LDFLAGS = $(LADD) + +LDLIBS = -Lblddir/src/cpp -lxmlrpc_cpp -lxmlrpc_server $(CLIENT_LDLIBS) + +PROGS := + +ifeq ($(MUST_BUILD_CLIENT),yes) + PROGS += xml-rpc-api2cpp +endif + +all: $(PROGS) + +OBJECTS = \ + xml-rpc-api2cpp.o \ + DataType.o \ + XmlRpcFunction.o \ + XmlRpcClass.o \ + SystemProxy.o \ + +xml-rpc-api2cpp: \ + $(OBJECTS) \ + $(LIBXMLRPC_CPP) \ + $(LIBXMLRPC_CLIENT) \ + $(LIBXMLRPC_SERVER) \ + $(LIBXMLRPC) \ + $(LIBXMLRPC_XML) \ + $(LIBXMLRPC_UTIL) + $(CXXLD) -o $@ $(LDFLAGS) $(OBJECTS) $(LDLIBS) + +%.o:%.cpp + $(CXX) -c $(CXXFLAGS) $< + +# This Makefile.config dependency makes sure the symlinks get built before +# this make file is used for anything. + +$(BLDDIR)/Makefile.config: blddir srcdir + +include Makefile.depend + +.PHONY: clean +clean: clean-common + rm -f xml-rpc-api2cpp + +.PHONY: distclean +distclean: clean distclean-common + +.PHONY: dep +dep: dep-common diff --git a/tools/xml-rpc-api2cpp/Makefile.depend b/tools/xml-rpc-api2cpp/Makefile.depend new file mode 100644 index 0000000..e69de29 diff --git a/tools/xml-rpc-api2cpp/README b/tools/xml-rpc-api2cpp/README new file mode 100644 index 0000000..4dff2a3 --- /dev/null +++ b/tools/xml-rpc-api2cpp/README @@ -0,0 +1,6 @@ +This program generates C++ wrapper classes for XML-RPC servers. It talks +to xmlrpc-c and XML-RPC.NET servers without any problems, but tends to +choke when talking to mod_php-based servers. It looks like there is some +kind of pipelining problem. + +This code is an ongoing project. Please send feedback! diff --git a/tools/xml-rpc-api2cpp/SystemProxy.cpp b/tools/xml-rpc-api2cpp/SystemProxy.cpp new file mode 100644 index 0000000..f24fadc --- /dev/null +++ b/tools/xml-rpc-api2cpp/SystemProxy.cpp @@ -0,0 +1,39 @@ +// SystemProxy.cc - xmlrpc-c C++ proxy class +// Auto-generated by xml-rpc-api2cpp. +// But for now, this file is maintained manually. When someone figures +// out how stuff in this directory works, maybe we'll make it an automatically +// generated file. -Bryan 2005.06.05. + +#include + +#include "xmlrpc-c/oldcppwrapper.hpp" +#include "SystemProxy.hpp" + +using namespace std; + +XmlRpcValue /*array*/ SystemProxy::listMethods () { + XmlRpcValue params = XmlRpcValue::makeArray(); + XmlRpcValue result = this->mClient.call("system.listMethods", params); + return result; +} + +XmlRpcValue /*array*/ SystemProxy::methodSignature (string string1) { + XmlRpcValue params = XmlRpcValue::makeArray(); + params.arrayAppendItem(XmlRpcValue::makeString(string1)); + XmlRpcValue result = this->mClient.call("system.methodSignature", params); + return result; +} + +string SystemProxy::methodHelp (string string1) { + XmlRpcValue params = XmlRpcValue::makeArray(); + params.arrayAppendItem(XmlRpcValue::makeString(string1)); + XmlRpcValue result = this->mClient.call("system.methodHelp", params); + return result.getString(); +} + +XmlRpcValue /*array*/ SystemProxy::multicall (XmlRpcValue /*array*/ array1) { + XmlRpcValue params = XmlRpcValue::makeArray(); + params.arrayAppendItem(array1); + XmlRpcValue result = this->mClient.call("system.multicall", params); + return result; +} diff --git a/tools/xml-rpc-api2cpp/SystemProxy.hpp b/tools/xml-rpc-api2cpp/SystemProxy.hpp new file mode 100644 index 0000000..f7e80a2 --- /dev/null +++ b/tools/xml-rpc-api2cpp/SystemProxy.hpp @@ -0,0 +1,48 @@ +// SystemProxy.h - xmlrpc-c C++ proxy class +// Auto-generated by xml-rpc-api2cpp. + +#ifndef _SystemProxy_H_ +#define _SystemProxy_H_ 1 + +#include + +#include "xmlrpc-c/oldcppwrapper.hpp" + +class SystemProxy { + XmlRpcClient mClient; + +public: + SystemProxy (const XmlRpcClient& client) + : mClient(client) {} + SystemProxy (const std::string& server_url) + : mClient(XmlRpcClient(server_url)) {} + SystemProxy (const SystemProxy& o) + : mClient(o.mClient) {} + + SystemProxy& operator= (const SystemProxy& o) { + if (this != &o) mClient = o.mClient; + return *this; + } + + /* Return an array of all available XML-RPC methods on this server. */ + XmlRpcValue /*array*/ listMethods (); + + /* Given the name of a method, return an array of legal + signatures. Each signature is an array of strings. The first item of + each signature is the return type, and any others items are + parameter types. */ + XmlRpcValue /*array*/ methodSignature (std::string string1); + + /* Given the name of a method, return a help string. */ + std::string methodHelp (std::string string1); + + /* Process an array of calls, and return an array of results. Calls + should be structs of the form {'methodName': string, 'params': + array}. Each result will either be a single-item array containg the + result value, or a struct of the form {'faultCode': int, + 'faultString': string}. This is useful when you need to make lots of + small calls without lots of round trips. */ + XmlRpcValue /*array*/ multicall (XmlRpcValue /*array*/ array1); +}; + +#endif /* _SystemProxy_H_ */ diff --git a/tools/xml-rpc-api2cpp/XmlRpcClass.cpp b/tools/xml-rpc-api2cpp/XmlRpcClass.cpp new file mode 100644 index 0000000..2e9a1ba --- /dev/null +++ b/tools/xml-rpc-api2cpp/XmlRpcClass.cpp @@ -0,0 +1,78 @@ +#include +#include +#include + +using namespace std; + +#include "xmlrpc-c/oldcppwrapper.hpp" + +#include "DataType.hpp" +#include "XmlRpcFunction.hpp" +#include "XmlRpcClass.hpp" + + +//========================================================================= +// XmlRpcClass +//========================================================================= +// This class stores information about a proxy class, and knows how to +// generate code. + +XmlRpcClass::XmlRpcClass (string class_name) + : mClassName(class_name) +{ +} + +XmlRpcClass::XmlRpcClass (const XmlRpcClass& c) + : mClassName(c.mClassName), + mFunctions(c.mFunctions) +{ +} + +XmlRpcClass& XmlRpcClass::operator= (const XmlRpcClass& c) +{ + if (this == &c) + return *this; + mClassName = c.mClassName; + mFunctions = c.mFunctions; + return *this; +} + +void XmlRpcClass::addFunction (const XmlRpcFunction& function) +{ + mFunctions.push_back(function); +} + +void XmlRpcClass::printDeclaration (ostream&) +{ + cout << "class " << mClassName << " {" << endl; + cout << " XmlRpcClient mClient;" << endl; + cout << endl; + cout << "public:" << endl; + cout << " " << mClassName << " (const XmlRpcClient& client)" << endl; + cout << " : mClient(client) {}" << endl; + cout << " " << mClassName << " (const string& server_url)" << endl; + cout << " : mClient(XmlRpcClient(server_url)) {}" << endl; + cout << " " << mClassName << " (const " << mClassName << "& o)" << endl; + cout << " : mClient(o.mClient) {}" << endl; + cout << endl; + cout << " " << mClassName << "& operator= (const " + << mClassName << "& o) {" << endl; + cout << " if (this != &o) mClient = o.mClient;" << endl; + cout << " return *this;" << endl; + cout << " }" << endl; + + vector::iterator f; + for (f = mFunctions.begin(); f < mFunctions.end(); ++f) { + f->printDeclarations(cout); + } + + cout << "};" << endl; +} + +void XmlRpcClass::printDefinition (ostream&) +{ + vector::iterator f; + for (f = mFunctions.begin(); f < mFunctions.end(); ++f) { + f->printDefinitions(cout, mClassName); + } +} diff --git a/tools/xml-rpc-api2cpp/XmlRpcClass.hpp b/tools/xml-rpc-api2cpp/XmlRpcClass.hpp new file mode 100644 index 0000000..4e22a7e --- /dev/null +++ b/tools/xml-rpc-api2cpp/XmlRpcClass.hpp @@ -0,0 +1,19 @@ +#include + +class XmlRpcClass { + std::string mClassName; + std::vector mFunctions; + + +public: + XmlRpcClass (std::string class_name); + XmlRpcClass (const XmlRpcClass&); + XmlRpcClass& operator= (const XmlRpcClass&); + + std::string className () const { return mClassName; } + + void addFunction (const XmlRpcFunction& function); + + void printDeclaration (ostream& out); + void printDefinition (ostream& out); +}; diff --git a/tools/xml-rpc-api2cpp/XmlRpcFunction.cpp b/tools/xml-rpc-api2cpp/XmlRpcFunction.cpp new file mode 100644 index 0000000..311fdda --- /dev/null +++ b/tools/xml-rpc-api2cpp/XmlRpcFunction.cpp @@ -0,0 +1,137 @@ +#include +#include + +#include "xmlrpc-c/oldcppwrapper.hpp" +#include "DataType.hpp" +#include "XmlRpcFunction.hpp" + +using std::domain_error; +using std::endl; + + +//========================================================================= +// class XmlRpcFunction +//========================================================================= +// Contains everything we know about a given server function, and knows +// how to print local bindings. + +XmlRpcFunction::XmlRpcFunction(const string& function_name, + const string& method_name, + const string& help, + XmlRpcValue synopsis) + : mFunctionName(function_name), mMethodName(method_name), + mHelp(help), mSynopsis(synopsis) +{ +} + +XmlRpcFunction::XmlRpcFunction (const XmlRpcFunction& f) + : mFunctionName(f.mFunctionName), mMethodName(f.mMethodName), + mHelp(f.mHelp), mSynopsis(f.mSynopsis) +{ +} + +XmlRpcFunction& XmlRpcFunction::operator= (const XmlRpcFunction& f) { + if (this == &f) + return *this; + mFunctionName = f.mFunctionName; + mMethodName = f.mMethodName; + mHelp = f.mHelp; + mSynopsis = f.mSynopsis; + return *this; +} + +void XmlRpcFunction::printDeclarations (ostream& out) { + + // XXX - Do a sloppy job of printing documentation. + out << endl << " /* " << mHelp << " */" << endl; + + // Print each declaration. + size_t end = mSynopsis.arraySize(); + for (size_t i = 0; i < end; i++) + printDeclaration(out, i); +} + +void XmlRpcFunction::printDefinitions (ostream& out, const string& className) { + size_t end = mSynopsis.arraySize(); + for (size_t i = 0; i < end; i++) { + out << endl; + printDefinition(out, className, i); + } +} + +// Print the parameter declarations. +void XmlRpcFunction::printParameters (ostream& out, size_t synopsis_index) { + size_t end = parameterCount(synopsis_index); + bool first = true; + for (size_t i = 0; i < end; i++) { + if (first) + first = false; + else + out << ", "; + + const DataType& ptype (parameterType(synopsis_index, i)); + string basename = ptype.defaultParameterBaseName(i + 1); + out << ptype.parameterFragment(basename); + } +} + +void XmlRpcFunction::printDeclaration (ostream& out, size_t synopsis_index) { + const DataType& rtype (returnType(synopsis_index)); + out << " " << rtype.returnTypeFragment() << " " + << mFunctionName << " ("; + printParameters(out, synopsis_index); + out << ");" << endl; +} + +void XmlRpcFunction::printDefinition (ostream& out, + const string& className, + size_t synopsis_index) +{ + const DataType& rtype (returnType(synopsis_index)); + out << rtype.returnTypeFragment() << " " + << className << "::" << mFunctionName << " ("; + printParameters(out, synopsis_index); + out << ") {" << endl; + out << " XmlRpcValue params = XmlRpcValue::makeArray();" << endl; + + /* Emit code to convert the parameters into an array of XML-RPC objects. */ + size_t end = parameterCount(synopsis_index); + for (size_t i = 0; i < end; i++) { + const DataType& ptype (parameterType(synopsis_index, i)); + string basename = ptype.defaultParameterBaseName(i + 1); + out << " params.arrayAppendItem(" + << ptype.inputConversionFragment(basename) << ");" << endl; + } + + /* Emit the function call.*/ + out << " XmlRpcValue result = this->mClient.call(\"" + << mMethodName << "\", params);" << endl; + + /* Emit the return statement. */ + out << " return " << rtype.outputConversionFragment("result") + << ";" << endl; + out << "}" << endl; +} + +const DataType& XmlRpcFunction::returnType (size_t synopsis_index) { + XmlRpcValue func_synop = mSynopsis.arrayGetItem(synopsis_index); + return findDataType(func_synop.arrayGetItem(0).getString()); +} + +size_t XmlRpcFunction::parameterCount (size_t synopsis_index) { + XmlRpcValue func_synop = mSynopsis.arrayGetItem(synopsis_index); + size_t size = func_synop.arraySize(); + if (size < 1) + throw domain_error("Synopsis contained no items"); + return size - 1; +} + +const DataType& XmlRpcFunction::parameterType (size_t synopsis_index, + size_t parameter_index) +{ + XmlRpcValue func_synop = mSynopsis.arrayGetItem(synopsis_index); + XmlRpcValue param = func_synop.arrayGetItem(parameter_index + 1); + return findDataType(param.getString()); +} + + diff --git a/tools/xml-rpc-api2cpp/XmlRpcFunction.hpp b/tools/xml-rpc-api2cpp/XmlRpcFunction.hpp new file mode 100644 index 0000000..4999805 --- /dev/null +++ b/tools/xml-rpc-api2cpp/XmlRpcFunction.hpp @@ -0,0 +1,37 @@ + +#include +#include + +using std::string; +using std::ostream; + +class XmlRpcFunction { + string mFunctionName; + string mMethodName; + string mHelp; + XmlRpcValue mSynopsis; + +public: + XmlRpcFunction(const string& function_name, + const string& method_name, + const string& help, + XmlRpcValue synopsis); + + XmlRpcFunction (const XmlRpcFunction&); + XmlRpcFunction& operator= (const XmlRpcFunction&); + + void printDeclarations (ostream& out); + void printDefinitions (ostream& out, const string& className); + +private: + void printParameters (ostream& out, size_t synopsis_index); + void printDeclaration (ostream& out, size_t synopsis_index); + void printDefinition (ostream& out, + const string& className, + size_t synopsis_index); + + const DataType& returnType (size_t synopsis_index); + size_t parameterCount (size_t synopsis_index); + const DataType& parameterType (size_t synopsis_index, + size_t parameter_index); +}; diff --git a/tools/xml-rpc-api2cpp/xml-rpc-api2cpp.1 b/tools/xml-rpc-api2cpp/xml-rpc-api2cpp.1 new file mode 100644 index 0000000..a1c8b80 --- /dev/null +++ b/tools/xml-rpc-api2cpp/xml-rpc-api2cpp.1 @@ -0,0 +1,62 @@ +.\" Hey, EMACS: -*- nroff -*- +.\" First parameter, NAME, should be all caps +.\" Second parameter, SECTION, should be 1-8, maybe w/ subsection +.\" other parameters are allowed: see man(7), man(1) +.TH XML-RPC-API2CPP 1 "June 27, 2001" +.\" Please adjust this date whenever revising the manpage. +.\" +.\" Some roff macros, for reference: +.\" .nh disable hyphenation +.\" .hy enable hyphenation +.\" .ad l left justify +.\" .ad b justify to both left and right margins +.\" .nf disable filling +.\" .fi enable filling +.\" .br insert line break +.\" .sp insert n+1 empty lines +.\" for manpage-specific macros, see man(7) +.SH NAME +xml-rpc-api2cpp \- Make a C++ wrapper class for an XML-RPC API +.SH SYNOPSIS +.B xml-rpc-api2cpp +\fIserver-url\fR \fIremote-method-prefix\fR \fIc++-class-name\fR +.SH DESCRIPTION +xml-rpc-api2cpp queries an XML-RPC server using the XML-RPC +Instrospection API designed by Edd Dumbill. It then prints a C++ +wrapper class to standard output. This class can be used with +xmlrpc-c's C++ API. +.PP +You can find a list of supported XML-RPC server libraries (and patches +for many others) at \fBhttp://xmlrpc-c.sourceforge.net/hacks.php\fR. +.SH OPTIONS +.TP +.I server-url +The name of the server to query. Try +\fBhttp://xmlrpc-c.sourceforge.net/cgi-bin/interop.cgi\fR. +.TP +.I remote-method-prefix +The prefix of the methods to wrap. For example, to wrap all the +system.* calls, you could specify "system". +.TP +.I c++-class-name +The name of the C++ class to generate. Try "SystemProxy". +.SH BUGS +xml-rpc-api2cpp can't talk to certain PHP servers based on Edd +Dumbill's PHP library, because the trailing bytes of the XML-RPC +message get truncated in HTTP pipelining mode. It's not clear whether +this is a PHP, Apache or w3c-libwww bug. +.PP +xml-rpc-api2cpp assumes that method descriptions are ASCII text, not +HTML as specified in the standard. (In practice, both conventions are +often seen.) It may also get unhappy if method descriptions contain +"*/". +.PP +In general, error messages and diagnostics are still fairly poor. +.SH SEE ALSO +.BR xmlrpc-c (7), +.BR xml-rpc-api2txt (1). +.PP +This program is part of xmlrpc-c. +.SH AUTHOR +This manual page was written by Eric Kidd . +It may be distributed under the same terms as the rest of xmlrpc-c. diff --git a/tools/xml-rpc-api2cpp/xml-rpc-api2cpp.cpp b/tools/xml-rpc-api2cpp/xml-rpc-api2cpp.cpp new file mode 100644 index 0000000..756d50d --- /dev/null +++ b/tools/xml-rpc-api2cpp/xml-rpc-api2cpp.cpp @@ -0,0 +1,157 @@ +#include +#include + +#include "xmlrpc-c/oldcppwrapper.hpp" + +#include "DataType.hpp" +#include "XmlRpcFunction.hpp" +#include "XmlRpcClass.hpp" +#include "SystemProxy.hpp" + +using namespace std; + +#define NAME "xml-rpc-api2cpp" +#define VERSION "0.1" + + +//========================================================================= +// function get_class_info +//========================================================================= +// Connect to a remote server and extract the information we'll need to +// build a proxy class. + +XmlRpcClass get_class_info (string server_url, + string class_prefix, + string class_name) +{ + // Create a place to store our data. + XmlRpcClass info(class_name); + + // Create a proxy class. + SystemProxy system(server_url); + + // Fetch the full list of methods, and process the ones we want. + XmlRpcValue methods = system.listMethods(); + size_t end = methods.arraySize(); + for (size_t i = 0; i < end; i++) { + + // Break the method name into two pieces. + string method_prefix; + string function_name; + string method_name = methods.arrayGetItem(i).getString(); + size_t last_dot = method_name.rfind('.'); + if (last_dot == string::npos) { + function_name = method_name; + } else { + method_prefix = string(method_name, 0, last_dot); + function_name = string(method_name, last_dot + 1); + } + + // Decide whether we care about this function. + if (method_prefix == class_prefix) { + + // Fetch some information about the function. + string help = system.methodHelp(method_name); + XmlRpcValue signature = system.methodSignature(method_name); + + // Add this function to our class information. + XmlRpcFunction func(function_name, method_name, help, signature); + info.addFunction(func); + } + } + + return info; +} + + +//========================================================================= +// function print_header +//========================================================================= +// Print a complete header for the specified class. + +void print_header (ostream& out, XmlRpcClass& class_info) { + string class_name = class_info.className(); + out << "// " << class_name << ".h - xmlrpc-c C++ proxy class" << endl; + out << "// Auto-generated by xml-rpc-api2cpp." << endl; + out << endl; + + string header_symbol = "_" + class_name + "_H_"; + out << "#ifndef " << header_symbol << endl; + out << "#define " << header_symbol << " 1" << endl; + out << endl; + out << "#include " << endl; + out << endl; + + class_info.printDeclaration(cout); + + out << endl; + out << "#endif /* " << header_symbol << " */" << endl; +} + + +//========================================================================= +// function print_cc_file +//========================================================================= +// Print a complete header for the specified class. + +void print_cc_file (ostream& out, XmlRpcClass& class_info) { + string class_name = class_info.className(); + out << "// " << class_name << ".cc - xmlrpc-c C++ proxy class" << endl; + out << "// Auto-generated by xml-rpc-api2cpp." << endl; + out << endl; + + out << "#include " << endl; + out << "#include \"" << class_name << ".h\"" << endl; + + class_info.printDefinition(cout); +} + + +//========================================================================= +// function main +//========================================================================= +// For now, just a test harness. + +int main (int argc, char **argv) { + + /* Parse our command-line arguments. */ + if (argc != 4) { + cerr << argv[0] << ": Usage:" << endl + << " xml-rpc-api2cpp " + << endl << endl + << "Sample arguments:" << endl + << " server_url = http://localhost/RPC2" << endl + << " method_prefix = system" << endl + << " local_class = SystemProxy" << endl; + exit(1); + } + string server_url = argv[1]; + string method_prefix = argv[2]; + string local_class = argv[3]; + + int status = 0; + XmlRpcClient::Initialize(NAME, VERSION); + + try { + XmlRpcClass system = get_class_info(server_url, + method_prefix, + local_class); + print_header(cout, system); + cout << endl; + print_cc_file(cout, system); + } catch (XmlRpcFault& fault) { + cerr << argv[0] << ": XML-RPC fault #" << fault.getFaultCode() + << ": " << fault.getFaultString() << endl; + status = 1; + } catch (logic_error& err) { + cerr << argv[0] << ": " << err.what() << endl; + status = 1; + } catch (...) { + cerr << argv[0] << ": Unknown exception" << endl; + status = 1; + } + + XmlRpcClient::Terminate(); + + return status; +} diff --git a/tools/xml-rpc-api2txt b/tools/xml-rpc-api2txt new file mode 100755 index 0000000..e771463 --- /dev/null +++ b/tools/xml-rpc-api2txt @@ -0,0 +1,147 @@ +#!/usr/bin/perl -w +# +# A handy little program to get the documentation of the available +# methods from an XML-RPC service (via XML-RPC Introspection) and +# print it out nicely formatted. +# +# (I wrote this in Perl because of all the spiffy report-generation +# features.) +# +# You'll need to get Ken MacLeod's Frontier::RPC2 module from CPAN to use +# this. +# +# Eric Kidd +# +# This script is part of xmlrpc-c, and may be used and distributed under +# the same terms as the rest of the package. + +use strict; + +# One global variable for use with Perl's format routines, and one for +# use inside an 'exec' block. +use vars qw/$helptext $method_list/; + +# Try to load our Perl XML-RPC bindings, but fail gracefully. +eval { + require Frontier::Client; +}; +if ($@) { + print STDERR <<"EOD"; +This script requires Ken MacLeod\'s Frontier::RPC2 module. You can get this +from CPAN or from his website at http://bitsko.slc.ut.us/~ken/xml-rpc/ . + +For installation instructions, see the XML-RPC HOWTO at: + http://www.linuxdoc.org/HOWTO/XML-RPC-HOWTO/index.html + +EOD + exit 1; +} + +# Parse our command-line arguments. +if (@ARGV != 1 || $ARGV[0] eq "--help") { + print STDERR "Usage: xml-rpc-api2txt serverURL\n"; + exit 1; +} + +my $server = Frontier::Client->new(url => $ARGV[0]); + +# Try (very carefully) to get our a list of methods from the server. +local $method_list; +eval { + $method_list = $server->call('system.listMethods'); +}; +if ($@) { + print STDERR <<"EOD"; +An error occurred while trying to talk to the XML-RPC server: + + $@ + +This may have been caused by several things--the server might not support +introspection, it might not be an XML-RPC server, or your network might be +down. Try the following: + + xml-rpc-api2txt http://xmlrpc-c.sourceforge.net/api/sample.php + +EOD + exit 1; +} + +# Enter the methods into a hashtable. +my @methods = sort @$method_list; +my %method_table; +foreach my $method (@methods) { + $method_table{$method} = {}; +} + +# Get more information for the hash table. Since we need to make lots and +# lots of very small XML-RPC calls, we'd like to use system.multicall to +# reduce the latency. +if (defined $method_table{'system.multicall'}) { + + # This is messy but fast. Everybody hates HTTP round-trip lag, right? + my @call; + foreach my $method (@methods) { + push @call, {methodName => 'system.methodSignature', + params => [$method]}; + push @call, {methodName => 'system.methodHelp', + params => [$method]}; + } + my @result = @{$server->call('system.multicall', \@call)}; + for (my $i = 0; $i < @methods; $i++) { + my $method = $methods[$i]; + $method_table{$method}->{'signatures'} = $result[2*$i]->[0]; + $method_table{$method}->{'help'} = $result[2*$i+1]->[0]; + } +} else { + + # This is easy but slow (especially over backbone links). + foreach my $method (@methods) { + my $signature = $server->call('system.methodSignature', $method); + my $help = $server->call('system.methodHelp', $method); + $method_table{$method}->{'signatures'} = $signature; + $method_table{$method}->{'help'} = $help; + } +} + +# Now, we need to dump the API. +print <<"EOD"; +XML-RPC API for $ARGV[0] + +See http://www.linuxdoc.org/HOWTO/XML-RPC-HOWTO/index.html for instructions +on using XML-RPC with Perl, Python, Java, C, C++, PHP, etc. +EOD +foreach my $method (@methods) { + print "\n"; + + # Print a synopsis of the function. + if ($method_table{$method}->{'signatures'} eq 'undef') { + # No documentation. Bad server. No biscuit. + print "unknown $method (...)\n"; + } else { + for my $signature (@{$method_table{$method}->{'signatures'}}) { + my $return_type = shift @$signature; + my $arguments = join(", ", @$signature); + print "$return_type $method ($arguments)\n"; + } + } + print "\n"; + + my $help = $method_table{$method}->{'help'}; + if ($help =~ /\n/) { + # Text has already been broken into lines by the server, so just + # indent it by two spaces and hope for the best. + my @lines = split(/\n/, $help); + my $help = " " . join("\n ", @lines); + print "$help\n"; + } else { + # Print our help text in a nicely-wrapped fashion using Perl's + # formatting routines. + $helptext = $method_table{$method}->{'help'}; + write; + } +} + +format STDOUT = + ^<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<~~ + $helptext +. diff --git a/tools/xml-rpc-api2txt.1 b/tools/xml-rpc-api2txt.1 new file mode 100644 index 0000000..a9e1ee3 --- /dev/null +++ b/tools/xml-rpc-api2txt.1 @@ -0,0 +1,47 @@ +.\" Hey, EMACS: -*- nroff -*- +.\" First parameter, NAME, should be all caps +.\" Second parameter, SECTION, should be 1-8, maybe w/ subsection +.\" other parameters are allowed: see man(7), man(1) +.TH XML-RPC-API2TXT 1 "June 27, 2001" +.\" Please adjust this date whenever revising the manpage. +.\" +.\" Some roff macros, for reference: +.\" .nh disable hyphenation +.\" .hy enable hyphenation +.\" .ad l left justify +.\" .ad b justify to both left and right margins +.\" .nf disable filling +.\" .fi enable filling +.\" .br insert line break +.\" .sp insert n+1 empty lines +.\" for manpage-specific macros, see man(7) +.SH NAME +xml-rpc-api2txt \- Print out a description of an XML-RPC API as text +.SH SYNOPSIS +.B xml-rpc-api2txt +\fIserver-url\fR +.SH DESCRIPTION +xml-rpc-api2txt queries an XML-RPC server using the XML-RPC +Instrospection API designed by Edd Dumbill. It then prints the +results to standard output in a nicely formatted form, suitable for +sending via e-mail. +.PP +You can find a list of supported XML-RPC server libraries (and patches +for many others) at \fBhttp://xmlrpc-c.sourceforge.net/hacks.php\fR. +.SH OPTIONS +.TP +.I server-url +The name of the server to query. Try +\fBhttp://xmlrpc-c.sourceforge.net/cgi-bin/interop.cgi\fR. +.SH BUGS +xml-rpc-api2txt assumes that method descriptions are ASCII text, not +HTML as specified in the standard. (In practice, both conventions are +often seen.) +.SH SEE ALSO +.BR xmlrpc-c (7), +.BR xml-rpc-api2cpp (1). +.PP +This program is part of xmlrpc-c. +.SH AUTHOR +This manual page was written by Eric Kidd . +It may be distributed under the same terms as the rest of xmlrpc-c. diff --git a/tools/xmlrpc/.cvsignore b/tools/xmlrpc/.cvsignore new file mode 100644 index 0000000..73a3b1b --- /dev/null +++ b/tools/xmlrpc/.cvsignore @@ -0,0 +1 @@ +xmlrpc diff --git a/tools/xmlrpc/Makefile b/tools/xmlrpc/Makefile new file mode 100644 index 0000000..fcc95ea --- /dev/null +++ b/tools/xmlrpc/Makefile @@ -0,0 +1,66 @@ +ifeq ($(SRCDIR)x,x) +SRCDIR = $(CURDIR)/../.. +endif +# BLDDIR is for use in places where a symbolic link won't work. +# BUILDDIR is for places in Makefile.common that can use the 'blddir' +# symbolic link (but in other directories, doesn't). +BLDDIR = $(SRCDIR) +BUILDDIR = blddir + +default: all + +include $(BLDDIR)/Makefile.config + +PROGRAMS_TO_INSTALL = xmlrpc + +include ../Makefile.common + +INCLUDES = -I$(SRCDIR) -I$(SRCDIR)/include -I$(SRCDIR)/lib/util/include + +CFLAGS = $(CFLAGS_COMMON) $(INCLUDES) $(CFLAGS_PERSONAL) $(CADD) + +LDFLAGS = $(LADD) + +all: xmlrpc + +UTIL_OBJS = cmdline_parser.o getoptx.o casprintf.o +UTILS = $(UTIL_OBJS:%=$(UTIL_DIR)/%) + +# These are the Libtool .la files. We use them only for make dependencies. +# We'd like to use these in the link rule, by using libtool --link, but +# Libtool adds -l options to the link to cover the dependencies that are +# recorded inside the shared libraries. And it doesn't add the necessary +# -L options (it can't), so we end up with a messy mixture of the two +# forms of specifying libraries. + +LIBS = $(LIBXMLRPC_CLIENT) $(LIBXMLRPC) $(LIBXMLRPC_XML) $(LIBXMLRPC_UTIL) + +XMLRPC_OBJS = xmlrpc.o dumpvalue.o + +xmlrpc: $(XMLRPC_OBJS) $(LIBS) $(UTILS) + $(CCLD) -o $@ $(LDFLAGS) $(XMLRPC_OBJS) $(UTILS) $(CLIENT_LDLIBS) + +%.o:%.c + $(CC) -c $(CFLAGS) $< + +*.c: config.h + +config.h: + $(LN_S) $(BLDDIR)/xmlrpc_config.h $@ + +# This Makefile.config dependency makes sure the symlinks get built before +# this make file is used for anything. + +$(BLDDIR)/Makefile.config: blddir srcdir + +include Makefile.depend + +.PHONY: dep +dep: dep-common + +.PHONY: clean +clean: clean-common + rm -f xmlrpc config.h + +.PHONY: distclean +distclean: clean distclean-common diff --git a/tools/xmlrpc/Makefile.depend b/tools/xmlrpc/Makefile.depend new file mode 100644 index 0000000..e69de29 diff --git a/tools/xmlrpc/dumpvalue.c b/tools/xmlrpc/dumpvalue.c new file mode 100644 index 0000000..4547380 --- /dev/null +++ b/tools/xmlrpc/dumpvalue.c @@ -0,0 +1,367 @@ +/* dumpvalue() service, which prints to Standard Output the value of + an xmlrpc_value. + + We've put this in a separate module in hopes that it eventually can be + used for debugging purposes in other places. +*/ + +#define _GNU_SOURCE + +#include +#include +#include + +#include "config.h" /* information about this build environment */ +#include "casprintf.h" +#include "mallocvar.h" + +#include "xmlrpc-c/base.h" + +#include "dumpvalue.h" + + + +static void +dumpInt(const char * const prefix, + xmlrpc_value * const valueP) { + + xmlrpc_env env; + xmlrpc_int value; + + xmlrpc_env_init(&env); + + xmlrpc_parse_value(&env, valueP, "i", &value); + + if (env.fault_occurred) + printf("Unable to parse integer xmlrpc_value %lx. %s\n", + (unsigned long)valueP, env.fault_string); + else + printf("%sInteger: %d\n", prefix, value); + + xmlrpc_env_clean(&env); +} + + + +static void +dumpBool(const char * const prefix, + xmlrpc_value * const valueP) { + + xmlrpc_env env; + xmlrpc_bool value; + + xmlrpc_env_init(&env); + + xmlrpc_parse_value(&env, valueP, "b", &value); + + if (env.fault_occurred) + printf("Unable to parse boolean xmlrpc_value %lx. %s\n", + (unsigned long)valueP, env.fault_string); + else + printf("%sBoolean: %s\n", prefix, value ? "TRUE" : "FALSE"); + + xmlrpc_env_clean(&env); +} + + + + +static void +dumpDouble(const char * const prefix, + xmlrpc_value * const valueP) { + + xmlrpc_env env; + xmlrpc_double value; + + xmlrpc_env_init(&env); + + xmlrpc_parse_value(&env, valueP, "d", &value); + + if (env.fault_occurred) + printf("Unable to parse floating point number xmlrpc_value %lx. %s\n", + (unsigned long)valueP, env.fault_string); + else + printf("%sFloating Point: %f\n", prefix, value); + + xmlrpc_env_clean(&env); +} + + + +static void +dumpDatetime(const char * const prefix, + xmlrpc_value * const valueP) { + + printf("%sDon't know how to print datetime value %lx.\n", + prefix, (unsigned long) valueP); +} + + + +static void +dumpString(const char * const prefix, + xmlrpc_value * const valueP) { + + xmlrpc_env env; + const char * value; + + xmlrpc_env_init(&env); + + xmlrpc_parse_value(&env, valueP, "s", &value); + + if (env.fault_occurred) + printf("Unable to parse string xmlrpc_value %lx. %s\n", + (unsigned long)valueP, env.fault_string); + else + printf("%sString: '%s'\n", prefix, value); + + xmlrpc_env_clean(&env); +} + + + +static void +dumpBase64(const char * const prefix, + xmlrpc_value * const valueP) { + + xmlrpc_env env; + const unsigned char * value; + size_t length; + + xmlrpc_env_init(&env); + + xmlrpc_parse_value(&env, valueP, "6", &value, &length); + + if (env.fault_occurred) + printf("Unable to parse base64 bit string xmlrpc_value %lx. %s\n", + (unsigned long)valueP, env.fault_string); + else { + unsigned int i; + + printf("%sBit string: ", prefix); + for (i = 0; i < length; ++i) + printf("%02x", value[i]); + } + xmlrpc_env_clean(&env); +} + + + +static void +dumpArray(const char * const prefix, + xmlrpc_value * const arrayP) { + + xmlrpc_env env; + unsigned int arraySize; + + xmlrpc_env_init(&env); + + XMLRPC_ASSERT_ARRAY_OK(arrayP); + + arraySize = xmlrpc_array_size(&env, arrayP); + if (env.fault_occurred) + printf("Unable to get array size. %s\n", env.fault_string); + else { + int const spaceCount = strlen(prefix); + + unsigned int i; + const char * blankPrefix; + + printf("%sArray of %u items:\n", prefix, arraySize); + + casprintf(&blankPrefix, "%*s", spaceCount, ""); + + for (i = 0; i < arraySize; ++i) { + xmlrpc_value * valueP; + + xmlrpc_array_read_item(&env, arrayP, i, &valueP); + + if (env.fault_occurred) + printf("Unable to get array item %u\n", i); + else { + const char * prefix2; + + casprintf(&prefix2, "%s Index %2u ", blankPrefix, i); + dumpValue(prefix2, valueP); + strfree(prefix2); + + xmlrpc_DECREF(valueP); + } + } + strfree(blankPrefix); + } + xmlrpc_env_clean(&env); +} + + + +static void +dumpStructMember(const char * const prefix, + xmlrpc_value * const structP, + unsigned int const index) { + + xmlrpc_env env; + + xmlrpc_value * keyP; + xmlrpc_value * valueP; + + xmlrpc_env_init(&env); + + xmlrpc_struct_read_member(&env, structP, index, &keyP, &valueP); + + if (env.fault_occurred) + printf("Unable to get struct member %u\n", index); + else { + int const blankCount = strlen(prefix); + const char * prefix2; + const char * blankPrefix; + + casprintf(&prefix2, "%s Key: ", prefix); + dumpValue(prefix2, keyP); + strfree(prefix2); + + casprintf(&blankPrefix, "%*s", blankCount, ""); + + casprintf(&prefix2, "%s Value: ", blankPrefix); + dumpValue(prefix2, valueP); + strfree(prefix2); + + strfree(blankPrefix); + + xmlrpc_DECREF(keyP); + xmlrpc_DECREF(valueP); + } + xmlrpc_env_clean(&env); +} + + + +static void +dumpStruct(const char * const prefix, + xmlrpc_value * const structP) { + + xmlrpc_env env; + unsigned int structSize; + + xmlrpc_env_init(&env); + + structSize = xmlrpc_struct_size(&env, structP); + if (env.fault_occurred) + printf("Unable to get struct size. %s\n", env.fault_string); + else { + unsigned int i; + + printf("%sStruct of %u members:\n", prefix, structSize); + + for (i = 0; i < structSize; ++i) { + const char * prefix1; + + if (i == 0) + prefix1 = strdup(prefix); + else { + int const blankCount = strlen(prefix); + casprintf(&prefix1, "%*s", blankCount, ""); + } + dumpStructMember(prefix1, structP, i); + + strfree(prefix1); + } + } + xmlrpc_env_clean(&env); +} + + + +static void +dumpCPtr(const char * const prefix, + xmlrpc_value * const valueP) { + + xmlrpc_env env; + const char * value; + + xmlrpc_env_init(&env); + + xmlrpc_parse_value(&env, valueP, "p", &value); + + if (env.fault_occurred) + printf("Unable to parse C pointer xmlrpc_value %lx. %s\n", + (unsigned long)valueP, env.fault_string); + else + printf("%sC pointer: '%p'\n", prefix, value); + + xmlrpc_env_clean(&env); +} + + + +static void +dumpNil(const char * const prefix, + xmlrpc_value * const valueP) { + + xmlrpc_env env; + + xmlrpc_env_init(&env); + + xmlrpc_parse_value(&env, valueP, "n"); + + if (env.fault_occurred) + printf("Unable to parse nil value xmlrpc_value %lx. %s\n", + (unsigned long)valueP, env.fault_string); + else + printf("%sNil\n", prefix); + + xmlrpc_env_clean(&env); +} + + + +static void +dumpUnknown(const char * const prefix, + xmlrpc_value * const valueP) { + + printf("%sDon't recognize value type %u of xmlrpc_value %lx.\n", + prefix, xmlrpc_value_type(valueP), (unsigned long)valueP); + printf("%sCan't print it.\n", prefix); +} + + + +void +dumpValue(const char * const prefix, + xmlrpc_value * const valueP) { + + switch (xmlrpc_value_type(valueP)) { + case XMLRPC_TYPE_INT: + dumpInt(prefix, valueP); + break; + case XMLRPC_TYPE_BOOL: + dumpBool(prefix, valueP); + break; + case XMLRPC_TYPE_DOUBLE: + dumpDouble(prefix, valueP); + break; + case XMLRPC_TYPE_DATETIME: + dumpDatetime(prefix, valueP); + break; + case XMLRPC_TYPE_STRING: + dumpString(prefix, valueP); + break; + case XMLRPC_TYPE_BASE64: + dumpBase64(prefix, valueP); + break; + case XMLRPC_TYPE_ARRAY: + dumpArray(prefix, valueP); + break; + case XMLRPC_TYPE_STRUCT: + dumpStruct(prefix, valueP); + break; + case XMLRPC_TYPE_C_PTR: + dumpCPtr(prefix, valueP); + break; + case XMLRPC_TYPE_NIL: + dumpNil(prefix, valueP); + break; + default: + dumpUnknown(prefix, valueP); + } +} diff --git a/tools/xmlrpc/dumpvalue.h b/tools/xmlrpc/dumpvalue.h new file mode 100644 index 0000000..84be009 --- /dev/null +++ b/tools/xmlrpc/dumpvalue.h @@ -0,0 +1,10 @@ +#ifndef DUMPVALUE_H_INCLUDED +#define DUMPVALUE_H_INCLUDED + +struct _xmlrpc_value; + +void +dumpValue(const char * const prefix, + struct _xmlrpc_value * const valueP); + +#endif diff --git a/tools/xmlrpc/xmlrpc.c b/tools/xmlrpc/xmlrpc.c new file mode 100644 index 0000000..f3c8d3c --- /dev/null +++ b/tools/xmlrpc/xmlrpc.c @@ -0,0 +1,514 @@ +/* Make an XML-RPC call. + + User specifies details of the call on the command line. + + We print the result on Standard Output. + + Example: + + $ xmlrpc http://localhost:8080/RPC2 sample.add i/3 i/5 + Result: + Integer: 8 + + $ xmlrpc localhost:8080 sample.add i/3 i/5 + Result: + Integer: 8 + + This is just the beginnings of this program. It should be extended + to deal with all types of parameters and results. + + An example of a good syntax for parameters would be: + + $ xmlrpc http://www.oreillynet.com/meerkat/xml-rpc/server.php \ + meerkat.getItems \ + struct/{search:linux,descriptions:i/76,time_period:12hour} + Result: + Array: + Struct: + title: String: DatabaseJournal: OpenEdge-Based Finance ... + link: String: http://linuxtoday.com/news_story.php3?ltsn=... + description: String: "Finance application with embedded ... + Struct: + title: ... + link: ... + description: ... + +*/ + +#define _GNU_SOURCE + +#include +#include +#include + +#include "config.h" /* information about this build environment */ +#include "casprintf.h" +#include "mallocvar.h" +#include "cmdline_parser.h" +#include "dumpvalue.h" + +#include "xmlrpc-c/base.h" +#include "xmlrpc-c/client.h" + +#define NAME "xmlrpc command line program" +#define VERSION "1.0" + +struct cmdlineInfo { + const char * url; + const char * username; + const char * password; + const char * methodName; + unsigned int paramCount; + const char ** params; + /* Array of parameters, in order. Has 'paramCount' entries. */ + const char * transport; + /* Name of XML transport he wants to use. NULL if he has no + preference. + */ + const char * curlinterface; + /* "network interface" parameter for the Curl transport. (Not + valid if 'transport' names a non-Curl transport). + */ + xmlrpc_bool curlnoverifypeer; + xmlrpc_bool curlnoverifyhost; + const char * curluseragent; +}; + + + +static void +die_if_fault_occurred (xmlrpc_env * const envP) { + if (envP->fault_occurred) { + fprintf(stderr, "Error: %s (%d)\n", + envP->fault_string, envP->fault_code); + exit(1); + } +} + + + +static void GNU_PRINTF_ATTR(2,3) +setError(xmlrpc_env * const envP, const char format[], ...) { + va_list args; + const char * faultString; + + va_start(args, format); + + cvasprintf(&faultString, format, args); + va_end(args); + + xmlrpc_env_set_fault(envP, XMLRPC_INTERNAL_ERROR, faultString); + + strfree(faultString); +} + + + +static void +processArguments(xmlrpc_env * const envP, + cmdlineParser const cp, + struct cmdlineInfo * const cmdlineP) { + + if (cmd_argumentCount(cp) < 2) + setError(envP, "Not enough arguments. Need at least a URL and " + "method name."); + else { + unsigned int i; + + cmdlineP->url = cmd_getArgument(cp, 0); + cmdlineP->methodName = cmd_getArgument(cp, 1); + cmdlineP->paramCount = cmd_argumentCount(cp) - 2; + MALLOCARRAY(cmdlineP->params, cmdlineP->paramCount); + for (i = 0; i < cmdlineP->paramCount; ++i) + cmdlineP->params[i] = cmd_getArgument(cp, i+2); + } +} + + + +static void +chooseTransport(xmlrpc_env * const envP ATTR_UNUSED, + cmdlineParser const cp, + const char ** const transportPP) { + + const char * transportOpt = cmd_getOptionValueString(cp, "transport"); + + if (transportOpt) { + *transportPP = transportOpt; + } else { + if (cmd_optionIsPresent(cp, "curlinterface") || + cmd_optionIsPresent(cp, "curlnoverifypeer") || + cmd_optionIsPresent(cp, "curlnoverifyhost") || + cmd_optionIsPresent(cp, "curluseragent")) + + *transportPP = strdup("curl"); + else + *transportPP = NULL; + } +} + + + +static void +parseCommandLine(xmlrpc_env * const envP, + int const argc, + const char ** const argv, + struct cmdlineInfo * const cmdlineP) { + + cmdlineParser const cp = cmd_createOptionParser(); + + const char * error; + + cmd_defineOption(cp, "transport", OPTTYPE_STRING); + cmd_defineOption(cp, "username", OPTTYPE_STRING); + cmd_defineOption(cp, "password", OPTTYPE_STRING); + cmd_defineOption(cp, "curlinterface", OPTTYPE_STRING); + cmd_defineOption(cp, "curlnoverifypeer", OPTTYPE_STRING); + cmd_defineOption(cp, "curlnoverifyhost", OPTTYPE_STRING); + cmd_defineOption(cp, "curluseragent", OPTTYPE_STRING); + + cmd_processOptions(cp, argc, argv, &error); + + if (error) { + setError(envP, "Command syntax error. %s", error); + strfree(error); + } else { + cmdlineP->username = cmd_getOptionValueString(cp, "username"); + cmdlineP->password = cmd_getOptionValueString(cp, "password"); + + if (cmdlineP->username && !cmdlineP->password) + setError(envP, "When you specify -username, you must also " + "specify -password."); + else { + chooseTransport(envP, cp, &cmdlineP->transport); + + cmdlineP->curlinterface = + cmd_getOptionValueString(cp, "curlinterface"); + cmdlineP->curlnoverifypeer = + cmd_optionIsPresent(cp, "curlnoverifypeer"); + cmdlineP->curlnoverifyhost = + cmd_optionIsPresent(cp, "curlnoverifyhost"); + cmdlineP->curluseragent = + cmd_getOptionValueString(cp, "curluseragent"); + + if ((!cmdlineP->transport || + strcmp(cmdlineP->transport, "curl") != 0) + && + (cmdlineP->curlinterface || + cmdlineP->curlnoverifypeer || + cmdlineP->curlnoverifyhost || + cmdlineP->curluseragent)) + setError(envP, "You may not specify a Curl transport " + "option unless you also specify -transport=curl"); + + processArguments(envP, cp, cmdlineP); + } + } + cmd_destroyOptionParser(cp); +} + + + +static void +freeCmdline(struct cmdlineInfo const cmdline) { + + unsigned int i; + + strfree(cmdline.url); + strfree(cmdline.methodName); + if (cmdline.transport) + strfree(cmdline.transport); + if (cmdline.curlinterface) + strfree(cmdline.curlinterface); + if (cmdline.curluseragent) + strfree(cmdline.curluseragent); + if (cmdline.username) + strfree(cmdline.username); + if (cmdline.password) + strfree(cmdline.password); + for (i = 0; i < cmdline.paramCount; ++i) + strfree(cmdline.params[i]); +} + + + +static void +computeUrl(const char * const urlArg, + const char ** const urlP) { + + if (strstr(urlArg, "://") != 0) + casprintf(urlP, "%s", urlArg); + else + casprintf(urlP, "http://%s/RPC2", urlArg); +} + + + +static void +buildString(xmlrpc_env * const envP, + const char * const valueString, + xmlrpc_value ** const paramPP) { + + *paramPP = xmlrpc_build_value(envP, "s", valueString); +} + + + +static void +buildInt(xmlrpc_env * const envP, + const char * const valueString, + xmlrpc_value ** const paramPP) { + + if (strlen(valueString) < 1) + setError(envP, "Integer argument has nothing after the 'i/'"); + else { + long value; + char * tailptr; + + value = strtol(valueString, &tailptr, 10); + + if (*tailptr != '\0') + setError(envP, + "Integer argument has non-digit crap in it: '%s'", + tailptr); + else + *paramPP = xmlrpc_build_value(envP, "i", value); + } +} + + + +static void +buildDouble(xmlrpc_env * const envP, + const char * const valueString, + xmlrpc_value ** const paramPP) { + + if (strlen(valueString) < 1) + setError(envP, "\"Double\" argument has nothing after the 'd/'"); + else { + double value; + char * tailptr; + + value = strtod(valueString, &tailptr); + + if (*tailptr != '\0') + setError(envP, + "\"Double\" argument has non-decimal crap in it: '%s'", + tailptr); + else + *paramPP = xmlrpc_build_value(envP, "d", value); + } +} + + + +static void +buildBool(xmlrpc_env * const envP, + const char * const valueString, + xmlrpc_value ** const paramPP) { + + if (strcmp(valueString, "t") == 0 || + strcmp(valueString, "true") == 0) + *paramPP = xmlrpc_build_value(envP, "b", 1); + else if (strcmp(valueString, "f") == 0 || + strcmp(valueString, "false") == 0) + *paramPP = xmlrpc_build_value(envP, "b", 0); + else + setError(envP, "Boolean argument has unrecognized value '%s'. " + "recognized values are 't', 'f', 'true', and 'false'.", + valueString); +} + + + +static void +buildNil(xmlrpc_env * const envP, + const char * const valueString, + xmlrpc_value ** const paramPP) { + + if (strlen(valueString) > 0) + setError(envP, "Nil argument has something after the 'n/'"); + else { + *paramPP = xmlrpc_build_value(envP, "n"); + } +} + + + +static void +computeParameter(xmlrpc_env * const envP, + const char * const paramArg, + xmlrpc_value ** const paramPP) { + + if (strncmp(paramArg, "s/", 2) == 0) + buildString(envP, ¶mArg[2], paramPP); + else if (strncmp(paramArg, "i/", 2) == 0) + buildInt(envP, ¶mArg[2], paramPP); + else if (strncmp(paramArg, "d/", 2) == 0) + buildDouble(envP, ¶mArg[2], paramPP); + else if (strncmp(paramArg, "b/", 2) == 0) + buildBool(envP, ¶mArg[2], paramPP); + else if (strncmp(paramArg, "n/", 2) == 0) + buildNil(envP, ¶mArg[2], paramPP); + else { + /* It's not in normal type/value format, so we take it to be + the shortcut string notation + */ + buildString(envP, paramArg, paramPP); + } +} + + + +static void +computeParamArray(xmlrpc_env * const envP, + unsigned int const paramCount, + const char ** const params, + xmlrpc_value ** const paramArrayPP) { + + unsigned int i; + + xmlrpc_value * paramArrayP; + + paramArrayP = xmlrpc_build_value(envP, "()"); + + for (i = 0; i < paramCount && !envP->fault_occurred; ++i) { + xmlrpc_value * paramP; + + computeParameter(envP, params[i], ¶mP); + + if (!envP->fault_occurred) { + xmlrpc_array_append_item(envP, paramArrayP, paramP); + + xmlrpc_DECREF(paramP); + } + } + *paramArrayPP = paramArrayP; +} + + + +static void +dumpResult(xmlrpc_value * const resultP) { + + printf("Result:\n\n"); + + dumpValue("", resultP); +} + + + +static void +doCall(xmlrpc_env * const envP, + const char * const transport, + const char * const curlinterface, + xmlrpc_bool const curlnoverifypeer, + xmlrpc_bool const curlnoverifyhost, + const char * const curluseragent, + const xmlrpc_server_info * const serverInfoP, + const char * const methodName, + xmlrpc_value * const paramArrayP, + xmlrpc_value ** const resultPP) { + + struct xmlrpc_clientparms clientparms; + + XMLRPC_ASSERT(xmlrpc_value_type(paramArrayP) == XMLRPC_TYPE_ARRAY); + + clientparms.transport = transport; + + if (transport && strcmp(transport, "curl") == 0) { + struct xmlrpc_curl_xportparms * curlXportParmsP; + MALLOCVAR(curlXportParmsP); + + curlXportParmsP->network_interface = curlinterface; + curlXportParmsP->no_ssl_verifypeer = curlnoverifypeer; + curlXportParmsP->no_ssl_verifyhost = curlnoverifyhost; + curlXportParmsP->user_agent = curluseragent; + + clientparms.transportparmsP = (struct xmlrpc_xportparms *) + curlXportParmsP; + clientparms.transportparm_size = XMLRPC_CXPSIZE(user_agent); + } else { + clientparms.transportparmsP = NULL; + clientparms.transportparm_size = 0; + } + xmlrpc_client_init2(envP, XMLRPC_CLIENT_NO_FLAGS, NAME, VERSION, + &clientparms, XMLRPC_CPSIZE(transportparm_size)); + if (!envP->fault_occurred) { + *resultPP = xmlrpc_client_call_server_params( + envP, serverInfoP, methodName, paramArrayP); + + xmlrpc_client_cleanup(); + } + if (clientparms.transportparmsP) + free(clientparms.transportparmsP); +} + + + +static void +createServerInfo(xmlrpc_env * const envP, + const char * const serverUrl, + const char * const userName, + const char * const password, + xmlrpc_server_info ** const serverInfoPP) { + + xmlrpc_server_info * serverInfoP; + + serverInfoP = xmlrpc_server_info_new(envP, serverUrl); + if (!envP->fault_occurred) { + if (userName) { + xmlrpc_server_info_set_basic_auth( + envP, serverInfoP, userName, password); + } + } + *serverInfoPP = serverInfoP; +} + + + +int +main(int const argc, + const char ** const argv) { + + struct cmdlineInfo cmdline; + xmlrpc_env env; + xmlrpc_value * paramArrayP; + xmlrpc_value * resultP; + const char * url; + xmlrpc_server_info * serverInfoP; + + xmlrpc_env_init(&env); + + parseCommandLine(&env, argc, argv, &cmdline); + die_if_fault_occurred(&env); + + computeUrl(cmdline.url, &url); + + computeParamArray(&env, cmdline.paramCount, cmdline.params, ¶mArrayP); + die_if_fault_occurred(&env); + + createServerInfo(&env, url, cmdline.username, cmdline.password, + &serverInfoP); + die_if_fault_occurred(&env); + + doCall(&env, cmdline.transport, cmdline.curlinterface, + cmdline.curlnoverifypeer, cmdline.curlnoverifyhost, + cmdline.curluseragent, + serverInfoP, + cmdline.methodName, paramArrayP, + &resultP); + die_if_fault_occurred(&env); + + dumpResult(resultP); + + strfree(url); + + xmlrpc_DECREF(resultP); + + freeCmdline(cmdline); + + xmlrpc_env_clean(&env); + + return 0; +} diff --git a/tools/xmlrpc/xmlrpc.html b/tools/xmlrpc/xmlrpc.html new file mode 100644 index 0000000..3d41c19 --- /dev/null +++ b/tools/xmlrpc/xmlrpc.html @@ -0,0 +1,249 @@ + +Xmlrpc User Manual + + +

xmlrpc makes an XML-RPC remote procedure call (RPC) and displays +the response. xmlrpc runs an XML-RPC client. + +

This program is mainly useful for debugging and learning about +XML-RPC servers. XML-RPC is such that the RPCs normally need to be made +by a program rather than a person to be of use. + +

A similar tool done as a web form is at +http://gggeek.damacom.it/debugger/ + +

Examples

+ +
+
+     $ xmlrpc http://localhost:8080/RPC2 sample.add i/3 i/5
+       Result:
+         Integer: 8
+
+
+ +
+
+     $ xmlrpc localhost:8080 sample.add i/3 i/5
+       Result:
+         Integer: 8
+     
+
+
+ +
+
+     $ xmlrpc http://xmlrpc.server.net/~bryanh echostring \
+         "s/This is a string"
+     Result:
+       String: This is a string
+
+
+
+ +
+
+     $ xmlrpc http://xmlrpc.server.net/~bryanh echostring \
+         "This is a string in shortcut syntax"
+     Result:
+       String: This is a string in shortcut syntax
+
+
+
+
+
+     $ xmlrpc http://xmlrpc.server.net sample.add i/3 i/5 \
+         transport=curl -curlinterface=eth1 -username=bryanh -password=passw0rd
+       Result:
+         Integer: 8
+     
+
+
+ +

Overview

+

+xmlrpc +url +methodName +parameter ... +[-transport=transportname] +[-username=username -password=password] +[-curlinterface={interface|host}] +[-curlnoverifypeer] +[-curlnoverifyhost] + +

parameter: + +

+i/integer | +s/string | +b/{true|false|t|f} | +d/realnum | +n/ | +string + + +

Minimum unique abbreviation of option is acceptable. You may use double +hyphens instead of single hyphen to denote options. You may use white +space in place of the equals sign to separate an option name from its value. + + +

Arguments

+ +
+
url + +
This is the URL of the XML-RPC server. As XML-RPC uses HTTP, this +must be an HTTP url. However, if you don't specify a type ("http:") +in the URL, xmlrpc assumes an "http://" prefix and a +"/RPC2" suffix. RPC2 is the conventional file name for +an XML-RPC responder. + +
methodName + +
The name of the XML-RPC method you want to invoke. + +
parameter ... + +
The list of parameters for the RPC. xmlrpc turns each of these +arguments into an XML-RPC parameter, in the order given. You may specify +no parameters if you like. + +

You specify the data type of the parameter with a prefix ending in +a slash. Example: i/5. Here, the "i" signifies an +integer data type. "5" is the value. + +

xmlrpc is capable of only a subset of the +possible XML-RPC types, as follows by prefix: + +

+
i/ +
integer (<int4>) + +
s/ +
string (<string>) + +
b/ +
boolean (<boolean>) + +
d/ +
double (<double>) (i.e. real number) + +
n/ +
nil (<nil>) + +
+ +

As a shortcut, if you don't specify a prefix (i.e. your argument does +not contain a slash), xmlrpc assumes string data type. + +

+ + +

Options

+ +
+
-transport=transportname + +
This selects the XML transport facility (e.g. libwww) that +xmlrpc uses to perform the RPC. + +

The name transportname is one that the Xmlrpc-c programming +library recognizes. This is typically libwww, curl, and +wininet. + +

By default, xmlrpc lets the Xmlrpc-c library choose. + +

-username=username +
-password=password + +
These options, which must be used together, cause the client to +authenticate itself to the server, if the server requires it, using +HTTP Basic Authentication and the specified username and password. + +
-curlinterface={interface|host} + +
+This option gives the "interface" option for a Curl XML transport. + +

The exact meaning of this option is up to the Curl library, and the +best documentation for it is the manual for the 'curl' program that comes +with the Curl library. + +

But essentially, it chooses the local network interface through which +to send the RPC. It causes the Curl library to perform a +"bind" operation on the socket it uses for the +communication. It can be the name of a network interface (e.g. on +Linux, "eth1") or an IP address of the interface or a host +name that resolves to the IP address of the interface. Unfortunately, +you can't explicitly state which form you're specifying, so there's +some ambiguity. + +

Examples: + +

    + +
  • + +-interface=eth1 + + +
  • + +-interface=64.171.19.66 + + +
  • + +-interface=giraffe.giraffe-data.com + + +
+ +

This option causes xmlrpc to default to using the Curl +XML transport. You may not specify any other transport. + +

-curlnoverifypeer + +
+This option gives the "no_ssl_verifypeer" option for the Curl +XML transport, which is essentially the CURLOPT_SSL_VERIFYPEER option +of the Curl library. + +

See the curl_easy_setopt() man page for details on this, but +essentially it means that the client does not authenticate the server's +certificate of identity -- it just believes whatever the server says. + +

You may want to use -curlnoverifyhost as well. Since you're +not authenticating the server's identity, there's not much sense in +checking it. + +

This option causes xmlrpc to default to using the Curl +XML transport. You may not specify any other transport. + + +

-curlnoverifyhost + +
+This option gives the "no_ssl_verifyhost" option for the Curl +XML transport, which is essentially the CURLOPT_SSL_VERIFYHOST option +of the Curl library. + +

See the curl_easy_setopt() man page for details on this, but +essentially it means that the client does not verify the server's +identity. It just assumes that if the server answers the IP address +of the server as indicated by the URL (probably via host name), then +it's the intended server. + +

You may want to use -curlnoverifypeer as well. As long as +you don't care who the server says it is, there's no point in +authenticating its identity. + +

This option causes xmlrpc to default to using the Curl +XML transport. You may not specify any other transport. + + +

+ + diff --git a/tools/xmlrpc_transport/.cvsignore b/tools/xmlrpc_transport/.cvsignore new file mode 100644 index 0000000..bff9884 --- /dev/null +++ b/tools/xmlrpc_transport/.cvsignore @@ -0,0 +1 @@ +xmlrpc_transport diff --git a/tools/xmlrpc_transport/Makefile b/tools/xmlrpc_transport/Makefile new file mode 100644 index 0000000..a6112ae --- /dev/null +++ b/tools/xmlrpc_transport/Makefile @@ -0,0 +1,64 @@ +ifeq ($(SRCDIR)x,x) +SRCDIR = $(CURDIR)/../.. +endif +# BLDDIR is for use in places where a symbolic link won't work. +# BUILDDIR is for places in Makefile.common that can use the 'blddir' +# symbolic link (but in other directories, doesn't). +BLDDIR = $(SRCDIR) +BUILDDIR = blddir + +default: all + +include $(BLDDIR)/Makefile.config + +PROGRAMS_TO_INSTALL = xmlrpc_transport + +include ../Makefile.common + +INCLUDES = -I$(SRCDIR) -I$(SRCDIR)/include -I$(SRCDIR)/lib/util/include + +CFLAGS = $(CFLAGS_COMMON) $(INCLUDES) $(CFLAGS_PERSONAL) $(CADD) + +LDFLAGS = $(LADD) + +all: xmlrpc_transport + +UTIL_OBJS = cmdline_parser.o getoptx.o casprintf.o +UTILS = $(UTIL_OBJS:%=$(UTIL_DIR)/%) + +# These are the Libtool .la files. We use them only for make dependencies. +# We'd like to use these in the link rule, by using libtool --link, but +# Libtool adds -l options to the link to cover the dependencies that are +# recorded inside the shared libraries. And it doesn't add the necessary +# -L options (it can't), so we end up with a messy mixture of the two +# forms of specifying libraries. + +LIBS = $(LIBXMLRPC_CLIENT) $(LIBXMLRPC) $(LIBXMLRPC_XML) $(LIBXMLRPC_UTIL) + +xmlrpc_transport:%:%.o $(LIBS) $(UTILS) + $(CCLD) -o $@ $(LDFLAGS) $< $(CLIENT_LDLIBS) $(UTILS) + +%.o:%.c + $(CC) -c $(CFLAGS) $< + +*.c: config.h + +config.h: + $(LN_S) $(BLDDIR)/xmlrpc_config.h $@ + +# This Makefile.config dependency makes sure the symlinks get built before +# this make file is used for anything. + +$(BLDDIR)/Makefile.config: blddir srcdir + +include Makefile.depend + +.PHONY: dep +dep: dep-common + +.PHONY: clean +clean: clean-common + rm -f xmlrpc_transport config.h + +.PHONY: distclean +distclean: clean distclean-common diff --git a/tools/xmlrpc_transport/Makefile.depend b/tools/xmlrpc_transport/Makefile.depend new file mode 100644 index 0000000..e69de29 diff --git a/tools/xmlrpc_transport/xmlrpc_transport.c b/tools/xmlrpc_transport/xmlrpc_transport.c new file mode 100644 index 0000000..ad0c7de --- /dev/null +++ b/tools/xmlrpc_transport/xmlrpc_transport.c @@ -0,0 +1,289 @@ +/* Transport some XML to a server and get the response back, as if doing + an XML-RPC call. +*/ + +#define _GNU_SOURCE + +#include +#include +#include + +#include "config.h" /* information about this build environment */ +#include "casprintf.h" +#include "mallocvar.h" +#include "cmdline_parser.h" + +#include "xmlrpc-c/base.h" +#include "xmlrpc-c/client.h" + +#define NAME "xmlrpc_transport command line program" +#define VERSION "1.0" + +struct cmdlineInfo { + const char * url; + const char * username; + const char * password; + const char * transport; + /* Name of XML transport he wants to use. NULL if he has no + preference. + */ +}; + + + +static void +die_if_fault_occurred (xmlrpc_env * const envP) { + if (envP->fault_occurred) { + fprintf(stderr, "Error: %s (%d)\n", + envP->fault_string, envP->fault_code); + exit(1); + } +} + + + +static void GNU_PRINTF_ATTR(2,3) +setError(xmlrpc_env * const envP, const char format[], ...) { + va_list args; + const char * faultString; + + va_start(args, format); + + cvasprintf(&faultString, format, args); + va_end(args); + + xmlrpc_env_set_fault(envP, XMLRPC_INTERNAL_ERROR, faultString); + + strfree(faultString); +} + + + +static void +processArguments(xmlrpc_env * const envP, + cmdlineParser const cp, + struct cmdlineInfo * const cmdlineP) { + + if (cmd_argumentCount(cp) < 1) + setError(envP, "Not enough arguments. Need a URL."); + else { + cmdlineP->url = cmd_getArgument(cp, 0); + } +} + + + +static void +parseCommandLine(xmlrpc_env * const envP, + int const argc, + const char ** const argv, + struct cmdlineInfo * const cmdlineP) { + + cmdlineParser const cp = cmd_createOptionParser(); + + const char * error; + + cmd_defineOption(cp, "transport", OPTTYPE_STRING); + cmd_defineOption(cp, "username", OPTTYPE_STRING); + cmd_defineOption(cp, "password", OPTTYPE_STRING); + + cmd_processOptions(cp, argc, argv, &error); + + if (error) { + setError(envP, "Command syntax error. %s", error); + strfree(error); + } else { + cmdlineP->username = cmd_getOptionValueString(cp, "username"); + cmdlineP->password = cmd_getOptionValueString(cp, "password"); + + if (cmdlineP->username && !cmdlineP->password) + setError(envP, "When you specify -username, you must also " + "specify -password."); + else { + cmdlineP->transport = cmd_getOptionValueString(cp, "transport"); + + processArguments(envP, cp, cmdlineP); + } + } + cmd_destroyOptionParser(cp); +} + + + +static void +freeCmdline(struct cmdlineInfo const cmdline) { + + strfree(cmdline.url); + if (cmdline.username) + strfree(cmdline.username); + if (cmdline.password) + strfree(cmdline.password); + if (cmdline.transport) + strfree(cmdline.transport); +} + + + +static void +computeUrl(const char * const urlArg, + const char ** const urlP) { + + if (strstr(urlArg, "://") != 0) { + *urlP = strdup(urlArg); + } else { + casprintf(urlP, "http://%s/RPC2", urlArg); + } +} + + + +static void +doCall(xmlrpc_env * const envP, + const char * const transport, + const xmlrpc_server_info * const serverInfoP, + xmlrpc_mem_block * const callXmlP, + xmlrpc_mem_block ** const respXmlPP) { + + struct xmlrpc_clientparms clientparms; + + clientparms.transport = transport; + + clientparms.transportparmsP = NULL; + clientparms.transportparm_size = 0; + + xmlrpc_client_init2(envP, XMLRPC_CLIENT_NO_FLAGS, NAME, VERSION, + &clientparms, XMLRPC_CPSIZE(transportparm_size)); + if (!envP->fault_occurred) { + xmlrpc_client_transport_call(envP, NULL, serverInfoP, + callXmlP, respXmlPP); + + xmlrpc_client_cleanup(); + } +} + + + +static void +createServerInfo(xmlrpc_env * const envP, + const char * const serverUrl, + const char * const userName, + const char * const password, + xmlrpc_server_info ** const serverInfoPP) { + + xmlrpc_server_info * serverInfoP; + + serverInfoP = xmlrpc_server_info_new(envP, serverUrl); + if (!envP->fault_occurred) { + if (userName) { + xmlrpc_server_info_set_basic_auth( + envP, serverInfoP, userName, password); + } + } + *serverInfoPP = serverInfoP; +} + + + +static void +readFile(xmlrpc_env * const envP, + FILE * const ifP, + xmlrpc_mem_block ** const fileContentsPP) { + + xmlrpc_mem_block * fileContentsP; + + fileContentsP = XMLRPC_MEMBLOCK_NEW(char, envP, 0); + + while (!envP->fault_occurred && !feof(ifP)) { + char buffer[4096]; + size_t bytesRead; + + bytesRead = fread(buffer, 1, sizeof(buffer), ifP); + XMLRPC_MEMBLOCK_APPEND(char, envP, + fileContentsP, buffer, bytesRead); + } + if (envP->fault_occurred) + XMLRPC_MEMBLOCK_FREE(char, fileContentsP); + + *fileContentsPP = fileContentsP; +} + + + +static void +writeFile(xmlrpc_env * const envP, + FILE * const ofP, + xmlrpc_mem_block * const fileContentsP) { + + size_t totalWritten; + + totalWritten = 0; + + while (!envP->fault_occurred && + totalWritten < XMLRPC_MEMBLOCK_SIZE(char, fileContentsP)) { + size_t bytesWritten; + + bytesWritten = fwrite( + XMLRPC_MEMBLOCK_CONTENTS(char, fileContentsP) + totalWritten, + 1, + XMLRPC_MEMBLOCK_SIZE(char, fileContentsP) - totalWritten, + ofP); + + if (bytesWritten < 1) + xmlrpc_env_set_fault_formatted( + envP, XMLRPC_INTERNAL_ERROR, + "Error writing output"); + + totalWritten -= bytesWritten; + } +} + + + +int +main(int const argc, + const char ** const argv) { + + struct cmdlineInfo cmdline; + xmlrpc_env env; + xmlrpc_mem_block * callXmlP; + xmlrpc_mem_block * respXmlP; + const char * url; + xmlrpc_server_info * serverInfoP; + + xmlrpc_env_init(&env); + + parseCommandLine(&env, argc, argv, &cmdline); + die_if_fault_occurred(&env); + + computeUrl(cmdline.url, &url); + + createServerInfo(&env, url, cmdline.username, cmdline.password, + &serverInfoP); + die_if_fault_occurred(&env); + + fprintf(stderr, "Reading call data from Standard Input...\n"); + + readFile(&env, stdin, &callXmlP); + die_if_fault_occurred(&env); + + fprintf(stderr, "Making call...\n"); + + doCall(&env, cmdline.transport, serverInfoP, callXmlP, + &respXmlP); + die_if_fault_occurred(&env); + + fprintf(stderr, "Writing response data to Standard Output\n"); + writeFile(&env, stdout, respXmlP); + die_if_fault_occurred(&env); + + XMLRPC_MEMBLOCK_FREE(char, callXmlP); + XMLRPC_MEMBLOCK_FREE(char, respXmlP); + + strfree(url); + + freeCmdline(cmdline); + + xmlrpc_env_clean(&env); + + return 0; +} diff --git a/tools/xmlrpc_transport/xmlrpc_transport.html b/tools/xmlrpc_transport/xmlrpc_transport.html new file mode 100644 index 0000000..4610fef --- /dev/null +++ b/tools/xmlrpc_transport/xmlrpc_transport.html @@ -0,0 +1,95 @@ + +Xmlrpc_transport User Manual + + +

xmlrpc_transport transports data to a server as if to make an +XML-RPC remote procedure call and displays the response from the server. + +

You supply the call in XML form on Standard Input and get the response +in XML form on Standard Output. xmlrpc_transport doesn't really know +anything about XML; it sends the characters you supply and displays the +characters it gets back. + +

xmlrpc_transport uses the lower levels of the XML-RPC For C/C++ +client libraries. + +

This program is mainly useful for debugging and learning about +XML-RPC servers and the XML-RPC For C/C++ client XML transports. + + +

Examples

+ +< + +
+
+     $ xmlrpc_transport http://localhost:8080/RPC2 <<-EOF
+        <?xml version="1.0" encoding="UTF-8"?>
+        <methodCall>
+        <methodName>sample.add</methodName>
+        <params>
+        <param><value><i4>5</i4></value></param>
+        <param><value><i4>7</i4></value></param>
+        </params>
+        </methodCall>
+        EOF
+     <?xml version="1.0" encoding="UTF-8"?>
+     <methodResponse>
+     <params>
+     <param><value><i4>12</i4></value></param>
+     </params>
+     </methodResponse>
+
+
+ +

Overview

+

+xmlrpc_transport +url +[-transport=transportname] +[-username=username -password=password] + +

Minimum unique abbreviation of option is acceptable. You may use double +hyphens instead of single hyphen to denote options. You may use white +space in place of the equals sign to separate an option name from its value. + + +

Arguments

+ +
+
url + +
This is the URL of the XML-RPC server. As XML-RPC uses HTTP, this +must be an HTTP url. However, if you don't specify a type ("http:") +in the URL, xmlrpc_transport assumes an "http://" prefix and a +"/RPC2" suffix. RPC2 is the conventional file name for +an XML-RPC responder. + +
+ + +

Options

+ +
+
-transport=transportname + +
This selects the XML transport facility (e.g. libwww) that +xmlrpc_transport uses to perform the RPC. + +

The name transportname is one that the Xmlrpc-c programming +library recognizes. This is typically libwww, curl, and +wininet. + +

By default, xmlrpc_transport lets the Xmlrpc-c library choose. + +

-username=username +
-password=password + +
These options, which must be used together, cause the client to +authenticate itself to the server, if the server requires it, using +HTTP Basic Authentication and the specified username and password. + +
+ + + diff --git a/unix-common.make b/unix-common.make new file mode 100644 index 0000000..276866a --- /dev/null +++ b/unix-common.make @@ -0,0 +1,71 @@ +# -*-makefile-*- <-- an Emacs control + +# The including make file must define these make variables: +# +# SHARED_LIBS_TO_INSTALL: List of the shared libraries that need to be +# installed -- just the basic library names. E.g. "libfoo libbar" +# +# SHLIB_SUFFIX: Shared library filename suffix, e.g. "so". +# +# MAJ: Library major version number, e.g. "3" in file name "libfoo.3.1" +# +# MIN: Library minor version number, e.g. "1" in file name "libfoo.3.1" +# +# LDFLAGS_SHLIB: linker (Ld) flags needed to link object files together into +# a shared library. May use $(SONAME) for the soname of the library. +# Include -lc if appropriate. +# +# LADD: Additional linker flags (normally set on the make command line). +# +# INSTALL_DATA: beginning of shell command to install a library file. +# +# DESTDIR: main installation directory +# +# LIBINST_DIR: directory in which to install libraries, relative to DESTDIR. +# +# LN_S: beginning of shell command to make symbolic link (e.g. "ln -s"). +# +# CXXLD: beginning of shell command to link, e.g. "g++". + +# This make file defines these make variables that the including make file +# can use: +# +# ALL_SHARED_LIBRARIES: list of targets to be dependencies of all: . + +# Including make file must contain a rule to build each library file +# (e.g. libfoo.3.1) + +# This make file provides these rules: +# +# install-shared-libraries: install all shared libraries and the necessary +# symbolic links. + +ALL_SHARED_LIBRARIES = \ + $(SHARED_LIBS_TO_BUILD:%=%.$(SHLIB_SUFFIX).$(MAJ).$(MIN)) + +# SONAME is to be referenced by $(LDSHLIB) in $(SHLIB_RULE) +# SONAME is the name of the library file being built, with the minor +# version number cut off. E.g. if we're building libfoo.so.1.2, SONAME +# is libfoo.so.1 . +SONAME = $(@:%.$(MIN)=%) + +SHLIB_RULE = $(CXXLD) $(LDFLAGS_SHLIB) -o $@ $^ $(LADD) + +SHLIB_INSTALL_TARGETS = $(SHARED_LIBS_TO_INSTALL:%=%/install) + +#SHLIB_INSTALL_TARGETS is like "install/libfoo install/libbar" + +.PHONY: $(SHLIB_INSTALL_TARGETS) +.PHONY: install-shared-libraries + +install-shared-libraries: $(SHLIB_INSTALL_TARGETS) + +$(SHLIB_INSTALL_TARGETS) X/install:%/install:%.$(SHLIB_SUFFIX).$(MAJ).$(MIN) +# $< is a library file name, e.g. libfoo.3.1 . + $(INSTALL_SHLIB) $< $(DESTDIR)$(LIBINST_DIR)/$< + cd $(DESTDIR)$(LIBINST_DIR); \ + rm -f $(<:%.$(MIN)=%); \ + $(LN_S) $< $(<:%.$(MIN)=%) + cd $(DESTDIR)$(LIBINST_DIR); \ + rm -f $(<:%.$(MAJ).$(MIN)=%); \ + $(LN_S) $(<:%.$(MIN)=%) $(<:%.$(MAJ).$(MIN)=%) diff --git a/xmlrpc-c-config.in b/xmlrpc-c-config.in new file mode 100644 index 0000000..80b84d8 --- /dev/null +++ b/xmlrpc-c-config.in @@ -0,0 +1,178 @@ +#!/bin/sh +# Stolen from rep-config and adapted for use with xmlrpc-c. +# Other bits stolen from gnome-config & automake output. + +prefix="@prefix@" +exec_prefix="@exec_prefix@" + +bindir="@bindir@" +datadir="@datadir@" +libdir="@libdir@" +includedir="@includedir@" + +ENABLE_LIBXML2_BACKEND='@ENABLE_LIBXML2_BACKEND@' +ENABLE_ABYSS_THREADS='@ENABLE_ABYSS_THREADS@' +MUST_BUILD_CURL_CLIENT='@MUST_BUILD_CURL_CLIENT@' +MUST_BUILD_WININET_CLIENT='@MUST_BUILD_WININET_CLIENT@' +MUST_BUILD_LIBWWW_CLIENT='@MUST_BUILD_LIBWWW_CLIENT@' +LSOCKET='@LSOCKET@' + +usage="Usage: xmlrpc-c-config ...