From 609b1ee5ca9d4c45c011cbe602ea85364fb09d19 Mon Sep 17 00:00:00 2001 From: Ryan Birmingham Date: Fri, 19 Apr 2019 12:40:53 -0400 Subject: [PATCH 1/2] try another command for apache --- Dockerfile | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index 4ec66dc..a6e8ff6 100644 --- a/Dockerfile +++ b/Dockerfile @@ -87,4 +87,5 @@ RUN cp /root/src/iipsrv/src/iipsrv.fcgi /var/www/localhost/fcgi-bin/ #COPY apache2-iipsrv-fcgid.conf /root/src/iip-openslide-docker/apache2-iipsrv-fcgid.conf -CMD service apache2 start && while true; do sleep 1000; done +#CMD service apache2 start && while true; do sleep 1000; done +CMD apachectl -D FOREGROUND From 7c78bc250e33197856c14adc4dbef5425cfec709 Mon Sep 17 00:00:00 2001 From: Ryan Birmingham Date: Fri, 19 Apr 2019 13:57:26 -0400 Subject: [PATCH 2/2] bring in iipsrv mods --- Dockerfile | 23 +- iipsrv/AUTHORS | 10 + iipsrv/COPYING | 674 + iipsrv/ChangeLog | 1244 ++ iipsrv/INSTALL | 291 + iipsrv/Makefile.am | 6 + iipsrv/NEWS | 1 + iipsrv/README | 406 + iipsrv/README.md | 1 + iipsrv/TODO | 13 + iipsrv/acinclude.m4 | 851 ++ iipsrv/autogen.sh | 1578 +++ iipsrv/configure.in | 325 + iipsrv/doc/doxygen-html.conf | 1510 +++ iipsrv/fcgi/LICENSE.TERMS | 28 + iipsrv/fcgi/Makefile.am | 91 + iipsrv/fcgi/Makefile.nt | 47 + iipsrv/fcgi/README | 400 + iipsrv/fcgi/Win32/FastCGI.dsw | 164 + iipsrv/fcgi/Win32/authorizer.dsp | 108 + iipsrv/fcgi/Win32/cgifcgi.dsp | 108 + iipsrv/fcgi/Win32/echo-cpp.dsp | 108 + iipsrv/fcgi/Win32/echo.dsp | 109 + iipsrv/fcgi/Win32/echox.dsp | 108 + iipsrv/fcgi/Win32/libfcgi.dsp | 175 + iipsrv/fcgi/Win32/logdump.dsp | 109 + iipsrv/fcgi/Win32/size.dsp | 108 + iipsrv/fcgi/Win32/threaded.dsp | 109 + iipsrv/fcgi/acinclude.m4 | 391 + iipsrv/fcgi/cgi-fcgi/cgi-fcgi.mak | 206 + iipsrv/fcgi/configure | 11250 ++++++++++++++++ iipsrv/fcgi/doc/FCGI_Accept.3 | 128 + iipsrv/fcgi/doc/FCGI_Finish.3 | 41 + iipsrv/fcgi/doc/FCGI_SetExitStatus.3 | 28 + iipsrv/fcgi/doc/FCGI_StartFilterData.3 | 52 + iipsrv/fcgi/doc/cgi-fcgi.1 | 113 + .../fcgi/doc/fastcgi-prog-guide/ap_guida.htm | 322 + .../fcgi/doc/fastcgi-prog-guide/ap_guide.htm | 226 + iipsrv/fcgi/doc/fastcgi-prog-guide/apaman.htm | 290 + .../fcgi/doc/fastcgi-prog-guide/ch1inta1.gif | Bin 0 -> 7194 bytes .../fcgi/doc/fastcgi-prog-guide/ch1intra.gif | Bin 0 -> 6208 bytes .../fcgi/doc/fastcgi-prog-guide/ch1intro.htm | 581 + iipsrv/fcgi/doc/fastcgi-prog-guide/ch2c.htm | 379 + .../fcgi/doc/fastcgi-prog-guide/ch3perl.htm | 151 + iipsrv/fcgi/doc/fastcgi-prog-guide/ch4tcl.htm | 131 + iipsrv/fcgi/doc/fastcgi-prog-guide/cover.htm | 119 + iipsrv/fcgi/doc/fastcgi-prog-guide/covera.gif | Bin 0 -> 42128 bytes .../fcgi/doc/fastcgi-whitepaper/fastcgi.htm | 833 ++ .../fcgi/doc/fastcgi-whitepaper/img00001.gif | Bin 0 -> 4128 bytes .../fcgi/doc/fastcgi-whitepaper/img00002.gif | Bin 0 -> 2426 bytes .../fcgi/doc/fastcgi-whitepaper/img00003.gif | Bin 0 -> 3779 bytes iipsrv/fcgi/doc/fcgi-devel-kit.htm | 691 + iipsrv/fcgi/doc/fcgi-java.htm | 501 + iipsrv/fcgi/doc/fcgi-perf.htm | 456 + iipsrv/fcgi/doc/fcgi-perl.htm | 53 + iipsrv/fcgi/doc/fcgi-spec.html | 1340 ++ iipsrv/fcgi/doc/fcgi-tcl.htm | 366 + iipsrv/fcgi/doc/omi-logo.gif | Bin 0 -> 217 bytes iipsrv/fcgi/doc/overview.html | 112 + iipsrv/fcgi/doc/www5-api-workshop.html | 269 + iipsrv/fcgi/examples/authorizer.mak | 203 + iipsrv/fcgi/examples/echo-cpp.mak | 203 + iipsrv/fcgi/examples/echo.mak | 205 + iipsrv/fcgi/examples/echox.mak | 203 + iipsrv/fcgi/examples/size.mak | 202 + iipsrv/fcgi/fcgi_config.h | 127 + iipsrv/fcgi/images/aplib-hd.gif | Bin 0 -> 1840 bytes iipsrv/fcgi/images/divider.gif | Bin 0 -> 159 bytes iipsrv/fcgi/images/fcgi-hd.gif | Bin 0 -> 1364 bytes iipsrv/fcgi/images/mail-hd.gif | Bin 0 -> 1605 bytes iipsrv/fcgi/images/navbar.gif | Bin 0 -> 2061 bytes iipsrv/fcgi/images/serv-hd.gif | Bin 0 -> 1781 bytes iipsrv/fcgi/images/words-hd.gif | Bin 0 -> 1725 bytes iipsrv/fcgi/include/Makefile.am | 8 + iipsrv/fcgi/include/fastcgi.h | 136 + iipsrv/fcgi/include/fcgi_config_x86.h | 39 + iipsrv/fcgi/include/fcgi_stdio.h | 245 + iipsrv/fcgi/include/fcgiapp.h | 622 + iipsrv/fcgi/include/fcgimisc.h | 38 + iipsrv/fcgi/include/fcgio.h | 151 + iipsrv/fcgi/include/fcgios.h | 130 + iipsrv/fcgi/java/FCGIGlobalDefs.java | 92 + iipsrv/fcgi/java/FCGIInputStream.java | 381 + iipsrv/fcgi/java/FCGIInterface.java | 247 + iipsrv/fcgi/java/FCGIMessage.java | 411 + iipsrv/fcgi/java/FCGIOutputStream.java | 335 + iipsrv/fcgi/java/FCGIRequest.java | 53 + iipsrv/fcgi/libfcgi/Makefile.am | 29 + iipsrv/fcgi/libfcgi/fcgi_stdio.c | 801 ++ iipsrv/fcgi/libfcgi/fcgiapp.c | 2309 ++++ iipsrv/fcgi/libfcgi/libfcgi.mak | 311 + iipsrv/fcgi/libfcgi/os_unix.c | 1293 ++ iipsrv/fcgi/libfcgi/os_win32.c | 1887 +++ iipsrv/fcgi/ltmain.sh | 4946 +++++++ iipsrv/fcgi/perl/ChangeLog | 229 + iipsrv/fcgi/perl/FCGI.PL | 570 + iipsrv/fcgi/perl/FCGI.XL | 625 + iipsrv/fcgi/perl/MANIFEST | 16 + iipsrv/fcgi/perl/Makefile.PL | 156 + iipsrv/fcgi/perl/README | 64 + iipsrv/fcgi/perl/aclocal.m4 | 472 + iipsrv/fcgi/perl/configure | 3116 +++++ iipsrv/fcgi/perl/configure.in | 16 + iipsrv/fcgi/perl/echo.PL | 67 + iipsrv/fcgi/perl/fcgi_config.h.in | 76 + iipsrv/fcgi/perl/oldinterface.pod | 50 + iipsrv/fcgi/perl/remote.PL | 36 + iipsrv/fcgi/perl/threaded.PL | 52 + iipsrv/fcgi/perl/typemap | 17 + iipsrv/fcgi/perl/version.pm | 3 + iipsrv/man/Makefile.am | 4 + iipsrv/man/iipsrv.8 | 180 + iipsrv/src/CVT.cc | 478 + iipsrv/src/Cache.h | 455 + iipsrv/src/DSOImage.cc | 280 + iipsrv/src/DSOImage.h | 120 + iipsrv/src/DeepZoom.cc | 198 + iipsrv/src/Environment.h | 247 + iipsrv/src/FIF.cc | 249 + iipsrv/src/ICC.cc | 79 + iipsrv/src/IIIF.cc | 552 + iipsrv/src/IIPImage.cc | 358 + iipsrv/src/IIPImage.h | 378 + iipsrv/src/IIPResponse.cc | 128 + iipsrv/src/IIPResponse.h | 155 + iipsrv/src/JPEGCompressor.cc | 446 + iipsrv/src/JPEGCompressor.h | 149 + iipsrv/src/JTL.cc | 311 + iipsrv/src/KakaduImage.cc | 643 + iipsrv/src/KakaduImage.h | 210 + iipsrv/src/Main.cc | 764 ++ iipsrv/src/Makefile.am | 66 + iipsrv/src/Memcached.h | 148 + iipsrv/src/OBJ.cc | 298 + iipsrv/src/OpenSlideImage.cc | 935 ++ iipsrv/src/OpenSlideImage.h | 206 + iipsrv/src/PFL.cc | 222 + iipsrv/src/RawTile.h | 304 + iipsrv/src/SPECTRA.cc | 163 + iipsrv/src/TIL.cc | 243 + iipsrv/src/TPTImage.cc | 325 + iipsrv/src/TPTImage.h | 108 + iipsrv/src/Task.cc | 458 + iipsrv/src/Task.h | 341 + iipsrv/src/TileManager.cc | 446 + iipsrv/src/TileManager.h | 148 + iipsrv/src/Timer.h | 87 + iipsrv/src/Tokenizer.h | 107 + iipsrv/src/Transforms.cc | 775 ++ iipsrv/src/Transforms.h | 127 + iipsrv/src/URL.h | 139 + iipsrv/src/View.cc | 253 + iipsrv/src/View.h | 246 + iipsrv/src/Watermark.cc | 148 + iipsrv/src/Watermark.h | 136 + iipsrv/src/Writer.h | 140 + iipsrv/src/Zoomify.cc | 169 + iipsrv/windows/MemcachedWindows.h | 160 + iipsrv/windows/Time.cc | 505 + iipsrv/windows/Time.h | 40 + iipsrv/windows/VISUAL_STUDIO_README.txt | 1 + .../64-bit kdu_v73, libfcgi and kdu_compress | 0 .../32-bit kdu_v73, libfcgi and kdu_compress | 0 .../header files and some kakadu source files | 0 .../dependencies/libs/x64/64-bit libraries | 0 .../dependencies/libs/x86/32-bit libraries | 0 iipsrv/windows/iipsrv-MSVC2008.sln | 26 + iipsrv/windows/iipsrv-MSVC2010.sln | 26 + iipsrv/windows/iipsrv.vcproj | 556 + iipsrv/windows/iipsrv.vcxproj | 243 + iipsrv/windows/iipsrv.vcxproj.filters | 159 + iipsrv/windows/unified installers/README.txt | 19 + .../iipimage_IIS_x86_x64.iss | 391 + 173 files changed, 64133 insertions(+), 21 deletions(-) create mode 100644 iipsrv/AUTHORS create mode 100644 iipsrv/COPYING create mode 100644 iipsrv/ChangeLog create mode 100644 iipsrv/INSTALL create mode 100644 iipsrv/Makefile.am create mode 100644 iipsrv/NEWS create mode 100644 iipsrv/README create mode 120000 iipsrv/README.md create mode 100644 iipsrv/TODO create mode 100644 iipsrv/acinclude.m4 create mode 100755 iipsrv/autogen.sh create mode 100644 iipsrv/configure.in create mode 100644 iipsrv/doc/doxygen-html.conf create mode 100644 iipsrv/fcgi/LICENSE.TERMS create mode 100644 iipsrv/fcgi/Makefile.am create mode 100644 iipsrv/fcgi/Makefile.nt create mode 100644 iipsrv/fcgi/README create mode 100644 iipsrv/fcgi/Win32/FastCGI.dsw create mode 100644 iipsrv/fcgi/Win32/authorizer.dsp create mode 100644 iipsrv/fcgi/Win32/cgifcgi.dsp create mode 100644 iipsrv/fcgi/Win32/echo-cpp.dsp create mode 100644 iipsrv/fcgi/Win32/echo.dsp create mode 100644 iipsrv/fcgi/Win32/echox.dsp create mode 100644 iipsrv/fcgi/Win32/libfcgi.dsp create mode 100644 iipsrv/fcgi/Win32/logdump.dsp create mode 100644 iipsrv/fcgi/Win32/size.dsp create mode 100644 iipsrv/fcgi/Win32/threaded.dsp create mode 100644 iipsrv/fcgi/acinclude.m4 create mode 100644 iipsrv/fcgi/cgi-fcgi/cgi-fcgi.mak create mode 100755 iipsrv/fcgi/configure create mode 100644 iipsrv/fcgi/doc/FCGI_Accept.3 create mode 100644 iipsrv/fcgi/doc/FCGI_Finish.3 create mode 100644 iipsrv/fcgi/doc/FCGI_SetExitStatus.3 create mode 100644 iipsrv/fcgi/doc/FCGI_StartFilterData.3 create mode 100644 iipsrv/fcgi/doc/cgi-fcgi.1 create mode 100644 iipsrv/fcgi/doc/fastcgi-prog-guide/ap_guida.htm create mode 100644 iipsrv/fcgi/doc/fastcgi-prog-guide/ap_guide.htm create mode 100644 iipsrv/fcgi/doc/fastcgi-prog-guide/apaman.htm create mode 100644 iipsrv/fcgi/doc/fastcgi-prog-guide/ch1inta1.gif create mode 100644 iipsrv/fcgi/doc/fastcgi-prog-guide/ch1intra.gif create mode 100644 iipsrv/fcgi/doc/fastcgi-prog-guide/ch1intro.htm create mode 100644 iipsrv/fcgi/doc/fastcgi-prog-guide/ch2c.htm create mode 100644 iipsrv/fcgi/doc/fastcgi-prog-guide/ch3perl.htm create mode 100644 iipsrv/fcgi/doc/fastcgi-prog-guide/ch4tcl.htm create mode 100644 iipsrv/fcgi/doc/fastcgi-prog-guide/cover.htm create mode 100644 iipsrv/fcgi/doc/fastcgi-prog-guide/covera.gif create mode 100644 iipsrv/fcgi/doc/fastcgi-whitepaper/fastcgi.htm create mode 100644 iipsrv/fcgi/doc/fastcgi-whitepaper/img00001.gif create mode 100644 iipsrv/fcgi/doc/fastcgi-whitepaper/img00002.gif create mode 100644 iipsrv/fcgi/doc/fastcgi-whitepaper/img00003.gif create mode 100644 iipsrv/fcgi/doc/fcgi-devel-kit.htm create mode 100644 iipsrv/fcgi/doc/fcgi-java.htm create mode 100644 iipsrv/fcgi/doc/fcgi-perf.htm create mode 100644 iipsrv/fcgi/doc/fcgi-perl.htm create mode 100644 iipsrv/fcgi/doc/fcgi-spec.html create mode 100644 iipsrv/fcgi/doc/fcgi-tcl.htm create mode 100644 iipsrv/fcgi/doc/omi-logo.gif create mode 100644 iipsrv/fcgi/doc/overview.html create mode 100644 iipsrv/fcgi/doc/www5-api-workshop.html create mode 100644 iipsrv/fcgi/examples/authorizer.mak create mode 100644 iipsrv/fcgi/examples/echo-cpp.mak create mode 100644 iipsrv/fcgi/examples/echo.mak create mode 100644 iipsrv/fcgi/examples/echox.mak create mode 100644 iipsrv/fcgi/examples/size.mak create mode 100644 iipsrv/fcgi/fcgi_config.h create mode 100644 iipsrv/fcgi/images/aplib-hd.gif create mode 100644 iipsrv/fcgi/images/divider.gif create mode 100644 iipsrv/fcgi/images/fcgi-hd.gif create mode 100644 iipsrv/fcgi/images/mail-hd.gif create mode 100644 iipsrv/fcgi/images/navbar.gif create mode 100644 iipsrv/fcgi/images/serv-hd.gif create mode 100644 iipsrv/fcgi/images/words-hd.gif create mode 100644 iipsrv/fcgi/include/Makefile.am create mode 100644 iipsrv/fcgi/include/fastcgi.h create mode 100644 iipsrv/fcgi/include/fcgi_config_x86.h create mode 100644 iipsrv/fcgi/include/fcgi_stdio.h create mode 100644 iipsrv/fcgi/include/fcgiapp.h create mode 100644 iipsrv/fcgi/include/fcgimisc.h create mode 100644 iipsrv/fcgi/include/fcgio.h create mode 100644 iipsrv/fcgi/include/fcgios.h create mode 100644 iipsrv/fcgi/java/FCGIGlobalDefs.java create mode 100644 iipsrv/fcgi/java/FCGIInputStream.java create mode 100644 iipsrv/fcgi/java/FCGIInterface.java create mode 100644 iipsrv/fcgi/java/FCGIMessage.java create mode 100644 iipsrv/fcgi/java/FCGIOutputStream.java create mode 100644 iipsrv/fcgi/java/FCGIRequest.java create mode 100644 iipsrv/fcgi/libfcgi/Makefile.am create mode 100644 iipsrv/fcgi/libfcgi/fcgi_stdio.c create mode 100644 iipsrv/fcgi/libfcgi/fcgiapp.c create mode 100644 iipsrv/fcgi/libfcgi/libfcgi.mak create mode 100644 iipsrv/fcgi/libfcgi/os_unix.c create mode 100644 iipsrv/fcgi/libfcgi/os_win32.c create mode 100644 iipsrv/fcgi/ltmain.sh create mode 100644 iipsrv/fcgi/perl/ChangeLog create mode 100644 iipsrv/fcgi/perl/FCGI.PL create mode 100644 iipsrv/fcgi/perl/FCGI.XL create mode 100644 iipsrv/fcgi/perl/MANIFEST create mode 100644 iipsrv/fcgi/perl/Makefile.PL create mode 100644 iipsrv/fcgi/perl/README create mode 100644 iipsrv/fcgi/perl/aclocal.m4 create mode 100755 iipsrv/fcgi/perl/configure create mode 100644 iipsrv/fcgi/perl/configure.in create mode 100644 iipsrv/fcgi/perl/echo.PL create mode 100644 iipsrv/fcgi/perl/fcgi_config.h.in create mode 100644 iipsrv/fcgi/perl/oldinterface.pod create mode 100644 iipsrv/fcgi/perl/remote.PL create mode 100644 iipsrv/fcgi/perl/threaded.PL create mode 100644 iipsrv/fcgi/perl/typemap create mode 100644 iipsrv/fcgi/perl/version.pm create mode 100644 iipsrv/man/Makefile.am create mode 100644 iipsrv/man/iipsrv.8 create mode 100644 iipsrv/src/CVT.cc create mode 100644 iipsrv/src/Cache.h create mode 100644 iipsrv/src/DSOImage.cc create mode 100644 iipsrv/src/DSOImage.h create mode 100644 iipsrv/src/DeepZoom.cc create mode 100644 iipsrv/src/Environment.h create mode 100644 iipsrv/src/FIF.cc create mode 100644 iipsrv/src/ICC.cc create mode 100644 iipsrv/src/IIIF.cc create mode 100644 iipsrv/src/IIPImage.cc create mode 100644 iipsrv/src/IIPImage.h create mode 100644 iipsrv/src/IIPResponse.cc create mode 100644 iipsrv/src/IIPResponse.h create mode 100644 iipsrv/src/JPEGCompressor.cc create mode 100644 iipsrv/src/JPEGCompressor.h create mode 100644 iipsrv/src/JTL.cc create mode 100644 iipsrv/src/KakaduImage.cc create mode 100644 iipsrv/src/KakaduImage.h create mode 100644 iipsrv/src/Main.cc create mode 100644 iipsrv/src/Makefile.am create mode 100644 iipsrv/src/Memcached.h create mode 100644 iipsrv/src/OBJ.cc create mode 100644 iipsrv/src/OpenSlideImage.cc create mode 100644 iipsrv/src/OpenSlideImage.h create mode 100644 iipsrv/src/PFL.cc create mode 100644 iipsrv/src/RawTile.h create mode 100644 iipsrv/src/SPECTRA.cc create mode 100644 iipsrv/src/TIL.cc create mode 100644 iipsrv/src/TPTImage.cc create mode 100644 iipsrv/src/TPTImage.h create mode 100644 iipsrv/src/Task.cc create mode 100644 iipsrv/src/Task.h create mode 100644 iipsrv/src/TileManager.cc create mode 100644 iipsrv/src/TileManager.h create mode 100644 iipsrv/src/Timer.h create mode 100644 iipsrv/src/Tokenizer.h create mode 100644 iipsrv/src/Transforms.cc create mode 100644 iipsrv/src/Transforms.h create mode 100644 iipsrv/src/URL.h create mode 100644 iipsrv/src/View.cc create mode 100644 iipsrv/src/View.h create mode 100644 iipsrv/src/Watermark.cc create mode 100644 iipsrv/src/Watermark.h create mode 100644 iipsrv/src/Writer.h create mode 100644 iipsrv/src/Zoomify.cc create mode 100644 iipsrv/windows/MemcachedWindows.h create mode 100644 iipsrv/windows/Time.cc create mode 100644 iipsrv/windows/Time.h create mode 100644 iipsrv/windows/VISUAL_STUDIO_README.txt create mode 100644 iipsrv/windows/dependencies/dlls/x64/64-bit kdu_v73, libfcgi and kdu_compress create mode 100644 iipsrv/windows/dependencies/dlls/x86/32-bit kdu_v73, libfcgi and kdu_compress create mode 100644 iipsrv/windows/dependencies/includes/header files and some kakadu source files create mode 100644 iipsrv/windows/dependencies/libs/x64/64-bit libraries create mode 100644 iipsrv/windows/dependencies/libs/x86/32-bit libraries create mode 100644 iipsrv/windows/iipsrv-MSVC2008.sln create mode 100644 iipsrv/windows/iipsrv-MSVC2010.sln create mode 100644 iipsrv/windows/iipsrv.vcproj create mode 100644 iipsrv/windows/iipsrv.vcxproj create mode 100644 iipsrv/windows/iipsrv.vcxproj.filters create mode 100644 iipsrv/windows/unified installers/README.txt create mode 100644 iipsrv/windows/unified installers/iipimage_IIS_x86_x64.iss diff --git a/Dockerfile b/Dockerfile index a6e8ff6..81048ff 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM ubuntu:14.04 +FROM ubuntu:bionic ### update RUN apt-get -q update @@ -7,24 +7,14 @@ RUN apt-get -q -y dist-upgrade RUN apt-get clean RUN apt-get -q update -RUN apt-get -q -y install openssh-server git autoconf automake make libtool pkg-config cmake apache2 libapache2-mod-fcgid libfcgi0ldbl -RUN apt-get -q -y install zlib1g-dev libpng12-dev libjpeg-dev libtiff5-dev libgdk-pixbuf2.0-dev libxml2-dev libsqlite3-dev libcairo2-dev libglib2.0-dev -RUN apt-get -q -y install g++ libmemcached-dev libjpeg-turbo8-dev +RUN apt-get -q -y install openssh-server git autoconf automake make libtool pkg-config cmake apache2 libapache2-mod-fcgid libfcgi0ldbl zlib1g-dev libpng-dev libjpeg-dev libtiff5-dev libgdk-pixbuf2.0-dev libxml2-dev libsqlite3-dev libcairo2-dev libglib2.0-dev g++ libmemcached-dev libjpeg-turbo8-dev RUN a2enmod rewrite RUN a2enmod fcgid -WORKDIR /images -VOLUME ["/images"] - RUN mkdir /root/src COPY . /root/src WORKDIR /root/src - -## get our configuration files -WORKDIR /root/src -#RUN git clone https://tcpan@bitbucket.org/tcpan/iip-openslide-docker.git - ## replace apache's default fcgi config with ours. RUN rm /etc/apache2/mods-enabled/fcgid.conf COPY ./fcgid.conf /etc/apache2/mods-enabled/fcgid.conf @@ -38,9 +28,6 @@ RUN ln -s /etc/apache2/mods-available/proxy.conf /etc/apache2/mods-enabled/proxy COPY apache2.conf /etc/apache2/apache2.conf COPY ports.conf /etc/apache2/ports.conf -## setup a mount point for images. - this is external to the docker container. -RUN mkdir -p /mnt/images - WORKDIR /root/src @@ -69,17 +56,11 @@ RUN make RUN make install ### iipsrv -WORKDIR /root/src -RUN git clone https://bitbucket.org/tcpan/iipsrv.git iipsrv - -## build iipsrv WORKDIR /root/src/iipsrv -RUN git checkout tags/iip-openslide-v0.3.1 RUN ./autogen.sh #RUN ./configure --enable-static --enable-shared=no RUN ./configure RUN make - ## create a directory for iipsrv's fcgi binary RUN mkdir -p /var/www/localhost/fcgi-bin/ RUN cp /root/src/iipsrv/src/iipsrv.fcgi /var/www/localhost/fcgi-bin/ diff --git a/iipsrv/AUTHORS b/iipsrv/AUTHORS new file mode 100644 index 0000000..2e027f0 --- /dev/null +++ b/iipsrv/AUTHORS @@ -0,0 +1,10 @@ +Ruven Pillay + +With help from: +Moravian Library in Brno +Chiara Marmo +Rob "Bubba" Hines +Petr Pridal +Michal Becak +The National Library of Wales +and many others ... diff --git a/iipsrv/COPYING b/iipsrv/COPYING new file mode 100644 index 0000000..94a9ed0 --- /dev/null +++ b/iipsrv/COPYING @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + 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 3 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, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + Copyright (C) + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. diff --git a/iipsrv/ChangeLog b/iipsrv/ChangeLog new file mode 100644 index 0000000..98318a9 --- /dev/null +++ b/iipsrv/ChangeLog @@ -0,0 +1,1244 @@ +27/11/2014: + - Added new magic identifier for BigTIFF images to IIPImage.cc + + +25/11/2014: + - Fix of rounding error problem in View.cc for calculating resolution level. + - Fix to IIIF.cc to properly handle resolution 0 requests. + + +24/11/2014: + - Fix to TileManager.cc to properly calculate tile height for final row. + - Updates to IIIF code to ensure tiles are properly detected. + - Changes to View class to calculate regions from full resolution image. + + +24/10/2014: + - Updated MINMAX command syntax in Task.cc to channel:min,max + + +22/10/2014: + - Updated KakaduImage.cc to use Kakadu namespaces in version 7.5 and greater. + + +05/09/2014: + - Updated IIIF info.json output to be compliant with changed IIIF 2.0 specification. + + +03/09/2014: + - Fix to IIPImage.cc for file type detection for multispectral sequences. + + +22/08/2014: + - Fix to properly read 12 bit JP2 files. + - KakaduImage's virtual_levels counter moved into IIPImage class. + - Modification to properly read number of components in multi-band JPEG2000 images. + + +21/08/2014: + - Fixes to allow compilation on older versions of gcc. + + +20/08/2014: + - Cleanup to IIIF code and some cosmetic improvements to generated JSON. + - Added string escape function to URL class and moved all environment variable access to + Main.cc. + + +19/08/2014: + - Added aspect ratio flag in View.h for use in CVT.cc. Also cleaned up Main.cc to remove + unnecesary logging and record extra http headers. + - Added IIIF protocol version 2.0 support via the IIIF argument. + + +13/08/2014: + - The rotate filter only ever operates on 8bit data, so remove if else type statements from + function - increases average function speed by about around 15%. + - Added missing URL.h to src/Makefile.am. + - Refactored JTL into 2 separate functions: run (parses arguments) & send (performs tile + request, processing and sending). Allows this to be re-used in other functions, such as + Zoomify.cc etc. + - Refactored CVT similarly to JTL with now a separate send() function. + + +11/08/2014: + - Renamed variable bpp in IIPImage and its derived classes to bpc (bits per channel), + which is more logical and how we have named things elsewhere. + - Modification to TileManager, which was requesting more tiles than necessary for regions. + - Changes to View.cc to make WID and HEI requests with region exports produce images with a + *final* size of that requested by WID or HEI. For example RGN=0.1,0.1,0.5,0.5&WID=500 will + now produce an image of 500px in width rather than extract the region from an image of size + 500px wide. CVT also cleaned up. + + +06/08/2014: + - Updated exception handling to use std::invalid_argument and a new derived file_error + exception within the IIPImage and derived classes. Allows better distinguishing between + HTTP status errors. + - Moved URL decoding code from FIF.cc to separate URL class in URL.h. + + +05/08/2014: + - Added flip function to Transforms. + - Modified JTL, DeepZoom, Zoomify and CVT to avoid float conversion if not required. + - Converted bilinear and nearest neighbour resize code to unsigned char to avoid + unnecessary conversion to float. + + +30/07/2014: + - Moved CTW processing function to before gamma function in JTL.cc and CVT.cc. + - Added missing function comments and minor layout changes in Transform.cc and FIF.cc. + + +24/07/2014: + - Simplified the use of hash_map types and removed the customized hash function, which + was causing our image metadata cache to work incorrectly. Removed the const prefix from + all hash maps keys. + + +20/07/2014: + - Min Max values are now read as vectors in multiple channel images - thanks to Chiara Marmo. + + +19/07/2014: + - Added support for magic byte signature file format detection instead of relying on + the file path suffix. Images can now be named arbitrarily (though suffixes still used + for sequences). Format enum types added to IIPImage class. + + +18/07/2014: + - Fix for unusual JPEG2000 "sRGB" bilevel images. + + +20/03/2014: + - Fixed signed/unsigned comparison compiler warning in Task.cc. + + +16/03/2014: + - Added back missing include to Task.cc. + + +12/03/2014: + - Added ability to handle multi-band (>3 channel) images and added new CTW color twist + command that takes a matrix that is applied to each channel in the image. + - Cleanup of and more comprehensive timing output within JTL.cc. + + +08/03/2014: + - Changes to resizing algorithms to enable expansions as well as shrink for all views + and regions. + - Added CORS (Cross Origin Resource Sharing) support via CORS environment variable for + (AJAX) metadata requests. + + +24/02/2014: + - Added missing function timer to JTL.cc and increased output precision in PFL.cc to 9. + + +24/01/2014: + - Changes to IIPImage and KakaduImage constructors to force correct initialization of + the tile size. + - Added missing std::isinfinite function for Windows Visual Studio compilation. + + +17/01/2013: + - Fix to rotation code to have array indices run fully down to zero when counting down. + Thanks to Michal Becak for spotting this. + + +06/12/2013: + - Minor fixes to PFL.cc to add extra error checking and eliminate compiler warnings. + + +05/12/2013: + - Another update to use the ISO C++11 version of unordered_map if available. Plus a bunch + of compiler warning clean-ups. + + +04/12/2013: + - Updated hash map definitions to try to use unordered_map if available and fall back to + hash_map or map. Now done more cleanly using autoconf detection. + + +02/12/2013: + - Changes to IIPImage, TPTImage and KakaduImage class contstructors to use more efficient + member initializer lists, which are also necessary for compilation with clang compiler. + + +25/11/2013: + - Bug on red/green/blue colormaps fixed. Adding colormap inversion function (Chiara Marmo). + + +22/10/2013: + - Bittype compatibility has been completely reviewed. After normalization all processing + is done in float (Chiara Marmo). + + +07/09/2013: + - Modified PFL to handle single points as well as profiles. Thus syntax for single + points: PFL=:, and for profiles PFL=:,-, + + +03/09/2013: + - Updated PFL command to also handle multi-spectral data. + + +02/09/2013: + - Modified PFL command to use JSON and implemented vertical profiles. + + +28/08/2013: + - Added PFL command for obtaining raw X profiles of data. Syntax + is :,-,. Only horizontal profiles are supported so far. + + +23/08/2013: + - Fix to OpenMP code in Transform.cc for compatibility with Intel compiler - thanks + Emmanuel Bertin. + - Addition of extra timing output in JTL.cc + + +06/08/2013: + - Moved setenv/unsetenv function definitions to Main.cc where they are now needed following + movement of timezone setting code there. + + +31/07/2013: + - Fix to JTL.cc and TPTImage.cc for multispectral sequences consisting of images of + different bit depths. + + +23/07/2013: + - Fix to KakaduImage.cc to enable correct handling of bilevel images. + - Fix to quality layer decoding - variables moved directly into IIPImage class + - Scaling of 8 and 16 bit spectral data to normalized 0.0->1.0 float in SPECTRA.cc + + +08/07/2013: + - Fix to configure.in for libmemcached configuration problem on Fedora. + + +02/07/2013: + - Optimizations to FIF.cc. Unnecessary file header reading is now avoided as top + level IIPImage class cache fully utilized. Cleanup of constructor code of IIPImage, + TPTImage and KakaduImage code. Significant speed up to requests of cached images. + - Modification to if_modified_since code in FIF.cc, to avoid repeatedly resetting the + timezone environment variable to UTC when checking timestamps, which is a relatively + slow process. This is now set once globally in Main.cc and set back on main exit. + + +12/06/2013: + - Extra checks for malformed images in KakaduImage.cc. + + +11/04/2013: + - Several fixes to Kakadu.cc. To force resolution levels to be floor(x/2) rather than the default + ceil(x/2) to match how TIFF resolutions are created. Also modification to force 16 bit + JPEG2000 to unsigned output. And also fix to strip alpha channels from images. + + +14/03/2013: + - Fix to gamma conversion - thanks Chiara Marmo + - Update to greyscale conversion code + + +09/03/2013: + - Updated copyright message in header to new Free Software Foundation address. + + +08/03/2013: + - Added greyscale conversion support via new filter_greyscale transform function. + + +23/02/2013: + - Gamma correction fixed, minmax commands added, colormap commands added (Chiara Marmo) + + +30/01/2013: + - Fix to prevent crashing on malformed JPEG2000 files. + + +11/12/2012: + - Changed FLOAT enum type to FLOATINGPOINT to avoid VC++ compiler error. + - Implemented 16 and 32bit versions of interpolation functions. + + +10/12/2012: + - Cleanup to 32 bit code + - New command to set dynamically the min and max for 32 bit float + - Addition of rotation function for 90,180,270 degree rotations + - Fixes to autoconf + + +30/10/2012: + - Autoconf cleanup. Removed unneccesary autoconf files: should now use + autogen.sh script first before ./configure + + +18/10/2012: + - Fix to imageCache delete in FIF.cc - thanks to Michal Becak. + + +16/10/2012: + - Added support for TIFF 32 bit integer and float. + - Fixed 16 bit JPEG2000 support. + - Added 1 bit support for TIFF. + - Added gamma support via GAM command. + - Thanks to Chiara Marmo for initial implementation. + + +09/09/2012: + - TIFF metadata fixes. + + +25/08/2012: + - Windows compilation fixes by Michal Becak. + + +13/08/2012: + - Detect JPEG YCbCr encoding in TIFF and request conversion to RGB + by libtiff. Tile _TIFFmalloc() now only occurs in getTile(). + + +16/07/2012: + - Added check to KakaduImage.cc to handle bilevel images. + - Clean up to use only floats and floorf() in Transforms.cc. + + +14/05/2012: + - Added bilinear interpolation option for CVT resizing. Added + INTERPOLATION parameter to Environment.h, which takes an integer. + 0 for fastest nearest neighbour and 1 for bilinear (default). + Current bilinear implementation 2.5x slower than nearest neighbour. + - Additional fix to MAX_LAYERS code. + + +11/05/2012: + - Modified layer handling to decode all available layers if + MAX_LAYERS parameter is set to -1. + + +08/05/2012: + - Fix to Mac OSX and FreeBSD compilation of KakaduImage.cc. + + +07/05/2012: + - Fixed strip height calculation error in CVT.cc + + +01/05/2012: + - Modified memory handling in JPEGCompressor.cc to better handle + images where the compressed version may be bigger than the + original (for example at very high quality levels). + - Changes to CVT.cc to work with new JPEGCompressor code and removal + of chunked encoding header directive from CVT.cc. + - Fixed bug in CVT when specifying both WID and HEI. + - Fixed compiler warning in IIPResponse.cc. + - Added man page. + - Added missing definition of get_nprocs() function to Kakadu.cc + for Mac OSX and FreeBSD. + + +20/04/2012: + - Fixed memory overun error in filter_contrast in Transforms.cc. + + +18/04/2012: + - Major rewrite of CVT code to unify TIFF and JPEG2000 region + export. Region compositing now in TileManager->getRegion with + modified getRegion Kakadu function. Changes also to View class + and ColourTransforms code to enable greater modularity for + image processing to regions. ColourTransforms renamed to + Transforms. + Thanks to The National Library of Wales, who will be using + iipsrv & iipmooviewer to deliver their Historic Newspapers + in 2012. + + +21/03/2012: + - Fix to TPTImage.c to force RGB conversion for YCbCr compressed + JPEG TIFFs, which is now the default in VIPS. Thanks to John + Cupitt for spotting this. + + +17/03/2012: + - Changes to View.[h,cc] to make sure getRequestWidth and Height + return correctly rounded values. + + +12/03/2012: + - Added HTTP Status: 400 Bad Request to error messages. + + +28/01/2012: + - Fixes to KakaduImage.cc to properly catch exceptions during file + opening and a check for existence during codestream shutdown. + - Also added a check to updateTimeStamp to throw an exception if file + unreadable. + + +28/08/2011: + - Performance improvement to JPEG2000 16->8 bit downsampling. Now + using integer arithmetic rather than float. + + +24/08/2011: + - Updates to configure.in, FIF.cc and DeepZoom.cc to check for and + handle missing setenv, unsetenv and log2 functions. Fixes problem + on Solaris 10. + + +02/08/2011: + - Changed timegm function in FIF.cc to use more cross-platform POSIX + mktime function instead. Fixes compilation error on Solaris. + + +22/07/2011: + - Added 16bit and CIELAB support for JPEG2000. + - Other minor cleanups. + + +24/05/2011: + - Fix added to DeepZoom.cc as FreeBSD does not have the log2 function. + Thanks to Andrew Hankinson for spotting this. + + +23/05/2011: + - Another fix to ensure the max layers variable is correctly used in + Zoomify and DeepZoom output. + + +15/04/2011: Version 0.9.9 Released + + +15/04/2011: + - Fix to View.h to properly take into account max layers variable. + + +14/04/2011: + - Minor logging update to Zoomify.cc. + + +13/04/2011: + - Updated VC++ project files. + - Minor changes to logging in Main.cc. + - Updated autoconf files. + + +08/04/2011: + - Change to TileManager.cc to take into account whether a tile is padded + or not when applying a watermark. + + +06/04/2011: + - Changes to allow compilation on Windows with Visual C++ Express 2010. + New windows subfolder with missing time definitions and VC solution file. + Fixes also include definition of snprintf, log2 and S_ISREG, which are + all missing in Windows. Many thanks to Rob "Bubba" Hines for his help in + porting. + + +21/03/2011: + - Added extra NULL assignment to Task pointer after catch block to avoid + problems with uninitialized memory being deleted. + - Added SIGINT handler for Ctrl-C interruptions with strsignal() to + display a more meaningful message. + + +17/03/2011: + - Clean-up of signed/unsigned variables in IIPImage.h and KakaduImage.h. + + +15/03/2011: + - Added sanity check for requested resolutions and tiles in JTL.cc. + - Fixed problem with edge tiles and watermarking. + - Clean-up of error message in TPTImage.cc. + + +14/03/2011: + - Fixed problem with standalone mode. Can now bind to an FCGI socket by + running iipsrv on the command line with the argument --bind. + For example: ./iipsrv.fcgi --bind localhost:9000 + - Fixed memory problem reported by valgrind with 16bit images. + Now simply use memcpy instead of re-assigning memory blocks. Changes to + JTL.cc, DeepZoom.cc and Zoomify.cc. + - Added extra buffer overhead during JPEG compression. + - Minor fixes to buffer copy code in Writer.h. + - Fixed memory leak in Memcached code - need to explicitly free returned + objects! + + +01/12/2010: + - Modified Main.cc to not check in Memcached if there has been a + If-Modified-Since parameter sent and to not store 304 or error replies. + Otherwise we risk to send 304 replies to requests from uncached browsers. + + +25/11/2010: + - Removed final CRLF from JTL, Zoomify and DeepZoom requests, which causes + problems with http pipelining in firefox. + + +24/11/2010: + - Added extra checks to both TPTImage and KakaduImage for whether the + requested resolution exists. + - Added ability to KakaduImage to downsize resolutions that were not generated + during encoding. + - Added decompressor.finish() to catch block as finish crashes if called after + thread environment shut down. + + +18/11/2010: + - Fixed problem when clipping when applying watermarks for both 8 and 16 bit images. + + +15/11/2010: + - Added memcached support via libmemcached. List of servers passed via + MEMCACHED_SERVERS environment variable. Length of time the cache + remains valid set by optional MEMCACHED_TIMEOUT environment variable + (default is 3600 seconds). Storage is at output level, rather than tile + level, so is complementary to internal tile cache. + Thanks to Moravian Library in Brno (Moravska zemska knihovna v Brne, + http://www.mzk.cz/) R&D grant MK00009494301 & Old Maps Online + (http://www.oldmapsonline.org/) from the Ministry of Culture + of the Czech Republic. + + +06/11/2010: + - Modification to Cache.h to use string::capacity() function instead of length() + to determine space used by string. + + +31/10/2010: + - Added simple watermarking support via Watermark class. New environment + variables added for the watermark image, the opacity and probability. + Changes mainly to the TileManager and Session class. Watermarking happens + transparently within the TileManager class for all tiles. Thanks to + Moravian Library in Brno (Moravska zemska knihovna v Brne, http://www.mzk.cz/) + R&D grant MK00009494301 & Old Maps Online (http://www.oldmapsonline.org/) + from the Ministry of Culture of the Czech Republic. + + +15/09/2010: + - Modified IIPImage.cc to enable handling of images with spectral band + indices with mixtures of 3 or 4 digits. For example, H1_pyr_000_090.tif + and H1_pyr_2500_090.tif. + + +05/03/2010: + - Another fix to JPEGCompressor.cc to fix a crash with very small + tiles with libjpeg-8. + + +23/02/2010: + - Modified JPEGCompressor.cc to fix compatibility problem with + libjpeg version 8. Simply removed jpeg_write_tables from + InitCompression function. + + +09/02/2010: + - Fixed memory leak in Zoomify.cc and DeepZoom.cc + + +11/01/2010: + - JPEG2000 support added via the Kakadu SDK. Added new class + KakaduImage derived from the IIPImage class. JPEG2000 support + added thanks to Moravian Library in Brno (Moravska zemska knihovna + v Brne, http://www.mzk.cz/) R&D grant MK00009494301 & Old Maps Online + (http://www.oldmapsonline.org/) from the Ministry of Culture of + the Czech Republic. + - Fix to string literal warnings in Writer.h + + +08/01/2010: + - Major changes to the HTTP headers sent by iipsrv. Added + HTTP Server id and Last-Modified timestamps to all server output. + Checks are now made for a If-Modified-Since response and a + 304 Not Modified reponse returned if the timestamps match. + This should significantly improve server performance. + + +04/01/2010: + - Fixed bug in FIF.cc - the file system prefix was not being + initialized for each new image. + - Layers environment variable changed to MAX_LAYERS to represent + the maximum number of layers user is allowed to decode. + + +03/12/2009: Version 0.9.8 Released + + +02/12/2009: + - Adding missing include to IIPImage.cc for compilation with + gcc 4.4.1 + + +01/12/2009: + - Added DeepZoom protocol support. Work carried out thanks to + Moravian Library in Brno (Moravska zemska knihovna v Brne, + http://www.mzk.cz/) R&D grant MK00009494301 & Old Maps Online + (http://www.oldmapsonline.org/) from the Ministry of Culture of + the Czech Republic. + + +29/11/2009: + - Added SPECTRA.cc class for returning spectral reflectance values + from multispectral images. + - Fix to IIPImage.cc to properly count the number of horizontal and + vertical angles (used for multispectral bands). + + +26/11/2009: + - Fix to View class to take resampling into account when limiting + the CVT output size to the maximum server setting. + + +17/11/2009: + - Update to Zoomify to fix way it calculates number of zoom levels. + + +05/11/2009: + - Updated the autoconf, aclocal, automake and libtool scripts to the + latest versions. + + +04/11/2009: + - Added FILESYSTEM_PREFIX environment variable to allow a fixed prefix to + be applied to all image paths. Embedded NULL bytes of the form %00 and + any "../" are also now stripped out of any path for security reasons. + (Thanks to Willem Hengeveld for suggesting this) + + +01/11/2009: + - Fixes to View.h and View.cc to set the requested size to the maximum + allowable if not WID or HEI is set for the CVT command. The correct + resolution to use for CVT is now calculated for views smaller than + the smallest available. + + +30/10/2009: + - Security fixes to Task.cc to make sure while loop is limited to the + expected number of arguments. (Thanks to Willem Hengeveld for pointing + this out). + + +19/08/2009: + - Minor updates to IIPImage.h and IIPImage.cc. FIF.cc also now tests + for upper/lowercase .tif and .tiff suffixes. + + +14/08/2009: + - Modification to View.cc and CVT.cc to calculate the appropriate + resolution as the smallest resolution with a dimension greater size + than the requested dimensions. The WID and HEI directives now + effectively give bounding dimensions. + +11/08/2009: + - Added simple nearest neighbour resampling to CVT command to allow it to + resize to the exact dimensions and not just the nearest available pyramid + resolution. + - CVT Content-disposition tag now gives the image filename allowing the user + to save the image directly with this. + + +01/07/2009: + - Added quality layer parameter to images for future use with file formats + such as JPEG2000 that support this. This allows the decoding of several + quality layers via the LYR command. Modifications to the RawTile API + as well as IIPImage::getTile resulting in a series of changes to + CVT.cc, JTL.CC, TIL.cc, TPTImage.cc, View.h, Main.cc and Environment.h. + New startup configuration "LAYERS" to set the default number of layers. + Default is 1 otherwise. + + +22/06/2009: + - Changes to Zoomify.cc to take into account the fact that Zoomify expects + a fixed number of resolution levels. + + +15/04/2009: + - Added a flag for padded tiles into RawTile.h. TIFF's are padded out + to the tile size, but other formats may not be. Changes to TPTImage, + TileManager and CVT to handle this. + - Also changed the RawTile flag for memory managed tiles. + + +18/03/2009: + - Added modification timestamps to the IIPImage and Rawtile classes. + The TileManager now checks whether the tile is fresh and reloads it + if necessary. + + +11/03/2009: + - Several changes to JTL.cc and Cache.h to eliminate a memory leak. Also + replaced malloc/free in Rawtile with new/delete. + + +04/03/2009: + - Minor changes to IIPResponse.cc to elimate type warnings. + + +06/06/2008: + - Modifed the way the image dimensions are stored in the IIPImage class. + Rather than simply storing the max size, a vector of available dimensions + is saved making it easier to get the size for a given resolution. + + +05/06/2008: + - Added Zoomify support via the Zoomify=/path.tif request. Works with both + the official flash client and the Zoomify patched OpenLayers javascript + client. Work carried out thanks to R&D grant DC08P02OUK006 - Old Maps + Online (www.oldmapsonline.org) from Ministry of Culture of the Czech Republic. + + +09/08/2007: + - Added a Bits-per-channel OBJ request so that viewers can determine whether + to perform contrast adjustment server-side or client-side. + + +07/08/2007: + - Added CIELAB conversion and contrast handling to JTL so that it can handle + 16 bit images. + + +12/06/2007: + - Updated URL decoding function in FIF.cc to C++ style and avoid a potential + buffer overflow. + - Changed Task::run arguments to be const std::string& instead of just std::string. + + +08/06/2007: + - Changed JTL headers to enable HTTP 1.1 compatible cache control. + + +13/12/2006: Version 0.9.7 Released + + +07/11/2006: + - Fixed the standalone mode, which is now activated by launching with + --standalone with an argument giving the socket port or path. For example, + localhost:8000 or /tmp/iipsrv.sock. + + +31/10/2006: + - Added hillshading Task class and function for simulated raking light + visualization using 3D surface normal data. This is used via the SHD + command in association with CVT, which takes 2 arguments: the horizontal + light source angle in degrees and the vertical angle from the horizontal + plane. + + +26/09/2006: + - Cleaned up the hash_map and pool_allocator stuff a little to use typedefs + instead of #ifdefs. + - Added the legacy JTLS command class for panoramic views. + + +22/09/2006: + - Added an FCGI stand-alone mode usable with lighttpd's spawn-fcgi command. + - Also changed the IIPImage cache to use a hash_map and pool_alloc memory. + + +19/09/2006: + - If we are using appropriate versions of g++, we now use the high + performance pool_alloc memory allocators for our cache containers. + Also, instead of a std::map, we use the hash_map extension which + offers better performance. Otherwise we default to std::map. + - Fixed problem in TileManager where uncompressed tiles in the cache + were not being cropped when converted to JPEG. The IIPImage tile_width + and tile_height fields now hold the base tile size and not the current + tile size. + + +18/092006: + - Added a "Last-Modified" and "ETag" header to the CVT HTTP response + to prevent double requests from being made by web browsers. + - Fixed bug in CVT where the tile size was being incorrectly set from + the IIPImage object and not the tile itself, which was a problem + when getting tiles from the cache. + + +15/09/2006: + - Changed the Cache keys to be simple strings rather than custom + objects. This has solved one of the crashing problems when tiles + are deleted from the cache. + + +29/08/2006: + - Added Writer class to shield the command implentations from any + FCGI specific functions. + + +28/08/2006: + - *Major* refactoring of the code. Each command is now called via its own + Task class (command pattern), with no processing done in Main.cc. + OBJ commands are in OBJ.cc and each output command (eg TIL,CVT etc) + now have their own classes. + - The xangle and yangle variables are now in the View class, which + was previously named the ImageTransform class. + + +25/08/2006: + - Cleaned up the option variable parsing in Main.cc. It is now mostly + done via an Environment class, which checks for defaults etc. + + +16/08/2006: + - Moved QLT limit checking from Main into JPEG class. Also now check + for empty strings. + + +08/08/2006: + - Changed the contrast adjustment code to limit the result to a max of + 255.0 as this was creating problems with the windows build. + + +07/03/2006: Version 0.9.6 release. + + +13/02/2006: + - Fixed another problem on Mac OS X in TPTImage.cc. The number of + channels and bits per sample were giving strange values, so a + temporary uint16 variable is now used and cast from. It now works + perfectly on Mac :-) + + +09/02/2006: + - Changed the start_t and start_u types in Timer.h to long for + compatibility with Solaris and Mac OS X. + - Some code cleanups in the IIPResponse class. + + +23/01/2006: + - Added an extra timer for tile insertion - this is the slowest + cache operation. We should look to put this in a separate + thread at some point! + + +18/01/2006: + - Added support for ptif suffix images. These are in fact just + pyramidal TIFF images. + + +11/01/2006: + - More fixes to the TileManager class. Cache can now handle + multiple compression types for the same tile simultaneously. + + +24/12/2005: + - Major rewrite of the TileManager class. Now much more concise. + + +21/10/2005: + - Added a check in JPEGCompressor for the number of channels. + JPEG can handle only image with either 1 or 3 channels. + + +13/10/2005: + - Added a TileManager class to act as a higher level access to + the tile cache. It checks whether a JPEG compressed tile + already exists and if not decodes one from the source image. + It also crops any edge tiles to the correct size (required + for the new Vips TIFF format). + + +12/10/2005: + - Fixed a JTL problem with the new tiled TIFF format. The edge + tiles are now cropped before being sent out. + - Reworked JTL to just forward the request to JTLS rather than + duplicating the code there. + + +09/06/2005: + - Changed IIPImage.cc to use glob conditionally if glob has been + detected. This is needed for mingw compilation. + + +01/04/2005: + - Completed an LRU tile cache with the ability to set the max + cache size via the configuration variable MAX_IMAGE_CACHE_SIZE, + specified in MB. + + +22/03/2005: + - Added new Timer class to handle timing data to debug tile + access, command and total request times. + + +06/01/2005: + - Found problem in the CVT code when dealing with image sequences + of different numbers of channels. We have to reload the channel + information. + + +15/12/2004: + - CVT now works with the new standard compliant TIFF tile format + as used by vips-7.10 and later. + + +10/12/2004: + - CVT now works with 16 bit TIFF. The compression type reported + by TIL also switches from JPEG with 8 bit images to none with + 16 bit. + + +08/12/2004: + - Added CNT contrast command support. Also added check to + TPTImage openImage() for whether our image is in fact + tiled or not, which can cause the server to crash. + + +07/12/2004: + - Added 16 bit support. Changes to RawTile - the data is now + a generic (void*) and there are now fields for channels per + sample and bits per channel. Changes also to TPTImage.cc, + Main.cc and JPEGCompressor.cc. + + +01/09/2004: + - Changed the LAB2sRGB code to allow a/b values from + +-127 as per the TIFF spec instead +-100. + - Also fixed a problem caused by signed/unsigned comparisons + in ImageTransform with requests for CVT sizes smaller than + the tile size. + + +26/08/2004: + - Added largefile support by simply adding a configure + directive that will add the appropriate defines. + + +05/07/2004: + - Fixed problem in JPEGCompressor.cc concerning the value of + a structure that we try to read after de-allocating memory. + Only seems to be a problem with MSVC++ compiler. (Thanks to + Chris Tuijn for spotting this). + + +11/05/2004: Version 0.9.5 release. + + +04/05/2004: + - Moved the colorspace check from TPTImage::getTile to + TPTImage::openImage so that a Colorspace request will always + have an associated colour space and not just after getTile + has been called. We assume for now that all the tiles of an + image are all of the same colour space. + + +21/05/2004: + - Removed no-cache pragma from CVT header. Also modified + max_CVT variable to limit the effective size and not the + total image size. ie a small RGN of a massive image can + still be sent OK. The resolution calculations have been + moved into ImageTransform and is now performed at the last + moment in the CVT section. + + +16/05/2004: + - Added MAX_CVT environment variable to limit width and height + requests of CVT commands. The default is set to 5000 pixels. + + +02/04/2004: + - Added SDS command support. This can be used for specifying + subimages or the horizontal/vertical angle in 3D sequence + images and will eventually replace the use of JTLS by the + client. Current usage is SDS=h,v where h and v are the + horizontal and vertical sequence angles. + + +01/04/2004: + - Fixed length given by the error response. We now count both + the code and the argument. + + +30/03/2004: + - Fixed TIL to only send the MIME type once before the tile + sequence. + - Added better error handling. The IIPResponse is now set + whenever we have a problem in Main.cc. Plus the catch + clause now checks for an error in IIPResponse and sends + this if available rather than the advertising banner. + + +29/03/2004: + - Changed the vertical and horizontal views syntax back to + old style. + - Fixed problem with the number of CRLF's after the MIME type: + Apache complains if there are not 2 sets of CRLF. + - Changed the IIPImage metadata map to use the string class + rather than char* - seems to fix a freeze problem. + + +06/03/2004: + - More fixes to RGN code. Moved the verification logic into + the ImageTransform class itself rather than having it in + Main.cc. Also fixed a crash resulting from the use of + inlining - a gcc bug perhaps? Anyway, now perfectly stable. + + +05/03/2004: + - Some minor fixes to the RGN code to prevent crashes from + images of less than 8 pixels in size. + + +04/03/2004: + - Finished implementation of RGN CVT modifier. Can now specify + a region to CVT rather than always having the whole image. + - Updated embedded XHTML advertising page. + - Some doxygen-related cleanups and documenting. + + +03/03/2004: + - Changed Horizontal-views and Vertical-views return syntax to + return the number of views also (request by Denis): + Vertical-views/:view1 view2 ... + eg. Vertical-views/3:0 90 180. + + +02/03/2004: + - Added automatic colour spaces conversion for CIELAB images + to sRGB in CVT mode. + + +14/12/2003: + - Added Content-disposition headers to the JTL,JTLS and CVT output. + + +10/11/2003: + - Added missing std:: prefixes to a few STL variables in IIPImage.h + and IIPResponse.h. + - Fixed the TIL command to return only the tiles within the + rectangle defined by the specified range rather than all of them. + + +25/10/2003: + - Fixed missing value in error message for non decodable tiles + in TPTImage.cc and erroneous extra CRLF in the Colorspace + reply. + + +22/10/2003: + - Changed the IIPImage class to give the horizontal and + vertical angles a default value of 0,90 for non-sequence + images. + + +11/10/2003: + - Removed the new allocator in getFileName() in IIPImage.cc to + a statically allocated buffer of size 1024. + + +04/10/2003: + - Generalised the metadata handling in Main to cope with any + available metadata. + - Changed the way Basic-info and Summary-info work to simply + add more objects to the request string rather than try to + handle it themselves. Nicely eliminates duplicate handler code + without introducing classes or external functions for each obj. + - Also fixed the server capability return code to follow the IIP + spec properly. + + +03/10/2003: + - Added tracking of image data to the IIPResponse class. In this + way, we can print an error if we have an uncomplete command + syntax. eg. a WID without a CVT. We should now never not have + some sort of response from the server. + - Also added Author, Subject etc metadata handling to IIPImage + and the necessary handlers to IIPResponse. + + +15/09/2003: + - Added doxygen compatible comments to the header files. The + generated documentation is in the doc subdirectory. + - Changed sprintf to snprintf in Main.cc for the vertical-views + handler; snprintf is already used everywhere else. + - Added IIPResponse class to handle message passing back to the + client from OBJ requests. This allows for better error and + mime header handling and eliminates having to use FCGX_Fprintf. + - Added SIGHUP handling to the other signals handled - we simply + exit and allow mod_fastcgi to restart us. + - Added support for IIP-opt-comm and IIP-opt-obj requests. + - Removed the deprecated Max-sequence and Vertical-views object + handlers. + + +12/09/2003: Version 0.9.4 release. + - Added content-type heading to error returns. + - Added default catch() clause to the end of the main try block. + + +11/09/2003: + - Added Base64 URL decoding for the image path argument supplied + to the FIF command. + - Cleanups to eliminate most GCC -Wall warnings. + + +10/09/2003: + - Changed tolower to ::tolower to fix compilation problem using + GCC 3x. + - Logging cleanup. + + +08/09/2003: + - Major cleanup up the JPEGCompressor class. + - Added bits per pixel to the IIPImage copy constructors. + - Used the new JPEG buffer-buffer functions to add support for the + CVT command (limited to JPEG output only). + + +07/09/2003: + - Modified the JPEGCompressor class to allow stream-based buffer + to buffer encoding via 3 new functions (init, compressstrip and + finish). + + +03/09/2003: + - Fixed bug in TPTImage.cc. Added TIFFGetField commands for tile_width + and tile_height so that they get reset to the correct value even if + we loop through the end of a row. + - Added a bits per pixel field to the IIPImage class. + + +02/09/2003: + - Fixed mis-placed jpeg_set_defaults in JPEGCompressor.cc. + Was being called after some individual values were set. This only + seemed affected the dct_method. Should compress faster now. + + +28/08/2003: + - Added WID and HEI command support. + + +25/08/2003: + - Autoconf cleanups. Now properly detect for JPEG and TIFF. + + +24/08/2003: + - Improvements to the configure script. Can now completely disable + the dynamic module loading code from even compiling. + - The FCGI development library is now included in the distribution + for convenience and is integrated into the top-level configure + system. It is only used if it is not found on the computer. + + +22/08/2003: + - Added extra variable to track the current vertical position as + well as the horizontal. Fixes bug when switching between vertical + angles on sequence zero. + - XHTMLified the advertising banner :-) + + +22/03/2003: Version 0.9.3 release. + - Reworked and cleaned up the TIL compression type and subtype data + stream prefix with reference to the FlashPix specification. + + +21/03/2003: + - All commands are converted to lower case to handle the java JAI + IIP implementation which does not properly follow the spec. + - Also fixed typo in the Colorspace OBJ reply. + + +15/03/2003: + - Modifications to the JPEGCompressor constructor to take only the + Q factor. Plus the environment variable JPEG_QUALITY can + set the default Q factor. + - Plus added an #undef HAVE_STDLIB_H to JPEGCompressor.h which was + interfering with libjpeg. No compiler warnings now even + with -pendantic set :-) + + +13/03/2003: + - Added extended colour space handling. The TIFF image now has its + colourspace extracted and a ColourSpace enum type now exists. + Greyscale, RGB and CIELAB are now handled, though the latter is not + in the official IIP spec. + + +10/03/2003: + - Changed RawTile copy constructor to use memcpy instead of looping + through an array: Big speed improvement :-) + + +08/03/2003: + - Added USR1 and TERM signal handling to main loop: We now have some + stats printed in the logfile on shutdown. + - Modified IIPImage to accept a filename pattern variable, so that + the "_pyr_" image sequence pattern can be user modified. + - Plus started work on a new tile cache system, but seems very slow, + so will mothball it till after the forthcoming release. + + +10/11/2002: + - Changes to some header files etc to make it compatible with gcc 3.2: + Mainly STL string specifiers, plus replacement of slist type + with std::list. + + +24/03/2002 + - Changed error handling to follow IIP return code specification + for unsupported objects and commands. Should do this for + each individual exception also. + - Added runtime configuration variable for max image cache size. + + +18/03/2002: Version 0.9.2 release. + - Changes to JPEGCompressor.cc: Fixed bug when encoding very small + tiles. Sometimes the JPEG data is larger than the original + so we need to allocate some extra memory just in case. + - Also fixed the iip_empty_output_buffer( j_compress_ptr cinfo ) + function. Now properly empties the buffer and returns TRUE. + - The Compress() routine now passes the entire image buffer array + into jpeg_write_scanlines rather than doing it row by + row. The row array is dynamically allocated and deleted + at the end. + - Added proper copy constructor to RawTile class to properly copy + data without leaving dangling pointers. + + +09/08/2001: + - Added time stamp. + - Some minor changes to the JPEG wrapper - a couple of ints + changed to size_t's and a conditional added just before + the memcopy code. + + +07/07/2001: Version 0.9.1 release. + - Added field for number of bands in Rawtile.h, so that we can now + view 1-band black and white as well as 3-band colour images + - Added missing JTL command handler for single non-sequential images + This does the same as JTLS command, but supplies 0 for sequence + and angle. + + +05/03/2001: Version 0.9 release. + - Bug fixes: moving IIPImage objects in the cache was resulting + in lost information. + - DSOImage memory bug. Modules should handle their own cleanup + in close_image, which is now called by the ~DSOImage + + +04/03/2001: + - Changed ModuleLoader to a DSOImage derived class of IIPImage. + - Use a STL map of image type to module path keywords instead + of trying to store caches of DSOImages. + - Clean up and rationalisation of IIPImage class and derived + classes. + + +01/03/2001: + - Added tokenizer class. + - Now checks for variables passed to fcgi at start up time + via --initial-env directive within Apache. + - Added basic ModuleLoader class for loading external image decoders. + - Fixes so that it no longer crashes even with null input query etc. + - Removed ifdef DEBUG stuff. + + +27/02/2001: + - Added Tile-size directive and related IIPImage::getTileWidth() etc. + - Allowing for various tile sizes to be used :) + - Improved logfile reporting. diff --git a/iipsrv/INSTALL b/iipsrv/INSTALL new file mode 100644 index 0000000..8b82ade --- /dev/null +++ b/iipsrv/INSTALL @@ -0,0 +1,291 @@ +Installation Instructions +************************* + +Copyright (C) 1994, 1995, 1996, 1999, 2000, 2001, 2002, 2004, 2005, +2006, 2007, 2008 Free Software Foundation, Inc. + + This file is free documentation; the Free Software Foundation gives +unlimited permission to copy, distribute and modify it. + +Basic Installation +================== + + Briefly, the shell commands `./configure; make; make install' should +configure, build, and install this package. The following +more-detailed instructions are generic; see the `README' file for +instructions specific to this package. + + 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, and a +file `config.log' containing compiler output (useful mainly for +debugging `configure'). + + It can also use an optional file (typically called `config.cache' +and enabled with `--cache-file=config.cache' or simply `-C') that saves +the results of its tests to speed up reconfiguring. Caching is +disabled by default to prevent problems with accidental use of stale +cache files. + + 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 you are using the cache, and at +some point `config.cache' contains results you don't want to keep, you +may remove or edit it. + + The file `configure.ac' (or `configure.in') is used to create +`configure' by a program called `autoconf'. You need `configure.ac' 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. + + Running `configure' might take a while. 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. + + 6. Often, you can also type `make uninstall' to remove the installed + files again. + +Compilers and Options +===================== + + Some systems require unusual options for compilation or linking that +the `configure' script does not know about. Run `./configure --help' +for details on some of the pertinent environment variables. + + You can give `configure' initial values for configuration parameters +by setting variables in the command line or in the environment. Here +is an example: + + ./configure CC=c99 CFLAGS=-g LIBS=-lposix + + *Note Defining Variables::, for more details. + +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 can use 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 `..'. + + With a non-GNU `make', it is safer 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. + + On MacOS X 10.5 and later systems, you can create libraries and +executables that work on multiple system types--known as "fat" or +"universal" binaries--by specifying multiple `-arch' options to the +compiler but only a single `-arch' option to the preprocessor. Like +this: + + ./configure CC="gcc -arch i386 -arch x86_64 -arch ppc -arch ppc64" \ + CXX="g++ -arch i386 -arch x86_64 -arch ppc -arch ppc64" \ + CPP="gcc -E" CXXCPP="g++ -E" + + This is not guaranteed to produce working output in all cases, you +may have to build one architecture at a time and combine the results +using the `lipo' tool if you have problems. + +Installation Names +================== + + By default, `make install' installs the package's commands under +`/usr/local/bin', include files under `/usr/local/include', etc. You +can specify an installation prefix other than `/usr/local' by giving +`configure' the option `--prefix=PREFIX'. + + You can specify separate installation prefixes for +architecture-specific files and architecture-independent files. If you +pass the option `--exec-prefix=PREFIX' to `configure', the package uses +PREFIX as the prefix for installing programs and libraries. +Documentation and other data files still use the regular prefix. + + In addition, if you use an unusual directory layout you can give +options like `--bindir=DIR' 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. + +Particular systems +================== + + On HP-UX, the default C compiler is not ANSI C compatible. If GNU +CC is not installed, it is recommended to use the following options in +order to use an ANSI C compiler: + + ./configure CC="cc -Ae" + +and if that doesn't work, install pre-built binaries of GCC for HP-UX. + + On OSF/1 a.k.a. Tru64, some versions of the default C compiler cannot +parse its `' header file. The option `-nodtk' can be used as +a workaround. If GNU CC is not installed, it is therefore recommended +to try + + ./configure CC="cc" + +and if that doesn't work, try + + ./configure CC="cc -nodtk" + +Specifying the System Type +========================== + + There may be some features `configure' cannot figure out +automatically, but needs to determine by the type of machine the package +will run on. Usually, assuming the package is built to be run on the +_same_ architectures, `configure' can figure that out, but if it prints +a message saying it cannot guess the machine type, give it the +`--build=TYPE' option. TYPE can either be a short name for the system +type, such as `sun4', or a canonical name which has the form: + + CPU-COMPANY-SYSTEM + +where SYSTEM can have one of these forms: + + OS KERNEL-OS + + 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 machine type. + + If you are _building_ compiler tools for cross-compiling, you should +use the option `--target=TYPE' to select the type of system they will +produce code for. + + If you want to _use_ a cross compiler, that generates code for a +platform different from the build platform, you should specify the +"host" platform (i.e., that on which the generated programs will +eventually be run) with `--host=TYPE'. + +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. + +Defining Variables +================== + + Variables not defined in a site shell script can be set in the +environment passed to `configure'. However, some packages may run +configure again during the build, and the customized values of these +variables may be lost. In order to avoid this problem, you should set +them in the `configure' command line, using `VAR=value'. For example: + + ./configure CC=/usr/local2/bin/gcc + +causes the specified `gcc' to be used as the C compiler (unless it is +overridden in the site shell script). + +Unfortunately, this technique does not work for `CONFIG_SHELL' due to +an Autoconf bug. Until the bug is fixed you can use this workaround: + + CONFIG_SHELL=/bin/bash /bin/bash ./configure CONFIG_SHELL=/bin/bash + +`configure' Invocation +====================== + + `configure' recognizes the following options to control how it +operates. + +`--help' +`-h' + Print a summary of all of the options to `configure', and exit. + +`--help=short' +`--help=recursive' + Print a summary of the options unique to this package's + `configure', and exit. The `short' variant lists options used + only in the top level, while the `recursive' variant lists options + also present in any nested packages. + +`--version' +`-V' + Print the version of Autoconf used to generate the `configure' + script, and exit. + +`--cache-file=FILE' + Enable the cache: use and save the results of the tests in FILE, + traditionally `config.cache'. FILE defaults to `/dev/null' to + disable caching. + +`--config-cache' +`-C' + Alias for `--cache-file=config.cache'. + +`--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. + +`--prefix=DIR' + Use DIR as the installation prefix. *Note Installation Names:: + for more details, including other options available for fine-tuning + the installation locations. + +`--no-create' +`-n' + Run the configure checks, but stop before creating any output + files. + +`configure' also accepts some other, not widely useful, options. Run +`configure --help' for more details. + diff --git a/iipsrv/Makefile.am b/iipsrv/Makefile.am new file mode 100644 index 0000000..2c1d030 --- /dev/null +++ b/iipsrv/Makefile.am @@ -0,0 +1,6 @@ +AUTOMAKE_OPTIONS = dist-bzip2 +ACLOCAL_AMFLAGS = -I m4 + +SUBDIRS = fcgi src man + +EXTRA_DIST = TODO COPYING.FCGI doc windows diff --git a/iipsrv/NEWS b/iipsrv/NEWS new file mode 100644 index 0000000..5edd533 --- /dev/null +++ b/iipsrv/NEWS @@ -0,0 +1 @@ +See http://iipimage.sourceforge.net/blog for the latest IIPImage news diff --git a/iipsrv/README b/iipsrv/README new file mode 100644 index 0000000..99a1417 --- /dev/null +++ b/iipsrv/README @@ -0,0 +1,406 @@ +IIPImage - High Resolution Streaming Image Server +================================================= + +[![Build Status](https://travis-ci.org/ruven/iipsrv.svg)](https://travis-ci.org/ruven/iipsrv) + +ABOUT +----- +IIPImage is an advanced high-performance feature-rich image server system for web-based streamed viewing and zooming of ultra high-resolution +images. It is designed to be fast and bandwidth-efficient with low processor and memory requirements. The system can comfortably handle gigapixel size images as +well as advanced image features such as 8, 16 and 32 bits per channel, CIELAB colorimetric images and scientific imagery such as multispectral images, image sequences and 3D surface topologies. + + +FEATURES +-------- +* Fast lightweight embeddable FastCGI server module +* High performance with inbuilt configurable cache +* Support for gigapixel images +* Dynamic JPEG export of whole or regions of images at any resolution +* Supports IIP, Zoomify, DeepZoom and IIIF protocols +* 8, 16 and 32 bit image support +* CIELAB support with automatic CIELAB->sRGB colour space conversion +* JPEG2000 support +* Multispectral image support +* Dynamic watermarking +* Memcached support +* 3D panoramic views +* Dynamic hillshading of 3D surface topologies +* Dynamic decoder module capability + + + +DOCUMENTATION +------------- +Detailed class descriptions (generated using doxygen) are available in the +doc subdirectory + + + +LICENCE +------- +iipsrv is released under the GNU General Public License (GPL). See the copyright +notice COPYING in this directory for licensing details or go to +http://www.gnu.org/licenses/gpl.html for more details. + +If you use IIPImage on a public site and remove the IIP link logo from the +client, you must provide a link on your site back to the IIPImage site - +http://iipimage.sf.net + +This distribution includes version 2.4.0 of the FCGI development libraries. +See COPYING.FCGI for licensing information for these libraries. + + + +REQUIREMENTS +------------ +Requirements: libtiff, zlib and the IJG JPEG development libraries. +Optional: libmemcached (for Memcached) and Kakadu (for JPEG2000) + +Plus, of course, an fcgi-enabled web server. The server has been successfully +tested on the following servers: +- Apache (http://httpd.apache.org), +- Lighttpd (http://www.lighttpd.net) +- IIS (http://www.iis.net) +- NginX (http://www.nginx.org) +- MyServer (http://www.myserverproject.net) +- Java Application Servers (Tomcat, JBoss) + +Example server configurations are shown below. + + + +BUILDING +-------- +The standard autoconf build process should work fine. If you want to allow +dynamic loading of 3rd party image decoders, use the configure option +--enable-modules. There is a version of the FCGI development library included +in this distribution. The configure script will use this bundled version +unless it detects one already installed. Alternatively, you may specify the +path using --with-fcgi-incl= and --with-fcgi-lib=. + +If this is an SVN or Git development version, first generate the autoconfigure +environment using autogen.sh: + + ./autogen.sh + +Otherwise for release versions, use configure directly: + + ./configure + make + + +OPTIONAL LIBRARIES: MEMCACHED +----------------------------- +IIPImage is able to use Memcached (http://www.memcached.org), a high-performance, +distributed memory object caching system. If enabled, IIPImage will cache +results using Memcached, giving IIPImage added speed and scalability. To use +this, you will need to install the library (and development files) of +libmemcached (http://libmemcached.org). This will be automatically detected +during the build process. + + + +OPTIONAL LIBRARIES: KAKADU +-------------------------- +IIPImage is able to decode JPEG2000 images via the Kakadu SDK +(http://www.kakadusoftware.com). This is, however, not open source and will +need to purchase a license for the source code. In order to use, first build +the Kakadu SDK as per the instructions supplied with the SDK. Then, the +following parameters to the ./configure command + + --with-kakadu=/path/to/kakadu/distribution + + + +INSTALLATION +------------ +Simply copy the executable called iipsrv.fcgi in the src subdirectory into +the web server fcgi directory. If one does not exist, simply create one, called, +for example, fcgi-bin. The web server will need to be configured to use this +executable. + + + +CONFIGURATION +------------- +There are several startup variables that can be passed to the server. +They are all optional. + +LOGFILE: the server will log its output to the file specified, if it can. + +VERBOSITY: 0 means no logging, 1 is minimal logging, 2 lots of debugging stuff, +3 even more debugging stuff and 10 a very large amount indeed ;-) + +MAX_IMAGE_CACHE_SIZE: Max image cache size to be held in RAM in MB. This is +a cache of the compressed JPEG image tiles requested by the client. +The default is 10MB. + +FILESYSTEM_PREFIX: This is a prefix automatically added by the server to the +beginning of each file system path. This can be useful for security reasons to +limit access to certain sub-directories. For example, with a prefix of +"/home/images/" set on the server, a request by a client for "image.tif" will +point to the path "/home/images/image.tif". Any reverse directory path +component such as ../ is also filtered out. No default value. + +JPEG_QUALITY: The default JPEG quality factor for compression when the +client does not specify one . The value should be between 1 (highest level of +compression) and 100 (highest image quality). The default is 75. + +MAX_CVT: Limits the maximum image dimensions in pixels (the WID or HEI +commands) allowable for dynamic JPEG export via the CVT command. This +prevents huge requests from overloading the server. The default is 5000. + +MAX_LAYERS: The maximum number of quality layers to decode for images that support +progressive quality encoding, such as JPEG2000. Ignored for other file +formats. If not set, half of the available quality layers will be decoded by default. +If set to -1, all the available layers will be decoded by default. + +FILENAME_PATTERN: Pattern that follows the name stem for a 3D or multispectral +sequence. eg: "_pyr_" for FZ1_pyr_000_090.tif. The default is "_pyr_". This is +only relevent to 3D image sequences. + +WATERMARK: TIFF image to use as watermark file. This image should be not be +bigger the tile size used for TIFF tiling. If bigger, it will simply be +cropped to the tile size. If smaller, the watermark will be positioned +randomly within the available space. The image can be either colour or +grayscale. + +WATERMARK_PROBABILITY: The probability that a particilar tile will have a watermark +applied to it. 0 means never, 1 means always. + +WATERMARK_OPACITY: The opacity (between 0 and 1) applied to the watermark image. + +MEMCACHED_SERVERS: A comma-delimitted list of memcached servers with optional +port numbers. For example: localhost,192.168.0.1:8888,192.168.0.2. + +MEMCACHED_TIMEOUT: Time in seconds that cache remains fresh. +Default is 86400 seconds (24 hours). + +INTERPOLATION: Interpolation method to use for rescaling when using image export. +Integer value. 0 for fastest nearest neighbour interpolation. 1 for bilinear +interpolation (better quality but about 2.5x slower). Bilinear by default. + +CORS: Cross Origin Resource Sharing setting. Disabled by default. +Set to * to enable for all domains or specify a single domain. +See http://www.w3.org/TR/cors/ for more details on CORS. + +BASE_URL: Set a base URL for use in certain protocol requests if web server rewriting +has taken place and the public URL is not the same as that supplied to iipsrv. + +DECODER_MODULES: Comma separated list of external modules for decoding +other image formats. This is only necessary if you have activated +--enable-modules for ./configure and written your own image format +handler(s). + + + + +IMAGE PATHS +----------- +The images paths given to the server via the FIF variable must be +absolute paths on the server machine (eg. FIF=/images/test.tif) +and not paths relative to the web server document root location. +Images do not, therefore, need to be directly accessible by the +client via the web server. Make sure the server process owner is +able to access and read the images! + + + +EXAMPLE SERVER CONFIGURATIONS +----------------------------- + +### Apache and mod_fastcgi + +httpd.conf example extract: + +``` +-------------------------------------------------------------------- +# Create a directory for the iipsrv binary +ScriptAlias /fcgi-bin/ "/usr/local/httpd/fcgi-bin/" + +# Set the options on that directory + + AllowOverride None + Options None + +# Syntax for access is different in Apache 2.4 - uncomment appropriate version +# Apache 2.2 +# Order allow,deny +# Allow from all + +# Apache 2.4 + Require all granted + + + +# Set the module handler +AddHandler fastcgi-script fcg fcgi fpl + +# Initialise some variables for the FCGI server +FastCgiServer /usr/local/httpd/fcgi-bin/iipsrv.fcgi \ +-initial-env LOGFILE=/tmp/iipsrv.log \ +-initial-env VERBOSITY=2 \ +-initial-env MAX_IMAGE_CACHE_SIZE=10 \ +-initial-env FILENAME_PATTERN=_pyr_ \ +-initial-env JPEG_QUALITY=50 \ +-initial-env MAX_CVT=3000 +-------------------------------------------------------------------- +``` + + + +### Apache and mod_fcgid + +mod_fcgid is a binary compatible replacement for mod_fastcgi. It works in the +same way, but is configured differently. Load the module like this: + + + LoadModule fcgid_module /path/to/apachemodules/mod_fcgid.so + + +Here is an example configuration. Note that mod_fcgid does not have a +FastCgiServer directive and there is no need to explicitly start the server: + +``` +------------------------------------------------------------------- +# Create a directory for the iipsrv binary +ScriptAlias /fcgi-bin/ "/var/www/localhost/fcgi-bin/" + +# Set the options on that directory + + AllowOverride None + Options None + +# Syntax for access is different in Apache 2.4 - uncomment appropriate version +# Apache 2.2 +# Order allow,deny +# Allow from all + +# Apache 2.4 + Require all granted + + # Set the module handler + AddHandler fcgid-script .fcgi + + +# Set our environment variables for the IIP server +FcgidInitialEnv VERBOSITY "5" +FcgidInitialEnv LOGFILE "/tmp/iipsrv.log" +FcgidInitialEnv MAX_IMAGE_CACHE_SIZE "10" +FcgidInitialEnv JPEG_QUALITY "50" +FcgidInitialEnv MAX_CVT "3000" + +# Define the idle timeout as unlimited and the number of +# processes we want +FcgidIdleTimeout 0 +FcgidMaxProcessesPerClass 1 + +------------------------------------------------------------------- +``` + +Note that on CentOS, FcgidIPCDir is configured by default to +/var/log/httpd/fcgidsock, which may not be writable by Apache. If this is the case, +specify another location for FcgidIPCDir, which is writable, such as /tmp/fcgidsock + + +### Lighttpd +lighttpd.conf example extract: + +``` +-------------------------------------------------------------------- +fastcgi.server = ( "/fcgi-bin/iipsrv.fcgi" => + (( "host" => "127.0.0.1", + "port" => 9000, + "check-local" => "disable", + "min-procs" => 1, + "max-procs" => 1, + "bin-path" => "/var/www/localhost/fcgi-bin/iipsrv.fcgi", + "bin-environment" => ( + "LOGFILE" => "/tmp/iipsrv.log", + "VERBOSITY" => "5", + "MAX_IMAGE_CACHE_SIZE" => "10", + "FILENAME_PATTERN" => "_pyr_", + "JPEG_QUALITY" => "50", + "MAX_CVT" => "3000" + ) + )) +) +-------------------------------------------------------------------- +``` + + +### spawn-fcgi + +iipsrv can also be used with lighttpd's spawn-fcgi without the need for a +full web server. Simply spawn the iipsrv process on the command line. The +process can be bound to an IP address and port for backend load-balancing +configurations. For example: + + spawn-fcgi -f src/iipsrv.fcgi -a 192.168.0.1 -p 9000 + + +### MyServer: +Simply run the MyServer configuration and in the MIME section, choose the .fcgi extension +and select: +``` +-------------------------------------------------------------------- +MIME Type: application octet-stream +Action: Execute self contained FastCGI +Manager: NONE +-------------------------------------------------------------------- +``` + + +### Java Application Servers (Tomcat, Jetty, JBoss etc) + +IIPImage can also be used with Java Application Servers such as Apache Tomcat, JBoss and Jetty. Simply add +the JFastCGI jar file to your webapp and add the following to your web.xml configuration file in order to +re-route FCGI requests to the IIPImage server on the specified port. + +``` + + + + fcgi + net.jr.fastcgi.FastCGIServlet + > + server-address + 127.0.0.1:6667 + + + + + fcgi + /cgi-bin/iipsrv.fcgi + +``` + +You then need to start an instance of the server on the requested port (6667 in this example) using +spawn-cgi (see spawn-cgi section above) or on the command line (see below). + + +### Command Line + +It is also possible to start iipsrv directly on the command line using the --bind parameter. +For example: + + iipsrv.fcgi --bind 192.168.0.1:9000 + +where the argument given to bind is the socket on which to listen to FCGI +requests. Note that these are *not* HTTP requests and iipsrv will still require a web server front-end. +Your web server should, therefore, be configured to use this address for FastCGI. +For example with lighttpd: + + fastcgi.server = ( + "/fcgi-bin/iipsrv.fcgi" => ( + ("host"=>"192.168.0.1", "port"=>9000, "check-local"=>"disable") + ) + ) + + + +--------------------------------------------------------------------------- +Please refer to the project site http://iipimage.sf.net for further details + +--------------------------------------------------------------------------- +(c) 2000-2014 Ruven Pillay diff --git a/iipsrv/README.md b/iipsrv/README.md new file mode 120000 index 0000000..100b938 --- /dev/null +++ b/iipsrv/README.md @@ -0,0 +1 @@ +README \ No newline at end of file diff --git a/iipsrv/TODO b/iipsrv/TODO new file mode 100644 index 0000000..029c9da --- /dev/null +++ b/iipsrv/TODO @@ -0,0 +1,13 @@ +TODO: + +* Multiprocess capabilty using either: + - threads + - multiple instances using shared memory to share a cache + - Asynchronous via asio or libevent +* ICC profile integration via lcms library +* Lossless Rotation / transposition support for JPEG tiles +* JPEG source image support +* Look into using malloc_usable_size to trace real allocated space +* Lanczos, bilinear etc interpolation for CVT +* Copy EXIF, IPTC data for CVT exports +* Rewrite JPEG writer code for better buffered output diff --git a/iipsrv/acinclude.m4 b/iipsrv/acinclude.m4 new file mode 100644 index 0000000..5784df3 --- /dev/null +++ b/iipsrv/acinclude.m4 @@ -0,0 +1,851 @@ +dnl $Id: acinclude.m4,v 1.2 2001/12/21 03:12:50 robs Exp $ + +AC_DEFUN([FCGI_COMMON_CHECKS], [ + AC_CHECK_TYPE([ssize_t], [int]) + + AC_MSG_CHECKING([for sun_len in sys/un.h]) + AC_EGREP_HEADER([sun_len], [sys/un.h], + [AC_MSG_RESULT([yes]) + AC_DEFINE([HAVE_SOCKADDR_UN_SUN_LEN], [1], + [Define if sockaddr_un in sys/un.h contains a sun_len component])], + AC_MSG_RESULT([no])) + + AC_MSG_CHECKING([for fpos_t in stdio.h]) + AC_EGREP_HEADER([fpos_t], [stdio.h], + [AC_MSG_RESULT([yes]) + AC_DEFINE([HAVE_FPOS], [1], + [Define if the fpos_t typedef is in stdio.h])], + AC_MSG_RESULT([no])) + + AC_CHECK_HEADERS([sys/socket.h netdb.h netinet/in.h arpa/inet.h]) + AC_CHECK_HEADERS([sys/time.h limits.h sys/param.h unistd.h]) + + AC_MSG_CHECKING([for a fileno() prototype in stdio.h]) + AC_EGREP_HEADER([fileno], [stdio.h], + [AC_MSG_RESULT([yes]) + AC_DEFINE([HAVE_FILENO_PROTO], [1], + [Define if there's a fileno() prototype in stdio.h])], + AC_MSG_RESULT([no])) + + if test "$HAVE_SYS_SOCKET_H"; then + AC_MSG_CHECKING([for socklen_t in sys/socket.h]) + AC_EGREP_HEADER([socklen_t], [sys/socket.h], + [AC_MSG_RESULT([yes]) + AC_DEFINE([HAVE_SOCKLEN], [1], + [Define if the socklen_t typedef is in sys/socket.h])], + AC_MSG_RESULT([no])) + fi + + #-------------------------------------------------------------------- + # Do we need cross-process locking on this platform? + #-------------------------------------------------------------------- + AC_MSG_CHECKING([whether cross-process locking is required by accept()]) + case "`uname -sr`" in + IRIX\ 5.* | SunOS\ 5.* | UNIX_System_V\ 4.0) + AC_MSG_RESULT([yes]) + AC_DEFINE([USE_LOCKING], [1], + [Define if cross-process locking is required by accept()]) + ;; + *) + AC_MSG_RESULT([no]) + ;; + esac + + #-------------------------------------------------------------------- + # Does va_arg(arg, long double) crash the compiler? + # hpux 9.04 compiler does and so does Stratus FTX (uses HP's compiler) + #-------------------------------------------------------------------- + AC_MSG_CHECKING([whether va_arg(arg, long double) crashes the compiler]) + AC_TRY_COMPILE([#include ], + [long double lDblArg; va_list arg; lDblArg = va_arg(arg, long double);], + AC_MSG_RESULT([no]), + [AC_MSG_RESULT([yes]) + AC_DEFINE([HAVE_VA_ARG_LONG_DOUBLE_BUG], [1], + [Define if va_arg(arg, long double) crashes the compiler])]) + + AC_C_CONST +]) + + +dnl @synopsis ACX_PTHREAD([ACTION-IF-FOUND[, ACTION-IF-NOT-FOUND]]) +dnl +dnl This macro figures out how to build C programs using POSIX +dnl threads. It sets the PTHREAD_LIBS output variable to the threads +dnl library and linker flags, and the PTHREAD_CFLAGS output variable +dnl to any special C compiler flags that are needed. (The user can also +dnl force certain compiler flags/libs to be tested by setting these +dnl environment variables.) +dnl +dnl Also sets PTHREAD_CC to any special C compiler that is needed for +dnl multi-threaded programs (defaults to the value of CC otherwise). +dnl (This is necessary on AIX to use the special cc_r compiler alias.) +dnl +dnl If you are only building threads programs, you may wish to +dnl use these variables in your default LIBS, CFLAGS, and CC: +dnl +dnl LIBS="$PTHREAD_LIBS $LIBS" +dnl CFLAGS="$CFLAGS $PTHREAD_CFLAGS" +dnl CC="$PTHREAD_CC" +dnl +dnl In addition, if the PTHREAD_CREATE_JOINABLE thread-attribute +dnl constant has a nonstandard name, defines PTHREAD_CREATE_JOINABLE +dnl to that name (e.g. PTHREAD_CREATE_UNDETACHED on AIX). +dnl +dnl ACTION-IF-FOUND is a list of shell commands to run if a threads +dnl library is found, and ACTION-IF-NOT-FOUND is a list of commands +dnl to run it if it is not found. If ACTION-IF-FOUND is not specified, +dnl the default action will define HAVE_PTHREAD. +dnl +dnl Please let the authors know if this macro fails on any platform, +dnl or if you have any other suggestions or comments. This macro was +dnl based on work by SGJ on autoconf scripts for FFTW (www.fftw.org) +dnl (with help from M. Frigo), as well as ac_pthread and hb_pthread +dnl macros posted by AFC to the autoconf macro repository. We are also +dnl grateful for the helpful feedback of numerous users. +dnl +dnl @version $Id: acinclude.m4,v 1.2 2001/12/21 03:12:50 robs Exp $ +dnl @author Steven G. Johnson and Alejandro Forero Cuervo + +AC_DEFUN([ACX_PTHREAD], [ +AC_REQUIRE([AC_CANONICAL_HOST]) +acx_pthread_ok=no + +# First, check if the POSIX threads header, pthread.h, is available. +# If it isn't, don't bother looking for the threads libraries. +AC_CHECK_HEADER(pthread.h, , acx_pthread_ok=noheader) + +# We must check for the threads library under a number of different +# names; the ordering is very important because some systems +# (e.g. DEC) have both -lpthread and -lpthreads, where one of the +# libraries is broken (non-POSIX). + +# First of all, check if the user has set any of the PTHREAD_LIBS, +# etcetera environment variables, and if threads linking works using +# them: +if test x"$PTHREAD_LIBS$PTHREAD_CFLAGS" != x; then + save_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS $PTHREAD_CFLAGS" + save_LIBS="$LIBS" + LIBS="$PTHREAD_LIBS $LIBS" + AC_MSG_CHECKING([for pthread_join in LIBS=$PTHREAD_LIBS with CFLAGS=$PTHREAD_CFLAGS]) + AC_TRY_LINK_FUNC(pthread_join, acx_pthread_ok=yes) + AC_MSG_RESULT($acx_pthread_ok) + if test x"$acx_pthread_ok" = xno; then + PTHREAD_LIBS="" + PTHREAD_CFLAGS="" + fi + LIBS="$save_LIBS" + CFLAGS="$save_CFLAGS" +fi + +# Create a list of thread flags to try. Items starting with a "-" are +# C compiler flags, and other items are library names, except for "none" +# which indicates that we try without any flags at all. + +acx_pthread_flags="pthreads none -Kthread -kthread lthread -pthread -pthreads -mthreads pthread --thread-safe -mt" + +# The ordering *is* (sometimes) important. Some notes on the +# individual items follow: + +# pthreads: AIX (must check this before -lpthread) +# none: in case threads are in libc; should be tried before -Kthread and +# other compiler flags to prevent continual compiler warnings +# -Kthread: Sequent (threads in libc, but -Kthread needed for pthread.h) +# -kthread: FreeBSD kernel threads (preferred to -pthread since SMP-able) +# lthread: LinuxThreads port on FreeBSD (also preferred to -pthread) +# -pthread: Linux/gcc (kernel threads), BSD/gcc (userland threads) +# -pthreads: Solaris/gcc +# -mthreads: Mingw32/gcc, Lynx/gcc +# -mt: Sun Workshop C (may only link SunOS threads [-lthread], but it +# doesn't hurt to check since this sometimes defines pthreads too; +# also defines -D_REENTRANT) +# pthread: Linux, etcetera +# --thread-safe: KAI C++ + +case "${host_cpu}-${host_os}" in + *solaris*) + + # On Solaris (at least, for some versions), libc contains stubbed + # (non-functional) versions of the pthreads routines, so link-based + # tests will erroneously succeed. (We need to link with -pthread or + # -lpthread.) (The stubs are missing pthread_cleanup_push, or rather + # a function called by this macro, so we could check for that, but + # who knows whether they'll stub that too in a future libc.) So, + # we'll just look for -pthreads and -lpthread first: + + acx_pthread_flags="-pthread -pthreads pthread -mt $acx_pthread_flags" + ;; +esac + +if test x"$acx_pthread_ok" = xno; then +for flag in $acx_pthread_flags; do + + case $flag in + none) + AC_MSG_CHECKING([whether pthreads work without any flags]) + ;; + + -*) + AC_MSG_CHECKING([whether pthreads work with $flag]) + PTHREAD_CFLAGS="$flag" + ;; + + *) + AC_MSG_CHECKING([for the pthreads library -l$flag]) + PTHREAD_LIBS="-l$flag" + ;; + esac + + save_LIBS="$LIBS" + save_CFLAGS="$CFLAGS" + LIBS="$PTHREAD_LIBS $LIBS" + CFLAGS="$CFLAGS $PTHREAD_CFLAGS" + + # Check for various functions. We must include pthread.h, + # since some functions may be macros. (On the Sequent, we + # need a special flag -Kthread to make this header compile.) + # We check for pthread_join because it is in -lpthread on IRIX + # while pthread_create is in libc. We check for pthread_attr_init + # due to DEC craziness with -lpthreads. We check for + # pthread_cleanup_push because it is one of the few pthread + # functions on Solaris that doesn't have a non-functional libc stub. + # We try pthread_create on general principles. + AC_TRY_LINK([#include ], + [pthread_t th; pthread_join(th, 0); + pthread_attr_init(0); pthread_cleanup_push(0, 0); + pthread_create(0,0,0,0); pthread_cleanup_pop(0); ], + [acx_pthread_ok=yes]) + + LIBS="$save_LIBS" + CFLAGS="$save_CFLAGS" + + AC_MSG_RESULT($acx_pthread_ok) + if test "x$acx_pthread_ok" = xyes; then + break; + fi + + PTHREAD_LIBS="" + PTHREAD_CFLAGS="" +done +fi + +# Various other checks: +if test "x$acx_pthread_ok" = xyes; then + save_LIBS="$LIBS" + LIBS="$PTHREAD_LIBS $LIBS" + save_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS $PTHREAD_CFLAGS" + + # Detect AIX lossage: threads are created detached by default + # and the JOINABLE attribute has a nonstandard name (UNDETACHED). + AC_MSG_CHECKING([for joinable pthread attribute]) + AC_TRY_LINK([#include ], + [int attr=PTHREAD_CREATE_JOINABLE;], + ok=PTHREAD_CREATE_JOINABLE, ok=unknown) + if test x"$ok" = xunknown; then + AC_TRY_LINK([#include ], + [int attr=PTHREAD_CREATE_UNDETACHED;], + ok=PTHREAD_CREATE_UNDETACHED, ok=unknown) + fi + if test x"$ok" != xPTHREAD_CREATE_JOINABLE; then + AC_DEFINE(PTHREAD_CREATE_JOINABLE, $ok, + [Define to the necessary symbol if this constant + uses a non-standard name on your system.]) + fi + AC_MSG_RESULT(${ok}) + if test x"$ok" = xunknown; then + AC_MSG_WARN([we do not know how to create joinable pthreads]) + fi + + AC_MSG_CHECKING([if more special flags are required for pthreads]) + flag=no + case "${host_cpu}-${host_os}" in + *-aix* | *-freebsd*) flag="-D_THREAD_SAFE";; + *solaris* | alpha*-osf*) flag="-D_REENTRANT";; + esac + AC_MSG_RESULT(${flag}) + if test "x$flag" != xno; then + PTHREAD_CFLAGS="$flag $PTHREAD_CFLAGS" + fi + + LIBS="$save_LIBS" + CFLAGS="$save_CFLAGS" + + # More AIX lossage: must compile with cc_r + AC_CHECK_PROG(PTHREAD_CC, cc_r, cc_r, ${CC}) +else + PTHREAD_CC="$CC" +fi + +AC_SUBST(PTHREAD_LIBS) +AC_SUBST(PTHREAD_CFLAGS) +AC_SUBST(PTHREAD_CC) + +# Finally, execute ACTION-IF-FOUND/ACTION-IF-NOT-FOUND: +if test x"$acx_pthread_ok" = xyes; then + ifelse([$1],,AC_DEFINE(HAVE_PTHREAD,1,[Define if you have POSIX threads libraries and header files.]),[$1]) + : +else + acx_pthread_ok=no + $2 +fi + +])dnl ACX_PTHREAD + + + +dnl @synopsis AC_PROG_CC_WARNINGS([ANSI]) +dnl +dnl Enables a reasonable set of warnings for the C compiler. Optionally, +dnl if the first argument is nonempty, turns on flags which enforce and/or +dnl enable proper ANSI C if such flags are known to the compiler used. +dnl +dnl Currently this macro knows about GCC, Solaris C compiler, +dnl Digital Unix C compiler, C for AIX Compiler, HP-UX C compiler, +dnl and IRIX C compiler. +dnl +dnl @version $Id: acinclude.m4,v 1.2 2001/12/21 03:12:50 robs Exp $ +dnl @author Ville Laurikari +dnl +AC_DEFUN([AC_PROG_CC_WARNINGS], [ + ansi=$1 + if test -z "$ansi"; then + msg="for C compiler warning flags" + else + msg="for C compiler warning and ANSI conformance flags" + fi + AC_CACHE_CHECK($msg, ac_cv_prog_cc_warnings, [ + if test -n "$CC"; then + cat > conftest.c <&1 | grep "Xc.*strict ANSI C" > /dev/null 2>&1 && + $CC -c -v -Xc conftest.c > /dev/null 2>&1 && + test -f conftest.o; then + if test -z "$ansi"; then + ac_cv_prog_cc_warnings="-v" + else + ac_cv_prog_cc_warnings="-v -Xc" + fi + + dnl HP-UX C compiler + elif $CC > /dev/null 2>&1 && + $CC -c -Aa +w1 conftest.c > /dev/null 2>&1 && + test -f conftest.o; then + if test -z "$ansi"; then + ac_cv_prog_cc_warnings="+w1" + else + ac_cv_prog_cc_warnings="+w1 -Aa" + fi + + dnl Digital Unix C compiler + elif ! $CC > /dev/null 2>&1 && + $CC -c -verbose -w0 -warnprotos -std1 conftest.c > /dev/null 2>&1 && + test -f conftest.o; then + if test -z "$ansi"; then + ac_cv_prog_cc_warnings="-verbose -w0 -warnprotos" + else + ac_cv_prog_cc_warnings="-verbose -w0 -warnprotos -std1" + fi + + dnl C for AIX Compiler + elif $CC > /dev/null 2>&1 | grep AIX > /dev/null 2>&1 && + $CC -c -qlanglvl=ansi -qinfo=all conftest.c > /dev/null 2>&1 && + test -f conftest.o; then + if test -z "$ansi"; then + ac_cv_prog_cc_warnings="-qsrcmsg -qinfo=all:noppt:noppc:noobs:nocnd" + else + ac_cv_prog_cc_warnings="-qsrcmsg -qinfo=all:noppt:noppc:noobs:nocnd -qlanglvl=ansi" + fi + + dnl IRIX C compiler + elif $CC -fullwarn -ansi -ansiE > /dev/null 2>&1 && + test -f conftest.o; then + if test -z "$ansi"; then + ac_cv_prog_cc_warnings="-fullwarn" + else + ac_cv_prog_cc_warnings="-fullwarn -ansi -ansiE" + fi + + fi + rm -f conftest.* + fi + if test -n "$ac_cv_prog_cc_warnings"; then + CFLAGS="$CFLAGS $ac_cv_prog_cc_warnings" + else + ac_cv_prog_cc_warnings="unknown" + fi + ]) +]) + + + + +dnl From vips acinclude.m4 +dnl +dnl FIND_TIFF[ACTION-IF-FOUND[, ACTION-IF-NOT-FOUND]] +dnl ------------------------------------------------ +dnl +dnl Find TIFF libraries and headers +dnl +dnl Put compile stuff in TIFF_INCLUDES +dnl Put link stuff in TIFF_LIBS +dnl +dnl Default ACTION-IF-FOUND defines HAVE_TIFF +dnl +AC_DEFUN([FIND_TIFF], [ + +TIFF_INCLUDES="" +TIFF_LIBS="" + +dnl AC_ARG_WITH(tiff, +dnl [ --without-tiff do not use libtiff]) + +# Treat --without-tiff like --without-tiff-includes --without-tiff-libraries. +if test "$with_tiff" = "no"; then + TIFF_INCLUDES=no + TIFF_LIBS=no +fi + +AC_ARG_WITH(tiff-includes, +[ --with-tiff-includes=DIR TIFF include files are in DIR], +TIFF_INCLUDES="-I$withval") +AC_ARG_WITH(tiff-libraries, +[ --with-tiff-libraries=DIR TIFF libraries are in DIR], +TIFF_LIBS="-L$withval -ltiff") + +AC_MSG_CHECKING(for TIFF) + +# Look for tiff.h +if test "$TIFF_INCLUDES" = ""; then + # Check the standard search path + AC_TRY_COMPILE([#include ],[int a;],[ + TIFF_INCLUDES="" + ], [ + # tiff.h is not in the standard search path. + + # A whole bunch of guesses + for dir in \ + "${prefix}"/*/include /usr/*/include \ + /usr/local/*/include "${prefix}"/include/* \ + /usr/include/* /usr/local/include/* /*/include; do + if test -f "$dir/tiff.h"; then + TIFF_INCLUDES="-I$dir" + break + fi + done + + if test "$TIFF_INCLUDES" = ""; then + TIFF_INCLUDES=no + fi + ]) +fi + +# Now for the libraries +if test "$TIFF_LIBS" = ""; then + tiff_save_LIBS="$LIBS" + tiff_save_INCLUDES="$INCLUDES" + + LIBS="-ltiff -lm $LIBS" + INCLUDES="$TIFF_INCLUDES $INCLUDES" + + # Try the standard search path first + AC_TRY_LINK([#include ],[TIFFGetVersion();], [ + TIFF_LIBS="-ltiff" + ], [ + # libtiff is not in the standard search path. + + # A whole bunch of guesses + for dir in \ + "${prefix}"/*/lib /usr/*/lib /usr/local/*/lib \ + "${prefix}"/lib/* /usr/lib/* \ + /usr/local/lib/* /*/lib; do + if test -d "$dir" && test "`ls $dir/libtiff.* 2> /dev/null`" != ""; then + TIFF_LIBS="-L$dir -ltiff" + break + fi + done + + if test "$TIFF_LIBS" = ""; then + TIFF_LIBS=no + fi + ]) + + LIBS="$tiff_save_LIBS" + INCLUDES="$tiff_save_INCLUDES" +fi + +AC_SUBST(TIFF_LIBS) +AC_SUBST(TIFF_INCLUDES) + +# Print a helpful message +tiff_libraries_result="$TIFF_LIBS" +tiff_includes_result="$TIFF_INCLUDES" + +if test x"$tiff_libraries_result" = x""; then + tiff_libraries_result="in default path" +fi +if test x"$tiff_includes_result" = x""; then + tiff_includes_result="in default path" +fi + +if test "$tiff_libraries_result" = "no"; then + tiff_libraries_result="(none)" +fi +if test "$tiff_includes_result" = "no"; then + tiff_includes_result="(none)" +fi + +AC_MSG_RESULT( + [libraries $tiff_libraries_result, headers $tiff_includes_result]) + +# Finally, execute ACTION-IF-FOUND/ACTION-IF-NOT-FOUND: +if test "$TIFF_INCLUDES" != "no" && test "$TIFF_LIBS" != "no"; then + ifelse([$1],,AC_DEFINE(HAVE_TIFF,1,[Define if you have tiff libraries and header files.]),[$1]) + : +else + TIFF_INCLUDES="" + TIFF_LIBS="" + $2 +fi + +])dnl + +dnl +dnl FIND_JPEG[ACTION-IF-FOUND[, ACTION-IF-NOT-FOUND]] +dnl ------------------------------------------------ +dnl +dnl Find JPEG libraries and headers +dnl +dnl Put compile stuff in JPEG_INCLUDES +dnl Put link stuff in JPEG_LIBS +dnl +dnl Default ACTION-IF-FOUND defines HAVE_JPEG +dnl +AC_DEFUN([FIND_JPEG], [ + +JPEG_INCLUDES="" +JPEG_LIBS="" + +dnl AC_ARG_WITH(jpeg, +dnl [ --without-jpeg do not use libjpeg]) +# Treat --without-jpeg like --without-jpeg-includes --without-jpeg-libraries. +if test "$with_jpeg" = "no"; then + JPEG_INCLUDES=no + JPEG_LIBS=no +fi + +AC_ARG_WITH(jpeg-includes, +[ --with-jpeg-includes=DIR JPEG include files are in DIR], +JPEG_INCLUDES="-I$withval") +AC_ARG_WITH(jpeg-libraries, +[ --with-jpeg-libraries=DIR JPEG libraries are in DIR], +JPEG_LIBS="-L$withval -ljpeg") + +AC_MSG_CHECKING(for JPEG) + +# Look for jpeg.h +if test "$JPEG_INCLUDES" = ""; then + jpeg_save_LIBS="$LIBS" + + LIBS="-ljpeg $LIBS" + + # Check the standard search path + AC_TRY_COMPILE([ + #include + #include ],[int a],[ + JPEG_INCLUDES="" + ], [ + # jpeg.h is not in the standard search path. + + # A whole bunch of guesses + for dir in \ + "${prefix}"/*/include \ + /usr/local/include \ + /usr/*/include \ + /usr/local/*/include /usr/*/include \ + "${prefix}"/include/* \ + /usr/include/* /usr/local/include/* /*/include; do + if test -f "$dir/jpeglib.h"; then + JPEG_INCLUDES="-I$dir" + break + fi + done + + if test "$JPEG_INCLUDES" = ""; then + JPEG_INCLUDES=no + fi + ]) + + LIBS="$jpeg_save_LIBS" +fi + +# Now for the libraries +if test "$JPEG_LIBS" = ""; then + jpeg_save_LIBS="$LIBS" + jpeg_save_INCLUDES="$INCLUDES" + + LIBS="-ljpeg $LIBS" + INCLUDES="$JPEG_INCLUDES $INCLUDES" + + # Try the standard search path first + AC_TRY_LINK([ + #include + #include ],[jpeg_abort((void*)0)], [ + JPEG_LIBS="-ljpeg" + ], [ + # libjpeg is not in the standard search path. + + # A whole bunch of guesses + for dir in \ + "${prefix}"/*/lib \ + /usr/local/lib \ + /usr/*/lib \ + "${prefix}"/lib/* /usr/lib/* \ + /usr/local/lib/* /*/lib; do + if test -d "$dir" && test "`ls $dir/libjpeg.* 2> /dev/null`" != ""; then + JPEG_LIBS="-L$dir -ljpeg" + break + fi + done + + if test "$JPEG_LIBS" = ""; then + JPEG_LIBS=no + fi + ]) + + LIBS="$jpeg_save_LIBS" + INCLUDES="$jpeg_save_INCLUDES" +fi + +AC_SUBST(JPEG_LIBS) +AC_SUBST(JPEG_INCLUDES) + +# Print a helpful message +jpeg_libraries_result="$JPEG_LIBS" +jpeg_includes_result="$JPEG_INCLUDES" + +if test x"$jpeg_libraries_result" = x""; then + jpeg_libraries_result="in default path" +fi +if test x"$jpeg_includes_result" = x""; then + jpeg_includes_result="in default path" +fi + +if test "$jpeg_libraries_result" = "no"; then + jpeg_libraries_result="(none)" +fi +if test "$jpeg_includes_result" = "no"; then + jpeg_includes_result="(none)" +fi + +AC_MSG_RESULT( + [libraries $jpeg_libraries_result, headers $jpeg_includes_result]) + +# Finally, execute ACTION-IF-FOUND/ACTION-IF-NOT-FOUND: +if test "$JPEG_INCLUDES" != "no" && test "$JPEG_LIBS" != "no"; then + ifelse([$1],,AC_DEFINE(HAVE_JPEG,1,[Define if you have jpeg libraries and header files.]),[$1]) + : +else + JPEG_INCLUDES="" + JPEG_LIBS="" + $2 +fi + +]) +dnl + + +# AC_HEADER_TR1_UNORDERED_MAP +AC_DEFUN([AC_HEADER_TR1_UNORDERED_MAP], [ + AC_CACHE_CHECK(for tr1/unordered_map, + ac_cv_cxx_tr1_unordered_map, + [AC_LANG_SAVE + AC_LANG_CPLUSPLUS + AC_TRY_COMPILE([#include ], [using std::tr1::unordered_map;], + ac_cv_cxx_tr1_unordered_map=yes, ac_cv_cxx_tr1_unordered_map=no) + AC_LANG_RESTORE + ]) + if test "$ac_cv_cxx_tr1_unordered_map" = yes; then + AC_DEFINE(HAVE_TR1_UNORDERED_MAP,,[Define if tr1/unordered_map is present. ]) + fi +]) + + +# AC_COMPILE_STDCXX_OX +AC_DEFUN([AC_COMPILE_STDCXX_0X], [ + AC_CACHE_CHECK(if g++ supports C++0x features without additional flags, + ac_cv_cxx_compile_cxx0x_native, + [AC_LANG_SAVE + AC_LANG_CPLUSPLUS + AC_TRY_COMPILE([ + template + struct check + { + static_assert(sizeof(int) <= sizeof(T), "not big enough"); + }; + + typedef check> right_angle_brackets; + + int a; + decltype(a) b; + + typedef check check_type; + check_type c; + check_type&& cr = c;],, + ac_cv_cxx_compile_cxx0x_native=yes, ac_cv_cxx_compile_cxx0x_native=no) + AC_LANG_RESTORE + ]) + + AC_CACHE_CHECK(if g++ supports C++0x features with -std=c++0x, + ac_cv_cxx_compile_cxx0x_cxx, + [AC_LANG_SAVE + AC_LANG_CPLUSPLUS + ac_save_CXXFLAGS="$CXXFLAGS" + CXXFLAGS="$CXXFLAGS -std=c++0x" + AC_TRY_COMPILE([ + template + struct check + { + static_assert(sizeof(int) <= sizeof(T), "not big enough"); + }; + + typedef check> right_angle_brackets; + + int a; + decltype(a) b; + + typedef check check_type; + check_type c; + check_type&& cr = c;],, + ac_cv_cxx_compile_cxx0x_cxx=yes, ac_cv_cxx_compile_cxx0x_cxx=no) + CXXFLAGS="$ac_save_CXXFLAGS" + AC_LANG_RESTORE + ]) + + AC_CACHE_CHECK(if g++ supports C++0x features with -std=gnu++0x, + ac_cv_cxx_compile_cxx0x_gxx, + [AC_LANG_SAVE + AC_LANG_CPLUSPLUS + ac_save_CXXFLAGS="$CXXFLAGS" + CXXFLAGS="$CXXFLAGS -std=gnu++0x" + AC_TRY_COMPILE([ + template + struct check + { + static_assert(sizeof(int) <= sizeof(T), "not big enough"); + }; + + typedef check> right_angle_brackets; + + int a; + decltype(a) b; + + typedef check check_type; + check_type c; + check_type&& cr = c;],, + ac_cv_cxx_compile_cxx0x_gxx=yes, ac_cv_cxx_compile_cxx0x_gxx=no) + CXXFLAGS="$ac_save_CXXFLAGS" + AC_LANG_RESTORE + ]) + + if test "$ac_cv_cxx_compile_cxx0x_native" = yes || + test "$ac_cv_cxx_compile_cxx0x_cxx" = yes || + test "$ac_cv_cxx_compile_cxx0x_gxx" = yes; then + AC_DEFINE(HAVE_STDCXX_0X,,[Define if g++ supports C++0x features. ]) + fi +]) + + +AU_ALIAS([AC_CXX_HEADER_UNORDERED_MAP], [AX_CXX_HEADER_UNORDERED_MAP]) +AC_DEFUN([AX_CXX_HEADER_UNORDERED_MAP], [ + AC_CACHE_CHECK(for unordered_map, + ax_cv_cxx_unordered_map, + [AC_REQUIRE([AC_COMPILE_STDCXX_0X]) + AC_LANG_SAVE + AC_LANG_CPLUSPLUS + ac_save_CXXFLAGS="$CXXFLAGS" + CXXFLAGS="$CXXFLAGS -std=gnu++0x" + AC_TRY_COMPILE([#include ], [using std::unordered_map;], + ax_cv_cxx_unordered_map=yes, ax_cv_cxx_unordered_map=no) + CXXFLAGS="$ac_save_CXXFLAGS" + AC_LANG_RESTORE + ]) + if test "$ax_cv_cxx_unordered_map" = yes; then + AC_DEFINE(HAVE_UNORDERED_MAP,,[Define if unordered_map is present. ]) + AC_SUBST([AM_CXXFLAGS], [-std=gnu++0x]) + fi +]) + + +AU_ALIAS([AC_CXX_NAMESPACES], [AX_CXX_NAMESPACES]) +AC_DEFUN([AX_CXX_NAMESPACES], +[AC_CACHE_CHECK(whether the compiler implements namespaces, +ax_cv_cxx_namespaces, +[AC_LANG_PUSH([C++]) + AC_COMPILE_IFELSE([AC_LANG_SOURCE([namespace Outer { namespace Inner { int i = 0; }} + using namespace Outer::Inner; int foo(void) { return i;} ])], + ax_cv_cxx_namespaces=yes, ax_cv_cxx_namespaces=no) + AC_LANG_POP +]) +if test "$ax_cv_cxx_namespaces" = yes; then + AC_DEFINE(HAVE_NAMESPACES,,[define if the compiler implements namespaces]) +fi +]) + + +AU_ALIAS([AC_CXX_HAVE_EXT_HASH_MAP], [AX_CXX_HAVE_EXT_HASH_MAP]) +AC_DEFUN([AX_CXX_HAVE_EXT_HASH_MAP], +[AC_CACHE_CHECK(whether the compiler has ext/hash_map, +ax_cv_cxx_have_ext_hash_map, +[AC_REQUIRE([AX_CXX_NAMESPACES]) + AC_LANG_SAVE + AC_LANG_CPLUSPLUS + AC_TRY_COMPILE([#include +#ifdef HAVE_NAMESPACES +using namespace __gnu_cxx; +#endif],[hash_map t; return 0;], + ax_cv_cxx_have_ext_hash_map=yes, ax_cv_cxx_have_ext_hash_map=no) + AC_LANG_RESTORE +]) +if test "$ax_cv_cxx_have_ext_hash_map" = yes; then + AC_DEFINE(HAVE_EXT_HASH_MAP,,[define if the compiler has ext/hash_map]) +fi +]) + + +dnl @synopsis AX_CXX_HAVE_ISFINITE +dnl +dnl If isfinite() is available to the C++ compiler: +dnl define HAVE_ISFINITE +dnl add "-lm" to LIBS +dnl +AC_DEFUN([AX_CXX_HAVE_ISFINITE], +[ax_cxx_have_isfinite_save_LIBS=$LIBS +LIBS="$LIBS -lm" +AC_CACHE_CHECK(for isfinite, ax_cv_cxx_have_isfinite, +[AC_LANG_SAVE +AC_LANG_CPLUSPLUS +AC_LINK_IFELSE( +[AC_LANG_PROGRAM( +[[#include ]], +[[int f = isfinite( 3 );]])], +[ax_cv_cxx_have_isfinite=yes], +[ax_cv_cxx_have_isfinite=no]) +AC_LANG_RESTORE]) +if test "$ax_cv_cxx_have_isfinite" = yes; then +AC_DEFINE([HAVE_ISFINITE],1,[define if compiler has isfinite]) +else +LIBS=$ax_cxx_have_isfinite_save_LIBS +fi +]) diff --git a/iipsrv/autogen.sh b/iipsrv/autogen.sh new file mode 100755 index 0000000..5bce9ba --- /dev/null +++ b/iipsrv/autogen.sh @@ -0,0 +1,1578 @@ +#!/bin/sh +# a u t o g e n . s h +# +# Copyright (c) 2005-2009 United States Government as represented by +# the U.S. Army Research Laboratory. +# +# 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 ``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. +# +### +# +# Script for automatically preparing the sources for compilation by +# performing the myriad of necessary steps. The script attempts to +# detect proper version support, and outputs warnings about particular +# systems that have autotool peculiarities. +# +# Basically, if everything is set up and installed correctly, the +# script will validate that minimum versions of the GNU Build System +# tools are installed, account for several common configuration +# issues, and then simply run autoreconf for you. +# +# If autoreconf fails, which can happen for many valid configurations, +# this script proceeds to run manual preparation steps effectively +# providing a POSIX shell script (mostly complete) reimplementation of +# autoreconf. +# +# The AUTORECONF, AUTOCONF, AUTOMAKE, LIBTOOLIZE, ACLOCAL, AUTOHEADER +# environment variables and corresponding _OPTIONS variables (e.g. +# AUTORECONF_OPTIONS) may be used to override the default automatic +# detection behaviors. Similarly the _VERSION variables will override +# the minimum required version numbers. +# +# Examples: +# +# To obtain help on usage: +# ./autogen.sh --help +# +# To obtain verbose output: +# ./autogen.sh --verbose +# +# To skip autoreconf and prepare manually: +# AUTORECONF=false ./autogen.sh +# +# To verbosely try running with an older (unsupported) autoconf: +# AUTOCONF_VERSION=2.50 ./autogen.sh --verbose +# +# Author: +# Christopher Sean Morrison +# +# Patches: +# Sebastian Pipping +# +###################################################################### + +# set to minimum acceptable version of autoconf +if [ "x$AUTOCONF_VERSION" = "x" ] ; then + AUTOCONF_VERSION=2.52 +fi +# set to minimum acceptable version of automake +if [ "x$AUTOMAKE_VERSION" = "x" ] ; then + AUTOMAKE_VERSION=1.6.0 +fi +# set to minimum acceptable version of libtool +if [ "x$LIBTOOL_VERSION" = "x" ] ; then + LIBTOOL_VERSION=1.4.2 +fi + + +################## +# ident function # +################## +ident ( ) { + # extract copyright from header + __copyright="`grep Copyright $AUTOGEN_SH | head -${HEAD_N}1 | awk '{print $4}'`" + if [ "x$__copyright" = "x" ] ; then + __copyright="`date +%Y`" + fi + + # extract version from CVS Id string + __id="$Id: autogen.sh 33925 2009-03-01 23:27:06Z brlcad $" + __version="`echo $__id | sed 's/.*\([0-9][0-9][0-9][0-9]\)[-\/]\([0-9][0-9]\)[-\/]\([0-9][0-9]\).*/\1\2\3/'`" + if [ "x$__version" = "x" ] ; then + __version="" + fi + + echo "autogen.sh build preparation script by Christopher Sean Morrison" + echo " + config.guess download patch by Sebastian Pipping (2008-12-03)" + echo "revised 3-clause BSD-style license, copyright (c) $__copyright" + echo "script version $__version, ISO/IEC 9945 POSIX shell script" +} + + +################## +# USAGE FUNCTION # +################## +usage ( ) { + echo "Usage: $AUTOGEN_SH [-h|--help] [-v|--verbose] [-q|--quiet] [-d|--download] [--version]" + echo " --help Help on $NAME_OF_AUTOGEN usage" + echo " --verbose Verbose progress output" + echo " --quiet Quiet suppressed progress output" + echo " --download Download the latest config.guess from gnulib" + echo " --version Only perform GNU Build System version checks" + echo + echo "Description: This script will validate that minimum versions of the" + echo "GNU Build System tools are installed and then run autoreconf for you." + echo "Should autoreconf fail, manual preparation steps will be run" + echo "potentially accounting for several common preparation issues. The" + + echo "AUTORECONF, AUTOCONF, AUTOMAKE, LIBTOOLIZE, ACLOCAL, AUTOHEADER," + echo "PROJECT, & CONFIGURE environment variables and corresponding _OPTIONS" + echo "variables (e.g. AUTORECONF_OPTIONS) may be used to override the" + echo "default automatic detection behavior." + echo + + ident + + return 0 +} + + +########################## +# VERSION_ERROR FUNCTION # +########################## +version_error ( ) { + if [ "x$1" = "x" ] ; then + echo "INTERNAL ERROR: version_error was not provided a version" + exit 1 + fi + if [ "x$2" = "x" ] ; then + echo "INTERNAL ERROR: version_error was not provided an application name" + exit 1 + fi + $ECHO + $ECHO "ERROR: To prepare the ${PROJECT} build system from scratch," + $ECHO " at least version $1 of $2 must be installed." + $ECHO + $ECHO "$NAME_OF_AUTOGEN does not need to be run on the same machine that will" + $ECHO "run configure or make. Either the GNU Autotools will need to be installed" + $ECHO "or upgraded on this system, or $NAME_OF_AUTOGEN must be run on the source" + $ECHO "code on another system and then transferred to here. -- Cheers!" + $ECHO +} + +########################## +# VERSION_CHECK FUNCTION # +########################## +version_check ( ) { + if [ "x$1" = "x" ] ; then + echo "INTERNAL ERROR: version_check was not provided a minimum version" + exit 1 + fi + _min="$1" + if [ "x$2" = "x" ] ; then + echo "INTERNAL ERROR: version check was not provided a comparison version" + exit 1 + fi + _cur="$2" + + # needed to handle versions like 1.10 and 1.4-p6 + _min="`echo ${_min}. | sed 's/[^0-9]/./g' | sed 's/\.\././g'`" + _cur="`echo ${_cur}. | sed 's/[^0-9]/./g' | sed 's/\.\././g'`" + + _min_major="`echo $_min | cut -d. -f1`" + _min_minor="`echo $_min | cut -d. -f2`" + _min_patch="`echo $_min | cut -d. -f3`" + + _cur_major="`echo $_cur | cut -d. -f1`" + _cur_minor="`echo $_cur | cut -d. -f2`" + _cur_patch="`echo $_cur | cut -d. -f3`" + + if [ "x$_min_major" = "x" ] ; then + _min_major=0 + fi + if [ "x$_min_minor" = "x" ] ; then + _min_minor=0 + fi + if [ "x$_min_patch" = "x" ] ; then + _min_patch=0 + fi + if [ "x$_cur_minor" = "x" ] ; then + _cur_major=0 + fi + if [ "x$_cur_minor" = "x" ] ; then + _cur_minor=0 + fi + if [ "x$_cur_patch" = "x" ] ; then + _cur_patch=0 + fi + + $VERBOSE_ECHO "Checking if ${_cur_major}.${_cur_minor}.${_cur_patch} is greater than ${_min_major}.${_min_minor}.${_min_patch}" + + if [ $_min_major -lt $_cur_major ] ; then + return 0 + elif [ $_min_major -eq $_cur_major ] ; then + if [ $_min_minor -lt $_cur_minor ] ; then + return 0 + elif [ $_min_minor -eq $_cur_minor ] ; then + if [ $_min_patch -lt $_cur_patch ] ; then + return 0 + elif [ $_min_patch -eq $_cur_patch ] ; then + return 0 + fi + fi + fi + return 1 +} + + +###################################### +# LOCATE_CONFIGURE_TEMPLATE FUNCTION # +###################################### +locate_configure_template ( ) { + _pwd="`pwd`" + if test -f "./configure.ac" ; then + echo "./configure.ac" + elif test -f "./configure.in" ; then + echo "./configure.in" + elif test -f "$_pwd/configure.ac" ; then + echo "$_pwd/configure.ac" + elif test -f "$_pwd/configure.in" ; then + echo "$_pwd/configure.in" + elif test -f "$PATH_TO_AUTOGEN/configure.ac" ; then + echo "$PATH_TO_AUTOGEN/configure.ac" + elif test -f "$PATH_TO_AUTOGEN/configure.in" ; then + echo "$PATH_TO_AUTOGEN/configure.in" + fi +} + + +################## +# argument check # +################## +ARGS="$*" +PATH_TO_AUTOGEN="`dirname $0`" +NAME_OF_AUTOGEN="`basename $0`" +AUTOGEN_SH="$PATH_TO_AUTOGEN/$NAME_OF_AUTOGEN" + +LIBTOOL_M4="${PATH_TO_AUTOGEN}/misc/libtool.m4" + +if [ "x$HELP" = "x" ] ; then + HELP=no +fi +if [ "x$QUIET" = "x" ] ; then + QUIET=no +fi +if [ "x$VERBOSE" = "x" ] ; then + VERBOSE=no +fi +if [ "x$VERSION_ONLY" = "x" ] ; then + VERSION_ONLY=no +fi +if [ "x$DOWNLOAD" = "x" ] ; then + DOWNLOAD=no +fi +if [ "x$AUTORECONF_OPTIONS" = "x" ] ; then + AUTORECONF_OPTIONS="-i -f" +fi +if [ "x$AUTOCONF_OPTIONS" = "x" ] ; then + AUTOCONF_OPTIONS="-f" +fi +if [ "x$AUTOMAKE_OPTIONS" = "x" ] ; then + AUTOMAKE_OPTIONS="-a -c -f" +fi +ALT_AUTOMAKE_OPTIONS="-a -c" +if [ "x$LIBTOOLIZE_OPTIONS" = "x" ] ; then + LIBTOOLIZE_OPTIONS="--automake -c -f" +fi +ALT_LIBTOOLIZE_OPTIONS="--automake --copy --force" +if [ "x$ACLOCAL_OPTIONS" = "x" ] ; then + ACLOCAL_OPTIONS="" +fi +if [ "x$AUTOHEADER_OPTIONS" = "x" ] ; then + AUTOHEADER_OPTIONS="" +fi +if [ "x$CONFIG_GUESS_URL" = "x" ] ; then + CONFIG_GUESS_URL="http://git.savannah.gnu.org/gitweb/?p=gnulib.git;a=blob_plain;f=build-aux/config.guess;hb=HEAD" +fi +for arg in $ARGS ; do + case "x$arg" in + x--help) HELP=yes ;; + x-[hH]) HELP=yes ;; + x--quiet) QUIET=yes ;; + x-[qQ]) QUIET=yes ;; + x--verbose) VERBOSE=yes ;; + x-[dD]) DOWNLOAD=yes ;; + x--download) DOWNLOAD=yes ;; + x-[vV]) VERBOSE=yes ;; + x--version) VERSION_ONLY=yes ;; + *) + echo "Unknown option: $arg" + echo + usage + exit 1 + ;; + esac +done + + +##################### +# environment check # +##################### + +# sanity check before recursions potentially begin +if [ ! -f "$AUTOGEN_SH" ] ; then + echo "INTERNAL ERROR: $AUTOGEN_SH does not exist" + if [ ! "x$0" = "x$AUTOGEN_SH" ] ; then + echo "INTERNAL ERROR: dirname/basename inconsistency: $0 != $AUTOGEN_SH" + fi + exit 1 +fi + +# force locale setting to C so things like date output as expected +LC_ALL=C + +# commands that this script expects +for __cmd in echo head tail pwd ; do + echo "test" | $__cmd > /dev/null 2>&1 + if [ $? != 0 ] ; then + echo "INTERNAL ERROR: '${__cmd}' command is required" + exit 2 + fi +done +echo "test" | grep "test" > /dev/null 2>&1 +if test ! x$? = x0 ; then + echo "INTERNAL ERROR: grep command is required" + exit 1 +fi +echo "test" | sed "s/test/test/" > /dev/null 2>&1 +if test ! x$? = x0 ; then + echo "INTERNAL ERROR: sed command is required" + exit 1 +fi + + +# determine the behavior of echo +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 + +# determine the behavior of head +case "x`echo 'head' | head -n 1 2>&1`" in + *xhead*) HEAD_N="n " ;; + *) HEAD_N="" ;; +esac + +# determine the behavior of tail +case "x`echo 'tail' | tail -n 1 2>&1`" in + *xtail*) TAIL_N="n " ;; + *) TAIL_N="" ;; +esac + +VERBOSE_ECHO=: +ECHO=: +if [ "x$QUIET" = "xyes" ] ; then + if [ "x$VERBOSE" = "xyes" ] ; then + echo "Verbose output quelled by quiet option. Further output disabled." + fi +else + ECHO=echo + if [ "x$VERBOSE" = "xyes" ] ; then + echo "Verbose output enabled" + VERBOSE_ECHO=echo + fi +fi + + +# allow a recursive run to disable further recursions +if [ "x$RUN_RECURSIVE" = "x" ] ; then + RUN_RECURSIVE=yes +fi + + +################################################ +# check for help arg and bypass version checks # +################################################ +if [ "x`echo $ARGS | sed 's/.*[hH][eE][lL][pP].*/help/'`" = "xhelp" ] ; then + HELP=yes +fi +if [ "x$HELP" = "xyes" ] ; then + usage + $ECHO "---" + $ECHO "Help was requested. No preparation or configuration will be performed." + exit 0 +fi + + +####################### +# set up signal traps # +####################### +untrap_abnormal ( ) { + for sig in 1 2 13 15; do + trap - $sig + done +} + +# do this cleanup whenever we exit. +trap ' + # start from the root + if test -d "$START_PATH" ; then + cd "$START_PATH" + fi + + # restore/delete backup files + if test "x$PFC_INIT" = "x1" ; then + recursive_restore + fi +' 0 + +# trap SIGHUP (1), SIGINT (2), SIGPIPE (13), SIGTERM (15) +for sig in 1 2 13 15; do + trap ' + $ECHO "" + $ECHO "Aborting $NAME_OF_AUTOGEN: caught signal '$sig'" + + # start from the root + if test -d "$START_PATH" ; then + cd "$START_PATH" + fi + + # clean up on abnormal exit + $VERBOSE_ECHO "rm -rf autom4te.cache" + rm -rf autom4te.cache + + if test -f "acinclude.m4.$$.backup" ; then + $VERBOSE_ECHO "cat acinclude.m4.$$.backup > acinclude.m4" + chmod u+w acinclude.m4 + cat acinclude.m4.$$.backup > acinclude.m4 + + $VERBOSE_ECHO "rm -f acinclude.m4.$$.backup" + rm -f acinclude.m4.$$.backup + fi + + { (exit 1); exit 1; } +' $sig +done + + +############################# +# look for a configure file # +############################# +if [ "x$CONFIGURE" = "x" ] ; then + CONFIGURE="`locate_configure_template`" + if [ ! "x$CONFIGURE" = "x" ] ; then + $VERBOSE_ECHO "Found a configure template: $CONFIGURE" + fi +else + $ECHO "Using CONFIGURE environment variable override: $CONFIGURE" +fi +if [ "x$CONFIGURE" = "x" ] ; then + if [ "x$VERSION_ONLY" = "xyes" ] ; then + CONFIGURE=/dev/null + else + $ECHO + $ECHO "A configure.ac or configure.in file could not be located implying" + $ECHO "that the GNU Build System is at least not used in this directory. In" + $ECHO "any case, there is nothing to do here without one of those files." + $ECHO + $ECHO "ERROR: No configure.in or configure.ac file found in `pwd`" + exit 1 + fi +fi + +#################### +# get project name # +#################### +if [ "x$PROJECT" = "x" ] ; then + PROJECT="`grep AC_INIT $CONFIGURE | grep -v '.*#.*AC_INIT' | tail -${TAIL_N}1 | sed 's/^[ ]*AC_INIT(\([^,)]*\).*/\1/' | sed 's/.*\[\(.*\)\].*/\1/'`" + if [ "x$PROJECT" = "xAC_INIT" ] ; then + # projects might be using the older/deprecated arg-less AC_INIT .. look for AM_INIT_AUTOMAKE instead + PROJECT="`grep AM_INIT_AUTOMAKE $CONFIGURE | grep -v '.*#.*AM_INIT_AUTOMAKE' | tail -${TAIL_N}1 | sed 's/^[ ]*AM_INIT_AUTOMAKE(\([^,)]*\).*/\1/' | sed 's/.*\[\(.*\)\].*/\1/'`" + fi + if [ "x$PROJECT" = "xAM_INIT_AUTOMAKE" ] ; then + PROJECT="project" + fi + if [ "x$PROJECT" = "x" ] ; then + PROJECT="project" + fi +else + $ECHO "Using PROJECT environment variable override: $PROJECT" +fi +$ECHO "Preparing the $PROJECT build system...please wait" +$ECHO + + +######################## +# check for autoreconf # +######################## +HAVE_AUTORECONF=no +if [ "x$AUTORECONF" = "x" ] ; then + for AUTORECONF in autoreconf ; do + $VERBOSE_ECHO "Checking autoreconf version: $AUTORECONF --version" + $AUTORECONF --version > /dev/null 2>&1 + if [ $? = 0 ] ; then + HAVE_AUTORECONF=yes + break + fi + done +else + HAVE_AUTORECONF=yes + $ECHO "Using AUTORECONF environment variable override: $AUTORECONF" +fi + + +########################## +# autoconf version check # +########################## +_acfound=no +if [ "x$AUTOCONF" = "x" ] ; then + for AUTOCONF in autoconf ; do + $VERBOSE_ECHO "Checking autoconf version: $AUTOCONF --version" + $AUTOCONF --version > /dev/null 2>&1 + if [ $? = 0 ] ; then + _acfound=yes + break + fi + done +else + _acfound=yes + $ECHO "Using AUTOCONF environment variable override: $AUTOCONF" +fi + +_report_error=no +if [ ! "x$_acfound" = "xyes" ] ; then + $ECHO "ERROR: Unable to locate GNU Autoconf." + _report_error=yes +else + _version="`$AUTOCONF --version | head -${HEAD_N}1 | sed 's/[^0-9]*\([0-9\.][0-9\.]*\)/\1/'`" + if [ "x$_version" = "x" ] ; then + _version="0.0.0" + fi + $ECHO "Found GNU Autoconf version $_version" + version_check "$AUTOCONF_VERSION" "$_version" + if [ $? -ne 0 ] ; then + _report_error=yes + fi +fi +if [ "x$_report_error" = "xyes" ] ; then + version_error "$AUTOCONF_VERSION" "GNU Autoconf" + exit 1 +fi + + +########################## +# automake version check # +########################## +_amfound=no +if [ "x$AUTOMAKE" = "x" ] ; then + for AUTOMAKE in automake ; do + $VERBOSE_ECHO "Checking automake version: $AUTOMAKE --version" + $AUTOMAKE --version > /dev/null 2>&1 + if [ $? = 0 ] ; then + _amfound=yes + break + fi + done +else + _amfound=yes + $ECHO "Using AUTOMAKE environment variable override: $AUTOMAKE" +fi + + +_report_error=no +if [ ! "x$_amfound" = "xyes" ] ; then + $ECHO + $ECHO "ERROR: Unable to locate GNU Automake." + _report_error=yes +else + _version="`$AUTOMAKE --version | head -${HEAD_N}1 | sed 's/[^0-9]*\([0-9\.][0-9\.]*\)/\1/'`" + if [ "x$_version" = "x" ] ; then + _version="0.0.0" + fi + $ECHO "Found GNU Automake version $_version" + version_check "$AUTOMAKE_VERSION" "$_version" + if [ $? -ne 0 ] ; then + _report_error=yes + fi +fi +if [ "x$_report_error" = "xyes" ] ; then + version_error "$AUTOMAKE_VERSION" "GNU Automake" + exit 1 +fi + + +######################## +# check for libtoolize # +######################## +HAVE_LIBTOOLIZE=yes +HAVE_ALT_LIBTOOLIZE=no +_ltfound=no +if [ "x$LIBTOOLIZE" = "x" ] ; then + LIBTOOLIZE=libtoolize + $VERBOSE_ECHO "Checking libtoolize version: $LIBTOOLIZE --version" + $LIBTOOLIZE --version > /dev/null 2>&1 + if [ ! $? = 0 ] ; then + HAVE_LIBTOOLIZE=no + $ECHO + if [ "x$HAVE_AUTORECONF" = "xno" ] ; then + $ECHO "Warning: libtoolize does not appear to be available." + else + $ECHO "Warning: libtoolize does not appear to be available. This means that" + $ECHO "the automatic build preparation via autoreconf will probably not work." + $ECHO "Preparing the build by running each step individually, however, should" + $ECHO "work and will be done automatically for you if autoreconf fails." + fi + + # look for some alternates + for tool in glibtoolize libtoolize15 libtoolize14 libtoolize13 ; do + $VERBOSE_ECHO "Checking libtoolize alternate: $tool --version" + _glibtoolize="`$tool --version > /dev/null 2>&1`" + if [ $? = 0 ] ; then + $VERBOSE_ECHO "Found $tool --version" + _glti="`which $tool`" + if [ "x$_glti" = "x" ] ; then + $VERBOSE_ECHO "Cannot find $tool with which" + continue; + fi + if test ! -f "$_glti" ; then + $VERBOSE_ECHO "Cannot use $tool, $_glti is not a file" + continue; + fi + _gltidir="`dirname $_glti`" + if [ "x$_gltidir" = "x" ] ; then + $VERBOSE_ECHO "Cannot find $tool path with dirname of $_glti" + continue; + fi + if test ! -d "$_gltidir" ; then + $VERBOSE_ECHO "Cannot use $tool, $_gltidir is not a directory" + continue; + fi + HAVE_ALT_LIBTOOLIZE=yes + LIBTOOLIZE="$tool" + $ECHO + $ECHO "Fortunately, $tool was found which means that your system may simply" + $ECHO "have a non-standard or incomplete GNU Autotools install. If you have" + $ECHO "sufficient system access, it may be possible to quell this warning by" + $ECHO "running:" + $ECHO + sudo -V > /dev/null 2>&1 + if [ $? = 0 ] ; then + $ECHO " sudo ln -s $_glti $_gltidir/libtoolize" + $ECHO + else + $ECHO " ln -s $_glti $_gltidir/libtoolize" + $ECHO + $ECHO "Run that as root or with proper permissions to the $_gltidir directory" + $ECHO + fi + _ltfound=yes + break + fi + done + else + _ltfound=yes + fi +else + _ltfound=yes + $ECHO "Using LIBTOOLIZE environment variable override: $LIBTOOLIZE" +fi + + +############################ +# libtoolize version check # +############################ +_report_error=no +if [ ! "x$_ltfound" = "xyes" ] ; then + $ECHO + $ECHO "ERROR: Unable to locate GNU Libtool." + _report_error=yes +else + _version="`$LIBTOOLIZE --version | head -${HEAD_N}1 | sed 's/[^0-9]*\([0-9\.][0-9\.]*\)/\1/'`" + if [ "x$_version" = "x" ] ; then + _version="0.0.0" + fi + $ECHO "Found GNU Libtool version $_version" + version_check "$LIBTOOL_VERSION" "$_version" + if [ $? -ne 0 ] ; then + _report_error=yes + fi +fi +if [ "x$_report_error" = "xyes" ] ; then + version_error "$LIBTOOL_VERSION" "GNU Libtool" + exit 1 +fi + + +##################### +# check for aclocal # +##################### +if [ "x$ACLOCAL" = "x" ] ; then + for ACLOCAL in aclocal ; do + $VERBOSE_ECHO "Checking aclocal version: $ACLOCAL --version" + $ACLOCAL --version > /dev/null 2>&1 + if [ $? = 0 ] ; then + break + fi + done +else + $ECHO "Using ACLOCAL environment variable override: $ACLOCAL" +fi + + +######################## +# check for autoheader # +######################## +if [ "x$AUTOHEADER" = "x" ] ; then + for AUTOHEADER in autoheader ; do + $VERBOSE_ECHO "Checking autoheader version: $AUTOHEADER --version" + $AUTOHEADER --version > /dev/null 2>&1 + if [ $? = 0 ] ; then + break + fi + done +else + $ECHO "Using AUTOHEADER environment variable override: $AUTOHEADER" +fi + + +######################### +# check if version only # +######################### +$VERBOSE_ECHO "Checking whether to only output version information" +if [ "x$VERSION_ONLY" = "xyes" ] ; then + $ECHO + ident + $ECHO "---" + $ECHO "Version requested. No preparation or configuration will be performed." + exit 0 +fi + + +################################# +# PROTECT_FROM_CLOBBER FUNCTION # +################################# +protect_from_clobber ( ) { + PFC_INIT=1 + + # protect COPYING & INSTALL from overwrite by automake. the + # automake force option will (inappropriately) ignore the existing + # contents of a COPYING and/or INSTALL files (depending on the + # version) instead of just forcing *missing* files like it does + # for AUTHORS, NEWS, and README. this is broken but extremely + # prevalent behavior, so we protect against it by keeping a backup + # of the file that can later be restored. + + for file in COPYING INSTALL ; do + if test -f ${file} ; then + if test -f ${file}.$$.protect_from_automake.backup ; then + $VERBOSE_ECHO "Already backed up ${file} in `pwd`" + else + $VERBOSE_ECHO "Backing up ${file} in `pwd`" + $VERBOSE_ECHO "cp -p ${file} ${file}.$$.protect_from_automake.backup" + cp -p ${file} ${file}.$$.protect_from_automake.backup + fi + fi + done +} + + +############################## +# RECURSIVE_PROTECT FUNCTION # +############################## +recursive_protect ( ) { + + # for projects using recursive configure, run the build + # preparation steps for the subdirectories. this function assumes + # START_PATH was set to pwd before recursion begins so that + # relative paths work. + + # git 'r done, protect COPYING and INSTALL from being clobbered + protect_from_clobber + + if test -d autom4te.cache ; then + $VERBOSE_ECHO "Found an autom4te.cache directory, deleting it" + $VERBOSE_ECHO "rm -rf autom4te.cache" + rm -rf autom4te.cache + fi + + # find configure template + _configure="`locate_configure_template`" + if [ "x$_configure" = "x" ] ; then + return + fi + # $VERBOSE_ECHO "Looking for configure template found `pwd`/$_configure" + + # look for subdirs + # $VERBOSE_ECHO "Looking for subdirs in `pwd`" + _det_config_subdirs="`grep AC_CONFIG_SUBDIRS $_configure | grep -v '.*#.*AC_CONFIG_SUBDIRS' | sed 's/^[ ]*AC_CONFIG_SUBDIRS(\(.*\)).*/\1/' | sed 's/.*\[\(.*\)\].*/\1/'`" + CHECK_DIRS="" + for dir in $_det_config_subdirs ; do + if test -d "`pwd`/$dir" ; then + CHECK_DIRS="$CHECK_DIRS \"`pwd`/$dir\"" + fi + done + + # process subdirs + if [ ! "x$CHECK_DIRS" = "x" ] ; then + $VERBOSE_ECHO "Recursively scanning the following directories:" + $VERBOSE_ECHO " $CHECK_DIRS" + for dir in $CHECK_DIRS ; do + $VERBOSE_ECHO "Protecting files from automake in $dir" + cd "$START_PATH" + eval "cd $dir" + + # recursively git 'r done + recursive_protect + done + fi +} # end of recursive_protect + + +############################# +# RESTORE_CLOBBERED FUNCION # +############################# +restore_clobbered ( ) { + + # The automake (and autoreconf by extension) -f/--force-missing + # option may overwrite COPYING and INSTALL even if they do exist. + # Here we restore the files if necessary. + + spacer=no + + for file in COPYING INSTALL ; do + if test -f ${file}.$$.protect_from_automake.backup ; then + if test -f ${file} ; then + # compare entire content, restore if needed + if test "x`cat ${file}`" != "x`cat ${file}.$$.protect_from_automake.backup`" ; then + if test "x$spacer" = "xno" ; then + $VERBOSE_ECHO + spacer=yes + fi + # restore the backup + $VERBOSE_ECHO "Restoring ${file} from backup (automake -f likely clobbered it)" + $VERBOSE_ECHO "rm -f ${file}" + rm -f ${file} + $VERBOSE_ECHO "mv ${file}.$$.protect_from_automake.backup ${file}" + mv ${file}.$$.protect_from_automake.backup ${file} + fi # check contents + elif test -f ${file}.$$.protect_from_automake.backup ; then + $VERBOSE_ECHO "mv ${file}.$$.protect_from_automake.backup ${file}" + mv ${file}.$$.protect_from_automake.backup ${file} + fi # -f ${file} + + # just in case + $VERBOSE_ECHO "rm -f ${file}.$$.protect_from_automake.backup" + rm -f ${file}.$$.protect_from_automake.backup + fi # -f ${file}.$$.protect_from_automake.backup + done + + CONFIGURE="`locate_configure_template`" + if [ "x$CONFIGURE" = "x" ] ; then + return + fi + + _aux_dir="`grep AC_CONFIG_AUX_DIR $CONFIGURE | grep -v '.*#.*AC_CONFIG_AUX_DIR' | tail -${TAIL_N}1 | sed 's/^[ ]*AC_CONFIG_AUX_DIR(\(.*\)).*/\1/' | sed 's/.*\[\(.*\)\].*/\1/'`" + if test ! -d "$_aux_dir" ; then + _aux_dir=. + fi + + for file in config.guess config.sub ltmain.sh ; do + if test -f "${_aux_dir}/${file}" ; then + $VERBOSE_ECHO "rm -f \"${_aux_dir}/${file}.backup\"" + rm -f "${_aux_dir}/${file}.backup" + fi + done +} # end of restore_clobbered + + +############################## +# RECURSIVE_RESTORE FUNCTION # +############################## +recursive_restore ( ) { + + # restore COPYING and INSTALL from backup if they were clobbered + # for each directory recursively. + + # git 'r undone + restore_clobbered + + # find configure template + _configure="`locate_configure_template`" + if [ "x$_configure" = "x" ] ; then + return + fi + + # look for subdirs + _det_config_subdirs="`grep AC_CONFIG_SUBDIRS $_configure | grep -v '.*#.*AC_CONFIG_SUBDIRS' | sed 's/^[ ]*AC_CONFIG_SUBDIRS(\(.*\)).*/\1/' | sed 's/.*\[\(.*\)\].*/\1/'`" + CHECK_DIRS="" + for dir in $_det_config_subdirs ; do + if test -d "`pwd`/$dir" ; then + CHECK_DIRS="$CHECK_DIRS \"`pwd`/$dir\"" + fi + done + + # process subdirs + if [ ! "x$CHECK_DIRS" = "x" ] ; then + $VERBOSE_ECHO "Recursively scanning the following directories:" + $VERBOSE_ECHO " $CHECK_DIRS" + for dir in $CHECK_DIRS ; do + $VERBOSE_ECHO "Checking files for automake damage in $dir" + cd "$START_PATH" + eval "cd $dir" + + # recursively git 'r undone + recursive_restore + done + fi +} # end of recursive_restore + + +####################### +# INITIALIZE FUNCTION # +####################### +initialize ( ) { + + # this routine performs a variety of directory-specific + # initializations. some are sanity checks, some are preventive, + # and some are necessary setup detection. + # + # this function sets: + # CONFIGURE + # SEARCH_DIRS + # CONFIG_SUBDIRS + + ################################## + # check for a configure template # + ################################## + CONFIGURE="`locate_configure_template`" + if [ "x$CONFIGURE" = "x" ] ; then + $ECHO + $ECHO "A configure.ac or configure.in file could not be located implying" + $ECHO "that the GNU Build System is at least not used in this directory. In" + $ECHO "any case, there is nothing to do here without one of those files." + $ECHO + $ECHO "ERROR: No configure.in or configure.ac file found in `pwd`" + exit 1 + fi + + ##################### + # detect an aux dir # + ##################### + _aux_dir="`grep AC_CONFIG_AUX_DIR $CONFIGURE | grep -v '.*#.*AC_CONFIG_AUX_DIR' | tail -${TAIL_N}1 | sed 's/^[ ]*AC_CONFIG_AUX_DIR(\(.*\)).*/\1/' | sed 's/.*\[\(.*\)\].*/\1/'`" + if test ! -d "$_aux_dir" ; then + _aux_dir=. + else + $VERBOSE_ECHO "Detected auxillary directory: $_aux_dir" + fi + + ################################ + # detect a recursive configure # + ################################ + CONFIG_SUBDIRS="" + _det_config_subdirs="`grep AC_CONFIG_SUBDIRS $CONFIGURE | grep -v '.*#.*AC_CONFIG_SUBDIRS' | sed 's/^[ ]*AC_CONFIG_SUBDIRS(\(.*\)).*/\1/' | sed 's/.*\[\(.*\)\].*/\1/'`" + for dir in $_det_config_subdirs ; do + if test -d "`pwd`/$dir" ; then + $VERBOSE_ECHO "Detected recursive configure directory: `pwd`/$dir" + CONFIG_SUBDIRS="$CONFIG_SUBDIRS `pwd`/$dir" + fi + done + + ########################################################### + # make sure certain required files exist for GNU projects # + ########################################################### + _marker_found="" + _marker_found_message_intro='Detected non-GNU marker "' + _marker_found_message_mid='" in ' + for marker in foreign cygnus ; do + _marker_found_message=${_marker_found_message_intro}${marker}${_marker_found_message_mid} + _marker_found="`grep 'AM_INIT_AUTOMAKE.*'${marker} $CONFIGURE`" + if [ ! "x$_marker_found" = "x" ] ; then + $VERBOSE_ECHO "${_marker_found_message}`basename \"$CONFIGURE\"`" + break + fi + if test -f "`dirname \"$CONFIGURE\"/Makefile.am`" ; then + _marker_found="`grep 'AUTOMAKE_OPTIONS.*'${marker} Makefile.am`" + if [ ! "x$_marker_found" = "x" ] ; then + $VERBOSE_ECHO "${_marker_found_message}Makefile.am" + break + fi + fi + done + if [ "x${_marker_found}" = "x" ] ; then + _suggest_foreign=no + for file in AUTHORS COPYING ChangeLog INSTALL NEWS README ; do + if [ ! -f $file ] ; then + $VERBOSE_ECHO "Touching ${file} since it does not exist" + _suggest_foreign=yes + touch $file + fi + done + + if [ "x${_suggest_foreign}" = "xyes" ] ; then + $ECHO + $ECHO "Warning: Several files expected of projects that conform to the GNU" + $ECHO "coding standards were not found. The files were automatically added" + $ECHO "for you since you do not have a 'foreign' declaration specified." + $ECHO + $ECHO "Considered adding 'foreign' to AM_INIT_AUTOMAKE in `basename \"$CONFIGURE\"`" + if test -f "`dirname \"$CONFIGURE\"/Makefile.am`" ; then + $ECHO "or to AUTOMAKE_OPTIONS in your top-level Makefile.am file." + fi + $ECHO + fi + fi + + ################################################## + # make sure certain generated files do not exist # + ################################################## + for file in config.guess config.sub ltmain.sh ; do + if test -f "${_aux_dir}/${file}" ; then + $VERBOSE_ECHO "mv -f \"${_aux_dir}/${file}\" \"${_aux_dir}/${file}.backup\"" + mv -f "${_aux_dir}/${file}" "${_aux_dir}/${file}.backup" + fi + done + + ############################ + # search alternate m4 dirs # + ############################ + SEARCH_DIRS="" + for dir in m4 ; do + if [ -d $dir ] ; then + $VERBOSE_ECHO "Found extra aclocal search directory: $dir" + SEARCH_DIRS="$SEARCH_DIRS -I $dir" + fi + done + + ###################################### + # remove any previous build products # + ###################################### + if test -d autom4te.cache ; then + $VERBOSE_ECHO "Found an autom4te.cache directory, deleting it" + $VERBOSE_ECHO "rm -rf autom4te.cache" + rm -rf autom4te.cache + fi +# tcl/tk (and probably others) have a customized aclocal.m4, so can't delete it +# if test -f aclocal.m4 ; then +# $VERBOSE_ECHO "Found an aclocal.m4 file, deleting it" +# $VERBOSE_ECHO "rm -f aclocal.m4" +# rm -f aclocal.m4 +# fi + +} # end of initialize() + + +############## +# initialize # +############## + +# stash path +START_PATH="`pwd`" + +# Before running autoreconf or manual steps, some prep detection work +# is necessary or useful. Only needs to occur once per directory, but +# does need to traverse the entire subconfigure hierarchy to protect +# files from being clobbered even by autoreconf. +recursive_protect + +# start from where we started +cd "$START_PATH" + +# get ready to process +initialize + + +######################################### +# DOWNLOAD_GNULIB_CONFIG_GUESS FUNCTION # +######################################### + +# TODO - should make sure wget/curl exist and/or work before trying to +# use them. + +download_gnulib_config_guess () { + # abuse gitweb to download gnulib's latest config.guess via HTTP + config_guess_temp="config.guess.$$.download" + ret=1 + for __cmd in wget curl fetch ; do + $VERBOSE_ECHO "Checking for command ${__cmd}" + ${__cmd} --version > /dev/null 2>&1 + ret=$? + if [ ! $ret = 0 ] ; then + continue + fi + + __cmd_version=`${__cmd} --version | head -n 1 | sed -e 's/^[^0-9]\+//' -e 's/ .*//'` + $VERBOSE_ECHO "Found ${__cmd} ${__cmd_version}" + + opts="" + case ${__cmd} in + wget) + opts="-O" + ;; + curl) + opts="-o" + ;; + fetch) + opts="-t 5 -f" + ;; + esac + + $VERBOSE_ECHO "Running $__cmd \"${CONFIG_GUESS_URL}\" $opts \"${config_guess_temp}\"" + eval "$__cmd \"${CONFIG_GUESS_URL}\" $opts \"${config_guess_temp}\"" > /dev/null 2>&1 + if [ $? = 0 ] ; then + mv -f "${config_guess_temp}" ${_aux_dir}/config.guess + ret=0 + break + fi + done + + if [ ! $ret = 0 ] ; then + $ECHO "Warning: config.guess download failed from: $CONFIG_GUESS_URL" + rm -f "${config_guess_temp}" + fi +} + + +############################## +# LIBTOOLIZE_NEEDED FUNCTION # +############################## +libtoolize_needed () { + ret=1 # means no, don't need libtoolize + for feature in AC_PROG_LIBTOOL AM_PROG_LIBTOOL LT_INIT ; do + $VERBOSE_ECHO "Searching for $feature in $CONFIGURE" + found="`grep \"^$feature.*\" $CONFIGURE`" + if [ ! "x$found" = "x" ] ; then + ret=0 # means yes, need to run libtoolize + break + fi + done + return ${ret} +} + + + +############################################ +# prepare build via autoreconf or manually # +############################################ +reconfigure_manually=no +if [ "x$HAVE_AUTORECONF" = "xyes" ] ; then + $ECHO + $ECHO $ECHO_N "Automatically preparing build ... $ECHO_C" + + $VERBOSE_ECHO "$AUTORECONF $SEARCH_DIRS $AUTORECONF_OPTIONS" + autoreconf_output="`$AUTORECONF $SEARCH_DIRS $AUTORECONF_OPTIONS 2>&1`" + ret=$? + $VERBOSE_ECHO "$autoreconf_output" + + if [ ! $ret = 0 ] ; then + if [ "x$HAVE_ALT_LIBTOOLIZE" = "xyes" ] ; then + if [ ! "x`echo \"$autoreconf_output\" | grep libtoolize | grep \"No such file or directory\"`" = "x" ] ; then + $ECHO + $ECHO "Warning: autoreconf failed but due to what is usually a common libtool" + $ECHO "misconfiguration issue. This problem is encountered on systems that" + $ECHO "have installed libtoolize under a different name without providing a" + $ECHO "symbolic link or without setting the LIBTOOLIZE environment variable." + $ECHO + $ECHO "Restarting the preparation steps with LIBTOOLIZE set to $LIBTOOLIZE" + + export LIBTOOLIZE + RUN_RECURSIVE=no + export RUN_RECURSIVE + untrap_abnormal + + $VERBOSE_ECHO sh $AUTOGEN_SH "$1" "$2" "$3" "$4" "$5" "$6" "$7" "$8" "$9" + sh "$AUTOGEN_SH" "$1" "$2" "$3" "$4" "$5" "$6" "$7" "$8" "$9" + exit $? + fi + fi + + $ECHO "Warning: $AUTORECONF failed" + + if test -f ltmain.sh ; then + $ECHO "libtoolize being run by autoreconf is not creating ltmain.sh in the auxillary directory like it should" + fi + + $ECHO "Attempting to run the preparation steps individually" + reconfigure_manually=yes + else + if [ "x$DOWNLOAD" = "xyes" ] ; then + if libtoolize_needed ; then + download_gnulib_config_guess + fi + fi + fi +else + reconfigure_manually=yes +fi + + +############################ +# LIBTOOL_FAILURE FUNCTION # +############################ +libtool_failure ( ) { + + # libtool is rather error-prone in comparison to the other + # autotools and this routine attempts to compensate for some + # common failures. the output after a libtoolize failure is + # parsed for an error related to AC_PROG_LIBTOOL and if found, we + # attempt to inject a project-provided libtool.m4 file. + + _autoconf_output="$1" + + if [ "x$RUN_RECURSIVE" = "xno" ] ; then + # we already tried the libtool.m4, don't try again + return 1 + fi + + if test -f "$LIBTOOL_M4" ; then + found_libtool="`$ECHO $_autoconf_output | grep AC_PROG_LIBTOOL`" + if test ! "x$found_libtool" = "x" ; then + if test -f acinclude.m4 ; then + rm -f acinclude.m4.$$.backup + $VERBOSE_ECHO "cat acinclude.m4 > acinclude.m4.$$.backup" + cat acinclude.m4 > acinclude.m4.$$.backup + fi + $VERBOSE_ECHO "cat \"$LIBTOOL_M4\" >> acinclude.m4" + chmod u+w acinclude.m4 + cat "$LIBTOOL_M4" >> acinclude.m4 + + # don't keep doing this + RUN_RECURSIVE=no + export RUN_RECURSIVE + untrap_abnormal + + $ECHO + $ECHO "Restarting the preparation steps with libtool macros in acinclude.m4" + $VERBOSE_ECHO sh $AUTOGEN_SH "$1" "$2" "$3" "$4" "$5" "$6" "$7" "$8" "$9" + sh "$AUTOGEN_SH" "$1" "$2" "$3" "$4" "$5" "$6" "$7" "$8" "$9" + exit $? + fi + fi +} + + +########################### +# MANUAL_AUTOGEN FUNCTION # +########################### +manual_autogen ( ) { + + ################################################## + # Manual preparation steps taken are as follows: # + # aclocal [-I m4] # + # libtoolize --automake -c -f # + # aclocal [-I m4] # + # autoconf -f # + # autoheader # + # automake -a -c -f # + ################################################## + + ########### + # aclocal # + ########### + $VERBOSE_ECHO "$ACLOCAL $SEARCH_DIRS $ACLOCAL_OPTIONS" + aclocal_output="`$ACLOCAL $SEARCH_DIRS $ACLOCAL_OPTIONS 2>&1`" + ret=$? + $VERBOSE_ECHO "$aclocal_output" + if [ ! $ret = 0 ] ; then $ECHO "ERROR: $ACLOCAL failed" && exit 2 ; fi + + ############## + # libtoolize # + ############## + if libtoolize_needed ; then + if [ "x$HAVE_LIBTOOLIZE" = "xyes" ] ; then + $VERBOSE_ECHO "$LIBTOOLIZE $LIBTOOLIZE_OPTIONS" + libtoolize_output="`$LIBTOOLIZE $LIBTOOLIZE_OPTIONS 2>&1`" + ret=$? + $VERBOSE_ECHO "$libtoolize_output" + + if [ ! $ret = 0 ] ; then $ECHO "ERROR: $LIBTOOLIZE failed" && exit 2 ; fi + else + if [ "x$HAVE_ALT_LIBTOOLIZE" = "xyes" ] ; then + $VERBOSE_ECHO "$LIBTOOLIZE $ALT_LIBTOOLIZE_OPTIONS" + libtoolize_output="`$LIBTOOLIZE $ALT_LIBTOOLIZE_OPTIONS 2>&1`" + ret=$? + $VERBOSE_ECHO "$libtoolize_output" + + if [ ! $ret = 0 ] ; then $ECHO "ERROR: $LIBTOOLIZE failed" && exit 2 ; fi + fi + fi + + ########### + # aclocal # + ########### + # re-run again as instructed by libtoolize + $VERBOSE_ECHO "$ACLOCAL $SEARCH_DIRS $ACLOCAL_OPTIONS" + aclocal_output="`$ACLOCAL $SEARCH_DIRS $ACLOCAL_OPTIONS 2>&1`" + ret=$? + $VERBOSE_ECHO "$aclocal_output" + + # libtoolize might put ltmain.sh in the wrong place + if test -f ltmain.sh ; then + if test ! -f "${_aux_dir}/ltmain.sh" ; then + $ECHO + $ECHO "Warning: $LIBTOOLIZE is creating ltmain.sh in the wrong directory" + $ECHO + $ECHO "Fortunately, the problem can be worked around by simply copying the" + $ECHO "file to the appropriate location (${_aux_dir}/). This has been done for you." + $ECHO + $VERBOSE_ECHO "cp -p ltmain.sh \"${_aux_dir}/ltmain.sh\"" + cp -p ltmain.sh "${_aux_dir}/ltmain.sh" + $ECHO $ECHO_N "Continuing build preparation ... $ECHO_C" + fi + fi # ltmain.sh + + if [ "x$DOWNLOAD" = "xyes" ] ; then + download_gnulib_config_guess + fi + fi # libtoolize_needed + + ############ + # autoconf # + ############ + $VERBOSE_ECHO + $VERBOSE_ECHO "$AUTOCONF $AUTOCONF_OPTIONS" + autoconf_output="`$AUTOCONF $AUTOCONF_OPTIONS 2>&1`" + ret=$? + $VERBOSE_ECHO "$autoconf_output" + + if [ ! $ret = 0 ] ; then + # retry without the -f and check for usage of macros that are too new + ac2_59_macros="AC_C_RESTRICT AC_INCLUDES_DEFAULT AC_LANG_ASSERT AC_LANG_WERROR AS_SET_CATFILE" + ac2_55_macros="AC_COMPILER_IFELSE AC_FUNC_MBRTOWC AC_HEADER_STDBOOL AC_LANG_CONFTEST AC_LANG_SOURCE AC_LANG_PROGRAM AC_LANG_CALL AC_LANG_FUNC_TRY_LINK AC_MSG_FAILURE AC_PREPROC_IFELSE" + ac2_54_macros="AC_C_BACKSLASH_A AC_CONFIG_LIBOBJ_DIR AC_GNU_SOURCE AC_PROG_EGREP AC_PROG_FGREP AC_REPLACE_FNMATCH AC_FUNC_FNMATCH_GNU AC_FUNC_REALLOC AC_TYPE_MBSTATE_T" + + macros_to_search="" + ac_major="`echo ${AUTOCONF_VERSION}. | cut -d. -f1 | sed 's/[^0-9]//g'`" + ac_minor="`echo ${AUTOCONF_VERSION}. | cut -d. -f2 | sed 's/[^0-9]//g'`" + + if [ $ac_major -lt 2 ] ; then + macros_to_search="$ac2_59_macros $ac2_55_macros $ac2_54_macros" + else + if [ $ac_minor -lt 54 ] ; then + macros_to_search="$ac2_59_macros $ac2_55_macros $ac2_54_macros" + elif [ $ac_minor -lt 55 ] ; then + macros_to_search="$ac2_59_macros $ac2_55_macros" + elif [ $ac_minor -lt 59 ] ; then + macros_to_search="$ac2_59_macros" + fi + fi + + configure_ac_macros=__none__ + for feature in $macros_to_search ; do + $VERBOSE_ECHO "Searching for $feature in $CONFIGURE" + found="`grep \"^$feature.*\" $CONFIGURE`" + if [ ! "x$found" = "x" ] ; then + if [ "x$configure_ac_macros" = "x__none__" ] ; then + configure_ac_macros="$feature" + else + configure_ac_macros="$feature $configure_ac_macros" + fi + fi + done + if [ ! "x$configure_ac_macros" = "x__none__" ] ; then + $ECHO + $ECHO "Warning: Unsupported macros were found in $CONFIGURE" + $ECHO + $ECHO "The `basename \"$CONFIGURE\"` file was scanned in order to determine if any" + $ECHO "unsupported macros are used that exceed the minimum version" + $ECHO "settings specified within this file. As such, the following macros" + $ECHO "should be removed from configure.ac or the version numbers in this" + $ECHO "file should be increased:" + $ECHO + $ECHO "$configure_ac_macros" + $ECHO + $ECHO $ECHO_N "Ignorantly continuing build preparation ... $ECHO_C" + fi + + ################### + # autoconf, retry # + ################### + $VERBOSE_ECHO + $VERBOSE_ECHO "$AUTOCONF" + autoconf_output="`$AUTOCONF 2>&1`" + ret=$? + $VERBOSE_ECHO "$autoconf_output" + + if [ ! $ret = 0 ] ; then + # test if libtool is busted + libtool_failure "$autoconf_output" + + # let the user know what went wrong + cat <], + [std::cout << "ok";], + [AC_MSG_RESULT(yes) + LIBFCGIXX=libfcgi++.la + ECHO_CPP=echo-cpp${EXEEXT} + AC_MSG_CHECKING([whether cin has a streambuf assignment operator]) + AC_TRY_COMPILE([#include ], + [cin = static_cast(0);], + [AC_MSG_RESULT(yes) + AC_DEFINE([HAVE_IOSTREAM_WITHASSIGN_STREAMBUF], [1], + [Define if cin/cout/cerr has a streambuf assignment operator])], + [AC_MSG_RESULT(no)]) + AC_MSG_CHECKING([whether char_type is defined in the context of streambuf]) + AC_TRY_COMPILE([#include ], + [class fcgi_streambuf : public std::streambuf { char_type ct; }], + [AC_MSG_RESULT(yes) + AC_DEFINE([HAVE_STREAMBUF_CHAR_TYPE], [1], + [Define if char_type is defined in the context of streambuf])], + [AC_MSG_RESULT(no)])], + [AC_MSG_RESULT(no)]) +AC_SUBST(LIBFCGIXX) +AC_SUBST(ECHO_CPP) + +AC_LANG([C]) + +AC_CHECK_LIB([nsl], [gethostbyname]) +AC_CHECK_LIB([socket], [socket]) + + +ACX_PTHREAD([THREADED=threaded${EXEEXT}]) +AC_SUBST([THREADED]) + + +FCGI_COMMON_CHECKS + +AC_REPLACE_FUNCS([strerror]) + + +SYSTEM=unix +AC_SUBST([SYSTEM]) + +AC_PROG_CC_WARNINGS + +AC_SUBST(LIBS) + +AC_PROG_MAKE_SET +AC_CONFIG_FILES([Makefile \ + src/Makefile \ + man/Makefile \ + fcgi/Makefile \ + fcgi/include/Makefile \ + fcgi/libfcgi/Makefile]) +AC_OUTPUT + +# Print out option status +AC_MSG_RESULT([ +Options Enabled: +--------------- + Memcached: ${MEMCACHED} + JPEG2000 (Kakadu): ${KAKADU} + PNG Output: ${PNG} + LitleCMS: ${LCMS} +]) diff --git a/iipsrv/doc/doxygen-html.conf b/iipsrv/doc/doxygen-html.conf new file mode 100644 index 0000000..45c689b --- /dev/null +++ b/iipsrv/doc/doxygen-html.conf @@ -0,0 +1,1510 @@ +# Doxyfile 1.5.8 + +# This file describes the settings to be used by the documentation system +# doxygen (www.doxygen.org) for a project +# +# All text after a hash (#) is considered a comment and will be ignored +# The format is: +# TAG = value [value, ...] +# For lists items can also be appended using: +# TAG += value [value, ...] +# Values that contain spaces should be placed between quotes (" ") + +#--------------------------------------------------------------------------- +# Project related configuration options +#--------------------------------------------------------------------------- + +# This tag specifies the encoding used for all characters in the config file +# that follow. The default is UTF-8 which is also the encoding used for all +# text before the first occurrence of this tag. Doxygen uses libiconv (or the +# iconv built into libc) for the transcoding. See +# http://www.gnu.org/software/libiconv for the list of possible encodings. + +DOXYFILE_ENCODING = UTF-8 + +# The PROJECT_NAME tag is a single word (or a sequence of words surrounded +# by quotes) that should identify the project. + +PROJECT_NAME = iipsrv + +# The PROJECT_NUMBER tag can be used to enter a project or revision number. +# This could be handy for archiving the generated documentation or +# if some version control system is used. + +PROJECT_NUMBER = 0.9.9 + +# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) +# base path where the generated documentation will be put. +# If a relative path is entered, it will be relative to the location +# where doxygen was started. If left blank the current directory will be used. + +OUTPUT_DIRECTORY = doc + +# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create +# 4096 sub-directories (in 2 levels) under the output directory of each output +# format and will distribute the generated files over these directories. +# Enabling this option can be useful when feeding doxygen a huge amount of +# source files, where putting all generated files in the same directory would +# otherwise cause performance problems for the file system. + +CREATE_SUBDIRS = NO + +# The OUTPUT_LANGUAGE tag is used to specify the language in which all +# documentation generated by doxygen is written. Doxygen will use this +# information to generate all constant output in the proper language. +# The default language is English, other supported languages are: +# Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional, +# Croatian, Czech, Danish, Dutch, Farsi, Finnish, French, German, Greek, +# Hungarian, Italian, Japanese, Japanese-en (Japanese with English messages), +# Korean, Korean-en, Lithuanian, Norwegian, Macedonian, Persian, Polish, +# Portuguese, Romanian, Russian, Serbian, Serbian-Cyrilic, Slovak, Slovene, +# Spanish, Swedish, and Ukrainian. + +OUTPUT_LANGUAGE = English + +# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will +# include brief member descriptions after the members that are listed in +# the file and class documentation (similar to JavaDoc). +# Set to NO to disable this. + +BRIEF_MEMBER_DESC = YES + +# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend +# the brief description of a member or function before the detailed description. +# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the +# brief descriptions will be completely suppressed. + +REPEAT_BRIEF = YES + +# This tag implements a quasi-intelligent brief description abbreviator +# that is used to form the text in various listings. Each string +# in this list, if found as the leading text of the brief description, will be +# stripped from the text and the result after processing the whole list, is +# used as the annotated text. Otherwise, the brief description is used as-is. +# If left blank, the following values are used ("$name" is automatically +# replaced with the name of the entity): "The $name class" "The $name widget" +# "The $name file" "is" "provides" "specifies" "contains" +# "represents" "a" "an" "the" + +ABBREVIATE_BRIEF = + +# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then +# Doxygen will generate a detailed section even if there is only a brief +# description. + +ALWAYS_DETAILED_SEC = NO + +# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all +# inherited members of a class in the documentation of that class as if those +# members were ordinary class members. Constructors, destructors and assignment +# operators of the base classes will not be shown. + +INLINE_INHERITED_MEMB = NO + +# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full +# path before files name in the file list and in the header files. If set +# to NO the shortest path that makes the file name unique will be used. + +FULL_PATH_NAMES = NO + +# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag +# can be used to strip a user-defined part of the path. Stripping is +# only done if one of the specified strings matches the left-hand part of +# the path. The tag can be used to show relative paths in the file list. +# If left blank the directory from which doxygen is run is used as the +# path to strip. + +STRIP_FROM_PATH = + +# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of +# the path mentioned in the documentation of a class, which tells +# the reader which header file to include in order to use a class. +# If left blank only the name of the header file containing the class +# definition is used. Otherwise one should specify the include paths that +# are normally passed to the compiler using the -I flag. + +STRIP_FROM_INC_PATH = + +# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter +# (but less readable) file names. This can be useful is your file systems +# doesn't support long names like on DOS, Mac, or CD-ROM. + +SHORT_NAMES = NO + +# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen +# will interpret the first line (until the first dot) of a JavaDoc-style +# comment as the brief description. If set to NO, the JavaDoc +# comments will behave just like regular Qt-style comments +# (thus requiring an explicit @brief command for a brief description.) + +JAVADOC_AUTOBRIEF = NO + +# If the QT_AUTOBRIEF tag is set to YES then Doxygen will +# interpret the first line (until the first dot) of a Qt-style +# comment as the brief description. If set to NO, the comments +# will behave just like regular Qt-style comments (thus requiring +# an explicit \brief command for a brief description.) + +QT_AUTOBRIEF = NO + +# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen +# treat a multi-line C++ special comment block (i.e. a block of //! or /// +# comments) as a brief description. This used to be the default behaviour. +# The new default is to treat a multi-line C++ comment block as a detailed +# description. Set this tag to YES if you prefer the old behaviour instead. + +MULTILINE_CPP_IS_BRIEF = NO + +# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented +# member inherits the documentation from any documented member that it +# re-implements. + +INHERIT_DOCS = YES + +# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce +# a new page for each member. If set to NO, the documentation of a member will +# be part of the file/class/namespace that contains it. + +SEPARATE_MEMBER_PAGES = NO + +# The TAB_SIZE tag can be used to set the number of spaces in a tab. +# Doxygen uses this value to replace tabs by spaces in code fragments. + +TAB_SIZE = 8 + +# This tag can be used to specify a number of aliases that acts +# as commands in the documentation. An alias has the form "name=value". +# For example adding "sideeffect=\par Side Effects:\n" will allow you to +# put the command \sideeffect (or @sideeffect) in the documentation, which +# will result in a user-defined paragraph with heading "Side Effects:". +# You can put \n's in the value part of an alias to insert newlines. + +ALIASES = + +# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C +# sources only. Doxygen will then generate output that is more tailored for C. +# For instance, some of the names that are used will be different. The list +# of all members will be omitted, etc. + +OPTIMIZE_OUTPUT_FOR_C = NO + +# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java +# sources only. Doxygen will then generate output that is more tailored for +# Java. For instance, namespaces will be presented as packages, qualified +# scopes will look different, etc. + +OPTIMIZE_OUTPUT_JAVA = NO + +# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran +# sources only. Doxygen will then generate output that is more tailored for +# Fortran. + +OPTIMIZE_FOR_FORTRAN = NO + +# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL +# sources. Doxygen will then generate output that is tailored for +# VHDL. + +OPTIMIZE_OUTPUT_VHDL = NO + +# Doxygen selects the parser to use depending on the extension of the files it parses. +# With this tag you can assign which parser to use for a given extension. +# Doxygen has a built-in mapping, but you can override or extend it using this tag. +# The format is ext=language, where ext is a file extension, and language is one of +# the parsers supported by doxygen: IDL, Java, Javascript, C#, C, C++, D, PHP, +# Objective-C, Python, Fortran, VHDL, C, C++. For instance to make doxygen treat +# .inc files as Fortran files (default is PHP), and .f files as C (default is Fortran), +# use: inc=Fortran f=C + +EXTENSION_MAPPING = + +# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want +# to include (a tag file for) the STL sources as input, then you should +# set this tag to YES in order to let doxygen match functions declarations and +# definitions whose arguments contain STL classes (e.g. func(std::string); v.s. +# func(std::string) {}). This also make the inheritance and collaboration +# diagrams that involve STL classes more complete and accurate. + +BUILTIN_STL_SUPPORT = NO + +# If you use Microsoft's C++/CLI language, you should set this option to YES to +# enable parsing support. + +CPP_CLI_SUPPORT = NO + +# Set the SIP_SUPPORT tag to YES if your project consists of sip sources only. +# Doxygen will parse them like normal C++ but will assume all classes use public +# instead of private inheritance when no explicit protection keyword is present. + +SIP_SUPPORT = NO + +# For Microsoft's IDL there are propget and propput attributes to indicate getter +# and setter methods for a property. Setting this option to YES (the default) +# will make doxygen to replace the get and set methods by a property in the +# documentation. This will only work if the methods are indeed getting or +# setting a simple type. If this is not the case, or you want to show the +# methods anyway, you should set this option to NO. + +IDL_PROPERTY_SUPPORT = YES + +# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC +# tag is set to YES, then doxygen will reuse the documentation of the first +# member in the group (if any) for the other members of the group. By default +# all members of a group must be documented explicitly. + +DISTRIBUTE_GROUP_DOC = NO + +# Set the SUBGROUPING tag to YES (the default) to allow class member groups of +# the same type (for instance a group of public functions) to be put as a +# subgroup of that type (e.g. under the Public Functions section). Set it to +# NO to prevent subgrouping. Alternatively, this can be done per class using +# the \nosubgrouping command. + +SUBGROUPING = YES + +# When TYPEDEF_HIDES_STRUCT is enabled, a typedef of a struct, union, or enum +# is documented as struct, union, or enum with the name of the typedef. So +# typedef struct TypeS {} TypeT, will appear in the documentation as a struct +# with name TypeT. When disabled the typedef will appear as a member of a file, +# namespace, or class. And the struct will be named TypeS. This can typically +# be useful for C code in case the coding convention dictates that all compound +# types are typedef'ed and only the typedef is referenced, never the tag name. + +TYPEDEF_HIDES_STRUCT = NO + +# The SYMBOL_CACHE_SIZE determines the size of the internal cache use to +# determine which symbols to keep in memory and which to flush to disk. +# When the cache is full, less often used symbols will be written to disk. +# For small to medium size projects (<1000 input files) the default value is +# probably good enough. For larger projects a too small cache size can cause +# doxygen to be busy swapping symbols to and from disk most of the time +# causing a significant performance penality. +# If the system has enough physical memory increasing the cache will improve the +# performance by keeping more symbols in memory. Note that the value works on +# a logarithmic scale so increasing the size by one will rougly double the +# memory usage. The cache size is given by this formula: +# 2^(16+SYMBOL_CACHE_SIZE). The valid range is 0..9, the default is 0, +# corresponding to a cache size of 2^16 = 65536 symbols + +SYMBOL_CACHE_SIZE = 0 + +#--------------------------------------------------------------------------- +# Build related configuration options +#--------------------------------------------------------------------------- + +# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in +# documentation are documented, even if no documentation was available. +# Private class members and static file members will be hidden unless +# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES + +EXTRACT_ALL = NO + +# If the EXTRACT_PRIVATE tag is set to YES all private members of a class +# will be included in the documentation. + +EXTRACT_PRIVATE = NO + +# If the EXTRACT_STATIC tag is set to YES all static members of a file +# will be included in the documentation. + +EXTRACT_STATIC = NO + +# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) +# defined locally in source files will be included in the documentation. +# If set to NO only classes defined in header files are included. + +EXTRACT_LOCAL_CLASSES = YES + +# This flag is only useful for Objective-C code. When set to YES local +# methods, which are defined in the implementation section but not in +# the interface are included in the documentation. +# If set to NO (the default) only methods in the interface are included. + +EXTRACT_LOCAL_METHODS = NO + +# If this flag is set to YES, the members of anonymous namespaces will be +# extracted and appear in the documentation as a namespace called +# 'anonymous_namespace{file}', where file will be replaced with the base +# name of the file that contains the anonymous namespace. By default +# anonymous namespace are hidden. + +EXTRACT_ANON_NSPACES = NO + +# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all +# undocumented members of documented classes, files or namespaces. +# If set to NO (the default) these members will be included in the +# various overviews, but no documentation section is generated. +# This option has no effect if EXTRACT_ALL is enabled. + +HIDE_UNDOC_MEMBERS = NO + +# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all +# undocumented classes that are normally visible in the class hierarchy. +# If set to NO (the default) these classes will be included in the various +# overviews. This option has no effect if EXTRACT_ALL is enabled. + +HIDE_UNDOC_CLASSES = NO + +# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all +# friend (class|struct|union) declarations. +# If set to NO (the default) these declarations will be included in the +# documentation. + +HIDE_FRIEND_COMPOUNDS = NO + +# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any +# documentation blocks found inside the body of a function. +# If set to NO (the default) these blocks will be appended to the +# function's detailed documentation block. + +HIDE_IN_BODY_DOCS = NO + +# The INTERNAL_DOCS tag determines if documentation +# that is typed after a \internal command is included. If the tag is set +# to NO (the default) then the documentation will be excluded. +# Set it to YES to include the internal documentation. + +INTERNAL_DOCS = NO + +# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate +# file names in lower-case letters. If set to YES upper-case letters are also +# allowed. This is useful if you have classes or files whose names only differ +# in case and if your file system supports case sensitive file names. Windows +# and Mac users are advised to set this option to NO. + +CASE_SENSE_NAMES = YES + +# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen +# will show members with their full class and namespace scopes in the +# documentation. If set to YES the scope will be hidden. + +HIDE_SCOPE_NAMES = NO + +# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen +# will put a list of the files that are included by a file in the documentation +# of that file. + +SHOW_INCLUDE_FILES = YES + +# If the INLINE_INFO tag is set to YES (the default) then a tag [inline] +# is inserted in the documentation for inline members. + +INLINE_INFO = YES + +# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen +# will sort the (detailed) documentation of file and class members +# alphabetically by member name. If set to NO the members will appear in +# declaration order. + +SORT_MEMBER_DOCS = YES + +# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the +# brief documentation of file, namespace and class members alphabetically +# by member name. If set to NO (the default) the members will appear in +# declaration order. + +SORT_BRIEF_DOCS = NO + +# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the +# hierarchy of group names into alphabetical order. If set to NO (the default) +# the group names will appear in their defined order. + +SORT_GROUP_NAMES = NO + +# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be +# sorted by fully-qualified names, including namespaces. If set to +# NO (the default), the class list will be sorted only by class name, +# not including the namespace part. +# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. +# Note: This option applies only to the class list, not to the +# alphabetical list. + +SORT_BY_SCOPE_NAME = NO + +# The GENERATE_TODOLIST tag can be used to enable (YES) or +# disable (NO) the todo list. This list is created by putting \todo +# commands in the documentation. + +GENERATE_TODOLIST = YES + +# The GENERATE_TESTLIST tag can be used to enable (YES) or +# disable (NO) the test list. This list is created by putting \test +# commands in the documentation. + +GENERATE_TESTLIST = YES + +# The GENERATE_BUGLIST tag can be used to enable (YES) or +# disable (NO) the bug list. This list is created by putting \bug +# commands in the documentation. + +GENERATE_BUGLIST = YES + +# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or +# disable (NO) the deprecated list. This list is created by putting +# \deprecated commands in the documentation. + +GENERATE_DEPRECATEDLIST= YES + +# The ENABLED_SECTIONS tag can be used to enable conditional +# documentation sections, marked by \if sectionname ... \endif. + +ENABLED_SECTIONS = + +# The MAX_INITIALIZER_LINES tag determines the maximum number of lines +# the initial value of a variable or define consists of for it to appear in +# the documentation. If the initializer consists of more lines than specified +# here it will be hidden. Use a value of 0 to hide initializers completely. +# The appearance of the initializer of individual variables and defines in the +# documentation can be controlled using \showinitializer or \hideinitializer +# command in the documentation regardless of this setting. + +MAX_INITIALIZER_LINES = 30 + +# Set the SHOW_USED_FILES tag to NO to disable the list of files generated +# at the bottom of the documentation of classes and structs. If set to YES the +# list will mention the files that were used to generate the documentation. + +SHOW_USED_FILES = YES + +# If the sources in your project are distributed over multiple directories +# then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy +# in the documentation. The default is NO. + +SHOW_DIRECTORIES = YES + +# Set the SHOW_FILES tag to NO to disable the generation of the Files page. +# This will remove the Files entry from the Quick Index and from the +# Folder Tree View (if specified). The default is YES. + +SHOW_FILES = YES + +# Set the SHOW_NAMESPACES tag to NO to disable the generation of the +# Namespaces page. +# This will remove the Namespaces entry from the Quick Index +# and from the Folder Tree View (if specified). The default is YES. + +SHOW_NAMESPACES = YES + +# The FILE_VERSION_FILTER tag can be used to specify a program or script that +# doxygen should invoke to get the current version for each file (typically from +# the version control system). Doxygen will invoke the program by executing (via +# popen()) the command , where is the value of +# the FILE_VERSION_FILTER tag, and is the name of an input file +# provided by doxygen. Whatever the program writes to standard output +# is used as the file version. See the manual for examples. + +FILE_VERSION_FILTER = + +# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed by +# doxygen. The layout file controls the global structure of the generated output files +# in an output format independent way. The create the layout file that represents +# doxygen's defaults, run doxygen with the -l option. You can optionally specify a +# file name after the option, if omitted DoxygenLayout.xml will be used as the name +# of the layout file. + +LAYOUT_FILE = + +#--------------------------------------------------------------------------- +# configuration options related to warning and progress messages +#--------------------------------------------------------------------------- + +# The QUIET tag can be used to turn on/off the messages that are generated +# by doxygen. Possible values are YES and NO. If left blank NO is used. + +QUIET = NO + +# The WARNINGS tag can be used to turn on/off the warning messages that are +# generated by doxygen. Possible values are YES and NO. If left blank +# NO is used. + +WARNINGS = YES + +# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings +# for undocumented members. If EXTRACT_ALL is set to YES then this flag will +# automatically be disabled. + +WARN_IF_UNDOCUMENTED = YES + +# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for +# potential errors in the documentation, such as not documenting some +# parameters in a documented function, or documenting parameters that +# don't exist or using markup commands wrongly. + +WARN_IF_DOC_ERROR = YES + +# This WARN_NO_PARAMDOC option can be abled to get warnings for +# functions that are documented, but have no documentation for their parameters +# or return value. If set to NO (the default) doxygen will only warn about +# wrong or incomplete parameter documentation, but not about the absence of +# documentation. + +WARN_NO_PARAMDOC = NO + +# The WARN_FORMAT tag determines the format of the warning messages that +# doxygen can produce. The string should contain the $file, $line, and $text +# tags, which will be replaced by the file and line number from which the +# warning originated and the warning text. Optionally the format may contain +# $version, which will be replaced by the version of the file (if it could +# be obtained via FILE_VERSION_FILTER) + +WARN_FORMAT = "$file:$line: $text" + +# The WARN_LOGFILE tag can be used to specify a file to which warning +# and error messages should be written. If left blank the output is written +# to stderr. + +WARN_LOGFILE = + +#--------------------------------------------------------------------------- +# configuration options related to the input files +#--------------------------------------------------------------------------- + +# The INPUT tag can be used to specify the files and/or directories that contain +# documented source files. You may enter file names like "myfile.cpp" or +# directories like "/usr/src/myproject". Separate the files or directories +# with spaces. + +INPUT = src + +# This tag can be used to specify the character encoding of the source files +# that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is +# also the default input encoding. Doxygen uses libiconv (or the iconv built +# into libc) for the transcoding. See http://www.gnu.org/software/libiconv for +# the list of possible encodings. + +INPUT_ENCODING = UTF-8 + +# If the value of the INPUT tag contains directories, you can use the +# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp +# and *.h) to filter out the source-files in the directories. If left +# blank the following patterns are tested: +# *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx +# *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.py *.f90 + +FILE_PATTERNS = *.h + +# The RECURSIVE tag can be used to turn specify whether or not subdirectories +# should be searched for input files as well. Possible values are YES and NO. +# If left blank NO is used. + +RECURSIVE = NO + +# The EXCLUDE tag can be used to specify files and/or directories that should +# excluded from the INPUT source files. This way you can easily exclude a +# subdirectory from a directory tree whose root is specified with the INPUT tag. + +EXCLUDE = + +# The EXCLUDE_SYMLINKS tag can be used select whether or not files or +# directories that are symbolic links (a Unix filesystem feature) are excluded +# from the input. + +EXCLUDE_SYMLINKS = NO + +# If the value of the INPUT tag contains directories, you can use the +# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude +# certain files from those directories. Note that the wildcards are matched +# against the file with absolute path, so to exclude all test directories +# for example use the pattern */test/* + +EXCLUDE_PATTERNS = + +# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names +# (namespaces, classes, functions, etc.) that should be excluded from the +# output. The symbol name can be a fully qualified name, a word, or if the +# wildcard * is used, a substring. Examples: ANamespace, AClass, +# AClass::ANamespace, ANamespace::*Test + +EXCLUDE_SYMBOLS = + +# The EXAMPLE_PATH tag can be used to specify one or more files or +# directories that contain example code fragments that are included (see +# the \include command). + +EXAMPLE_PATH = + +# If the value of the EXAMPLE_PATH tag contains directories, you can use the +# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp +# and *.h) to filter out the source-files in the directories. If left +# blank all files are included. + +EXAMPLE_PATTERNS = + +# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be +# searched for input files to be used with the \include or \dontinclude +# commands irrespective of the value of the RECURSIVE tag. +# Possible values are YES and NO. If left blank NO is used. + +EXAMPLE_RECURSIVE = NO + +# The IMAGE_PATH tag can be used to specify one or more files or +# directories that contain image that are included in the documentation (see +# the \image command). + +IMAGE_PATH = + +# The INPUT_FILTER tag can be used to specify a program that doxygen should +# invoke to filter for each input file. Doxygen will invoke the filter program +# by executing (via popen()) the command , where +# is the value of the INPUT_FILTER tag, and is the name of an +# input file. Doxygen will then use the output that the filter program writes +# to standard output. +# If FILTER_PATTERNS is specified, this tag will be +# ignored. + +INPUT_FILTER = + +# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern +# basis. +# Doxygen will compare the file name with each pattern and apply the +# filter if there is a match. +# The filters are a list of the form: +# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further +# info on how filters are used. If FILTER_PATTERNS is empty, INPUT_FILTER +# is applied to all files. + +FILTER_PATTERNS = + +# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using +# INPUT_FILTER) will be used to filter the input files when producing source +# files to browse (i.e. when SOURCE_BROWSER is set to YES). + +FILTER_SOURCE_FILES = NO + +#--------------------------------------------------------------------------- +# configuration options related to source browsing +#--------------------------------------------------------------------------- + +# If the SOURCE_BROWSER tag is set to YES then a list of source files will +# be generated. Documented entities will be cross-referenced with these sources. +# Note: To get rid of all source code in the generated output, make sure also +# VERBATIM_HEADERS is set to NO. + +SOURCE_BROWSER = NO + +# Setting the INLINE_SOURCES tag to YES will include the body +# of functions and classes directly in the documentation. + +INLINE_SOURCES = NO + +# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct +# doxygen to hide any special comment blocks from generated source code +# fragments. Normal C and C++ comments will always remain visible. + +STRIP_CODE_COMMENTS = YES + +# If the REFERENCED_BY_RELATION tag is set to YES +# then for each documented function all documented +# functions referencing it will be listed. + +REFERENCED_BY_RELATION = YES + +# If the REFERENCES_RELATION tag is set to YES +# then for each documented function all documented entities +# called/used by that function will be listed. + +REFERENCES_RELATION = YES + +# If the REFERENCES_LINK_SOURCE tag is set to YES (the default) +# and SOURCE_BROWSER tag is set to YES, then the hyperlinks from +# functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will +# link to the source code. +# Otherwise they will link to the documentation. + +REFERENCES_LINK_SOURCE = YES + +# If the USE_HTAGS tag is set to YES then the references to source code +# will point to the HTML generated by the htags(1) tool instead of doxygen +# built-in source browser. The htags tool is part of GNU's global source +# tagging system (see http://www.gnu.org/software/global/global.html). You +# will need version 4.8.6 or higher. + +USE_HTAGS = NO + +# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen +# will generate a verbatim copy of the header file for each class for +# which an include is specified. Set to NO to disable this. + +VERBATIM_HEADERS = YES + +#--------------------------------------------------------------------------- +# configuration options related to the alphabetical class index +#--------------------------------------------------------------------------- + +# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index +# of all compounds will be generated. Enable this if the project +# contains a lot of classes, structs, unions or interfaces. + +ALPHABETICAL_INDEX = NO + +# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then +# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns +# in which this list will be split (can be a number in the range [1..20]) + +COLS_IN_ALPHA_INDEX = 5 + +# In case all classes in a project start with a common prefix, all +# classes will be put under the same header in the alphabetical index. +# The IGNORE_PREFIX tag can be used to specify one or more prefixes that +# should be ignored while generating the index headers. + +IGNORE_PREFIX = + +#--------------------------------------------------------------------------- +# configuration options related to the HTML output +#--------------------------------------------------------------------------- + +# If the GENERATE_HTML tag is set to YES (the default) Doxygen will +# generate HTML output. + +GENERATE_HTML = YES + +# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `html' will be used as the default path. + +HTML_OUTPUT = html + +# The HTML_FILE_EXTENSION tag can be used to specify the file extension for +# each generated HTML page (for example: .htm,.php,.asp). If it is left blank +# doxygen will generate files with .html extension. + +HTML_FILE_EXTENSION = .html + +# The HTML_HEADER tag can be used to specify a personal HTML header for +# each generated HTML page. If it is left blank doxygen will generate a +# standard header. + +HTML_HEADER = + +# The HTML_FOOTER tag can be used to specify a personal HTML footer for +# each generated HTML page. If it is left blank doxygen will generate a +# standard footer. + +HTML_FOOTER = + +# The HTML_STYLESHEET tag can be used to specify a user-defined cascading +# style sheet that is used by each HTML page. It can be used to +# fine-tune the look of the HTML output. If the tag is left blank doxygen +# will generate a default style sheet. Note that doxygen will try to copy +# the style sheet file to the HTML output directory, so don't put your own +# stylesheet in the HTML output directory as well, or it will be erased! + +HTML_STYLESHEET = + +# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes, +# files or namespaces will be aligned in HTML using tables. If set to +# NO a bullet list will be used. + +HTML_ALIGN_MEMBERS = YES + +# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML +# documentation will contain sections that can be hidden and shown after the +# page has loaded. For this to work a browser that supports +# JavaScript and DHTML is required (for instance Mozilla 1.0+, Firefox +# Netscape 6.0+, Internet explorer 5.0+, Konqueror, or Safari). + +HTML_DYNAMIC_SECTIONS = NO + +# If the GENERATE_DOCSET tag is set to YES, additional index files +# will be generated that can be used as input for Apple's Xcode 3 +# integrated development environment, introduced with OSX 10.5 (Leopard). +# To create a documentation set, doxygen will generate a Makefile in the +# HTML output directory. Running make will produce the docset in that +# directory and running "make install" will install the docset in +# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find +# it at startup. +# See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html for more information. + +GENERATE_DOCSET = NO + +# When GENERATE_DOCSET tag is set to YES, this tag determines the name of the +# feed. A documentation feed provides an umbrella under which multiple +# documentation sets from a single provider (such as a company or product suite) +# can be grouped. + +DOCSET_FEEDNAME = "Doxygen generated docs" + +# When GENERATE_DOCSET tag is set to YES, this tag specifies a string that +# should uniquely identify the documentation set bundle. This should be a +# reverse domain-name style string, e.g. com.mycompany.MyDocSet. Doxygen +# will append .docset to the name. + +DOCSET_BUNDLE_ID = org.doxygen.Project + +# If the GENERATE_HTMLHELP tag is set to YES, additional index files +# will be generated that can be used as input for tools like the +# Microsoft HTML help workshop to generate a compiled HTML help file (.chm) +# of the generated HTML documentation. + +GENERATE_HTMLHELP = NO + +# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can +# be used to specify the file name of the resulting .chm file. You +# can add a path in front of the file if the result should not be +# written to the html output directory. + +CHM_FILE = + +# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can +# be used to specify the location (absolute path including file name) of +# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run +# the HTML help compiler on the generated index.hhp. + +HHC_LOCATION = + +# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag +# controls if a separate .chi index file is generated (YES) or that +# it should be included in the master .chm file (NO). + +GENERATE_CHI = NO + +# If the GENERATE_HTMLHELP tag is set to YES, the CHM_INDEX_ENCODING +# is used to encode HtmlHelp index (hhk), content (hhc) and project file +# content. + +CHM_INDEX_ENCODING = + +# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag +# controls whether a binary table of contents is generated (YES) or a +# normal table of contents (NO) in the .chm file. + +BINARY_TOC = NO + +# The TOC_EXPAND flag can be set to YES to add extra items for group members +# to the contents of the HTML help documentation and to the tree view. + +TOC_EXPAND = NO + +# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and QHP_VIRTUAL_FOLDER +# are set, an additional index file will be generated that can be used as input for +# Qt's qhelpgenerator to generate a Qt Compressed Help (.qch) of the generated +# HTML documentation. + +GENERATE_QHP = NO + +# If the QHG_LOCATION tag is specified, the QCH_FILE tag can +# be used to specify the file name of the resulting .qch file. +# The path specified is relative to the HTML output folder. + +QCH_FILE = + +# The QHP_NAMESPACE tag specifies the namespace to use when generating +# Qt Help Project output. For more information please see +# http://doc.trolltech.com/qthelpproject.html#namespace + +QHP_NAMESPACE = + +# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating +# Qt Help Project output. For more information please see +# http://doc.trolltech.com/qthelpproject.html#virtual-folders + +QHP_VIRTUAL_FOLDER = doc + +# If QHP_CUST_FILTER_NAME is set, it specifies the name of a custom filter to add. +# For more information please see +# http://doc.trolltech.com/qthelpproject.html#custom-filters + +QHP_CUST_FILTER_NAME = + +# The QHP_CUST_FILT_ATTRS tag specifies the list of the attributes of the custom filter to add.For more information please see +# Qt Help Project / Custom Filters. + +QHP_CUST_FILTER_ATTRS = + +# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this project's +# filter section matches. +# Qt Help Project / Filter Attributes. + +QHP_SECT_FILTER_ATTRS = + +# If the GENERATE_QHP tag is set to YES, the QHG_LOCATION tag can +# be used to specify the location of Qt's qhelpgenerator. +# If non-empty doxygen will try to run qhelpgenerator on the generated +# .qhp file. + +QHG_LOCATION = + +# The DISABLE_INDEX tag can be used to turn on/off the condensed index at +# top of each HTML page. The value NO (the default) enables the index and +# the value YES disables it. + +DISABLE_INDEX = NO + +# This tag can be used to set the number of enum values (range [1..20]) +# that doxygen will group on one line in the generated HTML documentation. + +ENUM_VALUES_PER_LINE = 4 + +# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index +# structure should be generated to display hierarchical information. +# If the tag value is set to FRAME, a side panel will be generated +# containing a tree-like index structure (just like the one that +# is generated for HTML Help). For this to work a browser that supports +# JavaScript, DHTML, CSS and frames is required (for instance Mozilla 1.0+, +# Netscape 6.0+, Internet explorer 5.0+, or Konqueror). Windows users are +# probably better off using the HTML help feature. Other possible values +# for this tag are: HIERARCHIES, which will generate the Groups, Directories, +# and Class Hierarchy pages using a tree view instead of an ordered list; +# ALL, which combines the behavior of FRAME and HIERARCHIES; and NONE, which +# disables this behavior completely. For backwards compatibility with previous +# releases of Doxygen, the values YES and NO are equivalent to FRAME and NONE +# respectively. + +GENERATE_TREEVIEW = YES + +# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be +# used to set the initial width (in pixels) of the frame in which the tree +# is shown. + +TREEVIEW_WIDTH = 250 + +# Use this tag to change the font size of Latex formulas included +# as images in the HTML documentation. The default is 10. Note that +# when you change the font size after a successful doxygen run you need +# to manually remove any form_*.png images from the HTML output directory +# to force them to be regenerated. + +FORMULA_FONTSIZE = 10 + +#--------------------------------------------------------------------------- +# configuration options related to the LaTeX output +#--------------------------------------------------------------------------- + +# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will +# generate Latex output. + +GENERATE_LATEX = NO + +# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `latex' will be used as the default path. + +LATEX_OUTPUT = latex + +# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be +# invoked. If left blank `latex' will be used as the default command name. + +LATEX_CMD_NAME = latex + +# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to +# generate index for LaTeX. If left blank `makeindex' will be used as the +# default command name. + +MAKEINDEX_CMD_NAME = makeindex + +# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact +# LaTeX documents. This may be useful for small projects and may help to +# save some trees in general. + +COMPACT_LATEX = NO + +# The PAPER_TYPE tag can be used to set the paper type that is used +# by the printer. Possible values are: a4, a4wide, letter, legal and +# executive. If left blank a4wide will be used. + +PAPER_TYPE = a4wide + +# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX +# packages that should be included in the LaTeX output. + +EXTRA_PACKAGES = + +# The LATEX_HEADER tag can be used to specify a personal LaTeX header for +# the generated latex document. The header should contain everything until +# the first chapter. If it is left blank doxygen will generate a +# standard header. Notice: only use this tag if you know what you are doing! + +LATEX_HEADER = + +# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated +# is prepared for conversion to pdf (using ps2pdf). The pdf file will +# contain links (just like the HTML output) instead of page references +# This makes the output suitable for online browsing using a pdf viewer. + +PDF_HYPERLINKS = NO + +# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of +# plain latex in the generated Makefile. Set this option to YES to get a +# higher quality PDF documentation. + +USE_PDFLATEX = NO + +# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode. +# command to the generated LaTeX files. This will instruct LaTeX to keep +# running if errors occur, instead of asking the user for help. +# This option is also used when generating formulas in HTML. + +LATEX_BATCHMODE = NO + +# If LATEX_HIDE_INDICES is set to YES then doxygen will not +# include the index chapters (such as File Index, Compound Index, etc.) +# in the output. + +LATEX_HIDE_INDICES = NO + +#--------------------------------------------------------------------------- +# configuration options related to the RTF output +#--------------------------------------------------------------------------- + +# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output +# The RTF output is optimized for Word 97 and may not look very pretty with +# other RTF readers or editors. + +GENERATE_RTF = NO + +# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `rtf' will be used as the default path. + +RTF_OUTPUT = rtf + +# If the COMPACT_RTF tag is set to YES Doxygen generates more compact +# RTF documents. This may be useful for small projects and may help to +# save some trees in general. + +COMPACT_RTF = NO + +# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated +# will contain hyperlink fields. The RTF file will +# contain links (just like the HTML output) instead of page references. +# This makes the output suitable for online browsing using WORD or other +# programs which support those fields. +# Note: wordpad (write) and others do not support links. + +RTF_HYPERLINKS = NO + +# Load stylesheet definitions from file. Syntax is similar to doxygen's +# config file, i.e. a series of assignments. You only have to provide +# replacements, missing definitions are set to their default value. + +RTF_STYLESHEET_FILE = + +# Set optional variables used in the generation of an rtf document. +# Syntax is similar to doxygen's config file. + +RTF_EXTENSIONS_FILE = + +#--------------------------------------------------------------------------- +# configuration options related to the man page output +#--------------------------------------------------------------------------- + +# If the GENERATE_MAN tag is set to YES (the default) Doxygen will +# generate man pages + +GENERATE_MAN = NO + +# The MAN_OUTPUT tag is used to specify where the man pages will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `man' will be used as the default path. + +MAN_OUTPUT = man + +# The MAN_EXTENSION tag determines the extension that is added to +# the generated man pages (default is the subroutine's section .3) + +MAN_EXTENSION = .3 + +# If the MAN_LINKS tag is set to YES and Doxygen generates man output, +# then it will generate one additional man file for each entity +# documented in the real man page(s). These additional files +# only source the real man page, but without them the man command +# would be unable to find the correct page. The default is NO. + +MAN_LINKS = NO + +#--------------------------------------------------------------------------- +# configuration options related to the XML output +#--------------------------------------------------------------------------- + +# If the GENERATE_XML tag is set to YES Doxygen will +# generate an XML file that captures the structure of +# the code including all documentation. + +GENERATE_XML = NO + +# The XML_OUTPUT tag is used to specify where the XML pages will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `xml' will be used as the default path. + +XML_OUTPUT = xml + +# The XML_SCHEMA tag can be used to specify an XML schema, +# which can be used by a validating XML parser to check the +# syntax of the XML files. + +XML_SCHEMA = + +# The XML_DTD tag can be used to specify an XML DTD, +# which can be used by a validating XML parser to check the +# syntax of the XML files. + +XML_DTD = + +# If the XML_PROGRAMLISTING tag is set to YES Doxygen will +# dump the program listings (including syntax highlighting +# and cross-referencing information) to the XML output. Note that +# enabling this will significantly increase the size of the XML output. + +XML_PROGRAMLISTING = YES + +#--------------------------------------------------------------------------- +# configuration options for the AutoGen Definitions output +#--------------------------------------------------------------------------- + +# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will +# generate an AutoGen Definitions (see autogen.sf.net) file +# that captures the structure of the code including all +# documentation. Note that this feature is still experimental +# and incomplete at the moment. + +GENERATE_AUTOGEN_DEF = NO + +#--------------------------------------------------------------------------- +# configuration options related to the Perl module output +#--------------------------------------------------------------------------- + +# If the GENERATE_PERLMOD tag is set to YES Doxygen will +# generate a Perl module file that captures the structure of +# the code including all documentation. Note that this +# feature is still experimental and incomplete at the +# moment. + +GENERATE_PERLMOD = NO + +# If the PERLMOD_LATEX tag is set to YES Doxygen will generate +# the necessary Makefile rules, Perl scripts and LaTeX code to be able +# to generate PDF and DVI output from the Perl module output. + +PERLMOD_LATEX = NO + +# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be +# nicely formatted so it can be parsed by a human reader. +# This is useful +# if you want to understand what is going on. +# On the other hand, if this +# tag is set to NO the size of the Perl module output will be much smaller +# and Perl will parse it just the same. + +PERLMOD_PRETTY = YES + +# The names of the make variables in the generated doxyrules.make file +# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. +# This is useful so different doxyrules.make files included by the same +# Makefile don't overwrite each other's variables. + +PERLMOD_MAKEVAR_PREFIX = + +#--------------------------------------------------------------------------- +# Configuration options related to the preprocessor +#--------------------------------------------------------------------------- + +# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will +# evaluate all C-preprocessor directives found in the sources and include +# files. + +ENABLE_PREPROCESSING = YES + +# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro +# names in the source code. If set to NO (the default) only conditional +# compilation will be performed. Macro expansion can be done in a controlled +# way by setting EXPAND_ONLY_PREDEF to YES. + +MACRO_EXPANSION = NO + +# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES +# then the macro expansion is limited to the macros specified with the +# PREDEFINED and EXPAND_AS_DEFINED tags. + +EXPAND_ONLY_PREDEF = NO + +# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files +# in the INCLUDE_PATH (see below) will be search if a #include is found. + +SEARCH_INCLUDES = YES + +# The INCLUDE_PATH tag can be used to specify one or more directories that +# contain include files that are not input files but should be processed by +# the preprocessor. + +INCLUDE_PATH = + +# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard +# patterns (like *.h and *.hpp) to filter out the header-files in the +# directories. If left blank, the patterns specified with FILE_PATTERNS will +# be used. + +INCLUDE_FILE_PATTERNS = + +# The PREDEFINED tag can be used to specify one or more macro names that +# are defined before the preprocessor is started (similar to the -D option of +# gcc). The argument of the tag is a list of macros of the form: name +# or name=definition (no spaces). If the definition and the = are +# omitted =1 is assumed. To prevent a macro definition from being +# undefined via #undef or recursively expanded use the := operator +# instead of the = operator. + +PREDEFINED = + +# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then +# this tag can be used to specify a list of macro names that should be expanded. +# The macro definition that is found in the sources will be used. +# Use the PREDEFINED tag if you want to use a different macro definition. + +EXPAND_AS_DEFINED = + +# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then +# doxygen's preprocessor will remove all function-like macros that are alone +# on a line, have an all uppercase name, and do not end with a semicolon. Such +# function macros are typically used for boiler-plate code, and will confuse +# the parser if not removed. + +SKIP_FUNCTION_MACROS = YES + +#--------------------------------------------------------------------------- +# Configuration::additions related to external references +#--------------------------------------------------------------------------- + +# The TAGFILES option can be used to specify one or more tagfiles. +# Optionally an initial location of the external documentation +# can be added for each tagfile. The format of a tag file without +# this location is as follows: +# +# TAGFILES = file1 file2 ... +# Adding location for the tag files is done as follows: +# +# TAGFILES = file1=loc1 "file2 = loc2" ... +# where "loc1" and "loc2" can be relative or absolute paths or +# URLs. If a location is present for each tag, the installdox tool +# does not have to be run to correct the links. +# Note that each tag file must have a unique name +# (where the name does NOT include the path) +# If a tag file is not located in the directory in which doxygen +# is run, you must also specify the path to the tagfile here. + +TAGFILES = + +# When a file name is specified after GENERATE_TAGFILE, doxygen will create +# a tag file that is based on the input files it reads. + +GENERATE_TAGFILE = + +# If the ALLEXTERNALS tag is set to YES all external classes will be listed +# in the class index. If set to NO only the inherited external classes +# will be listed. + +ALLEXTERNALS = NO + +# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed +# in the modules index. If set to NO, only the current project's groups will +# be listed. + +EXTERNAL_GROUPS = YES + +# The PERL_PATH should be the absolute path and name of the perl script +# interpreter (i.e. the result of `which perl'). + +PERL_PATH = /usr/bin/perl + +#--------------------------------------------------------------------------- +# Configuration options related to the dot tool +#--------------------------------------------------------------------------- + +# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will +# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base +# or super classes. Setting the tag to NO turns the diagrams off. Note that +# this option is superseded by the HAVE_DOT option below. This is only a +# fallback. It is recommended to install and use dot, since it yields more +# powerful graphs. + +CLASS_DIAGRAMS = YES + +# You can define message sequence charts within doxygen comments using the \msc +# command. Doxygen will then run the mscgen tool (see +# http://www.mcternan.me.uk/mscgen/) to produce the chart and insert it in the +# documentation. The MSCGEN_PATH tag allows you to specify the directory where +# the mscgen tool resides. If left empty the tool is assumed to be found in the +# default search path. + +MSCGEN_PATH = + +# If set to YES, the inheritance and collaboration graphs will hide +# inheritance and usage relations if the target is undocumented +# or is not a class. + +HIDE_UNDOC_RELATIONS = YES + +# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is +# available from the path. This tool is part of Graphviz, a graph visualization +# toolkit from AT&T and Lucent Bell Labs. The other options in this section +# have no effect if this option is set to NO (the default) + +HAVE_DOT = NO + +# By default doxygen will write a font called FreeSans.ttf to the output +# directory and reference it in all dot files that doxygen generates. This +# font does not include all possible unicode characters however, so when you need +# these (or just want a differently looking font) you can specify the font name +# using DOT_FONTNAME. You need need to make sure dot is able to find the font, +# which can be done by putting it in a standard location or by setting the +# DOTFONTPATH environment variable or by setting DOT_FONTPATH to the directory +# containing the font. + +DOT_FONTNAME = FreeSans + +# The DOT_FONTSIZE tag can be used to set the size of the font of dot graphs. +# The default size is 10pt. + +DOT_FONTSIZE = 10 + +# By default doxygen will tell dot to use the output directory to look for the +# FreeSans.ttf font (which doxygen will put there itself). If you specify a +# different font using DOT_FONTNAME you can set the path where dot +# can find it using this tag. + +DOT_FONTPATH = + +# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for each documented class showing the direct and +# indirect inheritance relations. Setting this tag to YES will force the +# the CLASS_DIAGRAMS tag to NO. + +CLASS_GRAPH = YES + +# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for each documented class showing the direct and +# indirect implementation dependencies (inheritance, containment, and +# class references variables) of the class with other documented classes. + +COLLABORATION_GRAPH = YES + +# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for groups, showing the direct groups dependencies + +GROUP_GRAPHS = YES + +# If the UML_LOOK tag is set to YES doxygen will generate inheritance and +# collaboration diagrams in a style similar to the OMG's Unified Modeling +# Language. + +UML_LOOK = NO + +# If set to YES, the inheritance and collaboration graphs will show the +# relations between templates and their instances. + +TEMPLATE_RELATIONS = NO + +# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT +# tags are set to YES then doxygen will generate a graph for each documented +# file showing the direct and indirect include dependencies of the file with +# other documented files. + +INCLUDE_GRAPH = YES + +# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and +# HAVE_DOT tags are set to YES then doxygen will generate a graph for each +# documented header file showing the documented files that directly or +# indirectly include this file. + +INCLUDED_BY_GRAPH = YES + +# If the CALL_GRAPH and HAVE_DOT options are set to YES then +# doxygen will generate a call dependency graph for every global function +# or class method. Note that enabling this option will significantly increase +# the time of a run. So in most cases it will be better to enable call graphs +# for selected functions only using the \callgraph command. + +CALL_GRAPH = NO + +# If the CALLER_GRAPH and HAVE_DOT tags are set to YES then +# doxygen will generate a caller dependency graph for every global function +# or class method. Note that enabling this option will significantly increase +# the time of a run. So in most cases it will be better to enable caller +# graphs for selected functions only using the \callergraph command. + +CALLER_GRAPH = NO + +# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen +# will graphical hierarchy of all classes instead of a textual one. + +GRAPHICAL_HIERARCHY = YES + +# If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT tags are set to YES +# then doxygen will show the dependencies a directory has on other directories +# in a graphical way. The dependency relations are determined by the #include +# relations between the files in the directories. + +DIRECTORY_GRAPH = YES + +# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images +# generated by dot. Possible values are png, jpg, or gif +# If left blank png will be used. + +DOT_IMAGE_FORMAT = png + +# The tag DOT_PATH can be used to specify the path where the dot tool can be +# found. If left blank, it is assumed the dot tool can be found in the path. + +DOT_PATH = + +# The DOTFILE_DIRS tag can be used to specify one or more directories that +# contain dot files that are included in the documentation (see the +# \dotfile command). + +DOTFILE_DIRS = + +# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of +# nodes that will be shown in the graph. If the number of nodes in a graph +# becomes larger than this value, doxygen will truncate the graph, which is +# visualized by representing a node as a red box. Note that doxygen if the +# number of direct children of the root node in a graph is already larger than +# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note +# that the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH. + +DOT_GRAPH_MAX_NODES = 50 + +# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the +# graphs generated by dot. A depth value of 3 means that only nodes reachable +# from the root by following a path via at most 3 edges will be shown. Nodes +# that lay further from the root node will be omitted. Note that setting this +# option to 1 or 2 may greatly reduce the computation time needed for large +# code bases. Also note that the size of a graph can be further restricted by +# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction. + +MAX_DOT_GRAPH_DEPTH = 0 + +# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent +# background. This is disabled by default, because dot on Windows does not +# seem to support this out of the box. Warning: Depending on the platform used, +# enabling this option may lead to badly anti-aliased labels on the edges of +# a graph (i.e. they become hard to read). + +DOT_TRANSPARENT = NO + +# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output +# files in one run (i.e. multiple -o and -T options on the command line). This +# makes dot run faster, but since only newer versions of dot (>1.8.10) +# support this, this feature is disabled by default. + +DOT_MULTI_TARGETS = NO + +# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will +# generate a legend page explaining the meaning of the various boxes and +# arrows in the dot generated graphs. + +GENERATE_LEGEND = YES + +# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will +# remove the intermediate dot files that are used to generate +# the various graphs. + +DOT_CLEANUP = YES + +#--------------------------------------------------------------------------- +# Options related to the search engine +#--------------------------------------------------------------------------- + +# The SEARCHENGINE tag specifies whether or not a search engine should be +# used. If set to NO the values of all tags below this one will be ignored. + +SEARCHENGINE = NO diff --git a/iipsrv/fcgi/LICENSE.TERMS b/iipsrv/fcgi/LICENSE.TERMS new file mode 100644 index 0000000..7e6bdfd --- /dev/null +++ b/iipsrv/fcgi/LICENSE.TERMS @@ -0,0 +1,28 @@ +This FastCGI application library source and object code (the +"Software") and its documentation (the "Documentation") are +copyrighted by Open Market, Inc ("Open Market"). The following terms +apply to all files associated with the Software and Documentation +unless explicitly disclaimed in individual files. + +Open Market permits you to use, copy, modify, distribute, and license +this Software and the Documentation for any purpose, provided that +existing copyright notices are retained in all copies and that this +notice is included verbatim in any distributions. No written +agreement, license, or royalty fee is required for any of the +authorized uses. Modifications to this Software and Documentation may +be copyrighted by their authors and need not follow the licensing +terms described here. If modifications to this Software and +Documentation have new licensing terms, the new terms must be clearly +indicated on the first page of each file where they apply. + +OPEN MARKET MAKES NO EXPRESS OR IMPLIED WARRANTY WITH RESPECT TO THE +SOFTWARE OR THE DOCUMENTATION, INCLUDING WITHOUT LIMITATION ANY +WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. IN +NO EVENT SHALL OPEN MARKET BE LIABLE TO YOU OR ANY THIRD PARTY FOR ANY +DAMAGES ARISING FROM OR RELATING TO THIS SOFTWARE OR THE +DOCUMENTATION, INCLUDING, WITHOUT LIMITATION, ANY INDIRECT, SPECIAL OR +CONSEQUENTIAL DAMAGES OR SIMILAR DAMAGES, INCLUDING LOST PROFITS OR +LOST DATA, EVEN IF OPEN MARKET HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. THE SOFTWARE AND DOCUMENTATION ARE PROVIDED "AS IS". +OPEN MARKET HAS NO LIABILITY IN CONTRACT, TORT, NEGLIGENCE OR +OTHERWISE ARISING OUT OF THIS SOFTWARE OR THE DOCUMENTATION. diff --git a/iipsrv/fcgi/Makefile.am b/iipsrv/fcgi/Makefile.am new file mode 100644 index 0000000..8192ca3 --- /dev/null +++ b/iipsrv/fcgi/Makefile.am @@ -0,0 +1,91 @@ +# +# Makefile for FastCGI development kit +# +# $Id: Makefile.am,v 1.7 2001/12/22 13:05:39 robs Exp $ +# + +SUBDIRS = libfcgi include #examples cgi-fcgi + +include_HEADERS = fcgi_config.h + +EXTRA_DIST = LICENSE.TERMS \ + Makefile.nt \ + cgi-fcgi/cgi-fcgi.mak \ + examples/authorizer.mak \ + examples/echo.mak \ + examples/echox.mak \ + examples/size.mak \ + examples/echo-cpp.mak \ + libfcgi/libfcgi.mak \ + images/aplib-hd.gif \ + images/divider.gif \ + images/fcgi-hd.gif \ + images/mail-hd.gif \ + images/navbar.gif \ + images/serv-hd.gif \ + images/words-hd.gif \ + include/fcgi_config_x86.h \ + java/FCGIGlobalDefs.java \ + java/FCGIInputStream.java \ + java/FCGIInterface.java \ + java/FCGIMessage.java \ + java/FCGIOutputStream.java \ + java/FCGIRequest.java \ + libfcgi/os_unix.c \ + libfcgi/os_win32.c \ + perl/ChangeLog \ + perl/FCGI.PL \ + perl/FCGI.XL \ + perl/MANIFEST \ + perl/Makefile.PL \ + perl/README \ + perl/aclocal.m4 \ + perl/configure \ + perl/configure.in \ + perl/echo.PL \ + perl/fcgi_config.h.in \ + perl/oldinterface.pod \ + perl/remote.PL \ + perl/threaded.PL \ + perl/typemap \ + perl/version.pm \ + Win32/FastCGI.dsw \ + Win32/authorizer.dsp \ + Win32/cgifcgi.dsp \ + Win32/echo-cpp.dsp \ + Win32/echo.dsp \ + Win32/echox.dsp \ + Win32/libfcgi.dsp \ + Win32/logdump.dsp \ + Win32/size.dsp \ + Win32/threaded.dsp \ + doc/FCGI_Accept.3 \ + doc/FCGI_Finish.3 \ + doc/FCGI_SetExitStatus.3 \ + doc/FCGI_StartFilterData.3 \ + doc/cgi-fcgi.1 \ + doc/fcgi-devel-kit.htm \ + doc/fcgi-java.htm \ + doc/fcgi-perf.htm \ + doc/fcgi-perl.htm \ + doc/fcgi-spec.html \ + doc/fcgi-tcl.htm \ + doc/omi-logo.gif \ + doc/overview.html \ + doc/www5-api-workshop.html \ + doc/fastcgi-prog-guide/ap_guida.htm \ + doc/fastcgi-prog-guide/ap_guide.htm \ + doc/fastcgi-prog-guide/apaman.htm \ + doc/fastcgi-prog-guide/ch1inta1.gif \ + doc/fastcgi-prog-guide/ch1intra.gif \ + doc/fastcgi-prog-guide/ch1intro.htm \ + doc/fastcgi-prog-guide/ch2c.htm \ + doc/fastcgi-prog-guide/ch3perl.htm \ + doc/fastcgi-prog-guide/ch4tcl.htm \ + doc/fastcgi-prog-guide/cover.htm \ + doc/fastcgi-prog-guide/covera.gif \ + doc/fastcgi-whitepaper/fastcgi.htm \ + doc/fastcgi-whitepaper/img00001.gif \ + doc/fastcgi-whitepaper/img00002.gif \ + doc/fastcgi-whitepaper/img00003.gif + diff --git a/iipsrv/fcgi/Makefile.nt b/iipsrv/fcgi/Makefile.nt new file mode 100644 index 0000000..7da07a4 --- /dev/null +++ b/iipsrv/fcgi/Makefile.nt @@ -0,0 +1,47 @@ +# +# Windows Makefile for FastCGI development kit +# +# $Id: Makefile.nt,v 1.4 2001/11/27 14:02:54 robs Exp $ +# + +!IF "$(CFG)" == "" +CFG=release +!ENDIF + +all: "include\fcgi_config.h" + cd ".\libfcgi" + $(MAKE) $(MAKEFLAGS) /NOLOGO /F libfcgi.mak CFG=$(CFG) $@ + + cd ".\..\cgi-fcgi" + $(MAKE) $(MAKEFLAGS) /NOLOGO /F cgi-fcgi.mak CFG=$(CFG) $@ + + cd ".\..\examples" + $(MAKE) $(MAKEFLAGS) /NOLOGO /F authorizer.mak CFG=$(CFG) $@ + $(MAKE) $(MAKEFLAGS) /NOLOGO /F echo.mak CFG=$(CFG) $@ + $(MAKE) $(MAKEFLAGS) /NOLOGO /F echox.mak CFG=$(CFG) $@ + $(MAKE) $(MAKEFLAGS) /NOLOGO /F size.mak CFG=$(CFG) $@ + $(MAKE) $(MAKEFLAGS) /NOLOGO /F echo-cpp.mak CFG=$(CFG) $@ + + cd ".\.." + +"include\fcgi_config.h": "include\fcgi_config_x86.h" + copy "include\fcgi_config_x86.h" "include\fcgi_config.h" + +clean: + cd ".\libfcgi" + $(MAKE) $(MAKEFLAGS) /NOLOGO /F libfcgi.mak CFG=$(CFG) $@ + + cd ".\..\cgi-fcgi" + $(MAKE) $(MAKEFLAGS) /NOLOGO /F cgi-fcgi.mak CFG=$(CFG) $@ + + cd ".\..\examples" + $(MAKE) $(MAKEFLAGS) /NOLOGO /F authorizer.mak CFG=$(CFG) $@ + $(MAKE) $(MAKEFLAGS) /NOLOGO /F echo.mak CFG=$(CFG) $@ + $(MAKE) $(MAKEFLAGS) /NOLOGO /F echox.mak CFG=$(CFG) $@ + $(MAKE) $(MAKEFLAGS) /NOLOGO /F size.mak CFG=$(CFG) $@ + $(MAKE) $(MAKEFLAGS) /NOLOGO /F echo-cpp.mak CFG=$(CFG) $@ + + cd ".\.." + +install: + @echo "Sorry, the install target hasn't been written yet" diff --git a/iipsrv/fcgi/README b/iipsrv/fcgi/README new file mode 100644 index 0000000..6cd00f1 --- /dev/null +++ b/iipsrv/fcgi/README @@ -0,0 +1,400 @@ +FastCGI Developer's Kit README +------------------------------ + + $Id: README,v 1.21 2003/01/19 17:19:41 robs Exp $ + Copyright (c) 1996 Open Market, Inc. + See the file "LICENSE.TERMS" for information on usage and redistribution + of this file, and for a DISCLAIMER OF ALL WARRANTIES. + +Basic Directions +---------------- + +Unix: + + ./configure + make + make install + +Win32: + + nmake -f Makefile.nt + + (or use the MSVC++ project files in the Win32 directory) + + +CHANGES +------- + +For more detail regarding changes, please consult the cvs log available +on http://fastcgi.com/. + + +2.4.0 +----- + + *) When closing connections, shutdown() the send side of TCP sockets to + prevent a TCP RST from trashing the reciept of data on the client (when + the client continues to send data to the application). + + *) [WIN32] force an exit from the ShutdownRequestThread when a shutdown is + signaled and NamedPipes are in use. + + *) Use streamsize and char_type in the C++ API. + + *) [WIN32] Eliminate the (partial and broken) use of OverlappedIO - this + was causing a loose spin in acceptNamedPipe(). + + *) Fix a bug that caused an assert to pop when an async file descriptor was + numbered greater than 16. Kevin Eye [eye@buffalo.edu] + + *) Update the echo-cpp example to show the restoral of the original + streambufs. Trub, Vladimir [vtrub@purolator.com] + + *) Fix a bug a that caused the lib to crash under certain circumstances + when an error occured on a read + + *) Test for iostreams that support a streambuf assigment operator + + *) (WIN32) Fixed initialization of the accept mutex when OpenSocket() was used. + Niklas Bergh [niklas.bergh@tific.com] + + +2.2.2 +----- + + *) Added support for shared libraries. + + *) Added support for a graceful shutdown via an event under Win32. + + *) Added default signal handlers for PIPE, USR1, and TERM. + + *) Fix some minor bugs in the 0S_ layer. + + *) Fixed the C++ streambuf implementation. + + +Changes with devkit 2.1.1 +------------------------- + + *) Fixed an unintentional sign extension during promotion in Java's + FCGIInputStream.read(). Takayuki Tachikawa + + *) Cleaned up warnings in examples (mostly main() complaints). + + *) Removed examples/tiny-cgi.c (it wasn't a FastCGI application?!). + + *) Remove some debugging code and clean up some gcc warnings in cgi-fcgi.c. + + *) Add multithread support to the fcgiapp lib and an example multithreaded + application, threaded.c. Based on work by Dennis Payne + and Gene Sokolov . + + *) Remove the printf() and #include of stdio.h from examples/echo2.c. + + *) Remove the static initialization of _fcgi_sF[] because on glibc 2.x based + systems stdin/stdout/stderr are no longer static. + + *) Flush FastCGI buffers at application exit. + + << INSERT OTHER STUFF HERE >> + + +What's New: Version 2.0b2, 04 April 1997 +-------------------------------------- + +Some additional bug fixes, mostly on NT port. The following list +of the bugs that have been and fixed: + 1. Updated build_no_shell.bat to create a FcgiBin directory under the + top level of the FastCGI kit and copy all executables and the + FastCGI dll there. This makes it easier to use. + 2. Corrected the Unix version of OS_SpawnChild so that it didn't close + the listenFd when forking off child processes. This code would + affect the cgi-fcgi application on Unix. The problem is that it + could only start one fastcgi process. Any other processes would not + get the listen file descriptor and they would die. + 3. Corrected cgi-fcgi.c so that it properly handled large posts. The + bug was introduced with the asynchronous I/O model implemented for + the Windows NT port. The problem was not clearing a bit indicating + that a read had completed. This caused the application to stall. + 4. Corrected OS_DoIo, the function used for scheduling I/O for cgi-fcgi. + It had a bug where it wasn't creating a copy of the file descriptors + used for I/O. This would cause the master list of FDs to watch to be + reset and thus would hang the application because we would no longer + watch for I/O on those file descriptors. (This problem was specific to + Unix and only happened with the cgi-fcgi application.) + 5. Cleaned up several compilation warnings present on OSF. + + +What's New: Version 2.0b1, 24 March 1997 +-------------------------------------- + +This "beta" release adds the functionality of "cgi-fcgi" to the +Windows NT platform and allows for creation of FastCGI applications +running in Win32 environment. There is almost no new documentation +provided, but will become part of this kit in the official release. + 1. Added FastCGI libraries running on Windows NT 3.51+ + 2. Rename errno to FCGI_errno in the FCGX_Stream, which was causing + problems on some Linux platforms and NT. + 3. Fixed a parenthesis problem in FCGI_gets + + +What's New: Version 1.5.1, 12 December 1996 +-------------------------------------- + +This release introduces mostly bug fixes, without any additional +functionality to the kit. + 1. Conditional compilation for the hp-ux compiler. + 2. Loop around the accept() call to eliminate "OS Error: Interrupted + System Call" message from appearing in the error logs. + 3. Casting of the FCGI_Header to (char *), which eliminates the + assertion failure "bufPtr->size>0". + + +What's New: Version 1.5, 12 June 1996 +-------------------------------------- + +General: + + Added a white paper on FastCGI application performance to the + doc directory. Generally brought the other docs up to date. + + Rearranged the kit to put more emphasis on running FastCGI-capable + servers and less on running cgi-fcgi. Added + examples/conf/om-httpd.config, a config file that demonstrates all + of the example apps. (Would like to have similar configs for NCSA + and Apache.) + + Added the tiny-authorizer and sample-store applications to + the examples. These are explained in the index.html. + + In addition to everything else it does, sample-store demonstrates + a bug in the Open Market WebServer 2.0: When an Authorizer + application denies access, the server tacks some extra junk onto + the end of the page the application returns. A little ugly but + not fatal. + +C libraries: + + Added the functions FCGX_Finish and FCGI_Finish. These functions + finish the current request from the HTTP server but do not begin a + new request. These functions make it possible for applications to + perform other processing between requests. An application must not + use its stdin, stdout, stderr, or environ between calling + FCGI_Finish and calling FCGI_Accept. See doc/FCGI_Finish.3 for + more information. The application examples/sample-store.c demonstrates + the use of FCGI_Finish. + + Added conditional 'extern "C"' stuff to the .h files fcgi_stdio.h, + fcgiapp.h, and fcgiappmisc.h for the benefit of C++ applications + (suggested by Jim McCarthy). + + Fixed two bugs in FCGX_VFPrintF (reported by Ben Laurie). These + bugs affected processing of %f format specifiers and of all format + specifiers containing a precision spec (e.g "%12.4g"). + + Fixed a bug in FCGX_Accept in which the environment variable + FCGI_WEBSERVER_ADDRS was being read rather than the specified + FCGI_WEB_SERVER_ADDRS. Fixed a bug in FCGX_Accept in which the + wrong storage was freed when FCGI_WEB_SERVER_ADDRS contained more + than one address or if the address check failed. + + Changed FCGX_Accept to avoid depending upon accept(2) returning the + correct value of sin_family in the socketaddr structure for an + AF_UNIX connection (SCO returns the wrong value, as reported by Paul + Mahoney). + + Changed the error retry logic in FCGX_Accept. FCGX_Accept now + returns -1 only in case of operating system errors that occur while + accepting a connection (e.g. out of file descriptors). Other errors + cause the current connection to be dropped and a new connection to + be attempted. + +Perl: + + Changed FCGI.xs to make it insensitive to Perl's treatment of + environ (we hope). Changed FCGI::accept so the initial environment + variables are not unset on the first call to FCGI::accept (or on + subsequent calls either). Added the echo-perl example + program. Added a workaround for the "empty initial environment bug" + to tiny-perl-fcgi. Changed the example Perl scripts to use a new + symbolic link ./perl, avoiding the HP-UX 32 character limit on the + first line of a command interpreter file. + + Because the FastCGI-enabled Perl interpreter uses the C fcgi_stdio + library, it picks up all the changes listed above for C. There's + a new Perl subroutine FCGI::finish. + +Tcl: + + Fixed a bug in tclFCGI.c that caused the request environment + variables to be lost. Changed FCGI_Accept so the initial + environment variables are not unset on the first call to FCGI_Accept + (or on subsequent calls either). Added the echo-tcl example + program. Fixed another bug that caused Tcl to become confused by + file opens; as a side effect of this change, writes to stdout/stderr + that occur in an app running as FastCGI before FCGI_Accept is called + are no-ops rather than crashing Tcl. Changed the example Tcl + scripts to use a new symbolic link ./tclsh, avoiding the HP-UX 32 + character limit on the first line of a command interpreter file. + + Because the FastCGI-enabled Tcl interpreter uses the C fcgi_stdio + library, it picks up all the changes listed above for C; there's + a new Tcl command FCGI_Finish. + +Java: + + Fixed a sign-extension bug in FCGIMessage.java that caused bad encodings + of names and values in name-value pairs for lengths in [128..255]. + Made small cleanups in the Java example programs to make them more + consistent with the other examples. + + + +What's New: Version 1.4, 10 May 1996 +-------------------------------------- + +Includes Java classes and Java examples. + + + +What's New: Version 1.3.1, 6 May 1996 +-------------------------------------- + +New, simplified, license terms. Includes an expanded whitepaper that +describes FastCGI support in Open Market's Secure WebServer 2.0. +Includes Open Market FastCGI 1.0 Programmer's Guide. Includes +"FastCGI: A High-Performance Gateway Interface", a position paper +presented at the workshop "Programming the Web - a search for APIs", +Fifth International World Wide Web Conference, 6 May 1996, Paris, +France. + + + +What's New: Version 1.3, 29 April 1996 +-------------------------------------- + +First public release; new license terms on all files. + +Changed cgi-fcgi.c to use SO_REUSEADDR when creating the listening socket; +this avoids the need to wait through the TIME_WAIT state on all the TCP +connections made by the previous instance of an external application +you are restarting. + + + +What's New: Version 1.2.2, 15 April 1996 +---------------------------------------- + +Partially fixed a bug in Perl's FCGI::accept (source file FCGI.xs). +The per-request environment variables were being lost. Now the +per-request environment variables show up correctly, except that if +the Perl application has an empty initial environment, the environment +variables associated with the *first* request are lost. Therefore, +when starting Perl, always set some environment variable using the +AppClass -initial-env option, or by running cgi-fcgi in a non-empty +environment. + + + +What's New: Version 1.2.1, 22 March 1996 +---------------------------------------- + +Fixed a bug in FCGI_Accept. If your application running as FastCGI +opened a file before calling FCGI_Accept, it would decide that it +was really running as CGI. Things went downhill quickly after that! + +Also added advisory locking to serialize calls to accept on shared +listening sockets on Solaris and IRIX, to work around problems +with concurrent accept calls on these platforms. + + + +What's New: Version 1.2, 20 March 1996 +-------------------------------------- + +1. This version of the kit implements the most recent draft +of the protocol spec. Enhancements to the protocol include +a BEGIN_REQUEST record that simplifies request ID management +and transmits role and keep-alive information, and a simplified +end-of-stream indication. + +The protocol spec has been revised to describe exactly what's +been implemented, leaving out the features that we hope to +introduce in later releases. + +At the application level, the visible change is the FCGI_ROLE +variable that's available to applications. This allows an application +to check that it has been invoked in the expected role. A single +application can be written to respond in several roles. The +FCGI_Accept.3 manpage contains more information. + +2. We introduced the new "module" prefix FCGX in order to simplify +the relationship between fcgi_stdio and fcgiapp. + +A growing number of functions are provided in both fcgi_stdio and +fcgiapp versions. Rather than inventing an ad hoc solution for each +naming conflict (as we did with FCGI_accept and FCGI_Accept), we've +bitten the bullet and systematically renamed *all* the fcgapp +primitives with the prefix FCGX_. In fcgi_stdio, we've renamed +FCGI_accept to FCGI_Accept. So all functions that are common in the +two libraries have the same name modulo the different prefixes. + +The Accept function visible in Tcl is now called FCGI_Accept, not +FCGI_accept. + +The Accept function visible in Perl is now FCGI::accept. All +lower case names for functions and all upper case names for +modules appears to be a Perl convention, so we conform. + +3. The kit now fully supports the Responder, Authorizer, +and Filter roles. + +The Filter role required a new function, FCGI_StartFilterData. +FCGI_StartFilterData changes the input stream from reading +FCGI_STDIN data to reading FCGI_DATA data. The manpage +gives full details. + +Another new function, FCGI_SetExitStatus, is primarily for +the Responder role but is available to all. FCGI_SetExitStatus +allows an application to set a nonzero "exit" status +before completing a request and calling FCGI_Accept again. +The manpage gives full details. + +These two new functions are provided at both the fcgi_stdio interface +and the basic fcgiapp interface. Naturally, the fcgiapp versions are +called FCGX_StartFilterData and FCGX_SetExitStatus. + +4. The fcgiapp interface changed slightly in order to treat +the streams and environment data more symmetrically. + +FCGX_Accept now returns an environment pointer, rather than requiring +a call to FCGX_GetAllParams to retrieve an environment pointer. +FCGX_GetParam takes an explicit environment pointer argument. +FCGX_GetAllParams is eliminated. See the documentation in the header +file for complete information. + +fcgiapp also added the procedure FCGX_IsCGI, providing a standardized +test of whether the app was started as CGI or FastCGI. + +5. We've ported the kits to vendor-supported ANSI C compilers +on Sun (Solaris 2.X), HP, and Digital platforms. GCC can be +selected on these platforms by performing SETENV CC gcc before +running configure. + + + +What's New: Version 1.1, 30 Jan 1996 +------------------------------------ + +1. More platforms: Digital UNIX, IBM AIX, Silicon Graphics IRIX, +Sun SunOS 4.1.4. + +2. Perl and Tcl: Simple recipes for producing Perl and Tcl +interpreters that run as FastCGI applications. No source +code changes are needed to Perl and Tcl. Documented +in separate documents, accessible via the index page. + + + +Version 1.0, 10 Jan 1996 +------------------------ diff --git a/iipsrv/fcgi/Win32/FastCGI.dsw b/iipsrv/fcgi/Win32/FastCGI.dsw new file mode 100644 index 0000000..114606d --- /dev/null +++ b/iipsrv/fcgi/Win32/FastCGI.dsw @@ -0,0 +1,164 @@ +Microsoft Developer Studio Workspace File, Format Version 6.00 +# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! + +############################################################################### + +Project: "authorizer"=".\authorizer.dsp" - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ + Begin Project Dependency + Project_Dep_Name libfcgi + End Project Dependency +}}} + +############################################################################### + +Project: "cgifcgi"=".\cgifcgi.dsp" - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ + Begin Project Dependency + Project_Dep_Name libfcgi + End Project Dependency +}}} + +############################################################################### + +Project: "config_h"=".\config_h.dsp" - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "echo"=".\echo.dsp" - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ + Begin Project Dependency + Project_Dep_Name libfcgi + End Project Dependency +}}} + +############################################################################### + +Project: "echo_cpp"=".\echo-cpp.dsp" - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ + Begin Project Dependency + Project_Dep_Name libfcgi + End Project Dependency +}}} + +############################################################################### + +Project: "echox"=".\echox.dsp" - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ + Begin Project Dependency + Project_Dep_Name libfcgi + End Project Dependency +}}} + +############################################################################### + +Project: "libfcgi"=".\libfcgi.dsp" - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ + Begin Project Dependency + Project_Dep_Name config_h + End Project Dependency +}}} + +############################################################################### + +Project: "logdump"=".\logdump.dsp" - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ + Begin Project Dependency + Project_Dep_Name libfcgi + End Project Dependency +}}} + +############################################################################### + +Project: "size"=".\size.dsp" - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ + Begin Project Dependency + Project_Dep_Name libfcgi + End Project Dependency +}}} + +############################################################################### + +Project: "threaded"=".\threaded.dsp" - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ + Begin Project Dependency + Project_Dep_Name libfcgi + End Project Dependency +}}} + +############################################################################### + +Global: + +Package=<5> +{{{ +}}} + +Package=<3> +{{{ +}}} + +############################################################################### + diff --git a/iipsrv/fcgi/Win32/authorizer.dsp b/iipsrv/fcgi/Win32/authorizer.dsp new file mode 100644 index 0000000..ed2fc5d --- /dev/null +++ b/iipsrv/fcgi/Win32/authorizer.dsp @@ -0,0 +1,108 @@ +# Microsoft Developer Studio Project File - Name="authorizer" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102 + +CFG=authorizer - 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 "authorizer.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 "authorizer.mak" CFG="authorizer - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "authorizer - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE "authorizer - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +MTL=midl.exe +RSC=rc.exe + +!IF "$(CFG)" == "authorizer - 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 "..\examples\authorizer\Release" +# PROP Intermediate_Dir "..\examples\authorizer\Release" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "LIB_EXPORTS" /YX /FD /c +# ADD CPP /nologo /MD /W3 /Gi /O2 /Ob2 /I "..\include" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# SUBTRACT CPP /Fr +# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# 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 libfcgi.lib /nologo /pdb:none /machine:IX86 /libpath:"..\libfcgi\Release" + +!ELSEIF "$(CFG)" == "authorizer - 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 "..\examples/authorizer/Debug" +# PROP Intermediate_Dir "..\examples/authorizer/Debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "LIB_EXPORTS" /YX /FD /GZ /c +# ADD CPP /nologo /MDd /W4 /Gm /Gi /ZI /Od /I "..\include" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /FR /YX /FD /GZ /c +# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# 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 libfcgi.lib /nologo /profile /debug /machine:IX86 /libpath:"..\libfcgi\Debug" + +!ENDIF + +# Begin Target + +# Name "authorizer - Win32 Release" +# Name "authorizer - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=..\examples\authorizer.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/iipsrv/fcgi/Win32/cgifcgi.dsp b/iipsrv/fcgi/Win32/cgifcgi.dsp new file mode 100644 index 0000000..c522a21 --- /dev/null +++ b/iipsrv/fcgi/Win32/cgifcgi.dsp @@ -0,0 +1,108 @@ +# Microsoft Developer Studio Project File - Name="cgifcgi" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102 + +CFG=cgifcgi - 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 "cgifcgi.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 "cgifcgi.mak" CFG="cgifcgi - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "cgifcgi - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE "cgifcgi - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +MTL=midl.exe +RSC=rc.exe + +!IF "$(CFG)" == "cgifcgi - 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 "..\cgi-fcgi\Release" +# PROP Intermediate_Dir "..\cgi-fcgi\Release" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "LIB_EXPORTS" /YX /FD /c +# ADD CPP /nologo /MD /W3 /Gi /O2 /Ob2 /I "..\include" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# SUBTRACT CPP /Fr +# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# 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 libfcgi.lib /nologo /pdb:none /machine:IX86 /out:"..\cgi-fcgi\Release\cgi-fcgi.exe" /libpath:"..\libfcgi\Release" + +!ELSEIF "$(CFG)" == "cgifcgi - 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 "../cgi-fcgi/Debug" +# PROP Intermediate_Dir "../cgi-fcgi/Debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "LIB_EXPORTS" /YX /FD /GZ /c +# ADD CPP /nologo /MDd /W4 /Gm /Gi /ZI /Od /I "..\include" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /FR /YX /FD /GZ /c +# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# 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 libfcgi.lib /nologo /profile /debug /machine:IX86 /out:"..\cgi-fcgi\Debug\cgi-fcgi.exe" /libpath:"..\libfcgi\Debug" + +!ENDIF + +# Begin Target + +# Name "cgifcgi - Win32 Release" +# Name "cgifcgi - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE="..\cgi-fcgi\cgi-fcgi.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/iipsrv/fcgi/Win32/echo-cpp.dsp b/iipsrv/fcgi/Win32/echo-cpp.dsp new file mode 100644 index 0000000..7f44ebf --- /dev/null +++ b/iipsrv/fcgi/Win32/echo-cpp.dsp @@ -0,0 +1,108 @@ +# Microsoft Developer Studio Project File - Name="echo_cpp" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102 + +CFG=echo_cpp - 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 "echo-cpp.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 "echo-cpp.mak" CFG="echo_cpp - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "echo_cpp - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE "echo_cpp - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +MTL=midl.exe +RSC=rc.exe + +!IF "$(CFG)" == "echo_cpp - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "echo-cpp\Release" +# PROP BASE Intermediate_Dir "echo-cpp\Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "..\examples\echo-cpp\Release" +# PROP Intermediate_Dir "..\examples\echo-cpp\Release" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "LIB_EXPORTS" /YX /FD /c +# ADD CPP /nologo /MD /W3 /Gi /GX /O2 /Ob2 /I "..\include" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# SUBTRACT CPP /Fr +# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# 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 libfcgi.lib /nologo /pdb:none /machine:IX86 /libpath:"..\libfcgi\Release" + +!ELSEIF "$(CFG)" == "echo_cpp - 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 "../examples/echo-cpp\Debug" +# PROP Intermediate_Dir "../examples/echo-cpp\Debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "LIB_EXPORTS" /YX /FD /GZ /c +# ADD CPP /nologo /MDd /W3 /Gm /Gi /GX /ZI /Od /I "..\include" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /FR /YX /FD /GZ /c +# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# 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 libfcgi.lib /nologo /profile /debug /machine:IX86 /libpath:"..\libfcgi\Debug" + +!ENDIF + +# Begin Target + +# Name "echo_cpp - Win32 Release" +# Name "echo_cpp - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE="..\examples\echo-cpp.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/iipsrv/fcgi/Win32/echo.dsp b/iipsrv/fcgi/Win32/echo.dsp new file mode 100644 index 0000000..d7e9410 --- /dev/null +++ b/iipsrv/fcgi/Win32/echo.dsp @@ -0,0 +1,109 @@ +# Microsoft Developer Studio Project File - Name="echo" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102 + +CFG=echo - 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 "echo.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 "echo.mak" CFG="echo - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "echo - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE "echo - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +MTL=midl.exe +RSC=rc.exe + +!IF "$(CFG)" == "echo - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "echo\Release" +# PROP BASE Intermediate_Dir "echo\Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "..\examples\echo\Release" +# PROP Intermediate_Dir "..\examples\echo\Release" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "LIB_EXPORTS" /YX /FD /c +# ADD CPP /nologo /MD /W3 /Gi /GX- /O2 /Ob2 /I "..\include" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# SUBTRACT CPP /Fr +# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# 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 libfcgi.lib /nologo /pdb:none /machine:IX86 /libpath:"..\libfcgi\Release" + +!ELSEIF "$(CFG)" == "echo - 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 "../examples/echo\Debug" +# PROP Intermediate_Dir "../examples/echo\Debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "LIB_EXPORTS" /YX /FD /GZ /c +# ADD CPP /nologo /MDd /W4 /Gm /Gi /GX- /ZI /Od /I "..\include" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /FR /YX /FD /GZ /c +# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# 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 libfcgi.lib /nologo /profile /map /debug /machine:IX86 /libpath:"..\libfcgi\Debug" +# SUBTRACT LINK32 /verbose + +!ENDIF + +# Begin Target + +# Name "echo - Win32 Release" +# Name "echo - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=..\examples\echo.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/iipsrv/fcgi/Win32/echox.dsp b/iipsrv/fcgi/Win32/echox.dsp new file mode 100644 index 0000000..77e7870 --- /dev/null +++ b/iipsrv/fcgi/Win32/echox.dsp @@ -0,0 +1,108 @@ +# Microsoft Developer Studio Project File - Name="echox" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102 + +CFG=echox - 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 "echox.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 "echox.mak" CFG="echox - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "echox - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE "echox - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +MTL=midl.exe +RSC=rc.exe + +!IF "$(CFG)" == "echox - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "echo-x\Release" +# PROP BASE Intermediate_Dir "echo-x\Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "..\examples\echo-x\Release" +# PROP Intermediate_Dir "..\examples\echo-x\Release" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "LIB_EXPORTS" /YX /FD /c +# ADD CPP /nologo /MD /W3 /Gi /GX- /O2 /Ob2 /I "..\include" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# SUBTRACT CPP /Fr +# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# 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 libfcgi.lib /nologo /pdb:none /machine:IX86 /out:"..\examples\echo-x\Release\echo-x.exe" /libpath:"..\libfcgi\Release" + +!ELSEIF "$(CFG)" == "echox - 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 "../examples/echo-x\Debug" +# PROP Intermediate_Dir "../examples/echo-x\Debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "LIB_EXPORTS" /YX /FD /GZ /c +# ADD CPP /nologo /MDd /W4 /Gm /Gi /GX- /ZI /Od /I "..\include" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /FR /YX /FD /GZ /c +# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# 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 libfcgi.lib /nologo /profile /debug /machine:IX86 /out:"..\examples\echo-x\Debug\echo-x.exe" /libpath:"..\libfcgi\Debug" + +!ENDIF + +# Begin Target + +# Name "echox - Win32 Release" +# Name "echox - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE="..\examples\echo-x.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/iipsrv/fcgi/Win32/libfcgi.dsp b/iipsrv/fcgi/Win32/libfcgi.dsp new file mode 100644 index 0000000..5839b91 --- /dev/null +++ b/iipsrv/fcgi/Win32/libfcgi.dsp @@ -0,0 +1,175 @@ +# Microsoft Developer Studio Project File - Name="libfcgi" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102 + +CFG=libfcgi - 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 "libfcgi.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 "libfcgi.mak" CFG="libfcgi - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "libfcgi - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE "libfcgi - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +MTL=midl.exe +RSC=rc.exe + +!IF "$(CFG)" == "libfcgi - 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 "..\libfcgi\Release" +# PROP Intermediate_Dir "..\libfcgi\Release" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "LIB_EXPORTS" /YX /FD /c +# ADD CPP /nologo /MD /W3 /O2 /Ob2 /I "..\include" /D "NDEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D "LIBFCGI_EXPORTS" /YX /FD /c +# SUBTRACT CPP /Fr +# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# 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 /nologo /dll /machine:I386 +# ADD LINK32 Ws2_32.lib /nologo /dll /pdb:none /machine:I386 +# SUBTRACT LINK32 /verbose /nodefaultlib + +!ELSEIF "$(CFG)" == "libfcgi - 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 "..\libfcgi\Debug" +# PROP Intermediate_Dir "..\libfcgi\Debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "LIB_EXPORTS" /YX /FD /GZ /c +# ADD CPP /nologo /MDd /W4 /Gm /Gi /ZI /Od /I "..\include" /D "_DEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D "LIBFCGI_EXPORTS" /FR /YX /FD /GZ /c +# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# 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 /nologo /dll /debug /machine:I386 /pdbtype:sept +# ADD LINK32 Ws2_32.lib /nologo /dll /profile /map /debug /machine:I386 +# SUBTRACT LINK32 /verbose /nodefaultlib + +!ENDIF + +# Begin Target + +# Name "libfcgi - Win32 Release" +# Name "libfcgi - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=..\libfcgi\fcgi_stdio.c +# End Source File +# Begin Source File + +SOURCE=..\libfcgi\fcgiapp.c +# End Source File +# Begin Source File + +SOURCE=..\libfcgi\fcgio.cpp + +!IF "$(CFG)" == "libfcgi - Win32 Release" + +# ADD CPP /GX + +!ELSEIF "$(CFG)" == "libfcgi - Win32 Debug" + +# ADD CPP /W3 /GX + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\libfcgi\os_unix.c +# PROP Exclude_From_Build 1 +# End Source File +# Begin Source File + +SOURCE=..\libfcgi\os_win32.c +# End Source File +# Begin Source File + +SOURCE=..\libfcgi\strerror.c +# PROP Exclude_From_Build 1 +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=..\include\fastcgi.h +# End Source File +# Begin Source File + +SOURCE=..\include\fcgi_config.h +# End Source File +# Begin Source File + +SOURCE=..\include\fcgi_config_x86.h +# End Source File +# Begin Source File + +SOURCE=..\include\fcgi_stdio.h +# End Source File +# Begin Source File + +SOURCE=..\include\fcgiapp.h +# End Source File +# Begin Source File + +SOURCE=..\include\fcgimisc.h +# End Source File +# Begin Source File + +SOURCE=..\include\fcgio.h +# End Source File +# Begin Source File + +SOURCE=..\include\fcgios.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 +# End Target +# End Project diff --git a/iipsrv/fcgi/Win32/logdump.dsp b/iipsrv/fcgi/Win32/logdump.dsp new file mode 100644 index 0000000..4d0074d --- /dev/null +++ b/iipsrv/fcgi/Win32/logdump.dsp @@ -0,0 +1,109 @@ +# Microsoft Developer Studio Project File - Name="logdump" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102 + +CFG=logdump - 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 "logdump.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 "logdump.mak" CFG="logdump - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "logdump - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE "logdump - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +MTL=midl.exe +RSC=rc.exe + +!IF "$(CFG)" == "logdump - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "log-dump\Release" +# PROP BASE Intermediate_Dir "log-dump\Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "..\examples\log-dump\Release" +# PROP Intermediate_Dir "..\examples\log-dump\Release" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "LIB_EXPORTS" /YX /FD /c +# ADD CPP /nologo /MD /W3 /Gi /GX- /O2 /Ob2 /I "..\include" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# SUBTRACT CPP /Fr +# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# 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 libfcgi.lib /nologo /pdb:none /machine:IX86 /out:"..\examples\log-dump\Release\log-dump.exe" /libpath:"..\libfcgi\Release" + +!ELSEIF "$(CFG)" == "logdump - 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 "../examples/log-dump\Debug" +# PROP Intermediate_Dir "../examples/log-dump\Debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "LIB_EXPORTS" /YX /FD /GZ /c +# ADD CPP /nologo /MDd /W4 /Gm /Gi /GX- /ZI /Od /I "..\include" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /FR /YX /FD /GZ /c +# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# 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 libfcgi.lib /nologo /profile /debug /machine:IX86 /out:"..\examples\log-dump\Debug\log-dump.exe" /libpath:"..\libfcgi\Debug" + +!ENDIF + +# Begin Target + +# Name "logdump - Win32 Release" +# Name "logdump - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE="..\examples\log-dump.c" +# PROP Exclude_From_Build 1 +# 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/iipsrv/fcgi/Win32/size.dsp b/iipsrv/fcgi/Win32/size.dsp new file mode 100644 index 0000000..9bafd29 --- /dev/null +++ b/iipsrv/fcgi/Win32/size.dsp @@ -0,0 +1,108 @@ +# Microsoft Developer Studio Project File - Name="size" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102 + +CFG=size - 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 "size.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 "size.mak" CFG="size - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "size - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE "size - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +MTL=midl.exe +RSC=rc.exe + +!IF "$(CFG)" == "size - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "size\Release" +# PROP BASE Intermediate_Dir "size\Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "..\examples\size\Release" +# PROP Intermediate_Dir "..\examples\size\Release" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "LIB_EXPORTS" /YX /FD /c +# ADD CPP /nologo /MD /W3 /Gi /GX- /O2 /Ob2 /I "..\include" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# SUBTRACT CPP /Fr +# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# 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 libfcgi.lib /nologo /pdb:none /machine:IX86 /libpath:"..\libfcgi\Release" + +!ELSEIF "$(CFG)" == "size - 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 "../examples/size\Debug" +# PROP Intermediate_Dir "../examples/size\Debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "LIB_EXPORTS" /YX /FD /GZ /c +# ADD CPP /nologo /MDd /W4 /Gm /Gi /GX- /ZI /Od /I "..\include" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /FR /YX /FD /GZ /c +# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# 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 libfcgi.lib /nologo /profile /debug /machine:IX86 /libpath:"..\libfcgi\Debug" + +!ENDIF + +# Begin Target + +# Name "size - Win32 Release" +# Name "size - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=..\examples\size.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/iipsrv/fcgi/Win32/threaded.dsp b/iipsrv/fcgi/Win32/threaded.dsp new file mode 100644 index 0000000..bce2268 --- /dev/null +++ b/iipsrv/fcgi/Win32/threaded.dsp @@ -0,0 +1,109 @@ +# Microsoft Developer Studio Project File - Name="threaded" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102 + +CFG=threaded - 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 "threaded.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 "threaded.mak" CFG="threaded - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "threaded - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE "threaded - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +MTL=midl.exe +RSC=rc.exe + +!IF "$(CFG)" == "threaded - 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 "..\examples\threaded\Release" +# PROP Intermediate_Dir "..\examples\threaded\Release" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "LIB_EXPORTS" /YX /FD /c +# ADD CPP /nologo /MD /W3 /Gi /GX /O2 /Ob2 /I "..\include" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# SUBTRACT CPP /Fr +# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# 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 libfcgi.lib /nologo /pdb:none /machine:IX86 /libpath:"..\libfcgi\Release" + +!ELSEIF "$(CFG)" == "threaded - 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 "..\examples/threaded/Debug" +# PROP Intermediate_Dir "..\examples/threaded/Debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "LIB_EXPORTS" /YX /FD /GZ /c +# ADD CPP /nologo /MDd /W4 /Gm /Gi /GX /ZI /Od /I "..\include" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /FR /YX /FD /GZ /c +# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# 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 libfcgi.lib /nologo /profile /debug /machine:IX86 /libpath:"..\libfcgi\Debug" + +!ENDIF + +# Begin Target + +# Name "threaded - Win32 Release" +# Name "threaded - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=..\examples\threaded.c +# PROP Exclude_From_Build 1 +# 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/iipsrv/fcgi/acinclude.m4 b/iipsrv/fcgi/acinclude.m4 new file mode 100644 index 0000000..ab19935 --- /dev/null +++ b/iipsrv/fcgi/acinclude.m4 @@ -0,0 +1,391 @@ +dnl $Id: acinclude.m4,v 1.2 2001/12/21 03:12:50 robs Exp $ + +AC_DEFUN(FCGI_COMMON_CHECKS, [ + AC_CHECK_TYPE([ssize_t], [int]) + + AC_MSG_CHECKING([for sun_len in sys/un.h]) + AC_EGREP_HEADER([sun_len], [sys/un.h], + [AC_MSG_RESULT([yes]) + AC_DEFINE([HAVE_SOCKADDR_UN_SUN_LEN], [1], + [Define if sockaddr_un in sys/un.h contains a sun_len component])], + AC_MSG_RESULT([no])) + + AC_MSG_CHECKING([for fpos_t in stdio.h]) + AC_EGREP_HEADER([fpos_t], [stdio.h], + [AC_MSG_RESULT([yes]) + AC_DEFINE([HAVE_FPOS], [1], + [Define if the fpos_t typedef is in stdio.h])], + AC_MSG_RESULT([no])) + + AC_CHECK_HEADERS([sys/socket.h netdb.h netinet/in.h arpa/inet.h]) + AC_CHECK_HEADERS([sys/time.h limits.h sys/param.h unistd.h]) + + AC_MSG_CHECKING([for a fileno() prototype in stdio.h]) + AC_EGREP_HEADER([fileno], [stdio.h], + [AC_MSG_RESULT([yes]) + AC_DEFINE([HAVE_FILENO_PROTO], [1], + [Define if there's a fileno() prototype in stdio.h])], + AC_MSG_RESULT([no])) + + if test "$HAVE_SYS_SOCKET_H"; then + AC_MSG_CHECKING([for socklen_t in sys/socket.h]) + AC_EGREP_HEADER([socklen_t], [sys/socket.h], + [AC_MSG_RESULT([yes]) + AC_DEFINE([HAVE_SOCKLEN], [1], + [Define if the socklen_t typedef is in sys/socket.h])], + AC_MSG_RESULT([no])) + fi + + #-------------------------------------------------------------------- + # Do we need cross-process locking on this platform? + #-------------------------------------------------------------------- + AC_MSG_CHECKING([whether cross-process locking is required by accept()]) + case "`uname -sr`" in + IRIX\ 5.* | SunOS\ 5.* | UNIX_System_V\ 4.0) + AC_MSG_RESULT([yes]) + AC_DEFINE([USE_LOCKING], [1], + [Define if cross-process locking is required by accept()]) + ;; + *) + AC_MSG_RESULT([no]) + ;; + esac + + #-------------------------------------------------------------------- + # Does va_arg(arg, long double) crash the compiler? + # hpux 9.04 compiler does and so does Stratus FTX (uses HP's compiler) + #-------------------------------------------------------------------- + AC_MSG_CHECKING([whether va_arg(arg, long double) crashes the compiler]) + AC_TRY_COMPILE([#include ], + [long double lDblArg; va_list arg; lDblArg = va_arg(arg, long double);], + AC_MSG_RESULT([no]), + [AC_MSG_RESULT([yes]) + AC_DEFINE([HAVE_VA_ARG_LONG_DOUBLE_BUG], [1], + [Define if va_arg(arg, long double) crashes the compiler])]) + + AC_C_CONST +]) + + +dnl @synopsis ACX_PTHREAD([ACTION-IF-FOUND[, ACTION-IF-NOT-FOUND]]) +dnl +dnl This macro figures out how to build C programs using POSIX +dnl threads. It sets the PTHREAD_LIBS output variable to the threads +dnl library and linker flags, and the PTHREAD_CFLAGS output variable +dnl to any special C compiler flags that are needed. (The user can also +dnl force certain compiler flags/libs to be tested by setting these +dnl environment variables.) +dnl +dnl Also sets PTHREAD_CC to any special C compiler that is needed for +dnl multi-threaded programs (defaults to the value of CC otherwise). +dnl (This is necessary on AIX to use the special cc_r compiler alias.) +dnl +dnl If you are only building threads programs, you may wish to +dnl use these variables in your default LIBS, CFLAGS, and CC: +dnl +dnl LIBS="$PTHREAD_LIBS $LIBS" +dnl CFLAGS="$CFLAGS $PTHREAD_CFLAGS" +dnl CC="$PTHREAD_CC" +dnl +dnl In addition, if the PTHREAD_CREATE_JOINABLE thread-attribute +dnl constant has a nonstandard name, defines PTHREAD_CREATE_JOINABLE +dnl to that name (e.g. PTHREAD_CREATE_UNDETACHED on AIX). +dnl +dnl ACTION-IF-FOUND is a list of shell commands to run if a threads +dnl library is found, and ACTION-IF-NOT-FOUND is a list of commands +dnl to run it if it is not found. If ACTION-IF-FOUND is not specified, +dnl the default action will define HAVE_PTHREAD. +dnl +dnl Please let the authors know if this macro fails on any platform, +dnl or if you have any other suggestions or comments. This macro was +dnl based on work by SGJ on autoconf scripts for FFTW (www.fftw.org) +dnl (with help from M. Frigo), as well as ac_pthread and hb_pthread +dnl macros posted by AFC to the autoconf macro repository. We are also +dnl grateful for the helpful feedback of numerous users. +dnl +dnl @version $Id: acinclude.m4,v 1.2 2001/12/21 03:12:50 robs Exp $ +dnl @author Steven G. Johnson and Alejandro Forero Cuervo + +AC_DEFUN([ACX_PTHREAD], [ +AC_REQUIRE([AC_CANONICAL_HOST]) +acx_pthread_ok=no + +# First, check if the POSIX threads header, pthread.h, is available. +# If it isn't, don't bother looking for the threads libraries. +AC_CHECK_HEADER(pthread.h, , acx_pthread_ok=noheader) + +# We must check for the threads library under a number of different +# names; the ordering is very important because some systems +# (e.g. DEC) have both -lpthread and -lpthreads, where one of the +# libraries is broken (non-POSIX). + +# First of all, check if the user has set any of the PTHREAD_LIBS, +# etcetera environment variables, and if threads linking works using +# them: +if test x"$PTHREAD_LIBS$PTHREAD_CFLAGS" != x; then + save_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS $PTHREAD_CFLAGS" + save_LIBS="$LIBS" + LIBS="$PTHREAD_LIBS $LIBS" + AC_MSG_CHECKING([for pthread_join in LIBS=$PTHREAD_LIBS with CFLAGS=$PTHREAD_CFLAGS]) + AC_TRY_LINK_FUNC(pthread_join, acx_pthread_ok=yes) + AC_MSG_RESULT($acx_pthread_ok) + if test x"$acx_pthread_ok" = xno; then + PTHREAD_LIBS="" + PTHREAD_CFLAGS="" + fi + LIBS="$save_LIBS" + CFLAGS="$save_CFLAGS" +fi + +# Create a list of thread flags to try. Items starting with a "-" are +# C compiler flags, and other items are library names, except for "none" +# which indicates that we try without any flags at all. + +acx_pthread_flags="pthreads none -Kthread -kthread lthread -pthread -pthreads -mthreads pthread --thread-safe -mt" + +# The ordering *is* (sometimes) important. Some notes on the +# individual items follow: + +# pthreads: AIX (must check this before -lpthread) +# none: in case threads are in libc; should be tried before -Kthread and +# other compiler flags to prevent continual compiler warnings +# -Kthread: Sequent (threads in libc, but -Kthread needed for pthread.h) +# -kthread: FreeBSD kernel threads (preferred to -pthread since SMP-able) +# lthread: LinuxThreads port on FreeBSD (also preferred to -pthread) +# -pthread: Linux/gcc (kernel threads), BSD/gcc (userland threads) +# -pthreads: Solaris/gcc +# -mthreads: Mingw32/gcc, Lynx/gcc +# -mt: Sun Workshop C (may only link SunOS threads [-lthread], but it +# doesn't hurt to check since this sometimes defines pthreads too; +# also defines -D_REENTRANT) +# pthread: Linux, etcetera +# --thread-safe: KAI C++ + +case "${host_cpu}-${host_os}" in + *solaris*) + + # On Solaris (at least, for some versions), libc contains stubbed + # (non-functional) versions of the pthreads routines, so link-based + # tests will erroneously succeed. (We need to link with -pthread or + # -lpthread.) (The stubs are missing pthread_cleanup_push, or rather + # a function called by this macro, so we could check for that, but + # who knows whether they'll stub that too in a future libc.) So, + # we'll just look for -pthreads and -lpthread first: + + acx_pthread_flags="-pthread -pthreads pthread -mt $acx_pthread_flags" + ;; +esac + +if test x"$acx_pthread_ok" = xno; then +for flag in $acx_pthread_flags; do + + case $flag in + none) + AC_MSG_CHECKING([whether pthreads work without any flags]) + ;; + + -*) + AC_MSG_CHECKING([whether pthreads work with $flag]) + PTHREAD_CFLAGS="$flag" + ;; + + *) + AC_MSG_CHECKING([for the pthreads library -l$flag]) + PTHREAD_LIBS="-l$flag" + ;; + esac + + save_LIBS="$LIBS" + save_CFLAGS="$CFLAGS" + LIBS="$PTHREAD_LIBS $LIBS" + CFLAGS="$CFLAGS $PTHREAD_CFLAGS" + + # Check for various functions. We must include pthread.h, + # since some functions may be macros. (On the Sequent, we + # need a special flag -Kthread to make this header compile.) + # We check for pthread_join because it is in -lpthread on IRIX + # while pthread_create is in libc. We check for pthread_attr_init + # due to DEC craziness with -lpthreads. We check for + # pthread_cleanup_push because it is one of the few pthread + # functions on Solaris that doesn't have a non-functional libc stub. + # We try pthread_create on general principles. + AC_TRY_LINK([#include ], + [pthread_t th; pthread_join(th, 0); + pthread_attr_init(0); pthread_cleanup_push(0, 0); + pthread_create(0,0,0,0); pthread_cleanup_pop(0); ], + [acx_pthread_ok=yes]) + + LIBS="$save_LIBS" + CFLAGS="$save_CFLAGS" + + AC_MSG_RESULT($acx_pthread_ok) + if test "x$acx_pthread_ok" = xyes; then + break; + fi + + PTHREAD_LIBS="" + PTHREAD_CFLAGS="" +done +fi + +# Various other checks: +if test "x$acx_pthread_ok" = xyes; then + save_LIBS="$LIBS" + LIBS="$PTHREAD_LIBS $LIBS" + save_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS $PTHREAD_CFLAGS" + + # Detect AIX lossage: threads are created detached by default + # and the JOINABLE attribute has a nonstandard name (UNDETACHED). + AC_MSG_CHECKING([for joinable pthread attribute]) + AC_TRY_LINK([#include ], + [int attr=PTHREAD_CREATE_JOINABLE;], + ok=PTHREAD_CREATE_JOINABLE, ok=unknown) + if test x"$ok" = xunknown; then + AC_TRY_LINK([#include ], + [int attr=PTHREAD_CREATE_UNDETACHED;], + ok=PTHREAD_CREATE_UNDETACHED, ok=unknown) + fi + if test x"$ok" != xPTHREAD_CREATE_JOINABLE; then + AC_DEFINE(PTHREAD_CREATE_JOINABLE, $ok, + [Define to the necessary symbol if this constant + uses a non-standard name on your system.]) + fi + AC_MSG_RESULT(${ok}) + if test x"$ok" = xunknown; then + AC_MSG_WARN([we do not know how to create joinable pthreads]) + fi + + AC_MSG_CHECKING([if more special flags are required for pthreads]) + flag=no + case "${host_cpu}-${host_os}" in + *-aix* | *-freebsd*) flag="-D_THREAD_SAFE";; + *solaris* | alpha*-osf*) flag="-D_REENTRANT";; + esac + AC_MSG_RESULT(${flag}) + if test "x$flag" != xno; then + PTHREAD_CFLAGS="$flag $PTHREAD_CFLAGS" + fi + + LIBS="$save_LIBS" + CFLAGS="$save_CFLAGS" + + # More AIX lossage: must compile with cc_r + AC_CHECK_PROG(PTHREAD_CC, cc_r, cc_r, ${CC}) +else + PTHREAD_CC="$CC" +fi + +AC_SUBST(PTHREAD_LIBS) +AC_SUBST(PTHREAD_CFLAGS) +AC_SUBST(PTHREAD_CC) + +# Finally, execute ACTION-IF-FOUND/ACTION-IF-NOT-FOUND: +if test x"$acx_pthread_ok" = xyes; then + ifelse([$1],,AC_DEFINE(HAVE_PTHREAD,1,[Define if you have POSIX threads libraries and header files.]),[$1]) + : +else + acx_pthread_ok=no + $2 +fi + +])dnl ACX_PTHREAD + + + +dnl @synopsis AC_PROG_CC_WARNINGS([ANSI]) +dnl +dnl Enables a reasonable set of warnings for the C compiler. Optionally, +dnl if the first argument is nonempty, turns on flags which enforce and/or +dnl enable proper ANSI C if such flags are known to the compiler used. +dnl +dnl Currently this macro knows about GCC, Solaris C compiler, +dnl Digital Unix C compiler, C for AIX Compiler, HP-UX C compiler, +dnl and IRIX C compiler. +dnl +dnl @version $Id: acinclude.m4,v 1.2 2001/12/21 03:12:50 robs Exp $ +dnl @author Ville Laurikari +dnl +AC_DEFUN([AC_PROG_CC_WARNINGS], [ + ansi=$1 + if test -z "$ansi"; then + msg="for C compiler warning flags" + else + msg="for C compiler warning and ANSI conformance flags" + fi + AC_CACHE_CHECK($msg, ac_cv_prog_cc_warnings, [ + if test -n "$CC"; then + cat > conftest.c <&1 | grep "Xc.*strict ANSI C" > /dev/null 2>&1 && + $CC -c -v -Xc conftest.c > /dev/null 2>&1 && + test -f conftest.o; then + if test -z "$ansi"; then + ac_cv_prog_cc_warnings="-v" + else + ac_cv_prog_cc_warnings="-v -Xc" + fi + + dnl HP-UX C compiler + elif $CC > /dev/null 2>&1 && + $CC -c -Aa +w1 conftest.c > /dev/null 2>&1 && + test -f conftest.o; then + if test -z "$ansi"; then + ac_cv_prog_cc_warnings="+w1" + else + ac_cv_prog_cc_warnings="+w1 -Aa" + fi + + dnl Digital Unix C compiler + elif ! $CC > /dev/null 2>&1 && + $CC -c -verbose -w0 -warnprotos -std1 conftest.c > /dev/null 2>&1 && + test -f conftest.o; then + if test -z "$ansi"; then + ac_cv_prog_cc_warnings="-verbose -w0 -warnprotos" + else + ac_cv_prog_cc_warnings="-verbose -w0 -warnprotos -std1" + fi + + dnl C for AIX Compiler + elif $CC > /dev/null 2>&1 | grep AIX > /dev/null 2>&1 && + $CC -c -qlanglvl=ansi -qinfo=all conftest.c > /dev/null 2>&1 && + test -f conftest.o; then + if test -z "$ansi"; then + ac_cv_prog_cc_warnings="-qsrcmsg -qinfo=all:noppt:noppc:noobs:nocnd" + else + ac_cv_prog_cc_warnings="-qsrcmsg -qinfo=all:noppt:noppc:noobs:nocnd -qlanglvl=ansi" + fi + + dnl IRIX C compiler + elif $CC -fullwarn -ansi -ansiE > /dev/null 2>&1 && + test -f conftest.o; then + if test -z "$ansi"; then + ac_cv_prog_cc_warnings="-fullwarn" + else + ac_cv_prog_cc_warnings="-fullwarn -ansi -ansiE" + fi + + fi + rm -f conftest.* + fi + if test -n "$ac_cv_prog_cc_warnings"; then + CFLAGS="$CFLAGS $ac_cv_prog_cc_warnings" + else + ac_cv_prog_cc_warnings="unknown" + fi + ]) +]) + + diff --git a/iipsrv/fcgi/cgi-fcgi/cgi-fcgi.mak b/iipsrv/fcgi/cgi-fcgi/cgi-fcgi.mak new file mode 100644 index 0000000..c5b58d1 --- /dev/null +++ b/iipsrv/fcgi/cgi-fcgi/cgi-fcgi.mak @@ -0,0 +1,206 @@ +# Microsoft Developer Studio Generated NMAKE File, Based on cgifcgi.dsp + +!IF "$(CFG)" == "" +CFG=release +!ENDIF + +!IF "$(CFG)" != "release" && "$(CFG)" != "debug" +!MESSAGE Invalid configuration "$(CFG)" specified. +!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 "cgifcgi.mak" CFG="debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "release" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE "debug" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE +!ERROR An invalid configuration is specified. +!ENDIF + +!IF "$(OS)" == "Windows_NT" +NULL= +!ELSE +NULL=nul +!ENDIF + +!IF "$(CFG)" == "release" + +OUTDIR=.\..\cgi-fcgi\Release +INTDIR=.\..\cgi-fcgi\Release +# Begin Custom Macros +OutDir=.\..\cgi-fcgi\Release +# End Custom Macros + +ALL : "$(OUTDIR)\cgi-fcgi.exe" + +CLEAN : + -@erase "$(INTDIR)\cgi-fcgi.obj" + -@erase "$(INTDIR)\vc60.idb" + -@erase "$(OUTDIR)\cgi-fcgi.exe" + +"$(OUTDIR)" : + if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)" + +CPP=cl.exe +CPP_PROJ=/nologo /MD /W3 /Gi /O2 /Ob2 /I "..\include" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /Fp"$(INTDIR)\cgifcgi.pch" /YX /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\\" /FD /c + +.c{$(INTDIR)}.obj:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.cpp{$(INTDIR)}.obj:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.cxx{$(INTDIR)}.obj:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.c{$(INTDIR)}.sbr:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.cpp{$(INTDIR)}.sbr:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.cxx{$(INTDIR)}.sbr:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +MTL=midl.exe +MTL_PROJ=/nologo /D "NDEBUG" /mktyplib203 /win32 +RSC=rc.exe +BSC32=bscmake.exe +BSC32_FLAGS=/nologo /o"$(OUTDIR)\cgifcgi.bsc" +BSC32_SBRS= \ + +LINK32=link.exe +LINK32_FLAGS=libfcgi.lib /nologo /pdb:none /machine:IX86 /out:"$(OUTDIR)\cgi-fcgi.exe" /libpath:"..\libfcgi\Release" +LINK32_OBJS= \ + "$(INTDIR)\cgi-fcgi.obj" \ + "..\libfcgi\Release\libfcgi.lib" + +"$(OUTDIR)\cgi-fcgi.exe" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS) + $(LINK32) @<< + $(LINK32_FLAGS) $(LINK32_OBJS) +<< + +!ELSEIF "$(CFG)" == "debug" + +OUTDIR=.\../cgi-fcgi/Debug +INTDIR=.\../cgi-fcgi/Debug +# Begin Custom Macros +OutDir=.\../cgi-fcgi/Debug +# End Custom Macros + +ALL : "$(OUTDIR)\cgi-fcgi.exe" "$(OUTDIR)\cgifcgi.bsc" + +CLEAN : + -@erase "$(INTDIR)\cgi-fcgi.obj" + -@erase "$(INTDIR)\cgi-fcgi.sbr" + -@erase "$(INTDIR)\vc60.idb" + -@erase "$(INTDIR)\vc60.pdb" + -@erase "$(OUTDIR)\cgi-fcgi.exe" + -@erase "$(OUTDIR)\cgifcgi.bsc" + +"$(OUTDIR)" : + if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)" + +CPP=cl.exe +CPP_PROJ=/nologo /MDd /W4 /Gm /Gi /ZI /Od /I "..\include" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /FR"$(INTDIR)\\" /Fp"$(INTDIR)\cgifcgi.pch" /YX /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\\" /FD /GZ /c + +.c{$(INTDIR)}.obj:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.cpp{$(INTDIR)}.obj:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.cxx{$(INTDIR)}.obj:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.c{$(INTDIR)}.sbr:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.cpp{$(INTDIR)}.sbr:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.cxx{$(INTDIR)}.sbr:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +MTL=midl.exe +MTL_PROJ=/nologo /D "_DEBUG" /mktyplib203 /win32 +RSC=rc.exe +BSC32=bscmake.exe +BSC32_FLAGS=/nologo /o"$(OUTDIR)\cgifcgi.bsc" +BSC32_SBRS= \ + "$(INTDIR)\cgi-fcgi.sbr" + +"$(OUTDIR)\cgifcgi.bsc" : "$(OUTDIR)" $(BSC32_SBRS) + $(BSC32) @<< + $(BSC32_FLAGS) $(BSC32_SBRS) +<< + +LINK32=link.exe +LINK32_FLAGS=libfcgi.lib /nologo /profile /debug /machine:IX86 /out:"$(OUTDIR)\cgi-fcgi.exe" /libpath:"..\libfcgi\Debug" +LINK32_OBJS= \ + "$(INTDIR)\cgi-fcgi.obj" \ + "..\libfcgi\Debug\libfcgi.lib" + +"$(OUTDIR)\cgi-fcgi.exe" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS) + $(LINK32) @<< + $(LINK32_FLAGS) $(LINK32_OBJS) +<< + +!ENDIF + + +"..\cgi-fcgi\cgi-fcgi.c" : \ + "..\include\fastcgi.h"\ + "..\include\fcgi_config.h"\ + "..\include\fcgiapp.h"\ + "..\include\fcgimisc.h"\ + "..\include\fcgios.h"\ + + +!IF "$(CFG)" == "release" || "$(CFG)" == "debug" +SOURCE="..\cgi-fcgi\cgi-fcgi.c" + +!IF "$(CFG)" == "release" + + +"$(INTDIR)\cgi-fcgi.obj" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +!ELSEIF "$(CFG)" == "debug" + + +"$(INTDIR)\cgi-fcgi.obj" "$(INTDIR)\cgi-fcgi.sbr" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +!ENDIF + +!ENDIF + diff --git a/iipsrv/fcgi/configure b/iipsrv/fcgi/configure new file mode 100755 index 0000000..af83652 --- /dev/null +++ b/iipsrv/fcgi/configure @@ -0,0 +1,11250 @@ +#! /bin/sh +# Guess values for system-dependent variables and create Makefiles. +# Generated by GNU Autoconf 2.57. +# +# Copyright 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001, 2002 +# 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 + +# Support unset when possible. +if (FOO=FOO; unset FOO) >/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 -n "`(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 + as_mkdir_p=false +fi + +as_executable_p="test -f" + +# Sed expression to map a string onto a valid CPP name. +as_tr_cpp="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="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 + + +# Find the correct PATH separator. Usually this is `:', but +# DJGPP uses `;' like DOS. +if test "X${PATH_SEPARATOR+set}" != Xset; then + UNAME=${UNAME-`uname 2>/dev/null`} + case X$UNAME in + *-DOS) lt_cv_sys_path_separator=';' ;; + *) lt_cv_sys_path_separator=':' ;; + esac + PATH_SEPARATOR=$lt_cv_sys_path_separator +fi + + +# Check that we are running under the correct shell. +SHELL=${CONFIG_SHELL-/bin/sh} + +case X$ECHO in +X*--fallback-echo) + # Remove one level of quotation (which was required for Make). + ECHO=`echo "$ECHO" | sed 's,\\\\\$\\$0,'$0','` + ;; +esac + +echo=${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 && + 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' && + echo_testing_string=`($echo "$echo_test_string") 2>/dev/null` && + test "X$echo_testing_string" = "X$echo_test_string"; then + : +else + # 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=$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' && + echo_testing_string=`($dir/echo "$echo_test_string") 2>/dev/null` && + test "X$echo_testing_string" = "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' && + echo_testing_string=`(print -r "$echo_test_string") 2>/dev/null` && + test "X$echo_testing_string" = "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 configure 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' && + echo_testing_string=`($echo "$echo_test_string") 2>/dev/null` && + test "X$echo_testing_string" = "X$echo_test_string"; then + # Cool, printf works + : + elif echo_testing_string=`($ORIGINAL_CONFIG_SHELL "$0" --fallback-echo '\t') 2>/dev/null` && + test "X$echo_testing_string" = 'X\t' && + echo_testing_string=`($ORIGINAL_CONFIG_SHELL "$0" --fallback-echo "$echo_test_string") 2>/dev/null` && + test "X$echo_testing_string" = "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 echo_testing_string=`($CONFIG_SHELL "$0" --fallback-echo '\t') 2>/dev/null` && + test "X$echo_testing_string" = 'X\t' && + echo_testing_string=`($CONFIG_SHELL "$0" --fallback-echo "$echo_test_string") 2>/dev/null` && + test "X$echo_testing_string" = "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-${CONFIG_SHELL-/bin/sh}} "$0" ${1+"$@"} + else + # Oops. We lost completely, so just stick with echo. + echo=echo + fi + fi + fi + fi +fi +fi + +# Copy echo and quote the copy suitably for passing to libtool from +# the Makefile, instead of quoting the original, which is used later. +ECHO=$echo +if test "X$ECHO" = "X$CONFIG_SHELL $0 --fallback-echo"; then + ECHO="$CONFIG_SHELL \\\$\$0 --fallback-echo" +fi + + + +# 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= + +# 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 CYGPATH_W PACKAGE VERSION ACLOCAL AUTOCONF AUTOMAKE AUTOHEADER MAKEINFO AMTAR install_sh STRIP ac_ct_STRIP INSTALL_STRIP_PROGRAM AWK SET_MAKE am__leading_dot CC CFLAGS LDFLAGS CPPFLAGS ac_ct_CC EXEEXT OBJEXT DEPDIR am__include am__quote AMDEP_TRUE AMDEP_FALSE AMDEPBACKSLASH CCDEPMODE am__fastdepCC_TRUE am__fastdepCC_FALSE CPP build build_cpu build_vendor build_os host host_cpu host_vendor host_os LN_S ECHO RANLIB ac_ct_RANLIB EGREP LIBTOOL CXX CXXFLAGS ac_ct_CXX CXXDEPMODE am__fastdepCXX_TRUE am__fastdepCXX_FALSE LIBFCGIXX ECHO_CPP PTHREAD_CC PTHREAD_LIBS PTHREAD_CFLAGS THREADED LIBOBJS SYSTEM LTLIBOBJS' +ac_subst_files='' + +# Initialize some variables set by options. +ac_init_help= +ac_init_version=false +# The variables have the same names as the options, with +# dashes changed to underlines. +cache_file=/dev/null +exec_prefix=NONE +no_create= +no_recursion= +prefix=NONE +program_prefix=NONE +program_suffix=NONE +program_transform_name=s,x,x, +silent= +site= +srcdir= +verbose= +x_includes=NONE +x_libraries=NONE + +# Installation directory options. +# These are left unexpanded so users can "make install exec_prefix=/foo" +# and all the variables that are supposed to be based on exec_prefix +# by default will actually change. +# Use braces instead of parens because sh, perl, etc. also accept them. +bindir='${exec_prefix}/bin' +sbindir='${exec_prefix}/sbin' +libexecdir='${exec_prefix}/libexec' +datadir='${prefix}/share' +sysconfdir='${prefix}/etc' +sharedstatedir='${prefix}/com' +localstatedir='${prefix}/var' +libdir='${exec_prefix}/lib' +includedir='${prefix}/include' +oldincludedir='/usr/include' +infodir='${prefix}/info' +mandir='${prefix}/man' + +ac_prev= +for ac_option +do + # If the previous option needs an argument, assign it. + if test -n "$ac_prev"; then + eval "$ac_prev=\$ac_option" + ac_prev= + continue + fi + + ac_optarg=`expr "x$ac_option" : 'x[^=]*=\(.*\)'` + + # Accept the important Cygnus configure options, so we can diagnose typos. + + case $ac_option in + + -bindir | --bindir | --bindi | --bind | --bin | --bi) + ac_prev=bindir ;; + -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*) + bindir=$ac_optarg ;; + + -build | --build | --buil | --bui | --bu) + ac_prev=build_alias ;; + -build=* | --build=* | --buil=* | --bui=* | --bu=*) + build_alias=$ac_optarg ;; + + -cache-file | --cache-file | --cache-fil | --cache-fi \ + | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c) + ac_prev=cache_file ;; + -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \ + | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*) + cache_file=$ac_optarg ;; + + --config-cache | -C) + cache_file=config.cache ;; + + -datadir | --datadir | --datadi | --datad | --data | --dat | --da) + ac_prev=datadir ;; + -datadir=* | --datadir=* | --datadi=* | --datad=* | --data=* | --dat=* \ + | --da=*) + datadir=$ac_optarg ;; + + -disable-* | --disable-*) + ac_feature=`expr "x$ac_option" : 'x-*disable-\(.*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_feature" : ".*[^-_$as_cr_alnum]" >/dev/null && + { echo "$as_me: error: invalid feature name: $ac_feature" >&2 + { (exit 1); exit 1; }; } + ac_feature=`echo $ac_feature | sed 's/-/_/g'` + eval "enable_$ac_feature=no" ;; + + -enable-* | --enable-*) + ac_feature=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_feature" : ".*[^-_$as_cr_alnum]" >/dev/null && + { echo "$as_me: error: invalid feature name: $ac_feature" >&2 + { (exit 1); exit 1; }; } + ac_feature=`echo $ac_feature | sed 's/-/_/g'` + case $ac_option in + *=*) ac_optarg=`echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"`;; + *) ac_optarg=yes ;; + esac + eval "enable_$ac_feature='$ac_optarg'" ;; + + -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \ + | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \ + | --exec | --exe | --ex) + ac_prev=exec_prefix ;; + -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \ + | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \ + | --exec=* | --exe=* | --ex=*) + exec_prefix=$ac_optarg ;; + + -gas | --gas | --ga | --g) + # Obsolete; use --with-gas. + with_gas=yes ;; + + -help | --help | --hel | --he | -h) + ac_init_help=long ;; + -help=r* | --help=r* | --hel=r* | --he=r* | -hr*) + ac_init_help=recursive ;; + -help=s* | --help=s* | --hel=s* | --he=s* | -hs*) + ac_init_help=short ;; + + -host | --host | --hos | --ho) + ac_prev=host_alias ;; + -host=* | --host=* | --hos=* | --ho=*) + host_alias=$ac_optarg ;; + + -includedir | --includedir | --includedi | --included | --include \ + | --includ | --inclu | --incl | --inc) + ac_prev=includedir ;; + -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \ + | --includ=* | --inclu=* | --incl=* | --inc=*) + includedir=$ac_optarg ;; + + -infodir | --infodir | --infodi | --infod | --info | --inf) + ac_prev=infodir ;; + -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*) + infodir=$ac_optarg ;; + + -libdir | --libdir | --libdi | --libd) + ac_prev=libdir ;; + -libdir=* | --libdir=* | --libdi=* | --libd=*) + libdir=$ac_optarg ;; + + -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \ + | --libexe | --libex | --libe) + ac_prev=libexecdir ;; + -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \ + | --libexe=* | --libex=* | --libe=*) + libexecdir=$ac_optarg ;; + + -localstatedir | --localstatedir | --localstatedi | --localstated \ + | --localstate | --localstat | --localsta | --localst \ + | --locals | --local | --loca | --loc | --lo) + ac_prev=localstatedir ;; + -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \ + | --localstate=* | --localstat=* | --localsta=* | --localst=* \ + | --locals=* | --local=* | --loca=* | --loc=* | --lo=*) + localstatedir=$ac_optarg ;; + + -mandir | --mandir | --mandi | --mand | --man | --ma | --m) + ac_prev=mandir ;; + -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*) + mandir=$ac_optarg ;; + + -nfp | --nfp | --nf) + # Obsolete; use --without-fp. + with_fp=no ;; + + -no-create | --no-create | --no-creat | --no-crea | --no-cre \ + | --no-cr | --no-c | -n) + no_create=yes ;; + + -no-recursion | --no-recursion | --no-recursio | --no-recursi \ + | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) + no_recursion=yes ;; + + -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \ + | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \ + | --oldin | --oldi | --old | --ol | --o) + ac_prev=oldincludedir ;; + -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \ + | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \ + | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*) + oldincludedir=$ac_optarg ;; + + -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) + ac_prev=prefix ;; + -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*) + prefix=$ac_optarg ;; + + -program-prefix | --program-prefix | --program-prefi | --program-pref \ + | --program-pre | --program-pr | --program-p) + ac_prev=program_prefix ;; + -program-prefix=* | --program-prefix=* | --program-prefi=* \ + | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*) + program_prefix=$ac_optarg ;; + + -program-suffix | --program-suffix | --program-suffi | --program-suff \ + | --program-suf | --program-su | --program-s) + ac_prev=program_suffix ;; + -program-suffix=* | --program-suffix=* | --program-suffi=* \ + | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*) + program_suffix=$ac_optarg ;; + + -program-transform-name | --program-transform-name \ + | --program-transform-nam | --program-transform-na \ + | --program-transform-n | --program-transform- \ + | --program-transform | --program-transfor \ + | --program-transfo | --program-transf \ + | --program-trans | --program-tran \ + | --progr-tra | --program-tr | --program-t) + ac_prev=program_transform_name ;; + -program-transform-name=* | --program-transform-name=* \ + | --program-transform-nam=* | --program-transform-na=* \ + | --program-transform-n=* | --program-transform-=* \ + | --program-transform=* | --program-transfor=* \ + | --program-transfo=* | --program-transf=* \ + | --program-trans=* | --program-tran=* \ + | --progr-tra=* | --program-tr=* | --program-t=*) + program_transform_name=$ac_optarg ;; + + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil) + silent=yes ;; + + -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) + ac_prev=sbindir ;; + -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ + | --sbi=* | --sb=*) + sbindir=$ac_optarg ;; + + -sharedstatedir | --sharedstatedir | --sharedstatedi \ + | --sharedstated | --sharedstate | --sharedstat | --sharedsta \ + | --sharedst | --shareds | --shared | --share | --shar \ + | --sha | --sh) + ac_prev=sharedstatedir ;; + -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \ + | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \ + | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \ + | --sha=* | --sh=*) + sharedstatedir=$ac_optarg ;; + + -site | --site | --sit) + ac_prev=site ;; + -site=* | --site=* | --sit=*) + site=$ac_optarg ;; + + -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) + ac_prev=srcdir ;; + -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) + srcdir=$ac_optarg ;; + + -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \ + | --syscon | --sysco | --sysc | --sys | --sy) + ac_prev=sysconfdir ;; + -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \ + | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*) + sysconfdir=$ac_optarg ;; + + -target | --target | --targe | --targ | --tar | --ta | --t) + ac_prev=target_alias ;; + -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*) + target_alias=$ac_optarg ;; + + -v | -verbose | --verbose | --verbos | --verbo | --verb) + verbose=yes ;; + + -version | --version | --versio | --versi | --vers | -V) + ac_init_version=: ;; + + -with-* | --with-*) + ac_package=`expr "x$ac_option" : 'x-*with-\([^=]*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_package" : ".*[^-_$as_cr_alnum]" >/dev/null && + { echo "$as_me: error: invalid package name: $ac_package" >&2 + { (exit 1); exit 1; }; } + ac_package=`echo $ac_package| sed 's/-/_/g'` + case $ac_option in + *=*) ac_optarg=`echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"`;; + *) ac_optarg=yes ;; + esac + eval "with_$ac_package='$ac_optarg'" ;; + + -without-* | --without-*) + ac_package=`expr "x$ac_option" : 'x-*without-\(.*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_package" : ".*[^-_$as_cr_alnum]" >/dev/null && + { echo "$as_me: error: invalid package name: $ac_package" >&2 + { (exit 1); exit 1; }; } + ac_package=`echo $ac_package | sed 's/-/_/g'` + eval "with_$ac_package=no" ;; + + --x) + # Obsolete; use --with-x. + with_x=yes ;; + + -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \ + | --x-incl | --x-inc | --x-in | --x-i) + ac_prev=x_includes ;; + -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \ + | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*) + x_includes=$ac_optarg ;; + + -x-libraries | --x-libraries | --x-librarie | --x-librari \ + | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l) + ac_prev=x_libraries ;; + -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \ + | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*) + x_libraries=$ac_optarg ;; + + -*) { echo "$as_me: error: unrecognized option: $ac_option +Try \`$0 --help' for more information." >&2 + { (exit 1); exit 1; }; } + ;; + + *=*) + ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='` + # Reject names that are not valid shell variable names. + expr "x$ac_envvar" : ".*[^_$as_cr_alnum]" >/dev/null && + { echo "$as_me: error: invalid variable name: $ac_envvar" >&2 + { (exit 1); exit 1; }; } + ac_optarg=`echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` + eval "$ac_envvar='$ac_optarg'" + export $ac_envvar ;; + + *) + # FIXME: should be removed in autoconf 3.0. + echo "$as_me: WARNING: you should use --build, --host, --target" >&2 + expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null && + echo "$as_me: WARNING: invalid host type: $ac_option" >&2 + : ${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option} + ;; + + esac +done + +if test -n "$ac_prev"; then + ac_option=--`echo $ac_prev | sed 's/_/-/g'` + { echo "$as_me: error: missing argument to $ac_option" >&2 + { (exit 1); exit 1; }; } +fi + +# Be sure to have absolute paths. +for ac_var in exec_prefix prefix +do + eval ac_val=$`echo $ac_var` + case $ac_val in + [\\/$]* | ?:[\\/]* | NONE | '' ) ;; + *) { echo "$as_me: error: expected an absolute directory name for --$ac_var: $ac_val" >&2 + { (exit 1); exit 1; }; };; + esac +done + +# Be sure to have absolute paths. +for ac_var in bindir sbindir libexecdir datadir sysconfdir sharedstatedir \ + localstatedir libdir includedir oldincludedir infodir mandir +do + eval ac_val=$`echo $ac_var` + case $ac_val in + [\\/$]* | ?:[\\/]* ) ;; + *) { echo "$as_me: error: expected an absolute directory name for --$ac_var: $ac_val" >&2 + { (exit 1); exit 1; }; };; + esac +done + +# There might be people who depend on the old broken behavior: `$host' +# used to hold the argument of --host etc. +# FIXME: To remove some day. +build=$build_alias +host=$host_alias +target=$target_alias + +# FIXME: To remove some day. +if test "x$host_alias" != x; then + if test "x$build_alias" = x; then + cross_compiling=maybe + echo "$as_me: WARNING: If you wanted to set the --build type, don't use --host. + If a cross compiler is detected then cross compile mode will be used." >&2 + elif test "x$build_alias" != "x$host_alias"; then + cross_compiling=yes + fi +fi + +ac_tool_prefix= +test -n "$host_alias" && ac_tool_prefix=$host_alias- + +test "$silent" = yes && exec 6>/dev/null + + +# Find the source files, if location was not specified. +if test -z "$srcdir"; then + ac_srcdir_defaulted=yes + # Try the directory containing this script, then its parent. + ac_confdir=`(dirname "$0") 2>/dev/null || +$as_expr X"$0" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$0" : 'X\(//\)[^/]' \| \ + X"$0" : 'X\(//\)$' \| \ + X"$0" : 'X\(/\)' \| \ + . : '\(.\)' 2>/dev/null || +echo X"$0" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; } + /^X\(\/\/\)[^/].*/{ s//\1/; q; } + /^X\(\/\/\)$/{ s//\1/; q; } + /^X\(\/\).*/{ s//\1/; q; } + s/.*/./; q'` + srcdir=$ac_confdir + if test ! -r $srcdir/$ac_unique_file; then + srcdir=.. + fi +else + ac_srcdir_defaulted=no +fi +if test ! -r $srcdir/$ac_unique_file; then + if test "$ac_srcdir_defaulted" = yes; then + { echo "$as_me: error: cannot find sources ($ac_unique_file) in $ac_confdir or .." >&2 + { (exit 1); exit 1; }; } + else + { echo "$as_me: error: cannot find sources ($ac_unique_file) in $srcdir" >&2 + { (exit 1); exit 1; }; } + fi +fi +(cd $srcdir && test -r ./$ac_unique_file) 2>/dev/null || + { echo "$as_me: error: sources are in $srcdir, but \`cd $srcdir' does not work" >&2 + { (exit 1); exit 1; }; } +srcdir=`echo "$srcdir" | sed 's%\([^\\/]\)[\\/]*$%\1%'` +ac_env_build_alias_set=${build_alias+set} +ac_env_build_alias_value=$build_alias +ac_cv_env_build_alias_set=${build_alias+set} +ac_cv_env_build_alias_value=$build_alias +ac_env_host_alias_set=${host_alias+set} +ac_env_host_alias_value=$host_alias +ac_cv_env_host_alias_set=${host_alias+set} +ac_cv_env_host_alias_value=$host_alias +ac_env_target_alias_set=${target_alias+set} +ac_env_target_alias_value=$target_alias +ac_cv_env_target_alias_set=${target_alias+set} +ac_cv_env_target_alias_value=$target_alias +ac_env_CC_set=${CC+set} +ac_env_CC_value=$CC +ac_cv_env_CC_set=${CC+set} +ac_cv_env_CC_value=$CC +ac_env_CFLAGS_set=${CFLAGS+set} +ac_env_CFLAGS_value=$CFLAGS +ac_cv_env_CFLAGS_set=${CFLAGS+set} +ac_cv_env_CFLAGS_value=$CFLAGS +ac_env_LDFLAGS_set=${LDFLAGS+set} +ac_env_LDFLAGS_value=$LDFLAGS +ac_cv_env_LDFLAGS_set=${LDFLAGS+set} +ac_cv_env_LDFLAGS_value=$LDFLAGS +ac_env_CPPFLAGS_set=${CPPFLAGS+set} +ac_env_CPPFLAGS_value=$CPPFLAGS +ac_cv_env_CPPFLAGS_set=${CPPFLAGS+set} +ac_cv_env_CPPFLAGS_value=$CPPFLAGS +ac_env_CPP_set=${CPP+set} +ac_env_CPP_value=$CPP +ac_cv_env_CPP_set=${CPP+set} +ac_cv_env_CPP_value=$CPP +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 + +# +# 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-dependency-tracking Speeds up one-time builds + --enable-dependency-tracking Do not reject slow dependency extractors + --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-gnu-ld assume the C compiler uses GNU ld default=no + --with-pic try to use only PIC/non-PIC objects default=use both + +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 + CPP C preprocessor + CXX C++ compiler command + CXXFLAGS C++ compiler flags + +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 +# Don't blindly perform a `cd "$ac_dir"/$ac_foo && pwd` since $ac_foo can be +# absolute. +ac_abs_builddir=`cd "$ac_dir" && cd $ac_builddir && pwd` +ac_abs_top_builddir=`cd "$ac_dir" && cd ${ac_top_builddir}. && pwd` +ac_abs_srcdir=`cd "$ac_dir" && cd $ac_srcdir && pwd` +ac_abs_top_srcdir=`cd "$ac_dir" && cd $ac_top_srcdir && pwd` + + 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 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001, 2002 +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.57. 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.* *.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 + + + + + + + + + + + + + + + + + + + +am__api_version="1.7" +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" +# ./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/* | \ + /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 > conftest.file +# 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 conftest.file 2> /dev/null` + if test "$*" = "X"; then + # -L didn't work. + set X `ls -t $srcdir/configure conftest.file` + fi + rm -f conftest.file + if test "$*" != "X $srcdir/configure conftest.file" \ + && test "$*" != "X conftest.file $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" = conftest.file + ) +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 +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 + + +# expand $ac_aux_dir to an absolute path +am_aux_dir=`cd $ac_aux_dir && pwd` + +test x"${MISSING+set}" = xset || MISSING="\${SHELL} $am_aux_dir/missing" +# Use eval to expand $SHELL +if eval "$MISSING --run true"; then + am_missing_run="$MISSING --run " +else + am_missing_run= + { echo "$as_me:$LINENO: WARNING: \`missing' script is too old or missing" >&5 +echo "$as_me: WARNING: \`missing' script is too old or missing" >&2;} +fi + +for ac_prog in gawk mawk nawk awk +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_AWK+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$AWK"; then + ac_cv_prog_AWK="$AWK" # 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_AWK="$ac_prog" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + +fi +fi +AWK=$ac_cv_prog_AWK +if test -n "$AWK"; then + echo "$as_me:$LINENO: result: $AWK" >&5 +echo "${ECHO_T}$AWK" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + + test -n "$AWK" && break +done + +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 + +rm -rf .tst 2>/dev/null +mkdir .tst 2>/dev/null +if test -d .tst; then + am__leading_dot=. +else + am__leading_dot=_ +fi +rmdir .tst 2>/dev/null + + # test to see if srcdir already configured +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 + +# test whether we have cygpath +if test -z "$CYGPATH_W"; then + if (cygpath --version) >/dev/null 2>/dev/null; then + CYGPATH_W='cygpath -w' + else + CYGPATH_W=echo + fi +fi + + +# Define the identity of the package. + PACKAGE=fcgi + VERSION=2.4.0 + + +cat >>confdefs.h <<_ACEOF +#define PACKAGE "$PACKAGE" +_ACEOF + + +cat >>confdefs.h <<_ACEOF +#define VERSION "$VERSION" +_ACEOF + +# Some tools Automake needs. + +ACLOCAL=${ACLOCAL-"${am_missing_run}aclocal-${am__api_version}"} + + +AUTOCONF=${AUTOCONF-"${am_missing_run}autoconf"} + + +AUTOMAKE=${AUTOMAKE-"${am_missing_run}automake-${am__api_version}"} + + +AUTOHEADER=${AUTOHEADER-"${am_missing_run}autoheader"} + + +MAKEINFO=${MAKEINFO-"${am_missing_run}makeinfo"} + + +AMTAR=${AMTAR-"${am_missing_run}tar"} + +install_sh=${install_sh-"$am_aux_dir/install-sh"} + +# Installed binaries are usually stripped using `strip' when the user +# run `make install-strip'. However `strip' might not be the right +# tool to use in cross-compilation environments, therefore Automake +# will honor the `STRIP' environment variable to overrule this program. +if test "$cross_compiling" != no; then + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}strip", so it can be a program name with args. +set dummy ${ac_tool_prefix}strip; 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_STRIP+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$STRIP"; then + ac_cv_prog_STRIP="$STRIP" # 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_STRIP="${ac_tool_prefix}strip" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + +fi +fi +STRIP=$ac_cv_prog_STRIP +if test -n "$STRIP"; then + echo "$as_me:$LINENO: result: $STRIP" >&5 +echo "${ECHO_T}$STRIP" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + +fi +if test -z "$ac_cv_prog_STRIP"; then + ac_ct_STRIP=$STRIP + # Extract the first word of "strip", so it can be a program name with args. +set dummy strip; 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_STRIP+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$ac_ct_STRIP"; then + ac_cv_prog_ac_ct_STRIP="$ac_ct_STRIP" # 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_STRIP="strip" + 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_STRIP" && ac_cv_prog_ac_ct_STRIP=":" +fi +fi +ac_ct_STRIP=$ac_cv_prog_ac_ct_STRIP +if test -n "$ac_ct_STRIP"; then + echo "$as_me:$LINENO: result: $ac_ct_STRIP" >&5 +echo "${ECHO_T}$ac_ct_STRIP" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + + STRIP=$ac_ct_STRIP +else + STRIP="$ac_cv_prog_STRIP" +fi + +fi +INSTALL_STRIP_PROGRAM="\${SHELL} \$(install_sh) -c -s" + +# We need awk for the "check" target. The system "awk" is bad on +# some platforms. + + + + + ac_config_headers="$ac_config_headers fcgi_config.h" + + +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 +#line $LINENO "configure" +/* 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" >&5 +echo $ECHO_N "checking for C compiler default output... $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 +#line $LINENO "configure" +/* 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 +#line $LINENO "configure" +/* 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>&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.$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 +#line $LINENO "configure" +/* 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>&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.$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 +#line $LINENO "configure" +/* 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; +} +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>&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.$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>&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 \ + ''\ + '#include ' \ + '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 +#line $LINENO "configure" +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +$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>&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.$ac_objext conftest.$ac_ext + cat >conftest.$ac_ext <<_ACEOF +#line $LINENO "configure" +/* 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>&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.$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.$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 +DEPDIR="${am__leading_dot}deps" + + ac_config_commands="$ac_config_commands depfiles" + + +am_make=${MAKE-make} +cat > confinc << 'END' +doit: + @echo done +END +# If we don't find an include directive, just comment out the code. +echo "$as_me:$LINENO: checking for style of include used by $am_make" >&5 +echo $ECHO_N "checking for style of include used by $am_make... $ECHO_C" >&6 +am__include="#" +am__quote= +_am_result=none +# First try GNU make style include. +echo "include confinc" > confmf +# We grep out `Entering directory' and `Leaving directory' +# messages which can occur if `w' ends up in MAKEFLAGS. +# In particular we don't look at `^make:' because GNU make might +# be invoked under some other name (usually "gmake"), in which +# case it prints its new name instead of `make'. +if test "`$am_make -s -f confmf 2> /dev/null | grep -v 'ing directory'`" = "done"; then + am__include=include + am__quote= + _am_result=GNU +fi +# Now try BSD make style include. +if test "$am__include" = "#"; then + echo '.include "confinc"' > confmf + if test "`$am_make -s -f confmf 2> /dev/null`" = "done"; then + am__include=.include + am__quote="\"" + _am_result=BSD + fi +fi + + +echo "$as_me:$LINENO: result: $_am_result" >&5 +echo "${ECHO_T}$_am_result" >&6 +rm -f confinc confmf + +# Check whether --enable-dependency-tracking or --disable-dependency-tracking was given. +if test "${enable_dependency_tracking+set}" = set; then + enableval="$enable_dependency_tracking" + +fi; +if test "x$enable_dependency_tracking" != xno; then + am_depcomp="$ac_aux_dir/depcomp" + AMDEPBACKSLASH='\' +fi + + +if test "x$enable_dependency_tracking" != xno; then + AMDEP_TRUE= + AMDEP_FALSE='#' +else + AMDEP_TRUE='#' + AMDEP_FALSE= +fi + + + + +depcc="$CC" am_compiler_list= + +echo "$as_me:$LINENO: checking dependency style of $depcc" >&5 +echo $ECHO_N "checking dependency style of $depcc... $ECHO_C" >&6 +if test "${am_cv_CC_dependencies_compiler_type+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then + # We make a subdir and do the tests there. Otherwise we can end up + # making bogus files that we don't know about and never remove. For + # instance it was reported that on HP-UX the gcc test will end up + # making a dummy file named `D' -- because `-MD' means `put the output + # in D'. + mkdir conftest.dir + # Copy depcomp to subdir because otherwise we won't find it if we're + # using a relative directory. + cp "$am_depcomp" conftest.dir + cd conftest.dir + + am_cv_CC_dependencies_compiler_type=none + if test "$am_compiler_list" = ""; then + am_compiler_list=`sed -n 's/^#*\([a-zA-Z0-9]*\))$/\1/p' < ./depcomp` + fi + for depmode in $am_compiler_list; do + # We need to recreate these files for each test, as the compiler may + # overwrite some of them when testing with obscure command lines. + # This happens at least with the AIX C compiler. + echo '#include "conftest.h"' > conftest.c + echo 'int i;' > conftest.h + echo "${am__include} ${am__quote}conftest.Po${am__quote}" > confmf + + case $depmode in + nosideeffect) + # after this tag, mechanisms are not by side-effect, so they'll + # only be used when explicitly requested + if test "x$enable_dependency_tracking" = xyes; then + continue + else + break + fi + ;; + none) break ;; + esac + # We check with `-c' and `-o' for the sake of the "dashmstdout" + # mode. It turns out that the SunPro C++ compiler does not properly + # handle `-M -o', and we need to detect this. + if depmode=$depmode \ + source=conftest.c object=conftest.o \ + depfile=conftest.Po tmpdepfile=conftest.TPo \ + $SHELL ./depcomp $depcc -c -o conftest.o conftest.c \ + >/dev/null 2>conftest.err && + grep conftest.h conftest.Po > /dev/null 2>&1 && + ${MAKE-make} -s -f confmf > /dev/null 2>&1; then + # icc doesn't choke on unknown options, it will just issue warnings + # (even with -Werror). So we grep stderr for any message + # that says an option was ignored. + if grep 'ignoring option' conftest.err >/dev/null 2>&1; then :; else + am_cv_CC_dependencies_compiler_type=$depmode + break + fi + fi + done + + cd .. + rm -rf conftest.dir +else + am_cv_CC_dependencies_compiler_type=none +fi + +fi +echo "$as_me:$LINENO: result: $am_cv_CC_dependencies_compiler_type" >&5 +echo "${ECHO_T}$am_cv_CC_dependencies_compiler_type" >&6 +CCDEPMODE=depmode=$am_cv_CC_dependencies_compiler_type + + + +if + test "x$enable_dependency_tracking" != xno \ + && test "$am_cv_CC_dependencies_compiler_type" = gcc3; then + am__fastdepCC_TRUE= + am__fastdepCC_FALSE='#' +else + am__fastdepCC_TRUE='#' + am__fastdepCC_FALSE= +fi + + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu +echo "$as_me:$LINENO: checking how to run the C preprocessor" >&5 +echo $ECHO_N "checking how to run the C preprocessor... $ECHO_C" >&6 +# On Suns, sometimes $CPP names a directory. +if test -n "$CPP" && test -d "$CPP"; then + CPP= +fi +if test -z "$CPP"; then + if test "${ac_cv_prog_CPP+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + # Double quotes because CPP needs to be expanded + for CPP in "$CC -E" "$CC -E -traditional-cpp" "/lib/cpp" + do + ac_preproc_ok=false +for ac_c_preproc_warn_flag in '' yes +do + # Use a header file that comes with gcc, so configuring glibc + # with a fresh cross-compiler works. + # Prefer 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 +#line $LINENO "configure" +/* 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 + 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 +#line $LINENO "configure" +/* 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 + 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 +#line $LINENO "configure" +/* 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 + 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 +#line $LINENO "configure" +/* 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 + 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 + +# 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" +# ./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/* | \ + /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' + +# 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; +# 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/'` + + +# Find the correct PATH separator. Usually this is `:', but +# DJGPP uses `;' like DOS. +if test "X${PATH_SEPARATOR+set}" != Xset; then + UNAME=${UNAME-`uname 2>/dev/null`} + case X$UNAME in + *-DOS) lt_cv_sys_path_separator=';' ;; + *) lt_cv_sys_path_separator=':' ;; + esac + PATH_SEPARATOR=$lt_cv_sys_path_separator +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 "$GCC" = 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 + case $host in + *-*-mingw*) + # gcc leaves a trailing carriage return which upsets mingw + ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;; + *) + ac_prog=`($CC -print-prog-name=ld) 2>&5` ;; + esac + 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 "${lt_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=$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 + lt_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 "$lt_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 + lt_cv_path_LD="$LD" # Let the user override the test with a path. +fi +fi + +LD="$lt_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 "${lt_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 + lt_cv_prog_gnu_ld=yes +else + lt_cv_prog_gnu_ld=no +fi +fi +echo "$as_me:$LINENO: result: $lt_cv_prog_gnu_ld" >&5 +echo "${ECHO_T}$lt_cv_prog_gnu_ld" >&6 +with_gnu_ld=$lt_cv_prog_gnu_ld + + +echo "$as_me:$LINENO: checking for $LD option to reload object files" >&5 +echo $ECHO_N "checking for $LD option to reload object files... $ECHO_C" >&6 +if test "${lt_cv_ld_reload_flag+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + lt_cv_ld_reload_flag='-r' +fi +echo "$as_me:$LINENO: result: $lt_cv_ld_reload_flag" >&5 +echo "${ECHO_T}$lt_cv_ld_reload_flag" >&6 +reload_flag=$lt_cv_ld_reload_flag +test -n "$reload_flag" && reload_flag=" $reload_flag" + +echo "$as_me:$LINENO: checking for BSD-compatible nm" >&5 +echo $ECHO_N "checking for BSD-compatible nm... $ECHO_C" >&6 +if test "${lt_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. + lt_cv_path_NM="$NM" +else + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=$PATH_SEPARATOR + for ac_dir in $PATH /usr/ccs/bin /usr/ucb /bin; do + test -z "$ac_dir" && ac_dir=. + tmp_nm=$ac_dir/${ac_tool_prefix}nm + if test -f $tmp_nm || test -f $tmp_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 + # Tru64's nm complains that /dev/null is an invalid object file + if ($tmp_nm -B /dev/null 2>&1 | sed '1q'; exit 0) | egrep '(/dev/null|Invalid file or object type)' >/dev/null; then + lt_cv_path_NM="$tmp_nm -B" + break + elif ($tmp_nm -p /dev/null 2>&1 | sed '1q'; exit 0) | egrep /dev/null >/dev/null; then + lt_cv_path_NM="$tmp_nm -p" + break + else + lt_cv_path_NM=${lt_cv_path_NM="$tmp_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 "$lt_cv_path_NM" && lt_cv_path_NM=nm +fi +fi + +NM="$lt_cv_path_NM" +echo "$as_me:$LINENO: result: $NM" >&5 +echo "${ECHO_T}$NM" >&6 + +echo "$as_me:$LINENO: checking for a sed that does not truncate output" >&5 +echo $ECHO_N "checking for a sed that does not truncate output... $ECHO_C" >&6 +if test "${lt_cv_path_SED+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + # Loop through the user's path and test for sed and gsed. +# Then use that list of sed's as ones to test for truncation. +as_executable_p="test -f" +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_prog in sed gsed; do + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_prog$ac_exec_ext"; then + _sed_list="$_sed_list $as_dir/$ac_prog$ac_exec_ext" + fi + done + done +done + + # 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. +: ${TMPDIR=/tmp} +{ + tmp=`(umask 077 && mktemp -d -q "$TMPDIR/sedXXXXXX") 2>/dev/null` && + test -n "$tmp" && test -d "$tmp" +} || +{ + tmp=$TMPDIR/sed$$-$RANDOM + (umask 077 && mkdir $tmp) +} || +{ + echo "$me: cannot create a temporary directory in $TMPDIR" >&2 + { (exit 1); exit 1; } +} + _max=0 + _count=0 + # Add /usr/xpg4/bin/sed as it is typically found on Solaris + # along with /bin/sed that truncates output. + for _sed in $_sed_list /usr/xpg4/bin/sed; do + test ! -f ${_sed} && break + cat /dev/null > "$tmp/sed.in" + _count=0 + echo ${ECHO_N-$ac_n} "0123456789${ECHO_C-$ac_c}" >"$tmp/sed.in" + # Check for GNU sed and select it if it is found. + if "${_sed}" --version 2>&1 < /dev/null | egrep '(GNU)' > /dev/null; then + lt_cv_path_SED=${_sed} + break + fi + while true; do + cat "$tmp/sed.in" "$tmp/sed.in" >"$tmp/sed.tmp" + mv "$tmp/sed.tmp" "$tmp/sed.in" + cp "$tmp/sed.in" "$tmp/sed.nl" + echo >>"$tmp/sed.nl" + ${_sed} -e 's/a$//' < "$tmp/sed.nl" >"$tmp/sed.out" || break + cmp -s "$tmp/sed.out" "$tmp/sed.nl" || break + # 40000 chars as input seems more than enough + test $_count -gt 10 && break + _count=`expr $_count + 1` + if test $_count -gt $_max; then + _max=$_count + lt_cv_path_SED=$_sed + fi + done + done + rm -rf "$tmp" + +fi + +if test "X$SED" != "X"; then + lt_cv_path_SED=$SED +else + SED=$lt_cv_path_SED +fi +echo "$as_me:$LINENO: result: $SED" >&5 +echo "${ECHO_T}$SED" >&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 + +echo "$as_me:$LINENO: checking how to recognise dependent libraries" >&5 +echo $ECHO_N "checking how to recognise dependent libraries... $ECHO_C" >&6 +if test "${lt_cv_deplibs_check_method+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + lt_cv_file_magic_cmd='$MAGIC_CMD' +lt_cv_file_magic_test_file= +lt_cv_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. + +case $host_os in +aix4* | aix5*) + lt_cv_deplibs_check_method=pass_all + ;; + +beos*) + lt_cv_deplibs_check_method=pass_all + ;; + +bsdi4*) + lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [ML]SB (shared object|dynamic lib)' + lt_cv_file_magic_cmd='/usr/bin/file -L' + lt_cv_file_magic_test_file=/shlib/libc.so + ;; + +cygwin* | mingw* | pw32*) + lt_cv_deplibs_check_method='file_magic file format pei*-i386(.*architecture: i386)?' + lt_cv_file_magic_cmd='$OBJDUMP -f' + ;; + +darwin* | rhapsody*) + lt_cv_deplibs_check_method='file_magic Mach-O dynamically linked shared library' + lt_cv_file_magic_cmd='/usr/bin/file -L' + case "$host_os" in + rhapsody* | darwin1.[012]) + lt_cv_file_magic_test_file=`echo /System/Library/Frameworks/System.framework/Versions/*/System | head -1` + ;; + *) # Darwin 1.3 on + lt_cv_file_magic_test_file='/usr/lib/libSystem.dylib' + ;; + esac + ;; + +freebsd*) + if echo __ELF__ | $CC -E - | grep __ELF__ > /dev/null; then + case $host_cpu in + i*86 ) + # Not sure whether the presence of OpenBSD here was a mistake. + # Let's accept both of them until this is cleared up. + lt_cv_deplibs_check_method='file_magic (FreeBSD|OpenBSD)/i[3-9]86 (compact )?demand paged shared library' + lt_cv_file_magic_cmd=/usr/bin/file + lt_cv_file_magic_test_file=`echo /usr/lib/libc.so.*` + ;; + esac + else + lt_cv_deplibs_check_method=pass_all + fi + ;; + +gnu*) + lt_cv_deplibs_check_method=pass_all + ;; + +hpux10.20*|hpux11*) + lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|PA-RISC[0-9].[0-9]) shared library' + lt_cv_file_magic_cmd=/usr/bin/file + lt_cv_file_magic_test_file=/usr/lib/libc.sl + ;; + +irix5* | irix6* | nonstopux*) + case $host_os in + irix5* | nonstopux*) + # this will be overridden with pass_all, but let us keep it just in case + lt_cv_deplibs_check_method="file_magic ELF 32-bit MSB dynamic lib MIPS - version 1" + ;; + *) + case $LD in + *-32|*"-32 ") libmagic=32-bit;; + *-n32|*"-n32 ") libmagic=N32;; + *-64|*"-64 ") libmagic=64-bit;; + *) libmagic=never-match;; + esac + # this will be overridden with pass_all, but let us keep it just in case + lt_cv_deplibs_check_method="file_magic ELF ${libmagic} MSB mips-[1234] dynamic lib MIPS - version 1" + ;; + esac + lt_cv_file_magic_test_file=`echo /lib${libsuff}/libc.so*` + lt_cv_deplibs_check_method=pass_all + ;; + +# This must be Linux ELF. +linux-gnu*) + case $host_cpu in + alpha* | hppa* | i*86 | mips | mipsel | powerpc* | sparc* | ia64*) + lt_cv_deplibs_check_method=pass_all ;; + *) + # glibc up to 2.1.1 does not perform some relocations on ARM + lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [LM]SB (shared object|dynamic lib )' ;; + esac + lt_cv_file_magic_test_file=`echo /lib/libc.so* /lib/libc-*.so` + ;; + +netbsd*) + if echo __ELF__ | $CC -E - | grep __ELF__ > /dev/null; then + lt_cv_deplibs_check_method='match_pattern /lib[^/\.]+\.so\.[0-9]+\.[0-9]+$' + else + lt_cv_deplibs_check_method='match_pattern /lib[^/\.]+\.so$' + fi + ;; + +newos6*) + lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [ML]SB (executable|dynamic lib)' + lt_cv_file_magic_cmd=/usr/bin/file + lt_cv_file_magic_test_file=/usr/lib/libnls.so + ;; + +openbsd*) + lt_cv_file_magic_cmd=/usr/bin/file + lt_cv_file_magic_test_file=`echo /usr/lib/libc.so.*` + if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then + lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [LM]SB shared object' + else + lt_cv_deplibs_check_method='file_magic OpenBSD.* shared library' + fi + ;; + +osf3* | osf4* | osf5*) + # this will be overridden with pass_all, but let us keep it just in case + lt_cv_deplibs_check_method='file_magic COFF format alpha shared library' + lt_cv_file_magic_test_file=/shlib/libc.so + lt_cv_deplibs_check_method=pass_all + ;; + +sco3.2v5*) + lt_cv_deplibs_check_method=pass_all + ;; + +solaris*) + lt_cv_deplibs_check_method=pass_all + lt_cv_file_magic_test_file=/lib/libc.so + ;; + +sysv5uw[78]* | sysv4*uw2*) + lt_cv_deplibs_check_method=pass_all + ;; + +sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*) + case $host_vendor in + motorola) + lt_cv_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]' + lt_cv_file_magic_test_file=`echo /usr/lib/libc.so*` + ;; + ncr) + lt_cv_deplibs_check_method=pass_all + ;; + sequent) + lt_cv_file_magic_cmd='/bin/file' + lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [LM]SB (shared object|dynamic lib )' + ;; + sni) + lt_cv_file_magic_cmd='/bin/file' + lt_cv_deplibs_check_method="file_magic ELF [0-9][0-9]*-bit [LM]SB dynamic lib" + lt_cv_file_magic_test_file=/lib/libc.so + ;; + siemens) + lt_cv_deplibs_check_method=pass_all + ;; + esac + ;; +esac + +fi +echo "$as_me:$LINENO: result: $lt_cv_deplibs_check_method" >&5 +echo "${ECHO_T}$lt_cv_deplibs_check_method" >&6 +file_magic_cmd=$lt_cv_file_magic_cmd +deplibs_check_method=$lt_cv_deplibs_check_method + + + + + + + + +# Check for command to grab the raw symbol name followed by C symbol from nm. +echo "$as_me:$LINENO: checking command to parse $NM output" >&5 +echo $ECHO_N "checking command to parse $NM output... $ECHO_C" >&6 +if test "${lt_cv_sys_global_symbol_pipe+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + +# 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 +lt_cv_global_symbol_to_cdecl="sed -n -e 's/^. .* \(.*\)$/extern char \1;/p'" + +# Transform an extracted symbol line into symbol name and symbol address +lt_cv_global_symbol_to_c_name_address="sed -n -e 's/^: \([^ ]*\) $/ {\\\"\1\\\", (lt_ptr) 0},/p' -e 's/^$symcode \([^ ]*\) \([^ ]*\)$/ {\"\2\", (lt_ptr) \&\2},/p'" + +# Define system-specific variables. +case $host_os in +aix*) + symcode='[BCDT]' + ;; +cygwin* | mingw* | pw32*) + symcode='[ABCDGISTW]' + ;; +hpux*) # Its linker distinguishes data from code symbols + lt_cv_global_symbol_to_cdecl="sed -n -e 's/^T .* \(.*\)$/extern char \1();/p' -e 's/^$symcode* .* \(.*\)$/extern char \1;/p'" + lt_cv_global_symbol_to_c_name_address="sed -n -e 's/^: \([^ ]*\) $/ {\\\"\1\\\", (lt_ptr) 0},/p' -e 's/^$symcode* \([^ ]*\) \([^ ]*\)$/ {\"\2\", (lt_ptr) \&\2},/p'" + ;; +irix* | nonstopux*) + symcode='[BCDEGRST]' + ;; +osf*) + symcode='[BCDEGQRST]' + ;; +solaris* | sysv5*) + symcode='[BDT]' + ;; +sysv4) + symcode='[DFNSTU]' + ;; +esac + +# Handle CRLF in mingw tool chain +opt_cr= +case $host_os in +mingw*) + opt_cr=`echo 'x\{0,1\}' | tr x '\015'` # option cr in regexp + ;; +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. +lt_cv_sys_global_symbol_pipe="sed -n -e 's/^.*[ ]\($symcode$symcode*\)[ ][ ]*\($ac_symprfx\)$sympat$opt_cr$/$symxfrm/p'" + + # Check to see that the pipe works correctly. + pipe_works=no + rm -f conftest* + cat > conftest.$ac_ext <&5 + (eval $ac_compile) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; then + # Now try to grab the symbols. + nlist=conftest.nm + if { (eval echo "$as_me:$LINENO: \"$NM conftest.$ac_objext \| $lt_cv_sys_global_symbol_pipe \> $nlist\"") >&5 + (eval $NM conftest.$ac_objext \| $lt_cv_sys_global_symbol_pipe \> $nlist) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && 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.$ac_ext +#ifdef __cplusplus +extern "C" { +#endif + +EOF + # Now generate the symbol file. + eval "$lt_cv_global_symbol_to_cdecl"' < "$nlist" >> conftest.$ac_ext' + + cat <> conftest.$ac_ext +#if defined (__STDC__) && __STDC__ +# define lt_ptr void * +#else +# define lt_ptr char * +# define const +#endif + +/* The mapping between symbol names and symbols. */ +const struct { + const char *name; + lt_ptr address; +} +lt_preloaded_symbols[] = +{ +EOF + sed "s/^$symcode$symcode* \(.*\) \(.*\)$/ {\"\2\", (lt_ptr) \&\2},/" < "$nlist" >> conftest.$ac_ext + cat <<\EOF >> conftest.$ac_ext + {0, (lt_ptr) 0} +}; + +#ifdef __cplusplus +} +#endif +EOF + # Now try linking the two files. + mv conftest.$ac_objext conftstm.$ac_objext + save_LIBS="$LIBS" + save_CFLAGS="$CFLAGS" + LIBS="conftstm.$ac_objext" + CFLAGS="$CFLAGS$no_builtin_flag" + 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); } && test -s conftest$ac_exeext; then + pipe_works=yes + fi + LIBS="$save_LIBS" + CFLAGS="$save_CFLAGS" + 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 $lt_cv_sys_global_symbol_pipe" >&5 + fi + else + echo "$progname: failed program was:" >&5 + cat conftest.$ac_ext >&5 + fi + rm -f conftest* conftst* + + # Do not use the global_symbol_pipe unless it works. + if test "$pipe_works" = yes; then + break + else + lt_cv_sys_global_symbol_pipe= + fi +done + +fi + +global_symbol_pipe="$lt_cv_sys_global_symbol_pipe" +if test -z "$lt_cv_sys_global_symbol_pipe"; then + global_symbol_to_cdecl= + global_symbol_to_c_name_address= +else + global_symbol_to_cdecl="$lt_cv_global_symbol_to_cdecl" + global_symbol_to_c_name_address="$lt_cv_global_symbol_to_c_name_address" +fi +if test -z "$global_symbol_pipe$global_symbol_to_cdec$global_symbol_to_c_name_address"; +then + echo "$as_me:$LINENO: result: failed" >&5 +echo "${ECHO_T}failed" >&6 +else + echo "$as_me:$LINENO: result: ok" >&5 +echo "${ECHO_T}ok" >&6 +fi + + +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 +#line $LINENO "configure" +/* 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>&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.$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 +#line $LINENO "configure" +/* 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 +#line $LINENO "configure" +/* 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 +#line $LINENO "configure" +/* 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.* *.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 +#line $LINENO "configure" +/* 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>&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.$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 dlfcn.h +do +as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh` +if eval "test \"\${$as_ac_Header+set}\" = set"; then + echo "$as_me:$LINENO: checking for $ac_header" >&5 +echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6 +if eval "test \"\${$as_ac_Header+set}\" = set"; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +fi +echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5 +echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6 +else + # Is the header compilable? +echo "$as_me:$LINENO: checking $ac_header usability" >&5 +echo $ECHO_N "checking $ac_header usability... $ECHO_C" >&6 +cat >conftest.$ac_ext <<_ACEOF +#line $LINENO "configure" +/* 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>&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.$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 +#line $LINENO "configure" +/* 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 + 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 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 preprocessor's result" >&5 +echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;} + ( + cat <<\_ASBOX +## ------------------------------------ ## +## Report this to bug-autoconf@gnu.org. ## +## ------------------------------------ ## +_ASBOX + ) | + sed "s/^/$as_me: WARNING: /" >&2 + ;; + 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: proceeding with the preprocessor's result" >&5 +echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;} + ( + cat <<\_ASBOX +## ------------------------------------ ## +## Report this to bug-autoconf@gnu.org. ## +## ------------------------------------ ## +_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 + + + + + + +# Only perform the check for file, if the check method requires it +case $deplibs_check_method in +file_magic*) + if test "$file_magic_cmd" = '$MAGIC_CMD'; then + echo "$as_me:$LINENO: checking for ${ac_tool_prefix}file" >&5 +echo $ECHO_N "checking for ${ac_tool_prefix}file... $ECHO_C" >&6 +if test "${lt_cv_path_MAGIC_CMD+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + case $MAGIC_CMD in + /*) + lt_cv_path_MAGIC_CMD="$MAGIC_CMD" # Let the user override the test with a path. + ;; + ?:/*) + lt_cv_path_MAGIC_CMD="$MAGIC_CMD" # Let the user override the test with a dos path. + ;; + *) + ac_save_MAGIC_CMD="$MAGIC_CMD" + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" + ac_dummy="/usr/bin:$PATH" + for ac_dir in $ac_dummy; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/${ac_tool_prefix}file; then + lt_cv_path_MAGIC_CMD="$ac_dir/${ac_tool_prefix}file" + if test -n "$file_magic_test_file"; then + case $deplibs_check_method in + "file_magic "*) + file_magic_regex="`expr \"$deplibs_check_method\" : \"file_magic \(.*\)\"`" + MAGIC_CMD="$lt_cv_path_MAGIC_CMD" + 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 + break + fi + done + IFS="$ac_save_ifs" + MAGIC_CMD="$ac_save_MAGIC_CMD" + ;; +esac +fi + +MAGIC_CMD="$lt_cv_path_MAGIC_CMD" +if test -n "$MAGIC_CMD"; then + echo "$as_me:$LINENO: result: $MAGIC_CMD" >&5 +echo "${ECHO_T}$MAGIC_CMD" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + +if test -z "$lt_cv_path_MAGIC_CMD"; then + if test -n "$ac_tool_prefix"; then + echo "$as_me:$LINENO: checking for file" >&5 +echo $ECHO_N "checking for file... $ECHO_C" >&6 +if test "${lt_cv_path_MAGIC_CMD+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + case $MAGIC_CMD in + /*) + lt_cv_path_MAGIC_CMD="$MAGIC_CMD" # Let the user override the test with a path. + ;; + ?:/*) + lt_cv_path_MAGIC_CMD="$MAGIC_CMD" # Let the user override the test with a dos path. + ;; + *) + ac_save_MAGIC_CMD="$MAGIC_CMD" + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" + ac_dummy="/usr/bin:$PATH" + for ac_dir in $ac_dummy; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/file; then + lt_cv_path_MAGIC_CMD="$ac_dir/file" + if test -n "$file_magic_test_file"; then + case $deplibs_check_method in + "file_magic "*) + file_magic_regex="`expr \"$deplibs_check_method\" : \"file_magic \(.*\)\"`" + MAGIC_CMD="$lt_cv_path_MAGIC_CMD" + 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 + break + fi + done + IFS="$ac_save_ifs" + MAGIC_CMD="$ac_save_MAGIC_CMD" + ;; +esac +fi + +MAGIC_CMD="$lt_cv_path_MAGIC_CMD" +if test -n "$MAGIC_CMD"; then + echo "$as_me:$LINENO: result: $MAGIC_CMD" >&5 +echo "${ECHO_T}$MAGIC_CMD" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + + else + MAGIC_CMD=: + fi +fi + + fi + ;; +esac + +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 + +if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}strip", so it can be a program name with args. +set dummy ${ac_tool_prefix}strip; 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_STRIP+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$STRIP"; then + ac_cv_prog_STRIP="$STRIP" # 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_STRIP="${ac_tool_prefix}strip" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + +fi +fi +STRIP=$ac_cv_prog_STRIP +if test -n "$STRIP"; then + echo "$as_me:$LINENO: result: $STRIP" >&5 +echo "${ECHO_T}$STRIP" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + +fi +if test -z "$ac_cv_prog_STRIP"; then + ac_ct_STRIP=$STRIP + # Extract the first word of "strip", so it can be a program name with args. +set dummy strip; 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_STRIP+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$ac_ct_STRIP"; then + ac_cv_prog_ac_ct_STRIP="$ac_ct_STRIP" # 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_STRIP="strip" + 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_STRIP" && ac_cv_prog_ac_ct_STRIP=":" +fi +fi +ac_ct_STRIP=$ac_cv_prog_ac_ct_STRIP +if test -n "$ac_ct_STRIP"; then + echo "$as_me:$LINENO: result: $ac_ct_STRIP" >&5 +echo "${ECHO_T}$ac_ct_STRIP" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + + STRIP=$ac_ct_STRIP +else + STRIP="$ac_cv_prog_STRIP" +fi + + +enable_dlopen=no +enable_win32_dll=no + +# 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 && enable_libtool_lock=yes + +# Some flags need to be propagated to the compiler or linker for good +# libtool support. +case $host in +*-*-irix6*) + # Find out which ABI we are using. + echo '#line 4650 "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.$ac_objext` 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 + + + 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 + + cat >conftest.$ac_ext <<_ACEOF +#line $LINENO "configure" +/* 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>&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.$ac_objext conftest$ac_exeext 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 + +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 + +# 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' + +# Constants: +rm="rm -f" + +# Global variables: +default_ofile=libtool +can_build_shared=yes + +# All known linkers require a `.a' archive for static linking (except M$VC, +# which needs '.lib'). +libext=a +ltmain="$ac_aux_dir/ltmain.sh" +ofile="$default_ofile" +with_gnu_ld="$lt_cv_prog_gnu_ld" +need_locks="$enable_libtool_lock" + +old_CC="$CC" +old_CFLAGS="$CFLAGS" + +# Set sane defaults for various variables +test -z "$AR" && AR=ar +test -z "$AR_FLAGS" && AR_FLAGS=cru +test -z "$AS" && AS=as +test -z "$CC" && CC=cc +test -z "$DLLTOOL" && DLLTOOL=dlltool +test -z "$LD" && LD=ld +test -z "$LN_S" && LN_S="ln -s" +test -z "$MAGIC_CMD" && MAGIC_CMD=file +test -z "$NM" && NM=nm +test -z "$OBJDUMP" && OBJDUMP=objdump +test -z "$RANLIB" && RANLIB=: +test -z "$STRIP" && STRIP=: +test -z "$ac_objext" && ac_objext=o + +if test x"$host" != x"$build"; then + ac_tool_prefix=${host_alias}- +else + ac_tool_prefix= +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 + +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 $AR_FLAGS $oldlib$oldobjs$old_deplibs' +old_postinstall_cmds='chmod 644 $oldlib' +old_postuninstall_cmds= + +if test -n "$RANLIB"; then + case $host_os in + openbsd*) + old_postinstall_cmds="\$RANLIB -t \$oldlib~$old_postinstall_cmds" + ;; + *) + old_postinstall_cmds="\$RANLIB \$oldlib~$old_postinstall_cmds" + ;; + esac + old_archive_cmds="$old_archive_cmds~\$RANLIB \$oldlib" +fi + +# Allow CC to be a program name with arguments. +set dummy $CC +compiler="$2" + +echo "$as_me:$LINENO: checking for objdir" >&5 +echo $ECHO_N "checking for objdir... $ECHO_C" >&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 "$as_me:$LINENO: result: $objdir" >&5 +echo "${ECHO_T}$objdir" >&6 + + + +# Check whether --with-pic or --without-pic was given. +if test "${with_pic+set}" = set; then + withval="$with_pic" + pic_mode="$withval" +else + pic_mode=default +fi; +test -z "$pic_mode" && pic_mode=default + +# We assume here that the value for lt_cv_prog_cc_pic will not be cached +# in isolation, and that seeing it set (from the cache) indicates that +# the associated values are set (in the cache) correctly too. +echo "$as_me:$LINENO: checking for $compiler option to produce PIC" >&5 +echo $ECHO_N "checking for $compiler option to produce PIC... $ECHO_C" >&6 +if test "${lt_cv_prog_cc_pic+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + lt_cv_prog_cc_pic= + lt_cv_prog_cc_shlib= + lt_cv_prog_cc_wl= + lt_cv_prog_cc_static= + lt_cv_prog_cc_no_builtin= + lt_cv_prog_cc_can_build_shared=$can_build_shared + + if test "$GCC" = yes; then + lt_cv_prog_cc_wl='-Wl,' + lt_cv_prog_cc_static='-static' + + case $host_os in + 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 + # not sure about C++ programs. + lt_cv_prog_cc_static="$lt_cv_prog_cc_static ${lt_cv_prog_cc_wl}-lC" + ;; + 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'. + lt_cv_prog_cc_pic='-m68020 -resident32 -malways-restore-a4' + ;; + beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*) + # PIC is the default for these OSes. + ;; + darwin* | rhapsody*) + # PIC is the default on this platform + # Common symbols not allowed in MH_DYLIB files + lt_cv_prog_cc_pic='-fno-common' + ;; + cygwin* | mingw* | pw32* | os2*) + # This hack is so that the source file can tell whether it is being + # built for inclusion in a dll (and should export symbols for example). + lt_cv_prog_cc_pic='-DDLL_EXPORT' + ;; + sysv4*MP*) + if test -d /usr/nec; then + lt_cv_prog_cc_pic=-Kconform_pic + fi + ;; + *) + lt_cv_prog_cc_pic='-fPIC' + ;; + esac + else + # PORTME Check for PIC flags for the system compiler. + case $host_os in + aix3* | aix4* | aix5*) + lt_cv_prog_cc_wl='-Wl,' + # All AIX code is PIC. + if test "$host_cpu" = ia64; then + # AIX 5 now supports IA64 processor + lt_cv_prog_cc_static='-Bstatic' + else + lt_cv_prog_cc_static='-bnso -bI:/lib/syscalls.exp' + fi + ;; + + hpux9* | hpux10* | hpux11*) + # Is there a better lt_cv_prog_cc_static that works with the bundled CC? + lt_cv_prog_cc_wl='-Wl,' + lt_cv_prog_cc_static="${lt_cv_prog_cc_wl}-a ${lt_cv_prog_cc_wl}archive" + lt_cv_prog_cc_pic='+Z' + ;; + + irix5* | irix6* | nonstopux*) + lt_cv_prog_cc_wl='-Wl,' + lt_cv_prog_cc_static='-non_shared' + # PIC (with -KPIC) is the default. + ;; + + cygwin* | mingw* | pw32* | os2*) + # This hack is so that the source file can tell whether it is being + # built for inclusion in a dll (and should export symbols for example). + lt_cv_prog_cc_pic='-DDLL_EXPORT' + ;; + + newsos6) + lt_cv_prog_cc_pic='-KPIC' + lt_cv_prog_cc_static='-Bstatic' + ;; + + osf3* | osf4* | osf5*) + # All OSF/1 code is PIC. + lt_cv_prog_cc_wl='-Wl,' + lt_cv_prog_cc_static='-non_shared' + ;; + + sco3.2v5*) + lt_cv_prog_cc_pic='-Kpic' + lt_cv_prog_cc_static='-dn' + lt_cv_prog_cc_shlib='-belf' + ;; + + solaris*) + lt_cv_prog_cc_pic='-KPIC' + lt_cv_prog_cc_static='-Bstatic' + lt_cv_prog_cc_wl='-Wl,' + ;; + + sunos4*) + lt_cv_prog_cc_pic='-PIC' + lt_cv_prog_cc_static='-Bstatic' + lt_cv_prog_cc_wl='-Qoption ld ' + ;; + + sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*) + lt_cv_prog_cc_pic='-KPIC' + lt_cv_prog_cc_static='-Bstatic' + lt_cv_prog_cc_wl='-Wl,' + ;; + + uts4*) + lt_cv_prog_cc_pic='-pic' + lt_cv_prog_cc_static='-Bstatic' + ;; + + sysv4*MP*) + if test -d /usr/nec ;then + lt_cv_prog_cc_pic='-Kconform_pic' + lt_cv_prog_cc_static='-Bstatic' + fi + ;; + + *) + lt_cv_prog_cc_can_build_shared=no + ;; + esac + fi + +fi + +if test -z "$lt_cv_prog_cc_pic"; then + echo "$as_me:$LINENO: result: none" >&5 +echo "${ECHO_T}none" >&6 +else + echo "$as_me:$LINENO: result: $lt_cv_prog_cc_pic" >&5 +echo "${ECHO_T}$lt_cv_prog_cc_pic" >&6 + + # Check to make sure the pic_flag actually works. + echo "$as_me:$LINENO: checking if $compiler PIC flag $lt_cv_prog_cc_pic works" >&5 +echo $ECHO_N "checking if $compiler PIC flag $lt_cv_prog_cc_pic works... $ECHO_C" >&6 + if test "${lt_cv_prog_cc_pic_works+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + save_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS $lt_cv_prog_cc_pic -DPIC" + cat >conftest.$ac_ext <<_ACEOF +#line $LINENO "configure" +/* 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>&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 + 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 + lt_cv_prog_cc_pic_works=no + else + lt_cv_prog_cc_pic_works=yes + fi + ;; + *) + lt_cv_prog_cc_pic_works=yes + ;; + esac + +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + lt_cv_prog_cc_pic_works=no + +fi +rm -f conftest.$ac_objext conftest.$ac_ext + CFLAGS="$save_CFLAGS" + +fi + + + if test "X$lt_cv_prog_cc_pic_works" = Xno; then + lt_cv_prog_cc_pic= + lt_cv_prog_cc_can_build_shared=no + else + lt_cv_prog_cc_pic=" $lt_cv_prog_cc_pic" + fi + + echo "$as_me:$LINENO: result: $lt_cv_prog_cc_pic_works" >&5 +echo "${ECHO_T}$lt_cv_prog_cc_pic_works" >&6 +fi + +# Check for any special shared library compilation flags. +if test -n "$lt_cv_prog_cc_shlib"; then + { echo "$as_me:$LINENO: WARNING: \`$CC' requires \`$lt_cv_prog_cc_shlib' to build shared libraries" >&5 +echo "$as_me: WARNING: \`$CC' requires \`$lt_cv_prog_cc_shlib' to build shared libraries" >&2;} + if echo "$old_CC $old_CFLAGS " | egrep -e "[ ]$lt_cv_prog_cc_shlib[ ]" >/dev/null; then : + else + { echo "$as_me:$LINENO: WARNING: add \`$lt_cv_prog_cc_shlib' to the CC or CFLAGS env variable and reconfigure" >&5 +echo "$as_me: WARNING: add \`$lt_cv_prog_cc_shlib' to the CC or CFLAGS env variable and reconfigure" >&2;} + lt_cv_prog_cc_can_build_shared=no + fi +fi + +echo "$as_me:$LINENO: checking if $compiler static flag $lt_cv_prog_cc_static works" >&5 +echo $ECHO_N "checking if $compiler static flag $lt_cv_prog_cc_static works... $ECHO_C" >&6 +if test "${lt_cv_prog_cc_static_works+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + lt_cv_prog_cc_static_works=no + save_LDFLAGS="$LDFLAGS" + LDFLAGS="$LDFLAGS $lt_cv_prog_cc_static" + cat >conftest.$ac_ext <<_ACEOF +#line $LINENO "configure" +/* 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>&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_prog_cc_static_works=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +fi +rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext + LDFLAGS="$save_LDFLAGS" + +fi + + +# Belt *and* braces to stop my trousers falling down: +test "X$lt_cv_prog_cc_static_works" = Xno && lt_cv_prog_cc_static= +echo "$as_me:$LINENO: result: $lt_cv_prog_cc_static_works" >&5 +echo "${ECHO_T}$lt_cv_prog_cc_static_works" >&6 + +pic_flag="$lt_cv_prog_cc_pic" +special_shlib_compile_flags="$lt_cv_prog_cc_shlib" +wl="$lt_cv_prog_cc_wl" +link_static_flag="$lt_cv_prog_cc_static" +no_builtin_flag="$lt_cv_prog_cc_no_builtin" +can_build_shared="$lt_cv_prog_cc_can_build_shared" + + +# Check to see if options -o and -c are simultaneously supported by compiler +echo "$as_me:$LINENO: checking if $compiler supports -c -o file.$ac_objext" >&5 +echo $ECHO_N "checking if $compiler supports -c -o file.$ac_objext... $ECHO_C" >&6 +if test "${lt_cv_compiler_c_o+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + +$rm -r conftest 2>/dev/null +mkdir conftest +cd conftest +echo "int some_variable = 0;" > conftest.$ac_ext +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.$ac_objext" +compiler_c_o=no +if { (eval echo configure:5179: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>out/conftest.err; } && test -s out/conftest2.$ac_objext; 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 + lt_cv_compiler_c_o=no + else + lt_cv_compiler_c_o=yes + fi +else + # Append any errors to the config.log. + cat out/conftest.err 1>&5 + lt_cv_compiler_c_o=no +fi +CFLAGS="$save_CFLAGS" +chmod u+w . +$rm conftest* out/* +rmdir out +cd .. +rmdir conftest +$rm -r conftest 2>/dev/null + +fi + +compiler_c_o=$lt_cv_compiler_c_o +echo "$as_me:$LINENO: result: $compiler_c_o" >&5 +echo "${ECHO_T}$compiler_c_o" >&6 + +if test x"$compiler_c_o" = x"yes"; then + # Check to see if we can write to a .lo + echo "$as_me:$LINENO: checking if $compiler supports -c -o file.lo" >&5 +echo $ECHO_N "checking if $compiler supports -c -o file.lo... $ECHO_C" >&6 + if test "${lt_cv_compiler_o_lo+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + + lt_cv_compiler_o_lo=no + save_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS -c -o conftest.lo" + save_objext="$ac_objext" + ac_objext=lo + cat >conftest.$ac_ext <<_ACEOF +#line $LINENO "configure" +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ +int some_variable = 0; + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +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); } && + { 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 + # 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 + lt_cv_compiler_o_lo=no + else + lt_cv_compiler_o_lo=yes + fi + +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +fi +rm -f conftest.$ac_objext conftest.$ac_ext + ac_objext="$save_objext" + CFLAGS="$save_CFLAGS" + +fi + + compiler_o_lo=$lt_cv_compiler_o_lo + echo "$as_me:$LINENO: result: $compiler_o_lo" >&5 +echo "${ECHO_T}$compiler_o_lo" >&6 +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 "$as_me:$LINENO: checking if we can lock with hard links" >&5 +echo $ECHO_N "checking if we can lock with hard links... $ECHO_C" >&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 "$as_me:$LINENO: result: $hard_links" >&5 +echo "${ECHO_T}$hard_links" >&6 + if test "$hard_links" = no; then + { echo "$as_me:$LINENO: WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&5 +echo "$as_me: 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 "$GCC" = yes; then + # Check to see if options -fno-rtti -fno-exceptions are supported by compiler + echo "$as_me:$LINENO: checking if $compiler supports -fno-rtti -fno-exceptions" >&5 +echo $ECHO_N "checking if $compiler supports -fno-rtti -fno-exceptions... $ECHO_C" >&6 + echo "int some_variable = 0;" > conftest.$ac_ext + save_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS -fno-rtti -fno-exceptions -c conftest.$ac_ext" + compiler_rtti_exceptions=no + cat >conftest.$ac_ext <<_ACEOF +#line $LINENO "configure" +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ +int some_variable = 0; + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +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); } && + { 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 + # 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 + compiler_rtti_exceptions=no + else + compiler_rtti_exceptions=yes + fi + +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +fi +rm -f conftest.$ac_objext conftest.$ac_ext + CFLAGS="$save_CFLAGS" + echo "$as_me:$LINENO: result: $compiler_rtti_exceptions" >&5 +echo "${ECHO_T}$compiler_rtti_exceptions" >&6 + + if test "$compiler_rtti_exceptions" = "yes"; then + no_builtin_flag=' -fno-builtin -fno-rtti -fno-exceptions' + else + no_builtin_flag=' -fno-builtin' + fi +fi + +# See if the linker supports building shared libraries. +echo "$as_me:$LINENO: checking whether the linker ($LD) supports shared libraries" >&5 +echo $ECHO_N "checking whether the linker ($LD) supports shared libraries... $ECHO_C" >&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= +old_archive_from_expsyms_cmds= +export_dynamic_flag_spec= +whole_archive_flag_spec= +thread_safe_flag_spec= +hardcode_into_libs=no +hardcode_libdir_flag_spec= +hardcode_libdir_separator= +hardcode_direct=no +hardcode_minus_L=no +hardcode_shlibpath_var=unsupported +runpath_var= +link_all_deplibs=unknown +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. +extract_expsyms_cmds= + +case $host_os in +cygwin* | mingw* | pw32*) + # 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 "$GCC" != yes; then + with_gnu_ld=no + fi + ;; +openbsd*) + with_gnu_ld=no + ;; +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* | aix5*) + # On AIX, the GNU linker is very broken + # Note:Check GNU linker on AIX 5-IA64 when/if it becomes available. + 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 $output_objdir/a2ixlibrary.data~$echo "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$echo "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$echo "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$echo "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_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 $compiler_flags ${wl}-soname $wl$soname -o $lib' + else + ld_shlibs=no + fi + ;; + + cygwin* | mingw* | pw32*) + # 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_expsyms_cmds='test -f $output_objdir/impgen.c || \ + sed -e "/^# \/\* impgen\.c starts here \*\//,/^# \/\* impgen.c ends here \*\// { s/^# //;s/^# *$//; p; }" -e d < $''0 > $output_objdir/impgen.c~ + test -f $output_objdir/impgen.exe || (cd $output_objdir && \ + if test "x$HOST_CC" != "x" ; then $HOST_CC -o impgen impgen.c ; \ + else $CC -o impgen impgen.c ; fi)~ + $output_objdir/impgen $dir/$soroot > $output_objdir/$soname-def' + + old_archive_from_expsyms_cmds='$DLLTOOL --as=$AS --dllname $soname --def $output_objdir/$soname-def --output-lib $output_objdir/$newlib' + + # cygwin and mingw dlls have different entry points and sets of symbols + # to exclude. + # FIXME: what about values for MSVC? + dll_entry=__cygwin_dll_entry@12 + dll_exclude_symbols=DllMain@12,_cygwin_dll_entry@12,_cygwin_noncygwin_dll_entry@12~ + case $host_os in + mingw*) + # mingw values + dll_entry=_DllMainCRTStartup@12 + dll_exclude_symbols=DllMain@12,DllMainCRTStartup@12,DllEntryPoint@12~ + ;; + esac + + # mingw and cygwin differ, and it's simplest to just exclude the union + # of the two symbol sets. + dll_exclude_symbols=DllMain@12,_cygwin_dll_entry@12,_cygwin_noncygwin_dll_entry@12,DllMainCRTStartup@12,DllEntryPoint@12 + + # recent cygwin and mingw systems supply a stub DllMain which the user + # can override, but on older systems we have to supply one (in ltdll.c) + if test "x$lt_cv_need_dllmain" = "xyes"; then + ltdll_obj='$output_objdir/$soname-ltdll.'"$ac_objext " + ltdll_cmds='test -f $output_objdir/$soname-ltdll.c || sed -e "/^# \/\* ltdll\.c starts here \*\//,/^# \/\* ltdll.c ends here \*\// { s/^# //; p; }" -e d < $''0 > $output_objdir/$soname-ltdll.c~ + test -f $output_objdir/$soname-ltdll.$ac_objext || (cd $output_objdir && $CC -c $soname-ltdll.c)~' + else + ltdll_obj= + ltdll_cmds= + fi + + # 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. + # Be careful not to strip the DATA tag left be newer dlltools. + export_symbols_cmds="$ltdll_cmds"' + $DLLTOOL --export-all --exclude-symbols '$dll_exclude_symbols' --output-def $output_objdir/$soname-def '$ltdll_obj'$libobjs $convenience~ + sed -e "1,/EXPORTS/d" -e "s/ @ [0-9]*//" -e "s/ *;.*$//" < $output_objdir/$soname-def > $export_symbols' + + # If the export-symbols file already is a .def file (1st line + # is EXPORTS), use it as is. + # If DATA tags from a recent dlltool are present, honour them! + archive_expsym_cmds='if test "x`sed 1q $export_symbols`" = xEXPORTS; then + cp $export_symbols $output_objdir/$soname-def; + else + echo EXPORTS > $output_objdir/$soname-def; + _lt_hint=1; + cat $export_symbols | while read symbol; do + set dummy \$symbol; + case \$# in + 2) echo " \$2 @ \$_lt_hint ; " >> $output_objdir/$soname-def;; + 4) echo " \$2 \$3 \$4 ; " >> $output_objdir/$soname-def; _lt_hint=`expr \$_lt_hint - 1`;; + *) echo " \$2 @ \$_lt_hint \$3 ; " >> $output_objdir/$soname-def;; + esac; + _lt_hint=`expr 1 + \$_lt_hint`; + done; + fi~ + '"$ltdll_cmds"' + $CC -Wl,--base-file,$output_objdir/$soname-base '$lt_cv_cc_dll_switch' -Wl,-e,'$dll_entry' -o $output_objdir/$soname '$ltdll_obj'$libobjs $deplibs $compiler_flags~ + $DLLTOOL --as=$AS --dllname $soname --exclude-symbols '$dll_exclude_symbols' --def $output_objdir/$soname-def --base-file $output_objdir/$soname-base --output-exp $output_objdir/$soname-exp~ + $CC -Wl,--base-file,$output_objdir/$soname-base $output_objdir/$soname-exp '$lt_cv_cc_dll_switch' -Wl,-e,'$dll_entry' -o $output_objdir/$soname '$ltdll_obj'$libobjs $deplibs $compiler_flags~ + $DLLTOOL --as=$AS --dllname $soname --exclude-symbols '$dll_exclude_symbols' --def $output_objdir/$soname-def --base-file $output_objdir/$soname-base --output-exp $output_objdir/$soname-exp --output-lib $output_objdir/$libname.dll.a~ + $CC $output_objdir/$soname-exp '$lt_cv_cc_dll_switch' -Wl,-e,'$dll_entry' -o $output_objdir/$soname '$ltdll_obj'$libobjs $deplibs $compiler_flags' + ;; + + netbsd*) + if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then + archive_cmds='$LD -Bshareable $libobjs $deplibs $linker_flags -o $lib' + wlarc= + else + archive_cmds='$CC -shared -nodefaultlibs $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + archive_expsym_cmds='$CC -shared -nodefaultlibs $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + 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 $compiler_flags ${wl}-soname $wl$soname -o $lib' + archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${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 $linker_flags' + 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 $compiler_flags ${wl}-soname $wl$soname -o $lib' + archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${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* | pw32*) + # 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 $output_objdir/$soname $libobjs $deplibs $linker_flags -bE:$export_symbols -T512 -H512 -bM:SRE~$AR $AR_FLAGS $lib $output_objdir/$soname' + # Note: this linker hardcodes the directories in LIBPATH if there + # are no directories specified by -L. + hardcode_minus_L=yes + if test "$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* | aix5*) + if test "$host_cpu" = ia64; then + # On IA64, the linker does run time linking by default, so we don't + # have to do anything special. + aix_use_runtimelinking=no + exp_sym_flag='-Bexport' + no_entry_flag="" + else + aix_use_runtimelinking=no + + # Test if we are trying to use run time linking or normal + # AIX style linking. If -brtl is somewhere in LDFLAGS, we + # need to do runtime linking. + case $host_os in aix4.[23]|aix4.[23].*|aix5*) + for ld_flag in $LDFLAGS; do + case $ld_flag in + *-brtl*) + aix_use_runtimelinking=yes + break + ;; + esac + done + esac + + exp_sym_flag='-bexport' + no_entry_flag='-bnoentry' + fi + + # When large executables or shared objects are built, AIX ld can + # have problems creating the table of contents. If linking a library + # or program results in "error TOC overflow" add -mminimal-toc to + # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not + # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS. + + hardcode_direct=yes + archive_cmds='' + hardcode_libdir_separator=':' + if test "$GCC" = yes; then + case $host_os in aix4.[012]|aix4.[012].*) + 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 + esac + + shared_flag='-shared' + else + # not using gcc + if test "$host_cpu" = ia64; then + shared_flag='${wl}-G' + else + if test "$aix_use_runtimelinking" = yes; then + shared_flag='${wl}-G' + else + shared_flag='${wl}-bM:SRE' + fi + fi + fi + + # It seems that -bexpall can do strange things, so it is better to + # generate a list of symbols to export. + always_export_symbols=yes + if test "$aix_use_runtimelinking" = yes; then + # Warning - without using the other runtime loading flags (-brtl), + # -berok will link without error, but may produce a broken library. + allow_undefined_flag='-berok' + hardcode_libdir_flag_spec='${wl}-blibpath:$libdir:/usr/lib:/lib' + archive_expsym_cmds="\$CC"' -o $output_objdir/$soname $libobjs $deplibs $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then echo "${wl}${allow_undefined_flag}"; else :; fi` '"\${wl}$no_entry_flag \${wl}$exp_sym_flag:\$export_symbols $shared_flag" + else + if test "$host_cpu" = ia64; then + hardcode_libdir_flag_spec='${wl}-R $libdir:/usr/lib:/lib' + allow_undefined_flag="-z nodefs" + archive_expsym_cmds="\$CC $shared_flag"' -o $output_objdir/$soname ${wl}-h$soname $libobjs $deplibs $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$no_entry_flag \${wl}$exp_sym_flag:\$export_symbols" + else + hardcode_libdir_flag_spec='${wl}-bnolibpath ${wl}-blibpath:$libdir:/usr/lib:/lib' + # Warning - without using the other run time loading flags, + # -berok will link without error, but may produce a broken library. + allow_undefined_flag='${wl}-berok' + # This is a bit strange, but is similar to how AIX traditionally builds + # it's shared libraries. + archive_expsym_cmds="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs $compiler_flags ${allow_undefined_flag} '"\${wl}$no_entry_flag \${wl}$exp_sym_flag:\$export_symbols"' ~$AR -crlo $objdir/$libname$release.a $objdir/$soname' + fi + fi + ;; + + amigaos*) + archive_cmds='$rm $output_objdir/a2ixlibrary.data~$echo "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$echo "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$echo "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$echo "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_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* | pw32*) + # 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 $compiler_flags `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$old_deplibs' + fix_srcfile_path='`cygpath -w "$srcfile"`' + ;; + + darwin* | rhapsody*) + case "$host_os" in + rhapsody* | darwin1.[012]) + allow_undefined_flag='-undefined suppress' + ;; + *) # Darwin 1.3 on + allow_undefined_flag='-flat_namespace -undefined suppress' + ;; + esac + # FIXME: Relying on posixy $() will cause problems for + # cross-compilation, but unfortunately the echo tests do not + # yet detect zsh echo's removal of \ escapes. Also zsh mangles + # `"' quotes if we put them in here... so don't! + archive_cmds='$CC -r -keep_private_externs -nostdlib -o ${lib}-master.o $libobjs && $CC $(test .$module = .yes && echo -bundle || echo -dynamiclib) $allow_undefined_flag -o $lib ${lib}-master.o $deplibs$linker_flags $(test .$module != .yes && echo -install_name $rpath/$soname $verstring)' + # We need to add '_' to the symbols in $export_symbols first + #archive_expsym_cmds="$archive_cmds"' && strip -s $export_symbols' + hardcode_direct=yes + hardcode_shlibpath_var=no + whole_archive_flag_spec='-all_load $convenience' + ;; + + 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 $linker_flags /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 $linker_flags' + 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 $compiler_flags' + hardcode_libdir_flag_spec='-R$libdir' + hardcode_direct=yes + hardcode_shlibpath_var=no + ;; + + hpux9* | hpux10* | hpux11*) + case $host_os in + hpux9*) archive_cmds='$rm $output_objdir/$soname~$LD -b +b $install_libdir -o $output_objdir/$soname $libobjs $deplibs $linker_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' ;; + *) archive_cmds='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags' ;; + 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* | nonstopux*) + if test "$GCC" = yes; then + archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' + else + archive_cmds='$LD -shared $libobjs $deplibs $linker_flags -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib' + hardcode_libdir_flag_spec='-rpath $libdir' + fi + hardcode_libdir_separator=: + link_all_deplibs=yes + ;; + + netbsd*) + if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then + archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' # a.out + else + archive_cmds='$LD -shared -o $lib $libobjs $deplibs $linker_flags' # ELF + fi + hardcode_libdir_flag_spec='-R$libdir' + hardcode_direct=yes + hardcode_shlibpath_var=no + ;; + + newsos6) + archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + hardcode_direct=yes + hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' + hardcode_libdir_separator=: + hardcode_shlibpath_var=no + ;; + + openbsd*) + hardcode_direct=yes + hardcode_shlibpath_var=no + if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then + archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' + hardcode_libdir_flag_spec='${wl}-rpath,$libdir' + export_dynamic_flag_spec='${wl}-E' + else + case "$host_os" in + openbsd[01].* | openbsd2.[0-7] | openbsd2.[0-7].*) + archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' + hardcode_libdir_flag_spec='-R$libdir' + ;; + *) + archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' + hardcode_libdir_flag_spec='${wl}-rpath,$libdir' + ;; + esac + fi + ;; + + os2*) + hardcode_libdir_flag_spec='-L$libdir' + hardcode_minus_L=yes + allow_undefined_flag=unsupported + archive_cmds='$echo "LIBRARY $libname INITINSTANCE" > $output_objdir/$libname.def~$echo "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~$echo DATA >> $output_objdir/$libname.def~$echo " SINGLE NONSHARED" >> $output_objdir/$libname.def~$echo EXPORTS >> $output_objdir/$libname.def~emxexp $libobjs >> $output_objdir/$libname.def~$CC -Zdll -Zcrtdll -o $lib $libobjs $deplibs $compiler_flags $output_objdir/$libname.def' + old_archive_from_new_cmds='emximp -o $output_objdir/$libname.a $output_objdir/$libname.def' + ;; + + osf3*) + if test "$GCC" = yes; then + allow_undefined_flag=' ${wl}-expect_unresolved ${wl}\*' + archive_cmds='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + else + allow_undefined_flag=' -expect_unresolved \*' + archive_cmds='$LD -shared${allow_undefined_flag} $libobjs $deplibs $linker_flags -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_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 -msym flag + if test "$GCC" = yes; then + allow_undefined_flag=' ${wl}-expect_unresolved ${wl}\*' + archive_cmds='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' + else + allow_undefined_flag=' -expect_unresolved \*' + archive_cmds='$LD -shared${allow_undefined_flag} $libobjs $deplibs $linker_flags -msym -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib' + archive_expsym_cmds='for i in `cat $export_symbols`; do printf "-exported_symbol " >> $lib.exp; echo "\$i" >> $lib.exp; done; echo "-hidden">> $lib.exp~ + $LD -shared${allow_undefined_flag} -input $lib.exp $linker_flags $libobjs $deplibs -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${objdir}/so_locations -o $lib~$rm $lib.exp' + + #Both c and cxx compiler support -rpath directly + hardcode_libdir_flag_spec='-rpath $libdir' + fi + hardcode_libdir_separator=: + ;; + + sco3.2v5*) + archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + hardcode_shlibpath_var=no + runpath_var=LD_RUN_PATH + hardcode_runpath_var=yes + export_dynamic_flag_spec='${wl}-Bexport' + ;; + + solaris*) + # gcc --version < 3.0 without binutils cannot create self contained + # shared libraries reliably, requiring libgcc.a to resolve some of + # the object symbols generated in some cases. Libraries that use + # assert need libgcc.a to resolve __eprintf, for example. Linking + # a copy of libgcc.a into every shared library to guarantee resolving + # such symbols causes other problems: According to Tim Van Holder + # , C++ libraries end up with a separate + # (to the application) exception stack for one thing. + no_undefined_flag=' -z defs' + if test "$GCC" = yes; then + case `$CC --version 2>/dev/null` in + [12].*) + cat <&2 + +*** Warning: Releases of GCC earlier than version 3.0 cannot reliably +*** create self contained shared libraries on Solaris systems, without +*** introducing a dependency on libgcc.a. Therefore, libtool is disabling +*** -no-undefined support, which will at least allow you to build shared +*** libraries. However, you may find that when you link such libraries +*** into an application without using GCC, you have to manually add +*** \`gcc --print-libgcc-file-name\` to the link command. We urge you to +*** upgrade to a newer version of GCC. Another option is to rebuild your +*** current GCC to use the GNU linker from GNU binutils 2.9.1 or newer. + +EOF + no_undefined_flag= + ;; + esac + fi + # $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 $linker_flags' + 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 $linker_flags~$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 + link_all_deplibs=yes + ;; + + sunos4*) + if test "x$host_vendor" = xsequent; then + # Use $CC to link under sequent, because it throws in some extra .o + # files that make .init and .fini sections work. + archive_cmds='$CC -G ${wl}-h $soname -o $lib $libobjs $deplibs $compiler_flags' + else + archive_cmds='$LD -assert pure-text -Bstatic -o $lib $libobjs $deplibs $linker_flags' + fi + hardcode_libdir_flag_spec='-L$libdir' + hardcode_direct=yes + hardcode_minus_L=yes + hardcode_shlibpath_var=no + ;; + + sysv4) + case $host_vendor in + sni) + archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + hardcode_direct=yes # is this really true??? + ;; + siemens) + ## LD is ld it makes a PLAMLIB + ## CC just makes a GrossModule. + archive_cmds='$LD -G -o $lib $libobjs $deplibs $linker_flags' + reload_cmds='$CC -r -o $output$reload_objs' + hardcode_direct=no + ;; + motorola) + archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + hardcode_direct=no #Motorola manual says yes, but my tests say they lie + ;; + esac + runpath_var='LD_RUN_PATH' + hardcode_shlibpath_var=no + ;; + + sysv4.3*) + archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + 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 $linker_flags' + 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 $linker_flags~$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 $linker_flags' + hardcode_libdir_flag_spec='-L$libdir' + hardcode_shlibpath_var=no + ;; + + dgux*) + archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + 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 $linker_flags' + 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 $linker_flags' + hardcode_direct=yes + hardcode_minus_L=no + hardcode_shlibpath_var=no + hardcode_runpath_var=yes + runpath_var=LD_RUN_PATH + ;; + + sysv5uw7* | unixware7*) + no_undefined_flag='${wl}-z ${wl}text' + if test "$GCC" = yes; then + archive_cmds='$CC -shared ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' + else + archive_cmds='$CC -G ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' + fi + runpath_var='LD_RUN_PATH' + hardcode_shlibpath_var=no + ;; + + *) + ld_shlibs=no + ;; + esac +fi +echo "$as_me:$LINENO: result: $ld_shlibs" >&5 +echo "${ECHO_T}$ld_shlibs" >&6 +test "$ld_shlibs" = no && can_build_shared=no + +# Check hardcoding attributes. +echo "$as_me:$LINENO: checking how to hardcode library paths into programs" >&5 +echo $ECHO_N "checking how to hardcode library paths into programs... $ECHO_C" >&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 "$as_me:$LINENO: result: $hardcode_action" >&5 +echo "${ECHO_T}$hardcode_action" >&6 + +striplib= +old_striplib= +echo "$as_me:$LINENO: checking whether stripping libraries is possible" >&5 +echo $ECHO_N "checking whether stripping libraries is possible... $ECHO_C" >&6 +if test -n "$STRIP" && $STRIP -V 2>&1 | grep "GNU strip" >/dev/null; then + test -z "$old_striplib" && old_striplib="$STRIP --strip-debug" + test -z "$striplib" && striplib="$STRIP --strip-unneeded" + echo "$as_me:$LINENO: result: yes" >&5 +echo "${ECHO_T}yes" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + +reload_cmds='$LD$reload_flag -o $output$reload_objs' +test -z "$deplibs_check_method" && deplibs_check_method=unknown + +# PORTME Fill in your ld.so characteristics +echo "$as_me:$LINENO: checking dynamic linker characteristics" >&5 +echo $ECHO_N "checking dynamic linker characteristics... $ECHO_C" >&6 +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" + +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* | aix5*) + version_type=linux + need_lib_prefix=no + need_version=no + hardcode_into_libs=yes + if test "$host_cpu" = ia64; then + # AIX 5 supports IA64 + library_names_spec='${libname}${release}.so$major ${libname}${release}.so$versuffix $libname.so' + shlibpath_var=LD_LIBRARY_PATH + else + # With GCC up to 2.95.x, collect2 would create an import file + # for dependence libraries. The import file would start with + # the line `#! .'. This would cause the generated library to + # depend on `.', always an invalid library. This was fixed in + # development snapshots of GCC prior to 3.0. + case $host_os in + aix4 | aix4.[01] | aix4.[01].*) + if { echo '#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 97)' + echo ' yes ' + echo '#endif'; } | ${CC} -E - | grep yes > /dev/null; then + : + else + can_build_shared=no + fi + ;; + esac + # AIX (on Power*) 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. + if test "$aix_use_runtimelinking" = yes; then + # If using run time linking (on AIX 4.2 or later) use lib.so + # instead of lib.a to let people know that these are not + # typical AIX shared libraries. + library_names_spec='${libname}${release}.so$versuffix ${libname}${release}.so$major $libname.so' + else + # We preserve .a as extension for shared libraries through AIX4.2 + # and later when we are not doing run time linking. + library_names_spec='${libname}${release}.a $libname.a' + soname_spec='${libname}${release}.so$major' + fi + shlibpath_var=LIBPATH + fi + hardcode_into_libs=yes + ;; + +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 + ;; + +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 + 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* | pw32*) + version_type=windows + need_version=no + need_lib_prefix=no + case $GCC,$host_os in + yes,cygwin*) + library_names_spec='$libname.dll.a' + soname_spec='`echo ${libname} | sed -e 's/^lib/cyg/'``echo ${release} | sed -e 's/[.]/-/g'`${versuffix}.dll' + postinstall_cmds='dlpath=`bash 2>&1 -c '\''. $dir/${file}i;echo \$dlname'\''`~ + dldir=$destdir/`dirname \$dlpath`~ + test -d \$dldir || mkdir -p \$dldir~ + $install_prog .libs/$dlname \$dldir/$dlname' + postuninstall_cmds='dldll=`bash 2>&1 -c '\''. $file; echo \$dlname'\''`~ + dlpath=$dir/\$dldll~ + $rm \$dlpath' + ;; + yes,mingw*) + library_names_spec='${libname}`echo ${release} | sed -e 's/[.]/-/g'`${versuffix}.dll' + sys_lib_search_path_spec=`$CC -print-search-dirs | grep "^libraries:" | sed -e "s/^libraries://" -e "s/;/ /g" -e "s,=/,/,g"` + ;; + yes,pw32*) + library_names_spec='`echo ${libname} | sed -e 's/^lib/pw/'``echo ${release} | sed -e 's/./-/g'`${versuffix}.dll' + ;; + *) + library_names_spec='${libname}`echo ${release} | sed -e 's/[.]/-/g'`${versuffix}.dll $libname.lib' + ;; + esac + dynamic_linker='Win32 ld.exe' + # FIXME: first we should search . and the directory the executable is in + shlibpath_var=PATH + ;; + +darwin* | rhapsody*) + dynamic_linker="$host_os dyld" + version_type=darwin + need_lib_prefix=no + need_version=no + # FIXME: Relying on posixy $() will cause problems for + # cross-compilation, but unfortunately the echo tests do not + # yet detect zsh echo's removal of \ escapes. + library_names_spec='${libname}${release}${versuffix}.$(test .$module = .yes && echo so || echo dylib) ${libname}${release}${major}.$(test .$module = .yes && echo so || echo dylib) ${libname}.$(test .$module = .yes && echo so || echo dylib)' + soname_spec='${libname}${release}${major}.$(test .$module = .yes && echo so || echo dylib)' + shlibpath_overrides_runpath=yes + shlibpath_var=DYLD_LIBRARY_PATH + ;; + +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*) + library_names_spec='${libname}${release}.so$versuffix ${libname}${release}.so $libname.so' + need_version=no + need_lib_prefix=no + ;; + freebsd-*) + library_names_spec='${libname}${release}.so$versuffix $libname.so$versuffix' + need_version=yes + ;; + esac + shlibpath_var=LD_LIBRARY_PATH + case $host_os in + freebsd2*) + shlibpath_overrides_runpath=yes + ;; + *) + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + ;; + 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 + hardcode_into_libs=yes + ;; + +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* | nonstopux*) + case $host_os in + nonstopux*) version_type=nonstopux ;; + *) version_type=irix ;; + esac + 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* | nonstopux*) + libsuff= shlibsuff= + ;; + *) + 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}" + ;; + +# 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 + # This implies no fast_install, which is unacceptable. + # Some rework will be needed to allow for fast_install + # before this can be enabled. + hardcode_into_libs=yes + + # We used to test for /lib/ld.so.1 and disable shared libraries on + # powerpc, because MkLinux only supported shared libraries with the + # GNU dynamic linker. Since this was broken with cross compilers, + # most powerpc-linux boxes support dynamic linking these days and + # people can always --disable-shared, the test was removed, and we + # assume the GNU/Linux dynamic linker is in use. + dynamic_linker='GNU/Linux ld.so' + ;; + +netbsd*) + version_type=sunos + need_lib_prefix=no + need_version=no + 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 + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + ;; + +newsos6) + version_type=linux + library_names_spec='${libname}${release}.so$versuffix ${libname}${release}.so$major $libname.so' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + ;; + +openbsd*) + version_type=sunos + need_lib_prefix=no + need_version=no + if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then + case "$host_os" in + openbsd2.[89] | openbsd2.[89].*) + shlibpath_overrides_runpath=no + ;; + *) + shlibpath_overrides_runpath=yes + ;; + esac + else + shlibpath_overrides_runpath=yes + 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$major' + library_names_spec='${libname}${release}.so$versuffix ${libname}${release}.so$major $libname.so' + shlibpath_var=LD_LIBRARY_PATH + 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" + hardcode_into_libs=yes + ;; + +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 + hardcode_into_libs=yes + # ldd complains unless libraries are executable + postinstall_cmds='chmod +x $lib' + ;; + +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 + sni) + shlibpath_overrides_runpath=no + need_lib_prefix=no + export_dynamic_flag_spec='${wl}-Blargedynsym' + runpath_var=LD_RUN_PATH + ;; + siemens) + need_lib_prefix=no + ;; + motorola) + need_lib_prefix=no + need_version=no + shlibpath_overrides_runpath=no + sys_lib_search_path_spec='/lib /usr/lib /usr/ccs/lib' + ;; + 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 "$as_me:$LINENO: result: $dynamic_linker" >&5 +echo "${ECHO_T}$dynamic_linker" >&6 +test "$dynamic_linker" = no && can_build_shared=no + +# Report the final consequences. +echo "$as_me:$LINENO: checking if libtool supports shared libraries" >&5 +echo $ECHO_N "checking if libtool supports shared libraries... $ECHO_C" >&6 +echo "$as_me:$LINENO: result: $can_build_shared" >&5 +echo "${ECHO_T}$can_build_shared" >&6 + +echo "$as_me:$LINENO: checking whether to build shared libraries" >&5 +echo $ECHO_N "checking whether to build shared libraries... $ECHO_C" >&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*) + if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then + test "$enable_shared" = yes && enable_static=no + fi + ;; +esac +echo "$as_me:$LINENO: result: $enable_shared" >&5 +echo "${ECHO_T}$enable_shared" >&6 + +echo "$as_me:$LINENO: checking whether to build static libraries" >&5 +echo $ECHO_N "checking whether to build static libraries... $ECHO_C" >&6 +# Make sure either enable_shared or enable_static is yes. +test "$enable_shared" = yes || enable_static=yes +echo "$as_me:$LINENO: result: $enable_static" >&5 +echo "${ECHO_T}$enable_static" >&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 + +variables_saved_for_relink="PATH $shlibpath_var $runpath_var" +if test "$GCC" = yes; then + variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH" +fi + +if test "x$enable_dlopen" != xyes; then + enable_dlopen=unknown + enable_dlopen_self=unknown + enable_dlopen_self_static=unknown +else + lt_cv_dlopen=no + lt_cv_dlopen_libs= + + case $host_os in + beos*) + lt_cv_dlopen="load_add_on" + lt_cv_dlopen_libs= + lt_cv_dlopen_self=yes + ;; + + cygwin* | mingw* | pw32*) + lt_cv_dlopen="LoadLibrary" + lt_cv_dlopen_libs= + ;; + + *) + echo "$as_me:$LINENO: checking for shl_load" >&5 +echo $ECHO_N "checking for shl_load... $ECHO_C" >&6 +if test "${ac_cv_func_shl_load+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +#line $LINENO "configure" +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +/* System header to define __stub macros and hopefully few prototypes, + which can conflict with char shl_load (); below. + Prefer to if __STDC__ is defined, since + exists even on freestanding compilers. */ +#ifdef __STDC__ +# include +#else +# include +#endif +/* 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 shl_load (); +/* 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 +char (*f) () = shl_load; +#endif +#ifdef __cplusplus +} +#endif + +int +main () +{ +return f != shl_load; + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext 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='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_shl_load=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_cv_func_shl_load=no +fi +rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext +fi +echo "$as_me:$LINENO: result: $ac_cv_func_shl_load" >&5 +echo "${ECHO_T}$ac_cv_func_shl_load" >&6 +if test $ac_cv_func_shl_load = yes; then + lt_cv_dlopen="shl_load" +else + echo "$as_me:$LINENO: checking for shl_load in -ldld" >&5 +echo $ECHO_N "checking for shl_load in -ldld... $ECHO_C" >&6 +if test "${ac_cv_lib_dld_shl_load+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-ldld $LIBS" +cat >conftest.$ac_ext <<_ACEOF +#line $LINENO "configure" +/* 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 shl_load (); +int +main () +{ +shl_load (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext 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='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_dld_shl_load=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_cv_lib_dld_shl_load=no +fi +rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +echo "$as_me:$LINENO: result: $ac_cv_lib_dld_shl_load" >&5 +echo "${ECHO_T}$ac_cv_lib_dld_shl_load" >&6 +if test $ac_cv_lib_dld_shl_load = yes; then + lt_cv_dlopen="shl_load" lt_cv_dlopen_libs="-dld" +else + echo "$as_me:$LINENO: checking for dlopen" >&5 +echo $ECHO_N "checking for dlopen... $ECHO_C" >&6 +if test "${ac_cv_func_dlopen+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +#line $LINENO "configure" +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +/* System header to define __stub macros and hopefully few prototypes, + which can conflict with char dlopen (); below. + Prefer to if __STDC__ is defined, since + exists even on freestanding compilers. */ +#ifdef __STDC__ +# include +#else +# include +#endif +/* 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 dlopen (); +/* 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 +char (*f) () = dlopen; +#endif +#ifdef __cplusplus +} +#endif + +int +main () +{ +return f != dlopen; + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext 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='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_dlopen=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_cv_func_dlopen=no +fi +rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext +fi +echo "$as_me:$LINENO: result: $ac_cv_func_dlopen" >&5 +echo "${ECHO_T}$ac_cv_func_dlopen" >&6 +if test $ac_cv_func_dlopen = yes; then + lt_cv_dlopen="dlopen" +else + echo "$as_me:$LINENO: checking for dlopen in -ldl" >&5 +echo $ECHO_N "checking for dlopen in -ldl... $ECHO_C" >&6 +if test "${ac_cv_lib_dl_dlopen+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-ldl $LIBS" +cat >conftest.$ac_ext <<_ACEOF +#line $LINENO "configure" +/* 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 dlopen (); +int +main () +{ +dlopen (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext 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='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_dl_dlopen=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_cv_lib_dl_dlopen=no +fi +rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +echo "$as_me:$LINENO: result: $ac_cv_lib_dl_dlopen" >&5 +echo "${ECHO_T}$ac_cv_lib_dl_dlopen" >&6 +if test $ac_cv_lib_dl_dlopen = yes; then + lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl" +else + echo "$as_me:$LINENO: checking for dlopen in -lsvld" >&5 +echo $ECHO_N "checking for dlopen in -lsvld... $ECHO_C" >&6 +if test "${ac_cv_lib_svld_dlopen+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lsvld $LIBS" +cat >conftest.$ac_ext <<_ACEOF +#line $LINENO "configure" +/* 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 dlopen (); +int +main () +{ +dlopen (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext 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='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_svld_dlopen=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_cv_lib_svld_dlopen=no +fi +rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +echo "$as_me:$LINENO: result: $ac_cv_lib_svld_dlopen" >&5 +echo "${ECHO_T}$ac_cv_lib_svld_dlopen" >&6 +if test $ac_cv_lib_svld_dlopen = yes; then + lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-lsvld" +else + echo "$as_me:$LINENO: checking for dld_link in -ldld" >&5 +echo $ECHO_N "checking for dld_link in -ldld... $ECHO_C" >&6 +if test "${ac_cv_lib_dld_dld_link+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-ldld $LIBS" +cat >conftest.$ac_ext <<_ACEOF +#line $LINENO "configure" +/* 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 dld_link (); +int +main () +{ +dld_link (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext 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='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_dld_dld_link=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_cv_lib_dld_dld_link=no +fi +rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +echo "$as_me:$LINENO: result: $ac_cv_lib_dld_dld_link" >&5 +echo "${ECHO_T}$ac_cv_lib_dld_dld_link" >&6 +if test $ac_cv_lib_dld_dld_link = yes; then + lt_cv_dlopen="dld_link" lt_cv_dlopen_libs="-dld" +fi + + +fi + + +fi + + +fi + + +fi + + +fi + + ;; + esac + + if test "x$lt_cv_dlopen" != xno; then + enable_dlopen=yes + else + enable_dlopen=no + fi + + case $lt_cv_dlopen in + dlopen) + save_CPPFLAGS="$CPPFLAGS" + test "x$ac_cv_header_dlfcn_h" = xyes && CPPFLAGS="$CPPFLAGS -DHAVE_DLFCN_H" + + save_LDFLAGS="$LDFLAGS" + eval LDFLAGS=\"\$LDFLAGS $export_dynamic_flag_spec\" + + save_LIBS="$LIBS" + LIBS="$lt_cv_dlopen_libs $LIBS" + + echo "$as_me:$LINENO: checking whether a program can dlopen itself" >&5 +echo $ECHO_N "checking whether a program can dlopen itself... $ECHO_C" >&6 +if test "${lt_cv_dlopen_self+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test "$cross_compiling" = yes; then : + lt_cv_dlopen_self=cross +else + lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 + lt_status=$lt_dlunknown + cat > conftest.$ac_ext < +#endif + +#include + +#ifdef RTLD_GLOBAL +# define LT_DLGLOBAL RTLD_GLOBAL +#else +# ifdef DL_GLOBAL +# define LT_DLGLOBAL DL_GLOBAL +# else +# define LT_DLGLOBAL 0 +# endif +#endif + +/* We may have to define LT_DLLAZY_OR_NOW in the command line if we + find out it does not work in some platform. */ +#ifndef LT_DLLAZY_OR_NOW +# ifdef RTLD_LAZY +# define LT_DLLAZY_OR_NOW RTLD_LAZY +# else +# ifdef DL_LAZY +# define LT_DLLAZY_OR_NOW DL_LAZY +# else +# ifdef RTLD_NOW +# define LT_DLLAZY_OR_NOW RTLD_NOW +# else +# ifdef DL_NOW +# define LT_DLLAZY_OR_NOW DL_NOW +# else +# define LT_DLLAZY_OR_NOW 0 +# endif +# endif +# endif +# endif +#endif + +#ifdef __cplusplus +extern "C" void exit (int); +#endif + +void fnord() { int i=42;} +int main () +{ + void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW); + int status = $lt_dlunknown; + + if (self) + { + if (dlsym (self,"fnord")) status = $lt_dlno_uscore; + else if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore; + /* dlclose (self); */ + } + + exit (status); +} +EOF + 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); } && test -s conftest${ac_exeext} 2>/dev/null; then + (./conftest; exit; ) 2>/dev/null + lt_status=$? + case x$lt_status in + x$lt_dlno_uscore) lt_cv_dlopen_self=yes ;; + x$lt_dlneed_uscore) lt_cv_dlopen_self=yes ;; + x$lt_unknown|x*) lt_cv_dlopen_self=no ;; + esac + else : + # compilation failed + lt_cv_dlopen_self=no + fi +fi +rm -fr conftest* + + +fi +echo "$as_me:$LINENO: result: $lt_cv_dlopen_self" >&5 +echo "${ECHO_T}$lt_cv_dlopen_self" >&6 + + if test "x$lt_cv_dlopen_self" = xyes; then + LDFLAGS="$LDFLAGS $link_static_flag" + echo "$as_me:$LINENO: checking whether a statically linked program can dlopen itself" >&5 +echo $ECHO_N "checking whether a statically linked program can dlopen itself... $ECHO_C" >&6 +if test "${lt_cv_dlopen_self_static+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test "$cross_compiling" = yes; then : + lt_cv_dlopen_self_static=cross +else + lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 + lt_status=$lt_dlunknown + cat > conftest.$ac_ext < +#endif + +#include + +#ifdef RTLD_GLOBAL +# define LT_DLGLOBAL RTLD_GLOBAL +#else +# ifdef DL_GLOBAL +# define LT_DLGLOBAL DL_GLOBAL +# else +# define LT_DLGLOBAL 0 +# endif +#endif + +/* We may have to define LT_DLLAZY_OR_NOW in the command line if we + find out it does not work in some platform. */ +#ifndef LT_DLLAZY_OR_NOW +# ifdef RTLD_LAZY +# define LT_DLLAZY_OR_NOW RTLD_LAZY +# else +# ifdef DL_LAZY +# define LT_DLLAZY_OR_NOW DL_LAZY +# else +# ifdef RTLD_NOW +# define LT_DLLAZY_OR_NOW RTLD_NOW +# else +# ifdef DL_NOW +# define LT_DLLAZY_OR_NOW DL_NOW +# else +# define LT_DLLAZY_OR_NOW 0 +# endif +# endif +# endif +# endif +#endif + +#ifdef __cplusplus +extern "C" void exit (int); +#endif + +void fnord() { int i=42;} +int main () +{ + void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW); + int status = $lt_dlunknown; + + if (self) + { + if (dlsym (self,"fnord")) status = $lt_dlno_uscore; + else if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore; + /* dlclose (self); */ + } + + exit (status); +} +EOF + 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); } && test -s conftest${ac_exeext} 2>/dev/null; then + (./conftest; exit; ) 2>/dev/null + lt_status=$? + case x$lt_status in + x$lt_dlno_uscore) lt_cv_dlopen_self_static=yes ;; + x$lt_dlneed_uscore) lt_cv_dlopen_self_static=yes ;; + x$lt_unknown|x*) lt_cv_dlopen_self_static=no ;; + esac + else : + # compilation failed + lt_cv_dlopen_self_static=no + fi +fi +rm -fr conftest* + + +fi +echo "$as_me:$LINENO: result: $lt_cv_dlopen_self_static" >&5 +echo "${ECHO_T}$lt_cv_dlopen_self_static" >&6 + fi + + CPPFLAGS="$save_CPPFLAGS" + LDFLAGS="$save_LDFLAGS" + LIBS="$save_LIBS" + ;; + 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 + + +if test "$enable_shared" = yes && test "$GCC" = yes; then + case $archive_cmds in + *'~'*) + # FIXME: we may have to deal with multi-command sequences. + ;; + '$CC '*) + # Test whether the compiler implicitly links with -lc since on some + # systems, -lgcc has to come before -lc. If gcc already passes -lc + # to ld, don't add -lc before -lgcc. + echo "$as_me:$LINENO: checking whether -lc should be explicitly linked in" >&5 +echo $ECHO_N "checking whether -lc should be explicitly linked in... $ECHO_C" >&6 + if test "${lt_cv_archive_cmds_need_lc+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + $rm conftest* + echo 'static int dummy;' > 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 + soname=conftest + lib=conftest + libobjs=conftest.$ac_objext + deplibs= + wl=$lt_cv_prog_cc_wl + compiler_flags=-v + linker_flags=-v + verstring= + output_objdir=. + libname=conftest + save_allow_undefined_flag=$allow_undefined_flag + allow_undefined_flag= + if { (eval echo "$as_me:$LINENO: \"$archive_cmds 2\>\&1 \| grep \" -lc \" \>/dev/null 2\>\&1\"") >&5 + (eval $archive_cmds 2\>\&1 \| grep \" -lc \" \>/dev/null 2\>\&1) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } + then + lt_cv_archive_cmds_need_lc=no + else + lt_cv_archive_cmds_need_lc=yes + fi + allow_undefined_flag=$save_allow_undefined_flag + else + cat conftest.err 1>&5 + fi +fi + + echo "$as_me:$LINENO: result: $lt_cv_archive_cmds_need_lc" >&5 +echo "${ECHO_T}$lt_cv_archive_cmds_need_lc" >&6 + ;; + esac +fi +need_lc=${lt_cv_archive_cmds_need_lc-yes} + +# The second clause should only fire when bootstrapping the +# libtool distribution, otherwise you forgot to ship ltmain.sh +# with your package, and you will get complaints that there are +# no rules to generate ltmain.sh. +if test -f "$ltmain"; then + : +else + # If there is no Makefile yet, we rely on a make rule to execute + # `config.status --recheck' to rerun these tests and create the + # libtool script then. + test -f Makefile && make "$ltmain" +fi + +if test -f "$ltmain"; then + trap "$rm \"${ofile}T\"; exit 1" 1 2 15 + $rm -f "${ofile}T" + + echo creating $ofile + + # Now quote all the things that may contain metacharacters while being + # careful not to overquote the AC_SUBSTed values. We take copies of the + # variables and quote the copies for generation of the libtool script. + for var in echo old_CC old_CFLAGS SED \ + AR AR_FLAGS CC LD LN_S NM SHELL \ + 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 extract_expsyms_cmds old_archive_from_expsyms_cmds \ + old_striplib striplib 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 \ + global_symbol_to_c_name_address \ + 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 | \ + extract_expsyms_cmds | old_archive_from_expsyms_cmds | \ + postinstall_cmds | postuninstall_cmds | \ + finish_cmds | sys_lib_search_path_spec | sys_lib_dlsearch_path_spec) + # Double-quote double-evaled strings. + eval "lt_$var=\\\"\`\$echo \"X\$$var\" | \$Xsed -e \"\$double_quote_subst\" -e \"\$sed_quote_subst\" -e \"\$delay_variable_subst\"\`\\\"" + ;; + *) + eval "lt_$var=\\\"\`\$echo \"X\$$var\" | \$Xsed -e \"\$sed_quote_subst\"\`\\\"" + ;; + esac + done + + cat <<__EOF__ > "${ofile}T" +#! $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 ltmain.sh. +# +# Copyright (C) 1996-2000 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. + +# A sed that does not truncate output. +SED=$lt_SED + +# 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 + +# Libtool was configured on host `(hostname || uname -n) 2>/dev/null | sed 1q`: + +# Shell to use when invoking shell scripts. +SHELL=$lt_SHELL + +# 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 add -lc for building shared libraries. +build_libtool_need_lc=$need_lc + +# 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=$lt_echo + +# The archiver. +AR=$lt_AR +AR_FLAGS=$lt_AR_FLAGS + +# The default C compiler. +CC=$lt_CC + +# Is the compiler the GNU C compiler? +with_gcc=$GCC + +# The linker used to build libraries. +LD=$lt_LD + +# Whether we need hard or soft links. +LN_S=$lt_LN_S + +# A BSD-compatible nm program. +NM=$lt_NM + +# A symbol stripping program +STRIP=$STRIP + +# Used to examine libraries when file_magic_cmd begins "file" +MAGIC_CMD=$MAGIC_CMD + +# 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=$lt_reload_flag +reload_cmds=$lt_reload_cmds + +# How to pass a linker flag through the compiler. +wl=$lt_wl + +# Object file suffix (normally "o"). +objext="$ac_objext" + +# Old archive suffix (normally "a"). +libext="$libext" + +# Executable file suffix (normally ""). +exeext="$exeext" + +# Additional compiler flags for building library objects. +pic_flag=$lt_pic_flag +pic_mode=$pic_mode + +# Does compiler simultaneously support -c and -o options? +compiler_c_o=$lt_compiler_c_o + +# Can we write directly to a .lo ? +compiler_o_lo=$lt_compiler_o_lo + +# Must we lock files when doing compilation ? +need_locks=$lt_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_support=$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=$lt_link_static_flag + +# Compiler flag to turn off builtin functions. +no_builtin_flag=$lt_no_builtin_flag + +# Compiler flag to allow reflexive dlopens. +export_dynamic_flag_spec=$lt_export_dynamic_flag_spec + +# Compiler flag to generate shared objects directly from archives. +whole_archive_flag_spec=$lt_whole_archive_flag_spec + +# Compiler flag to generate thread-safe objects. +thread_safe_flag_spec=$lt_thread_safe_flag_spec + +# Library versioning type. +version_type=$version_type + +# Format of library name prefix. +libname_spec=$lt_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=$lt_library_names_spec + +# The coded name of the library, if different from the real name. +soname_spec=$lt_soname_spec + +# Commands used to build and install an old-style archive. +RANLIB=$lt_RANLIB +old_archive_cmds=$lt_old_archive_cmds +old_postinstall_cmds=$lt_old_postinstall_cmds +old_postuninstall_cmds=$lt_old_postuninstall_cmds + +# Create an old-style archive from a shared archive. +old_archive_from_new_cmds=$lt_old_archive_from_new_cmds + +# Create a temporary old-style archive to link instead of a shared archive. +old_archive_from_expsyms_cmds=$lt_old_archive_from_expsyms_cmds + +# Commands used to build and install a shared archive. +archive_cmds=$lt_archive_cmds +archive_expsym_cmds=$lt_archive_expsym_cmds +postinstall_cmds=$lt_postinstall_cmds +postuninstall_cmds=$lt_postuninstall_cmds + +# Commands to strip libraries. +old_striplib=$lt_old_striplib +striplib=$lt_striplib + +# Method to check whether dependent libraries are shared objects. +deplibs_check_method=$lt_deplibs_check_method + +# Command to use when deplibs_check_method == file_magic. +file_magic_cmd=$lt_file_magic_cmd + +# Flag that allows shared libraries with undefined symbols to be built. +allow_undefined_flag=$lt_allow_undefined_flag + +# Flag that forces no undefined symbols. +no_undefined_flag=$lt_no_undefined_flag + +# Commands used to finish a libtool library installation in a directory. +finish_cmds=$lt_finish_cmds + +# Same as above, but a single script fragment to be evaled but not shown. +finish_eval=$lt_finish_eval + +# Take the output of nm and produce a listing of raw symbols and C names. +global_symbol_pipe=$lt_global_symbol_pipe + +# Transform the output of nm in a proper C declaration +global_symbol_to_cdecl=$lt_global_symbol_to_cdecl + +# Transform the output of nm in a C name address pair +global_symbol_to_c_name_address=$lt_global_symbol_to_c_name_address + +# 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 + +# Whether we should hardcode library paths into libraries. +hardcode_into_libs=$hardcode_into_libs + +# Flag to hardcode \$libdir into a binary during linking. +# This must work even if \$libdir does not exist. +hardcode_libdir_flag_spec=$lt_hardcode_libdir_flag_spec + +# Whether we need a single -rpath flag with a separated argument. +hardcode_libdir_separator=$lt_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 + +# Variables whose values should be saved in libtool wrapper scripts and +# restored at relink time. +variables_saved_for_relink="$variables_saved_for_relink" + +# Whether libtool must link a program against all its dependency libraries. +link_all_deplibs=$link_all_deplibs + +# Compile-time system search path for libraries +sys_lib_search_path_spec=$lt_sys_lib_search_path_spec + +# Run-time system search path for libraries +sys_lib_dlsearch_path_spec=$lt_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=$lt_export_symbols_cmds + +# The commands to extract the exported symbol list from a shared archive. +extract_expsyms_cmds=$lt_extract_expsyms_cmds + +# Symbols that should not be listed in the preloaded symbols. +exclude_expsyms=$lt_exclude_expsyms + +# Symbols that must always be exported. +include_expsyms=$lt_include_expsyms + +# ### END LIBTOOL CONFIG + +__EOF__ + + case $host_os in + aix3*) + cat <<\EOF >> "${ofile}T" + +# 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 + + case $host_os in + cygwin* | mingw* | pw32* | os2*) + cat <<'EOF' >> "${ofile}T" + # 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-2000 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() */ +# +# /* O_BINARY isn't required (or even defined sometimes) under Unix */ +# #ifndef O_BINARY +# #define O_BINARY 0 +# #endif +# +# 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 < 1) +# 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> "${ofile}T" || (rm -f "${ofile}T"; exit 1) + + mv -f "${ofile}T" "$ofile" || \ + (rm -f "$ofile" && cp "${ofile}T" "$ofile" && rm -f "${ofile}T") + chmod +x "$ofile" +fi + + + + + +# This can be used to rebuild libtool when needed +LIBTOOL_DEPS="$ac_aux_dir/ltmain.sh" + +# Always use our own libtool. +LIBTOOL='$(SHELL) $(top_builddir)/libtool' + +# Prevent multiple expansion + + + +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 +#line $LINENO "configure" +/* 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>&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.$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 +#line $LINENO "configure" +/* 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>&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.$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 \ + ''\ + '#include ' \ + '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 +#line $LINENO "configure" +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +$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>&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.$ac_objext conftest.$ac_ext + cat >conftest.$ac_ext <<_ACEOF +#line $LINENO "configure" +/* 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>&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.$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 + +depcc="$CXX" am_compiler_list= + +echo "$as_me:$LINENO: checking dependency style of $depcc" >&5 +echo $ECHO_N "checking dependency style of $depcc... $ECHO_C" >&6 +if test "${am_cv_CXX_dependencies_compiler_type+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then + # We make a subdir and do the tests there. Otherwise we can end up + # making bogus files that we don't know about and never remove. For + # instance it was reported that on HP-UX the gcc test will end up + # making a dummy file named `D' -- because `-MD' means `put the output + # in D'. + mkdir conftest.dir + # Copy depcomp to subdir because otherwise we won't find it if we're + # using a relative directory. + cp "$am_depcomp" conftest.dir + cd conftest.dir + + am_cv_CXX_dependencies_compiler_type=none + if test "$am_compiler_list" = ""; then + am_compiler_list=`sed -n 's/^#*\([a-zA-Z0-9]*\))$/\1/p' < ./depcomp` + fi + for depmode in $am_compiler_list; do + # We need to recreate these files for each test, as the compiler may + # overwrite some of them when testing with obscure command lines. + # This happens at least with the AIX C compiler. + echo '#include "conftest.h"' > conftest.c + echo 'int i;' > conftest.h + echo "${am__include} ${am__quote}conftest.Po${am__quote}" > confmf + + case $depmode in + nosideeffect) + # after this tag, mechanisms are not by side-effect, so they'll + # only be used when explicitly requested + if test "x$enable_dependency_tracking" = xyes; then + continue + else + break + fi + ;; + none) break ;; + esac + # We check with `-c' and `-o' for the sake of the "dashmstdout" + # mode. It turns out that the SunPro C++ compiler does not properly + # handle `-M -o', and we need to detect this. + if depmode=$depmode \ + source=conftest.c object=conftest.o \ + depfile=conftest.Po tmpdepfile=conftest.TPo \ + $SHELL ./depcomp $depcc -c -o conftest.o conftest.c \ + >/dev/null 2>conftest.err && + grep conftest.h conftest.Po > /dev/null 2>&1 && + ${MAKE-make} -s -f confmf > /dev/null 2>&1; then + # icc doesn't choke on unknown options, it will just issue warnings + # (even with -Werror). So we grep stderr for any message + # that says an option was ignored. + if grep 'ignoring option' conftest.err >/dev/null 2>&1; then :; else + am_cv_CXX_dependencies_compiler_type=$depmode + break + fi + fi + done + + cd .. + rm -rf conftest.dir +else + am_cv_CXX_dependencies_compiler_type=none +fi + +fi +echo "$as_me:$LINENO: result: $am_cv_CXX_dependencies_compiler_type" >&5 +echo "${ECHO_T}$am_cv_CXX_dependencies_compiler_type" >&6 +CXXDEPMODE=depmode=$am_cv_CXX_dependencies_compiler_type + + + +if + test "x$enable_dependency_tracking" != xno \ + && test "$am_cv_CXX_dependencies_compiler_type" = gcc3; then + am__fastdepCXX_TRUE= + am__fastdepCXX_FALSE='#' +else + am__fastdepCXX_TRUE='#' + am__fastdepCXX_FALSE= +fi + + + +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 + + +echo "$as_me:$LINENO: checking whether $CXX works" >&5 +echo $ECHO_N "checking whether $CXX works... $ECHO_C" >&6 + +cat >conftest.$ac_ext <<_ACEOF +#line $LINENO "configure" +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +int +main () +{ +std::cout << "ok"; + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +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); } && + { 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 + echo "$as_me:$LINENO: result: yes" >&5 +echo "${ECHO_T}yes" >&6 + LIBFCGIXX=libfcgi++.la + ECHO_CPP=echo-cpp${EXEEXT} + echo "$as_me:$LINENO: checking whether cin has a streambuf assignment operator" >&5 +echo $ECHO_N "checking whether cin has a streambuf assignment operator... $ECHO_C" >&6 + cat >conftest.$ac_ext <<_ACEOF +#line $LINENO "configure" +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +int +main () +{ +cin = static_cast(0); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +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); } && + { 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 + echo "$as_me:$LINENO: result: yes" >&5 +echo "${ECHO_T}yes" >&6 + +cat >>confdefs.h <<\_ACEOF +#define HAVE_IOSTREAM_WITHASSIGN_STREAMBUF 1 +_ACEOF + +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi +rm -f conftest.$ac_objext conftest.$ac_ext + echo "$as_me:$LINENO: checking whether char_type is defined in the context of streambuf" >&5 +echo $ECHO_N "checking whether char_type is defined in the context of streambuf... $ECHO_C" >&6 + cat >conftest.$ac_ext <<_ACEOF +#line $LINENO "configure" +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +int +main () +{ +class fcgi_streambuf : public std::streambuf { char_type ct; } + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +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); } && + { 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 + echo "$as_me:$LINENO: result: yes" >&5 +echo "${ECHO_T}yes" >&6 + +cat >>confdefs.h <<\_ACEOF +#define HAVE_STREAMBUF_CHAR_TYPE 1 +_ACEOF + +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi +rm -f conftest.$ac_objext conftest.$ac_ext +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi +rm -f 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 + + + +echo "$as_me:$LINENO: checking for gethostbyname in -lnsl" >&5 +echo $ECHO_N "checking for gethostbyname in -lnsl... $ECHO_C" >&6 +if test "${ac_cv_lib_nsl_gethostbyname+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lnsl $LIBS" +cat >conftest.$ac_ext <<_ACEOF +#line $LINENO "configure" +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +/* Override any gcc2 internal prototype to avoid an error. */ +#ifdef __cplusplus +extern "C" +#endif +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char gethostbyname (); +int +main () +{ +gethostbyname (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_lib_nsl_gethostbyname=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_cv_lib_nsl_gethostbyname=no +fi +rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +echo "$as_me:$LINENO: result: $ac_cv_lib_nsl_gethostbyname" >&5 +echo "${ECHO_T}$ac_cv_lib_nsl_gethostbyname" >&6 +if test $ac_cv_lib_nsl_gethostbyname = yes; then + cat >>confdefs.h <<_ACEOF +#define HAVE_LIBNSL 1 +_ACEOF + + LIBS="-lnsl $LIBS" + +fi + + +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 +#line $LINENO "configure" +/* 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>&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.$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 + + + + +acx_pthread_ok=no + +# First, check if the POSIX threads header, pthread.h, is available. +# If it isn't, don't bother looking for the threads libraries. +if test "${ac_cv_header_pthread_h+set}" = set; then + echo "$as_me:$LINENO: checking for pthread.h" >&5 +echo $ECHO_N "checking for pthread.h... $ECHO_C" >&6 +if test "${ac_cv_header_pthread_h+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +fi +echo "$as_me:$LINENO: result: $ac_cv_header_pthread_h" >&5 +echo "${ECHO_T}$ac_cv_header_pthread_h" >&6 +else + # Is the header compilable? +echo "$as_me:$LINENO: checking pthread.h usability" >&5 +echo $ECHO_N "checking pthread.h usability... $ECHO_C" >&6 +cat >conftest.$ac_ext <<_ACEOF +#line $LINENO "configure" +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +#include +_ACEOF +rm -f conftest.$ac_objext +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); } && + { 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.$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 pthread.h presence" >&5 +echo $ECHO_N "checking pthread.h presence... $ECHO_C" >&6 +cat >conftest.$ac_ext <<_ACEOF +#line $LINENO "configure" +/* 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 + 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 in + yes:no ) + { echo "$as_me:$LINENO: WARNING: pthread.h: accepted by the compiler, rejected by the preprocessor!" >&5 +echo "$as_me: WARNING: pthread.h: accepted by the compiler, rejected by the preprocessor!" >&2;} + { echo "$as_me:$LINENO: WARNING: pthread.h: proceeding with the preprocessor's result" >&5 +echo "$as_me: WARNING: pthread.h: proceeding with the preprocessor's result" >&2;} + ( + cat <<\_ASBOX +## ------------------------------------ ## +## Report this to bug-autoconf@gnu.org. ## +## ------------------------------------ ## +_ASBOX + ) | + sed "s/^/$as_me: WARNING: /" >&2 + ;; + no:yes ) + { echo "$as_me:$LINENO: WARNING: pthread.h: present but cannot be compiled" >&5 +echo "$as_me: WARNING: pthread.h: present but cannot be compiled" >&2;} + { echo "$as_me:$LINENO: WARNING: pthread.h: check for missing prerequisite headers?" >&5 +echo "$as_me: WARNING: pthread.h: check for missing prerequisite headers?" >&2;} + { echo "$as_me:$LINENO: WARNING: pthread.h: proceeding with the preprocessor's result" >&5 +echo "$as_me: WARNING: pthread.h: proceeding with the preprocessor's result" >&2;} + ( + cat <<\_ASBOX +## ------------------------------------ ## +## Report this to bug-autoconf@gnu.org. ## +## ------------------------------------ ## +_ASBOX + ) | + sed "s/^/$as_me: WARNING: /" >&2 + ;; +esac +echo "$as_me:$LINENO: checking for pthread.h" >&5 +echo $ECHO_N "checking for pthread.h... $ECHO_C" >&6 +if test "${ac_cv_header_pthread_h+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_cv_header_pthread_h=$ac_header_preproc +fi +echo "$as_me:$LINENO: result: $ac_cv_header_pthread_h" >&5 +echo "${ECHO_T}$ac_cv_header_pthread_h" >&6 + +fi +if test $ac_cv_header_pthread_h = yes; then + : +else + acx_pthread_ok=noheader +fi + + + +# We must check for the threads library under a number of different +# names; the ordering is very important because some systems +# (e.g. DEC) have both -lpthread and -lpthreads, where one of the +# libraries is broken (non-POSIX). + +# First of all, check if the user has set any of the PTHREAD_LIBS, +# etcetera environment variables, and if threads linking works using +# them: +if test x"$PTHREAD_LIBS$PTHREAD_CFLAGS" != x; then + save_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS $PTHREAD_CFLAGS" + save_LIBS="$LIBS" + LIBS="$PTHREAD_LIBS $LIBS" + echo "$as_me:$LINENO: checking for pthread_join in LIBS=$PTHREAD_LIBS with CFLAGS=$PTHREAD_CFLAGS" >&5 +echo $ECHO_N "checking for pthread_join in LIBS=$PTHREAD_LIBS with CFLAGS=$PTHREAD_CFLAGS... $ECHO_C" >&6 + cat >conftest.$ac_ext <<_ACEOF +#line $LINENO "configure" +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +/* Override any gcc2 internal prototype to avoid an error. */ +#ifdef __cplusplus +extern "C" +#endif +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char pthread_join (); +int +main () +{ +pthread_join (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext 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='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 + acx_pthread_ok=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +fi +rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext + echo "$as_me:$LINENO: result: $acx_pthread_ok" >&5 +echo "${ECHO_T}$acx_pthread_ok" >&6 + if test x"$acx_pthread_ok" = xno; then + PTHREAD_LIBS="" + PTHREAD_CFLAGS="" + fi + LIBS="$save_LIBS" + CFLAGS="$save_CFLAGS" +fi + +# Create a list of thread flags to try. Items starting with a "-" are +# C compiler flags, and other items are library names, except for "none" +# which indicates that we try without any flags at all. + +acx_pthread_flags="pthreads none -Kthread -kthread lthread -pthread -pthreads -mthreads pthread --thread-safe -mt" + +# The ordering *is* (sometimes) important. Some notes on the +# individual items follow: + +# pthreads: AIX (must check this before -lpthread) +# none: in case threads are in libc; should be tried before -Kthread and +# other compiler flags to prevent continual compiler warnings +# -Kthread: Sequent (threads in libc, but -Kthread needed for pthread.h) +# -kthread: FreeBSD kernel threads (preferred to -pthread since SMP-able) +# lthread: LinuxThreads port on FreeBSD (also preferred to -pthread) +# -pthread: Linux/gcc (kernel threads), BSD/gcc (userland threads) +# -pthreads: Solaris/gcc +# -mthreads: Mingw32/gcc, Lynx/gcc +# -mt: Sun Workshop C (may only link SunOS threads [-lthread], but it +# doesn't hurt to check since this sometimes defines pthreads too; +# also defines -D_REENTRANT) +# pthread: Linux, etcetera +# --thread-safe: KAI C++ + +case "${host_cpu}-${host_os}" in + *solaris*) + + # On Solaris (at least, for some versions), libc contains stubbed + # (non-functional) versions of the pthreads routines, so link-based + # tests will erroneously succeed. (We need to link with -pthread or + # -lpthread.) (The stubs are missing pthread_cleanup_push, or rather + # a function called by this macro, so we could check for that, but + # who knows whether they'll stub that too in a future libc.) So, + # we'll just look for -pthreads and -lpthread first: + + acx_pthread_flags="-pthread -pthreads pthread -mt $acx_pthread_flags" + ;; +esac + +if test x"$acx_pthread_ok" = xno; then +for flag in $acx_pthread_flags; do + + case $flag in + none) + echo "$as_me:$LINENO: checking whether pthreads work without any flags" >&5 +echo $ECHO_N "checking whether pthreads work without any flags... $ECHO_C" >&6 + ;; + + -*) + echo "$as_me:$LINENO: checking whether pthreads work with $flag" >&5 +echo $ECHO_N "checking whether pthreads work with $flag... $ECHO_C" >&6 + PTHREAD_CFLAGS="$flag" + ;; + + *) + echo "$as_me:$LINENO: checking for the pthreads library -l$flag" >&5 +echo $ECHO_N "checking for the pthreads library -l$flag... $ECHO_C" >&6 + PTHREAD_LIBS="-l$flag" + ;; + esac + + save_LIBS="$LIBS" + save_CFLAGS="$CFLAGS" + LIBS="$PTHREAD_LIBS $LIBS" + CFLAGS="$CFLAGS $PTHREAD_CFLAGS" + + # Check for various functions. We must include pthread.h, + # since some functions may be macros. (On the Sequent, we + # need a special flag -Kthread to make this header compile.) + # We check for pthread_join because it is in -lpthread on IRIX + # while pthread_create is in libc. We check for pthread_attr_init + # due to DEC craziness with -lpthreads. We check for + # pthread_cleanup_push because it is one of the few pthread + # functions on Solaris that doesn't have a non-functional libc stub. + # We try pthread_create on general principles. + cat >conftest.$ac_ext <<_ACEOF +#line $LINENO "configure" +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +int +main () +{ +pthread_t th; pthread_join(th, 0); + pthread_attr_init(0); pthread_cleanup_push(0, 0); + pthread_create(0,0,0,0); pthread_cleanup_pop(0); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>&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 + acx_pthread_ok=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +fi +rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext + + LIBS="$save_LIBS" + CFLAGS="$save_CFLAGS" + + echo "$as_me:$LINENO: result: $acx_pthread_ok" >&5 +echo "${ECHO_T}$acx_pthread_ok" >&6 + if test "x$acx_pthread_ok" = xyes; then + break; + fi + + PTHREAD_LIBS="" + PTHREAD_CFLAGS="" +done +fi + +# Various other checks: +if test "x$acx_pthread_ok" = xyes; then + save_LIBS="$LIBS" + LIBS="$PTHREAD_LIBS $LIBS" + save_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS $PTHREAD_CFLAGS" + + # Detect AIX lossage: threads are created detached by default + # and the JOINABLE attribute has a nonstandard name (UNDETACHED). + echo "$as_me:$LINENO: checking for joinable pthread attribute" >&5 +echo $ECHO_N "checking for joinable pthread attribute... $ECHO_C" >&6 + cat >conftest.$ac_ext <<_ACEOF +#line $LINENO "configure" +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +int +main () +{ +int attr=PTHREAD_CREATE_JOINABLE; + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext 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='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 + ok=PTHREAD_CREATE_JOINABLE +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ok=unknown +fi +rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext + if test x"$ok" = xunknown; then + cat >conftest.$ac_ext <<_ACEOF +#line $LINENO "configure" +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +int +main () +{ +int attr=PTHREAD_CREATE_UNDETACHED; + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext 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='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 + ok=PTHREAD_CREATE_UNDETACHED +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ok=unknown +fi +rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext + fi + if test x"$ok" != xPTHREAD_CREATE_JOINABLE; then + +cat >>confdefs.h <<\_ACEOF +#define PTHREAD_CREATE_JOINABLE $ok +_ACEOF + + fi + echo "$as_me:$LINENO: result: ${ok}" >&5 +echo "${ECHO_T}${ok}" >&6 + if test x"$ok" = xunknown; then + { echo "$as_me:$LINENO: WARNING: we do not know how to create joinable pthreads" >&5 +echo "$as_me: WARNING: we do not know how to create joinable pthreads" >&2;} + fi + + echo "$as_me:$LINENO: checking if more special flags are required for pthreads" >&5 +echo $ECHO_N "checking if more special flags are required for pthreads... $ECHO_C" >&6 + flag=no + case "${host_cpu}-${host_os}" in + *-aix* | *-freebsd*) flag="-D_THREAD_SAFE";; + *solaris* | alpha*-osf*) flag="-D_REENTRANT";; + esac + echo "$as_me:$LINENO: result: ${flag}" >&5 +echo "${ECHO_T}${flag}" >&6 + if test "x$flag" != xno; then + PTHREAD_CFLAGS="$flag $PTHREAD_CFLAGS" + fi + + LIBS="$save_LIBS" + CFLAGS="$save_CFLAGS" + + # More AIX lossage: must compile with cc_r + # Extract the first word of "cc_r", so it can be a program name with args. +set dummy cc_r; 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_PTHREAD_CC+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$PTHREAD_CC"; then + ac_cv_prog_PTHREAD_CC="$PTHREAD_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_PTHREAD_CC="cc_r" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + + test -z "$ac_cv_prog_PTHREAD_CC" && ac_cv_prog_PTHREAD_CC="${CC}" +fi +fi +PTHREAD_CC=$ac_cv_prog_PTHREAD_CC +if test -n "$PTHREAD_CC"; then + echo "$as_me:$LINENO: result: $PTHREAD_CC" >&5 +echo "${ECHO_T}$PTHREAD_CC" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + +else + PTHREAD_CC="$CC" +fi + + + + + +# Finally, execute ACTION-IF-FOUND/ACTION-IF-NOT-FOUND: +if test x"$acx_pthread_ok" = xyes; then + THREADED=threaded${EXEEXT} + : +else + acx_pthread_ok=no + +fi + + + + + + echo "$as_me:$LINENO: checking for ssize_t" >&5 +echo $ECHO_N "checking for ssize_t... $ECHO_C" >&6 +if test "${ac_cv_type_ssize_t+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +#line $LINENO "configure" +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +int +main () +{ +if ((ssize_t *) 0) + return 0; +if (sizeof (ssize_t)) + return 0; + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +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); } && + { 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_ssize_t=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_cv_type_ssize_t=no +fi +rm -f conftest.$ac_objext conftest.$ac_ext +fi +echo "$as_me:$LINENO: result: $ac_cv_type_ssize_t" >&5 +echo "${ECHO_T}$ac_cv_type_ssize_t" >&6 +if test $ac_cv_type_ssize_t = yes; then + : +else + +cat >>confdefs.h <<_ACEOF +#define ssize_t int +_ACEOF + +fi + + + echo "$as_me:$LINENO: checking for sun_len in sys/un.h" >&5 +echo $ECHO_N "checking for sun_len in sys/un.h... $ECHO_C" >&6 + cat >conftest.$ac_ext <<_ACEOF +#line $LINENO "configure" +/* 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 "sun_len" >/dev/null 2>&1; then + echo "$as_me:$LINENO: result: yes" >&5 +echo "${ECHO_T}yes" >&6 + +cat >>confdefs.h <<\_ACEOF +#define HAVE_SOCKADDR_UN_SUN_LEN 1 +_ACEOF + +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi +rm -f conftest* + + + echo "$as_me:$LINENO: checking for fpos_t in stdio.h" >&5 +echo $ECHO_N "checking for fpos_t in stdio.h... $ECHO_C" >&6 + cat >conftest.$ac_ext <<_ACEOF +#line $LINENO "configure" +/* 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 "fpos_t" >/dev/null 2>&1; then + echo "$as_me:$LINENO: result: yes" >&5 +echo "${ECHO_T}yes" >&6 + +cat >>confdefs.h <<\_ACEOF +#define HAVE_FPOS 1 +_ACEOF + +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi +rm -f conftest* + + + + + + +for ac_header in sys/socket.h netdb.h netinet/in.h arpa/inet.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 +#line $LINENO "configure" +/* 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>&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.$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 +#line $LINENO "configure" +/* 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 + 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 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 preprocessor's result" >&5 +echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;} + ( + cat <<\_ASBOX +## ------------------------------------ ## +## Report this to bug-autoconf@gnu.org. ## +## ------------------------------------ ## +_ASBOX + ) | + sed "s/^/$as_me: WARNING: /" >&2 + ;; + 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: proceeding with the preprocessor's result" >&5 +echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;} + ( + cat <<\_ASBOX +## ------------------------------------ ## +## Report this to bug-autoconf@gnu.org. ## +## ------------------------------------ ## +_ASBOX + ) | + sed "s/^/$as_me: WARNING: /" >&2 + ;; +esac +echo "$as_me:$LINENO: checking for $ac_header" >&5 +echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6 +if eval "test \"\${$as_ac_Header+set}\" = set"; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + eval "$as_ac_Header=$ac_header_preproc" +fi +echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5 +echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6 + +fi +if test `eval echo '${'$as_ac_Header'}'` = yes; then + cat >>confdefs.h <<_ACEOF +#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1 +_ACEOF + +fi + +done + + + + + +for ac_header in sys/time.h limits.h sys/param.h unistd.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 +#line $LINENO "configure" +/* 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>&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.$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 +#line $LINENO "configure" +/* 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 + 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 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 preprocessor's result" >&5 +echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;} + ( + cat <<\_ASBOX +## ------------------------------------ ## +## Report this to bug-autoconf@gnu.org. ## +## ------------------------------------ ## +_ASBOX + ) | + sed "s/^/$as_me: WARNING: /" >&2 + ;; + 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: proceeding with the preprocessor's result" >&5 +echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;} + ( + cat <<\_ASBOX +## ------------------------------------ ## +## Report this to bug-autoconf@gnu.org. ## +## ------------------------------------ ## +_ASBOX + ) | + sed "s/^/$as_me: WARNING: /" >&2 + ;; +esac +echo "$as_me:$LINENO: checking for $ac_header" >&5 +echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6 +if eval "test \"\${$as_ac_Header+set}\" = set"; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + eval "$as_ac_Header=$ac_header_preproc" +fi +echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5 +echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6 + +fi +if test `eval echo '${'$as_ac_Header'}'` = yes; then + cat >>confdefs.h <<_ACEOF +#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1 +_ACEOF + +fi + +done + + + echo "$as_me:$LINENO: checking for a fileno() prototype in stdio.h" >&5 +echo $ECHO_N "checking for a fileno() prototype in stdio.h... $ECHO_C" >&6 + cat >conftest.$ac_ext <<_ACEOF +#line $LINENO "configure" +/* 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 "fileno" >/dev/null 2>&1; then + echo "$as_me:$LINENO: result: yes" >&5 +echo "${ECHO_T}yes" >&6 + +cat >>confdefs.h <<\_ACEOF +#define HAVE_FILENO_PROTO 1 +_ACEOF + +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi +rm -f conftest* + + + if test "$HAVE_SYS_SOCKET_H"; then + echo "$as_me:$LINENO: checking for socklen_t in sys/socket.h" >&5 +echo $ECHO_N "checking for socklen_t in sys/socket.h... $ECHO_C" >&6 + cat >conftest.$ac_ext <<_ACEOF +#line $LINENO "configure" +/* 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 "socklen_t" >/dev/null 2>&1; then + echo "$as_me:$LINENO: result: yes" >&5 +echo "${ECHO_T}yes" >&6 + +cat >>confdefs.h <<\_ACEOF +#define HAVE_SOCKLEN 1 +_ACEOF + +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi +rm -f conftest* + + fi + + #-------------------------------------------------------------------- + # Do we need cross-process locking on this platform? + #-------------------------------------------------------------------- + echo "$as_me:$LINENO: checking whether cross-process locking is required by accept()" >&5 +echo $ECHO_N "checking whether cross-process locking is required by accept()... $ECHO_C" >&6 + case "`uname -sr`" in + IRIX\ 5.* | SunOS\ 5.* | UNIX_System_V\ 4.0) + echo "$as_me:$LINENO: result: yes" >&5 +echo "${ECHO_T}yes" >&6 + +cat >>confdefs.h <<\_ACEOF +#define USE_LOCKING 1 +_ACEOF + + ;; + *) + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 + ;; + esac + + #-------------------------------------------------------------------- + # Does va_arg(arg, long double) crash the compiler? + # hpux 9.04 compiler does and so does Stratus FTX (uses HP's compiler) + #-------------------------------------------------------------------- + echo "$as_me:$LINENO: checking whether va_arg(arg, long double) crashes the compiler" >&5 +echo $ECHO_N "checking whether va_arg(arg, long double) crashes the compiler... $ECHO_C" >&6 + cat >conftest.$ac_ext <<_ACEOF +#line $LINENO "configure" +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +int +main () +{ +long double lDblArg; va_list arg; lDblArg = va_arg(arg, long double); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +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); } && + { 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 + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +echo "$as_me:$LINENO: result: yes" >&5 +echo "${ECHO_T}yes" >&6 + +cat >>confdefs.h <<\_ACEOF +#define HAVE_VA_ARG_LONG_DOUBLE_BUG 1 +_ACEOF + +fi +rm -f conftest.$ac_objext conftest.$ac_ext + + echo "$as_me:$LINENO: checking for an ANSI C-conforming const" >&5 +echo $ECHO_N "checking for an ANSI C-conforming const... $ECHO_C" >&6 +if test "${ac_cv_c_const+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +#line $LINENO "configure" +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ +/* FIXME: Include the comments suggested by Paul. */ +#ifndef __cplusplus + /* Ultrix mips cc rejects this. */ + typedef int charset[2]; + const charset x; + /* SunOS 4.1.1 cc rejects this. */ + char const *const *ccp; + char **p; + /* NEC SVR4.0.2 mips cc rejects this. */ + struct point {int x, y;}; + static struct point const zero = {0,0}; + /* AIX XL C 1.02.0.0 rejects this. + It does not let you subtract one const X* pointer from another in + an arm of an if-expression whose if-part is not a constant + expression */ + const char *g = "string"; + ccp = &g + (g ? g-g : 0); + /* HPUX 7.0 cc rejects these. */ + ++ccp; + p = (char**) ccp; + ccp = (char const *const *) p; + { /* SCO 3.2v4 cc rejects this. */ + char *t; + char const *s = 0 ? (char *) 0 : (char const *) 0; + + *t++ = 0; + } + { /* Someone thinks the Sun supposedly-ANSI compiler will reject this. */ + int x[] = {25, 17}; + const int *foo = &x[0]; + ++foo; + } + { /* Sun SC1.0 ANSI compiler rejects this -- but not the above. */ + typedef const int *iptr; + iptr p = 0; + ++p; + } + { /* AIX XL C 1.02.0.0 rejects this saying + "k.c", line 2.27: 1506-025 (S) Operand must be a modifiable lvalue. */ + struct s { int j; const int *ap[3]; }; + struct s *b; b->j = 5; + } + { /* ULTRIX-32 V3.1 (Rev 9) vcc rejects this */ + const int foo = 10; + } +#endif + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_c_const=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_cv_c_const=no +fi +rm -f conftest.$ac_objext conftest.$ac_ext +fi +echo "$as_me:$LINENO: result: $ac_cv_c_const" >&5 +echo "${ECHO_T}$ac_cv_c_const" >&6 +if test $ac_cv_c_const = no; then + +cat >>confdefs.h <<\_ACEOF +#define const +_ACEOF + +fi + + + + +for ac_func in strerror +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 +#line $LINENO "configure" +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +/* 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 +/* 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>&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.$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 + +else + LIBOBJS="$LIBOBJS $ac_func.$ac_objext" +fi +done + + + +echo "$as_me:$LINENO: checking for inline" >&5 +echo $ECHO_N "checking for inline... $ECHO_C" >&6 +if test "${ac_cv_c_inline+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_cv_c_inline=no +for ac_kw in inline __inline__ __inline; do + cat >conftest.$ac_ext <<_ACEOF +#line $LINENO "configure" +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#ifndef __cplusplus +typedef int foo_t; +static $ac_kw foo_t static_foo () {return 0; } +$ac_kw foo_t foo () {return 0; } +#endif + +_ACEOF +rm -f conftest.$ac_objext +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); } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_c_inline=$ac_kw; break +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +fi +rm -f conftest.$ac_objext conftest.$ac_ext +done + +fi +echo "$as_me:$LINENO: result: $ac_cv_c_inline" >&5 +echo "${ECHO_T}$ac_cv_c_inline" >&6 +case $ac_cv_c_inline in + inline | yes) ;; + no) +cat >>confdefs.h <<\_ACEOF +#define inline +_ACEOF + ;; + *) cat >>confdefs.h <<_ACEOF +#define inline $ac_cv_c_inline +_ACEOF + ;; +esac + + +#-------------------------------------------------------------------- +# This is a little hokie in that it avoids including config.guess +# and config.sub in the distribution, but its been working so far. +# Windows builds don't run configure so we should be safe fixing +# this to 'unix' (at least for now). +#-------------------------------------------------------------------- +SYSTEM=unix + + + + ansi= + if test -z "$ansi"; then + msg="for C compiler warning flags" + else + msg="for C compiler warning and ANSI conformance flags" + fi + echo "$as_me:$LINENO: checking $msg" >&5 +echo $ECHO_N "checking $msg... $ECHO_C" >&6 +if test "${ac_cv_prog_cc_warnings+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + + if test -n "$CC"; then + cat > conftest.c <&1 | grep "Xc.*strict ANSI C" > /dev/null 2>&1 && + $CC -c -v -Xc conftest.c > /dev/null 2>&1 && + test -f conftest.o; then + if test -z "$ansi"; then + ac_cv_prog_cc_warnings="-v" + else + ac_cv_prog_cc_warnings="-v -Xc" + fi + + elif $CC > /dev/null 2>&1 && + $CC -c -Aa +w1 conftest.c > /dev/null 2>&1 && + test -f conftest.o; then + if test -z "$ansi"; then + ac_cv_prog_cc_warnings="+w1" + else + ac_cv_prog_cc_warnings="+w1 -Aa" + fi + + elif ! $CC > /dev/null 2>&1 && + $CC -c -verbose -w0 -warnprotos -std1 conftest.c > /dev/null 2>&1 && + test -f conftest.o; then + if test -z "$ansi"; then + ac_cv_prog_cc_warnings="-verbose -w0 -warnprotos" + else + ac_cv_prog_cc_warnings="-verbose -w0 -warnprotos -std1" + fi + + elif $CC > /dev/null 2>&1 | grep AIX > /dev/null 2>&1 && + $CC -c -qlanglvl=ansi -qinfo=all conftest.c > /dev/null 2>&1 && + test -f conftest.o; then + if test -z "$ansi"; then + ac_cv_prog_cc_warnings="-qsrcmsg -qinfo=all:noppt:noppc:noobs:nocnd" + else + ac_cv_prog_cc_warnings="-qsrcmsg -qinfo=all:noppt:noppc:noobs:nocnd -qlanglvl=ansi" + fi + + elif $CC -fullwarn -ansi -ansiE > /dev/null 2>&1 && + test -f conftest.o; then + if test -z "$ansi"; then + ac_cv_prog_cc_warnings="-fullwarn" + else + ac_cv_prog_cc_warnings="-fullwarn -ansi -ansiE" + fi + + fi + rm -f conftest.* + fi + if test -n "$ac_cv_prog_cc_warnings"; then + CFLAGS="$CFLAGS $ac_cv_prog_cc_warnings" + else + ac_cv_prog_cc_warnings="unknown" + fi + +fi +echo "$as_me:$LINENO: result: $ac_cv_prog_cc_warnings" >&5 +echo "${ECHO_T}$ac_cv_prog_cc_warnings" >&6 + + + ac_config_files="$ac_config_files Makefile cgi-fcgi/Makefile include/Makefile libfcgi/Makefile examples/Makefile" + + +cat >confcache <<\_ACEOF +# This file is a shell script that caches the results of configure +# tests run on this system so they can be shared between configure +# scripts and configure runs, see configure's option --config-cache. +# It is not useful on other systems. If it contains results you don't +# want to keep, you may remove or edit it. +# +# config.status only pays attention to the cache file if you give it +# the --recheck option to rerun configure. +# +# `ac_cv_env_foo' variables (set or unset) will be overridden when +# loading this file, other *unset* `ac_cv_foo' will be assigned the +# following values. + +_ACEOF + +# The following way of writing the cache mishandles newlines in values, +# but we know of no workaround that is simple, portable, and efficient. +# So, 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 + + +if test -z "${AMDEP_TRUE}" && test -z "${AMDEP_FALSE}"; then + { { echo "$as_me:$LINENO: error: conditional \"AMDEP\" was never defined. +Usually this means the macro was only invoked conditionally." >&5 +echo "$as_me: error: conditional \"AMDEP\" was never defined. +Usually this means the macro was only invoked conditionally." >&2;} + { (exit 1); exit 1; }; } +fi +if test -z "${am__fastdepCC_TRUE}" && test -z "${am__fastdepCC_FALSE}"; then + { { echo "$as_me:$LINENO: error: conditional \"am__fastdepCC\" was never defined. +Usually this means the macro was only invoked conditionally." >&5 +echo "$as_me: error: conditional \"am__fastdepCC\" was never defined. +Usually this means the macro was only invoked conditionally." >&2;} + { (exit 1); exit 1; }; } +fi +if test -z "${am__fastdepCXX_TRUE}" && test -z "${am__fastdepCXX_FALSE}"; then + { { echo "$as_me:$LINENO: error: conditional \"am__fastdepCXX\" was never defined. +Usually this means the macro was only invoked conditionally." >&5 +echo "$as_me: error: conditional \"am__fastdepCXX\" was never defined. +Usually this means the macro was only invoked conditionally." >&2;} + { (exit 1); exit 1; }; } +fi + +: ${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 + +# Support unset when possible. +if (FOO=FOO; unset FOO) >/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 -n "`(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 + as_mkdir_p=false +fi + +as_executable_p="test -f" + +# Sed expression to map a string onto a valid CPP name. +as_tr_cpp="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="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.57. 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.57, + with options \\"`echo "$ac_configure_args" | sed 's/[\\""\`\$]/\\\\&/g'`\\" + +Copyright 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001 +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. +# + +AMDEP_TRUE="$AMDEP_TRUE" ac_aux_dir="$ac_aux_dir" + +_ACEOF + + + +cat >>$CONFIG_STATUS <<\_ACEOF +for ac_config_target in $ac_config_targets +do + case "$ac_config_target" in + # Handling of arguments. + "Makefile" ) CONFIG_FILES="$CONFIG_FILES Makefile" ;; + "cgi-fcgi/Makefile" ) CONFIG_FILES="$CONFIG_FILES cgi-fcgi/Makefile" ;; + "include/Makefile" ) CONFIG_FILES="$CONFIG_FILES include/Makefile" ;; + "libfcgi/Makefile" ) CONFIG_FILES="$CONFIG_FILES libfcgi/Makefile" ;; + "examples/Makefile" ) CONFIG_FILES="$CONFIG_FILES examples/Makefile" ;; + "depfiles" ) CONFIG_COMMANDS="$CONFIG_COMMANDS depfiles" ;; + "fcgi_config.h" ) CONFIG_HEADERS="$CONFIG_HEADERS fcgi_config.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,@CYGPATH_W@,$CYGPATH_W,;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,@AMTAR@,$AMTAR,;t t +s,@install_sh@,$install_sh,;t t +s,@STRIP@,$STRIP,;t t +s,@ac_ct_STRIP@,$ac_ct_STRIP,;t t +s,@INSTALL_STRIP_PROGRAM@,$INSTALL_STRIP_PROGRAM,;t t +s,@AWK@,$AWK,;t t +s,@SET_MAKE@,$SET_MAKE,;t t +s,@am__leading_dot@,$am__leading_dot,;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,@DEPDIR@,$DEPDIR,;t t +s,@am__include@,$am__include,;t t +s,@am__quote@,$am__quote,;t t +s,@AMDEP_TRUE@,$AMDEP_TRUE,;t t +s,@AMDEP_FALSE@,$AMDEP_FALSE,;t t +s,@AMDEPBACKSLASH@,$AMDEPBACKSLASH,;t t +s,@CCDEPMODE@,$CCDEPMODE,;t t +s,@am__fastdepCC_TRUE@,$am__fastdepCC_TRUE,;t t +s,@am__fastdepCC_FALSE@,$am__fastdepCC_FALSE,;t t +s,@CPP@,$CPP,;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,@LN_S@,$LN_S,;t t +s,@ECHO@,$ECHO,;t t +s,@RANLIB@,$RANLIB,;t t +s,@ac_ct_RANLIB@,$ac_ct_RANLIB,;t t +s,@EGREP@,$EGREP,;t t +s,@LIBTOOL@,$LIBTOOL,;t t +s,@CXX@,$CXX,;t t +s,@CXXFLAGS@,$CXXFLAGS,;t t +s,@ac_ct_CXX@,$ac_ct_CXX,;t t +s,@CXXDEPMODE@,$CXXDEPMODE,;t t +s,@am__fastdepCXX_TRUE@,$am__fastdepCXX_TRUE,;t t +s,@am__fastdepCXX_FALSE@,$am__fastdepCXX_FALSE,;t t +s,@LIBFCGIXX@,$LIBFCGIXX,;t t +s,@ECHO_CPP@,$ECHO_CPP,;t t +s,@PTHREAD_CC@,$PTHREAD_CC,;t t +s,@PTHREAD_LIBS@,$PTHREAD_LIBS,;t t +s,@PTHREAD_CFLAGS@,$PTHREAD_CFLAGS,;t t +s,@THREADED@,$THREADED,;t t +s,@LIBOBJS@,$LIBOBJS,;t t +s,@SYSTEM@,$SYSTEM,;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 +# Don't blindly perform a `cd "$ac_dir"/$ac_foo && pwd` since $ac_foo can be +# absolute. +ac_abs_builddir=`cd "$ac_dir" && cd $ac_builddir && pwd` +ac_abs_top_builddir=`cd "$ac_dir" && cd ${ac_top_builddir}. && pwd` +ac_abs_srcdir=`cd "$ac_dir" && cd $ac_srcdir && pwd` +ac_abs_top_srcdir=`cd "$ac_dir" && cd $ac_top_srcdir && pwd` + + + 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; }; } + 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 +# Compute $ac_file's index in $config_headers. +_am_stamp_count=1 +for _am_header in $config_headers :; do + case $_am_header in + $ac_file | $ac_file:* ) + break ;; + * ) + _am_stamp_count=`expr $_am_stamp_count + 1` ;; + esac +done +echo "timestamp for $ac_file" >`(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'`/stamp-h$_am_stamp_count +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'` + 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 +# Don't blindly perform a `cd "$ac_dir"/$ac_foo && pwd` since $ac_foo can be +# absolute. +ac_abs_builddir=`cd "$ac_dir" && cd $ac_builddir && pwd` +ac_abs_top_builddir=`cd "$ac_dir" && cd ${ac_top_builddir}. && pwd` +ac_abs_srcdir=`cd "$ac_dir" && cd $ac_srcdir && pwd` +ac_abs_top_srcdir=`cd "$ac_dir" && cd $ac_top_srcdir && pwd` + + + { echo "$as_me:$LINENO: executing $ac_dest commands" >&5 +echo "$as_me: executing $ac_dest commands" >&6;} + case $ac_dest in + depfiles ) test x"$AMDEP_TRUE" != x"" || for mf in $CONFIG_FILES; do + # Strip MF so we end up with the name of the file. + mf=`echo "$mf" | sed -e 's/:.*$//'` + # Check whether this is an Automake generated Makefile or not. + # We used to match only the files named `Makefile.in', but + # some people rename them; so instead we look at the file content. + # Grep'ing the first line is not enough: some people post-process + # each Makefile.in and add a new line on top of each file to say so. + # So let's grep whole file. + if grep '^#.*generated by automake' $mf > /dev/null 2>&1; then + dirpart=`(dirname "$mf") 2>/dev/null || +$as_expr X"$mf" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$mf" : 'X\(//\)[^/]' \| \ + X"$mf" : 'X\(//\)$' \| \ + X"$mf" : 'X\(/\)' \| \ + . : '\(.\)' 2>/dev/null || +echo X"$mf" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; } + /^X\(\/\/\)[^/].*/{ s//\1/; q; } + /^X\(\/\/\)$/{ s//\1/; q; } + /^X\(\/\).*/{ s//\1/; q; } + s/.*/./; q'` + else + continue + fi + grep '^DEP_FILES *= *[^ #]' < "$mf" > /dev/null || continue + # Extract the definition of DEP_FILES from the Makefile without + # running `make'. + DEPDIR=`sed -n -e '/^DEPDIR = / s///p' < "$mf"` + test -z "$DEPDIR" && continue + # When using ansi2knr, U may be empty or an underscore; expand it + U=`sed -n -e '/^U = / s///p' < "$mf"` + test -d "$dirpart/$DEPDIR" || mkdir "$dirpart/$DEPDIR" + # We invoke sed twice because it is the simplest approach to + # changing $(DEPDIR) to its actual value in the expansion. + for file in `sed -n -e ' + /^DEP_FILES = .*\\\\$/ { + s/^DEP_FILES = // + :loop + s/\\\\$// + p + n + /\\\\$/ b loop + p + } + /^DEP_FILES = / s/^DEP_FILES = //p' < "$mf" | \ + sed -e 's/\$(DEPDIR)/'"$DEPDIR"'/g' -e 's/\$U/'"$U"'/g'`; do + # Make sure the directory exists. + test -f "$dirpart/$file" && continue + fdir=`(dirname "$file") 2>/dev/null || +$as_expr X"$file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$file" : 'X\(//\)[^/]' \| \ + X"$file" : 'X\(//\)$' \| \ + X"$file" : 'X\(/\)' \| \ + . : '\(.\)' 2>/dev/null || +echo X"$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 $dirpart/$fdir + else + as_dir=$dirpart/$fdir + 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 $dirpart/$fdir" >&5 +echo "$as_me: error: cannot create directory $dirpart/$fdir" >&2;} + { (exit 1); exit 1; }; }; } + + # echo "creating $dirpart/$file" + echo '# dummy' > "$dirpart/$file" + done +done + ;; + 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 + diff --git a/iipsrv/fcgi/doc/FCGI_Accept.3 b/iipsrv/fcgi/doc/FCGI_Accept.3 new file mode 100644 index 0000000..65ff08a --- /dev/null +++ b/iipsrv/fcgi/doc/FCGI_Accept.3 @@ -0,0 +1,128 @@ +NAME + FCGI_Accept, FCGI_ToFILE, FCGI_ToFcgiStream + - fcgi_stdio compatibility library + +SYNOPSIS + #include "fcgi_stdio.h" + + int + FCGI_Accept(void); + + FILE * + FCGI_ToFILE(FCGI_FILE *); + + FCGI_Stream * + FCGI_ToFcgiStream(FCGI_FILE *); + + +DESCRIPTION + The FCGI_Accept function accepts a new request from the HTTP server + and creates a CGI-compatible execution environment for the request. + + If the application was invoked as a CGI program, the first + call to FCGI_Accept is essentially a no-op and the second + call returns -1. This causes a correctly coded FastCGI Responder + application to run a single request and exit, giving CGI + behavior. + + If the application was invoked as a FastCGI server, the first + call to FCGI_Accept indicates that the application has completed + its initialization and is ready to accept its first request. + Subsequent calls to FCGI_Accept indicate that the application has + completed processing its current request and is ready to accept a + new request. An application can complete the current request + without accepting a new one by calling FCGI_Finish(3); later, when + ready to accept a new request, the application calls FCGI_Accept. + + In completing the current request, FCGI_Accept may detect + errors, e.g. a broken pipe to a client who has disconnected + early. FCGI_Accept ignores such errors. An application + that wishes to handle such errors should explicitly call + fclose(stderr), then fclose(stdout); an EOF return from + either one indicates an error. + + If the environment variable FCGI_WEB_SERVER_ADDRS is set when + FCGI_Accept is called, it should contain a comma-separated list + of IP addresses. Each IP address is written as four decimal + numbers in the range [0..255] separated by decimal points. + (nslookup(8) translates the more familiar symbolic IP hostname + into this form.) So one legal binding for this variable is + + FCGI_WEB_SERVER_ADDRS=199.170.183.28,199.170.183.71 + + FCGI_Accept checks the peer IP address of each new connection for + membership in the list. If the check fails (including the + possibility that the connection didn't use TCP/IP transport), + FCGI_Accept closes the connection and accepts another one + (without returning in between). + + After accepting a new request, FCGI_Accept assigns new values + to the global variables stdin, stdout, stderr, and environ. + After FCGI_Accept returns, these variables have the same + interpretation as on entry to a CGI program. + + FCGI_Accept frees any storage allocated by the previous call + to FCGI_Accept. This has important consequences: + + DO NOT retain pointers to the environ array or any strings + contained in it (e.g. to the result of calling getenv(3)), + since these will be freed by the next call to FCGI_Finish or + FCGI_Accept. + + DO NOT use setenv(3) or putenv(3) to modify the environ array + created by FCGI_Accept, since this will either leak storage + or cause the next call to FCGI_Finish or FCGI_Accept to free + storage that should not be freed. + + If your application needs to use setenv or putenv to modify + the environ array, it should follow this coding pattern: + + char **savedEnviron, **requestEnviron; + int acceptStatus; + + savedEnviron = environ; + acceptStatus = FCGI_Accept(); + requestEnviron = environ; + environ = savedEnviron; + if(acceptStatus >= 0 && !FCGX_IsCGI()) { + /* + * requestEnviron points to name-value pairs in + * storage allocated by FCGI_Accept. OK to read, + * not OK to retain pointers -- make copies instead. + */ + } + /* + * OK to do setenv or putenv, but beware of storage leaks! + */ + + In addition to the standard CGI environment variables, the + environment variable FCGI_ROLE is always set to the role + of the current request. The roles currently defined are + RESPONDER, AUTHORIZER, and FILTER. + + In the FILTER role, the additional variables FCGI_DATA_LENGTH + and FCGI_DATA_LAST_MOD are also defined. See the manpage + FCGI_StartFilterData(3) for complete information. + + The macros FCGI_ToFILE and FCGI_ToFcgiStream are provided + to allow escape to native functions that use the types FILE or + FCGI_Stream. In the case of FILE, functions would have to + be separately compiled, since fcgi_stdio.h replaces the standard + FILE with FCGI_FILE. + + +RETURN VALUES + 0 for successful call, -1 for error (application should exit). + +SEE ALSO + FCGI_Finish(3) + FCGI_StartFilterData(3) + FCGI_SetExitStatus(3) + cgi-fcgi(1) + nslookup(8) + +HISTORY + Copyright (c) 1996 Open Market, Inc. + See the file "LICENSE.TERMS" for information on usage and redistribution + of this file, and for a DISCLAIMER OF ALL WARRANTIES. + $Id: FCGI_Accept.3,v 1.1.1.1 1997/09/16 15:36:25 stanleyg Exp $ diff --git a/iipsrv/fcgi/doc/FCGI_Finish.3 b/iipsrv/fcgi/doc/FCGI_Finish.3 new file mode 100644 index 0000000..9332253 --- /dev/null +++ b/iipsrv/fcgi/doc/FCGI_Finish.3 @@ -0,0 +1,41 @@ +NAME + FCGI_Finish + - fcgi_stdio compatibility library + +SYNOPSIS + #include "fcgi_stdio.h" + + void + FCGI_Finish(void); + + +DESCRIPTION + The FCGI_Finish function finishes the current request from the + HTTP server. The current request was started by the most recent + call to FCGI_Accept(3). + + FCGI_Finish allows an application to interleave other activities + with the processing of requests. In an extreme case, an + application would call FCGI_Finish to complete the current + request before exiting, e.g. to reclaim leaked storage. + + In completing the current request, FCGI_Finish may detect + errors, e.g. a broken pipe to a client who has disconnected + early. FCGI_Finish ignores such errors. An application + that wishes to handle such errors should explicitly call + fclose(stderr), then fclose(stdout); an EOF return from + either one indicates an error. + + FCGI_Finish frees any storage allocated by the most recent call + to FCGI_Accept. See FCGI_Accept(3) for warnings against retaining + pointers to this storage. + + +SEE ALSO + FCGI_Accept(3) + +HISTORY + Copyright (c) 1996 Open Market, Inc. + See the file "LICENSE.TERMS" for information on usage and redistribution + of this file, and for a DISCLAIMER OF ALL WARRANTIES. + $Id: FCGI_Finish.3,v 1.1.1.1 1997/09/16 15:36:25 stanleyg Exp $ diff --git a/iipsrv/fcgi/doc/FCGI_SetExitStatus.3 b/iipsrv/fcgi/doc/FCGI_SetExitStatus.3 new file mode 100644 index 0000000..d0538ff --- /dev/null +++ b/iipsrv/fcgi/doc/FCGI_SetExitStatus.3 @@ -0,0 +1,28 @@ +NAME + FCGI_SetExitStatus - fcgi_stdio compatibility library + +SYNOPSIS + #include "fcgi_stdio.h" + + void + FCGI_SetExitStatus(int status); + + +DESCRIPTION + Sets the exit status for the current FastCGI request. + The exit status is the status code the request would have + exited with, had the request been run as a CGI program. + + You can call FCGI_SetExitStatus several times during a request; + the last call before the request ends determines the value. + +SEE ALSO + FCGI_Accept(3) + FCGI_StartFilterData(3) + cgi-fcgi(1) + +HISTORY + Copyright (c) 1996 Open Market, Inc. + See the file "LICENSE.TERMS" for information on usage and redistribution + of this file, and for a DISCLAIMER OF ALL WARRANTIES. + $Id: FCGI_SetExitStatus.3,v 1.1.1.1 1997/09/16 15:36:25 stanleyg Exp $ diff --git a/iipsrv/fcgi/doc/FCGI_StartFilterData.3 b/iipsrv/fcgi/doc/FCGI_StartFilterData.3 new file mode 100644 index 0000000..12ff2da --- /dev/null +++ b/iipsrv/fcgi/doc/FCGI_StartFilterData.3 @@ -0,0 +1,52 @@ +NAME + FCGI_StartFilterData - fcgi_stdio compatibility library + +SYNOPSIS + #include "fcgi_stdio.h" + + int + FCGI_StartFilterData(void); + + +DESCRIPTION + Enables a FastCGI Filter application to begin reading its filter + input data from stdin. + + In order to call FCGI_StartFilterData, the FastCGI + application should have been invoked in the Filter role + (getenv("FCGI_ROLE") == "FILTER"), and should have read + stdin to EOF, consuming the entire FCGI_STDIN data stream. + The call to FCGI_StartFilterData positions stdin at the + start of FCGI_DATA. + + If the preconditions are not met (e.g. the application has + not read stdin to EOF), FCGI_StartFilterData returns + a negative result, and the application will get EOF on attempts + to read from stdin. + + The application can determine the number of bytes available + on FCGI_DATA by performing atoi(getenv("FCGI_DATA_LENGTH")). + If fewer than this many bytes are delievered on stdin after + calling FCGI_StartFilterData, the application should perform + an application-specific error response. If the application + normally makes an update, most likely it should abort the update. + + The application can determine last modification time of the + filter input data by performing getenv("FCGI_DATA_LAST_MOD"). + This allows applications to perform caching based on last + modification time. + + +RETURN VALUES + 0 for successful call, < 0 for error. + +SEE ALSO + FCGI_Accept(3) + FCGI_SetExitStatus(3) + cgi-fcgi(1) + +HISTORY + Copyright (c) 1996 Open Market, Inc. + See the file "LICENSE.TERMS" for information on usage and redistribution + of this file, and for a DISCLAIMER OF ALL WARRANTIES. + $Id: FCGI_StartFilterData.3,v 1.1.1.1 1997/09/16 15:36:26 stanleyg Exp $ diff --git a/iipsrv/fcgi/doc/cgi-fcgi.1 b/iipsrv/fcgi/doc/cgi-fcgi.1 new file mode 100644 index 0000000..1af4d0a --- /dev/null +++ b/iipsrv/fcgi/doc/cgi-fcgi.1 @@ -0,0 +1,113 @@ +NAME + cgi-fcgi - bridge from CGI to FastCGI + +SYNOPSIS + cgi-fcgi -f cmdPath + cgi-fcgi -bind -connect connName + cgi-fcgi -start -connect connName appPath [nServers] + cgi-fcgi -connect connName appPath [nServers] + +DESCRIPTION + cgi-fcgi is a CGI/1.1 program that communicates with an + already-running FastCGI application in order to respond to an + HTTP request. cgi-fcgi is also capable of starting a FastCGI + application. + + When you invoke cgi-fcgi as + + cgi-fcgi -f cmdPath + + then cgi-fcgi opens the file at cmdPath and reads its + arguments from that file. cgi-fcgi will skip lines + that begin with the comment character #. The first + non-comment line should contain valid arguments in + one of the other three forms. + + The -f form of cgi-fcgi is designed for Unix systems + whose exec(2) family of system calls supports the execution of + command interpreter files. For instance, if a file with + execute permission contains the text + + #! /bin/cgi-fcgi -f + -connect /httpd/root/sock/app /httpd/root/bin/app + + the effect is the same as executing + + /bin/cgi-fcgi -connect /httpd/root/sock/app /httpd/root/bin/app + + When you invoke cgi-fcgi as + + cgi-fcgi -bind -connect connName + + the connName argument is either the path name of a Unix domain + listening socket or a host:port pair. If connName contains + a colon, it is assumed to be host:port. cgi-fcgi performs + a connect(2) using connName. If the connect succeeds, cgi-fcgi + forwards the CGI environment variables and stdin data to the + FastCGI application, and forwards the stdout and stderr data from + the application to cgi-fcgi's stdout (most likely connected to + a Web server). When the FastCGI application signals the end of + its response, cgi-fcgi flushes its buffers and + exits, and the Web server completes the http response. + + When you invoke cgi-fcgi as + + cgi-fcgi -start -connect connName appPath [nServers] + + then cgi-fcgi performs the function of starting one or more + FastCGI application processes. The connName argument specifies + either the path name of the Unix domain listening socket that + cgi-fcgi will create, or is "localhost:NNN" where NNN is the port + number of the TCP/IP listening socket that cgi-fcgi will create + on the local machine. (cgi-fcgi will not create processes + on remote machines.) After cgi-fcgi creates the listening socket, + it forks nServers copies of a process running the executable file + appPath. If nServers is omitted, the effect is as if the value "1" + had been specified. The processes share the single listening socket. + + When you invoke cgi-fcgi as + + cgi-fcgi -connect connName appPath [nServers] + + cgi-fcgi performs -bind and then, if necssary, performs -start + and repeats the -bind. That is, cgi-fcgi first operates as if + the command had been + + cgi-fcgi -bind -connect connName + + If the connect fails, cgi-fcgi tries + + cgi-fcgi -start -connect connName appPath [nServers] + + and finally retries + + cgi-fcgi -bind -connect connName + + In this form, cgi-fcgi does not support TCP/IP connections. + +ENVIRONMENT VARIABLES + The usual CGI ones, but they are not interpreted by cgi-fcgi. + +SEE ALSO + FGCI_accept(3) + +BUGS + cgi-fcgi doesn't generate useful HTTP responses in case of error, + and it generates no response at all when run as start-fcgi. + + On Digital UNIX 3.0 systems the implementation of Unix Domain + sockets does not work when such sockets are stored on NFS file + systems. Symptom: cgi-fcgi may core dump or may exit with + status 38. Work-around: store sockets in local file systems + (/tmp often works) or use TCP/IP. + + On AIX systems the implementation of listening sockets + does not support socket sharing, and the standard FastCGI + application libraries can't synchronize access to AIX listening + sockets. Work-around: Don't use the nServers argument on AIX. + +HISTORY + Copyright (c) 1996 Open Market, Inc. + See the file "LICENSE.TERMS" for information on usage and redistribution + of this file, and for a DISCLAIMER OF ALL WARRANTIES. + $Id: cgi-fcgi.1,v 1.1.1.1 1997/09/16 15:36:26 stanleyg Exp $ diff --git a/iipsrv/fcgi/doc/fastcgi-prog-guide/ap_guida.htm b/iipsrv/fcgi/doc/fastcgi-prog-guide/ap_guida.htm new file mode 100644 index 0000000..77d8c17 --- /dev/null +++ b/iipsrv/fcgi/doc/fastcgi-prog-guide/ap_guida.htm @@ -0,0 +1,322 @@ + + + + + FastCGI Application Programmer's Guide - Index + + + + + [Top] [Prev] +

+ [Next] [Bottom] +

+
+
+ +
+

+ Index
+

+
+ +
+

+ A +

+
+
+
+ +
+
+ applications in Tcl 19 +
+
+ Authorizer applications 4 +
+
+ +
+
+ environment variables 6 +
+
+ stdin and stderr 4 +
+
+
+
+ +
+

+ C +

+
+
+
+ +
+
+ C language, writing FastCGI applications in 11 +
+
+ +
+

+ E +

+
+
+
+ +
+
+ environment variables +
+
+ +
+
+ differences from CGI 6 +
+
+ returned from Authorizer applications 4 +
+
+ +
+
+ examples +
+
+ +
+
+ responder application in C 13 +
+
+ responder application in perl 18 +
+
+ responder application in Tcl 20 +
+
+ +
+
+ exit status, of FastCGI application 24 +
+
+ +
+

+ F +

+
+
+
+ +
+
+ FastCGI +
+
+ +
+
+ 19 +
+
+ applications in C 11 +
+
+ applications in Perl 17 +
+
+ differences from CGI 1 +
+
+ +
+
+ FCGI_DATA_LAST_MOD 23 +
+
+ FCGI_DATA_LENGTH 23 +
+
+ FCGI_DATA_LENGTH (in Filter applications) 6 +
+
+ FCGI_ROLE 6, 22 +
+
+ FCGI_SetExitStatus 24 +
+
+ FCGI_StartFilterData 22 +
+
+ fcgi_stdio library 11 +
+
+ +
+
+ location of 15 +
+
+ manpages for 21 +
+
+ +
+
+ FCGI_ToFcgiStream 22 +
+
+ FCGI_ToFILE 22 +
+
+ fcgiapp library 11 +
+
+ FILE_LAST_MOD (in Filter applications) 6 +
+
+ Filter applications +
+
+ +
+
+ last modification time 23 +
+
+ reading from stdin 23 +
+
+
+
+ +
+

+ G +

+
+
+
+ +
+
+ Great Circle (C garbage collector) 16 +
+
+ +
+

+ I +

+
+
+
+ +
+
+ Initial Environment Variables 5 +
+
+ +
+

+ M +

+
+
+
+ +
+
+ manpages 21 +
+
+ memory leaks 16 +
+
+ +
+

+ P +

+
+
+
+ +
+
+ Perl +
+
+ +
+
+ writing FastCGI applications in 17 +
+
+ +
+
+ Purify (for checking storage leaks) 16 +
+
+ +
+

+ R +

+
+
+
+ +
+
+ response loop 5 +
+
+ +
+
+ in C 12 +
+
+ in Perl 17 +
+
+ in TCL 19 +
+
+
+
+
+
+ [Top] [Prev] +

+ [Next] [Bottom] +

+
+
+ + + + + + + + + diff --git a/iipsrv/fcgi/doc/fastcgi-prog-guide/ap_guide.htm b/iipsrv/fcgi/doc/fastcgi-prog-guide/ap_guide.htm new file mode 100644 index 0000000..f049120 --- /dev/null +++ b/iipsrv/fcgi/doc/fastcgi-prog-guide/ap_guide.htm @@ -0,0 +1,226 @@ + + + + + FastCGI Programmer's Guide - Table of Contents + + + + + [Top] [Prev] [Next] [Bottom] +
+
+ +

+ 1. The Fast Common Gateway Interface 1 +

+
+
+ +
+
+ Advantages of FastCGI 1 +
+
+ +
+
+ Long-lived Applications 1 +
+
+ Separating Application and Server 2 +
+
+ FastCGI "Roles" 2 +
+
+ +
+
+ Writing FastCGI Applications 4 +
+
+ +
+
+ Code Structure 5 +
+
+ Initial Environment Variables 5 +
+
+ Per-Request Environment Variables 6 +
+
+ Building FastCGI Applications in C 6 +
+
+ Building FastCGI Applications in Perl 7 +
+
+ Building FastCGI Applications in Tcl 7 +
+
+ +
+
+ Implementation Details 7 +
+
+ +
+
+ The fcgi_stdio Library: I/O Compatibility 9 +
+
+ The fcgi_stdio Library: Binary compatibility 10 +
+
+
+
+

+ 2. Developing FastCGI Applications in C 11 +

+
+
+ +
+
+ The I/O Libraries 11 +
+
+ Code Structure 12 +
+
+ Example 1: TinyFastCGI 12 +
+
+
+
+ Example 2: Prime Number Generator 13 +
+
+ Building 15 +
+
+ Memory Leaks 16 +
+
+

+ 3. Developing FastCGI Applications in Perl 17 +

+
+
+ +
+
+ Getting Started 17 +
+
+ Example: TinyFastCGI 18 +
+
+

+ 4. Developing FastCGI Applications in Tcl 19 +

+
+
+ +
+
+ Getting Started 19 +
+
+ Example: TinyFastCGI 20 +
+
+

+ A. FastCGI Reference Pages 21 +

+
+
+ +
+
+ FCGI_Accept (3) 21 +
+
+ +
+
+ Name 21 +
+
+ Synopsis 21 +
+
+ Description 21 +
+
+ Return Values 22 +
+
+ +
+
+ FCGI_StartFilterData (3) 22 +
+
+ +
+
+ Name 22 +
+
+ Synopsis 22 +
+
+ Description 23 +
+
+ Return Values 23 +
+
+ Example 23 +
+
+ +
+
+ FCGI_SetExitStatus(3) 24 +
+
+ +
+
+ Name 24 +
+
+ Synopsis 24 +
+
+ Description 24 +
+
+
+
+
+
+ [Top] [Prev] [Next] [Bottom] +
+
+ + + + + + + + + diff --git a/iipsrv/fcgi/doc/fastcgi-prog-guide/apaman.htm b/iipsrv/fcgi/doc/fastcgi-prog-guide/apaman.htm new file mode 100644 index 0000000..8ff40cd --- /dev/null +++ b/iipsrv/fcgi/doc/fastcgi-prog-guide/apaman.htm @@ -0,0 +1,290 @@ + + + + + FCGI_Accept(2) Man Page + + + + + [Top] [Prev] [Next] [Bottom] +
+
+ +
+

+ A FastCGI
+ Reference Pages +

+
+ +

+ This appendix contains reference pages for the following FastCGI routines from the fcgi_stdio + library: +

+
+
+
    +
  • + +
  • +
  • + FCGI_Accept +
  • +
  • + FCGI_Start_Filter_Data +
  • +
  • + FCGI_SetExitStatus +
  • +
+

+ FCGI_Accept (3) +

+

+ Name +

+ FCGI_Accept, FCGI_ToFILE, FCGI_ToFcgiStream +

+ - fcgi_stdio compatibility library +

+
+
+

+ Synopsis +

+
+#include <fcgi_stdio.h>
+
+int
+ FCGI_Accept(void); +
+FILE *
+ FCGI_ToFILE(FCGI_FILE *); +
+FCGI_Stream *
+ FCGI_ToFcgiStream(FCGI_FILE *); +
+
+

+ Description +

+ +

+ The FCGI_Accept function accepts a new request from the HTTP server and creates a CGI-compatible execution + environment for the request. +

+

+ If the application was invoked as a CGI program, the first call to FCGI_Accept is + essentially a no-op and the second call returns -1. This causes a correctly coded FastCGI application to run a + single request and exit, giving CGI behavior. +

+

+ If the application was invoked as a FastCGI server, the first call to FCGI_Accept + indicates that the application has completed its initialization and is ready to accept its first request. + Subsequent calls to FCGI_Accept indicate that the application has completed processing its current request and + is ready to accept a new request. +

+

+ In completing the current request, FCGI_Accept may detect errors, such as a broken pipe + to a client who has disconnected early. FCGI_Accept ignores such errors. An application that wishes to handle + such errors should explicitly call fclose(stderr), then fclose(stdout); an EOF return from either one + indicates an error. +

+

+ After accepting a new request, FCGI_Accept assigns new values to the global variables + stdin, stdout, stderr, and environ. After FCGI_Accept returns, these variables have the same interpretation as + on entry to a CGI program. +

+

+ In addition to the standard CGI environment variables, the environment variable + FCGI_ROLE is always set to the role of the current request. The roles currently defined are + RESPONDER, AUTHORIZER, and FILTER. +

+

+ In the FILTER role, the additional variables FCGI_DATA_LENGTH + and FCGI_DATA_LAST_MOD are also defined. See FCGI_StartFilterData(3) + for complete information. +

+

+ The macros FCGI_ToFILE and FCGI_ToFcgiStream are provided to + allow escape to native functions that use the types FILE or FCGI_Stream. In the case + of FILE, functions would have to be separately compiled, since fcgi_stdio.h replaces + the standard FILE with FCGI_FILE. +

+
+
+

+ Return Values +

+ +

+ 0 for successful call, -1 for error (application should exit). +

+
+
+

+ FCGI_StartFilterData (3) +

+

+ Name +

+ FCGI_StartFilterData +

+ -fcgi_stdio compatibility library +

+
+
+

+ Synopsis +

+
+#include <fcgi_stdio.h>
+
+int FCGI_StartFilterData(void)
+
+
+

+ Description +

+ +

+ Enables a FastCGI Filter application to begin reading its filter input data from stdin. +

+

+ In order to call FCGI_StartFilterData, the FastCGI application should have + been invoked in the filter role (getenv("FCGI_ROLE") == "FILTER"), and should + have read stdin to EOF, consuming the entire FCGI_STDIN data stream. The call to + FCGI_StartFilterData positions stdin at the start of FCGI_DATA. +

+

+ If the preconditions are not met (e.g., the application has not read stdin + to EOF), FCGI_StartFilterData returns a negative result, and the application will get EOF on + attempts to read from stdin. +

+

+ The application can determine the number of bytes available on FCGI_DATA by + performing atoi(getenv("FCGI_DATA_LENGTH"). If fewer than this many bytes are delivered + on stdin after calling FCGI_StartFilterData, the application should perform an + application-specific error response. If the application normally makes an update, most likely it should abort + the update. +

+

+ The application can determine last modification time of the filter input data by + performing getenv("FCGI_DATA_LAST_MOD"). This allows applications to perform caching + based on last modification time. +

+
+
+

+ Return Values +

+ +

+ Returns 0 on success and a negative integer on failure. +

+
+
+

+ Example +

+ +

+ The following example reads in all the client data, but ignores it. Then, the code calls + FCGI_StartFilterData. Finally, the code reads in the file to be filtered and simply echos it back + to the client. +

+
+
+
+while (FCGI_Accept() >= 0) {
+
+...
+
+ /* Read data passed by client. */
+
+  while (getchar () != OF) 
+
+{
+
+}
+
+
+
+ /* Adjust standard input stream. */
+
+  status = FCGI_StartFilterData();
+
+
+
+ /* Read in filter data and echo it back to client. */
+
+  while ((len = fread(tempBuffer, 1, 1024, stdin)) > 0) 
+
+    fwrite(tempBuffer, 1, len, stdout);
+
+
+
+} /* End FCGI_Accept loop */
+
+
+

+ FCGI_SetExitStatus(3) +

+

+ Name +

+ FCGI_SetExitStatus +

+ - fcgi_stdio compatibility library +

+
+
+

+ Synopsis +

+
+#include <fcgi_stdio.h>
+
+void FCGI_SetExitStatus(int status);
+
+
+

+ Description +

+ +

+ Sets the exit status for the current FastCGI request. The exit status is the status code the request would + have exited with, had the request been run as a CGI program. +

+

+ You can call FCGI_SetExitStatus several times during a request; the last + call before the request ends determines the value. +

+

+ +

+

+

+
+
+ [Top] [Prev] [Next] [Bottom] +
+
+ + + + + + + + + diff --git a/iipsrv/fcgi/doc/fastcgi-prog-guide/ch1inta1.gif b/iipsrv/fcgi/doc/fastcgi-prog-guide/ch1inta1.gif new file mode 100644 index 0000000000000000000000000000000000000000..4111cc627aab6e9470dd7674f8c0ae64a5ea9601 GIT binary patch literal 7194 zcmV+#9OdIjNk%w1VZ8y=0OtSz0001h|A4;$0IjX9eEWQ(yQ8bCtDm2ro12@DkB|Au z$%~7NeVu(k|3HU_hd%v2V8390e}Cz@xqW?od3kv-0047yb7f^^U0q#UTU%FGSG$Xg zO-)Vy{{H;@{QCO(_V)HeLqk75Kkn}C?Ck70IXUR)=;r3;Gcz+UFE1@EE#BVVA3q-} zD=XaG+}POIA0Hnb9UaQb$`=D;vbwsuxVX3l1qJ!J zxu&M3q@<*vprAki0RI30oSdARnwpH9jF6C!hK7cMf`Wj6fPQ{{e0+R#baZfVaBgmH zY;0^`U|?QeURqjOSXfwAR#s9{Qbt}z|Ns9?Oica#{rmg-NJvQe`T6(v_e4ZQKtMn~ zK0fd7@BKbLIyyQuG&C?UFfJ}G-{0RXEG*sK-6|?7+1c49CMLZ5ybwSTA|fIfFc=^p zAkWXw&CSir%gY!T7|F@W!^6X#{hkmI5DpFwzrVi<3JSZsyScf!v$M0j9K^nlfbY*- zzD{N-oG+4(#J)TPG}8=_9|ODql{}9irb!IGhd?O=JdlqxT%P;_K+FIE1-<|d000aD zzyJUlc+3VMzyJVHPyoyT0KfzQ^gsYm2zbC`0Q3N0c8|~aNe=*rP<8+=_>Ug|o=f~d z0IUH50Gk3pm_7giG4M~e0NrhN_-wq!007itc8~D9&-8dew6th!0AvPuS8TM{Yybf7 zMA&kym;eII)|&%tAS6`ST(BsIY%J8|G;F4ui)^LF2AlY>001naNC2nC1^~=#HlTZ( zyZ{3{0GpTqq(cAG70C*$d01Si+4gm)5 z0{{-R10w(ek^un@5cD*I5Ree+3)hNU)&6g9sBUT*$DY!-o(fN^}SS zfD%3cCTiTsv7^V26ESM6sN^9=0DP2y0m-tZ%a<@?N(7JqjYyd|bLx~C#7xGAPJ#&J zW2U4-jC{nX+{v`5)2AQ-M6rRUWDq4-vudTPH7gn$UZIK|3sDJ4G+3%;6^fNB7BFD2 zzKv^D>({Utm3(EZ70cDFYP;UWik7V5!-x&Sy~yXS9Jm0?$k78=&qV-W^gITGvM1&_ zi9?f}qmpyuIh-Z0j2uKHn9YuTI)=>0GZ@gQ!5rWNIx-m9P9|5roOyF+pSMLTU*6Pg z#<&7eE`58Mdi2IOnQPAp9Sh2V(pUate{PhzYop(@59BN!%gyO=&tG@{bG!Zf9Mh90 z2)}&yf$HHWU`O43cimF@Stn3@`w^7gd+qVJl7bWtRo{RZW@ylH&&lD$T#pGv+J}yP zc$;S$rU+4H=$R1&YSK~0nrj}uWf?}rnK%cE7Ge?HYA&MYV~ALcxL}PZ%BJFy1L_4< zU3@7alt4C2c@=2N5S&iRwdI|7 z=BekNeD>+*pMVA`=%9oaYUrVeCaUP7j5g}%qmV`_DH@>h!AD_|4myXWmWq+-r=lTf z5vYQ4R*`|ErW%u}r?%?qtNyUII-#nfu^Q{GxRysNtxmw@>#us?DlD#Hbg^qwzb0GR zu*|wT!4}76y2Sxn$zK#L_K?4tX;YAn&I!L2YH z48Q^y=<#*YS>Hjn{?li_3_#HU?EL~0gcol3;U#0h1Oj{S-E-d!okTLzJMVz_<%GXY z_zsOXtuo|>0+0d%DtB(W7fjS__32GN4!S}Zg>gsftT!G8;I-@g`RjwOUV83L)4n?J z8=K8LLm#6~Iq?(YPWIRh{J*uc9UeL=}nPc!ki{|-F#+xIzrMPh%g{`!pD zd_D8pmv3RxXJqa5`uOW@bNGQj|Frygvf2(bXSiYAj&Orh9rkh;Klyb}TZMa@uoPD~ zZHX^;LNLJqd=4=<=4AlHaQ6VmUJm}H$H{YMr>dZ|6UlLNS&aB;?L$=qjY$5{P6W z3XW0 zFI@g96IQ0AL1D6PaD*dg$)3o%C`M12xdW)Y-gZbjrgK34w4N~wicA0^6nt`I9U>o^ zp@`;gld$CIMS=IsIdW7>9(AP?M<~)0?vSJzJ>5o6Dxj3I4y4CyY0_SryOL_up)}o& zO;3kYit2QoRBWC%WeU`wGH0l!E9&VCdc2YLG^VDTsZ)j8O?m!tqEoG?16`U_rFzw* zTkU99W5v^Dg4J|X<=re}Rm;x#l&RWLmR|R&R}w*PbrKMO05;IJapDgO#awA1kIIA! z2;h>b!(Y4FXV!*lCo0Aq>F>O#>+A3MbHWhV-G`6aK;w z$Y#0KRxk_zFF-B8xX)46ac(Ce65@m zBWPF|n}abB4*_3;=fNzioRa{+0w+kXdev)zaOuUlB&$eSr3zQE=8&vOy=zvR>XefV zpuOTkZ+gklD*GO*B3M<=TEGmP%CLqvJOSXIfWQ?=igN)F z&-uQ!b8&s$#~xf({dSJRP{D`=?qGpgJ;Vl40KkV&HCn~xmWuR6v4Ia7IPgOFbS|DS zf184l6Zk;`HZ}!)>>Yn*VV*R$qNuPY*Kml3;h#wMGu`)1YJC0WeP zmI)XvFn|zGWZdZ`3Gc4Gw`{jA+K}sZgm10nT9F$io|4G8{QzP;Lyg@tjP=f}yX~{d z8_CO-7y=F!8YRf#-d&2wxXZ2X*8x0u0#`T_BnWSA*LsQH)>%OQD-xQDXy6FJoxp}U zg{gu}{8auPwxz$S<-M8UYG)`gvOP_2o86qxi8&Ri(+gl&#r)+JclB9`XKbULs^bR# zIP*fzGN2;{Rsvoxdt=3DibFkB7k6vTgBPo>`|RLg?s*T>oEV}2V9^zcfpCTE2N^{A z?stE|5z=7pb=i!YX{n4sW}RB4FdfI*d&$<&#B6+5u6>v8&QRhBC;33^jQB-J8Jof`h&D60JEJ znI(FLk$!I_b=%-?br|Phi_vsY!j4;YZ{L$D>>_{V+C%=o^EqGfe5oJHl#6~|ieIbi zY(F0M6U)kL6+d6cC)+5Q8UCkyfCS^O2$f^NcPeWj3By8r9DoE?=XWf#KAyKR1tT}^ z$5<((J}^}}P%wCOGb~R50y|IyrDg#jb^=Fmc`9ary>V2cQ);J zDwo4K?WQ_ubS>IqeTH{J8FM(9gnYQOeKlBrIk7K%-~tw~XeV$1F;D|!5NR^-0t0}1 z_aVXQei6_x54c*DBMee*mTgKOlL1v{vv^hW-QN1zNyZ1LI6T*edZgF3qJAICd)4 z_g{DhVmhXYf7pq6IAE<7JuldZPDFpzqck)%S0?j_!!l@K$P(0K2dBb+6`_TThI{|# zcr}oVAEp73hI>Ls22Fr+!1#*)W{4G|K;DA^TQfHpP(NM(1$dK+ZMcf1gImq`Dq#}_ zMeql8AQMjl0F`%nn)n4O5P}s!232rgAxL8$$Y>`pi|ti;>u4t1Gm7w{j7uXyio-Ze z5CJ!^1?IwtGxLME1uGb^1B0UkF0ch2027uH1x!c=exP;42mlul0+gWwI4}cn004A= z0={^6GB9AdcZ)}$0VLN?$ViIQV@^vG{yu+@98RT*6~l_Hl0w~x0LJJMLZ@{=8EjYp z2r4iI1n6+Cl69P@iQFWH$ykc2(<(``l3Qhy1A~*N;!L3^6Inn5NvU<^_F+?C11Er# zDgX$=f{CZn1{APLEt!v{*i1asf&^)e4(2KvgM$x213lm>atB;~uy?vR16E)IKVSd@ zzyoY>cL4Y*O#lRqnE-d725#w;E*Xh)^9Onp1_#h`RauQUd5x!XH7{UYBDNF4QU#ib zf>SUBcmR|%W_jxf07w7`N9maW6hSl7MBv8+FHl?Wl~w~$6(d)Wr2}5t;svKS0d)Bi zaFJQh2b5r05lP?xRM3;h(*;ld@JQ<;E()}8R`UlFKuN->7_aew1|u%GgGTl92T}kA ze&rO-cYe~jUgo!zf~GUxxl%*ZoWiLDl;dpEhcEd7vNoa*$Srbl0gi^phHzPJVCzn0U@0g1 zHF|S%Vw0hPGlBK99e;rp(1|M+Py%hhYQdRSKZ+GgU^p_UoQ5MXG`Ivg#w{?~5J@@# zha-cCV?lot0bn2k19>04GI_Vs0x>`tRay{1@GBD_Hu^JxsuLvGnWhCXroPgqSkr@M zbt3VJANv9@+V4>!y5#f9!1E}{A1W}M-UqlnQ zDX9m6shqL`GwP`>;RKAq2P3coYq%xTktT#estnPpug!6&-9 zs|xX}z{(N5x+lUqtOjwc$f|F(nj*@&th@xR9#O1%@~qHmtaXtlu75(XX{xZxDzHq#urLa-!|Je0BC&yLum=lF)rzt6%CYqduNY#n|LL*kO0l*| zvXUyYxN5S_ivF^Ws#EP%Tci`x>1 zs}PUdFo}y0k-IC6n-iBC6_a}qmCGodyCIvaDw!)2qwABQTM(bCD5*;js|zZn3z33b zw@}f#heEr(WVbOEyA5Hxwi`94%eueoy1J_oubUsiJ0J4HyT_X;#p@EyI}*#=yM&^= zxJzck{)@PT8%)u=ypr;~EaAN~vAx=xy)}8gKV!ZLLA~O3L=4(H;yV$dLYJ=5Y7{#} zegeK9fxmD2zA>?DD?t=Pn-D?Jr=p?03qg~=_P>_`J75$A6EX*#Y7k-66hgwd=nE10 zJGir(xJ%)1dZ86qA}3-(C0&6f9(<%F$G-*PBtjt-Y=RY(q)%)@!bZ`-Xb~7M>?SxI zC0-%IeUYR;oJV+J5pLooI-EyqA{Rm67RYnKQiiu1oD)ibVKagmuYqB=u@o%w9+Z(8 zla|F@ysAN`!mOJBO7J1Rk*UwQ5-b8Es*%8O{2gu_B3o?5bR0>ap~ZMSBr@Vil4KnI zk|87G0T)wJ$InS}!GWe=5CsQ-of*s#kG#8N{4E9g9xK@&5V9av2D2Suz^JQB2|^|l zQXnZYE3Jwk#uFY3QXQha%9(5)KY_~hp&+Up$^`LCWOB))jGqY+$;9i#pi90o5x)-- z%cIQ7rz{?vY`nsZx}|)(uT0AQAt9@LAjeG2upF(pEX%6IOSX)#u58TV967*D&QSam zk-HQCj3YaO9Fue;$Uz!t%1AL1w3^$@z>6R*f+O$T#-^bJid-IvJRC5R5@>29L&C<{ zl*I~79PeDkB?2Nq(i)#Z5D0z6c6`htK}Nk?&P{yIP7%3s;urZ8CZ#bacJcls_jD#I z{Zy0eC412(`Ls_m4JIo6A3$8vEj`kBq|^Ac!!O}e$88!76(~)(s}sGJ)1mu_=~v)?nR9 zSRD~_O}TMRDqteX`20F*^3l1g)u_qUDRL4Cz$uV>*ItVfmLkTx^w(pJ*q^efRLQxJ zor6NT)E>PMbxqlOO)HWuE5RJaQWPtEwAp9|*mWe>8uHnv(#2pfC2Z|+u(BD+VcO>W z*m)ZTLcH6&-P^wX+rS;%!u{K_CoFWqyShEx%Dvpo-Q3O{+{Jw>y8fMGY8?~2>qvZ+ z-P*m~+}+*Y{oUE^6S$Hr*A3q0ectGu-s;U);teaV{Ycdf6R}MytX)LF+u8AUD>i1^ ze!bR}-Mz4aO!J-C1=!fui`ocI-=~tPonqJcE!&0t)(64gnw{Cmi_WT@A%UUP>HFUd zlh+I!-!C!XF6iO+CE_kY;{RsiqmAN@%i{T>;udA$9i8C*J-(tHR1_ZKxSiwo2;)^n z0jQ=KWcPOe&9Wh&JkYUr&8--o9nv1>%7kEyo>AY4J!=Z>%?B{#(wNkJGPIW z;?di*&i?GsjxEg|?bKfF*3K+@z7f=G>#V*a?5j(@o4wo)b4w0&<|?yHX6gX4>Dfz! ze6Z@>{t*7_9z{{R;_L44PVN#hz@dG>VtlL>e9NRB6N5hFvmVlH^dv|b?+?+zEQrHO zJkwpl#0r1JNt_iN9_OeYCs`4s;Jy$dToo)>CuYI^2P(b9Hr>LyZ6!18swABkN9@5s zEyNj*x$52{2mjOwVW$N*#Tc>Ab{t|+@FJ=4ND%E8$dOI&E*va!7_n`qP2Uhc55{mo zEwlm9Y^($Ytnr8Ia*3{dM!Roby|)*YI1(vCQiFVaur$V$(d; z|826)q0Q*=%(VQ>98;_(F&=y$&3!NHh`;d&FU6~25ykxX^g;LJF~43t5sjV@sC@UT z{P(ha;p?8wtql4C@A(#-?a-_79ih%e!OkdBAdZx&N8kE#AV~l)&-^5Qi{8rhJRAQU z(9sddsR7%9RQFVG$U9;pmQm1&pYBAi=sEtu(>fjT(XsMDO~V&|{Y&ihxgYW;pVHFb zCKFHkX<-%7kMSuV)F@o~%l_i1zxV-^`{KsfTT<|2-u#fh9Ma4Fg)Y}>Kj@e5yZ`|J z03R#`4IV_8P~k#`4IL^R_)y}+gAplS#F$azMvfEt0O-i^W5|aVNn$j4GNc$je8i}P zxiMu-hcjv3#F^70NSzEv_5=_`$xxz2jUGjs6sgUgO`W17_!J>isa36F{CPENPB2}) zegzv=>{zm3=3GUawjkA}Y}LL^yS1uZxOMH`rRY|tUc7y2(tQfp?_k1e`QkiWSTRfltBECFPAIskX3U*Em;My0RP<=lmOo$qNLuykqEQ~7h8-JWS=zO2pOu{( z%N*OieSg&*T=;O}#f=|Fo?Q8I=FOcyhaO$}bn4ZuU&o$Z`*!Z#y?+NEKDZKr1(kr= zIgmU^FaXeF0i$FsWrLg*u7~eFJ^hJYgYY&>yt|wL!wG|eFc1qT{zH#I1IPikw&&-sM zMVq8=jxbFELl0ZqGeZtNy3zwy1?4b<5C1IGLq7n_@JhX7;ZwrZVsEujAoje?4?XqD zW3fp9lx@#jbt!$wQcE*^ZBtl1J$J2j)Ae>^hF=9pcF+{IK=`pUh}TY@_r8Q>P}`z|Yh zZ|*Q+gAnd`VUiF2y4Yf6;naCP4?Qh8=!`l2DCwVRJ-{{gqBsD(a$Pdm4a@w0(Fkk>@h_JYj!5dax}7 z&cTAb4-mk*6I>8O@ViQobcG_6J^kHotuXXI>;8&C1q(coeEcCCU46S)HkpF literal 0 HcmV?d00001 diff --git a/iipsrv/fcgi/doc/fastcgi-prog-guide/ch1intra.gif b/iipsrv/fcgi/doc/fastcgi-prog-guide/ch1intra.gif new file mode 100644 index 0000000000000000000000000000000000000000..5565f985d6656fa625218edd86b9096fb14f83ab GIT binary patch literal 6208 zcmV-G7{BL7Nk%w1VY31C0LB0S00023t*wj8i=UsLo12@DkB|F&e2a^Ve}8{{eSLR# zclg-YU7cNXb8~NRZ$BR&X=!O^XJ=()WdQ#GU0q#UTU%FGS5s3{O-)Vy{{8^J07FAV zKR-V?IXUR)=;r3;FE1}GEiK;O-YY9B*x1+~A0HhZ9TyiD#>U1I6B7>)55T~{zP`S^ zyu7-)x&;LV`MJ5EprAki0G^(n{{R4*nwpT1kcNhagoK2Gf`Wj6fPQ{{e0+R#baZfV zaBOUBW@ct!U|?EWT2@w8|Ns9?Oica#{rmg-NJvQe`T6(v_e4ZQKtMn~K0fd7?>ag< z>+9<_Ha0XgG%_+WFfcGKE-v5S-z+RFC@3h|+1Vy0CL$stARr*m&(F=x%>Y0E$;rt8 zFaX2D!w?V<4h{~#zrVY?y9fvfxw*Nwx3{yivjC9bKm*JG=mh{=4giOE0Mr0PYzzpC zk7UN|0=&~c0GC`043rWK0sxP`5CkAM(*P1&AWy_3fG?7$(7tr4A^8LW002Y)EC2ui z0J8!0000O6fJB0WgoTEOh>41ejE#Ew3F~Y&W#==%B%Dc|b(9zP$c_dkE=rAvBEUjtY zEJz2qc9cUu+Dy7H~u24OUTSZ@4ri6-dB_&vY_y?gYq2ir9)y`Sal zowak{Ph^6B4Vs|ALwS$!pu~a1`DNgN3@Q=dU~}2GNhf&KH6e2pN~Z~b9M&aZ69^Jm z92yOl*x-YEc?FhOWR7xfGCjN=y zjZ8La2oLS;nB0F*i9l3}*V-I!9UY2uk_ z%2^_tZsz$~c_dCrr=53t$)OLMouwy#1cLD1qGRxYCZHz@x}OeQ_*I)QVg!)PrpEYm zs8zx>QNn;Cj;frabwb)DlczN>L<+FJa2ge2De);)0DP##qP)I$Pm!vjs_KDw?)g{; zMI>893dJ>dt5ms?X=h}Q4qGf`nl$jiw%m5>Ew@iRCh4O#nDM~;hStfp z4b;rY&=6yXb5sASi6&$K!>rfP5}080B1qq}bjdoG>4C~sP;fx1F9*HY3b%dm1QVV@ zlJ$mLm)rHQE(0ocS~{rkgxW(zV#N%5hYNDtOEnE}-P4+_m=1gMJqhF6hI=*PGZ{|z z&t-E6`FxUWuF2$-$7DIi)dJ0*H+w(#c}uw&m1%!L!bAi9&qE)5QPKX@vzeF+ zzu!HLcMF*z--o}+_|gj~0}V95pv2RSosWH)+QUj2xDhyc;p>113_xkd06yl>&nVHl zU;dQvHI<>E2E7_X2|y6M#PKHvw)?Wzyi2Lf-BkZ zJVT1w@buD!AdDb$00zh0YMysCYFE!bZFuP zLeNALhQ!Fq4F{5ClH{7?D3vlmAqi&C#1(pQKnpyu_PzGgN8LGAc7uq9#0cFKrfQZhFDINj9735_G8vs)idQ+P*<@v)WsGtGw3Z@107Jw1pGoKof zCM?lMMfGtd7+1W9Cpmc!PJ;4w+6vd+NGM7GjI;r22mt_igVBw^?t1;q-an60BZ1QE z3Xl1rJ>|JKd<|2eCir0xkidkL)HI{Ni(O6uxc*b4q%oWAG!8u9dCz;nF=9`(X;g9A z(R5w~1wv@wx4;E}5U9aAkZB;do+nSZg;lK5I^0yvSk;*@VG1YETf8LDt#>`api#&| z46v{P2{^_CK#iC49BP6J^!2XLxG5R;YN8)B;Rma_%418|(w8y;2r)=Q3cvanlxpGv zEx>Fv$GX|FCaH$Xv14dKC8BPwbzTC+K@C3AHrZlCvv}mJ5=byMG48f1z4h%{-4_5g z+=i0Ibp~=Hsa#Sy7rQc{5P`Bd-E9G&16r_acA=Wr%h{GejsX#PW749q6reakjF%0% zWdk9S0RmxJ?`+!(yd)6-KK*+xSAYT1{^Bel0wu(NCVR000mEdwu|y{UcrYZ#jB36~ z0ik9p)ffqE;2vbqf<;GWVZ3g1O9HE4*qZAXM*`qvAa2T4A%kA^wwS#yrjo$;=a@Rm z_p(+AsV0_1mmgnPK=@9K%Vw=JiDe{c9=%ph)*P8IKY$8!#nX*$H8GsDW)h z1oh3@tH$R1 zIQ0`Y9xrHCxSFa3L62e0ccDRDhM%B=gGw` zjWmX=F`&DIc)z`su+#pX7Ir5EMOJaubcc8Df1ibj+d+0xbRpxas8Jb$(A2E>J@KM| zx=ngh6tC|?2NkBuf--`r98u zB%o=1TF7p3rS#tS4E9a(f8+UM7v=bWZ$0o+zn#?!A12VJd+yt`{g-4P;d_@@;5G7n zUIU+P^@aSch+p}Olpo9t27UZPPr2rU-WF?di~ikm-~Ic)E$Y`q_4R-JcMot!fd2;^ z2)KWmaDWTAe{dlQO6F<=!go!iaugU{z>$Hj_D_R13m*tZ?-vOpSTcqe3Aq!3te}D| zRDzG-g5`38kp7T@7Pty5_&_k&2su~^J;4)SHw!uD2sCI5H%LD_h&8sy3X7Boi9rlb zbqhh*2t!y4ML0f3s0dd$gF(}TyAXwpFom>Gh0&9Rh(LyhFn%iM8X1xp5i$sN*M_O! zg~8#0HK+<=*gIxu2zfXNK7b8_Ko+j>6@u_~VG#u9AP7B_7glgzCP8_sAcu+oh9Fpn zMwo=8u!m(g46)%Qt55%(dBc|nW$@rW`=7<5R4yf}uwCdnW%SeUIh= z1GKV)DOZ%ZhnAHC7&ysdAZd{jc$J?}lCm%z7g8bVV3*@ijecPt+4z>wsFss3k?+v{ z7&Qo(o5+*kI1Pn&kbHTJ*0Gn_;Scy^iw3cgT2Uc8SqlznhjK|1v;qJip%05#izR^{ zli7&0(hinc5SVFs3rUq1shIZ2nEe2hZMF=z0aB;Q1iJ|gG?jFDNmB~(n$9tmxmcCE zI1Mr2R6Y(V9omo!Ii7a2W}784Bwe z4di(c?^zLoDG7urXz0n1;klR!;SGb65uULbPpF6UNrD4vg0q>QwW$!r5DXi!V>2ZT z^d|`BxfqDq3d;GAapRzt@{W#K3-x(i_nDXonvq+hp^f1X6RH>$3X8M}f*k(%qA(hx zG8&_{fNy~ppN~mCA!?y5dWsJCfIu3gLOP^GTBJrgd5}?-_En%SXnUoZj?`BOji(CL zAqy*77Z>W88ETlp&^9S5pu`Y*{b+xi0u=Hm5ewQIP?rpw$0;jtl=MfY%Ak2Y$Y+~L z3!Rw??fE5FRc}V~rG)?xLs1S~zzx-Th@!a-uY9HFb4IRM_C$XAQDx!FrrF#0AP12ZH$fS;7bAmb%k~tkH>IuSFtH;O?kqL`z zxROIL?3Cl_{&02QsFrEES4&%Uh15gr^Dh>iMn%#h?pK7Zsfu;Xhor-E5g-Q;9W(Doq z8Q_qphB}#!>aCoKs;Dro5>u{3u%c8(HUo2aAO*=LBXJDniI_+r9%O+ z4EnHU8llFTusyn*t>myyfpG|Xsw<13E$gZ}XtT#va(4=Z3VR9++b=H5G>Vk6GCQJH zsgXE~gqisleu|$(i>%_wNI_dJk0A^@aiw{>u;EHB8+oK&`?X-}7R3>oJIbO)%d%3N zw5>X$Y}>XJShiR?vszlSHLAAR_83mfvvQlNNL#l{>leur{$Qr6w`WVUY3sLHaSyy< zr-N&yJ!=X-%e8h}hLg(|))1iJ`Ly5~wR1GJnF+U9>$6+?ES{UVp!>L`5V@pVxnTMm zSc|#?*|#3bx|MUfd#kmwOA8;mY_?mtb9=b6yMet6wfYIXx=Xt<@w&Gwy16?GyQ>h& z>$`kQx54YW!@Ie~+quZQiraf(*E<@cE4{slxX1ae;LEup*u5QEzA7ue%uBt;E4=3G z2&(J8;z+*UIlqlizr<_2&a1vQ^}X~PzWuAc_z{ z8%)6+Jj1JC!*2V-KrAjVtOzkYz|E_|g@_tqyTnXPq|wX4Xj{SY`>?_w!rf!KLwt58 zY{V%{!-jytSBw=;tiw^9z6Z<;H-p7FEW;$q!>RzQBMh0^Rl+d5#S(nPUd#w!xv-^* zqraEIC`iXdY{w>y$35J=PM41MP#bNNe2MX~R6Metf;I|+vI`-|T8zGlUf*FWd2JOlO0}updNqN>VBQBAe#Bi=Z7&4fQ2t|CyhyloM^2wLLg7?v6++!od zYK)^W#%#R9hmeMG!^@Yjjd3fhgy77>tcL!sYRp`mpoO3rpxQcH!_1Y?hXMASW*ZUF z>|@jHti@c*hj7bI;n55Ddh*vBof+oT7ZfpwEL4e-Zl$){M(x=z!bo z7)sj23cb(_O{9!y!K{G6oQlDo2%y%%8H7L@*?hU6FwpHBhCv+CB0bW@amFgD&hSIX zbvzNL5zk@b&A5Wn*{sroe2!%S&&xc|aSWnaY|AvA$!8c0*Tv0C1JhIC(JP(3hH!q= znF=bxjsYloI=u+!sK%Om%w^1kE-e>yAwIJ=)kJ(zq9xNA{nI{eo8+95CT*fPeAU<7 z#?Sx}>Uw^fQJv7)lF+HI*U1vvx&9fm91X_F)Gch)gbT%n8`r!+VMo~)$6!gdab3O; z3m}x((y_R}Y0qYj2^%R4L+uz&`PrZy+MnVr&T z9hqymA;Q=?b^#Dw&E46!tF{f+87)qP?YPSexz!B`oQ#Mv0*@x)+R5{k4)N43k`M6x zisOC8`4`=wLe|iH+7QeX&C1z3J(P1i-PSGO1_6k0YtnC=gjIS9W_bwBy$Zp7)(q~N zG?x@c9SUr6;mD}qGp)%j{z%?+X;;e3y?J?>7nR+$sNGG52^mh^CXRzBz6#)MBY-&H zgXo)uc!;Q67QvSdenXCn?&ndi7jN$5 zaqf(x9v7t!>d5TqA8fs!&gY?i;;Eh%t1j!UF6wiB(y`9yxlZf5E+31|&PnaYsqnx~ zH0c)-=$bJz1w+>e%?H9|=X4CH96ngElCkc_>(EHcv^fQ3ozJCfh?*A8ozL)Om zzV7Va?(Y8X@E-5-KJWBi@AiK0_@3|jzVH0r?~7sIVj*sl9^YX3cm)q5mmXkG9hUVC z?s{=_jTiA}q2Gau?v0@77atZDKN{a%?UVyO_!08Hsx@$k=)S%fFrK5mnz=WtnMc#% zkf4|B7L3!#cLbr_&+73FS~DNG^72VL*MeQC{R(tF8_zj?&H3YeEuD95<>N#1tbX(J zT8tp`ctx)nciq=7iMdH(nIG8RzD^+&chNBE6N&1am8Thvy5?GM*L2PGyRpc~AR9Dw z4VF~d{cQf(KnawNZONen^|&te1!u7ky4Z>B3wIBcS-zX+@YhA*^?l=cj2^;6K`Hf2 z_n0jZto(T#TPgMtmBT3!cE8B>maXc_tEc&q1wfYCDBDgz+h+gZivjpyU&9C2-s-yA zjVjFQu=^&Ft~#F!WGN}Wc@`ug>pm~uEuPlPe;AX8sJ!p<%WvVSkNV7im-VsS>G||E zAN96R{So13Th9B;&J@lJSH)QU+REqFs{YL%{oShl%Afu4gN?!(-rGH^%&pybA^VC! z`+&ftLqtee20*9-fLK_l!$h>Ga|lqTxLDRGNGM4OFxVI>I!anrmS)%AOw zys=m(N?*0z1x?MO=SYHTEgqo1qFFe5`uqtrsL-KA ei + + + + FastCGI Programmer's Guide - Chapter 1, The Fast Common Gateway Interface + + + + + [Top] [Prev] [Next] [Bottom] +
+
+ +
+

+ 1 The Fast Common
+ Gateway Interface +

+
+ +

+ The Fast Common Gateway Interface (FastCGI) is an enhancement to the existing CGI (Common Gateway Interface), + which is a standard for interfacing external applications with Web servers. +

+

+ FastCGI is a proposed open standard and we expect both free and commercial Web servers to + support it. FastCGI is included in Open Market WebServer and Secure WebServer, versions 2.0 and greater. +

+
+
+

+ Advantages of FastCGI +

+ +

+ FastCGI extends and enhances the CGI model in several ways: +

+
+
+
    +
  • + +
  • +
  • + FastCGI enables applications to persist between client requests, eliminating application start up overhead + and allowing the application to maintain state between client calls. +
  • +
  • + FastCGI enables applications to reside on remote systems (rather than having to reside on the same system + as the Web server) +
  • +
  • + FastCGI enables additional flexibility in application functionality, with explicit support for applications + that do client authentication and filtering of input. +
  • +
+

+ Long-lived Applications +

+ +

+ CGI applications are ephemeral and short-lived: each time a client requests a CGI application, the server asks + the operating system to spawn a new CGI process. After the CGI process satisfies the request, the server kills + it. The server spawns and subsequently kills a new process for each client request. +

+

+ FastCGI applications are long-lived, and can persist between client calls. The server + spawns the FastCGI process once and it continues to run and satisfy client requests until it is explicitly + terminated. You can also ask the Web server to start multiple copies of a FastCGI application, if you expect + that concurrent processing will improve the application's performance. +

+

+ Long-lived applications have two important advantages over short-lived applications: +

+
+
+
    +
  • + +
  • +
  • + A short-lived application pays start up overhead on every request; a long-lived application spreads the + overhead over many requests. For an application that has a heavy start up cost, such as opening a database, + doing initialization on every call can be very inefficient. Reinitializing for every client is also very + inefficient for Perl programs, where the interpreter reads through the entire program before executing any + of it. +
  • +
  • + A long-lived application can cache information in memory between requests, allowing it to respond more + quickly to later requests. +
  • +
+ +

+ FastCGI is not the only way to get a long-lived application on the Web, however. For example, there are many + existing search engines that are implemented as long-lived applications. +

+

+ In most cases, these applications rely on customized Web servers. In other words, since + most Web servers do not support long-lived applications, a programmer must code this support into a Web + server. This approach requires a tremendous amount of work and also ties the application to a particular + server. +

+

+ Another way to get a long-lived application is to write code that calls routines from the + Web server's API. This alternative involves a lot of extra coding, ties the application to a particular + Web server, and introduces problems of maintainability, scalability, and security. +

+

+ We believe that FastCGI is the most general and flexible strategy for building long-lived + Web applications. +

+
+
+

+ Separating Application and Server +

+ +

+ CGI applications must run on the same node as the Web server; FastCGI applications can run on any node that + can be reached from your Web server using TCP/IP protocols. For example, you might want to run the FastCGI + application on a high-speed computer server or database engine, and run the Web server on a different node. +

+
+
+

+ FastCGI "Roles" +

+ +

+ CGI and FastCGI applications are effective ways to allow an application to act as an extension to the Web + server. CGI provides no explicit support for different kinds of applications: under CGI, every application + receives an HTTP request, does something with it, and generates an HTTP response. FastCGI provides explicit + support for several common "roles" that applications can play. +

+

+ The three roles supported by the WebServer 2.0 are: +

+
+
+
    +
  • + +
  • +
  • + Responder +
  • +
  • + Filter +
  • +
  • + Authorizer +
  • +
+

+ Responder Applications +

+ +

+ A responder application is the most basic kind of FastCGI application: it receives the information + associated with an HTTP request and generates an HTTP response. Responder is the role most similar to + traditional CGI programming, and most FastCGI applications are responders. +

+
+
+

+ Filter Applications +

+ +

+ A filter FastCGI application receives the information associated with an HTTP request, plus an extra + stream of data from a file stored on the Web server, and generates a "filtered" version of the data + stream as an HTTP response. +

+

+ With filter applications, the system administrator maps a particular MIME-type to a + particular filter FastCGI application. When a client requests a URL with that MIME-type, the Web server + invokes the filter application, which processes the file at the specified URL and sends a response (usually + HTML text) back to the client. +

+

+ For example, suppose you write a filter FastCGI application that converts SGML text to + HTML, and map the extension .sgml (MIME-type SGML) to your filter FastCGI application. Now, suppose that a + user requests the following URL: +

+
+
+
+/www.aerjug.com/docs/chap1.sgml
+
+
+ +

+ Given this URL, the Web server passes chap1.sgml as input to your filter FastCGI application, + which processes chap1.sgml and returns an HTML version of it to the requesting client. +

+
+
+

+ Authorizer Applications +

+ +

+ An authorizer FastCGI application receives the information in an HTTP request header and generates a + decision whether to authorize the request. +

+

+ To mark a FastCGI application as having the authorizer role, the system administrator + names the application inside the server configuration file, using a directive called + AuthorizeRegion. (See the Open Market Web Server manual for information on server configuration + directives.) +

+

+ When a client requests a URL that meets the AuthorizeRegion criteria, the Web + server calls your authorizer FastCGI application. If your application grants authorization (by returning a + response code of 200), the Web server resumes execution of commands in the AuthorizeRegion + section. If your application denies authorization (by returning any other response code), the Web server stops + processing subsequent commands in the AuthorizeRegion section, and returns the response from your + FastCGI application to the client. +

+

+ Authorizer applications can return headers containing environment variables. Other CGI or + FastCGI programs accessing this request (including other authorizers) can access these environment variables. + The headers must have the following format: +

+
+
+
+Variable-name: value
+
+
+ +

+ For example, the following header +

+
+
+
+Variable-AUTH_METHOD: database lookup
+
+
+ +

+ causes the environment variable AUTH_METHOD to be set to "database lookup" + for this request. Other CGI or FastCGI applications running on this request can access the value of + AUTH_METHOD. +

+

+ Authorizer applications cannot successfully read from standard input. Any attempts to read + from standard input result in an immediate EOF. +

+

+ All data that authorizer applications write to standard error will get written to the + traditional server error logs. +

+
+
+

+ Writing FastCGI Applications +

+ +

+ The work involved in writing a FastCGI application depends in large part on the I/O libraries that you use. + This manual describes how to write FastCGI applications in terms of the Open Market libraries, which are + available for C, Perl, and Tcl. FastCGI is an open standard and you are welcome to build your own libraries + for other languages as well, but this manual focuses on building FastCGI applications in the context of the + Open Market libraries. +

+

+ +

+

+ In general, the goal of the libraries is to make the job of writing a FastCGI application + as much like writing a CGI application as possible. For example, you use the same techniques for query string + decoding, HTML output to stdout, use of environment variables, and so on. When you use our libraries, porting + CGI applications to FastCGI is mostly a matter of restructuring the code to take advantage of FastCGI features + and libraries. +

+
+
+

+ Code Structure +

+ +

+ The main task of converting a CGI program into a FastCGI program is separating the initialization code from + the code that needs to run for each request. The structure should look something like this: +

+
+
+
+Initialization code
+
+Start of response loop
+
+   body of response loop
+
+End of response loop
+
+
+ +

+ The initialization code is run exactly once, when the application is initialized. Initialization code + usually performs time-consuming operations such as opening databases or calculating values for tables or + bitmaps. +

+

+ The response loop runs continuously, waiting for client requests to arrive. The + loop starts with a call to FCGI_Accept, a routine in the FastCGI library. The + FCGI_Accept routine blocks program execution until a client requests the FastCGI application. + When a client request comes in, FCGI_Accept unblocks, runs one iteration of the response loop + body, and then blocks again waiting for another client request. The loop terminates only when the system + administrator or the Web server kills the FastCGI application. +

+
+
+

+ Initial Environment Variables +

+ +

+ When a FastCGI process starts up, it has not yet accepted a request, and therefore none of the CGI environment + variables are set. +

+

+ You set the initial environment of a FastCGI process started by the AppClass + directive using the -initial-env option. The process would use this environment to configure its + options and locate files or databases. +

+

+ In FastCGI processes started by the AppClass directive with the -affinity + option, the FCGI_PROCESS_ID variable is set in the initial environment (not in the environment of + a request). FCGI_PROCESS_ID is a decimal number in the range 0 to N - 1 where N is the number of + processes (argument to the -processes option to AppClass). The process would use + FCGI_PROCESS_ID in conjunction with other variables to locate session-related files or databases + during restart. +

+
+
+

+ Per-Request Environment Variables +

+ +

+ In general, FastCGI uses the same per-request environment variables as CGI, and you access the values of + environment variables in FastCGI applications just as you would in CGI applications. The only differences are + as follows: +

+
+
+
    +
  • + +
  • +
  • + In Authorizer FastCGI applications, the Web server unsets the PATH_INFO, + PATH_TRANSLATED, and CONTENT_LENGTH variables. +
  • +
  • + In Filter FastCGI applications, the Web server sets two additional environment variables: +
      +
    • + +
    • +
    • + FILE_LAST_MOD: The Web server sets FILE_LAST_MOD to the date and time that + filter input file was last modified. The format is the number of seconds since midnight (UTC), + January 1, 1970. +
    • +
    • + FCGI_DATA_LENGTH: The application reads at most FCGI_DATA_LENGTH bytes from + the data stream before receiving the end-of-stream indication. +
    • +
    + +
  • +
  • + FastCGI sets FCGI_ROLE for each request to RESPONDER, AUTHORIZER, or + FILTER. +
  • +
+

+ Building FastCGI Applications in C +

+ +

+ The Software Development Toolkit that accompanies WebServer 2.0 contains two libraries, fcgi_stdio and + fcgiapp, for building FastCGI applications in C. +

+

+ The fcgi_stdio library implements our philosophy of making FastCGI applications similar to + CGI applications, and provides full binary compatibility between FastCGI applications and CGI applications: + you can run the same C binary as either CGI or FastCGI. +

+

+ The fcgiapp library is more specific to FastCGI, and doesn't attempt the veneer of + CGI. +

+

+ We recommend that you use the fcgi_stdio library, and this manual describes the routines + in that library. The documentation for the fcgiapp library is in the code in the development kit. +

+
+
+

+ Building FastCGI Applications in Perl +

+ +

+ To build FastCGI applications in Perl, you need a FastCGI-savvy version of Perl, plus the FastCGI extension to + Perl. We build FastCGI-savvy versions of the Perl interpreter for several common platforms and make them + available on our Website. For details and examples, see Chapter 3, "Developing + FastCGI Applications in Perl," on page 17. +

+
+
+

+ Building FastCGI Applications in Tcl +

+ +

+ To build FastCGI applications in Tcl, you need a FastCGI-savvy version of Tcl. We build FastCGI-savvy versions + of the Tcl interpreter for several common platforms and make them available on our Website. For details and + examples, see Chapter 4, "Developing FastCGI Applications in Tcl," on page + 19. +

+
+
+

+ Implementation Details +

+ +

+ The FastCGI application libraries are designed to shield you from the details of the FastCGI design. This + section is designed for the curious reader who would like some low-level understanding. If you are not curious + about the implementation, you can happily skip this section. +

+

+ As shown in the following figure, CGI applications use the three standard POSIX streams + (stdin, stdout, and stderr), plus environment variables, to communicate + with an HTTP server. +

+

+ error-file:TidyOut.log +

+

+ +

+
+
+
+ Figure 1: Flow of Data in CGI +
+ +

+ The fundamental difference between FastCGI and CGI is that FastCGI applications are long-lived, which means + that the Web Server needs to rendezvous with a running application, rather than starting the application in + order to explicitly communicate with it. +

+

+ The FastCGI implementation basically creates a bidirectional connection between two + processes that have no relationship. FastCGI uses a single connection for all the data associated with an + application -- stdin, stdout, stderr, and environment variables. The data on the connection is encapsulated + using a FastCGI protocol that allows stdin and the environment variables to share the same half connection (on + the way in) and stdout and stderr to share the half connection (on the way out). +

+

+ On the input side, the FastCGI application receives data on the connection, unpacks it to + separate stdin from the environment variables and then invokes the application. On the output side, FastCGI + wraps stdout and stderr with appropriate protocol headers, and sends the encapsulated data out to the server. +

+

+ Since a FastCGI application does not always run on the same node as the HTTP server, we + support two implementations of the connection: a stream pipe1, for + communications on the same machine, and TCP streams, for communication when the client and the server are on + different machines. +

+

+ error-file:TidyOut.log +

+
+
+
+ Figure 2: Flow of Data in FastCGI when server and application are on different machines +
+

+ The fcgi_stdio Library: I/O Compatibility +

+ +

+ The implementation for I/O compatibility is that the library fcgi_stdio.h contains macros to + translate the types and procedures defined in stdio.h into the appropriate FastCGI calls. For example, + consider a FastCGI program written in C containing the following line of code: +

+
+
+
+fprintf(stdout, "<H2>Aerobic Juggling</H2>/n");
+
+
+ fcgi_stdio.h +

+ header file contains the macro +

+
+
+
+#define fprintf FCGI_fprintf
+
+
+ +

+ So the preprocessor translates the fprintf call into the following call: +

+
+
+
+FCGI_fprintf(stdout, "<H2>Aerobic Juggling</H2>/n");
+
+
+ FCGI_fprintf +

+ takes the same arguments as fprintf. +

+

+ The implementation of FCGI_fprintf tests the file to see if it is a normal C stream or a + FastCGI stream, and calls the appropriate implementation. +

+

+ The fcgi_stdio.h header file contains macros to translate calls to all ISO + stdio.h routines (and all conventional Posix additions, such as fileno, fdopen, + popen, and pclose) into their FastCGI equivalents. +

+
+
+

+ The fcgi_stdio Library: Binary compatibility +

+ +

+ The fcgi_stdio library provides full binary compatibility between FastCGI applications and CGI applications: + you can run the same C binary as either CGI or FastCGI. +

+

+ The implementation is in FCGI_Accept: the FCGI_Accept function tests its environment to + determine whether the application was invoked as a CGI program or an FastCGI program. If it was invoked as a + CGI program, the request loop will satisfy a single client request and then exit, producing CGI behavior. +

+

+ +

+

+

+
+
+ [Top] [Prev] [Next] [Bottom] +
+
+ 1 +

+ UNIX Network Programming, W. Richard Stevens, 1990 Prentice-Hall, Section 7.9 +

+

+ + + + + + +

+ + + diff --git a/iipsrv/fcgi/doc/fastcgi-prog-guide/ch2c.htm b/iipsrv/fcgi/doc/fastcgi-prog-guide/ch2c.htm new file mode 100644 index 0000000..8e69697 --- /dev/null +++ b/iipsrv/fcgi/doc/fastcgi-prog-guide/ch2c.htm @@ -0,0 +1,379 @@ + + + + + FastCGI Programmer's Guide - Chapter 2, Developing FastCGI Applications in C + + + + + [Top] [Prev] [Next] [Bottom] +
+
+ +
+

+ 2 Developing FastCGI
+ Applications in C +

+
+ +

+ This chapter explains how to code FastCGI applications in C and how to build them into executables. +

+

+ If you are converting a CGI application into a FastCGI application, in many cases you will + only need to add a few lines of code. For more complex applications, you may also need to rearrange some code. +

+
+
+

+ The I/O Libraries +

+ +

+ The FastCGI Software Development Kit that accompanies Open Market WebServer 2.0 includes I/O libraries to + simplify the job of converting existing CGI applications to FastCGI or writing new FastCGI applications. There + are two libraries in the kit: fcgi_stdio and fcgiapp. You must include one of these header files in your + program: +

+
+
+
    +
  • + +
  • +
  • + fcgi_stdio.h +
  • +
  • + fcgiapp.h +
  • +
+ +

+ The fcgi_stdio library is a layer on top of the fcgiapp library, and we recommend + strongly that you use it, both for converting existing CGI applications and for writing new FastCGI + applications. The fcgi_stdio library offers several advantages: +

+
+
+
    +
  • + +
  • +
  • + Simplicity: there are only 3 new API calls to learn +
  • +
  • + Familiarity: If you are converting a CGI application to FastCGI, you will find few changes between CGI and + FastCGI. We designed our library to make the job of building a FastCGI application as similar as possible + to that of building a FastCGI application: you use the same environment variables, same techniques for + parsing query strings, the same I/O routines, and so on. +
  • +
  • + Convenience: the library provides full binary compatibility between CGI and FastCGI. That is, you can run + the same binary as either CGI or FastCGI. +
  • +
+ +

+ The fcgiapp library is more specific to FastCGI, without trying to provide the veneer of familiarity with CGI. + This manual describes the fcgi_stdio library; the fcgiapp library is documented in the header files that + accompany the development kit. +

+
+
+

+ Code Structure +

+ +

+ To structure code for FastCGI, you separate your code into two sections: +

+
+
+
    +
  • + +
  • +
  • + Initialization section, which is executed only once. +
  • +
  • + Response loop section, which gets executed every time the FastCGI script gets called. +
  • +
+ +

+ A response loop typically has the following format: +

+
+
+
+while (FCGI_Accept() >= 0) {
+
+# body of response loop
+
+}
+
+
+ +

+ The FCGI_Accept blocks until a client request comes in, and then returns 0. If there is a system + failure, or the system administrator terminates the process, Accept will return -1. +

+

+ If the application was invoked as a CGI program, the first call to Accept returns 0 and + the second always returns -1, producing CGI behavior. (See "FCGI_Accept + (3)" on page 21 for details.) +

+

+ Also note that the CGI world encourages small scripts, whereas FastCGI encourages + combining scripts. You may choose to rethink the overall structure of your applications to take better + advantage of FastCGI performance gains. +

+
+
+

+ Example 1: TinyFastCGI +

+ Here is a simple example of a responder FastCGI application written in C:
+
+
+#include "fcgi_stdio.h" /* fcgi library; put it first*/
+#include <stdlib.h> + +int count; + +void initialize(void) +{ + count=0; +} + +void main(void) +{ +/* Initialization. */ + initialize(); + +/* Response loop. */ + while (FCGI_Accept() >= 0) { + printf("Content-type: text/html\r\n" + "\r\n" + "<title>FastCGI Hello! (C, fcgi_stdio library)</title>" + "<h1>FastCGI Hello! (C, fcgi_stdio library)</h1>" + "Request number %d running on host <i>%s</i>\n", + ++count, getenv("SERVER_HOSTNAME")); + } +} +
+

+ Example 2: Prime Number Generator +

+ +

+ Consider a responder application that generates the n-th prime number. +

+

+ A CGI application would have no efficient way of solving this problem. For example, if the + user asks for the 50,000th prime number, a CGI application would have to calculate the first prime number, + then the second, and so on, up until the 50,000th. The application would then terminate, taking with it all + its hard-earned calculations. If a client then asks for the 49,000th prime number, the server will have to + spawn a new CGI application which will have to start calculating prime numbers from scratch. +

+

+ FastCGI applications can be much more efficient at this sort of problem, since they can + maintain state. A FastCGI application can calculate an extensive table of prime numbers in its initialization + phase and then keep the table around indefinitely. Whenever a client requests a particular prime number, the + response loop merely needs to look it up in the table. +

+

+ Here is the code for the prime number example: +

+
+
+
+#include "fcgi_stdio.h"
+#include <stdlib.h>
+#include <string.h>
+
+#define POTENTIALLY_PRIME 0
+#define COMPOSITE 1
+#define VALS_IN_SIEVE_TABLE 1000000
+#define MAX_NUMBER_OF_PRIME_NUMBERS 78600 
+
+/* All initialized to POTENTIALLY_PRIME */
+long int  sieve_table[VALS_IN_SIEVE_TABLE]; 
+long int  prime_table[MAX_NUMBER_OF_PRIME_NUMBERS];  
+/* Use Sieve of Erastothenes method of building 
+   a prime number table. */
+void
+initialize_prime_table(void)
+{
+ long int prime_counter=1;
+ long int current_prime=2, c, d; 
+  
+  prime_table[prime_counter]=current_prime;
+
+  while (current_prime < VALS_IN_SIEVE_TABLE)   {
+   /* Mark off composite numbers. */
+     for (c = current_prime; c <= VALS_IN_SIEVE_TABLE; 
+          c += current_prime)  {
+        sieve_table[c] = COMPOSITE;  
+     }
+
+   /* Find the next prime number. */
+     for (d=current_prime+1; sieve_table[d] == COMPOSITE; d++); 
+   /* Put the new prime number into the table. */ 
+     prime_table[++prime_counter]=d; 
+     current_prime=d;
+  }
+}
+
+
+void main(void)
+{
+    char *query_string;
+    long int n;
+
+    initialize_prime_table();
+
+    while(FCGI_Accept() >= 0) {
+        /*
+         * Produce the necessary HTTP header.
+         */
+        printf("Content-type: text/html\r\n"
+               "\r\n");
+        /*
+         * Produce the constant part of the HTML document.
+         */
+        printf("<title>Prime FastCGI</title>\n"
+               "<h1>Prime FastCGI</h1>\n");
+        /*
+         * Read the query string and produce the variable part
+         * of the HTML document.
+         */
+        query_string = getenv("QUERY_STRING");
+        if(query_string == NULL) {
+            printf("Usage: Specify a positive number in the query string.\n");
+        } else {
+            query_string = strchr(query_string, `=') + 1;
+            n = strtol(query_string);
+            if(n < 1) {
+                printf("The query string `%s' is not a positive number.\n",
+                       query_string);
+            } else if(n > MAX_NUMBER_OF_PRIME_NUMBERS) {
+                printf("The number %d is too large for this program.\n", n);
+            } else
+                printf("The %ldth prime number is %ld.\n", n, prime_table[n]);
+            }
+        }
+    } /* while FCGI_Accept */
+}
+
+ +

+ This application has a noticeable start up cost while it initializes the table, but subsequent accesses are + fast. +

+
+
+

+ Building +

+ +

+ This section explains how to build and debug FastCGI applications written in C. +

+

+ The C preprocessor needs to know the location of the fcgi_stdio.h header + file, which is at the following pathname: +

+
+
+
+$toolkit/include/fcgi_stdio.h
+
+
+ +

+ where $toolkit symbolizes the directory in which you have installed the Software Development Kit for + FastCGI. +

+

+ The linker needs to know the location of the libfcgi.a library file, which is + at the following pathname: +

+
+
+
+$toolkit/libfcgi/libfcgi.a 
+
+
+ +

+ If your linker does not search the Berkeley socket library, then you must add linker directives to force this + search. +

+

+ We provide a sample application Makefile at the following pathname: +

+
+
+
+$toolkit/examples/Makefile
+
+
+ +

+ This Makefile contains the necessary rules and pathnames to build the C FastCGI applications + accompanying the toolkit. To build all the applications, type: +

+
+
+
+$ ./configure
+$ make +
+
+

+ Memory Leaks +

+ +

+ Memory leaks are seldom a problem in CGI programming because CGI applications rarely run long enough to be + concerned with leaks. However, memory leaks can become a problem in FastCGI applications, particularly if each + call to a popular FastCGI application causes additional memory to leak. +

+

+ When converting to FastCGI, you can either use a tool such as Purify from Pure Software to + discover and fix storage leaks or you can run a C garbage collector such as Great Circle from Geodesic + Systems. +

+

+ +

+

+

+
+
+ [Top] [Prev] [Next] [Bottom] +
+
+ + + + + + + + + diff --git a/iipsrv/fcgi/doc/fastcgi-prog-guide/ch3perl.htm b/iipsrv/fcgi/doc/fastcgi-prog-guide/ch3perl.htm new file mode 100644 index 0000000..e2a20e3 --- /dev/null +++ b/iipsrv/fcgi/doc/fastcgi-prog-guide/ch3perl.htm @@ -0,0 +1,151 @@ + + + + + FastCGI Programmer's Guide - Chapter 3, Developing FastCGI Applications in Perl + + + + + [Top] [Prev] [Next] [Bottom] +
+
+ +
+

+ 3 Developing FastCGI
+ Applications in Perl +

+
+ +

+ This chapter explains how to code FastCGI applications in Perl. Before you can build FastCGI applications in + Perl, you must have a FastCGI-savvy version of the Perl interpreter. Open Market develops such Perl binaries + for popular platforms and makes them available with our developer's kit. +

+

+ The FastCGI-savvy binaries are extensions of standard Perl, and are intended to replace + your existing Perl installation. There is no need to maintain two versions of Perl: the version that we supply + will work fine when invoked from a shell or a CGI program. There are also directions in the developer's + kit for how to make your own FastCGI-savvy Perl, if you need a version for some platform that we don't + supply. +

+

+ FastCGI is ideal for applications written in Perl, because it provides a huge performance + gain. When you run a Perl script, the Perl interpreter analyzes the entire script before executing any of it. + With FastCGI, you can factor out this initialization cost and pay it only once, making execution of the actual + script much faster in response to client calls. +

+
+
+

+ Getting Started +

+ +

+ The first line of any Perl script typically specifies the pathname of the Perl interpreter itself. You must + specify the pathname of a FastCGI-savvy Perl. +

+

+ Next, you must tell Perl to load the FastCGI extension. To do so, place the following line + near the beginning of every FastCGI script: +

+
+
+
+use FCGI;
+
+
+ +

+ Then, you have to divide FastCGI scripts into the following two sections: +

+
+
+
    +
  • + +
  • +
  • + Initialization section, which is executed only once. +
  • +
  • + Response loop section, which gets executed every time the FastCGI script gets called. +
  • +
+ +

+ A response loop typically has the following format: +

+
+
+
+while (FCGI::accept >= 0) {
+
+# body of response loop
+
+}
+
+
+ +

+ The accept call returns 0 whenever a client requests the FastCGI script. Otherwise, the + accept call returns -1. +

+
+
+

+ Example: TinyFastCGI +

+ +

+ Here is a simple example of a FastCGI application written in Perl: +

+
+
+
+
+#!fcgi-savvy-perl
+
+use FCGI; # Imports the library; required line
+
+# Initialization code
+
+$cnt = 0;
+
+# Response loop
+
+while (FCGI::accept >= 0) {
+  print "Content-type: text/html\r\n\r\n";
+  print "<head>\n<title>FastCGI Demo Page (perl)</title>\n</head>\n";
+  print  "<h1>FastCGI Demo Page (perl)</h1>\n";
+  print "This is coming from a FastCGI server.\n<BR>\n";
+  print "Running on <EM>$ENV{SERVER_NAME}</EM> to <EM>$ENV{REMOTE_HOST}</EM>\n<BR>\n";
+   $cnt++;
+  print "This is connection number $cnt\n";
+}
+
+

+

+
+
+ [Top] [Prev] [Next] [Bottom] +
+
+ + + + + + + + + diff --git a/iipsrv/fcgi/doc/fastcgi-prog-guide/ch4tcl.htm b/iipsrv/fcgi/doc/fastcgi-prog-guide/ch4tcl.htm new file mode 100644 index 0000000..9a5f652 --- /dev/null +++ b/iipsrv/fcgi/doc/fastcgi-prog-guide/ch4tcl.htm @@ -0,0 +1,131 @@ + + + + + FastCGI Programmer's Guide - Chapter 4, Developing FastCGI Applications in Tcl + + + + + [Top] [Prev] [Next] [Bottom] +
+
+ +
+

+ 4 Developing FastCGI
+ Applications in Tcl +

+
+ +

+ This chapter explains how to code FastCGI applications in Tcl. Prior to creating a FastCGI application, you + must have a FastCGI-savvy version of the Tcl interpreter. Open Market develops Tcl binaries for popular + platforms and makes them available with our developer's kit. +

+

+ The FastCGI-savvy binaries are extensions of standard Tcl, and are intended to replace + your existing Tcl installation. There is no need to maintain two versions of Tcl: the version that we supply + will work fine when invoked from a shell or a CGI program. There are also directions in the developer's + kit for how to make your own FastCGI-savvy Tcl, if you need a version for some platform that we don't + supply. +

+

+ In many cases, you can convert a Tcl script from CGI to FastCGI by adding a few lines of + code to an existing script. For more complex scripts, you may also need to rearrange some existing code. +

+
+
+

+ Getting Started +

+ +

+ The first line of any Tcl script typically specifies the pathname of the Tcl interpreter itself. You must + specify the pathname of a FastCGI-savvy Tcl. +

+

+ Then, you have to divide FastCGI scripts into the following two sections: +

+
+
+
    +
  • + +
  • +
  • + Initialization section, which is executed only once. +
  • +
  • + Response loop section, which gets executed every time the FastCGI script gets called. +
  • +
+ +

+ A response loop typically has the following format: +

+
+
+
+while {[FCGI_Accept] >= 0 } {
+
+# body of response loop
+
+}
+
+
+ +

+ The FCGI_Accept call returns 0 whenever a client requests the FastCGI script. Otherwise, the + FCGI_Accept call returns -1. +

+
+
+

+ Example: TinyFastCGI +

+ +

+ Here is a simple example of a FastCGI application written in Tcl: +

+
+
+
+
+#!fcgi-savvy-tcl
+
+set count 0
+
+# Response Loop
+while {[FCGI_Accept] >= 0 } {
+        incr count
+        puts -nonewline "Content-type: text/html\r\n\r\n"
+        puts "<title>FastCGI Hello! (Tcl)</title>"
+        puts "<h1>FastCGI Hello! (Tcl)</h1>"
+        puts "Request number $count running on host  <i>$env(SERVER_NAME)</i>"
+}
+
+

+

+
+
+ [Top] [Prev] [Next] [Bottom] +
+
+ + + + + + + + + diff --git a/iipsrv/fcgi/doc/fastcgi-prog-guide/cover.htm b/iipsrv/fcgi/doc/fastcgi-prog-guide/cover.htm new file mode 100644 index 0000000..78c3006 --- /dev/null +++ b/iipsrv/fcgi/doc/fastcgi-prog-guide/cover.htm @@ -0,0 +1,119 @@ + + + + + FastCGI Programmer's Guide + + + + +

+ [Top] [Prev] [Next] [Bottom] +

+
+
+ +

+ Open Market FastCGI 1.0 +

+ +

+ Open Market, Inc.
+ 245 First Street, Cambridge, MA 02142
+ T: 617-621-9500 F: 617-252-3492 +

+
+
+

+ error-file:TidyOut.log +

+

+ Programmer's Guide +

+

+ April 15, 1996 s p/n 42-10530-001 Rev. A +

+
+
+ +

+ OPEN MARKET, INC., PROVIDES THIS PUBLICATION "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR + PURPOSE. In no event shall Open Market be liable for any loss of profits, loss of business, loss of use of + data, interruption of business, or for indirect, special, incidental, or consequential damages of any kind, + even if Open Market has been advised of the possibility of such damages arising from any defect or error in + this publication. +

+

+ +

+

+ Open Market may revise this publication from time to time without notice. Some states or + jurisdictions do not allow disclaimer of express or implied warranties in certain transactions; therefore, + this statement may not apply to you. +

+

+ +

+

+ Copyright © 1996 Open Market, Inc. +

+

+ +

+

+ All rights reserved. +

+

+ +

+

+ Alpha/OSF is a trademark of Digital Equipment Corporation. +

+

+ Digital UNIX is a trademark of Digital Equipment Corporation.
+ BSD/386 is a trademark of Berkeley Software Design, Inc.
+ BSD/OS is a trademark of Berkeley Software Design, Inc. +

+

+ Great Circle is a trademark of Geodesic Systems, Inc.
+ HP-UX is a trademark of Hewlett-Packard Co., Inc.
+ IBM AIX is a trademark of International Business Machines, Inc.
+ Word is a trademark of Microsoft Corporation.
+ Netscape is a trademark of Netscape Communications Company.
+ PostScript is a trademark of Adobe Systems Inc. +

+

+ Purify is a trademark of Pure Software, Inc.
+ SecureWeb is a trademark of Terisa Systems, Inc.
+ HylaFAX is a trademark of Silicon Graphics, Inc.
+ SGI IRIX is a trademark of Silicon Graphics, Inc.
+ Solaris is a trademark of Sun Microsystems, Inc.
+ SunOS is a trademark of Sun Microsystems, Inc.
+ UNIX is a trademark of UNIX Systems Laboratories, Inc. +

+

+ +

+

+ Any other trademarks and product names used herein may be the trademarks of their + respective companies. +

+

+ [Top] [Prev] [Next] [Bottom] +

+
+
+ + + + + + + + + diff --git a/iipsrv/fcgi/doc/fastcgi-prog-guide/covera.gif b/iipsrv/fcgi/doc/fastcgi-prog-guide/covera.gif new file mode 100644 index 0000000000000000000000000000000000000000..c1012fd11043620bc35d169afeade69a835279b6 GIT binary patch literal 42128 zcmWifd0dR$`^WFOXJ4vm-!tvgBGaawY2P!YWuh{rk|dK#p@(~xYD#5VO$(+~5~d^} zOw%F?BO!z-B>P0jvQ}A{hVDAqrnW|EdccN^qfC`{_NSa zXU?2CefspNQ>WV7+gn>(o12?Yo;-Q{`0>WZ#`^mDW56S65b69zA-ryuAF# zks~D~CB?cpMU;2c<|u<{rmIs@^W)?v$M0avaVQrqIyP;NalE zz(9Y0|CN;$UtixJKYn<7doM39dwP0){rYv|#*K2h+{44;^XJcQZf+kxespnhdH?>s zlatfp;-aIYIiUrtWW-o1O7OlD?g zW=2LvdU|?VT3TvqYI1UNQc@Cw!AM9*h>MHcvSkaMPLGa`j*N_qh=`!kXklStAt50_ zK|uil0l$9z^7Hfi`SYibkI(n--@UxNzJ2>frBaucmNsnI@a4-FcX#(spFX*|x_b+bo|u`LJ%0Sy#Kh#`!-qyjMh_l5AdyJ-@835tFt~T`o}QlGojZ4QbaW;rCbYD) zZr!@2p`mf}=1nyQxK|bNTXR z6bg0e(j^1}aq;5C3l}cLO)3&6jbU(pG4LNT4df>SWdy}$A^t8;|Ukp#7;Ej5gv!HA5mLl5OSb6(Bq0el4h#}Qtj z;nj$a$v3U0M~}Iu-?Og*)uey@Dx7=;oU$zN(_qdhj!S8!y=Xb`OFCWYM zH2Zkl>Jc*M@Q zNl=?`Adhm05lfTy(UED*>h~G8p^kdd!=uGid1O`KHDQ|y(fSt? zAL719sSb4>N#dvyh;JS!c>m#AbojrKM@G0fJbZVGcE5M{bX06^ZS=;zf4%9eqC@H< z-JZ196GXR2VBGyf-*7REHQ>lYnKiYP+K?zB|Ad2|mL6XKFzdBEN)7kX-Iw&BTk4ge z(e)``>K_}d-&UaU^s+FXHKG4jKDNc>Y+;_hPG7E*V&;z*AGQpB1>d6aXGTbJF#j3$9msa5~V zO(Tcf`NkElKb$@JUN%Oa#s+$Q#Ht{>SeCIG#V!RA<;u8(lDMnYQ&4~C%-Y&F*9B_Kk~wR4syZHIYkWy&0t#Ll1+OWfvASLXxO3J(Or zogIy18!S(sc$9hYbl~yQ^eB(z>z2{y#w-VI`W~g9TGv$|6T2;+g9D;WLx5#+Tv#=% z+S|zwMBQ=yodK|X8~qI)ZaL`hp8GLtD7kv{lJCH)sv|aOiQH%eGIeG`XV;&inDe{7 z-+sKy`q7Pp3M9B4qk^C@E=IZXS>581HLj0D#W0bZ%8^h*;vCuz!(2ZLOT@sOD`4&< zc!Qj4l`)6YXp$kCsY6&VDi|>iX?%D$IUzH?(D0-ix9XfdrnWpxIDt%~1_2FHwGm+o zH2~+o%WtZ#$WS4d=S@;kE(ytT?0)k_uS7_FoUz=mS9sQcqvf+2Gh#_d=We*pxVXwF z3x*%OJlWB@bcD z!dX~%iOSNm#K{Bn3;zPjJABH}D*x2^m@1wv+2qhLRi{x-*g01kyDZTd5|!KR;}Bjl zh7GKx7j;~~%+w6-%v9$XmMT#Z&~%>(eEiQnn)W~7K4KgR5Ryr)SSx`T1dGQdOAkXh z*{`Wa7J)(ZdDUYkcnSnNqQsyozayg{S0|MSmD@GNL2p_TBC2EiRM4rAPk3^r1$`E( z8`u?O)7l$+X8G$eaoK7u#XP3&DF}zZgS^&H%PRnf2WwecBXGNBFhr(HHPSi@ zVr@CmGe57NWsV{dG{t<+NLL_UVI)DdB5InT-M$Fd?pHpcoch-7;xEDa_jxDQQirwr z$)o1(OC_5aY!!891dQ)l{$p`kXDd(XcL6Rk)!DlfC|$Y-?VCoq*q**ax7>VorO!HO zcY4$XOYQl&N7|Lj-AU@Y1`nOvFQgis#l>1xzt6wf;|qX9@`z&* z!K?3z^DswscDB$}DhKPWXpnJ8nu5Z=8(#FP~8n9j-cx(gREIcpOPc~d8%BTqZt zPH&#tvh_b3s~&ZOCX1?DPoMS^9}7XwDHUlmS3Ou)ujQgTc<=QyCh;sCN0Np4)e}=l7`(vW zSNjHh&%~eAJJ_jQo|)`tx^90EW!s1e1;#c%;~1FH-fO(igk|LoC@X0VDb=tDf#khR zwpDh$rU>9zzYg7W@^ynn4@_M)f2Ug4itz(Xng1+SkS-Vv=P#4;RN=o_YdQ1bzUYhA>YS z;!{ZOr>2Ogl@@h@WW3?g#dF?nI{XiNh9-69)9;=4Rz*dS8BTDMFRQN~emwYRQ`?f+ zmpxLs0*WtDcfhRn?V|oSues*gxy~Wv!u?N~!)Kh-)h=EAoKj>G0(&0Y>7`nmAbrK)Fp{x4p(8FGU6)R6OXVS~~z3gUTF>vfxwrliGJOP~|7*GYkyx+Xo;V zLYP^&r0q@}kp_8&+AW5g3Vn@#ZjZ}xOctU`7|F?q^?{F!li}IQM3~)MSiKyEOvHv4 zWp7UPciWLdPjym}!Ca`|5n%w-o>M5!3Gv6c4scx4*m@%3#sOkYA8eO~f0GcG?djg< zi#Ma};6SJl8X;eUWNb)IdA!52GN?-}%~gt5q2Y?7^ZFeu_vPgczH%#goOkH4`e=1- zjeY*bLUS<%t}jx&M?z&X(Fd8p(YG2nBCM8#bCV**AMU!Iidlsd*Pi!VJDs~BSI*

ERT?SZeiIp$~U@1!F2YXCqK0nt2QM~Ebv{*OC35d4bdFn zaETNR5S89Ss9$g@69UGM?Y@v^aaIienBI2c-EQJ2>Mc8`k~B8t*q*|C`~@=- zVH>3U4dj$cqOqFTII;@E`+LY@05AMIb4Zr~qbEWxwTj73CC75BDcD*mE|8b2b{{7s zVynfNFMLu2uR3y|I;A+atvZO(3|~*#-yTup&vJ{<-VwQT=b#)ehSw(A?%a$mPU)dj zuh7*1G#x;_gV1mQb6?d1C&CD%U_WF3U9F90XqZ>tN&s;eGd8{%U6Lb4SIaicI@&ZY z#>WE+d&Q_k%E~@XD4%hvMkL##~+XJ{#s?tjt@~@*w<)csX>sPr4(!vsP z1ewiMOvCeiiqDx?QyC_muaHVpEP@oSJYvR*kP;F0L7x6>k75~B@zq|`Bp+8L!%)P8 z?FiPbuTWPKdB8r%x)~ieAMEHR>y!0x(!ACdA3vc~PhoRQ1*M zylE`fJQln8QmT3btcrpY0b7Hdm3?KPJ_%b5pd*=C;k;_YIhST*SIfETEh{P;xZKlA*4BjUeK?y?ByV|#=$7ctk@eFWE6klIi(lCB3QG^i43wGVs z<@~zX$~$<8g+ehbdPQ(MDVD(0&7fkg@avsKX+ihlt+I=Ef7VaW74YQnt+K`@8U_hq zFZYMlu@pq|Q!jt&^0XBTM5#+oXwRQfvSlV=70? z&uB|eCwb)BJ9E%O4Leki9Uo2K?w9QlA7pTLpA-GJ7t;^2-5c&i*{hzD`qSVO5;W(gWo zKocrxc%fG`1z#rut;C=;17}Uc>1W_Nq~IwjXcl5u#R;q}GPf?cAZ8+Xe8rbCQ~=H+ zxB)1XV~#`INvQ9WGA!gnUy1Fmz1k%?B(yRgSC?NB4_!PlbnGcZ!9lKg$Gm^rhmP$B zJujaEjx#I*vfzK}z@%9amf@D`f2mE1S!uhpI(o2!L8z)kibZfIA^zW(lBIA&lW^b& zz6&YFuC}w7;bQO@fK?%y3WBknVug4bvaB7a{{w5n$5v5b4UJc9yekNAy^qcvz6)Gc za3i!3ND(U)T05==wqL#a?5f8PLupV{vJj<}fA*%;$?R_|q8xKfioN5;7BJW=rR-dj zYpT?1#SDzo0Dz?dYBJado%7Gn037DE>5w~Y;JQ};w?+tieYHwQ2J?hkHLOD@Vyw0h z2GSHz&Nn2MDt?UE9miVMX5lwT6 ztBVK}GQk$&eKG`E5bs-1a9ZW}tx0fSQhwf)#D>t;C&%jNDt;pYho!570N&eu}|e%Q&a-S z$5e3SvMLFTl{bb8@lJfu9M~+#hP99gPbux@b%(#rZQfXj4qzY*Sw8TH+fVmreHGm9 zDli;;cH7V>$}~o?fN|D3hQB|DzorwT#l$v>CmLmgH_B2iUHnf(8vpN|aZFL=&8A5# z1u)>_6vfvb7F>H=aL4n5MvcSu=Yv&RBA8I_mJn`rWmS&V6IDGVAyJEnkKH?x^J0su z$d_b@e<%pQz)Ka6aBV;@UQY@Sl^&OZ=b(px?(;KzP^lbL-hE%=`2AKPXd{AaEwvi{ zbK$xiWDE22NWdZHEQSvh16ZLH=PM(8tZeLu@G0eWO`eKnlo6itF}KiTpQMU8a@c03 z_F(jM!4qVI)Mk)%38wLC1@Z9wlEQu_HmC7bP)|*yC%nq?(Sb9l92zE`|0wKDvbZRQ1=14M~4@mz70W)ycv0pC-ia&o*lq ztKQ01CJ7&&nS@h8Um1);y2Fva8~yWc^p5OTsmYtI%~ed80SRBxubwc3?-ydN-eD9} zZhUoX`82rWSmC}6Lik=j)}g`o}hxI ziqFb7V1xI<9{!7|%uK1d{)}*C(nO9Jl!v^;zh{eOH$ASm+xQ3d!c0jQq-!-AWyGp~ zNi_cRn~V>$y9-kvS6`*|C{qvv-{iK>aAaxE`}k}^*~eQ6I7gcLi0bo=0KS>{Y3jtw z77Fgy@%vp=^Eg|?tU;SU2}D5cNT4oQ2ctlN)zNT+M5JlIcA^-kNix-v!$#SJDU!`= zB5Y|@KKBi{$j|?>m#^5sxcPZG3{X-y%4`VTE!XDCxi0<1Ok8=&ZH)I{? z@p(43ZpQt<$E47L_qLCgz3eVANfmALY5J+s z8~m@00nGVHOYQMTil2M0{RCbb^G+)ZC@HrQppRK-gV#*qo}XiiUp8ibz*TJws0eSS z{z3by!H_nc^597HoY;^8EAeHyS>bB z*?EVa)kD!ef{&t<@ z{Dc#-@s{-tJ)~dHf=P8hbvnTNl6aw5hXKGUsQ1*e^&BKUD&=mZl6h=0e}7V8kWL`k z5Mw=*3=gE7_N-N>_VBn-H9Nl^si-0BY^w^pJ&&u4o`;tnZ(6~YCKnlX)u(nkTb}M{ z@$4sCH00JIbw5FK6T`L_+Fu}z^uW! zrC8CLysKx-;7Az};q?nvZ$_CF+204Wh5ELWD;+Fnj7o4Q>2`>q>L-IKxVpS4 zw(S0uMu@QqA5jhp`Wr*ycssqcw}nyWAh(6YIDdnGy5ZxbH#A|f@zsEcz@r)ee7$AU zCFGRb-?Yxoq5Q9VdfEP7^UXTvPlNWGo}?VTvhQ>Z%|yv2-26f#u83?AK3D7%(Pnc_ z3uL=S-cu>Jem?G9zo|03s8-nq5=IuP1#*>xlcnwI;g;{YsGUuNQMZioj*&XsVvP({ z0!WvIs{!v%Zan;Ftw_f9ndV2^w~4IVD83e9Lu`%JHoMy0DaQJR0_wn+uZCZZ)!Gaf z48lYNQyEFI$-Nw$@ME48>5zEfWW<;yWr^2g?WL^5BqW>I^Ss6x*fBC2=FlbrF(jog zn5wq^rLv3+W2-|_qj{f=R=EZ5Xa?ZkjW6Y<$gR!ROA7CR^GS+W~o2)Bh9MKZU5Og^4F~LL_ zJ}K77*YSEXX+{XTErG$9y0eI8$e$@u6OoD*`lTg)0aUoY7Sb}6hETgQuT;i)3lCDZEC9SzvPbT=FdTs6A{jzAr@&eY}3QO zg^%FnJEs*4kw=L>q=h-ui*j$ph5<>lN(wo>dyh%{3TV2RcxBr0i>^z6WcdIeR7g7? zNu>Lj1ogmm_+Dx!iJl4~)`o58jvk+4t_g0k4KMv$U`_H*43+hS4-q+4fqYL86m)|+ zMAl4cX@B=#1-P}us@Ri&v`QPwwlGnyl=}ESMSA7Og9u^g5cZTNGJ=+5y_+>>s3ih! zVc04jv?5BJX9GwSD#3;RZnt|Bc8B}o(*ykJqg_6a7$lV)|8Olb`TBh9C$x8`=QcYb znoJr!G6A%zj?h=j8c9RvQ@XX4Ti^(T5HI!2HU+&oy6X}($Bzm2yDn9< z3bsY)*NqSXda|n1EO$@A8+?Gj)R=Y{hc;nUTJ6)gcl^t1KiBvBT^}Tp&=256IC2*8 zuvxOQP|Me13%_(zhL^_n#W?Sy%hI2ooEG(KA%2ab@CudT)VU$kHBGFn4!uK|Q#Rwz`6_1yJ~ku1^~@`zt!tAN(l+J8!}J{ED`MY+YD7#t(HM7q z1py-D71@!v+&Mw9!7>2Y!GY~suf8ux`l`hI5MpQvltwMiW1mW!%ri4eLduNPMOvW!hKsns>9os}?Qh%` znG;*@a)>X)V*%a2l|Q;#V2)AX-$tg}3W;>)9RKv+o~lk(r-jT&_esa8OBWC<;i22w4pM}%PB$N& zk))!=gAis+*k&KY;fCzD=Q?5c6=UXxHAfe*fwSR33shArv(rb8v8mcI?YetKK*f;C zgPx|s4sFC>Kk(rX05FKF@pioregULf4^B^I&$u9*(lJ%jxhUz-&VlGN#R2@e}ad z?L~O;{?{yn0~jjsgZXg7G7CUbs5_^+7aaZBs@>ACt-FSgXr?8>j|qnz%c+L6z~ z(*QPJtwr&j-#``#j-tat8rMyEixJjrWU?5QBSu*_8k5}TYEub2ns?GiFtEm|okPcCWkBQ%+dOa$pT4FtxTGo@Rh^AGl2jB{ zZ=hn28VUdtg@s|zWr4l01L{F0k!%=nOeb{w)#~LF_W0~2TT(C=Ekk%uS+sgzX?eok zoOZ>WS){uNi6F!#av`r8`26cwdk}u7Z zE@ylPfdFcu&bZsPXMgcG-iHErzizj3R(y%9Se;B2BDD0^^pEni%8}3hN$jtyIPFoOYo`XUj7!@ZrCm&tF|L9cVUK zf#CU#TxA5BhuAd0G93U1V^#d~xq$#njR)I822~?aN#h6rGSxrL$%mT8-)(Ra7W?J1 zSO-t-w7-%53KdP`2HL7RtTHyHZZUg+EyfC2R2}xeoI*`1ODP}WOF_Wt#f`1p``*+8 zt(VZr)WG?1jA!FfclMeUgdI?`1}ciXtXHFkt#m8V;h_tI*HKEKsDN?ve6~IbsmK`8 z2tiyT*JA&+HCLSDJOh2^YI*D;OIi?dnA|u`R6wfE8B+FXi%S9A3n5&ZxPjt+C6szJc#%t5sWB&mn+LdP8sr%OU^}^lPLd0^7a70} zp&Dw>0G@QnlM3uaAmHPCc-kb@$H%)Z#J3D_;R-ztfN*jM3;E-&=c?R05FepH^IwjK(2QbYfxH zx6w_%yYHzKp7n%9q!qfuP$_CC)!{G|)msDsfa0CKM~D0X)@BU2LpFAF985|>1j->5 zYM~yPtqT^J31RroO1(MdyyeQbxGFauq{&A?s@MYe8|4EaE+4I|H?)UyW9bS!MC!ox z5gP@7+XO6ifQ2Rlesox(z^V7$I8i+u8+-BS0TzyC<_N(zNKv%~r)=cn)d*Askuw!| zJ}4HU)d`D{t1)=6P=-ij*&H(fX<#_!JvOz|p1dUNnkI4$UeaN_>h*EDFoMYz^6Ow# zm%E#a&Nh{12+=;`9?^iL-e_WN$T2ho`BB?8ky$Off|uoxDzj+Q5;Bs`^`rq_vdt(O z!mpEb7#k8qD|YLEkyPBas0D&$}N(o^+P00j%H| zZn~f-O$3ItfihynL$%h%MXMRL?pzu4w5M487&6Vwh9l#vf=2UHm33@Ipc(Vg6IJ~ByIq&tF2CLsw@ zK$&Q>m4b4QBq}oidV}eo<;wgT4poS(ULEiU*V3Z@_D3J|CkNgCdcZ7*jx4i&)T@k2 zW)ztPu$2|=tF+Ikv`2r;0E1RgYy~KkX+Ei3a(MeG8$OaCR?}@iWqm6=lE%t&EYexz zI;%~U90B$?M-)kFjT3Lxq)jQcc1}e7(trdi8<8fyvH5>s1u2W()+jBwc zg~~pH&IkMk5dWjFoC+VoIrF#aCREJ;*Qq}2+yXmHq zm%G8OE8H&x1X_qta}J1mpqEKO1@REda>u_cemkj1cN~$h0wBee2MYC82~|0A1f7A} zO)>a7;r|f_XD-^M^;RYQYqR5aRVEqvsCI^U@owqGnIjKh{(1hAMgttgRW^nQ2p(Ih z9$P6Z3KgsTbes{i0b0(;Z~#Sn2aD)LI39n3dVtu%N9_^Eet$x#4#3u~)GA#qBQ>2+ zZcR}ARv7L4)U*b4-{sX&Ub=${VVMXKal*QL3n_TB?LT3(#VyY2EFx7&Jr-Gf4W`5= z^hK=#C;@=eIzmk$knIbN+^~zPb^0!LJX>wRMaYYJL(PHCSP(V_+c= zcOTSq(=pT?t~h*V_S)W1J3G)F1G{&p8n=L-dh_rb?dbOvt~PD^bSW{O&k7^KHZeT5 zaXo;nyQ@olqzh8P5Yh;NVFDgc5UDTZY_Z zSfodSF~+%`((8Gzub&?_-3TE3R=CErgb%JS%Q5gw3@2>@OkIJkY~}j@76gtH(jSpg36v?J59#wVmMx19PhuHO2#g9cA72 zbjE=QK#dQh=f@5wwHaCQ`xDMP(UsY+c1cZi!wT42gJsO5XR*7>rk z;?si`UPC~UKDlUnte5tQIh%*AM5pI zxRLvz3@NBJ3~nCvnNHTGB;AQAFG=KawSeURq-ol6Zje@dbeu!NsBtL3+V-HLXJ>pI zu`nR@THq?e`+x_H%-0fK+lok`T|agZ3##!E3K85@KROr90~ASxx+Ij}QoEH1sX&Hp ztN!~IPQ?A-8cPvKhCd^r|JIPHGlP>)1qdXV4i)v`eG`RNq)RD`AQh?sg`uLZ{;QTS z4CF4Y+&A7X+RMpiaDMlyW!y~-w&kcTva-T-bNs&KB)t88eI{(*m!F@L;{%}IT?;5@ zWUE^2-2GUeAyjw(#3ZBN!UFPBU+#zIl?04rQjxwhOmj6&p^3=bBW2GdA`X$fGlE3m2$u^l0oPgzS$WJpumJL~eqx>TGN2WPXw@g47JSeR>E zKVjp;J>CzUIP~D;`uP?tOP#V>)Em0hi_TS``x51l#Y_ARAwppsP{FXx>EJdhm&%*= z?2Dw-eO|1~e0LpKwRnXSLp0JZhp<<72Vt562qhu30V>_e{4nl|lRU7$V$gbn%~4;R zeO9BBu$U3jiBOc`ugjpQroBolP#~H`ltm_zb+f(OGSDjL}w=8P2r+fdYYmwk>Y0?W;nJFIPMg;1zhUKefylD zed{T3?NwpnyJJG3#E=2sL3K-E!jr*Uph?_0f*J?Tu8FXp)AuS{U| z?R{Ig-3%u}USoy<)jOg7l~Wt<7<>xk@+OM{fMzA8cNCAMbhtKDkn;n0rba2UToknt z-jP$5G>WsD`B@=NbEg1K?%&oDW+H2@r|VCT&Gb$~^RMSU_CD8R>2(5VCghvX4atXT zLoBU;!gGgVkxZ6oBXV;9sH(#bmvcZ~WYC**d#7*qU*N0z5zPIFO%Tgz-G{;Lg_9Eq zFA{v642&r3aqYKC8L|os8DsWo^|mz^3^UiTaqg?UIhph*J?~bsTGLcg6^_&aTdX{P5Ufvc}NrNJye; zYEaeMt!8i5&hFTIGWPT?O?<-o3Imt)=`>I#Rxz=*93*=o+KC1fzt>vf$iMKio;-KD znipzlmm+yR$1(RTw&U)-7!<91p)2NCxzUlKlVC5N*txrrdUEzkp3>r{XOdRgQF1ra z^hlj`tV^2hsap7$X-Lg~%q2!eSK;eU)*90nT&gj^n5B6uje*j-9BJ z3Pv?Brb<%Gn%Je5o!yjDhewQWM(bx~dnM#<@%)79YU*hjVDN3^+jjR{j775BUai>I zuFSUT3f;`6Z?By-W{Ie>ZE4x2b+c)3MN6K8+*GhlM*`HRGz6v!7!~`?8Vd#31w*As zYKfUyP48`mffcVZTeRuxx85wA>*C4ly!#QpbDa>ue=GF5GQc=6=#Hwvxb5BQH&TRZ z=ED`p{nzjF%%OOhWL04mHm+x7Sx^M&CeZWZ_dR=Ps;Pd5u4k}6 zOmDlvfnjKF{GjH06~rx*mw7LVS3ZhQ9{wMe%uw>xqRW&e1kVYA!(xcH)wz|A_SPGR zBfOQq>JRNu4cx;EQQJ5oG9nAY)!Al7%=tiE*Ca5Z5TExqCZ9>33q5T$Dd!B1yN7d7 z;0oq7KX=gEzjE*Nag*w>-YkEFlj}F%T6%)^SZ!?C-hhT}y_W|JOV+Kfyee|$2O!EE zB3MXGANF6BXmAw^)m&Urf;rg<1zGj}$8VkrHEDBbPP2Hx3@{CnaTSYDU}sosU_w+U^B~p8?h7h!b1(Q8dfM_RB=? z^@Ggv4{3&O_XS#`mPI{fy9pjaOb+VRX1fH!T=I%Gs8%dHQqvPsv<^?SsQ}81nLViz zB8tK^^ov^-Yiw6*wHYJZ{UuU6yA1u5k{LJ}6a1%}9!E%*S9 zPAZI$mc>>0w2Dy03T{4|H@kF2`&K~yt|^z-G#+sTU{WMwn%ySOlAYVJC(_~sgdVeT zTcGxIvZ?jGNM5W)60E<^bS=L5cKim0vf6;y#HO+&G-qDbj4#Dfv)HsIVSO{r6VDKr z>dqKp#B_F8Z@qDfm<_wM6^qP=sk~TH%wK3La_Atk6-~U9Ue??S7Wh|VW@XrO#z?eY z7K~PwlzUc6{TZYMWkGW~sD~1FtwjIjTA});aY^)n?`K35W1LIXnm6xe2iN-kylgBd#FbwarQbiLLalAH!4pXloBht z8cdeOY7LknuhT}L`d?Pvn=f9oO5u6MkyOn|f_2mtt{O?E_-$bLs7c@@*LQd+htN2^WtHd}NK;qSy!qYFcOQ zH(7gayEs=K`Ahg_?Vcxv>iGy%^3cUP{bG$S0BJ_)K|63Ai(LmR_T6>Wv}}uV_i^83 zyD9|ZXK!j|pFJ9%vi<@|YsbbY2LWWXYer(`Ng5ORDvhU&*}L}lXwK78))iQ7DiedS zmE}|Fb0wMsUYaeEG`IPsr!!-_GksfLyMFCgJfLNazp+{v&g6Vhhzyvo?Fl(25d0p9 zt-E#kQLRny^AYIn?T9P);sL{!P)zEV72?#1AK>3_1v`9hUw_d*Mi}I)y!rKbb1L0a zwFy=pX+qNfmd~~85Fw%&VnQ5c1pOK++$nE-`I5}-*rU!4r*eh|zfyRIwM5PV?`*ly>6NZaSQvdyK*I|J-+aX3mcm{A*Bv-t7iJo_}!>!cp)}KhC zBq|^7KN|nR^+HeewU69*hgJnILPE`bjq2#tR-IZ**+XZ}8Q6`7XbJ#$AgD^fjGJ)) zjL=KwXjDKZ8L?~I@}|#T+biDcIzwb>r@eY~a`K{V1O~3N$h=$vzbw)`^>JZJ<=CyT z_4R_#e;=6to@qaoxmKHs2GXdyFE+d_YBwx5u7L>kPb1ymXe-)tTURa_58Gd{y}rYP zgzBOofv!YN3em_u@6>JcXx3ex*Y*~PN?q&;aoI-Z5LWSLr<&2{?h^eZ(55J>zi)Ic z(r#hv(Qq5ERLVzSK04%Bl=a1BWpSb%SCG{mq72=U`Y%8s& z&H6Vj3qnyus*`*C^c$&SVsY$h*3CG2ncD2pN47&Go|kHKh+1H{@}y8$e_SCmTyyOf zm5(w-#SxYNWGW`Gr;ZIz6%d%jX&fZM$Z!wSBxZcEc@3a?2rwp!Uwn!;AOePDHr^35 zS{`~vHmH<7dNstV=8N$%FSQ)jn`=CB;)zdDpn#$&a-=SfPJI|M_;5cW+v8a8r{;Is zx*vZf=01sVYZ^8P0M{pbYRnq=FB+Hx4QrHn!GxYJqM;>V&EZ^}PR{%(uD5%Lm{{iR z=ng-Azus^_j2E(D8N(LQ!=&l^-$RiG?+kv1Mv5Y9JlYElA=a;p$bV0-`5$A*k?>qP z^b#>S({F8ELk%&F#{=SiluW zMX+_;P-1B~NUk~7yi*;QAwfH{b$Bc-_xMJaNk={@K|mTU@W(xUlCK9ho29Cb%Hr?K z6kaei_ba!4m#GjD#0@?lNKq?>-pb?9_gG&{KAYT4#nqVLAhvnaCUl4xR0Dw5Fb^5b z;5E$kJBC3vWB>zrt2^U#x4h7mG*cMVEd7{z2gu0huYin=qyv#(eT@UC z2op9OYO-|HgcEfQa4iO(n|t=R(^2!*%JUc0jrwkRI*VWiZ4f1Z<6=ASM=>(?TWyIZ zd7Gw{>cl0PRW-Wb@p1Z(Wh!O6EweQ9Ye+oMau6~U!s2|qL3-<7wbj2|0P`BKr$!e4 z39=bGYDX74{Wm{6R7lw{>?j>#HmUWeP1tpmmJij0xB#J^#`R>jHHKqFGh3e^`Ck+p zl?lYcZDu3llpo15A)jdd8!*rn#X65c>-t+kvvK>VOQLZ3}q$sgdU46ZQtVc_$cljeZer-<1wk*d#P|3 z5J2lD+Z|?8OcGeNTTWZ~h!0&JF|E*buYDH6^>zikNco^`-;izys6&M{_U<%biY*hU z`h6DaBp@YB!L}B%Zn{;M7<-)C8DJph_PRHH$-HlMZO>-N=+5%JWPs8O}HF$&9k94vSwEND3HW257_ zT%wE%I&`kc&WB}3;aHWi4{z}`$0QKD%dES-O1s6$JSyi!si}jQ8@=c*JEQezs7M2= z*EwW33pwNr`4irptxP*t$a2b;Ajs|YG%*^IaOg$mabs*jlUeddvynw~zSy)A&+M8t z{+Ny+NgAfBNIDihrxPmsPh2Q$U$fyENP_f4K1;{pnDNJ7UK=Fn=*7_BSOoZ0p5o$u z%Slc1b0>5v?Ec2*vaNiUgR3_<@q490WZ}> z1L1)V5iva$!?CfhgUGA?inCDjL#hI)*t)T|iEXFl9XXP= zBS-wdtnDT~nO&vEF4w!@ezmTvdO7py=k|T(DpuiEy7nzlt$1v+0xAg_>M^sL{{D)- z(~}BT=5^K{H|0>&Sn=^z{Znr>l?_jt`1mT`o+{WC@y{B2XZTuyc(8~^9*{g+Kp&O@ zR$|D43*rI{&jD$GY*(S#36skW&%5D32w;;xT)^TEt!hY6noc}#gqlqw9l`{Rk3?JZ z=}-C5N*sRMvkbojj=*1zSq@8P_h31>sp&UT1Kj*a;^=Xkrgdnx2|T={UtR}?#d zx}U;Q(j0c-gO=T1@D+-x^AN0HcT^2v(dlKu1F_DA{|d!Qbk050`{H*-J=R<*W=?Zw zIBWVL{;LERz3n-T^;PwSsM`Cg%rVlv=!|KGot-M9&pxfxk$L&^^97bK)o_ z0MJ^nnjgBurzDtO+myjJ zv*x9wgL#Lb9V-i0;%KHBRAxiENgQB;@sGmN$_>Vnrp@4ARN$vF=wUHP@0iIK5pFf! zXw7Y|E3DKC%FlX=-&N|GvSI0%&$iV0Pu$^8%PCG}!vIsPO!n5~!KW7}E|52Qafl*| zwdKMw4yhOtZ~_MYC>keEikG_pGQ`s#qCVZbMuRisd*|LsB1dyg9ZU9E?cq%exkn}0t}I6VXPBuKtQwMl}RT|&Oga(1G^MCo^jx=5<4c4z;MHxMVkooBt3)S;Wa z?yZy=o1?9||N34DOw7_Q816~y#Y+X>ZjvtX-?5Rl_UMx9b0(s#EIl7FNecM}fyNBH-y$u#&YnEAS zw5TL90C$FrD3W7=Z;%BQD4LfkQ;eE+a#Gy!`g8WiZ-p04jP33GGE!6E*7E4}qR9vm zYr-1k{|pqdbbNBE!yp2Q6aAls-}Yto)nrfjp!c>q?`>n7i*NdvE3P4ppU1DTT?L%r zt9>q7-YDJ>Wn_iI_cRrtj5N$e)9?k z7BHK2y?tH3Yi5VDCS{Ss0A@sBmwK_{T+eo5{sm<==;Vlina93504w z4b@OZK}|wON~i*&CNu#N1EQjCRsqGDUI>@MrN zd|&>6JWrm<$=rMHd4KN($k%zChRrqy^UHpRZS}j0*PPqv^OhBMGX24y?7v5?^@s&5 z+1WF&i;ib!nfAB`a>|uqZx1da{VuLphpS>8Njm!R#C|#tVTJ=e8#<*Vse3!%dMKuD3d*7$PRk<<#-a$=J}{C~{-+x#4u?_9 z)=NGh+FxLHGXiIRW#S5w>vnLwJz6SsoVC9^(iv7Qrj;g!H>wnEx6Kx+cxRt_6pNq}NK-niiV9&cLQ?4SY*|aNF-2J-Y3Cy`N}&g<%aBRpFQmGuQ^Rwj z54kZE#0pGJOw%%_(K<{`Zd|MG$l`$bo45UaUu#0$-+q60Me>2Pzi!>0^p)q=_Memf z)iJT~qKMNR|F3{y!zqg_s0-MdP-7QSazlpBOl*&_ox!}Mw*bgNm0nrmDVCug?Dlg>n^u_|Csy;S+@8P`-E~T*#6O3-#zuGx3hvL$*t(1+uJp(SCwGa1WzphWGgp`=Enb}=twkqz5F%gH1 z!Q0o5CO*jU&z4nY9>G1ta}LyI97<>oe={C`xK>v0+V@0eF503&l*j)ZYm-OVi0x}J zrr{!rAhEadINxMml80!_&p6;9pi_dKj{WuR25DJL(TS>7O-F`jZkDIU%6D|X%c-Ix z7T9|3n-t`kt&^)WcPE-M26lIi$M4>cbJN#(L`e>15Hd@yH1B7|;D>23>UvjHwDyMW zg_ge61%&I3^#xv;E>{bJNXsuOm7y^~?!M&jr_NuC_j>}%a7G=U{0w984VTfJ8z}!t zmABEAX+^WW^ljVebG;w6&tmo-AEX%@Z-03MDT_N3cikeZT#Gif(Ek#}?$5nsUXiFOYuDG9A8MAaLCef*mz4>86wEO<598?`SBX`hJJSX#Qo2=#p zit!PY@|+!1#RC0+>EecdVlst56}6a{8+sx)5hBc9mg?vEC=!EE<^9=~wxkHTz>T-t znUd{U?HOv=f}J}V{MtF+|CwJG-{>5?TebE}x%bO{6e~T`7eI_V zD})eCt)ixg*ggsPE;{69IPF^3Zyr;$hgM1C+2S3A!3#9r)~(j=0g*_aO&`rBa0qFP zZs0j4^QtIOBH(k%b=SuTtbfU;_2R=)ykA@;uU)EK;u-XGl%+wK&+rHX1D@|NZ1)`k zv+b`|{XTyHmFFmBdg+Gr_VNBCR!q^^=AlYIHJCijGwn+Ot2q_bPJ#WVt^gm0y13Z7 z7CN>pjcVVO*T%PjGY=!SZ*8$TcFu`xQE;9@nz7m7!zM7!h$!D0M*dOEwuk?hv2%ZM z)6eP0&i_s>H2>$>@2A>WXkeL~a9=&>p!LLTEX^cka#?=8YR9wjueg;(BQ!-naaE51 z)8QXNOwr01^$^uD&_0F^LBO0M&3*iawVQ^JlNcpR2(NPG@-Wu#)fI6?gMlA)<+dK( zu6h1QTrXRZ?{mMhJv@XcWHlrR2Q4493rtA8zGm$JeQlsMeg~qaa`WkoyECrd$=E|R zXKR@o=p)L&*4>HRmMlxL!che5esYJ0IjusF=HqLhGsgjx0=^Ty#T$qA*CP+*wn+@< z0_2|`K}N2?)r$+w6chtHDDdW<){0oa8k^QWBoYH-47*NSNEGC~ryuq6Y}EmuhI`~F zzKp^XRQ&q$_%3kBkK6NU1Ac5kW`$zAeB@&c=8@n1f}?MZAE3+kO{2Rid#HKv;r*H+ zVirFp1(#VIE5vvvvcc%wmZlPFKW=+4XuY|G5g{q}+VYr7-7$b(%b4L=`YRSpOkuPQ z{n;xfhgtVRP{h%}KmrSq6wD@$e#kxCU^Z5p(b~36@a|ak1=#`2`{Rz23PPe<7N0&~ zd>8#I&BNp}3or-%?A#i-xilMvVxc)cNa90@)|6*c?5^u%%%4TL2YSk)q9B)Fr;WKZHw@+% zDbXm@G2vkUJU%r&Jcv1RyWBmqnys+4RS;`cH9;AXi6G5WgI=7?uP(6-GT(y-iC&(s zEFPf4zK_>Bl~D{aSlP%)S3V(JJZ%@0vswH}>YlYozN!{PAJg7<_)7#(xS7w^92g1X z6HdOZd2)Mu{@y>&EkeZ>Z1i&w^PD32Rl*$usK!#*drQ7)Q@l$V?{%VQ;PJI_j6d6t zN4hYCv1nXsvw3y+Kw^hQUO`{w*duM%%3se`Pvn2>K3ZGnA%h6~dJCr^FUaDyeqYiv z#_G}@9=N{ev614{Be|~`z-czx`d{OPAr6XB{VCW~A>isbgXRP9Lq{wAnR7fPL4psR zk4N#NpYK`bZOVD}q_Ze!8xoT%5>dz8eFNE;#@mdS?l0?zj7ahML>Lhdo-+Zc)1V&8 z^v4yNkUUJhq^9*^LMRXLxsiL$F0a1)R{$`6I%##YnFq7p&nv(t?j=(k-7a`h2;puuwe@=&fC)`X(>E3gbI(GhiMG}-tS)g{Ks#C z&t+9N+X>Mf@e2i3(+#Kkfg|GBa|BDyow4q-8M7N7jC|@YhsA-oVF57AvK=j@5RI@QAla{CM{m{tBbeP$*_unai4)RP~R=AJc8wu=p z9qPAipFFMTH;pt}5sawjvFQ1l&$%=6Ul)4$mH+Sgj39*%e8>ewBCHV?@%j@w12C&+ z6S73e;=vpf9+lG!TH=vJ4-*?UjU_i3)n8D+t zcn~5*SaFPsdz{liYI{?y<{#seJ>X1kLE}8MC-VTyc{2jVk`nM?hwa5fCSgS)Hul&b zm~=Nni-=??XU1rHc>wtV<$8%5;gkkn2vnC)=!p=$4mSEsxlsj~N!VBg5o4HE1sT@X zNDnVDY7N9W2UC_3sOVU#*@aoFFWdVN3>!fBwAzo!Lkb~uct6VT3oQ~bG0|I=_3wP? z)XqCk=f9>m>wW&Yt^;s?Cg0e) zyHv(lkw+wtp%c&lJIW??iU?{xa|?7PzL`GPDgHW09}V}sjr(6cyTAO+Ou)qJ?eAX2dOt5zVsk`EGZLkrj8q5k z@bxnY;6P3upb1_6&RXIVwyEBzv@7hF?+$qyOoj**3L`Q70Yzi4f4o}0Wo(1qk+06P z$%Qwbh!|9{o%a=IHtO;5kcrJC^~l(aR_E_1Mf&%<m9f>oM@Hm90`S*UoPd7|q!V6Vl1TMT{v z!fk@_mvdMPp~jEIPP9DlM`)%c!d`rY_oDkKkABJ+f}qxX3;vc+?y@T;VOKI5N>2DQ z`LnP1Tf+&&^a&|7i)ZfWPAojXD*Z!7^17Njo_FA@zsq=LMv<6sDCJo8qAhX<6d&l7 znjijR{x_1`Qe<@kDn6#cQbaCkb?GCM4`IZz>lambS%erp`tE(YP%{z_GhbeGeWWK{ zV-Xv~_;L|8AKEKuMnz#G1T1<9!t>+CMQ9(d@lhVK*gGFK8Ly#oAx8Vq3rC-qBA%(D zIpP?Aacrg(I2!O_lP%XlPrjWK+r&>p-_aZqniJB2oaze7`^p05OAi1)^^2>!jo0|( ziRliXc@Ep?;bJi(SVMDTBcAIWH_td7_`ckv+G#SB-y$V3HOm&GX52FI0~<2!`@w5n zGs{pzB&Q-1Ct5n}vPpwgNu#YZ3E@22l#kmww`1?e-LEP!7RjSAJaptF{dT1=vkk9c z?~X6POr1rygl~N#qs8m7xP)yJ_SCS*1mb7vf(=-1^Kq9ruh^-?6=K7&2Hk7lR{;dh z=q>8l3ClM6EO$suJpMgu;h!nq__O*3$T#JZ-n@!!M(Rh8glBw<5X~+m;NCCVtHA}@ z;dT_sjH*o2VPp(vagzh(yMEQ7`{vD?oLatkHp25pAuQvTiw+OO#soHQYV(>K4=h#9 z=yXk|+oIq_&FJ@!RoY1c>!2B>n*ll-)ea>d;$H&Bt6N08|7yMb+%lz7(`Eb@ZZImB zZ^}v(IM-v+74J)$QFLiGHIHJUL2hwE@c{ooD92ZWDim$5pERLsmh9MKjM7XFeK0lx z5OvwA$`lF(GFCGySE!8vDZ&N-P1yDVFn=XG%pcA_e<0wYXnD6^1HHO|(q?gnM@fMT z?)hyPbhmNRfKR&#XSs!8Z6-?)rtwjx+j$!;gUqWZO-{LfxXqQIk=N5ioGLy2r&&ZG z;!`AoVez=g^`sQyo4L$jGUmtVX^ZBkTWIYgrpMW{FSBL^D?Ps{N-iPL90(Er*uJop z?nXlk5L+@=dM}+sz);zigIgmOG7gIws~!-_Hd{dE4NE;Nst{O-$aEg&mV;&vO!Enx z|IRqGQvNT$s!av`RQ0A+P1y*N$foh)j@EBGZZK9i@H5rT#(H@5m&5ryrI{ z$=1An`rJyopq?h|f85tX8qpKmCcWD3FrxT$`b4NrxmknwQtzEhT#Wg+s{3cTw**9AiBywtSqfJbvPh=Z3zsR2-ou+US&ZTGKh z^`mG`&j0ch$gn`zPSRz7dCsWCM+GBCvp$!Vzj?aq1#36<77S_E9~~$5@%Z+W!{_KV z4-R}P187##ng!Atc7IKfeW61?Ek`5Y#KL_&;JUAcu!l$IHt&5+S0jT^vlxqNHhR36 z7A&Qw>Cwr2GgW`>{SLg9D(#b3er&%NqR2xyiSHrYHu6pgNsT>MvAt&!Nn!6tzNW`W z=`s4vYgZ_#S$G>)+RPZ9wTS+e&v|wvaq~)dv%*;f9@-q$q@Q`sw$_MBCR^ zc((=1Bz$I5jG+){^%t|FH>6@<^0g<6Kb%S%xniXjdsS%|F!W=5+bJ^*dMK|+nuq%tD8_V_*CWHS#Ia0M-{MJ zLrh=hvhfo}rX0Y0!w7;iNec&B&U`?|H|8|6yVdMKDjj_nfPu5avEFJdgARvhFo${g-P}aWD&0$C5pa z@H(KE&TqtRuQij!F`Hu+rWroV>%F{<4FcqISIsZ3y82LWHMD`zrc5syb50XdMIxf^ zS=k-2Vd117$wliUXem;QDh?U$zu2h1wo1$hCDLyiMf_2E>8msEavemZI|`>;u{l#z=ttAd#G_79^+KN9I*u1^mBmZ7HwB2cCfxy54rwutq= zA>N=AH+~gag!0VVcHEr&8gfj8i{gXYBWL>SZ~g9Xu)3kQz*jcHW-ajf-m`?;|C#*J zyZ0>dE>ez`0TwNqg_h+s9zwX9$H>uR?^fQ+L`9k$yD>^wm?Zid3LN9{4bSd$n>hGjM-4fx)2r|wpS2CXv?Cl(W43fJ&0R%DJh9&3+xhlcW>T*uxZk_^5BH%SBrCE zOC8VXyU1ECGL^izjOU@tftJVN6Fb@dQmWa@Jx2;f|E%XR{4`JYCmc={IMM;*u{W0R zW~GKk9%os*WIEq%PJgj^-s-N@#-pFn#y)oa=!M&Cl0=L?qRRH;8_Jt(>Pmipc-d|i zHlw&JTyzu2*vFHeD9^eAx{Dd>Naiu(k*FuMtmx|0^iD-eo&A8q8u8{sg@$k9Q{aE4 zIo@D0bxFNxpPy*7_LwO>ji*wBm}>uq+40H;CnyWJ+j@q?G?nqulpDQqgNzyjy_(qj zoxSf-6w6=ugYegB49PmYdP!0%&O3i?*Uo=r?&qFg*_3*x;l9g8R}0UwDv|JRjmYoy zIMX00E%NvNeN;_Frji;8>VF-T#@%mub7w@oZNA#A>NKT><9}+F^QRrr%=XG21-l!c zv^eWV%jUM`!ufScC1+ujRYLMvmQS9AzxqHYr$-&IfFo11Gfs*|CCc?Tf_2ZYZrvsL zs9LzXE9<_xxeDzZ=NOFhxj<;V^v}00|b&JA$ix`tTMrd_;Aq^|r)dO6ll@ zn1JHjo3J*(tS5jd0|sDF1=-3`1Q(_>*0G*9fIDIcSK}H*#RHv=YC$AHqlRxd@fP2T z=$YK39ml?DJY4B$TarO=A4lHedHrI&zy}QvYT&@6?6AEDD&xb&(sose`u*N&HPp(m|Ag1RSxhuyPtI zC>nBVTJjjrX;sHtyK1v8zZep1x{TuX&DJ3kPiqDSIL!(#gBMm5)YMn>>H0kR(f|H4 zV=X%37O#GOtQRFHJ;OI$tKuAc*@t%ys6M5> zaaZ%+eBIgZr}wELbDfY)@01iqU{Nv%B>O|E$-TL(%6}^Y0X}NC&`ZW?QJ6Ff>oXvf z)i5Vs{~O9tyTLSHb2$*f$8Bk$Ij}-p>!mf^lsoyWHTQNTv*(e0(rO~6jtWI8e2QwZW zZ!JY1NJ*7+w=iBQM4U#+Fiq1>e9t~fGi0$`)==c;2C!}fmuCFS1S$h3H#@j5#5Hje zG_42eMpcDFXKT&8ty4JX9q>0#3~)5;ya<|dtiDA?#}ss|2$34XGy=vo^$4?zdfsTe zYhbwfi~2OA>nq2A-eWT+I$zWa@aR02YJM?JmaKCI+1X*@UB|C_6`9 za9DeeZ`gB=eTESEY*gT$lzVy=typQQ&>)iwo+MYbR=O7oP)X|YjYAV0nrfi>lqiIp z+q~Pc=Sxk{dV$Fv-gWDFVFYG(T0edXTTL5LA&~^RoPqKIi~gw`VZJUdL8Q6oc}}aX5gW5n&vI4`+!F;Yftg} zMe*yyk&DvR9J4bb+6s>R^AKXsHo@SwE=h=M6qR7|+zq9Hl|B>`-HSklhW>;kSp4;r zNjOX~l0cN*b1HJmfQi*CgpC)|HY)qG5ohiM3MlIdD>*Fi49?@vfGUb!x z3v#=Hd0&EV0`x1n`Cxm*p_57bc9Z^KjQ=_g)0#$uQF|=3(krt{&k~oc?xLD)M`Ra9 zb*H=z(9jt>G@vOoMD=7HO`%~BUB;?(-Anuf zOSiQQZU}KV9__yEnK*CCSLbjc`sH!UD7ya3ljE2G{V-KQRl13gClgL|)_-7R=lf@Rr!6|MCRdwH%N2m4HIs|$Phn2n zqg)FYfbx{ebU8z*`(xkw(iOLo*00b zZ$F8KUZ9*JxhbY?84Mr2kL7Z5{%6(pJxeE~ZZSKnOwR!5`Czkte2OPJ_15c)mCx^; zMbw8EW=&!{tPi6DFH|K_u5K9i>wg-hwx9`c z`CqaV&Xd{yyy}5;L8wH2>&cw6uxOUF!>zy*K$@t5<_A%Cy8x2bXlDPK(-$2PW=1 zDftV<*pq6QMH7;c3m}9!7jLe{kG0?@GeAr*!G(qFn_YUglN!fVzPi66X=254NV!~R z|3@;i0|rm%2nO&WPK#cv=dZ(NC!Q#u|8@bL3X{TsD0qB}?L&gu7@|UJwAqPUdT?vr zSmItbCPj_Cs|$+b3M+8bYii_KJz+2r8J}UfSc`o05ZNQD%nu>w`$%X1{E-r*3K^c8e_U{|)XRcRnlxPr>8? zY}&}y@YSytj2cXLTiy2Sz`tz?rXazn%dZ8(?b7ai_BVFttkDBjnR{{M!eVlv5E!|H zWAN~w|1LAqU@i$)_=}L=A+Sei6U%mZwt3-wCy2{LqzpK`+P`u2fPol-{&#};iX!<; zL7dWKFSTN<)#&%Sc_{e<*Z)=ihlS|Kmi<>mLH7mi^ndPSzMRcfFsKVs9+xB4YWJ3K%8$yKdoW5y2qTGi3qWREZHuTT~VGlwtGpX9Y z&0}Fwtv9MiWO+tQ-~!^GCg35M^awD!-oD`a$?Ew@qOrajACGIG>}(eqbRRX;`FJ)J z0-kY>paI-lEx8_n5oyV_Yz(Nyl?Nfr0r0p6M+Fd-@E+}V0ECfWa*-*sVFTam{~lX? z{2#CqBvb+F){6kLl7E<^y(UG)Ng7k(6EiiujYpX_>Fa+#-illb82Q?y;)?$*o1ZX}k_=B?&IPwqfRJA7FBE{lBc$GFi#oL>rfzYk z8re0wzwn@$Czqh15O(uiC6dH&UvBC3#F`7-hZ^iWtUDB^Ik73?Akr5d4HIi-2zz@D z?!XgM)>$rPkvI>E-B&g!4xyzM?UmaaR*BkIiOBAHJhXXxLk^*xcgR);pRCT?#3qgN9zDjJ zL%>u2BhP!V0PD=)DeUlefGqT{1n@Qh;WQ7iUyD#v5S6nVK4TFi7<-AgE6{{^1wzkG z?rL)`-~!0E@4%C4e5EGpm2zWCtHXD$QLJwhcPN_Du3pz^BvT_Fsby9@m=zSl5ef!; z>hydT<*Aj*TLKMUKfV@u6P_>1hRG8Ed4&)apk3`Q0tH{J*jkX!BYT+bBT-wLCdC&0 z)FGJg_9=LlcQW3#yzUzcmLNU#EpICc?l2f|+NPC7aDx2;c%)1I=*6=LJdBOFg$1=( z1_e2)YfHU?R#Y_w~lQy&WY=KqS{d{$Uw+W;Pe@$PD5wC2?HhUzPhX%jkRXBw`8 z0uIklSDFp@UD?h)Cc&4_o*oS7!&8<&eurxifhUB>mz{WP31W|~?8&yHuPLNwy>=Hw z$kJIvJG}bU4^R-ARi_6KR~-DC9g0Pm3|5mE49bp={yWbg=>e<(WVY@+#w9@~qn6*pS&=Clh;7eIgq!kMQiPvjdO#NFr|Y>TK_{#{9W7 zf=61+L!N~RQCoe6W>FjeLWKbp9dJCCL2#PII{^IWo%r&<5$-TC@H?t!7C~YGNYT&^ z3a*ZYjDz+oKMchN_Kd61(OguwWOM8xf;|ATO0tuC7dGqgWIblS>+5lGD7Re9&9!uV zronaqmsLGW6SS725HWV$b-uQwPg4>kBK;55BR3yb<@MP3pgV=zk4WlS(z3+aL1F$hZuc#?&T^*V3_!duPaKCL|a$KSvU9_r3_vdb!dy-8KT!C zWJ@uH+^Ds6GJT|*Eje%~_0wFtwb{R0y*&(6TsNA(( zx*dIU7CE)p;gk@x7UFhMcCJ2R=B*~gUc{rFv8&UzikIXpY~uo4!p1=1(+8BpbC*q5 zKiU=8kV+YsM`aHPw+C%?KQ6R>JW1#hUXL`tv2lpBSPN_xVoQWr1jWMkhxL*79bMe0 z`fNhxldvNIVNAC`vpM|C`vsX?)SbDTmOMgD?k(yR&#VqX(B0}I;fS-5yLpI%TJVe- z8J6H6Y{l0L5!6}W$$SS6uO@dTuDAl=+_i*7yW_7s2HPojZw^JRipSkAx%;hm$zSi5 zyb@t7xTx8W=k)+N3&L!BOx8kV^vCn`2+kWWrf`(ht0P=lN8CBKmU>$@z}0y|gjT?N z6alvLNWAU$dy7{=^T(C57+&&y=%<<(_yYV$ezWY6YZ8g!bwF# zp>9AGm+*)(Zf!_+??jLCh~YbtK0@%j&S=e#@wAmiG2R3+G_~?qqcx2OzyzoA$qKP8 zmI9Ey%`a#CY8ls6sVIMx_h~ZfDf+G!d3@0WCoaKYLR*$_r57d+@JNUL4ZQ||@AQvL z3<>UcT3m;oqL$BEOUnj6_$@`(1e%4_>*+ zGuZoga-R-<<4y_LMm=V5wzFHixTeI`@gT0(C{ zv&D?l@C<2_Pt;lN!zNoob49E9iQkdgy8}64ajfYxi-+I5*sH43yX@qV=Erz!@VE|H zR7tuG5gA&nS>cemo{;ciGCqBJS0Acdb1?3{>clK=JJ_>`%CF=8mG11h=yJ*FrG*cZgYKRz`*B@nIjp=|p8FUnM5Y{_#dBtRJSeZV!Yh43 zR0L(L-~{O;1p$3}-Q8&fK)@cu8WXW;Ku-)Zyj^GOxdt`38r*meZ_gtv;*k-8C-J-1 zzl6yrX2VIk_3H0{3lDkHl%M|Qsw0fU>9NZB({jr4Dm8Ae1b>8rJo|}Y&O;o~gM1dT zLk;fVgE!aV3jSAi!*_+@Vxx-`(pw?urU%_c1Y{T3DgovCsHq*-(g%)w`oPrQUGr80 z2+!ZMRvCF}aV2oYHZz0|Tr}Xpap)i!{N1NvP&3b>2T(9ZP8Y^Cq?Lz}Mt3;(#31G< z+B)5ZyRs8~+}ykt)l!Gn@qW3w5b3x3`@6P_6H^ys6KecF;tj!v0QI3*7U|?H_UlWm zqlg$s8UAOF;a4D~zxy0tYjzyQl|k6e>Zx~>ok>4f94=um3m`3g&uQ8FPp4 zGf6M^{#J9_&n>zoswnyX)Ubh(FE_8djs@?rIy9VRn(v$x|7@)DxNn1}cuR8x z&9Zyp${f|i_=C6iqK^a~WeyL7oJ#V^dh)|Fm}$t`w#6KeOiJBN*zsPM=XCw_kK@kMCa} zRvpiY618MW@7spl*zdGU%UX3l)xYhPYX2=l3&kbs0_Rf3uoHnWmLH9buooe{6}_dkoBDatvE~vMD_LH8H>KpWId#kK&vv=Y~qq zy`$Q5tieGQS8kgVSfVUXPM%M7z%b+auj@@ySjzgiV7voexXihqW)k^?jkn$Bk2XR4 zV2U7~TMrw*PPpWqecjh_s{OK%n=ORwy3$&V0KXv{V_~4bjs?u5I9V@htFL32r%+y_ zggCf$&(>a$xTi$G7_E`njPGqO@2t(hu05b?30rWqqs1<5=~%+O{l(D{j%zaCPdSP< z{%BE|LS9?;#Vq4X>rI7m$M;+2zT=y%txK_WFR0ztQXT?mTK8-T{PTO|jM)t4YM_max5;u(C3yb3R=@lI5XG}wp&U%zY$<~mecZJx#@ z@0MkSn%nO6F>zU2RyuINGJSDkq|4c%_!S<%q7tIAe_`dEa!9OfGhjp|L-cgX;*1vc z-1iq-)6TaG!n5ny=!W9mck9PsGM< zz>(%%V-}-LGup1SC(i}-?zdmP=|#)qHS&l5b6lUI`I6F93erRP%8Qz8;u<=i`8eJz z$&f5X>0VjCpdDQK2;m~t@)4R`mREI=f;}TJ(?V32NHKw4BA_jOhjKf^Hrg=66-mwI zi*U)v6`ZJwI`%D>EVewhM4&o4QSCI+Rf(t%&0OIIv+KX9R%k?wE?zm#h!2d

1N zl-x3y@Jq+6iJ6LLD>-3>t!_1a;5@R(KdB<9AY(=AM6eyG0Z#b3FP%XQEqVSe?DUO_ zWjR8eMfVAccl9gd{XNnp`upX*_)*J{9>CmUnk5e$CCPN5_DdsJUHn%3d|yw$OYoP< zzV9ehfJSFAM8)J8h|!ktY>_9oI(cUTrX)O;j%Yd#qvftYnR<{xu0Rs2K)#{9c7A~8;1!iM`fnnx?##57&dZg#o!zC0X<(C#5I(7 zlz4Cnj^>Eh*{^R=qH#V_+-`jUkz++<-Bg8{)dw{MOL0>HzObwnxW>Tf4t4EKwGr5`cIw;?3WpkBT+uxDTQV~ACp$H~jfZ2+pRbCV^RQT7VNymgVD*MaY_NTV^ zq|w497qxe{*ti_~R=@7gwsD!Up*{Gge%|KKQwPDcG{Cr&)z1IjFh58!+{j|`kY~}@ zq->Cqf8i(zq5W>6D0Ug^NxM(XSlq!KiH?39_z3xNa_((WsPm^vT(|`MqyY_(taJ3v zB85G(RX!>lakf`i{P7>X{R8Xq+=Or(4Ai6G(F2~U$?*jrfkR%UQs+bnj8%z(?Q;2) zw&o-lHDYOinv6E5sC?e?FnQLtc%BG>?D5TnQh3Eov6Ng7qlJuq*1UElnDx|W7gJ&D zqei9c0LIoQ3M_{&4Ss$*(-=TmwTUo)Y+h({@kAKH9)gyBl;$0cHn#bns9cx4q3gK& zG&><+&*o`1g{m2vx4IqI>^m!?e!*32SpTozGrxNBCt!qm6Z4!{IcWJ*RK75aDo@xU zqutt2SbofP#k)tHP7fcx_BgLwvDRdxd$i8VD<76wvG!rS4dSOg6oo~X=#*RT#)CqD z5Zj~21i{W;TX=Y0ZV`a$8FJ1C9$Kn})At8LdT(E;{lztic}*9xON?;91f;xi*9NnH zaK$^%y)r6Q*Smx+B^Xga4xKEwh`CGxrOVVzvVtS$Ce5aK19E|5!-V363M2#&h5gV?g>5TRFyu;|yqfh6Ckc)M47BH9=m#3$xs34-`-pOO& z0;~DZknv)B8}bLkAE)ynYV_Z!)%oZ6q;%MNSB8;Q|(3)sD4r{MBKH(enf)%=t+IC=y+{JGXp+1kFrAG>8|yl{u6KDBu04q;Sw5dOg-m;Zm>Q z*p=Ytw1al$$1QO^PSTSOrC{bPdR3{^?NEDMX@7hQTAK&jZUa;GDE{cY4^jk$mm*g7 zNY%8(CZ`a#3beuhCFYfLxHfBHbebByvH@YxDMXuyQ0@bZ-${`e5h@}T z_UM3snQKxPjz54%hss@q%H{splXj|2rH7RgI}!!GbUf%9P|lfIk_+Q%xF=nC_yf84 zfBP4#hcOoeuGWrqoX)>WokPW|0+=Fn3Tv@^cc=3zSz<2A_*K<8rWwhiX((WLs}5SA zKexWI%1H%gFl8*A(kk4BDO~W|KMSI{(xg&Z8G^KNMn-1-dP4#caNsIPN=sR4G6V26 zNWLKu_3c-OA4rtHB1i=hX8{wn}Cd**8?j=3Iq2!>0QGEq>1VdGafn~K-07+ zVlD~~0l^fgw6x;GX?g0cYtlw+AP!m%{I=A>7}PZC2=-?@-GkDWkB|NK-#+X=mXv&^ zj5&w-d29LespXgP6)~l3sF<9ijk z3-`yAM~D8h9Rib%yW-R#wULD6s08L36T{<9lAu@Sg=F%in9;6f5(EDwwZ;i-Ki;(9 z(1Wf>7jVFOdw+Aaz%WO2t44HZtw_qfN#-g%+O%6>IfaXkh)|k+LxnJV{}`0Zisi{Y zvMM!3Ad;K31_dOl<_lHW=!u|ZBqb9lukDdJvoN>QWp>+G>mW?tglz5Pf{s|D#J}72uDT2=v5Nw!%XL34RRqM=lLI!B>F68 zLCbSdMieO`|8#W(APkqTP(cPu@wgs|1JL4GO2-mqj20ECQebuR0QlOj>I#THN~Rg) zwT-Jk_#OiReeRdzkvWXgAs)vIk-t_lXCZz2xHWC{*r9E<}02?(Sos2*u!?A;{K~p7$Z&ZO~DHr0=QUBD@QV{8sN-LZ+h=&sHgs?!8 zK0vX|TY=#w#my4eItPTgajRvRd`N1N8_?7c9LG{72$kk6b{eeglUKbc0MmP}#dK(5 zsf@6t!~cC#aP%0F)M2yOuo+v9e4Q#(g?zu zyHg4c6+!kj^Or_V#2r*bET~zenMEb(G3!$*Z6ER$T(DXX^6m2CO&Sqv)bTF=!p^N; z=_&v$jRkeUO38v;-m$HM2g&M_T?Gk;Hr;foOz4hQZVg7ql|sQ66GA)W9cmLZ$puC( z1o%TybB}`|-4dpuQkEiB74s!5h^Ce@=Aa-R^6Qh|BpiU;o)}ddMw>$kS?INra?=z= zkOa6Nf{KgwJuC&rlTg!4bh=8``Rc+&OIaLC>iLeO<06EktA#ivgCqSPyOYY13WbQ) zo}s5h%Em}ge8+y1S2cc~JK^Ba@ zc`?xao#KCZgb5R!%);RPQOoTf7heKWbxM{R<)@K@8dNhyxoxhzfFt70l$XrP2@>e} z=*kdp05^+Dok1|UQX|6&9Is}1IEpNkT2g%JdV?!iUh!}l{^&&WE#z{hf_NvTCJ8|J z&tv!gH*w!qex}1OGvVyhB^9ONPki)>X!LhjUsI&th~snV}>I#bBDX&BX+sUdHZFtqf$qR z@!JD5=CD(jgZ0UuuP$Xj11+Xq7o!u~A+*1F?=TWz);Vd+Ooa%>41{E%j3*H5W|bx! z6x@a!T;ID{ghc9;21)bEIlxnu?yKM1Jo-Y%H8^fwo9UIYA_zlSec%1X;mO$fbQIp8 zBvvbJwfL}~GA>7HGzyR#P>~u1xm^*-3R^J)L}?#3&7f$bNoMn?1Qn|+?ha3Hu ztC+8DdzRZX!4zKRi(pLh96+2yttmY^@5Cv%BrJCvl`?dOQn5t~L$Wni>qO;ctCcQ+ zs}}v2$ty?P-SX`FkB?>&#GmG$3~Erba0OqOb;Por#l>W+rrcAd0wxfitF-9=Q}jTK zH^Ibi1<5CnMdWFFz9rf4C zv7vG!9b~XcM(CiNvNyTiC}UOdDqpV_gUHb^$8DD$%CE93JzB6$X2+8T!1W3IXr>o)|JRR}XRlz7TCLQCgHDqBRPfYUIHTQoenHe>U&% zNS@(COS!;>CE-nXclw(h>M09_@NphFcO_K$*g56|74^tjC@+KJ8nnhdb~359S_0wH3} zi}e}dCTlgyq*<5cbMnbm!1@2EtaslHZj4N|V9|yZ-K4C0m<@>%MAF*LX1R!j(#(c(D>YpkZH*B zDC2ric#fjP3aI$+Ixa-~+y5&%6Mrbz|Nr0jJv)OL24f$CF@`J|OA_~tU1BVCBx!6V zNk~FYXJ!n>l57b{L$akp>S#OPdxnHmqa&%*vDMK|spFha$NA0gFSs9%`?~LId0+3> z^BIw`MUfBK1FGNNUXbMMF&-2_ACj* z)_z9;XcV#vEeVV}Buz7UtS1G`w>Lafce(!jf|DhT^!)etKh?tpz^?ZDMQp{c$LJ%x+R2j+Zawqnz+!^`5Ma0T;=$;(t>F zyM~8TpCCu$Vl-W6dsjs-C&_ zX;+7^z1By+|I6#M&3=!{c2a6A&ah*5d?7eQiB(?P)I|2uICv6T6HmiZm+zSrmGw1= zRBfqZYx`EsW^t!9ta-hly{@Xc&>-2hy2$Yo9B5TZ;=(2%0Ef7L?EcD=Sf@cF{NqfB zgTj5_Xh4^2K%!kYP!;TsV+sH;d!RDGJB7ayBAkT@uknq%(PI1=|1?Rknqh_nwTJ!% zL6Mls7D(NGptNDLP4ffaJ;>V$zu1%&6!vJ~#^NS@9yh?kNYFESYMPwfh;I^a98+nN zYNFKoroW)~Ki%!SX<;12rQDV^zBv3F z=z_Akt9>&7f8Xh^=*-`@AAOnL(4jy%@6O!!;OJapdO?mNqO!>`yhqoE^4Zi8vvCY9 zlbfws++U7c|5tZbfLZT_?1_DMUTIyw&2OG*@8=zTX_&PZYt_2^^4C9_1ZhHm*)`Hq zYTXEr&gKGBYse~9K1N2?>R`9?RsWE@-`);D}?;Q>kF4%o% zOpSgoMSC;d-0w}G?M^aqiub$EMI%|)Hmd2JL))}J?tUIm^85g(s%>nPb5+ho%Srd* zkheNgfb>C%zeob87({`?YXLWe~=mbltY z2#kV40dlGjidiAkh)xq}*h3m$fyg~y6axqm8whOv$0pn>oKof{l)n*WgTcWIIPQd-f;aKO3> zD5EXHq%;`61xhOlv*=VONWv_=U2c-ZuvP;AGIVCQ9bySUHK4jqvstpyL9UrB^1=2_ zcvPgBHT5jR=AXnu_x-eNL&SSq`A^K?Y&u41a#G#FK}9Mc-J3w+x1OU_7PtA(3Qf`u zTXcnP@;?09y2xO4Sz^|G$n0~TiGSw0ZlP_oQ126`(4lHpb@x&n&Lz!<81c3^fLI|I z{j!%J28m&drdCzGQ{jC_>Y3$Upc%iwE(unegt?#qKZlRS#V1%)GlmFH%S z5ixNGM@w~?q;Y)3luu-MiwOXzVo#69I^Z$W+8PUybgd0K+UIwW)WTco`e9%7o_26b zi=Cbwh`HM5kwh@Nj6mI=vtDRXCSKL&r1E=HWDV0 ziK^V@nm}@%8}WPR=aBD@m_P8P!Tqy%Rnest$#em(nf0%S;om7irJ+Q8rX~n_%q)TV`U70+R2!e}Of&AaXr+^xq?*h=Tg)Q&&5d}9}@@#R|U zKlWL=hpOl_wn*{YnRbFo@%z{kz3Y6~oe>qf92bE8_xhbok<)^n(*9NN*bu{FVhnD7H-gmoe;=<}-*pw#_ZbngyekO- zFiiT{^|T2d(e_-81-q$owXlg|B1{8O(7$RirBdDMyBk1RAothzdE$dFh<;Q&*W;O~#Gf z7iX;hEqrl{l6Q4f8+cPC8Hty@^-yPjcvVG0&tdTz36DE2s4{2 zhB|WhaiilP0#k5SRZ)a1gLV6|W#>#dwwD$86Ddy9GV%2NEqJ9zgoM7Jdw4&$HQpeg zQm6f2747rK_x2cV#u+DE?VajiICl8zr9^&w_cD7>UqLF|kW9)CO^UlJ)|Y8yeZ0D9 zDl};r1X*P=a%+yId#BTP+OCVV=~qTtC9XTBTVK8i3r8);B?ZCk`~Ne&kS%U}aI8q(kfTZAkb*>pts_S3l-(0#05`&|$&tIbdP6CK zA)jbQ612k{xOPg7W++gqDDD*(qmmG2x0bCp=hKq<)Lkv-Z28y?{+2t9jIxL0u{g_2 z5kX1K>W5iMOxB2eby-f13{ljJHx6)V)Rz+lC6ArZe|w{S1~~5hqK%RH6|#VU6A=ZK z6o2IgF#1FQKL4`vl711eOezlkIO#$bS#-!XnfZp|{1<19>j||pokX7=*(M@_k;*AV z&}IO!%tXv+qRO-aGby6f0pWN8)A4!}w8+$+%Yy5zB#0SXKnvQw2VbTUYTUZJ30MY| ze}D-M*=-bh_t_JuF+VgVYEO>-`n%ng9X^#w2{5fYpPHnqbNA&3huY*1oQp4GQnLqj zyg|D~gjENr;7yt{xhpw4u2`642mm5;@T{Xxg`^6SHmC zvkFx+2~-w)^3qJ8``Ch}Ifqpz&+Ij^>Ja?z>=|Z_09OX6EXDtj?O{?Am=dmfw463% zU@H`%NHIAtLEIYGM;)}FN{{_rpuTMqh=espIOZ=#VJy*U`m-2yQnILrPc=S)i+5g?HE~t!98Z>lVQ313n`!zXfR<5QD zDx3{Atvd_m$kog_n#uxr^nG;VeeDxvMztt|#b$&6qf;Q(55TsEdn*Z{+aS>tm>$h# zP6DbGu*Gue9|2sIey;k6fDpmO^nx!^^F1$g_C9Ya4WR)kEoPtTzKlc3{ zm89p#7=pF?RaOrQoy+}b+d1E^={)h~kn6Z8wg9L%8~iZ!mz99A3gqEC1nXn*!r^$W z9{}ri)sfx0Sr?Fej}C$a#(9gdnJ}ZLm60b>ks^fbC4xY1l>k8OMXw};MuJP!VPk(e zaX@60OMXpd-9Z*5u1Co@%2BEMg{xl8YAjl#KKPwUMbgV?9oDErXXf- zy^FR8Y82T4s12D7=p#WhqejNQ-c{xSZVGT6(+#gKaajV0!G|M^5EDEX-Kty?fFut& z6tw;91}?r4vYvreYXlZBVoVI$g&{Ll;Qm)zhx8=a-eHIWJrsc7G=du8}IwlkD$ zk}Yszb2OJl)?&HY4{(b@sL!uV#_z~%sMinLcjVPDmG7m!#?=@{uKZn1Aj+}>%@F;2 zxDh4KBgA>*w&ePvysmq>G%wO@`|)|5U)mP7dO$39p)mJ@yM8#CqMQJ^`Ar65E|ar& z3JY^FY&kjzFpGdKq%cd_3pktd&=|^nea?U=FqzZ?>vZW6T!y<9jjg|h4>QtW3`t~6 zIji)W`(4AE1M78FahIx`tr&cf8C8CwN$q(y1|=9}bZ}3{a6)nipJ$+)BM`Hi{Yo6L zd9+A!$toigA~XtAhB{gOay5l$1MeiM3jN)Fkhp49Uaax^!5V#6fR*Oga(%3&wr2Fs zqtP6cOBv@ypw}FIFeDa<`SKcSR5u;rD(5g(X1)#MO=n99(wXdgVUVj3nl=g?*SOXL z@ZMNDZTgu>HcXu6vT8(F8kaV{6Rer1yLyrPxlDhk#MQcW=PToi`8(e@CaoPbY22S1 zeBJX5r&(E&XqU!!xeBP3-#h05Q zA29s{^t&teI72bZ^H0JAlAxi9gw%)hfK8A0*n4l#eQ+ymsrV z-2HO&?(ftTTh~mEwiNA{Eua1-e)iFV;R9~qK{NGT@!P$PyWXvLwV@1cysfX~8{YO} zd;sheh*h>6=MB-Rz?>d}?uTp}Awr}GlVnFUMX(V7O*(RQY_DD7tA3rsAXRd0O8Zbw z%-v39!PKWe^F8mB9p$W@c0C8PByxtmDE)SJ3a+&vj1>)`CWZU!c6Lr!Codm5!u8Xd zl>_GmFaHTwF$AIfTEkxeoBof!v~By3;Ccgka(bq6gM@4w5h~I~KQ86a251A*3vUNH zM21`*@Uc?5oun`PFQ)x4TI3|lu@zRtV~rL|a&4t@PSLM~hBI6JH5S5zq=w?Ur%bGX z4#e{eoEIqx-PJY6qylYqEdQ8&ivG`571K(>ecYk{k9e- zLH%R->=DSkC*2@~%fOEr8jRtY8h<#CaRNd}YjU!UEO57qomdXjjHD$Yrqvog=2PY$ z0CuKu@n(rxJI&nl`kTF<-UNRMNaSe4C>$HM{H1y+OF+2JHKFajGdyhN@&*~THSFoL zM!nliflY%%%zntGj%#VY&vd4XW-c-x5?D_*n7a#1bzle(0eCDk<`uJi9!NO!y`(}& z1;|citXHS*S|Kiy7}SZTud%oHes3>cVC#Xb4D z<<@h31wk|>C)UX=*V*yS9RhoNW{zgRjlj#7*3bQ`a#im|FFDL|yAb0J`y4fKt2!a5 zgX}W<{SK@Z9_zOW(mQSt=RrdGk=8c4XfF3C}>XcvsFd}Tr&Gd z@M+b#{oeqz)54mJsQ@mei$LbL2@7v`b|=n$llD=h+H=$PJzP@&A{|cuULM!4RBo_g zm2RyK6maM1YdfzT)LZ5fcu3SP*qkrlHF!;`#O0QWvYWXNIVG(Fbq>qd0zL@vw^89m zA=ZO3>DaImg1dp~Z1!tlRH~_a?}f;aK9`DXulI`C3CPc7w(U9!OEl;>g19ZWytm!k z)z!D2d?m{omAqLYJNJ|WGP&3?ct$M8Nw(4^cS1@OhceP4ktgaywAIHae=?T4esz4x z0D+H(cUjRg?P8uiaWbHqW_o2E{<>D%q-FHPCU@8+4c4gvofBjfw(#VDcTf+)6o?o+ z0f>M}BS$kI|9bIfVbB#vVi`n8l8>K)9MEfQV;o)~*Bcl`eXTUP^XFinj#3zag#}_i zgM#ogw1|^_xV?9GxjXd8RggVnUG^&3d4az$B~95k4++e>2hgybK=RTWVi6Qm&r0~;;+wsfRmzo-FQDyc7H9>tC^9Vs*;LbK<;eKZ^@VjS!`eXH^i&F}&--t2c8b)3Q(PBXOCe@aB=>TaRMw)#LRggStVSj)qf& zk(HHxfy3%8s0dNV|B&mrCvOrkUfW=jV%F-QN6p>cZi81Ucu4!B2j0 z1pXWafb2KTe`!6sowM?8^6lZd#~0LV>zt3=lyOZwF&*D~-S{B_Aa`{cJzFHQj*QPw z`8^~ zMI^~Y+`(d0$n3>Ya_GV&`%sK}?u`ej9k)i;iT5(Tf5@Q!dhD-%cTZ$5jN$}6U6Ycn zmByqxl_apwz>ddf(clB?z_IVMtDaJgzY_G9HR^}}T8PGm@+;7k>>e4~+)zxi>jP1P zst!YG1`h5&dJHytQzptZAK)z;(|OTkwOr#RbS<;BUQXSU_cy0@2hTK-LUA8$MR`4s z4L*@x=B_zv{@1dgk#RQf%P4zDR;b5M+L>4r;;XQ>)2-Nfe$;7*;H4j*D=0V>?)~hs zEjicK%V0A2y@-9_x)d9-zx4*x;Bhex%Y)nbj2Z&fb(J@dHxHG8&g(j9LT7TP&F^D$fwBcGnJZRI*iND}}n_S=I|`#GKAd>UO;YMdp)kKN<3D zJES5%8^tWj_Vt5{)nQw$F!r(}nU8LacxOxTFk0OL95p}FePMiNwoGlwcH(vE#LWsV zrzg?32Cm!hIInj7YR1>SzdpZhl_;7OTVEc)bf>rBwn-w)+??Ak+B$wr`BYy1xkU5i z?GxjTC(@RC7BNvNu@>4oVfcb-lI@LIlB1;2V8x<2dS=wIhf}B< zdEFvWOnP(88oL)U_Y2ziz&m`K^LzbfT-uKFR0B7^TUsH>eY00XlGcftitQ{WIuuJu z?3ejz*Ll}(Ex1xc4bxF}euM^W`KA@p_{(qNVEg6-%^glvvz5USU?Q6AJZDZuVHMjg zYO(f!c&l@rc|QN3yjTMq2%NH%e(G2t1vNBWe;(+p00jDc6UL4TmFdmF z<5H|&&+rXJSm8!NzTQ^aFm@kFWm~km*lbPATt20uCrRAHVRGXjhW&7698klFyrOfx zzHt3izIr>q@ExPjt#o&{li@<)@LsJmFA#={sn@(7TOg@!E_0RiAli-pzmjINcjNis zy_fTi&V&}K#}YLjWwFaO2CeU^6s;P|!XzD+##6jjXC~tGYAO2E8P#S>3 z2~heCTIE6XhyEq;hBc3Qh4*~au@~%xcpIF2M?~!5v(~@YKkje4l_}SG75PAy+2*#n z_u-LaB`-fD6_xrgs)rUtQa&3W0mDi0*@I?<*h%;Jy9V* z>pPsj$)_u;Hpm(;%wveZO$YYCP!%xECfKeQygBMzJY zR;H1ijuzaga0r?9HfB~ExlSqyU-Jju*dQ_4pLnDbj8k^H4AJQ;HrE4MH1F{Wu}kVD zcSF4yUBHPj60|p^;{EsxfV-8OzPWmT5mk28@k`@M88;wa|1Bu+bZ;RSM*_6rzxq1@ zPMi!|8BDm6b&X?8BZ(p_p3>3IoTaaZ&qxOgeeatFbe&i~c<^eg_4~q>ARR(&ip0;% ze1Z^OF^@J=h;hyeiKn7@QxeJ6=AP;Ooo)of83b#e36@5biL_iVsoJ!X#~swPGKc$1 zEz_FE6P>HsigB(^>)Uo1RMD%p7n}BUJ~+sly=uB9TrTJB`QLM0YDX2`+anbEZ~gSy zhX$j90HjzQ(K34)j;535@cy(cl3*F-dGuSkih`~}TSE$6fUwQCp0!<9cY~pt~_};$k`D;`DSf>F9X}vw22wyjs0; zUz*^L)+4T}d@-}pR2jVU>dJiG^5A;@)!(Wr-9<(=v2QDJO-r)!qvIz5=7XZn(CdAe zlHw^q*}j>l!z~PI6??odN|Q{bTqsB|=hQqu)V*WC#?3JOBNim(aWRb9A)Ko{fdD`Q z$y8gL6UU-6DE0aS(;VyIIa!P-4Y#Yu)}?1x(8NJG+H?7`b6r61@^#yW#}XsDwv%zJ6G8l*U*-*vLv7H9h6m1ZR zFCbKhXb_}Ih*%{dDEh~IzT8GEm9fMh1U<>>uv_q5 zmNSrlm8kcp!%NYID)%eF6|-oT63P+bkjVOvkN2}Lbcm8f*#5!USSuqQaYY%q(&Tza z#@=Z>{qbaaK(9Ex_V7rbpcL)ya7i@{Z9Q%Xxi+46o4TRi{B*+Ta~XMJ;YNOo?wxMG z!>{-AUZ4{G^>Xrzn1V&ykIO3(Z z&dKlC`tFrK%`AAVUvaWY$A5qG@J^}d3N9f{ocqgv|GQn`BN+YczU!>#&7)+FCA(Lc z9SF=7MrIG1yb9sAa`pbcCmweCjj}(K4ynVyk{_TVyc<^jT9Y?yBLEE)(7c>X=RsCd za`Xkrauzd8`?JtStpvbihr}$O5ErIuC(UA0IJy!3R0-!k)l7wLYRp27cU*qA1Zzo~ z|Gs|teav}h=Qj^Le2cU4^#Z|1C0?L0M^}k&wuvppp7=Dd@F{cn%9!Lc_Pu2lW*O2r zX>(~gSp<;mDth*=*k4>Rv;(OYl^&&&3=I$s6KzlSJENdjn$fj?@5mgIzYXQE6=h+sKd0t!q11hKic}rbgND})t>zO9eQRJ zoi%=6uLIOFp8cn9|I1lbN(S&FD*aWaPELTz6_GYYd#l7WjSLzhmT zdp-xHaFiw-y~a7smIA%@MASw=lSzY!LO>ZuP?te&fv+h%O?#Rq4K$Qhf^(wXEE;45 z7)|s-PkYG>KI9&YcTQ{T0d-Qy=oblScT*)R6mz^wJ9!p;Qxb$! z&Ze;*6{=eWc*k7&x~w?$X0Jx2_kfb7r81|fbW3|Emyi{sX}J2PWL+(g}bS-m&$vX@t{K`|Ba>L$In?|o*yL3X>wJKM}3kn8agLe#z_Q15h&^&9}YD`fft9arjaC?-Y@AqfA4WXX^Oq^YcXv o+s~1`c@CGtp%^wp5!Ft+wVY8JfCdx5DofTiAjQ^{1^}D?AAAQlcK`qY literal 0 HcmV?d00001 diff --git a/iipsrv/fcgi/doc/fastcgi-whitepaper/fastcgi.htm b/iipsrv/fcgi/doc/fastcgi-whitepaper/fastcgi.htm new file mode 100644 index 0000000..13b419b --- /dev/null +++ b/iipsrv/fcgi/doc/fastcgi-whitepaper/fastcgi.htm @@ -0,0 +1,833 @@ + + + + FastCGI + + + + + + + + + +

+ Open Market, Inc. +

+

+

+
+ Technical White Paper
+
+

+ FastCGI:
+ A High-Performance Web Server Interface +

+

+ April 1996 +

+
+ +

+ 1. Introduction +

+

+ The surge in the use of the Web by business has created a tremendous need for server extension applications + that create dynamic content. These are the applications that will allow businesses to deliver products, + services, and messages whose shape and content are in part determined by the interaction with, and knowledge + of, the customers to which they are delivered. +

+

+ This important movement away from static Web content is pushing the limits and exposing the weaknesses of the + environment in which these applications are currently bound: CGI (Common Gateway Interface). Most importantly + it does not offer the performance these applications require. A new communication infrastructure is needed to + connect Web servers with these new applications. This is what led Open Market to develop FastCGI. +

+

+ FastCGI is a fast, open, and secure Web server interface that solves the performance problems inherent in CGI, + without introducing the overhead and complexity of proprietary APIs (Application Programming Interfaces). +

+

+ This paper assumes that the reader has basic familiarity with Web technology and developing Web applications. +

+

+ Common Gateway Interface +

+

+ The de facto standard interface for Web server applications is CGI, which was first implemented in the NCSA + server. CGI has many benefits: +

+
    +
  • + Simplicity. It is easy to understand. +
  • +
  • + Language independence. CGI applications can be written in nearly any language. +
  • +
  • + Process isolation. Since applications run in separate processes, buggy applications cannot crash the + Web server or access the server's private internal state. +
  • +
  • + Open standard. Some form of CGI has been implemented on every Web server. +
  • +
  • + Architecture independence. CGI is not tied to any particular server architecture (single threaded, + multi-threaded, etc.). +
  • +
+

+ CGI also has some significant drawbacks. The leading problem is performance: Since a new process is created + for each request and thrown away when the request is done, efficiency is poor. +

+

+ CGI also has limited functionality: It only supports a simple "responder" role, where the + application generates the response that is returned to the client. CGI programs can't link into other + stages of Web server request processing, such as authorization and logging. +

+

+ Server APIs +

+

+ In response to the performance problems for CGI, several vendors have developed APIs for their servers. The + two most notable are NSAPI from Netscape and ISAPI from Microsoft. The freely available Apache server also has + an API. +

+

+ Applications linked into the server API may be significantly faster than CGI programs. The CGI + startup/initialization problem is improved, because the application runs in the server process and is + persistent across requests. Web server APIs also offer more functionality than CGI: you can write extensions + that perform access control, get access to the server's log file, and link in to other stages in the + server's request processing. +

+

+ However, APIs sacrifice all of CGI's benefits. Vendor APIs have the following problems: +

+
    +
  • + Complexity. Vendor APIs introduce a steep learning curve, with increased implementation and + maintenance costs. +
  • +
  • + Language dependence. Applications have to be written in a language supported by the vendor API + (usually C/C++). Perl, the most popular language for CGI programs, can't be used with any existing + vendor API. +
  • +
  • + No process isolation. Since the applications run in the server's address space, buggy + applications can corrupt the core server (or each other). A malicious or buggy application can compromise + server security, and bugs in the core server can corrupt applications. +
  • +
  • + Proprietary. Coding your application to a particular API locks you into a particular vendor's + server. +
  • +
  • + Tie-in to server architecture. API applications have to share the same architecture as the server: + If the Web server is multi-threaded, the application has to be thread-safe. If the Web server has + single-threaded processes, multi-threaded applications don't gain any performance advantage. Also, when + the vendor changes the server's architecture, the API will usually have to change, and applications + will have to be adapted or rewritten. +
  • +
+

+ FastCGI +

+

+ The FastCGI interface combines the best aspects of CGI and vendor APIs. Like CGI, FastCGI applications run in + separate, isolated processes. FastCGI's advantages include: +

+
    +
  • + Performance. FastCGI processes are persistent-they are reused to handle multiple requests. This + solves the CGI performance problem of creating new processes for each request. +
  • +
  • + Simplicity, with easy migration from CGI. The FastCGI application library (described on page 9) + simplifies the migration of existing CGI applications. Applications built with the application library can + also run as CGI programs, for backward compatibility with old Web servers. +
  • +
  • + Language independence. Like CGI, FastCGI applications can be written in any language, not just + languages supported by the vendor API. +
  • +
  • + Process isolation. A buggy FastCGI application cannot crash or corrupt the core server or other + applications. A malicious FastCGI application cannot steal any secrets (such as session keys for + encryption) from the Web server. +
  • +
  • + Non-proprietary. FastCGI is supported in all of Open Market's server products, and support is + under development for other Web servers, including the freely available Apache and NCSA servers, as well as + commercial servers from Microsoft and Netscape. +
  • +
  • + Architecture independence. The FastCGI interface is not tied to a particular server architecture. + Any Web server can implement the FastCGI interface. Also, FastCGI does not impose any architecture on the + application: applications can be single or multi-threaded, regardless of the threading architecture of the + Web server. +
  • +
  • + Support for distributed computing. FastCGI provides the ability to run applications remotely, which + is useful for distributing load and managing external Web sites. +
  • +
+

+ The following sections describe the FastCGI interface, protocol, application library, and support in Open + Market's WebServer products. +

+

+ 2. FastCGI Interface +

+

+ The functionality provided by the FastCGI interface is very similar to that provided by CGI. To best + understand the FastCGI protocol, we review the CGI interface here. Basic CGI request processing proceeds as + follows: +

+
    +
  1. + For each request, the server creates a new process and the process initializes itself. +
  2. +
  3. + The Web server passes the request information (such as remote host, username, HTTP headers, etc.) to the + CGI program in environment variables. +
  4. +
  5. + The Web server sends any client input (such as user-entered field values from an HTML form) to the CGI + program's standard input. +
  6. +
  7. + The CGI program writes any output to be returned to the client on standard output. Error information + written to standard error is logged by the Web server. +
  8. +
  9. + When the CGI process exits, the request is complete. +
  10. +
+

+ FastCGI is conceptually very similar to CGI, with two major differences: +

+
    +
  • + FastCGI processes are persistent: after finishing a request, they wait for a new request instead of + exiting. +
  • +
  • + Instead of using operating system environment variables and pipes, the FastCGI protocol multiplexes the + environment information, standard input, output and error over a single full-duplex connection. This allows + FastCGI programs to run on remote machines, using TCP connections between the Web server and the FastCGI + application. +
  • +
+

+ Request processing in a single-threaded FastCGI application proceeds as follows: +

+
    +
  1. + The Web server creates FastCGI application processes to handle requests. The processes may be created at + startup, or created on demand. +
  2. +
  3. + The FastCGI program initializes itself, and waits for a new connection from the Web server. +
  4. +
  5. + When a client request comes in, the Web server opens a connection to the FastCGI process. The server sends + the CGI environment variable information and standard input over the connection. +
  6. +
  7. + The FastCGI process sends the standard output and error information back to the server over the same + connection. +
  8. +
  9. + When the FastCGI process closes the connection, the request is complete. The FastCGI process then waits for + another connection from the Web server. +
  10. +
+

+ FastCGI applications can run locally (on the same machine as the Web server) or remotely. For local + applications, the server uses a full-duplex pipe to connect to the FastCGI application process. For remote + applications, the server uses a TCP connection. +

+

+ FastCGI applications can be single-threaded or multi-threaded. For single threaded applications, the Web + server maintains a pool of processes (if the application is running locally) to handle client requests. The + size of the pool is user configurable. Multi-threaded FastCGI applications may accept multiple connections + from the Web server and handle them simultaneously in a single process. (For example, Java's built-in + multi-threading, garbage collection, synchronization primitives, and platform independence make it a natural + implementation language for multi-threaded FastCGI applications.) +

+

+ Remote FastCGI +

+

+ FastCGI's ability to run applications remotely (over a TCP connection) provides some major benefits. These + benefits are described in this section, along with some of the security issues that affect remote FastCGI + applications. +

+

+ FastCGI with Firewalls +

+

+ Applications that run on organizational (external) Web servers and depend on internal databases can be a + challenge to administer. Figure 1 shows a typical organization, with an external Web server, a firewall + restricting access to the internal network, and internal databases and applications. +

+

+

+
+

+ With CGI and vendor APIs, the application has to run on the Web server machine. This means the server + administrator has to replicate the necessary database information onto the system hosting the Web server + (which may be difficult to do in an automated way without compromising firewall security). Or, the + administrator may build a "bridge" that allows access through the Web server to internal databases + and applications (which is effectively re-inventing remote FastCGI). +

+

+ With remote FastCGI, the applications can run on the internal network, simplifying the administrator's + job. When used with appropriate firewall configuration and auditing, this approach provides a secure, + high-performance, scalable way to bring internal applications and data to the external network. +

+

+ Load Distribution +

+

+ For resource-intensive CGI and API applications, the Web server machine quickly becomes the bottleneck for + overall throughput. The usual way to solve this performance problem is to buy a bigger, faster Web server + machine, or to partition the Web site across several Web servers. +

+

+ With remote FastCGI, the resource-intensive applications can be moved off the Web server machine, giving the + server administrator additional flexibility in configuring the Web server. The administrator can configure + FastCGI applications "behind the scenes" without having to change any content links or the external + view of the Web site. The administrator can use several smaller, inexpensive server machines for applications, + and can tailor each machine to the application it is hosting. +

+

+ Security Issues with Remote FastCGI +

+

+ The two security issues with remote FastCGI connections are authentication and privacy. FastCGI applications + should only accept connections from Web servers that they trust (the application library includes support for + IP address validation). Future versions of the protocol will include support for applications authenticating + Web servers, as well as support for running remote connections over secure transport protocols such as SSL or + PCT. +

+

+ The FastCGI Protocol +

+

+ This section offers a brief introduction to the protocol used on the connection between the Web server and + FastCGI application. Most application developers will use the FastCGI application library and won't have + to worry about the protocol details. However, specialized applications are free to implement the FastCGI + protocol directly. +

+

+ FastCGI uses a simple packet record format on the connection between the application and the Web server. The + same record format is used in both directions and is outlined in Figure 2. +

+

+

+
+ error-file:TidyOut.logFigure 2 +
+

+ The protocol version field specifies the version of the FastCGI protocol that is in use. The type field + specifies the type of the record (described in the following section). The request ID identifies this record + to a particular request, allowing multiple requests to be multiplexed over a single connection. The data + length field specifies the number of data bytes that follow. +

+

+ The different FastCGI packet types are: +

+ + + + + + + + + + + + + + + + + + + + + + + + + +
+ FCGI_PARAMS + + Used for sending name/value pairs (CGI environment variables) from the Web server to the application. +
+ FCGI_STDIN + + Used for sending the standard input from the Web server to the application. +
+ FCGI_DATA + + Used for sending filter data to the application (for more information, see the filter role described on + page 7.) +
+ FCGI_STDOUT + + Used to send standard output from the application to the Web server. +
+ FCGI_STDERR + + Used to send standard error information from the application to the Web server. +
+ FCGI_END_REQUEST + + Ends the request (can be sent by either the server or the application). +
+

+

+

+ For complete protocol details, see the FastCGI Protocol Specification, available from the Web site + listed at the end of this paper. +

+

+ 3. Application Roles +

+

+ A major problem with CGI is its limited functionality: CGI programs can only provide simple responses to + requests. FastCGI provides expanded functionality with support for three different application + "roles": +

+
    +
  • + Responder. This is the basic FastCGI role, and corresponds to the simple functionality offered by + CGI today. +
  • +
  • + Filter. The FastCGI application filters the requested Web server file before sending it to the + client. +
  • +
  • + Authorizer. The FastCGI program performs an access control decision for the request (such as + performing a username/password database lookup). +
  • +
+

+ Other roles will be defined in the future. For instance, a "logger" role would be useful, where the + FastCGI program would receive the server's log entries for real-time processing and analysis. +

+

+ The roles are described in more detail in the following sections. +

+

+ Responder Role +

+

+ FastCGI's Responder role is identical to the functionality provided by CGI today. When a request comes + into the server, the FastCGI program generates the response that's returned to the client (typically an + HTML page). +

+

+ Filter Role +

+

+ The Filter role allows a FastCGI application to process a requested file before it is returned to the client. +

+

+ Let's assume that the Web server is configured so that all files with the .sgml + extension are processed by a SGML-to-HTML FastCGI filter application, and the user accesses the following URL: +

+

+ /document.sgml +

+

+ After the Web server makes an access control decision and maps this URL to a content file, it invokes the + FastCGI filter application with this file available as input. The FastCGI program's HTML output is sent + back to the client, just as in the responder role. The process is outlined in Figure 3. +

+

+

+
+ error-file:TidyOut.logFigure 3 +
+

+ Filter applications can significantly improve performance by caching filter results (the server provides the + modification time in the request information so that applications can flush the cache when the server file has + been modified). +

+

+ The Filter role is useful for: +

+
    +
  • + On-the-fly format conversions +
  • +
  • + Dynamic documents (such as documents with embedded SQL queries, or dynamic advertisement insertion) +
  • +
  • + Applying a standard template: headers, footers, and backgrounds +
  • +
+

+ Authorizer Role +

+

+ The Authorizer role allows a FastCGI application to make an access control decision for a request. The FastCGI + application is invoked with all of the request information, just as in the Responder role. If the authorizer + application generates a "200 OK" HTTP result, the Web server assumes that access is allowed and + proceeds with the request. (The Web server may process other access checks, including other FastCGI + authorizers, before access is ultimately allowed.) If the application generates any other response, that + response is returned to the client and the request is ended. The response can be any valid HTTP response, + including "Access Denied" or "Redirect". +

+

+ The Authorizer role is useful for: +

+
    +
  • + Access control based on username and password, where the user information is looked up in an external + database. +
  • +
  • + Complex access policies, such as time-of-day based access. +
  • +
  • + Smart-card challenge/response authentication. +
  • +
  • + Dynamic redirects, where the user is sent to different pages based on the request profile. +
  • +
+

+ 4. FastCGI Application Library +

+

+ Open Market has developed a FastCGI application library that implements the FastCGI protocol (hiding the + protocol details from the developer). This library makes implementing FastCGI programs as easy as writing CGI + applications. +

+

+ The application library provides a replacement for the C language standard I/O (stdio) routines, such as printf() and gets(). The library converts references to standard input, + standard output, and standard error to the FastCGI protocol. References to other files "fall + through" to the underlying operating system standard I/O routines. +

+

+ This approach has several benefits: +

+
    +
  • + Developers don't have to learn a new API to develop FastCGI applications. +
  • +
  • + Existing CGI programs can be migrated with minimal source changes (CGI migration is described in more + detail in the following section). +
  • +
  • + FastCGI interpreters for Perl, Tcl, and other interpreted languages can be built without modifying the + interpreter source code. +
  • +
+

+ Here's a simple FastCGI application: +

+
+
+
+    #include <fcgi_stdio.h>
+
+    void main(void)
+    {
+        int count = 0;
+        while(FCGI_Accept() >= 0) {
+            printf("Content-type: text/html\r\n");
+            printf("\r\n");
+            printf("Hello world!<br>\r\n");
+            printf("Request number %d.", count++);
+        }
+        exit(0);
+    }
+
+

+ This application returns a "Hello world" HTML response to the client. It also keeps a counter of the + number of times it has been accessed, displaying the value of the counter at each request. +

+

+ The fcgi_stdio.h header file provides the FastCGI replacement routines for the C standard I/O + library. The FCGI_Accept() routine accepts a new request from the Web server. +

+

+ Migrating Existing CGI Programs +

+

+ The application library was designed to make migration of existing CGI programs as simple as possible. Many + applications can be converted by adding a loop around the main request processing code and recompiling with + the FastCGI application library. FastCGI applications have the following structure, with an initialization + section and a request processing loop: +

+

+ Initialize application;
+
while(FCGI_Accept() >= 0) {
+ Process request;
+ } +

+

+ To ease migration to FastCGI, executables built with the application library can run as either CGI or FastCGI + programs, depending on how they are invoked. The library detects the execution environment and automatically + selects FastCGI or regular I/O routines, as appropriate. +

+

+ After migration, developers can clean up their FastCGI applications for best performance: +

+
    +
  • + Fix any resource leaks. Many CGI programs do not attempt to manage memory or close files, because they + assume the world is going to be cleaned up when they exit. (If you don't want to clean up your program, + you can just have your process assume that it is leaking memory and exit after processing some fixed number + of requests.) Purify from Pure Software is one of a number of excellent tools for finding leaks and other + memory use problems. +
  • +
  • + Fix any problems with retained application state. The application must ensure that any state that it + creates in processing one request has no unintended effects on later requests. +
  • +
  • + Collapse functionality. A common practice with CGI applications is to implement many small programs, with + one function per program. CGI encourages this, because smaller programs load faster. With FastCGI, it's + better to have related functionality in a single executable, so there are fewer processes to manage and + applications can take advantage of sharing cached information across functions. +
  • +
+

+ Applications written in Perl, Tcl, and other scripting languages can be migrated by using a language + interpreter built with the application library. FastCGI-integrated Tcl and Perl interpreters for popular Unix + platforms are available from Open Market. The interpreters are backward-compatible: They can run standard Tcl + and Perl applications. +

+

+ 5. FastCGI in the Open Market WebServer +

+

+ This section describes the FastCGI support in the following Open Market server products: +

+
    +
  • + Open Market WebServer V2.0 +
  • +
  • + Open Market Secure WebServer V2.0 +
  • +
  • + Open Market Secure WebServer (Global) V2.0 +
  • +
+

+ For more information about FastCGI support, see the Open Market WebServer Installation and Configuration + Guide. +

+

+ Server Configuration +

+

+ FastCGI applications are configured with the server's configuration file. Configuration has two parts. +

+

+ First, the server administrator defines an application class. For local applications, the application + class specifies the details of running the FastCGI application, such as: +

+
    +
  • + The pathname of the application executable. +
  • +
  • + Any arguments and environment variables to pass to the process at startup. +
  • +
  • + The number of processes to run. +
  • +
+

+ For remote applications, the class configuration information includes the host and TCP port to connect to. The + Web server assumes that the FastCGI application has been started on the remote host. If a request comes in and + the server can't connect to the FastCGI TCP port, the server logs an error and returns an error page to + the client. +

+

+ The second configuration step is mapping the application class to a role: +

+
    +
  • + For responder roles, the administrator configures some part of the URL space to be handled by the FastCGI + application. For example, all URLs beginning with /rollcall/ might be handled by + the employee database application. +
  • +
  • + For filter roles, the administrator configures a file extension to be handled by a filter application. For + example, all files with the .sql extension could be handled by a SQL query lookup + filter. +
  • +
  • + For authorizer roles, the administrator configures an authorizer application in the same manner as other + access methods (hostname, username/password, etc.) A request must pass all access control checks + (possibly including multiple FastCGI authorizers) before access is allowed. +
  • +
+

+ Basic FastCGI +

+

+ To simplify migration for existing CGI programs, the WebServer provides a simple way to install new FastCGI + programs without having to reconfigure the server. However, this approach doesn't offer all of the + performance benefits of FastCGI application classes. +

+

+ The WebServer treats any file with the extension .fcg as a FastCGI application. When a + request corresponds to such a file, the WebServer creates a new FastCGI process to handle the request, and + shuts down the process when the request is complete (just as in CGI). In this mode of operation performance is + comparable to CGI. Future versions of the WebServer will improve performance by automatically caching + processes and re-using them for subsequent requests. +

+

+ Session Affinity +

+

+ FastCGI programs can improve performance by caching information in the application process. For applications + that require frequent but expensive operations such as validating a username/password in an external database + for each request, this technique can significantly improve performance. +

+

+ To improve the effectiveness of this technique, the WebServer implements session affinity. When session + affinity is enabled, the WebServer arranges for all requests in a user session to be handled by the same + FastCGI application process. What constitutes a "session" is configurable. The default configuration + uses the WebServer's built-in session tracking facility to identify user sessions. However, the server + administrator can use any part of the request information for the session affinity mapping: the URL path, the + client's hostname, the username, etc. + +

+

+ 6. FastCGI Performance Analysis +

+

+ How fast is FastCGI? The answer depends on the application. This section contains some real FastCGI + performance measurements, as well as guidelines for estimating the FastCGI speedup. +

+

+ FastCGI vs CGI +

+

+ We measured the relative performance of CGI, FastCGI, and static files on the Open Market WebServer, using a + simple application that generates a fixed number of output bytes. The following table shows the measured + request processing time for different request types on a typical platform. The times are measured from the + client perspective and include client, server, and application processing time. +

+ + + + + + + + + + + + + +
+
+ Static file +
+
+
+ 21ms + 0.19ms per Kbyte +
+
+
+ FastCGI +
+
+
+ 22ms + 0.28ms per Kbyte +
+
+
+ CGI +
+
+
+ 59ms + 0.37ms per Kbyte +
+
+

+ FastCGI performance is comparable to serving static files, and significantly better than CGI (clearly showing + the high overhead for process creation). Real applications have an additional time component: process + initialization, which should be added to overall request processing time. +

+

+ Let's use this data to estimate the speedup from migrating a typical database CGI application to FastCGI. + Assume the application takes 50ms to initialize the database connection and generates 5K of output data. + Request performance can be computed as follows: +

+ + + + + + + + + +
+ CGI + + 59ms + 50ms + (0.37ms)(5) = 111ms +
+ FastCGI + + 22ms + (0.28ms)(5) = 23ms +
+

+ In this example, FastCGI has a 5x performance advantage over CGI, mostly due to savings from not having to + create and initialize new processes for each request. +

+

+ 7. Conclusions +

+

+ Today's Web business applications need a platform that's fast, open, maintainable, straightforward, + stable, and secure. FastCGI's design meets these requirements, and provides for a logical extension from + proven and widely deployed CGI technology. This allows developers to take advantage of FastCGI's benefits + without losing their existing investment in CGI applications. + + +

+

+ 8. For More Information +

+

+ For more information about Open Market and our products, visit our Web site at:http://www.openmarket.com/ +

+

+ For more information about the FastCGI protocol and the developer's kit, and the latest information about + FastCGI standardization and support in other Web servers, visit the FastCGI project page at:http://www.openmarket.com/fastcgi/ +

+ + + diff --git a/iipsrv/fcgi/doc/fastcgi-whitepaper/img00001.gif b/iipsrv/fcgi/doc/fastcgi-whitepaper/img00001.gif new file mode 100644 index 0000000000000000000000000000000000000000..f69a978cdd59febecf300cf1d9f6dc4929aa8eb4 GIT binary patch literal 4128 zcmX9=c{o)28~+NSQkH8EhYT^6Tahgs*++=V5^|IX*|IOWr_i+|B21BvB|FKM#5gG? zq;4BANm4YVMIy&Q0Pv83-*C<#9|35GQC;$Y20Dxcs zp#UNPc?ZJ)MgdF!1ONmE2nrBly%2=~iUO1X7yuXyFce?}zyZKvfTI8>06~JmfItC3 zKqMr9A%H@FfFJ-tFa)6xL_j1D3_~yq!32Z=2!SC4g%AQlNq!hYQ3xd<3_utRVJL(V z5Dp+5hHwD&5fnxU7$rTC z*C>nV@N{S*-gdj5l>x$L` zCH(+04$?VkjP$cEb6qG|2S^$ck!&FA$SZXH5GV#v3`Q{&#RwD!C=R1IisA%HPKh*1 z))E9pj)-(g76Jl;00zMrgklhZk#i%hlie_ZApk>Q3_&r3z)*mpWF#aifnfl{U<^Ys zjKFY!;V_1y7*1g1rknjKFb#<1mh+I8NZ?Hjx7%JrTtEDgk)i5LjO(a&O2LAva)s zzhHRXCA>Z)avo&#WU}i^hr;XD(RK5rPtp>pm=sECBI!wV5|r#GOUXBd6&?V{4?&%L zg7t3#@N)nmu-&>5yPw1_s^;;ivE;$OLOW+!QUqaifo!Ih6?qxOU?@Q=qg?iP)ikx=QfBeN@bpl zk-aEi`luvUq?CT*qU3Z;X{xI7l1GM}*srpSI&t*L%)QE^3RyGtq%iL#7_fIy^0+M>GXo^M5gig?j%MXzFcl$T*DB z<5(Z6E^$WKxu8$|YkAQnf$9gI@9&nE0IlsRPuz}eak+MWV?tTC(UXi1xG`s};W^Sv zVOQ7}>o@$@$=*C$Nr(|u>dOyz3ftn1pnV+PY-?mL>Yb#hN$tJiv&kbk!FkterC zP36-iW4&qoA7)n@6J^#Wsf{uDtTLw)SKGYCmP_m>9j4Xef9mDRV1f z7*px~^Ft<=y>IcQRd?ji*SGl9>O1{z80Ni*_bUJPU{KTe_IMU?@b?U>1^HTM;-0X& zPse2&fRcF`Q;W3*CYFG+q7n+-KhMhrnY)H4@F#7R-+ysum|}1GRxY83dIwMRC5xM! z-=ca(sXs@Vs(e7zpE7tw&Y|aXd#LY&RLzjS$8I@OCdK=BD_*Kb?0i;gA=-4HCW1Xs zU}>UUVIe<->y+rC>PWHk^)1* zwf~L*D_FbzmDXg>g{}s>PVq)o)gjY^XRSvXc$4F`_86bu70$YU%_K=Y-DMZMXXgxbxzY9J)V)S&JdH&Hrwz^(SI?F7bG+EBd0P8ykF(m76|)` z<{UZRFL&H>LA=aSU`XZrOUgfh~y=gMX6n_q;qGdNgZYN`hJSM7*OMTF->lzI{R;AX6i>HhQUVB`MIrf3cMElo%Ej<7uIO}J%S{?qfbZpq&_xLot> zq=v@#$2mrsiw9|el94fXChDy*CP$5&M~2SI<`26xOGV{8KQ8$5wQhl+=9q7M>)zKb z9c!n@0tdRbkG$j1j_baOo(V!&y-RlL??N_SV!ch4(43o;r8Mjr|BINV=BQ=){+bB2 zGM@OLxN^mDnAuQ%_k2;(rMUAMNt$uUk+manjaeC)+Z(CPZw(GM*owzbU4L$0Ie+J$ zqWJU%;=^B-dVaxoMrz{a#5~%!HH6HUe3grK&=?5T3ks(`6#99?y*pv4Cm?w(WxO!) zuTdvEor1JQMj&TtwmXr*_`I5_zj(!#vRgLX=2)i=l{@HbV&|aOhLL5%2;Ms18*Z5% zbysAy=P5B${?9hZ(2X~K`Fc)B8*BbNMQ1+JGNcb+%R>A;aa|wP|Af2#S2Ha#T>hUC z^~%uaU&=jCY&fSajRUi`@-3R=uLz||Z+a%A)o!*yUo(wXGFDVhvbX}k4Bo!w!&;-muSkj?Uy4=_U#C_r2q9ITNkD9V486Jh=5O)~A5lkoQoA1~|qe#pw+?hv<8ppVv5 zN#PDilCe^eta@p`XGrGbnVf8qL(YBxU7KJE$Ttn*qX)>oRX1zMq4{hxK zVeV|{NKY62ct_d|OFT(6ukLwPb8S@3`CQX3#W`2R-bY{0UrRUqvwQ@tO84Y^fMf4% zkEh!FyVJi1kHpTHR`Pk%6$7F&%w#vsn7>msud)fvn6Me;`%%EC53Qv~LF=RJZZ$HZ>5G3#+E*9W_=fl(H+z&XI7+PHfquU|wirXLc|N(cUk9($RKh z)Pc^?J|`^ep9dd#p+CB@kaCYbym!iBe^3B@S3-^T2)kNOwzc#CCDl}_?MRPgNTm5q zH|MKOhtk`XPDr14-_er}rERLKv(=|s(3F*_OCj!AJaWz-X)dSkn)~ihnrP`WP%4xA zdCPEeip5WLuJskTt!!6i1~>~2@8I*if^z2cgOmF&2+A5K#|Yu(U=!8yAzfGz*yLy@ z@<=(od-#v2VX^sDr;oHeF`M*csYBBTu5DC3W}ezSZJ#C^%h|Hhq-0xa;lTK7(_yw# zg?z}-)4y}em{mu@XUk6=4rG?w)F<-ZTlC+5-8<>G_UfxS>s)uoOO*D#^Bx^ileD_I zMW447XZYUoY^Rs@HYEtkYsN@uy}uAtz56ZuPKD2-ya#H>PLC?nhH^LmD1YPD;`CUA z_lD*5qdx;)7FjX3XzW=E9Bbk;i70em{&J<&`w3@lbUF0(9fbwUVh>8#WxQ~+pWJvu z82eSwa!RnLq4x}{tFVvb$@$asd}=7kZ)|PfkA=DM+URTJT|bw83_Tc0o#1@>z1ls; z_##u({lUF*hx;#WZ_s#NP&7x=z{J_$(Jl=C3RaH5)Y0ZrqP))>X<08kGx~ z|0R6ra*6m9byuHgKdm0-cPXE@==oH-(^9lw^neH$YrkwX8+zdHeH&F4!uo2}Q4!ju z3#ZFyiWW)@)=GviE?df7RTt(_vCD9xsnyqs3{JMZSuoR)Pk7NR*Bc>>?$)65+fk<; ze}A+$^YC+Zun~%AOZ)Qh#{un?gv=omskw!kyZkp>ddvokoStfrgfBjOplI<_ohBd% z-?uG$eAvNK=I4tSV{j|S{|Mc(zQsQM@yjcZmXAi}y@KycYom^~yiScCC&lVt99!AH zRN`w|+B#h8$_jUJEwFQ_^DCjWvbZ*hiY8Ot4&~b(yZteQ_4v7T1n{5}x(#7#;YM#phyGoJWBYVFYxlBY92DR5H1)nK!_Er^nVZMvvsB^?l ziZMJ{1#G`JD%lt7y*{PNYkDF~qTatR51pU$I<~oK$gjG&Ruj zx9*kbt-suJRB58B1=ht{6Xmy@PqCwH#4gQ>)%O{EK7Z!zn159pkNfG?{!4AAzCU+1 zJl)3H>SoYB#W3)za7m3C3%ZxpXBe8+GA(n=;j4J3FK#`5)w#QwXJ1%9uUb*aah7?) znX@WtKP&nKnfuNRQM7DZP4>teMQ(R=>H5j<7Hzb&h7@!yT@7LyMUO|%bVX16!)F{b z`L7BiW-80dIQC;_ CM9RAW literal 0 HcmV?d00001 diff --git a/iipsrv/fcgi/doc/fastcgi-whitepaper/img00002.gif b/iipsrv/fcgi/doc/fastcgi-whitepaper/img00002.gif new file mode 100644 index 0000000000000000000000000000000000000000..3a3982085d838c6b1e264d83d11dcf704a4fee93 GIT binary patch literal 2426 zcmX9-d03818y`nW=!onUV<}Fktd-=9tdQI3Mmdjh$9RTMhFvxIU>T7xF(2jL;<1*QGzH(3?POOBZzS% z+zS9s5a(D}7u|qhz%c|EA`A(J9E&^zBqA7bi~+_7V}dcqMC2r>2qqj;fGNV1V9GHA zm?6vvW*mz|g(yxi7a0MCB1NFW4-jz(=farqqmZc(D(Zls5s0Ee)QKyiIGj*GC?b>) z$_WF6A;Jh@oQNq2qoS5`Dn=w+ibB9C1Qa3)35A@Bxe4o{8*z#O#fV};F{cDjA|er} zoKiq3qLfg|DFc)t$_Qngiph)c1V86Yj9nxr$N^^%Fo+l=400xRLBuH(Adxql8h;7+?%BMi}EvY?By>@Wi=dl>ky00*Yl4dm~mvY=C0F5K_2A ziXn-4i0DPKilrk+VVx+<3!lQ0P%MNBO@dya3sBK7O2ym6UL^p;k1#_#f#RP41N#71 z)v~xi{|O(cq33+_!s%;K>XWTbS;*6_OUKNSG~Se_SI5Am(OQ-T88z|K>~frI3Nmje z7;d_C%Ca!)Zj!NoM`KOlnc7qoK1kcD=;pnmjlGHdXBU`1J1W((@b6f=L7VjJ~_OUk%e3 zy09^J*3#;I@k?B%J8a*4AYNnqy+g5|7uUu`h3OmbDr%}voH=>L-32{s>ZJyn=4KUN zI-ZufSlbVA`sy21xld)nH8%p!OzEqb<=c{T;`MyTle=45rRP-~{Nl=c+GEoD za)X}t_O@3(DNpFpe?C9B`TgmH7~5u}SKS>t1*N~t_VN#(pLmYSFpo2*#gFrrat!=tJH5O7xkM^SEz{qi>pSeZxo6Q(*RL;1_PsEjSQweL zwcTlFzOH_`(o-iF|GqVu+bX*T{daiM!{<_MR$zJOgKV&YPqyW_&qoa%$6kBdRjn2O zbKT9K$8B=$rWq~#bj!B5(YM0Ty5!xR-yeq_y;ED)HM}bD<>>67#vtzzwWCjj&azQa z=_opQQ}t(2{90*{f2|3(Ne!~yW}II(OjD)gvHI{|+phOq4hpPWv{jb>VE7I5xeWm^ zGDAtgwLM0jb{0FMvXe;t$O~*!?ew$800x zGx6)M@1(o-9F5gCTO{jer&s>A zGUSltSx3P=tA2ewD_c;QvfB7%j_QEyR~OEp zc2>G>?)>z&p~$AcLuOJ>{ziFpzv-c!4h0_h$DYl;5#rd^5_xLQIA!e(JzjO0wyEZ7 z7dxGA9_5zHEwNJBa$6Hw_hC;VrQf6{Qd8jnHBoSWsOtYTZ@}M75Qq;?rzfA z7hdUFxx2a2sW*sAHTx<$-Ui4$bq6gf{2G&TzaYx(Nc*-QAM^Iz^K;{!y{pvTzrI-+ zuB3DU^&jeE@aJ#CJT5F&QCVwvMP+Knzn7K2c!8@@dIYb#s|>!0KwHZP)J1ZawKQGnugdrQBF2!K1+PfxTv} z!Ng5TtINm7bg5eZ%8>e4JR_C(V zyQUwf99sD&Uv|(2sr<5AwPa|r|H@_kyE+#cDX$%2y>xWbw34@dok!}dCO-_A(#TBf zmued1%`lt0*esxK#kznzd1+W^&qynW?4ljB7bRECb8y+I<2zN~DI)OZrAN*~3=LG; z=B?kHp#84Q(PiCXi}i1N>gv{=SL>-TvK@J>!P?C(#>r2vQ|jzryWGen@bTtSmz~WK zMy|oHGfQ1V-d`VmwfT8K9H;%&xNWb)mS7tF?0cd|qOX1M z#;^r@%Ua{z&Bwk;iZFk(F;nBwm`U-ekte-#j;-jHjuALU+P(zR=nqC|w02c*;#bH8ogGK~Rz~X#CxTq2?HVO3uS&y7u z96ACnN+%Y@Bb`VRVvL9)P6!@VM@3OS3Po=cKbHf5egp;d1dIO!;N=2(rKr&ZvOb7+ zgZ#0k2bm3_Yo(0Sj7sl5y|sDwsn<=VS&fm{fpAeqS$1=*tVQ9m=CYjDL}izjGzL4j zJypYJ@^v#iuQLM%tr9aX&wr6+6f1AvQeM!VXP#xuGOj4>EwW{w8fvL1>MOw;!o^HD z_XgN*-G%n8oZ?rNXFjyBOe*gW)%ty(9BQpBdHaZ1#wTuC_26AY*oGYrZB?Zo8l$94 z(oL(&Mq871d%S6@X1kVw{kOyq)|7wj&bKIXXs@Z5>U(hbS_mJ0VS2#(^yQa#E-Rky zcyu|4-%GXXB#4ROTk!MG|JK$NuQZ;tXTqoL#kPZQ^9O6DM+Pgou6ylE-keVxS9BHH zS66-s%t3I_@sjqhTUol4(we*U?=M|LHZR;pH#Rxy6$k5WJu$yhgLL~#ocFN%aNr6k zl6Ag(__#p$d}L_$6{9qmqiBfVm^sKx@F>{96lo!jgj9&Qb9v@*fvXzNy(;F6?s`kT z$rryND_P}y%Sck_!)?2w+DtlX9@k9wwVX-7X zyI;wr%5tsU9PRV3c2p@xynJ8PW34q-J>34}bHK0nBZ?(Uq*GikYzkLbtZ4AI^Q`;0 zJ?&nDw93@yO8F3Lr{Iy0kIGL%GEAzGkYBQL$nNjzhArc{d| zdZv=E%zYw~vs0Cgs~GMra2E`;&5hi%(RG3$w4OTaHFt<=U!e?eln2UioZJ$gyX4uIGcH+<1|B?wf#x>4mpf*{14M39J5n zH4xM~B0=4*~#hZQ&D44Pag8Jol(R@VdmiBu8O}fL%{DEs;4_Jo{Uo2nvDeq%k%L}>O z|E+>R#`^8jOK_qgblFm%VYHUe2VOf5?ae0<0A?Rv0)t-jZza-&KGgN;;@-z#5#Dvx?G=Rpy^uD`!+H_O`65ExED%j3VOZYN;FSz=gSbM^Ghoi!bP=RS1-^M#tGTofpTiBDm_g(XPf0)HQ zQ|6_KAX1uRh*;Fpx@8i@Ag@^ zZgCtP`b1V%a*Xai`trp`#X7@u>dyxIK+wN_y}h)Gthr|yOZ6>tSxb4p^9GfLH9o@D zvJ#Hb#oH1MfWHi8B`oKb9`r&@BSl|+%Y>852BuqT5dZt}b!XXuNj5j(bwgpRXZpDg z*OxMwm}lp^I4nS7{m8M~QYtso1D|bN0oQLSXiAH}G7yt&ZF0Fl2S$JXc&Pqe5bm0qe@@*678wt zhXw=F&4rWYCG|bK3f>PG-M_OdOHA0SqF2#LQQ{5vQ=nI3p7yWl%>@DbHajQ$rNWqo z9UqNf6n<6ocIe)8`MhFJ+;@%d2mK9$tA@9KQ&5^nTjwqRG4-ODpY8svI?>_rnl}}- z1G!pf3i4_ls;(5Vxz(SV>$!4YZGviD%0BDtRR6}d7_9wL{b5w?Q=7$La&yu-aqW+_ zc|Dp_Lw{>&&-MDG9}De2U3}$dmDX0Rqe{V!|NbD@ryr(#RI2>vkKsCQz>$DbR)C(N z4!3v2@2l~!qp2&!tv>B{K9KcWPmlUn&HS>$hv;Wd%If$|P6x(D4=)c5l7085GiY{j z>ni)@`#X5eh`)Ee>$CQ|ySnR)F8A_Qm*f3a0uBeI_Hsps1VWEDNa*YgUF$2c=JfnM z%I?21si^M2~C zkYPWj9<%z^89~u4-;El122>)6+s^B{`x`kE%28n>@3D5#{J;79GG|3mv#EZM!Rd8jr+6{I&<=@EJ>G9sc z>_tf;#hB<<916 zNC|e##QUU8^a#k!Rdx8*#43y*ci8)u(fNm9v*y}P$~^sC(0TQcp-1s-9volMpxEI< z^0HWKGX0+4*du5!pl`3Y)%eA8_nqX%_WbQaE#?8IX0tYZkTEhe&bWE5GfO%rpJA5L zmC$lFLiW7-ewRXae9LUE*i(1o)6L!K|IX%hcF8dScgAcOUgr@I*Gn>gw?9NcZ1wW5 z=I`~wH!3`NBohtjnz z#%6`fWy~}6?})1z3x4d%FlFfk4>H{?3peLkKTWaP@ub*(hr`?!YftkBE)5B4sn*3k z6<&1ac@dk>`c*!xmldftUv&Sud~1GA#BV2FzjvjOf#>`KV{q%C`dEr>8QzHbSabNh zrN^3CndioM1$`S|@c(_;K-*8Y{#mgE=MDc+Y@|}eo_)hhOLBVPzR=iJ#b2EI?t(id zihttgW-56uYGsI3|NK7I=KjIkDAs>=;#IZHK5+-G=giH);sY{v0seEZ`*MQlb`h@o zm*M7Hjr2@iL+f~AUgBrXSE~MNlopmAi`4uv + + + + FastCGI Developer's Kit + + + + +

+ [[FastCGI]]
+

+

+ FastCGI Developer's Kit +

+ + + +

+ Mark R. Brown
+ Open Market, Inc.
+

+

+ Document Version: 1.08
+ 11 June 1996
+

+
+ Copyright © 1996 Open Market, Inc. 245 First Street, Cambridge, MA 02142 U.S.A.
+ Tel: 617-621-9500 Fax: 617-621-1703 URL: http://www.openmarket.com/
+ $Id: fcgi-devel-kit.htm,v 1.6 2002/02/25 00:42:59 robs Exp $
+
+
+ +
+

+ 1. Introduction +

+

+ FastCGI is an open extension to CGI that provides high performance for all Internet applications without the + penalties of Web server APIs. +

+

+ FastCGI is designed to be layered on top of existing Web server APIs. For instance, the mod_fastcgi + Apache module adds FastCGI support to the Apache server. FastCGI can also be used, with reduced functionality + and reduced performance, on any Web server that supports CGI. +

+

+ This FastCGI Developer's Kit is designed to make developing FastCGI applications easy. The kit currently + supports FastCGI applications written in C/C++, Perl, Tcl, and Java. +

+

+ This document: +

+
    +
  • + Describes how to configure and build the kit for your development platform. +
  • +
  • + Tells how to write applications using the libraries in the kit. +
  • +
  • + Tells how to run applications using Web servers that support FastCGI or using any Web server and + cgi-fcgi. +
  • +
+

+ The kit includes a technical white paper, + doc/fastcgi-whitepaper/fastcgi.htm. You should read at least the first three sections of the + technical white paper before starting to write FastCGI applications. The performance + paper will help you understand how application design affects performance with FastCGI. +

+

+ The FastCGI Specification, doc/fcgi-spec.html, defines the interface + between a FastCGI application and a Web server that supports FastCGI. The software in the kit implements the + specification. You don't need to read the specification in order to write applications. +

+

+ Additional information is provided in the FAQ document, which + contains frequently asked questions about application development using FastCGI, as well as some general + information. +

+

+ Experience with CGI programming will be extremely valuable in writing FastCGI applications. If you don't + have enough experience with CGI programming, you should read one of the popular books on the topic or study + the NCSA CGI page. For a more formal treatment of CGI/1.1 see + the Internet Draft CGI 1.1 Specification. +

+

+ 2. Getting started +

+

+ The kit is a compressed tar (tar.Z) file, distributed via the fastcgi.com + Web page. Unpacking the tar file creates a new directory fcgi-devel-kit. +

+

+ Open the kit's index page, fcgi-devel-kit/index.html, using the "Open File" command in + your Web browser. The index page gives you an overview of the kit structure and helps you navigate the kit. + The index page also contains links that run some example applications, but the applications won't work + when index.html is opened using the "Open File" command because they aren't aren't being + accessed through a Web server. +

+

+ In order to use the kit in earnest you'll need a Web server that you control, a Web server running with + your user ID. The Web server will be starting FastCGI applications that you will need to debug; this will be a + lot more convenient for you if these processes run with your user ID. It is best to have a Web server that + supports FastCGI. Section 4 discusses Web server issues. +

+

+ If you can, keep the kit on a file system accessible from your personal workstation, do your builds on your + workstation, and run your Web server on your workstation. If that's not possible, arrange a configuration + such that the kit is accessible from the machine that's going to run your Web server, and build the kit + and your applications on a machine that's configured exactly the same way (same processor architecture, + operating system, etc.) as the machine that's going to run your Web server. +

+

+ To build the kit you execute this sequence of commands in the fcgi-devel-kit directory: +

+
+    % ./configure
+    % make
+
+

+ We've built and exercised the kit on these platforms (listed in alphabetical order): +

+
    +
  • + BSD/OS 1.1 (Intel Pentium), gcc +
  • +
  • + Digital UNIX V3.2 148 (Alpha), gcc/cc +
  • +
  • + Hewlett-Packard HP-UX A.09.05 C and B.10.01 A (PA-RISC), gcc/cc +
  • +
  • + IBM AIX 1 4 (RS/6000), gcc +
  • +
  • + Silicon Graphics IRIX 5.3 11091812 (MIPS), gcc +
  • +
  • + Sun Solaris 2.4 and 2.5 (SPARC), gcc/cc +
  • +
  • + Sun SunOS 4.1.4 (SPARC), gcc +
  • +
+

+ Once you've built the kit, follow the directions in Section 4 to bring up your Web + server and run the example applications. +

+

+ 3. Writing applications +

+

+ 3.1 Using the fcgi_stdio library +

+

+ The fcgi_stdio library provides the easiest transition for C CGI programs and C CGI programmers to + FastCGI. Using this library your application can run using either CGI or FastCGI, with the same binary for + both situations. +

+

+ To introduce the fcgi_stdio library we give a pair of examples: a tiny CGI program and the + translation of this program to FastCGI. These two example programs are included in the kit. +

+

+ The CGI program is examples/tiny-cgi.c: +

+
+    #include <stdio.h>
+    #include <stdlib.h>
+
+    void main(void)
+    {
+        int count = 0;
+        printf("Content-type: text/html\r\n"
+               "\r\n"
+               "<title>CGI Hello!</title>"
+               "<h1>CGI Hello!</h1>"
+               "Request number %d running on host <i>%s</i>\n",
+               ++count, getenv("SERVER_NAME"));
+    }
+
+

+ The key features of this tiny CGI program are: +

+
    +
  • + The program sends data to the Web server by writing to stdout, using printf in this + example. The CGI program first sends a Content-type header, then a small HTML document. The + program includes stdio.h in order to get access to the printf function. +
  • +
  • + The program obtains parameters provided by the Web server by reading environment variables. The CGI program + reads the SERVER_NAME variable using getenv and includes the value in the HTML document. + The program includes stdlib.h in order to get access to the getenv function. +
  • +
+

+ The count variable is degenerate in this example; the CGI program runs a single request, so the + request number is always one. This variable will be more interesting in the FastCGI example. +

+

+ The corresponding FastCGI program is examples/tiny-fcgi.c: +

+
+    #include "fcgi_stdio.h"
+    #include <stdlib.h>
+
+    void main(void)
+    {
+        int count = 0;
+        while(FCGI_Accept() >= 0)
+            printf("Content-type: text/html\r\n"
+                   "\r\n"
+                   "<title>FastCGI Hello!</title>"
+                   "<h1>FastCGI Hello!</h1>"
+                   "Request number %d running on host <i>%s</i>\n",
+                    ++count, getenv("SERVER_NAME"));
+    }
+
+

+ The key features of this tiny FastCGI program are: +

+
    +
  • + The program is structured as a loop that begins by calling the function FCGI_Accept. The + FCGI_Accept function blocks until a new request arrives for the program to execute. The program + includes fcgi_stdio.h in order to get access to the FCGI_Accept function. +
  • +
  • + Within the loop, FCGI_Accept creates a CGI-compatible world. printf and getenv + operate just as in the CGI program. stdin and stderr, not used by this tiny program, also + operate just as in a CGI program. +
  • +
+

+ The count variable increments each time through the loop, so the program displays a new request + number each time. You can use the reload button in your browser to demonstrate this, once you've got the + program built and running. +

+

+ Building the program +

+

+ If you can build examples/tiny-cgi.c, it will be straightforward for you to build + examples/tiny-fcgi.c. You need to: +

+
    +
  • + Add the directory containing the fcgi_stdio.h header to the compiler's include search path. + The kit calls this directory include. +
  • +
  • + Add the library libfcgi.a to the linker's command line so that it will be searched when + linking. The libfcgi.a library implements the functions defined in fcgi_stdio.h. The kit + calls the directory containing this library libfcgi. +
  • +
  • + Determine whether or not the linker on your platform searches the Berkeley socket library by default, and + if not, add linker directives to force this search. +
  • +
+

+ See examples/Makefile (created by configure) for a Makefile that builds both programs. + Autoconf handles the platform-dependent linking issues; to see how, examine configure.in and + examples/Makefile.in. +

+

+ Running the program +

+

+ Section 4 is all about how to run FastCGI applications. +

+

+ You can use CGI to run application binaries built with the fcgi_stdio library. The + FCGI_Accept function tests its environment to determine how the application was invoked. If it was + invoked as a CGI program, the first call to FCGI_Accept is essentially a no-op and the second call returns + -1. In effect, the request loop disappears. +

+

+ Of course, when a FastCGI application is run using CGI it does not get the benefits of FastCGI. For instance, + the application exits after servicing a single request, so it cannot maintain cached information. +

+

+ Implementation details +

+

+ fcgi_stdio.h works by first including stdio.h, then defining macros to replace essentially + all of the types and procedures defined in stdio.h. (stdio.h defines a few procedures that + have nothing to do with FILE *, such as sprintf and sscanf; fcgi_stdio.h + doesn't replace these.) For instance, FILE becomes FCGI_FILE and printf becomes + FCGI_printf. You'll only see these new names if you read fcgi_stdio.h or examine your C + source code after preprocessing. +

+

+ Here are some consequences of this implementation technique: +

+
    +
  • + On some platforms the implementation will break if you include stdio.h after including + fcgi_stdio.h, because stdio.h often defines macros for functions such as getc + and putc. Fortunately, on most platforms stdio.h is protected against multiple includes + by lines near the top of the file that look like +
    +    #ifndef _STDIO_H
    +    #define _STDIO_H
    +   
    +
    +

    + The specific symbol used for multiple-include protection, _STDIO_H in this example, varies from + platform to platform. As long as your platform protects stdio.h against multiple includes, you + can forget about this issue. +

    +
  • +
  • + If your application passes FILE * to functions implemented in libraries for which you have source + code, then you'll want to recompile these libraries with fcgi_stdio.h included. Most C + compilers provide a command-line option for including headers in a program being compiled; using such a + compiler feature allows you to rebuild your libraries without making source changes. For instance the gcc + command line +
    +    gcc -include /usr/local/include/fcgi_stdio.h wonderlib.c
    +   
    +
    +

    + causes gcc to include fcgi_stdio.h before it even begins to read the module + wonderlib.c. +

    +
  • +
  • + If your application passes FILE * to functions implemented in libraries for which you do not have + source code, then you'll need to include the headers for these libraries before you include + fcgi_stdio.h. You can't pass the stdin, stdout, or stderr streams + produced by FCGI_Accept to any functions implemented by these libraries. You can pass a stream on + a Unix file to a library function by following this pattern: +
    +    FILE *myStream = fopen(path, "r");
    +    answer = MungeStream(FCGI_ToFile(myStream));
    +   
    +
    +

    + Here MungeStream is a library function that you can't recompile and FCGI_ToFile is + a macro that converts from FCGI_FILE * to FILE *. The macro FCGI_ToFile is + defined in fcgi_stdio.h. +

    +
  • +
+

+ Converting CGI programs +

+

+ The main task in converting a CGI program into a FastCGI program is separating the code that needs to execute + once, initializing the program, from the code that needs to run for each request. In our tiny example, + initializing the count variable is outside the loop, while incrementing the count variable + goes inside. +

+

+ Retained application state may be an issue. You must ensure that any application state created in processing + one request has no unintended effects on later requests. FastCGI offers the possibility of significant + application performance improvements, through caching; it is up to you to make the caches work correctly. +

+

+ Storage leaks may be an issue. Many CGI programs don't worry about storage leaks because the programs + don't run for long enough for bloating to be a problem. When converting to FastCGI, you can either use a + tool such as Purify from Pure Software to discover and fix storage + leaks, or you can run a C garbage collector such as Great Circle + from Geodesic Systems. +

+

+ Limitations +

+

+ Currently there are some limits to the compatibility provided by the fcgi_stdio library: +

+
    +
  • + The library does not provide FastCGI versions of the functions fscanf and scanf. If you + wish to apply fscanf or scanf to stdin of a FastCGI program, the workaround is + to read lines or other natural units into memory and then call sscanf. If you wish to apply + fscanf to a stream on a Unix file, the workaround is to follow the pattern: +
    +    FILE *myStream = fopen(path, "r");
    +    count = fscanf(FCGI_ToFile(myStream), format, ...);
    +   
    +
    +
  • +
+

+ Reference documentation +

+

+ The FCGI_Accept manpage, doc/FCGI_Accept.3, describes the + function in the traditional format. +

+

+ The FCGI_Finish (doc/FCGI_Finish.3), FCGI_SetExitStatus (doc/FCGI_SetExitStatus.3), and FCGI_StartFilterData (doc/FCGI_StartFilterData.3) manpages + document capabilities of the fcgi-stdio library that are not illustrated above. +

+

+ 3.2 Using the fcgiapp library +

+

+ The fcgiapp library is a second C library for FastCGI. It does not provide the high degree of source + code compatibility provided by fcgi_stdio; in return, it does not make such heavy use of + #define. fcgi_stdio is implemented as a thin layer on top of fcgiapp. +

+

+ Applications built using the fcgiapp library cannot run as CGI programs; that feature is provided at + the fcgi_stdio level. +

+

+ Functions defined in fcgiapp are named using the prefix FCGX_ rather than FCGI_. + For instance, FCGX_Accept is the fcgiapp version of FCGI_Accept. +

+

+ Documentation of the fcgiapp library takes the form of extensive comments in the header file + include/fcgiapp.h. The sample programs examples/tiny-fcgi2.c and examples/echo2.c + illustrate how to use fcgiapp. +

+

+ 3.3 Using Perl and Tcl +

+

+ A major advantage of the FastCGI approach to high-performance Web applications is its language-neutrality. CGI + scripts written in popular languages such as Perl and Tcl can be evolved into high-performance FastCGI + applications. +

+

+ We have produced FastCGI-integrated Perl and Tcl interpreters. Doing so was easy, since Perl and Tcl are + conventional C applications and fcgi_stdio was designed for converting conventional C applications. + Essentially no source code changes were required in these programs; a small amount of code was added in order + to make FCGI_Accept and other FastCGI primitives available in these languages. And because these + interpreters were developed using fcgi_stdio, they run standard Perl and Tcl applications (e.g. CGI + scripts) as well as FastCGI applications. +

+

+ See the fastcgi.com Web page for more information about the Perl and Tcl + libraries. +

+

+ Here are the Perl and Tcl versions of tiny-fcgi: +

+
+#!./perl
+use FCGI;
+$count = 0;
+while(FCGI::accept() >= 0) {
+    print("Content-type: text/html\r\n\r\n",
+          "<title>FastCGI Hello! (Perl)</title>\n",
+          "<h1>FastCGI Hello! (Perl)</h1>\n";
+          "Request number ",  ++$count,
+          " running on host <i>";$env(SERVER_NAME)</i>");
+}
+
+
+#!./tclsh
+set count 0 
+while {[FCGI_Accept] >= 0 } {
+    incr count
+    puts -nonewline "Content-type: text/html\r\n\r\n"
+    puts "<title>FastCGI Hello! (Tcl)</title>"
+    puts "<h1>FastCGI Hello! (Tcl)</h1>"
+    puts "Request number $count running on host <i>$env(SERVER_NAME)</i>"
+}
+
+

+ Converting a Perl or Tcl CGI application to FastCGI is not fundamentally different from converting a C CGI + application to FastCGI. You separate the portion of the application that performs one-time initialization from + the portion that performs per-request processing. You put the per-request processing into a loop controlled by + FCGI::accept (Perl) or FCGI_Accept (Tcl). +

+

+ 3.4 Using Java +

+

+ Java is not just for browser-based applets. It is already suitable for writing some Web server applications, + and its range of applicability will only grow as Java compilers and other Java tools improve. Java's + modules, garbage collection, and threads are especially valuable for writing long-lived application servers. +

+

+ The FCGIInterface class provides facilities for Java applications analogous to what + fcgi_stdio provides for C applications. Using this library your Java application can run using either + CGI or FastCGI. +

+

+ The kit includes separate companion document on using FastCGI with Java. The + source code for FastCGI classes is contained in directory java/src and the compiled code in + java/classes. +

+

+ Here is the Java version of tiny-fcgi: +

+
+import FCGIInterface;
+
+class TinyFCGI { 
+    public static void main (String args[]) {  
+        int count = 0;
+        while(new FCGIInterface().FCGIaccept()>= 0) {
+            count ++;
+            System.out.println("Content-type: text/html\r\n\r\n");
+            System.out.println(
+                    "<title>FastCGI Hello! (Java)</title>");
+            System.out.println("<h1>FastCGI Hello! (Java)</h1>");
+            System.out.println(
+                    "request number " + count + " running on host <i>" +
+                    System.getProperty("SERVER_NAME") + "</i>");
+        }
+    }
+}
+
+

+ 4. Running applications +

+

+ 4.1 Using a Web server that supports FastCGI +

+

+ For a current listing of Web servers that support FastCGI, see the fastcgi.com Web page. +

+

+ Some of the Web servers that support FastCGI perform management of FastCGI applications. You don't need to + start and stop FastCGI applications; the Web server takes care of this. If an application process should + crash, the Web server restarts it. +

+

+ Web servers support FastCGI via new configuration directives. Since these directives are server-specific, get + more information from the documentation that accompanies each server. +

+

+ 4.2 Using cgi-fcgi with any Web server +

+

+ The program cgi-fcgi allows you to run FastCGI applications using any Web server that supports CGI. +

+

+ Here is how cgi-fcgi works. cgi-fcgi is a standard CGI program that uses Unix domain or + TCP/IP sockets to communicate with a FastCGI application. cgi-fcgi takes the path name or host/port + name of a listening socket as a parameter and connects to the FastCGI application listening on that + socket. cgi-fcgi then forwards the CGI environment variables and stdin data to the FastCGI + application, and forwards the stdout and stderr data from the FastCGI application to the Web + server. When the FastCGI application signals the end of its response, cgi-fcgi flushes its buffers + and exits. +

+

+ Obviously, having cgi-fcgi is not as good as having a server with integrated FastCGI support: +

+
    +
  • + Communication is slower than with a Web server that avoids the fork/exec overhead on every FastCGI request. +
  • +
  • + cgi-fcgi does not perform application management, so you need to provide this yourself. +
  • +
  • + cgi-fcgi supports only the Responder role. +
  • +
+

+ But cgi-fcgi does allow you to develop applications that retain state in memory between connections, + which often provides a major performance boost over normal CGI. And all the applications you develop using + cgi-fcgi will work with Web servers that have integrated support for FastCGI. +

+

+ The file examples/tiny-fcgi.cgi demonstrates a way to use cgi-fcgi to run a typical + application, in this case the examples/tiny-fcgi application: +

+
+    #!../cgi-fcgi/cgi-fcgi -f
+    -connect sockets/tiny-fcgi tiny-fcgi
+
+

+ On most Unix platforms, executing this command-interpreter file runs cgi-fcgi with arguments + -f and examples/tiny-fcgi.cgi. (Beware: On some Unix platforms, including HP-UX, the first + line of a command-interpreter file cannot contain more than 32 characters, including the newline; you may need + to install the cgi-fcgi application in a standard place like /usr/local/bin or create a + symbolic link to the cgi-fcgi application in the directory containing your application.) The + cgi-fcgi program reads the command-interpreter file and connects to the FastCGI application whose + listening socket is examples/sockets/tiny-fcgi. +

+

+ Continuing the example, if cgi-fcgi's connection attempt fails, it creates a new process running + the program examples/tiny-fcgi and listening on socket examples/sockets/tiny-fcgi. Then + cgi-fcgi retries the connection attempt, which now should succeed. +

+

+ The cgi-fcgi program has two other modes of operation. In one mode it connects to applications but + does not start them; in the other it starts applications but does not connect to them. These modes are + required when using TCP/IP. The cgi-fcgi manpage, doc/cgi-fcgi.1, + tells the full story. +

+

+ To run the example applications using cgi-fcgi, start your Web server and give it the directory + fcgi-devel-kit as the root of its URL space. If the machine running your server is called + bowser and your server is running on port 8888, you'd then open the URL + http://bowser:8888/index.html to reach the kit's index page. Now the links on the index page that + run example applications via cgi-fcgi should be active. +

+

+ 5. Known problems +

+

+ On Digital UNIX 3.0 there's a problem with Unix domain listening sockets on NFS file systems. The symptom + when using cgi-fcgi is an exit status of 38 (ENOTSOCK: socket operation on non-socket), but cgi-fcgi + may dump core in this case when compiled optimized. Work-around: Store your Unix domain listening sockets on a + non NFS file system, upgrade to Digital UNIX 3.2, or use TCP sockets. +

+

+ On AIX there's a problem with shared listening sockets. The symptoms can include application core dumps + and kernel panic. Work-around: Run a single FastCGI application server per listening socket. +

+

+ 6. Getting support +

+

+ The mailing list fastcgi-developers is used for discussions of issues in developing FastCGI + applications. Topics include announcement of FastCGI-capable Web servers or changes to such servers, + announcement of new application libraries or changes to such libraries, announcement of known bugs, discussion + of design trade-offs in FastCGI application programming, and discussion of development plans and experiences. + To join the list, see http://fastcgi.com/fastcgi-developers. +

+

+ A link to a mail archive can be found on the FastCGI home page, http://www.fastcgi.com +

+
+
+ © 1996, Open Market, Inc. / mbrown@openmarket.com +
+ + + diff --git a/iipsrv/fcgi/doc/fcgi-java.htm b/iipsrv/fcgi/doc/fcgi-java.htm new file mode 100644 index 0000000..b19f381 --- /dev/null +++ b/iipsrv/fcgi/doc/fcgi-java.htm @@ -0,0 +1,501 @@ + + + + + Integrating FastCGI with Java + + + + +
+ [[FastCGI]] +
+
+
+

+ Integrating FastCGI with Java +

+
+ + + + +

+ Steve Harris
+ Open Market, Inc.
+ 7 May 1996 +

+
+ Copyright © 1996 Open Market, Inc. 245 First Street, Cambridge, MA 02142 U.S.A.
+ Tel: 617-621-9500 Fax: 617-621-1703 URL: http://www.openmarket.com/
+
+
+

+ 1. Introduction +

+

+ Java is an object-oriented programming language developed by Sun Microsystems. The Java Depvelopers Kit (JDK), + which contains the basic Java class packages, is available from Sun in both source and binary forms at + Sun's JavaSoft site. This document + assumes that you have some familiarity with the basics of compiling and running Java programs. +

+

+ There are two kinds of applications built using Java. +

+
    +
  • + Java Applets are graphical components which are run off HTML pages via the <APPLET> + HTML extention tag.
    +
    +
  • +
  • + Java Applications (Apps) are stand-alone programs that are run by invoking the Java interpreter + directly. Like C programs, they have a main() method which the interpreter uses as an entry point. +
  • +
+

+ The initial emphasis on using Java for client side applets should not obscure the fact that Java is a full + strength programming language which can be used to develop server side stand alone applications, including CGI + and now FastCGI applications. +

+

+ The remainder of this document explains how to write and run FastCGI Java applications. It also illustrates + the conversion of a sample Java CGI program to a FastCGI program. +

+

+ 2. Writing FastCGI applications in Java +

+

+ Writing a FastCGI application in Java is as simple as writing one in C. +

+
    +
  1. + Import the FCGIInterface class. +
  2. +
  3. + Perform one-time initialization at the top of the main() method. +
  4. +
  5. + Create a new FCGIInterface object and send it an FCGIaccept() message in a loop. +
  6. +
  7. + Put the per-request application code inside that loop. +
  8. +
+

+ On return from FCGIaccept() you can access the request's environment variables using + System.getProperty and perform request-related I/O through the standard variables System.in, + System.out, and System.err. +

+

+ To illustrate these points, the kit includes examples/TinyCGI, a CGI Java application, and + examples/TinyFCGI, the FastCGI version of TinyCGI. These programs perform the same functions as the C + programs examples/tiny-cgi.c and examples/tiny-fcgi.c that are used as examples in the FastCGI Developer's Kit document. +

+

+ A. TinyCGI +

+
+ 
+class TinyCGI { 
+ public static void main (String args[]) {  
+  int count = 0;
+                ++count;
+  System.out.println("Content-type: text/html\n\n");
+  System.out.println("<html>");
+  System.out.println(
+                 "<head><TITLE>CGI Hello</TITLE></head>");
+  System.out.println("<body>");
+  System.out.println("<H3>CGI-Hello</H3>");
+  System.out.println("request number " + count + 
+     " running on host " 
+    + System.getProperty<"SERVER_NAME"));
+  System.out.println("</body>");
+  System.out.println("</html>"); 
+  }
+ }
+
+
+

+ B. TinyFCGI +

+
+ 
+import FCGIInterface;
+
+class TinyFCGI { 
+ public static void main (String args[]) {  
+  int count = 0;
+   while(new FCGIInterface().FCGIaccept()>= 0) {
+   count ++;
+   System.out.println("Content-type: text/html\n\n");
+   System.out.println("<html>");
+   System.out.println(
+     "<head><TITLE>FastCGI-Hello Java stdio</TITLE></head>");
+   System.out.println("<body>");
+   System.out.println("<H3>FastCGI-HelloJava stdio</H3>");
+   System.out.println("request number " + count + 
+     " running on host " 
+    + System.getProperty<"SERVER_NAME"));
+   System.out.println("</body>");
+   System.out.println("</html>"); 
+   }
+  }
+ }
+
+
+

+ C. Running these Examples +

+

+ We assume that you have downloaded the JDK and the FastCGI Developer's Kit, and that you have a Web server + running that can access the fcgi-devel-kit/examples directory. In all cases where we specify paths, + we are using relative paths within fcgi-devel-kit or the JDK which will need to be enlarged to a full + path by the user. +

+
+ Configuring +
+
    +
  1. + Add your JDK's java/bin directory to your Unix PATH if it isn't there + already.
    +
    +
  2. +
  3. + Add the directories fcgi-devel-kit/examples and fcgi-devel-kit/java/classes to your Java + CLASSPATH.
    +
    +
  4. +
  5. + In your Open Market Secure WebServer configuration file, httpd.config, add the following two + lines:
    +
    + ExternalAppClass TinyFCGI -host hostName:portNum
    + Responder TinyFCGI fcgi-devel-kit/examples/TinyFCGI
    +
    + +
      +
    • + hostName is the name of your host machine.
      +
    • +
    • + portNum is the port that you've selected for communication between the Web server and the + Java application.
      +
    • +
    +
    + On other servers you can use cgi-fcgi to get a similar effect. +
  6. +
  7. + Create a soft link examples/javexe to the java/bin directory in your JDK. This link is + required only to run the CGI scripts examples/TinyCGI.cgi and examples/TinyFCGI.cgi, + which use it to invoke the Java interpreter java/bin/java. It is not used by FastCGI applications. +
  8. +
  9. + You might have to modify examples/TinyFCGI.cgi to use a Unix shell for which your CLASSPATH is + defined. +
  10. +
+
+ Running +
+
    +
  • + To run TinyFCGI as FastCGI, you invoke the Java interpreter with the -D option, giving it the + FCGI_PORT environment variable and the same portNum that was used in the Web server + configuration. The command is:
    +
    + java -DFCGI_PORT=portNum TinyFCGI
    +
    + Then point your browser at fcgi-devel-kit/examples/TinyFCGI. Notice that each time you reload, + the count increments.
    +
    +
  • +
  • + To run TinyCGI, point your browser at fcgi-devel-kit/examples/TinyCGI.cgi on your host machine. + Notice that the count does not increment.
    +
    +
  • +
  • + Finally, you can run TinyFCGI as a straight CGI program by pointing your browser at + fcgi-devel-kit/examplesi/TinyFCGI.cgi. The results are exactly the same as when you ran TinyCGI. + Invoking a FastCGI program without an FCGI_PORT parameter tells the FastCGI interface to leave the + normal CGI environment in place. +
  • +
+

+ Due to gaps in the Java interpreter's support for listening sockets, Java FastCGI applications are + currently limited to being started as external applications. They can't be started and managed by the Web + server because they are incapable of using a listening socket that the Web server creates. +

+

+ 3. Standard I/O and Application Libraries +

+

+ As we have seen above, FastCGI for Java offers a redefinition of standard I/O corresponding to the the + fcgi_stdio functionality. It also offers a set of directly callable I/O methods corresponding to the + fcgiapp C library. To understand where these methods occur we need to look briefly at the FastCGI + redefinition of standard I/O. +

+

+ Java defines standard I/O in the java.System class as follows: +

+

+ public static InputStream in = new BufferedInputStream(new FileInputStream(FileDescriptor.in), 128);
+ public static PrintStream out = new PrintStream(new BufferedOutputStream(new + FileOutputStream(FileDescriptor.out), 128), true);
+ public static PrintStream err = new PrintStream(new BufferedOutputStream(new + FileOutputStream(FileDescriptor.err), 128), true); +

+

+ The File Descriptors in, out, err are constants set to 0, 1 and 2 respectively. +

+

+ The FastCGI interface redefines java.System in, out, and err by replacing the File streams with + Socket streams and inserting streams which know how to manage the FastCGI protocol between the Socket streams + and the Buffered streams in the above definitions. +

+

+ For those cases where the FCGI application needs to bypass the standard I/O streams, it can directly access + the methods of the FCGI input and output streams which roughly correspond to the functions in the C + fcgiapp library. These streams can be accessed via the request class variable in FCGIInterface. + Each Request object has instance variables that refer to an FCGIInputStream, and to two FCGIOutputStreams + associated with that request. +

+

+ 4. Environment Variables +

+

+ Java does not use the C environ list. Nor is there a getenv command that reads system + environment variables. This is intentional for reasons of portability and security. Java has an internal + dictionary of properties which belongs to the System class. These System properties are name/value + associations that constitute the Java environment. When a Java application starts up, it reads in a file with + default properties. As we have seen, additional System properties may be inserted by using the -D Java + command argument. +

+

+ For CGI, where the Java application is invoked from a .cgi script that, in turn, invokes the Java interpreter, + this script could read the environment and pass the variables to the Java application either by writing a file + or by creating -D options on the fly. Both of these methods are somewhat awkward. +

+

+ For FastCGI Java applications, the environment variables are obtained from the FastCGI web server via + FCGI_PARAMS records that are sent to the application at the start of each request. The FastCGI + interface stores the original startup properties, combines these with the properties obtained from the server, + and puts the new set of properties in the System properties dictionary. The only parameter that has to be + specifically added at startup time is the FCGI_PORT parameter for the Socket creation. In the future, we + expect that even this parameter won't be needed, since its use is due to an acknowledged rigidity in the + JDK's implementation of sockets. +

+

+

+

+ 5. Further examples: EchoFCGI and Echo2FCGI +

+

+ The next two examples illustrate the points made in the last two sections. EchoFCGI and Echo2FCGI both echo + user input and display the application's environment variables. EchoFCGI reads the user input from + System.in, while Echo2FCGI reads the user input directly from the intermediate FastCGI input stream. +

+

+ A. EchoFCGI +

+
+import FCGIInterface;
+import FCGIGlobalDefs;
+import java.io.*;
+
+class EchoFCGI {
+ 
+ public static void main (String args[]) {
+  int status = 0;
+   while(new FCGIInterface().FCGIaccept()>= 0) {
+  System.out.println("Content-type: text/html\n\n");
+   System.out.println("<html>");
+   System.out.println(
+    "<head%gt;<TITLE>FastCGI echo
+                                      </TITLE></head>");
+   System.out.println("<body>"); 
+   System.out.println(
+                                         "<H2>FastCGI echo</H2>");
+   System.out.println("<H3>STDIN</H3>");
+   for ( int c = 0; c != -1; ) {
+    try {
+     c = System.in.read();
+    } catch(IOException e) {
+     System.out.println(
+     "<br><b>SYSTEM EXCEPTION");
+     Runtime rt = Runtime.getRuntime();
+     rt.exit(status);
+     }
+    if (c != -1) { 
+     System.out.print((char)c);
+     }
+    }
+   System.out.println(
+    "<H3>Environment Variables:</H3>");
+ 
+   System.getProperties().list(System.out);
+   System.out.println("</body>");
+   System.out.println("</html>");
+      }
+  }
+   }
+
+

+ B. Echo2FCGI +

+
+import FCGIInterface;
+import FCGIGlobalDefs;
+import FCGIInputStream;
+import FCGIOutputStream;
+import FCGIMessage;
+import FCGIRequest;
+import java.io.*;
+
+class Echo2FCGI {
+
+ public static void main (String args[]) {
+  int status = 0;
+                FCGIInterface intf = new FCGIInterface();
+   while(intf.FCGIaccept()>= 0) {
+  System.out.println("Content-type: text/html\n\n");
+   System.out.println("<html>");
+   System.out.println(
+    "<head><TITLE>FastCGI echo
+                                    </TITLE></head>");
+   System.out.println("<body>");   
+   System.out.println("<H2>FastCGI echo</H2>");
+   System.out.println("<H3>STDIN:</H3">);
+   for ( int c = 0; c != -1; ) {
+    try {
+     c = intf.request.inStream.read();
+    } catch(IOException e) {
+     System.out.println(
+     "<br><b>SYSTEM EXCEPTION");
+     Runtime rt = Runtime.getRuntime();
+     rt.exit(status);
+     }
+    if (c != -1) { 
+     System.out.print((char)c);
+     }
+    }
+   System.out.println(
+    "<H3>Environment Variables:</H3>");
+ 
+   System.getProperties().list(System.out);
+   System.out.println(<"/body>");
+   System.out.println("</html>");
+      }
+  }
+   }
+
+

+ C. Running these Examples +

+
+ Configuring +
+

+ As with TinyFCGI, you need to configure the web server to recognize these two FastCGI applications. Your + configuration now looks like this: +

+

+

+
+ExternalAppClass java1 -host hostname:portNum
+Responder java1 fcgi-devel-kit/examples/TinyFCGI
+ExternalAppClass java2 -host hostname:portNumA
+Responder java2 fcgi-devel-kit/examples/EchoFCGI
+ExternalAppClass java3 -host hostname:porNumB
+Responder java3 fcgi-devel-kit/examples/Echo2FCGI
+
+

+ Note that the application classes and port numbers are different for each application. +

+
+ Running +
+

+ As with TinyFCGI, you need to run these programs with the -D option using FCGI_PORT and the appropriate port + number. To get some data for standard input we have created two html pages with forms that use a POST method. + These are echo.html and echo2.html. You must edit these .html files to expand the path to + fcgi-devel-kit/examples to a full path. Once the appropriate Java program is running, point your + browser at the corresponding HTML page, enter some data and select the go_find button. +

+

+ 6. FastCGI Java Classes +

+

+ The Java FastCGI classes are included in both source and byte code format in fcgi-devel-kit/java/src + and :fcgi-devel-kit/java/classes respectively. The following is a brief description of these classes: +

+

+

+
+
+ FCGIInterface +
+
+ This class contains the FCGIaccept method called by the FastCGI user application. This method sets up the + appropriate FastCGI environment for communication with the web server and manages FastCGI requests.
+
+
+ FCGIInputStream +
+
+ This input stream manages FastCGI internal buffers to ensure that the user gets all of the FastCGI messages + associated with a request. It uses FCGIMessage objects to interpret these incoming messages.
+
+
+ FCGIOutputStream +
+
+ This output stream manages FastCGI internal buffers to send user data back to the web server and to notify + the server of various FCGI protocol conditions. It uses FCGIMessage objects to format outgoing FastCGI + messages.
+
+
+ FCGIMessage +
+
+ This is the only class that understands the actual structure of the FastCGI messages. It interprets + incoming FastCGI records and constructs outgoing ones..
+
+
+ FCGIRequest +
+
+ This class currently contains data fields used by FastCGI to manage user requests. In a multi-threaded + version of FastCGI, the role of this class will be expanded.
+
+
+ FCGIGlobalDefs +
+
+ This class contains definitions of FastCGI constants. +
+
+
+
+ Steve Harris // harris@openmarket.com +
+ + + diff --git a/iipsrv/fcgi/doc/fcgi-perf.htm b/iipsrv/fcgi/doc/fcgi-perf.htm new file mode 100644 index 0000000..bf697c9 --- /dev/null +++ b/iipsrv/fcgi/doc/fcgi-perf.htm @@ -0,0 +1,456 @@ + + + + + Understanding FastCGI Application Performance + + + + +
+ [[FastCGI]] +
+
+
+

+ Understanding FastCGI Application Performance +

+
+ + + +
+ Mark R. Brown
+ Open Market, Inc.
+

+ 10 June 1996
+

+
+

+

+
+ Copyright © 1996 Open Market, Inc. 245 First Street, Cambridge, MA 02142 U.S.A.
+ Tel: 617-621-9500 Fax: 617-621-1703 URL: http://www.openmarket.com/
+ $Id: fcgi-perf.htm,v 1.4 2002/02/25 00:42:59 robs Exp $
+
+
+ +

+

+
+

+ 1. Introduction +

+

+ Just how fast is FastCGI? How does the performance of a FastCGI application compare with the performance of + the same application implemented using a Web server API? +

+

+ Of course, the answer is that it depends upon the application. A more complete answer is that FastCGI often + wins by a significant margin, and seldom loses by very much. +

+

+ Papers on computer system performance can be laden with complex graphs showing how this varies with that. + Seldom do the graphs shed much light on why one system is faster than another. Advertising copy is + often even less informative. An ad from one large Web server vendor says that its server "executes web + applications up to five times faster than all other servers," but the ad gives little clue where the + number "five" came from. +

+

+ This paper is meant to convey an understanding of the primary factors that influence the performance of Web + server applications and to show that architectural differences between FastCGI and server APIs often give an + "unfair" performance advantage to FastCGI applications. We run a test that shows a FastCGI + application running three times faster than the corresponding Web server API application. Under different + conditions this factor might be larger or smaller. We show you what you'd need to measure to figure that + out for the situation you face, rather than just saying "we're three times faster" and moving + on. +

+

+ This paper makes no attempt to prove that FastCGI is better than Web server APIs for every application. Web + server APIs enable lightweight protocol extensions, such as Open Market's SecureLink extension, to be + added to Web servers, as well as allowing other forms of server customization. But APIs are not well matched + to mainstream applications such as personalized content or access to corporate databases, because of API + drawbacks including high complexity, low security, and limited scalability. FastCGI shines when used for the + vast majority of Web applications. +

+

+

+

+ 2. Performance Basics +

+

+ Since this paper is about performance we need to be clear on what "performance" is. +

+

+ The standard way to measure performance in a request-response system like the Web is to measure peak request + throughput subject to a response time constriaint. For instance, a Web server application might be capable of + performing 20 requests per second while responding to 90% of the requests in less than 2 seconds. +

+

+ Response time is a thorny thing to measure on the Web because client communications links to the Internet have + widely varying bandwidth. If the client is slow to read the server's response, response time at both the + client and the server will go up, and there's nothing the server can do about it. For the purposes of + making repeatable measurements the client should have a high-bandwidth communications link to the server. +

+

+ [Footnote: When designing a Web server application that will be accessed over slow (e.g. 14.4 or even 28.8 + kilobit/second modem) channels, pay attention to the simultaneous connections bottleneck. Some servers are + limited by design to only 100 or 200 simultaneous connections. If your application sends 50 kilobytes of data + to a typical client that can read 2 kilobytes per second, then a request takes 25 seconds to complete. If your + server is limited to 100 simultaneous connections, throughput is limited to just 4 requests per second.] +

+

+ Response time is seldom an issue when load is light, but response times rise quickly as the system approaches + a bottleneck on some limited resource. The three resources that typical systems run out of are network I/O, + disk I/O, and processor time. If short response time is a goal, it is a good idea to stay at or below 50% load + on each of these resources. For instance, if your disk subsystem is capable of delivering 200 I/Os per second, + then try to run your application at 100 I/Os per second to avoid having the disk subsystem contribute to slow + response times. Through careful management it is possible to succeed in running closer to the edge, but + careful management is both difficult and expensive so few systems get it. +

+

+ If a Web server application is local to the Web server machine, then its internal design has no impact on + network I/O. Application design can have a big impact on usage of disk I/O and processor time. +

+

+

+

+ 3. Caching +

+

+ It is a rare Web server application that doesn't run fast when all the information it needs is available + in its memory. And if the application doesn't run fast under those conditions, the possible solutions are + evident: Tune the processor-hungry parts of the application, install a faster processor, or change the + application's functional specification so it doesn't need to do so much work. +

+

+ The way to make information available in memory is by caching. A cache is an in-memory data structure that + contains information that's been read from its permanent home on disk. When the application needs + information, it consults the cache, and uses the information if it is there. Otherwise is reads the + information from disk and places a copy in the cache. If the cache is full, the application discards some old + information before adding the new. When the application needs to change cached information, it changes both + the cache entry and the information on disk. That way, if the application crashes, no information is lost; the + application just runs more slowly for awhile after restarting, because the cache doesn't improve + performance when it is empty. +

+

+ Caching can reduce both disk I/O and processor time, because reading information from disk uses more processor + time than reading it from the cache. Because caching addresses both of the potential bottlenecks, it is the + focal point of high-performance Web server application design. CGI applications couldn't perform in-memory + caching, because they exited after processing just one request. Web server APIs promised to solve this + problem. But how effective is the solution? +

+

+ Today's most widely deployed Web server APIs are based on a pool-of-processes server model. The Web server + consists of a parent process and a pool of child processes. Processes do not share memory. An incoming request + is assigned to an idle child at random. The child runs the request to completion before accepting a new + request. A typical server has 32 child processes, a large server has 100 or 200. +

+

+ In-memory caching works very poorly in this server model because processes do not share memory and incoming + requests are assigned to processes at random. For instance, to keep a frequently-used file available in memory + the server must keep a file copy per child, which wastes memory. When the file is modified all the children + need to be notified, which is complex (the APIs don't provide a way to do it). +

+

+ FastCGI is designed to allow effective in-memory caching. Requests are routed from any child process to a + FastCGI application server. The FastCGI application process maintains an in-memory cache. +

+

+ In some cases a single FastCGI application server won't provide enough performance. FastCGI provides two + solutions: session affinity and multi-threading. +

+

+ With session affinity you run a pool of application processes and the Web server routes requests to individual + processes based on any information contained in the request. For instance, the server can route according to + the area of content that's been requested, or according to the user. The user might be identified by an + application-specific session identifier, by the user ID contained in an Open Market Secure Link ticket, by the + Basic Authentication user name, or whatever. Each process maintains its own cache, and session affinity + ensures that each incoming request has access to the cache that will speed up processing the most. +

+

+ With multi-threading you run an application process that is designed to handle several requests at the same + time. The threads handling concurrent requests share process memory, so they all have access to the same + cache. Multi-threaded programming is complex -- concurrency makes programs difficult to test and debug -- but + with FastCGI you can write single threaded or multithreaded applications. +

+

+

+

+ 4. Database Access +

+

+ Many Web server applications perform database access. Existing databases contain a lot of valuable + information; Web server applications allow companies to give wider access to the information. +

+

+ Access to database management systems, even within a single machine, is via connection-oriented protocols. An + application "logs in" to a database, creating a connection, then performs one or more accesses. + Frequently, the cost of creating the database connection is several times the cost of accessing data over an + established connection. +

+

+ To a first approximation database connections are just another type of state to be cached in memory by an + application, so the discussion of caching above applies to caching database connections. +

+

+ But database connections are special in one respect: They are often the basis for database licensing. You pay + the database vendor according to the number of concurrent connections the database system can sustain. A + 100-connection license costs much more than a 5-connection license. It follows that caching a database + connection per Web server child process is not just wasteful of system's hardware resources, it could + break your software budget. +

+

+

+

+ 5. A Performance Test +

+

+ We designed a test application to illustrate performance issues. The application represents a class of + applications that deliver personalized content. The test application is quite a bit simpler than any real + application would be, but still illustrates the main performance issues. We implemented the application using + both FastCGI and a current Web server API, and measured the performance of each. +

+

+

+

+ 5.1 Application Scenario +

+

+ The application is based on a user database and a set of content files. When a user requests a content file, + the application performs substitutions in the file using information from the user database. The application + then returns the modified content to the user. +

+

+ Each request accomplishes the following: +

+

+

+
    +
  1. + authentication check: The user id is used to retrieve and check the password. +

    +

    +
  2. +
  3. + attribute retrieval: The user id is used to retrieve all of the user's attribute values. +

    +

    +
  4. +
  5. + file retrieval and filtering: The request identifies a content file. This file is read and all occurrences + of variable names are replaced with the user's corresponding attribute values. The modified HTML is + returned to the user.
    +
    +
  6. +
+

+ Of course, it is fair game to perform caching to shortcut any of these steps. +

+

+ Each user's database record (including password and attribute values) is approximately 100 bytes long. + Each content file is 3,000 bytes long. Both database and content files are stored on disks attached to the + server platform. +

+

+ A typical user makes 10 file accesses with realistic think times (30-60 seconds) between accesses, then + disappears for a long time. +

+

+

+

+ 5.2 Application Design +

+

+ The FastCGI application maintains a cache of recently-accessed attribute values from the database. When the + cache misses the application reads from the database. Because only a small number of FastCGI application + processes are needed, each process opens a database connection on startup and keeps it open. +

+

+ The FastCGI application is configured as multiple application processes. This is desirable in order to get + concurrent application processing during database reads and file reads. Requests are routed to these + application processes using FastCGI session affinity keyed on the user id. This way all a user's requests + after the first hit in the application's cache. +

+

+ The API application does not maintain a cache; the API application has no way to share the cache among its + processes, so the cache hit rate would be too low to make caching pay. The API application opens and closes a + database connection on every request; keeping database connections open between requests would result in an + unrealistically large number of database connections open at the same time, and very low utilization of each + connection. +

+

+

+

+ 5.3 Test Conditions +

+

+ The test load is generated by 10 HTTP client processes. The processes represent disjoint sets of users. A + process makes a request for a user, then a request for a different user, and so on until it is time for the + first user to make another request. +

+

+ For simplicity the 10 client processes run on the same machine as the Web server. This avoids the possibility + that a network bottleneck will obscure the test results. The database system also runs on this machine, as + specified in the application scenario. +

+

+ Response time is not an issue under the test conditions. We just measure throughput. +

+

+ The API Web server is in these tests is Netscape 1.1. +

+

+

+

+ 5.4 Test Results and Discussion +

+

+ Here are the test results: +

+

+

+
+
+    FastCGI  12.0 msec per request = 83 requests per second
+    API      36.6 msec per request = 27 requests per second
+
+
+

+ Given the big architectural advantage that the FastCGI application enjoys over the API application, it is not + surprising that the FastCGI application runs a lot faster. To gain a deeper understanding of these results we + measured two more conditions: +

+

+

+
    +
  • + API with sustained database connections. If you could afford the extra licensing cost, how much faster + would your API application run? +

    +

    +
    +    API      16.0 msec per request = 61 requests per second
    +
    + Answer: Still not as fast as the FastCGI application. +

    +

    +
  • +
  • + FastCGI with cache disabled. How much benefit does the FastCGI application get from its cache? +

    +

    +
    +    FastCGI  20.1 msec per request = 50 requests per second
    +
    + Answer: A very substantial benefit, even though the database access is quite simple.
    +
    +
  • +
+

+ What these two extra experiments show is that if the API and FastCGI applications are implemented in exactly + the same way -- caching database connections but not caching user profile data -- the API application is + slightly faster. This is what you'd expect, since the FastCGI application has to pay the cost of + inter-process communication not present in the API application. +

+

+ In the real world the two applications would not be implemented in the same way. FastCGI's architectural + advantage results in much higher performance -- a factor of 3 in this test. With a remote database or more + expensive database access the factor would be higher. With more substantial processing of the content files + the factor would be smaller. +

+

+

+

+ 6. Multi-threaded APIs +

+

+ Web servers with a multi-threaded internal structure (and APIs to match) are now starting to become more + common. These servers don't have all of the disadvantages described in Section 3. Does this mean that + FastCGI's performance advantages will disappear? +

+

+ A superficial analysis says yes. An API-based application in a single-process, multi-threaded server can + maintain caches and database connections the same way a FastCGI application can. The API-based application + does not pay for inter-process communication, so the API-based application will be slightly faster than the + FastCGI application. +

+

+ A deeper analysis says no. Multi-threaded programming is complex, because concurrency makes programs much more + difficult to test and debug. In the case of multi-threaded programming to Web server APIs, the normal problems + with multi-threading are compounded by the lack of isolation between different applications and between the + applications and the Web server. With FastCGI you can write programs in the familiar single-threaded style, + get all the reliability and maintainability of process isolation, and still get very high performance. If you + truly need multi-threading, you can write multi-threaded FastCGI and still isolate your multi-threaded + application from other applications and from the server. In short, multi-threading makes Web server APIs + unusable for practially all applications, reducing the choice to FastCGI versus CGI. The performance winner in + that contest is obviously FastCGI. +

+

+

+

+ 7. Conclusion +

+

+ Just how fast is FastCGI? The answer: very fast indeed. Not because it has some specially-greased path through + the operating system, but because its design is well matched to the needs of most applications. We invite you + to make FastCGI the fast, open foundation for your Web server applications. +

+

+

+
+ OMI Home Page +
+ © 1995, Open Market, Inc. / mbrown@openmarket.com +
+ + + diff --git a/iipsrv/fcgi/doc/fcgi-perl.htm b/iipsrv/fcgi/doc/fcgi-perl.htm new file mode 100644 index 0000000..c5f936c --- /dev/null +++ b/iipsrv/fcgi/doc/fcgi-perl.htm @@ -0,0 +1,53 @@ + + + + + Integrating FastCGI with Perl-5 + + + + +
+ [[FastCGI]] +
+
+ +
+

+ Integrating FastCGI with Perl-5 +

+
+ + + +
+ Copyright © 1996 Open Market, Inc. 245 First Street, Cambridge, MA 02142 U.S.A.
+ Tel: 617-949-7000 URL: http://www.openmarket.com/
+ $Id: fcgi-perl.htm,v 1.5 2002/02/25 00:42:59 robs Exp $
+
+
+

+ Perl (Practical Extraction and Report Language) is a scripting language that is often used for CGI + programming. Perl is freely available. +

+

+ FastCGI support is available for Perl via the FCGI.pm Perl module. FCGI.pm no longer requires SFIO or a + specially-built Perl. FCGI.pm is available via CPAN as well as in the perl directory of this kit. +

+

+ Please see the FCGI.pm documentation for examples and details. +

+ + + diff --git a/iipsrv/fcgi/doc/fcgi-spec.html b/iipsrv/fcgi/doc/fcgi-spec.html new file mode 100644 index 0000000..e24f378 --- /dev/null +++ b/iipsrv/fcgi/doc/fcgi-spec.html @@ -0,0 +1,1340 @@ + + + + + + + + FastCGI Specification + + + + +
+

+ FastCGI Specification +

+
+
+ Mark R. Brown
+ Open Market, Inc.
+

+ Document Version: 1.0
+ 29 April 1996
+

+
+

+

+
+ Copyright © 1996 Open Market, Inc. 245 First Street, Cambridge, MA 02142 U.S.A.
+ Tel: 617-621-9500 Fax: 617-621-1703 URL: http://www.openmarket.com/
+
+ $Id: fcgi-spec.html,v 1.4 2002/02/25 00:42:59 robs Exp $ +
+
+ +

+

+
+

+ 1. Introduction +

+

+ FastCGI is an open extension to CGI that provides high performance for all Internet applications without the + penalties of Web server APIs. +

+

+ This specification has narrow goal: to specify, from an application perspective, the interface between a + FastCGI application and a Web server that supports FastCGI. Many Web server features related to FastCGI, e.g. + application management facilities, have nothing to do with the application to Web server interface, and are + not described here. +

+

+ This specification is for Unix (more precisely, for POSIX systems that support Berkeley Sockets). The bulk of + the specification is a simple communications protocol that is independent of byte ordering and will extend to + other systems. +

+

+ We'll introduce FastCGI by comparing it with conventional Unix implementations of CGI/1.1. FastCGI is + designed to support long-lived application processes, i.e. application servers. That's a major + difference compared with conventional Unix implementations of CGI/1.1, which construct an application process, + use it respond to one request, and have it exit. +

+

+ The initial state of a FastCGI process is more spartan than the initial state of a CGI/1.1 process, because + the FastCGI process doesn't begin life connected to anything. It doesn't have the conventional open + files stdin, stdout, and stderr, and it doesn't receive much information + through environment variables. The key piece of initial state in a FastCGI process is a listening socket, + through which it accepts connections from a Web server. +

+

+ After a FastCGI process accepts a connection on its listening socket, the process executes a simple protocol + to receive and send data. The protocol serves two purposes. First, the protocol multiplexes a single transport + connection between several independent FastCGI requests. This supports applications that are able to process + concurrent requests using event-driven or multi-threaded programming techniques. Second, within each request + the protocol provides several independent data streams in each direction. This way, for instance, both + stdout and stderr data pass over a single transport connection from the application to the + Web server, rather than requiring separate pipes as with CGI/1.1. +

+

+ A FastCGI application plays one of several well-defined roles. The most familiar is the + Responder role, in which the application receives all the information associated with an HTTP request + and generates an HTTP response; that's the role CGI/1.1 programs play. A second role is Authorizer, + in which the application receives all the information associated with an HTTP request and generates an + authorized/unauthorized decision. A third role is Filter, in which the application receives all the + information associated with an HTTP request, plus an extra stream of data from a file stored on the Web + server, and generates a "filtered" version of the data stream as an HTTP response. The framework is + extensible so that more FastCGI can be defined later. +

+

+ In the remainder of this specification the terms "FastCGI application," "application + process," or "application server" are abbreviated to "application" whenever that + won't cause confusion. +

+

+

+

+ 2. Initial Process State +

+

+ 2.1 Argument list +

+

+ By default the Web server creates an argument list containing a single element, the name of the application, + taken to be the last component of the executable's path name. The Web server may provide a way to specify + a different application name, or a more elaborate argument list. +

+

+ Note that the file executed by the Web server might be an interpreter file (a text file that starts with the + characters #!), in which case the application's argument list is constructed as described in the + execve manpage. +

+

+

+

+ 2.2 File descriptors +

+

+ The Web server leaves a single file descriptor, FCGI_LISTENSOCK_FILENO, open when the application + begins execution. This descriptor refers to a listening socket created by the Web server. +

+

+ FCGI_LISTENSOCK_FILENO equals STDIN_FILENO. The standard descriptors STDOUT_FILENO + and STDERR_FILENO are closed when the application begins execution. A reliable method for an + application to determine whether it was invoked using CGI or FastCGI is to call + getpeername(FCGI_LISTENSOCK_FILENO), which returns -1 with errno set to ENOTCONN + for a FastCGI application. +

+

+ The Web server's choice of reliable transport, Unix stream pipes (AF_UNIX) or TCP/IP + (AF_INET), is implicit in the internal state of the FCGI_LISTENSOCK_FILENO socket. +

+

+

+

+ 2.3 Environment variables +

+

+ The Web server may use environment variables to pass parameters to the application. This specification defines + one such variable, FCGI_WEB_SERVER_ADDRS; we expect more to be defined as the specification evolves. + The Web server may provide a way to bind other environment variables, such as the PATH variable. +

+

+

+

+ 2.4 Other state +

+

+ The Web server may provide a way to specify other components of an application's initial process state, + such as the priority, user ID, group ID, root directory, and working directory of the process. +

+

+

+

+ 3. Protocol Basics +

+

+ 3.1 Notation +

+

+ We use C language notation to define protocol message formats. All structure elements are defined in terms of + the unsigned char type, and are arranged so that an ISO C compiler lays them out in the obvious + manner, with no padding. The first byte defined in the structure is transmitted first, the second byte second, + etc. +

+

+ We use two conventions to abbreviate our definitions. +

+

+ First, when two adjacent structure components are named identically except for the suffixes + "B1" and "B0," it means that the two components may be viewed as a + single number, computed as B1<<8 + B0. The name of this single number is the name of the + components, minus the suffixes. This convention generalizes in an obvious way to handle numbers represented in + more than two bytes. +

+

+ Second, we extend C structs to allow the form +

+
+        struct {
+            unsigned char mumbleLengthB1;
+            unsigned char mumbleLengthB0;
+            ... /* other stuff */
+            unsigned char mumbleData[mumbleLength];
+        };
+
+

+ meaning a structure of varying length, where the length of a component is determined by the values of the + indicated earlier component or components. +

+

+

+

+ 3.2 Accepting Transport Connections +

+

+ A FastCGI application calls accept() on the socket referred to by file descriptor + FCGI_LISTENSOCK_FILENO to accept a new transport connection. If the accept() succeeds, and + the FCGI_WEB_SERVER_ADDRS environment variable is bound, the application application immediately + performs the following special processing: +

+

+

+
    +
  • + FCGI_WEB_SERVER_ADDRS: The value is a list of valid IP addresses for the Web server. +

    + If FCGI_WEB_SERVER_ADDRS was bound, the application checks the peer IP address of the new + connection for membership in the list. If the check fails (including the possibility that the connection + didn't use TCP/IP transport), the application responds by closing the connection. +

    +

    + FCGI_WEB_SERVER_ADDRS is expressed as a comma-separated list of IP addresses. Each IP address + is written as four decimal numbers in the range [0..255] separated by decimal points. So one legal + binding for this variable is FCGI_WEB_SERVER_ADDRS=199.170.183.28,199.170.183.71. +

    +
    +
    +
  • +
+

+ An application may accept several concurrent transport connections, but it need not do so. +

+

+

+

+ 3.3 Records +

+

+ Applications execute requests from a Web server using a simple protocol. Details of the protocol depend upon + the application's role, but roughly speaking the Web server first sends parameters and other data to the + application, then the application sends result data to the Web server, and finally the application sends the + Web server an indication that the request is complete. +

+

+ All data that flows over the transport connection is carried in FastCGI records. FastCGI records + accomplish two things. First, records multiplex the transport connection between several independent FastCGI + requests. This multiplexing supports applications that are able to process concurrent requests using + event-driven or multi-threaded programming techniques. Second, records provide several independent data + streams in each direction within a single request. This way, for instance, both stdout and + stderr data can pass over a single transport connection from the application to the Web server, + rather than requiring separate connections. +

+

+

+
+        typedef struct {
+            unsigned char version;
+            unsigned char type;
+            unsigned char requestIdB1;
+            unsigned char requestIdB0;
+            unsigned char contentLengthB1;
+            unsigned char contentLengthB0;
+            unsigned char paddingLength;
+            unsigned char reserved;
+            unsigned char contentData[contentLength];
+            unsigned char paddingData[paddingLength];
+        } FCGI_Record;
+
+

+ A FastCGI record consists of a fixed-length prefix followed by a variable number of content and padding bytes. + A record contains seven components: +

+

+

+
    +
  • + version: Identifies the FastCGI protocol version. This specification documents + FCGI_VERSION_1. +

    +

    +
  • +
  • + type: Identifies the FastCGI record type, i.e. the general function that the record performs. + Specific record types and their functions are detailed in later sections. +

    +

    +
  • +
  • + requestId: Identifies the FastCGI request to which the record belongs. +

    +

    +
  • +
  • + contentLength: The number of bytes in the contentData component of the record. +

    +

    +
  • +
  • + paddingLength: The number of bytes in the paddingData component of the record. +

    +

    +
  • +
  • + contentData: Between 0 and 65535 bytes of data, interpreted according to the record type. +

    +

    +
  • +
  • + paddingData: Between 0 and 255 bytes of data, which are ignored.
    +
    +
  • +
+

+ We use a relaxed C struct initializer syntax to specify constant FastCGI records. We omit the + version component, ignore padding, and treat requestId as a number. Thus + {FCGI_END_REQUEST, 1, {FCGI_REQUEST_COMPLETE,0}} is a record with type == FCGI_END_REQUEST, + requestId == 1, and contentData == {FCGI_REQUEST_COMPLETE,0}. +

+

+

+
+ Padding +
+

+ The protocol allows senders to pad the records they send, and requires receivers to interpret the + paddingLength and skip the paddingData. Padding allows senders to keep data aligned for more + efficient processing. Experience with the X window system protocols shows the performance benefit of such + alignment. +

+

+ We recommend that records be placed on boundaries that are multiples of eight bytes. The fixed-length portion + of a FCGI_Record is eight bytes. +

+

+

+
+ Managing Request IDs +
+

+ The Web server re-uses FastCGI request IDs; the application keeps track of the current state of each request + ID on a given transport connection. A request ID R becomes active when the application receives a + record {FCGI_BEGIN_REQUEST, R, ...} and becomes inactive when the application sends a record + {FCGI_END_REQUEST, R, ...} to the Web server. +

+

+ While a request ID R is inactive, the application ignores records with requestId == R, + except for FCGI_BEGIN_REQUEST records as just described. +

+

+ The Web server attempts to keep FastCGI request IDs small. That way the application can keep track of request + ID states using a short array rather than a long array or a hash table. An application also has the option of + accepting only one request at a time. In this case the application simply checks incoming requestId + values against the current request ID. +

+

+

+
+ Types of Record Types +
+

+ There are two useful ways of classifying FastCGI record types. +

+

+ The first distinction is between management records and application records. A management record + contains information that is not specific to any Web server request, such as information about the protocol + capabilities of the application. An application record contains information about a particular request, + identified by the requestId component. +

+

+ Management records have a requestId value of zero, also called the null request ID. + Application records have a nonzero requestId. +

+

+ The second distinction is between discrete and stream records. A discrete record contains a + meaningful unit of data all by itself. A stream record is part of a stream, i.e. a series of zero or + more non-empty records (length != 0) of the stream type, followed by an empty record (length == + 0) of the stream type. The contentData components of a stream's records, when concatenated, + form a byte sequence; this byte sequence is the value of the stream. Therefore the value of a stream is + independent of how many records it contains or how its bytes are divided among the non-empty records. +

+

+ These two classifications are independent. Among the record types defined in this version of the FastCGI + protocol, all management record types are also discrete record types, and nearly all application record types + are stream record types. But three application record types are discrete, and nothing prevents defining a + management record type that's a stream in some later version of the protocol. +

+

+

+

+ 3.4 Name-Value Pairs +

+

+ In many of their roles, FastCGI applications need to read and write varying numbers of variable-length values. + So it is useful to adopt a standard format for encoding a name-value pair. +

+

+ FastCGI transmits a name-value pair as the length of the name, followed by the length of the value, followed + by the name, followed by the value. Lengths of 127 bytes and less can be encoded in one byte, while longer + lengths are always encoded in four bytes: +

+

+

+
+        typedef struct {
+            unsigned char nameLengthB0;  /* nameLengthB0  >> 7 == 0 */
+            unsigned char valueLengthB0; /* valueLengthB0 >> 7 == 0 */
+            unsigned char nameData[nameLength];
+            unsigned char valueData[valueLength];
+        } FCGI_NameValuePair11;
+
+        typedef struct {
+            unsigned char nameLengthB0;  /* nameLengthB0  >> 7 == 0 */
+            unsigned char valueLengthB3; /* valueLengthB3 >> 7 == 1 */
+            unsigned char valueLengthB2;
+            unsigned char valueLengthB1;
+            unsigned char valueLengthB0;
+            unsigned char nameData[nameLength];
+            unsigned char valueData[valueLength
+                    ((B3 & 0x7f) << 24) + (B2 << 16) + (B1 << 8) + B0];
+        } FCGI_NameValuePair14;
+
+        typedef struct {
+            unsigned char nameLengthB3;  /* nameLengthB3  >> 7 == 1 */
+            unsigned char nameLengthB2;
+            unsigned char nameLengthB1;
+            unsigned char nameLengthB0;
+            unsigned char valueLengthB0; /* valueLengthB0 >> 7 == 0 */
+            unsigned char nameData[nameLength
+                    ((B3 & 0x7f) << 24) + (B2 << 16) + (B1 << 8) + B0];
+            unsigned char valueData[valueLength];
+        } FCGI_NameValuePair41;
+
+        typedef struct {
+            unsigned char nameLengthB3;  /* nameLengthB3  >> 7 == 1 */
+            unsigned char nameLengthB2;
+            unsigned char nameLengthB1;
+            unsigned char nameLengthB0;
+            unsigned char valueLengthB3; /* valueLengthB3 >> 7 == 1 */
+            unsigned char valueLengthB2;
+            unsigned char valueLengthB1;
+            unsigned char valueLengthB0;
+            unsigned char nameData[nameLength
+                    ((B3 & 0x7f) << 24) + (B2 << 16) + (B1 << 8) + B0];
+            unsigned char valueData[valueLength
+                    ((B3 & 0x7f) << 24) + (B2 << 16) + (B1 << 8) + B0];
+        } FCGI_NameValuePair44;
+
+

+ The high-order bit of the first byte of a length indicates the length's encoding. A high-order zero + implies a one-byte encoding, a one a four-byte encoding. +

+

+ This name-value pair format allows the sender to transmit binary values without additional encoding, and + enables the receiver to allocate the correct amount of storage immediately even for large values. +

+

+

+

+ 3.5 Closing Transport Connections +

+

+ The Web server controls the lifetime of transport connections. The Web server can close a connection when no + requests are active. Or the Web server can delegate close authority to the application (see + FCGI_BEGIN_REQUEST). In this case the application closes the connection at the end of a specified + request. +

+

+ This flexibility accommodates a variety of application styles. Simple applications will process one request at + a time and accept a new transport connection for each request. More complex applications will process + concurrent requests, over one or multiple transport connections, and will keep transport connections open for + long periods of time. +

+

+ A simple application gets a significant performance boost by closing the transport connection when it has + finished writing its response. The Web server needs to control the connection lifetime for long-lived + connections. +

+

+ When an application closes a connection or finds that a connection has closed, the application initiates a new + connection. +

+

+

+

+ 4. Management Record Types +

+

+ 4.1 FCGI_GET_VALUES, FCGI_GET_VALUES_RESULT +

+

+ The Web server can query specific variables within the application. The server will typically perform a query + on application startup in order to to automate certain aspects of system configuration. +

+

+ The application receives a query as a record {FCGI_GET_VALUES, 0, ...}. The contentData + portion of a FCGI_GET_VALUES record contains a sequence of name-value pairs with empty values. +

+

+ The application responds by sending a record {FCGI_GET_VALUES_RESULT, 0, ...} with the values + supplied. If the application doesn't understand a variable name that was included in the query, it omits + that name from the response. +

+

+ FCGI_GET_VALUES is designed to allow an open-ended set of variables. The initial set provides + information to help the server perform application and connection management: +

+

+

+
    +
  • + FCGI_MAX_CONNS: The maximum number of concurrent transport connections this application will + accept, e.g. "1" or "10". +

    +

    +
  • +
  • + FCGI_MAX_REQS: The maximum number of concurrent requests this application will accept, e.g. + "1" or "50". +

    +

    +
  • +
  • + FCGI_MPXS_CONNS: "0" if this application does not multiplex connections (i.e. + handle concurrent requests over each connection), "1" otherwise.
    +
    +
  • +
+

+ An application may receive a FCGI_GET_VALUES record at any time. The application's response + should not involve the application proper but only the FastCGI library. +

+

+

+

+ 4.2 FCGI_UNKNOWN_TYPE +

+

+ The set of management record types is likely to grow in future versions of this protocol. To provide for this + evolution, the protocol includes the FCGI_UNKNOWN_TYPE management record. When an application + receives a management record whose type T it does not understand, the application responds with + {FCGI_UNKNOWN_TYPE, 0, {T}}. +

+

+ The contentData component of a FCGI_UNKNOWN_TYPE record has the form: +

+
+        typedef struct {
+            unsigned char type;    
+            unsigned char reserved[7];
+        } FCGI_UnknownTypeBody;
+
+

+ The type component is the type of the unrecognized management record. +

+

+

+

+ 5. Application Record Types +

+

+ 5.1 FCGI_BEGIN_REQUEST +

+

+ The Web server sends a FCGI_BEGIN_REQUEST record to start a request. +

+

+ The contentData component of a FCGI_BEGIN_REQUEST record has the form: +

+
+        typedef struct {
+            unsigned char roleB1;
+            unsigned char roleB0;
+            unsigned char flags;
+            unsigned char reserved[5];
+        } FCGI_BeginRequestBody;
+
+

+ The role component sets the role the Web server expects the application to play. The + currently-defined roles are: +

+

+

+
    +
  • + FCGI_RESPONDER +
  • +
  • + FCGI_AUTHORIZER +
  • +
  • + FCGI_FILTER +
  • +
+

+ Roles are described in more detail in Section 6 below. +

+

+ The flags component contains a bit that controls connection shutdown: +

+

+

+
    +
  • + flags & FCGI_KEEP_CONN: If zero, the application closes the connection after responding to + this request. If not zero, the application does not close the connection after responding to this request; + the Web server retains responsibility for the connection.
    +
    +
  • +
+

+ 5.2 Name-Value Pair Stream: FCGI_PARAMS +

+ FCGI_PARAMS +

+ is a stream record type used in sending name-value pairs from the Web server to the application. The + name-value pairs are sent down the stream one after the other, in no specified order. +

+

+

+

+ 5.3 Byte Streams: FCGI_STDIN, FCGI_DATA, FCGI_STDOUT, + FCGI_STDERR +

+ FCGI_STDIN +

+ is a stream record type used in sending arbitrary data from the Web server to the application. + FCGI_DATA is a second stream record type used to send additional data to the application. +

+

+ FCGI_STDOUT and FCGI_STDERR are stream record types for sending arbitrary data and error + data respectively from the application to the Web server. +

+

+

+

+ 5.4 FCGI_ABORT_REQUEST +

+

+ The Web server sends a FCGI_ABORT_REQUEST record to abort a request. After receiving + {FCGI_ABORT_REQUEST, R}, the application responds as soon as possible with {FCGI_END_REQUEST, R, + {FCGI_REQUEST_COMPLETE, appStatus}}. This is truly a response from the application, not a low-level + acknowledgement from the FastCGI library. +

+

+ A Web server aborts a FastCGI request when an HTTP client closes its transport connection while the FastCGI + request is running on behalf of that client. The situation may seem unlikely; most FastCGI requests will have + short response times, with the Web server providing output buffering if the client is slow. But the FastCGI + application may be delayed communicating with another system, or performing a server push. +

+

+ When a Web server is not multiplexing requests over a transport connection, the Web server can abort a request + by closing the request's transport connection. But with multiplexed requests, closing the transport + connection has the unfortunate effect of aborting all the requests on the connection. +

+

+

+

+ 5.5 FCGI_END_REQUEST +

+

+ The application sends a FCGI_END_REQUEST record to terminate a request, either because the + application has processed the request or because the application has rejected the request. +

+

+ The contentData component of a FCGI_END_REQUEST record has the form: +

+
+        typedef struct {
+            unsigned char appStatusB3;
+            unsigned char appStatusB2;
+            unsigned char appStatusB1;
+            unsigned char appStatusB0;
+            unsigned char protocolStatus;
+            unsigned char reserved[3];
+        } FCGI_EndRequestBody;
+
+

+ The appStatus component is an application-level status code. Each role documents its usage of + appStatus. +

+

+ The protocolStatus component is a protocol-level status code; the possible protocolStatus + values are: +

+

+

+
    +
  • + FCGI_REQUEST_COMPLETE: normal end of request. +

    +

    +
  • +
  • + FCGI_CANT_MPX_CONN: rejecting a new request. This happens when a Web server sends concurrent + requests over one connection to an application that is designed to process one request at a time per + connection. +

    +

    +
  • +
  • + FCGI_OVERLOADED: rejecting a new request. This happens when the application runs out of some + resource, e.g. database connections. +

    +

    +
  • +
  • + FCGI_UNKNOWN_ROLE: rejecting a new request. This happens when the Web server has specified a role + that is unknown to the application.
    +
    +
  • +
+

+ 6. Roles +

+

+ 6.1 Role Protocols +

+

+ Role protocols only include records with application record types. They transfer essentially all data using + streams. +

+

+ To make the protocols reliable and to simplify application programming, role protocols are designed to use + nearly sequential marshalling. In a protocol with strictly sequential marshalling, the application + receives its first input, then its second, etc. until it has received them all. Similarly, the application + sends its first output, then its second, etc. until it has sent them all. Inputs are not interleaved with each + other, and outputs are not interleaved with each other. +

+

+ The sequential marshalling rule is too restrictive for some FastCGI roles, because CGI programs can write to + both stdout and stderr without timing restrictions. So role protocols that use both + FCGI_STDOUT and FCGI_STDERR allow these two streams to be interleaved. +

+

+ All role protocols use the FCGI_STDERR stream just the way stderr is used in conventional + applications programming: to report application-level errors in an intelligible way. Use of the + FCGI_STDERR stream is always optional. If an application has no errors to report, it sends either no + FCGI_STDERR records or one zero-length FCGI_STDERR record. +

+

+ When a role protocol calls for transmitting a stream other than FCGI_STDERR, at least one record of + the stream type is always transmitted, even if the stream is empty. +

+

+ Again in the interests of reliable protocols and simplified application programming, role protocols are + designed to be nearly request-response. In a truly request-response protocol, the application receives + all of its input records before sending its first output record. Request-response protocols don't allow + pipelining. +

+

+ The request-response rule is too restrictive for some FastCGI roles; after all, CGI programs aren't + restricted to read all of stdin before starting to write stdout. So some role protocols + allow that specific possibility. First the application receives all of its inputs except for a final stream + input. As the application begins to receive the final stream input, it can begin writing its output. +

+

+ When a role protocol uses FCGI_PARAMS to transmit textual values, such as the values that CGI + programs obtain from environment variables, the length of the value does not include the terminating null + byte, and the value itself does not include a null byte. An application that needs to provide + environ(7) format name-value pairs must insert an equal sign between the name and value and append a + null byte after the value. +

+

+ Role protocols do not support the non-parsed header feature of CGI. FastCGI applications set response status + using the Status and Location CGI headers. +

+

+

+

+ 6.2 Responder +

+

+ A Responder FastCGI application has the same purpose as a CGI/1.1 program: It receives all the information + associated with an HTTP request and generates an HTTP response. +

+

+ It suffices to explain how each element of CGI/1.1 is emulated by a Responder: +

+
+
+
    +
  • + The Responder application receives CGI/1.1 environment variables from the Web server over + FCGI_PARAMS. +

    +

    +
  • +
  • + Next the Responder application receives CGI/1.1 stdin data from the Web server over + FCGI_STDIN. The application receives at most CONTENT_LENGTH bytes from this stream before + receiving the end-of-stream indication. (The application receives less than CONTENT_LENGTH bytes + only if the HTTP client fails to provide them, e.g. because the client crashed.) +

    +

    +
  • +
  • + The Responder application sends CGI/1.1 stdout data to the Web server over FCGI_STDOUT, + and CGI/1.1 stderr data over FCGI_STDERR. The application sends these concurrently, not + one after the other. The application must wait to finish reading FCGI_PARAMS before it begins + writing FCGI_STDOUT and FCGI_STDERR, but it needn't finish reading from + FCGI_STDIN before it begins writing these two streams. +

    +

    +
  • +
  • + After sending all its stdout and stderr data, the Responder application sends a + FCGI_END_REQUEST record. The application sets the protocolStatus component to + FCGI_REQUEST_COMPLETE and the appStatus component to the status code that the CGI program + would have returned via the exit system call.
    +
    +
  • +
+

+ A Responder performing an update, e.g. implementing a POST method, should compare the number of bytes + received on FCGI_STDIN with CONTENT_LENGTH and abort the update if the two numbers are not + equal. +

+

+

+

+ 6.3 Authorizer +

+

+ An Authorizer FastCGI application receives all the information associated with an HTTP request and generates + an authorized/unauthorized decision. In case of an authorized decision the Authorizer can also associate + name-value pairs with the HTTP request; when giving an unauthorized decision the Authorizer sends a complete + response to the HTTP client. +

+

+ Since CGI/1.1 defines a perfectly good way to represent the information associated with an HTTP request, + Authorizers use the same representation: +

+

+

+
    +
  • + The Authorizer application receives HTTP request information from the Web server on the + FCGI_PARAMS stream, in the same format as a Responder. The Web server does not send + CONTENT_LENGTH, PATH_INFO, PATH_TRANSLATED, and SCRIPT_NAME headers. +

    +

    +
  • +
  • + The Authorizer application sends stdout and stderr data in the same manner as a + Responder. The CGI/1.1 response status specifies the disposition of the request. If the application sends + status 200 (OK), the Web server allows access. Depending upon its configuration the Web server may proceed + with other access checks, including requests to other Authorizers. +

    + An Authorizer application's 200 response may include headers whose names are prefixed with + Variable-. These headers communicate name-value pairs from the application to the Web server. + For instance, the response header +

    +
    +        Variable-AUTH_METHOD: database lookup
    +
    + transmits the value "database lookup" with name AUTH-METHOD. The server + associates such name-value pairs with the HTTP request and includes them in subsequent CGI or FastCGI + requests performed in processing the HTTP request. When the application gives a 200 response, the server + ignores response headers whose names aren't prefixed with Variable- prefix, and ignores any + response content. +

    + For Authorizer response status values other than "200" (OK), the Web server denies access and + sends the response status, headers, and content back to the HTTP client. +

    +
    +
    +
  • +
+

+ 6.4 Filter +

+

+ A Filter FastCGI application receives all the information associated with an HTTP request, plus an extra + stream of data from a file stored on the Web server, and generates a "filtered" version of the data + stream as an HTTP response. +

+

+ A Filter is similar in functionality to a Responder that takes a data file as a parameter. The difference is + that with a Filter, both the data file and the Filter itself can be access controlled using the Web + server's access control mechanisms, while a Responder that takes the name of a data file as a parameter + must perform its own access control checks on the data file. +

+

+ The steps taken by a Filter are similar to those of a Responder. The server presents the Filter with + environment variables first, then standard input (normally form POST data), finally the data file + input: +

+
+
+
    +
  • + Like a Responder, the Filter application receives name-value pairs from the Web server over + FCGI_PARAMS. Filter applications receive two Filter-specific variables: + FCGI_DATA_LAST_MOD and FCGI_DATA_LENGTH. +

    +

    +
  • +
  • + Next the Filter application receives CGI/1.1 stdin data from the Web server over + FCGI_STDIN. The application receives at most CONTENT_LENGTH bytes from this stream before + receiving the end-of-stream indication. (The application receives less than CONTENT_LENGTH bytes + only if the HTTP client fails to provide them, e.g. because the client crashed.) +

    +

    +
  • +
  • + Next the Filter application receives the file data from the Web server over FCGI_DATA. This + file's last modification time (expressed as an integer number of seconds since the epoch January 1, + 1970 UTC) is FCGI_DATA_LAST_MOD; the application may consult this variable and respond from a + cache without reading the file data. The application reads at most FCGI_DATA_LENGTH bytes from + this stream before receiving the end-of-stream indication. +

    +

    +
  • +
  • + The Filter application sends CGI/1.1 stdout data to the Web server over FCGI_STDOUT, and + CGI/1.1 stderr data over FCGI_STDERR. The application sends these concurrently, not one + after the other. The application must wait to finish reading FCGI_STDIN before it begins writing + FCGI_STDOUT and FCGI_STDERR, but it needn't finish reading from FCGI_DATA + before it begins writing these two streams. +

    +

    +
  • +
  • + After sending all its stdout and stderr data, the application sends a + FCGI_END_REQUEST record. The application sets the protocolStatus component to + FCGI_REQUEST_COMPLETE and the appStatus component to the status code that a similar CGI + program would have returned via the exit system call.
    +
    +
  • +
+

+ A Filter should compare the number of bytes received on FCGI_STDIN with CONTENT_LENGTH and + on FCGI_DATA with FCGI_DATA_LENGTH. If the numbers don't match and the Filter is a + query, the Filter response should provide an indication that data is missing. If the numbers don't match + and the Filter is an update, the Filter should abort the update. +

+

+

+

+ 7. Errors +

+

+ A FastCGI application exits with zero status to indicate that it terminated on purpose, e.g. in order to + perform a crude form of garbage collection. A FastCGI application that exits with nonzero status is assumed to + have crashed. How a Web server or other application manager responds to applications that exit with zero or + nonzero status is outside the scope of this specification. +

+

+ A Web server can request that a FastCGI application exit by sending it SIGTERM. If the application + ignores SIGTERM the Web server can resort to SIGKILL. +

+

+ FastCGI applications report application-level errors with the FCGI_STDERR stream and the + appStatus component of the FCGI_END_REQUEST record. In many cases an error will be reported + directly to the user via the FCGI_STDOUT stream. +

+

+ On Unix, applications report lower-level errors, including FastCGI protocol errors and syntax errors in + FastCGI environment variables, to syslog. Depending upon the severity of the error, the application + may either continue or exit with nonzero status. +

+

+

+

+ 8. Types and Constants +

+
+/*
+ * Listening socket file number
+ */
+#define FCGI_LISTENSOCK_FILENO 0
+
+typedef struct {
+    unsigned char version;
+    unsigned char type;
+    unsigned char requestIdB1;
+    unsigned char requestIdB0;
+    unsigned char contentLengthB1;
+    unsigned char contentLengthB0;
+    unsigned char paddingLength;
+    unsigned char reserved;
+} FCGI_Header;
+
+/*
+ * Number of bytes in a FCGI_Header.  Future versions of the protocol
+ * will not reduce this number.
+ */
+#define FCGI_HEADER_LEN  8
+
+/*
+ * Value for version component of FCGI_Header
+ */
+#define FCGI_VERSION_1           1
+
+/*
+ * Values for type component of FCGI_Header
+ */
+#define FCGI_BEGIN_REQUEST       1
+#define FCGI_ABORT_REQUEST       2
+#define FCGI_END_REQUEST         3
+#define FCGI_PARAMS              4
+#define FCGI_STDIN               5
+#define FCGI_STDOUT              6
+#define FCGI_STDERR              7
+#define FCGI_DATA                8
+#define FCGI_GET_VALUES          9
+#define FCGI_GET_VALUES_RESULT  10
+#define FCGI_UNKNOWN_TYPE       11
+#define FCGI_MAXTYPE (FCGI_UNKNOWN_TYPE)
+
+/*
+ * Value for requestId component of FCGI_Header
+ */
+#define FCGI_NULL_REQUEST_ID     0
+
+typedef struct {
+    unsigned char roleB1;
+    unsigned char roleB0;
+    unsigned char flags;
+    unsigned char reserved[5];
+} FCGI_BeginRequestBody;
+
+typedef struct {
+    FCGI_Header header;
+    FCGI_BeginRequestBody body;
+} FCGI_BeginRequestRecord;
+
+/*
+ * Mask for flags component of FCGI_BeginRequestBody
+ */
+#define FCGI_KEEP_CONN  1
+
+/*
+ * Values for role component of FCGI_BeginRequestBody
+ */
+#define FCGI_RESPONDER  1
+#define FCGI_AUTHORIZER 2
+#define FCGI_FILTER     3
+
+typedef struct {
+    unsigned char appStatusB3;
+    unsigned char appStatusB2;
+    unsigned char appStatusB1;
+    unsigned char appStatusB0;
+    unsigned char protocolStatus;
+    unsigned char reserved[3];
+} FCGI_EndRequestBody;
+
+typedef struct {
+    FCGI_Header header;
+    FCGI_EndRequestBody body;
+} FCGI_EndRequestRecord;
+
+/*
+ * Values for protocolStatus component of FCGI_EndRequestBody
+ */
+#define FCGI_REQUEST_COMPLETE 0
+#define FCGI_CANT_MPX_CONN    1
+#define FCGI_OVERLOADED       2
+#define FCGI_UNKNOWN_ROLE     3
+
+/*
+ * Variable names for FCGI_GET_VALUES / FCGI_GET_VALUES_RESULT records
+ */
+#define FCGI_MAX_CONNS  "FCGI_MAX_CONNS"
+#define FCGI_MAX_REQS   "FCGI_MAX_REQS"
+#define FCGI_MPXS_CONNS "FCGI_MPXS_CONNS"
+
+typedef struct {
+    unsigned char type;    
+    unsigned char reserved[7];
+} FCGI_UnknownTypeBody;
+
+typedef struct {
+    FCGI_Header header;
+    FCGI_UnknownTypeBody body;
+} FCGI_UnknownTypeRecord;
+
+

+

+

+ 9. References +

+

+ National Center for Supercomputer Applications, The Common Gateway + Interface, version CGI/1.1. +

+

+ D.R.T. Robinson, The WWW + Common Gateway Interface Version 1.1, Internet-Draft, 15 February 1996. +

+

+

+

+ A. Table: Properties of the record types +

+

+ The following chart lists all of the record types and indicates these properties of each: +

+

+

+
    +
  • + WS->App: records of this type can only be sent by the Web server to the application. Records of + other types can only be sent by the application to the Web server. +

    +

    +
  • +
  • + management: records of this type contain information that is not specific to a Web server request, + and use the null request ID. Records of other types contain request-specific information, and cannot use + the null request ID. +

    +

    +
  • +
  • + stream: records of this type form a stream, terminated by a record with empty + contentData. Records of other types are discrete; each carries a meaningful unit of data.
    +
    +
  • +
+
+                               WS->App   management  stream
+
+        FCGI_GET_VALUES           x          x
+        FCGI_GET_VALUES_RESULT               x
+        FCGI_UNKNOWN_TYPE                    x
+
+        FCGI_BEGIN_REQUEST        x
+        FCGI_ABORT_REQUEST        x
+        FCGI_END_REQUEST
+        FCGI_PARAMS               x                    x
+        FCGI_STDIN                x                    x
+        FCGI_DATA                 x                    x
+        FCGI_STDOUT                                    x 
+        FCGI_STDERR                                    x     
+
+
+
+

+

+

+ B. Typical Protocol Message Flow +

+

+ Additional notational conventions for the examples: +

+
    +
  • + The contentData of stream records (FCGI_PARAMS, FCGI_STDIN, + FCGI_STDOUT, and FCGI_STDERR) is represented as a character string. A string ending in + " ... " is too long to display, so only a prefix is shown. +
  • +
  • + Messages sent to the Web server are indented with respect to messages received from the Web server. +
  • +
  • + Messages are shown in the time sequence experienced by the application. +
  • +
+

+ 1. A simple request with no data on stdin, and a successful response: +

+
+{FCGI_BEGIN_REQUEST,   1, {FCGI_RESPONDER, 0}}
+{FCGI_PARAMS,          1, "\013\002SERVER_PORT80\013\016SERVER_ADDR199.170.183.42 ... "}
+{FCGI_PARAMS,          1, ""}
+{FCGI_STDIN,           1, ""}
+
+    {FCGI_STDOUT,      1, "Content-type: text/html\r\n\r\n<html>\n<head> ... "}
+    {FCGI_STDOUT,      1, ""}
+    {FCGI_END_REQUEST, 1, {0, FCGI_REQUEST_COMPLETE}}
+
+

+ 2. Similar to example 1, but this time with data on stdin. The Web server chooses to send the + parameters using more FCGI_PARAMS records than before: +

+
+{FCGI_BEGIN_REQUEST,   1, {FCGI_RESPONDER, 0}}
+{FCGI_PARAMS,          1, "\013\002SERVER_PORT80\013\016SER"}
+{FCGI_PARAMS,          1, "VER_ADDR199.170.183.42 ... "}
+{FCGI_PARAMS,          1, ""}
+{FCGI_STDIN,           1, "quantity=100&item=3047936"}
+{FCGI_STDIN,           1, ""}
+
+    {FCGI_STDOUT,      1, "Content-type: text/html\r\n\r\n<html>\n<head> ... "}
+    {FCGI_STDOUT,      1, ""}
+    {FCGI_END_REQUEST, 1, {0, FCGI_REQUEST_COMPLETE}}
+
+

+ 3. Similar to example 1, but this time the application detects an error. The application logs a message to + stderr, returns a page to the client, and returns non-zero exit status to the Web server. The + application chooses to send the page using more FCGI_STDOUT records: +

+
+{FCGI_BEGIN_REQUEST,   1, {FCGI_RESPONDER, 0}}
+{FCGI_PARAMS,          1, "\013\002SERVER_PORT80\013\016SERVER_ADDR199.170.183.42 ... "}
+{FCGI_PARAMS,          1, ""}
+{FCGI_STDIN,           1, ""}
+
+    {FCGI_STDOUT,      1, "Content-type: text/html\r\n\r\n<ht"}
+    {FCGI_STDERR,      1, "config error: missing SI_UID\n"}
+    {FCGI_STDOUT,      1, "ml>\n<head> ... "}
+    {FCGI_STDOUT,      1, ""}
+    {FCGI_STDERR,      1, ""}
+    {FCGI_END_REQUEST, 1, {938, FCGI_REQUEST_COMPLETE}}
+
+

+ 4. Two instances of example 1, multiplexed onto a single connection. The first request is more difficult than + the second, so the application finishes the requests out of order: +

+
+{FCGI_BEGIN_REQUEST,   1, {FCGI_RESPONDER, FCGI_KEEP_CONN}}
+{FCGI_PARAMS,          1, "\013\002SERVER_PORT80\013\016SERVER_ADDR199.170.183.42 ... "}
+{FCGI_PARAMS,          1, ""}
+{FCGI_BEGIN_REQUEST,   2, {FCGI_RESPONDER, FCGI_KEEP_CONN}}
+{FCGI_PARAMS,          2, "\013\002SERVER_PORT80\013\016SERVER_ADDR199.170.183.42 ... "}
+{FCGI_STDIN,           1, ""}
+
+    {FCGI_STDOUT,      1, "Content-type: text/html\r\n\r\n"}
+
+{FCGI_PARAMS,          2, ""}
+{FCGI_STDIN,           2, ""}
+
+    {FCGI_STDOUT,      2, "Content-type: text/html\r\n\r\n<html>\n<head> ... "}
+    {FCGI_STDOUT,      2, ""}
+    {FCGI_END_REQUEST, 2, {0, FCGI_REQUEST_COMPLETE}}
+    {FCGI_STDOUT,      1, "<html>\n<head> ... "}
+    {FCGI_STDOUT,      1, ""}
+    {FCGI_END_REQUEST, 1, {0, FCGI_REQUEST_COMPLETE}}
+
+

+

+
+
+ © 1995, 1996 Open Market, Inc. / mbrown@openmarket.com +
+ + + diff --git a/iipsrv/fcgi/doc/fcgi-tcl.htm b/iipsrv/fcgi/doc/fcgi-tcl.htm new file mode 100644 index 0000000..16dd767 --- /dev/null +++ b/iipsrv/fcgi/doc/fcgi-tcl.htm @@ -0,0 +1,366 @@ + + + + + Integrating FastCGI with Tcl + + + + +
+ [[FastCGI]] +
+
+
+

+ Integrating FastCGI with Tcl +

+
+ + + +

+ Michael S. Shanzer
+ Open Market, Inc.
+ 19 January 1995 +

+
+ Copyright © 1996 Open Market, Inc. 245 First Street, Cambridge, MA 02142 U.S.A.
+ Tel: 617-621-9500 Fax: 617-621-1703 URL: http://www.openmarket.com/
+ $Id: fcgi-tcl.htm,v 1.4 2002/02/25 00:42:59 robs Exp $
+
+
+

+ 1. Introduction +

+

+ Tcl (tool command language) is an embeddable scripting language that's often used for CGI programming. Tcl + is freely available as a source kit. +

+

+ We've built a Tcl interpreter that runs as a FastCGI application. Our purpose in doing so was twofold: +

+
    +
  • + Create a useful artifact. Open Market has written many CGI applications using Tcl. Now we'd like + to turn them into FastCGI applications. +

    +

    +
  • +
  • + Demonstrate how easy it is to integrate FastCGI with an existing program. The Tcl interpreter is a + substantial program, so integrating FastCGI with the Tcl interpreter is a good test of the + fcgi_stdio compatability library. +
  • +
+

+ We've succeeded on both counts. We now have a platform for migrating our Tcl-based CGI applications to + FastCGI. And the integration required a very small effort. The only source code change to the Tcl interpreter + was the routine addition of a handful of new commands: FCGI_Accept, FCGI_Finish, + FCGI_SetExitStatus, and FCGI_StartFilterData. +

+

+ The FastCGI-integrated Tcl interpreter works as usual when run from a shell or as a CGI program. You don't + need two Tcls, one for FastCGI and one for other uses. +

+

+ The remainder of this document gives a recipe you can follow to build FastCGI into Tcl, explains what's + happening in the recipe, and illustrates the use of FastCGI Tcl with an example program. +

+

+

+

+ 2. Recipe +

+

+ Here are the assumptions embedded in the following recipe: +

+
    +
  • + You are building Tcl 7.4p3, the current stable Tcl release as this is written. You unpack the Tcl kit into + a directory tcl7.4 that's a sibling of the FastCGI kit directory fcgi-devel-kit. +

    +

    +
  • +
  • + You have gcc version 2.7 installed on your system, and use it in the build. gcc is convenient because it + supports the -include command-line option that instructs the C preprocessor to include a specific + file before processing any other include files. This allows you to include fcgi_stdio.h without + modifying Tcl source files. (The reason for specifying gcc version 2.7 is that I have experienced bad + behavior with an earlier version and the -include flag -- the C preprocessor died with SIGABRT.) +

    +

    +
  • +
  • + You have GNU autoconf installed on your system. If you don't have GNU autoconf, you will have to make + certain edits by hand and repeat these edits for each build platform.
    +
    +
  • +
+

+ If those are valid assumptions, follow these steps: +

+
    +
  1. + Build the FastCGI Developer's Kit. Tcl needs to link against libfcgi.a, so build the FastCGI Developer's Kit in order to create this library for your + platform. +

    +

    +
  2. +
  3. + Pull the Tcl 7.4p3 kit. You'll need the files tcl7.4.tar.Z, tcl7.4p1.patch.gz, tcl7.4p2.patch.gz, and tcl7.4p3.patch.gz. (Some older Netscape browsers + can't perform these retrievals because of a protocol conflict between Netscape and Sun's firewall.) +

    + Unpack the tar file in the parent directory of the FastCGI kit directory you used in the previous step, + so that the directories tcl7.4 and fcgi-devel-kit are siblings. After unpacking the + tar file, follow the directions in the README to apply the patches. +

    +

    + The Sun Labs Tcl/Tk Project Page contains a wealth + of information on Tcl, including up to date information on the latest kits. +

    +

    +

    +
  4. +
  5. + Copy the files tclFCGI.c, tclAppInit.c, Makefile.in, and + configure.in from the FastCGI kit. +
    +    > cd tcl7.4
    +    > mv tclAppInit.c tclAppInit.c.orig
    +    > mv Makefile.in.orig Makefile.in.orig.orig
    +    > mv Makefile.in Makefile.in.orig
    +    > mv configure.in configure.in.orig
    +    > cp ../fcgi-devel-kit/tcl/tcl7.4/* .
    +    > cp ../fcgi-devel-kit/tcl/common/* .
    +
    +
  6. +
  7. + Create a new configure script. +
    +    > autoconf
    +
    +
  8. +
  9. + Configure and build. +
    +    > ./configure
    +    > make
    +
    + The make creates the Tcl interpreter tclsh and library archive libtcl.a (for + embedding Tcl in your own C applications). The Tcl README file explains how you can experiment + with tclsh without installing it in a standard place.
    +
    +
  10. +
+

+ 3. Recipe Explained +

+

+ The recipe alone is fine if you are using Tcl 7.4p3, you have gcc version 2.7, and you have GNU autoconf. In + case one or more of these assumptions doesn't hold for you, and to illuminate how little work was involved + in integrating FastCGI, here's an explanation of how and why you would modify the files + tclAppInit.c, Makefile.in, and configure.in from the Tcl kit. +

+
    +
  • + tclAppInit.c: +

    +

    +
      +
    • + Add the following three lines of code to the function Tcl_AppInit after the call to + Tcl_Init and after the comment about calling init procedures: +
      +    if (FCGI_Init(interp) == TCL_ERROR) {
      +        return TCL_ERROR;
      +    }
      +
      + This registers four Tcl commands (FCGI_Accept, FCGI_Finish, + FCGI_SetExitStatus, and FCGI_StartFilterData), implemented in tclFCGI.c, + with the Tcl interpreter. +

      +

      +
    • +
    +
  • +
  • + Makefile.in: +

    +

    +
      +
    • + Add tclFCGI.o to the GENERIC_OBJS variable, and add tclFCGI.c to the + SRCS variable. +

      + This builds the FastCGI Tcl commands and links them into the Tcl interpreter. +

      +

      +

      +
    • +
    • + Add -I../fcgi-devel-kit/include -include ../fcgi-devel-kit/include/fcgi_stdio.h to the + CFLAGS variable. +

      + This includes fcgi_stdio.h when compiling C code for the Tcl interpreter, overriding the + normal stdio types, variables, and functions. +

      +

      +

      +
    • +
    • + Add ../fcgi-devel-kit/libfcgi/libfcgi.a before the @LIBS@ part of the LIBS + variable. +

      + This links the implementation of fcgi_stdio.h into the Tcl interpreter, for use by the + FCGI_accept command and any code that uses stdio variables or calls + stdio functions. +

      +

      +

      +
    • +
    +

    + The last two edits will vary if you use a compiler other than gcc or install the tcl7.4 + directory somewhere else in relation to the fcgi-devel-kit directory. +

    +

    +

    +
  • +
  • + configure.in: +

    +

    +
      +
    • + Replace the lines +
      +AC_C_CROSS
      +CC=${CC-cc}
      +
      + with the lines +
      +AC_PROG_CC
      +AC_C_CROSS
      +
      + This selects gcc in preference to other C compilers. +

      +

      +
    • +
    • + Add the following lines just after the AC_SUBST(CC) line: +
      +AC_CHECK_LIB(socket, main, [LIBS="$LIBS -lsocket"])
      +AC_CHECK_LIB(nsl, main, [LIBS="$LIBS -lnsl"])
      +AC_SUBST(LIBS)
      +
      + This ensures that the socket libraries used by FastCGI are linked into the Tcl interpreter. +

      +

      +
    • +
    + If GNU autoconf is not available to you, you'll leave configure.in alone and perform the + following steps: +

    +

    +
      +
    • + Execute +
      +    > SETENV CC gcc
      +
      + before running configure. +

      +

      +
    • +
    • + If you are running on a SVR4-derived Unix platform, edit Makefile to add -lsocket + -lnsl to the LIBS value after running configure. +

      +

      +
    • +
    + If you ever re-run configure, you'll need to repeat these steps. +

    +

    +
  • +
+

+ 4. Writing FastCGI applications in Tcl +

+

+ The Tcl program tcl/tiny-tcl-fcgi performs the same function as the C program + examples/tiny-fcgi.c that's used as an example in the FastCGI + Developer's Kit document. Here's what the Tcl version looks like: +

+

+

+
+#!./tclsh
+set count 0 
+while {[FCGI_Accept] >= 0 } {
+    incr count
+    puts -nonewline "Content-type: text/html\r\n\r\n"
+    puts "<title>FastCGI Hello! (Tcl)</title>"
+    puts "<h1>FastCGI Hello! (Tcl)</h1>"
+    puts "Request number $count running on host <i>$env(SERVER_NAME)</i>"
+}
+
+

+ If you've built Tcl according to the recipe and you have a Web server set up to run FastCGI applications, + load the FastCGI Developer's Kit Index Page in that server and run this Tcl application now. +

+

+ The script invokes Tcl indirectly via the symbolic link examples/tclsh. It does this because HP-UX + has a limit of 32 characters for the first line of a command-interpreter file such as + examples/tiny-tcl-fcgi. If you run on HP-UX you won't want to sprinkle symbolic links to + tclsh everywhere, so you should install tclsh with a shorter pathname than + /usr/local/tcl7.4-fcgi/bin/tclsh7.4. +

+

+ The Tcl command FCGI_Accept treats the initial environment differently than the C function + FCGI_Accept. The first call to the C function FCGI_Accept replaces the initial environment + with the environment of the first request. The first call to the Tcl command FCGI_Accept adds the + variable bindings of the first request to the bindings present in the initial environment. So when the first + call to FCGI_Accept returns, bindings from the initial environment are still there (unless, due to + naming conflicts, some of them have been overwritten by the first request). The next call to + FCGI_Accept removes the bindings made on the previous call before adding a new set for the request + just accepted, again preserving the initial environment. +

+

+ The FastCGI-integrated tclsh also includes commands FCGI_Finish, + FCGI_SetExitStatus, and FCGI_StartFilterData that correspond to C functions in + fcgi_stdio.h; see the manpages for full information. +

+

+ Converting a Tcl CGI application to FastCGI is not fundamentally different from converting a C CGI + application. You separate the portion of the application that performs one-time initialization from the + portion that performs per-request processing. You put the per-request processing into a loop controlled by + FCGI_Accept. +

+

+

+
+
+ Mike Shanzer // shanzer@openmarket.com +
+ + + diff --git a/iipsrv/fcgi/doc/omi-logo.gif b/iipsrv/fcgi/doc/omi-logo.gif new file mode 100644 index 0000000000000000000000000000000000000000..00bda568029eb15c19a2800077417158c4282e8d GIT binary patch literal 217 zcmZ?wbhEHbv|>zJUGoc7||vJ~%)MrM~6@s=;25y@viJ<~L=NxE + + + + FastCGI Developer's Kit Index Page + + + + +
+

+ FastCGI Developer's Kit +

+
+ + + + +
    +
  • + doc +
      +
    • + FastCGI Technical White Paper Motivates FastCGI, then + explains the FastCGI interface, FastCGI application roles, the FastCGI application library, server + support for FastCGI, and FastCGI performance. +
    • +
    • + Understanding FastCGI Application Performance Why FastCGI applications + often run faster than applications coded directly to Web server APIs. +
    • +
    • + FastCGI Developer's Kit
      + +
        +
      • + How to configure and build the kit for your development platform. +
      • +
      • + How to write applications using the libraries in the kit. +
      • +
      • + Documents cgi-fcgi, a tool in the kit that allows you to develop and test FastCGI + applications using a Web server that lacks FastCGI support. +
      • +
      +
    • +
    • + Open Market FastCGI 1.0 Programmer's Guide + Programmer-oriented documentation for developers of applications that run on the Open Market's + Secure WebServer 2.0. The content overlaps considerably with Section 3 of the Developer's Kit + document. +
    • +
    • + FCGI_Accept.3, FCGI_Finish.3, FCGI_SetExitStatus.3, FCGI_StartFilterData.3, and cgi-fcgi.1 + manpages. +
    • +
    • + Integrating FastCGI with Perl How to build FastCGI support into the Perl + interpreter and how to write FastCGI applications in Perl. +
    • +
    • + Integrating FastCGI with Tcl How to build FastCGI support into the Tcl + interpreter and how to write FastCGI applications in Tcl. +
    • +
    • + Integrating FastCGI with Java How to build Web server applications in + Java using FastCGI. +
    • +
    • + FastCGI: A High-Performance Gateway Interface Position paper + presented at the workshop "Programming the Web -- a search for APIs", Fifth International + World Wide Web Conference, 6 May 1996, Paris, France. A short paper, addressed to an audience of + technical specialists. +
    • +
    • + FastCGI Specification document.
      + Defines the interface between a FastCGI application and a Web server that supports FastCGI. This is + dry stuff, not needed for writing applications! +
    • +
    +
  • +
  • + include .h files for the FastCGI libraries. +
  • +
  • + libfcgi .c files for the FastCGI libraries. +
  • +
  • + examples Several example FastCGI programs. +
  • +
  • + perl The FastCGI Perl module, FCGI.pm. +
  • +
  • + java The FastCGI Java library. +
  • +
  • + cgi-fcgi The CGI-to-FastCGI bridge source code. +
  • +
+
+
+ © 1996, Open Market, Inc. +
+ + + diff --git a/iipsrv/fcgi/doc/www5-api-workshop.html b/iipsrv/fcgi/doc/www5-api-workshop.html new file mode 100644 index 0000000..66945ae --- /dev/null +++ b/iipsrv/fcgi/doc/www5-api-workshop.html @@ -0,0 +1,269 @@ + + + + + FastCGI: A High-Performance Gateway Interface + + + + +
+

+ FastCGI: A High-Performance Gateway Interface +

+ Position paper for the workshop "Programming the Web - a search for APIs",
+ Fifth International World Wide Web Conference, 6 May 1996, Paris, France.
+

+ Mark R. Brown
+ Open Market, Inc.
+

+

+ 2 May 1996
+

+
+

+

+
+ Copyright © 1996 Open Market, Inc. 245 First Street, Cambridge, MA 02142 U.S.A.
+ Tel: 617-621-9500 Fax: 617-621-1703 URL: http://www.openmarket.com/
+
+
+

+ Abstract +

+

+ FastCGI is a fast, open, and secure Web server interface that solves the performance problems inherent in CGI + without introducing any of the new problems associated with writing applications to lower-level Web server + APIs. Modules to support FastCGI can be plugged into Web server APIs such as Apache API, NSAPI, and ISAPI. Key + considerations in designing FastCGI included minimizing the cost of migrating CGI applications (including + applications written in popular scripting languages such as Perl), supporting both single-threaded and + multi-threaded application programming, supporting distributed configurations for scaling and high + availability, and generalizing the roles that gateway applications can play beyond CGI's + "responder" role. +

+

+ For more information on FastCGI, including an interface specification and a module for the Apache server, + visit the www.fastcgi.com Web site. +

+

+ 1. Introduction +

+

+ The surge in the use of the Web by business has created great demand for applications that create dynamic + content. These applications allow businesses to deliver products, services, and messages whose shape and + content are influenced by interaction with and knowledge of users. +

+

+ This move towards dynamic Web content has highlighted the performance limits of CGI (Common Gateway + Interface). In response there has been a proliferation of Web server APIs. These APIs address some (though not + all) of the performance problems with CGI, but are not designed to meet the need of business applications. + When applied to business applications, Web server APIs suffer from these problems: +

+
    +
  • + Complexity. Server APIs introduce a steep learning curve, with increased implementation and + maintenance costs. +
  • +
  • + Language dependence. Applications have to be written in a language supported by the server API + (usually C/C++). Perl, the most popular language for CGI programs, can't be used with any existing + server API. +
  • +
  • + No process isolation. Since the applications run in the server's address space, buggy + applications can corrupt the core server (or each other). A malicious or buggy application can compromise + server security, and bugs in the core server can corrupt applications. +
  • +
  • + Proprietary. Coding your application to a particular API locks you into a particular server. +
  • +
  • + Tie-in to server architecture. API applications have to share the same architecture as the server: + If the Web server is multi-threaded, the application has to be thread-safe. If the Web server has + single-threaded processes, multi-threaded applications don't gain any performance advantage. Also, when + the server's architecture changes, the API will usually have to change, and applications will have to + be adapted or rewritten. +
  • +
+

+ Web server APIs are suitable for applications that require an intimate connection to the core Web server, such + as security protocols. But using a Web server API for a Web business application would be much like using an + old-fashioned TP monitor, which required linking applications right into the monitor, for a modern business + transaction processing application. The old-fashioned solution suffers a huge development and maintenance cost + penalty because it ignores 30 years of progress in computing technology, and may end up providing inferior + performance to boot. Nobody uses the old technology unless they are already locked into it. +

+

+ FastCGI is best viewed as a new implementation of CGI, designed to overcome CGI's performance problems. + The major implementation differences are: +

+
    +
  • + FastCGI processes are persistent: after finishing a request, they wait for a new request instead of + exiting. +
  • +
  • + Instead of using operating system environment variables and pipes, the FastCGI protocol multiplexes the + environment information, standard input, output, and error over a single full-duplex connection. This + allows FastCGI programs to run on remote machines, using TCP connections between the Web server and the + FastCGI application. +
  • +
+

+ FastCGI communicates the exact same information as CGI in a different way. Because FastCGI is CGI, and + like CGI runs applications in separate processes, it suffers none of the server API problems listed above. +

+

+ 2. Migration from CGI +

+

+ Open Market has developed a FastCGI application library that implements the FastCGI protocol, hiding the + protocol details from the developer. This library, which is freely available, makes writing FastCGI programs + as easy as writing CGI applications. +

+

+ The application library provides replacements for the C language standard I/O (stdio) routines such as + printf() and gets(). The library converts references to environment variables, standard + input, standard output, and standard error to the FastCGI protocol. References to other files "fall + through" to the underlying operating system standard I/O routines. This approach has several benefits: +

+
    +
  • + Developers don't have to learn a new API to develop FastCGI applications. +
  • +
  • + Existing CGI programs can be migrated with minimal source changes. +
  • +
  • + FastCGI interpreters for Perl, Tcl, and other interpreted languages can be built without modifying the + interpreter source code. +
  • +
+

+ Here's a simple FastCGI application: +

+
+
+
+    #include <fcgi_stdio.h>
+
+    void main(void)
+    {
+        int count = 0;
+        while(FCGI_Accept() >= 0) {
+            printf("Content-type: text/html\r\n");
+            printf("\r\n");
+            printf("Hello world!<br>\r\n");
+            printf("Request number %d.", count++);
+        }
+        exit(0);
+    }
+
+

+ This application returns a "Hello world" HTML response to the client. It also keeps a counter of the + number of times it has been accessed, displaying the value of the counter at each request. The + fcgi_stdio.h header file provides the FastCGI replacement routines for the C standard I/O library. + The FCGI_Accept() routine accepts a new request from the Web server. +

+

+ The application library was designed to make migration of existing CGI programs as simple as possible. Many + applications can be converted by adding a loop around the main request processing code and recompiling with + the FastCGI application library. To ease migration to FastCGI, executables built with the application library + can run as either CGI or FastCGI programs, depending on how they are invoked. The library detects the + execution environment and automatically selects FastCGI or regular I/O routines, as appropriate. +

+

+ Applications written in Perl, Tcl, and other scripting languages can be migrated by using a language + interpreter built with the application library. FastCGI-integrated Tcl and Perl interpreters for popular Unix + platforms are available from the www.fastcgi.com Web site. The interpreters are backward-compatible: + They can run standard Tcl and Perl applications. +

+

+ 3. Single-threaded and multi-threaded applications +

+

+ FastCGI gives developers a free choice of whether to develop applications in a single-threaded or + multi-threaded style. The FastCGI interface supports multi-threading in two ways: +

+
    +
  • + Applications can accept concurrent Web server connections to provide concurrent requests to multiple + application threads. +
  • +
  • + Applications can accept multiplexed Web server connections, in which concurrent requests are communicated + over a single connection to multiple application threads. +
  • +
+

+ Multi-threaded programming is complex -- concurrency makes programs difficult to test and debug -- so many + developers will prefer to program in the familiar single-threaded style. By having several concurrent + processes running the same application it is often possible to achieve high performance with single-threaded + programming. +

+

+ The FastCGI interface allows Web servers to implement session affinity, a feature that allows + applications to maintain caches of user-related data. With session affinity, when several concurrent processes + are running the same application, the Web server routes all requests from a particular user to the same + application process. Web server APIs don't provide this functionality to single-threaded applications, so + the performance of an API-based application is often inferior to the performance of the corresponding FastCGI + application. +

+

+ 4. Distributed FastCGI +

+

+ Because FastCGI can communicate over TCP/IP connections, it supports configurations in which applications run + remotely from the Web server. This can provide scaling, load balancing, high availability, and connections to + systems that don't have Web servers. +

+

+ Distributed FastCGI can also provide security advantages. A Web server outside a corporate firewall can + communicate through the firewall to internal databases. For instance, an application might need to + authenticate incoming users as customers in order to give access to certain documents on the external Web + site. With FastCGI this authentication can be done without replicating data and without compromising security. +

+

+ 5. Roles +

+

+ A problem with CGI is its limited functionality: CGI programs can only provide responses to requests. FastCGI + provides expanded functionality with support for three different application "roles": +

+
    +
  • + Responder. This is the basic FastCGI role, and corresponds to the simple functionality offered by + CGI today. +
  • +
  • + Filter. The FastCGI application filters the requested Web server file before sending it to the + client. +
  • +
  • + Authorizer. The FastCGI program performs an access control decision for the request (such as + performing a username/password database lookup). +
  • +
+

+ Other roles will be defined in the future. For instance, a "logger" role would be useful, where the + FastCGI program would receive the server's log entries for real-time processing and analysis. +

+

+ 6. Conclusions +

+

+ Today's Web business applications need a platform that's fast, open, maintainable, straightforward, + stable, and secure. FastCGI's design meets these requirements, and provides a logical migration path from + the proven and widely deployed CGI technology. This allows developers to take advantage of FastCGI's + benefits without losing their existing investment in CGI applications. +

+

+ For more information about FastCGI, visit the www.fastcgi.com Web site. +

+ + + diff --git a/iipsrv/fcgi/examples/authorizer.mak b/iipsrv/fcgi/examples/authorizer.mak new file mode 100644 index 0000000..084b3f8 --- /dev/null +++ b/iipsrv/fcgi/examples/authorizer.mak @@ -0,0 +1,203 @@ +# Microsoft Developer Studio Generated NMAKE File, Based on authorizer.dsp + +!IF "$(CFG)" == "" +CFG=release +!ENDIF + +!IF "$(CFG)" != "release" && "$(CFG)" != "debug" +!MESSAGE Invalid configuration "$(CFG)" specified. +!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 "authorizer.mak" CFG="debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "release" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE "debug" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE +!ERROR An invalid configuration is specified. +!ENDIF + +!IF "$(OS)" == "Windows_NT" +NULL= +!ELSE +NULL=nul +!ENDIF + +!IF "$(CFG)" == "release" + +OUTDIR=.\..\examples\authorizer\Release +INTDIR=.\..\examples\authorizer\Release +# Begin Custom Macros +OutDir=.\..\examples\authorizer\Release +# End Custom Macros + +ALL : "$(OUTDIR)\authorizer.exe" + +CLEAN : + -@erase "$(INTDIR)\authorizer.obj" + -@erase "$(INTDIR)\vc60.idb" + -@erase "$(OUTDIR)\authorizer.exe" + +"$(OUTDIR)" : + if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)" + +CPP=cl.exe +CPP_PROJ=/nologo /MD /W3 /Gi /O2 /Ob2 /I "..\include" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /Fp"$(INTDIR)\authorizer.pch" /YX /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\\" /FD /c + +.c{$(INTDIR)}.obj:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.cpp{$(INTDIR)}.obj:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.cxx{$(INTDIR)}.obj:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.c{$(INTDIR)}.sbr:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.cpp{$(INTDIR)}.sbr:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.cxx{$(INTDIR)}.sbr:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +MTL=midl.exe +MTL_PROJ=/nologo /D "NDEBUG" /mktyplib203 /win32 +RSC=rc.exe +BSC32=bscmake.exe +BSC32_FLAGS=/nologo /o"$(OUTDIR)\authorizer.bsc" +BSC32_SBRS= \ + +LINK32=link.exe +LINK32_FLAGS=libfcgi.lib /nologo /pdb:none /machine:IX86 /out:"$(OUTDIR)\authorizer.exe" /libpath:"..\libfcgi\Release" +LINK32_OBJS= \ + "$(INTDIR)\authorizer.obj" \ + "..\libfcgi\Release\libfcgi.lib" + +"$(OUTDIR)\authorizer.exe" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS) + $(LINK32) @<< + $(LINK32_FLAGS) $(LINK32_OBJS) +<< + +!ELSEIF "$(CFG)" == "debug" + +OUTDIR=.\..\examples/authorizer/Debug +INTDIR=.\..\examples/authorizer/Debug +# Begin Custom Macros +OutDir=.\..\examples/authorizer/Debug +# End Custom Macros + +ALL : "$(OUTDIR)\authorizer.exe" "$(OUTDIR)\authorizer.bsc" + +CLEAN : + -@erase "$(INTDIR)\authorizer.obj" + -@erase "$(INTDIR)\authorizer.sbr" + -@erase "$(INTDIR)\vc60.idb" + -@erase "$(INTDIR)\vc60.pdb" + -@erase "$(OUTDIR)\authorizer.bsc" + -@erase "$(OUTDIR)\authorizer.exe" + +"$(OUTDIR)" : + if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)" + +CPP=cl.exe +CPP_PROJ=/nologo /MDd /W4 /Gm /Gi /ZI /Od /I "..\include" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /FR"$(INTDIR)\\" /Fp"$(INTDIR)\authorizer.pch" /YX /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\\" /FD /GZ /c + +.c{$(INTDIR)}.obj:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.cpp{$(INTDIR)}.obj:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.cxx{$(INTDIR)}.obj:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.c{$(INTDIR)}.sbr:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.cpp{$(INTDIR)}.sbr:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.cxx{$(INTDIR)}.sbr:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +MTL=midl.exe +MTL_PROJ=/nologo /D "_DEBUG" /mktyplib203 /win32 +RSC=rc.exe +BSC32=bscmake.exe +BSC32_FLAGS=/nologo /o"$(OUTDIR)\authorizer.bsc" +BSC32_SBRS= \ + "$(INTDIR)\authorizer.sbr" + +"$(OUTDIR)\authorizer.bsc" : "$(OUTDIR)" $(BSC32_SBRS) + $(BSC32) @<< + $(BSC32_FLAGS) $(BSC32_SBRS) +<< + +LINK32=link.exe +LINK32_FLAGS=libfcgi.lib /nologo /profile /debug /machine:IX86 /out:"$(OUTDIR)\authorizer.exe" /libpath:"..\libfcgi\Debug" +LINK32_OBJS= \ + "$(INTDIR)\authorizer.obj" \ + "..\libfcgi\Debug\libfcgi.lib" + +"$(OUTDIR)\authorizer.exe" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS) + $(LINK32) @<< + $(LINK32_FLAGS) $(LINK32_OBJS) +<< + +!ENDIF + + +..\examples\authorizer.c : \ + "..\include\fcgi_stdio.h"\ + "..\include\fcgiapp.h"\ + + +!IF "$(CFG)" == "release" || "$(CFG)" == "debug" +SOURCE=..\examples\authorizer.c + +!IF "$(CFG)" == "release" + + +"$(INTDIR)\authorizer.obj" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +!ELSEIF "$(CFG)" == "debug" + + +"$(INTDIR)\authorizer.obj" "$(INTDIR)\authorizer.sbr" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +!ENDIF + +!ENDIF + diff --git a/iipsrv/fcgi/examples/echo-cpp.mak b/iipsrv/fcgi/examples/echo-cpp.mak new file mode 100644 index 0000000..62910ad --- /dev/null +++ b/iipsrv/fcgi/examples/echo-cpp.mak @@ -0,0 +1,203 @@ +# Microsoft Developer Studio Generated NMAKE File, Based on echo-cpp.dsp +!IF "$(CFG)" == "" +CFG=release +!ENDIF + +!IF "$(CFG)" != "release" && "$(CFG)" != "debug" +!MESSAGE Invalid configuration "$(CFG)" specified. +!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 "echo-cpp.mak" CFG="debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "release" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE "debug" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE +!ERROR An invalid configuration is specified. +!ENDIF + +!IF "$(OS)" == "Windows_NT" +NULL= +!ELSE +NULL=nul +!ENDIF + +!IF "$(CFG)" == "release" + +OUTDIR=.\..\examples\echo-cpp\Release +INTDIR=.\..\examples\echo-cpp\Release +# Begin Custom Macros +OutDir=.\..\examples\echo-cpp\Release +# End Custom Macros + +ALL : "$(OUTDIR)\echo-cpp.exe" + + +CLEAN : + -@erase "$(INTDIR)\echo-cpp.obj" + -@erase "$(INTDIR)\vc60.idb" + -@erase "$(OUTDIR)\echo-cpp.exe" + +"$(OUTDIR)" : + if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)" + +CPP=cl.exe +CPP_PROJ=/nologo /MD /W3 /Gi /GX /O2 /Ob2 /I "..\include" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /Fp"$(INTDIR)\echo-cpp.pch" /YX /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\\" /FD /c + +.c{$(INTDIR)}.obj:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.cpp{$(INTDIR)}.obj:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.cxx{$(INTDIR)}.obj:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.c{$(INTDIR)}.sbr:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.cpp{$(INTDIR)}.sbr:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.cxx{$(INTDIR)}.sbr:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +MTL=midl.exe +MTL_PROJ=/nologo /D "NDEBUG" /mktyplib203 /win32 +RSC=rc.exe +BSC32=bscmake.exe +BSC32_FLAGS=/nologo /o"$(OUTDIR)\echo-cpp.bsc" +BSC32_SBRS= \ + +LINK32=link.exe +LINK32_FLAGS=libfcgi.lib /nologo /pdb:none /machine:IX86 /out:"$(OUTDIR)\echo-cpp.exe" /libpath:"..\libfcgi\Release" +LINK32_OBJS= \ + "$(INTDIR)\echo-cpp.obj" + +"$(OUTDIR)\echo-cpp.exe" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS) + $(LINK32) @<< + $(LINK32_FLAGS) $(LINK32_OBJS) +<< + +!ELSEIF "$(CFG)" == "debug" + +OUTDIR=.\../examples/echo-cpp\Debug +INTDIR=.\../examples/echo-cpp\Debug +# Begin Custom Macros +OutDir=.\../examples/echo-cpp\Debug +# End Custom Macros + +ALL : "$(OUTDIR)\echo-cpp.exe" "$(OUTDIR)\echo-cpp.bsc" + + +CLEAN : + -@erase "$(INTDIR)\echo-cpp.obj" + -@erase "$(INTDIR)\echo-cpp.sbr" + -@erase "$(INTDIR)\vc60.idb" + -@erase "$(INTDIR)\vc60.pdb" + -@erase "$(OUTDIR)\echo-cpp.bsc" + -@erase "$(OUTDIR)\echo-cpp.exe" + +"$(OUTDIR)" : + if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)" + +CPP=cl.exe +CPP_PROJ=/nologo /MDd /W3 /Gm /Gi /GX /ZI /Od /I "..\include" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /FR"$(INTDIR)\\" /Fp"$(INTDIR)\echo-cpp.pch" /YX /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\\" /FD /GZ /c + +.c{$(INTDIR)}.obj:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.cpp{$(INTDIR)}.obj:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.cxx{$(INTDIR)}.obj:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.c{$(INTDIR)}.sbr:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.cpp{$(INTDIR)}.sbr:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.cxx{$(INTDIR)}.sbr:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +MTL=midl.exe +MTL_PROJ=/nologo /D "_DEBUG" /mktyplib203 /win32 +RSC=rc.exe +BSC32=bscmake.exe +BSC32_FLAGS=/nologo /o"$(OUTDIR)\echo-cpp.bsc" +BSC32_SBRS= \ + "$(INTDIR)\echo-cpp.sbr" + +"$(OUTDIR)\echo-cpp.bsc" : "$(OUTDIR)" $(BSC32_SBRS) + $(BSC32) @<< + $(BSC32_FLAGS) $(BSC32_SBRS) +<< + +LINK32=link.exe +LINK32_FLAGS=libfcgi.lib /nologo /profile /debug /machine:IX86 /out:"$(OUTDIR)\echo-cpp.exe" /libpath:"..\libfcgi\Debug" +LINK32_OBJS= \ + "$(INTDIR)\echo-cpp.obj" + +"$(OUTDIR)\echo-cpp.exe" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS) + $(LINK32) @<< + $(LINK32_FLAGS) $(LINK32_OBJS) +<< + +!ENDIF + + +"..\examples\echo-cpp.cpp" : \ + "..\include\fcgiapp.h"\ + "..\include\fcgio.h"\ + + +!IF "$(CFG)" == "release" || "$(CFG)" == "debug" +SOURCE="..\examples\echo-cpp.cpp" + +!IF "$(CFG)" == "release" + + +"$(INTDIR)\echo-cpp.obj" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +!ELSEIF "$(CFG)" == "debug" + + +"$(INTDIR)\echo-cpp.obj" "$(INTDIR)\echo-cpp.sbr" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +!ENDIF + + +!ENDIF + diff --git a/iipsrv/fcgi/examples/echo.mak b/iipsrv/fcgi/examples/echo.mak new file mode 100644 index 0000000..cf3e7e6 --- /dev/null +++ b/iipsrv/fcgi/examples/echo.mak @@ -0,0 +1,205 @@ +# Microsoft Developer Studio Generated NMAKE File, Based on echo.dsp + +!IF "$(CFG)" == "" +CFG=release +!ENDIF + +!IF "$(CFG)" != "release" && "$(CFG)" != "debug" +!MESSAGE Invalid configuration "$(CFG)" specified. +!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 "echo.mak" CFG="debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "release" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE "debug" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE +!ERROR An invalid configuration is specified. +!ENDIF + +!IF "$(OS)" == "Windows_NT" +NULL= +!ELSE +NULL=nul +!ENDIF + +!IF "$(CFG)" == "release" + +OUTDIR=.\..\examples\echo\Release +INTDIR=.\..\examples\echo\Release +# Begin Custom Macros +OutDir=.\..\examples\echo\Release +# End Custom Macros + +ALL : "$(OUTDIR)\echo.exe" + +CLEAN : + -@erase "$(INTDIR)\echo.obj" + -@erase "$(INTDIR)\vc60.idb" + -@erase "$(OUTDIR)\echo.exe" + +"$(OUTDIR)" : + if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)" + +CPP=cl.exe +CPP_PROJ=/nologo /MD /W3 /Gi /O2 /Ob2 /I "..\include" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /Fp"$(INTDIR)\echo.pch" /YX /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\\" /FD /c + +.c{$(INTDIR)}.obj:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.cpp{$(INTDIR)}.obj:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.cxx{$(INTDIR)}.obj:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.c{$(INTDIR)}.sbr:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.cpp{$(INTDIR)}.sbr:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.cxx{$(INTDIR)}.sbr:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +MTL=midl.exe +MTL_PROJ=/nologo /D "NDEBUG" /mktyplib203 /win32 +RSC=rc.exe +BSC32=bscmake.exe +BSC32_FLAGS=/nologo /o"$(OUTDIR)\echo.bsc" +BSC32_SBRS= \ + +LINK32=link.exe +LINK32_FLAGS=libfcgi.lib /nologo /pdb:none /machine:IX86 /out:"$(OUTDIR)\echo.exe" /libpath:"..\libfcgi\Release" +LINK32_OBJS= \ + "$(INTDIR)\echo.obj" \ + "..\libfcgi\Release\libfcgi.lib" + +"$(OUTDIR)\echo.exe" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS) + $(LINK32) @<< + $(LINK32_FLAGS) $(LINK32_OBJS) +<< + +!ELSEIF "$(CFG)" == "debug" + +OUTDIR=.\../examples/echo\Debug +INTDIR=.\../examples/echo\Debug +# Begin Custom Macros +OutDir=.\../examples/echo\Debug +# End Custom Macros + +ALL : "$(OUTDIR)\echo.exe" "$(OUTDIR)\echo.bsc" + +CLEAN : + -@erase "$(INTDIR)\echo.obj" + -@erase "$(INTDIR)\echo.sbr" + -@erase "$(INTDIR)\vc60.idb" + -@erase "$(INTDIR)\vc60.pdb" + -@erase "$(OUTDIR)\echo.bsc" + -@erase "$(OUTDIR)\echo.exe" + -@erase "$(OUTDIR)\echo.map" + +"$(OUTDIR)" : + if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)" + +CPP=cl.exe +CPP_PROJ=/nologo /MDd /W4 /Gm /Gi /ZI /Od /I "..\include" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /FR"$(INTDIR)\\" /Fp"$(INTDIR)\echo.pch" /YX /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\\" /FD /GZ /c + +.c{$(INTDIR)}.obj:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.cpp{$(INTDIR)}.obj:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.cxx{$(INTDIR)}.obj:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.c{$(INTDIR)}.sbr:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.cpp{$(INTDIR)}.sbr:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.cxx{$(INTDIR)}.sbr:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +MTL=midl.exe +MTL_PROJ=/nologo /D "_DEBUG" /mktyplib203 /win32 +RSC=rc.exe +BSC32=bscmake.exe +BSC32_FLAGS=/nologo /o"$(OUTDIR)\echo.bsc" +BSC32_SBRS= \ + "$(INTDIR)\echo.sbr" + +"$(OUTDIR)\echo.bsc" : "$(OUTDIR)" $(BSC32_SBRS) + $(BSC32) @<< + $(BSC32_FLAGS) $(BSC32_SBRS) +<< + +LINK32=link.exe +LINK32_FLAGS=libfcgi.lib /nologo /profile /map:"$(INTDIR)\echo.map" /debug /machine:IX86 /out:"$(OUTDIR)\echo.exe" /libpath:"..\libfcgi\Debug" +LINK32_OBJS= \ + "$(INTDIR)\echo.obj" \ + "..\libfcgi\Debug\libfcgi.lib" + +"$(OUTDIR)\echo.exe" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS) + $(LINK32) @<< + $(LINK32_FLAGS) $(LINK32_OBJS) +<< + +!ENDIF + + +..\examples\echo.c : \ + "..\include\fcgi_config.h"\ + "..\include\fcgi_stdio.h"\ + "..\include\fcgiapp.h"\ + + +!IF "$(CFG)" == "release" || "$(CFG)" == "debug" +SOURCE=..\examples\echo.c + +!IF "$(CFG)" == "release" + + +"$(INTDIR)\echo.obj" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +!ELSEIF "$(CFG)" == "debug" + + +"$(INTDIR)\echo.obj" "$(INTDIR)\echo.sbr" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +!ENDIF + +!ENDIF + diff --git a/iipsrv/fcgi/examples/echox.mak b/iipsrv/fcgi/examples/echox.mak new file mode 100644 index 0000000..37876e2 --- /dev/null +++ b/iipsrv/fcgi/examples/echox.mak @@ -0,0 +1,203 @@ +# Microsoft Developer Studio Generated NMAKE File, Based on echox.dsp + +!IF "$(CFG)" == "" +CFG=release +!ENDIF + +!IF "$(CFG)" != "release" && "$(CFG)" != "debug" +!MESSAGE Invalid configuration "$(CFG)" specified. +!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 "echox.mak" CFG="debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "release" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE "debug" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE +!ERROR An invalid configuration is specified. +!ENDIF + +!IF "$(OS)" == "Windows_NT" +NULL= +!ELSE +NULL=nul +!ENDIF + +!IF "$(CFG)" == "release" + +OUTDIR=.\..\examples\echo-x\Release +INTDIR=.\..\examples\echo-x\Release +# Begin Custom Macros +OutDir=.\..\examples\echo-x\Release +# End Custom Macros + +ALL : "$(OUTDIR)\echo-x.exe" + +CLEAN : + -@erase "$(INTDIR)\echo-x.obj" + -@erase "$(INTDIR)\vc60.idb" + -@erase "$(OUTDIR)\echo-x.exe" + +"$(OUTDIR)" : + if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)" + +CPP=cl.exe +CPP_PROJ=/nologo /MD /W3 /Gi /O2 /Ob2 /I "..\include" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /Fp"$(INTDIR)\echox.pch" /YX /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\\" /FD /c + +.c{$(INTDIR)}.obj:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.cpp{$(INTDIR)}.obj:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.cxx{$(INTDIR)}.obj:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.c{$(INTDIR)}.sbr:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.cpp{$(INTDIR)}.sbr:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.cxx{$(INTDIR)}.sbr:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +MTL=midl.exe +MTL_PROJ=/nologo /D "NDEBUG" /mktyplib203 /win32 +RSC=rc.exe +BSC32=bscmake.exe +BSC32_FLAGS=/nologo /o"$(OUTDIR)\echox.bsc" +BSC32_SBRS= \ + +LINK32=link.exe +LINK32_FLAGS=libfcgi.lib /nologo /pdb:none /machine:IX86 /out:"$(OUTDIR)\echo-x.exe" /libpath:"..\libfcgi\Release" +LINK32_OBJS= \ + "$(INTDIR)\echo-x.obj" \ + "..\libfcgi\Release\libfcgi.lib" + +"$(OUTDIR)\echo-x.exe" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS) + $(LINK32) @<< + $(LINK32_FLAGS) $(LINK32_OBJS) +<< + +!ELSEIF "$(CFG)" == "debug" + +OUTDIR=.\../examples/echo-x\Debug +INTDIR=.\../examples/echo-x\Debug +# Begin Custom Macros +OutDir=.\../examples/echo-x\Debug +# End Custom Macros + +ALL : "$(OUTDIR)\echo-x.exe" "$(OUTDIR)\echox.bsc" + +CLEAN : + -@erase "$(INTDIR)\echo-x.obj" + -@erase "$(INTDIR)\echo-x.sbr" + -@erase "$(INTDIR)\vc60.idb" + -@erase "$(INTDIR)\vc60.pdb" + -@erase "$(OUTDIR)\echo-x.exe" + -@erase "$(OUTDIR)\echox.bsc" + +"$(OUTDIR)" : + if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)" + +CPP=cl.exe +CPP_PROJ=/nologo /MDd /W4 /Gm /Gi /ZI /Od /I "..\include" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /FR"$(INTDIR)\\" /Fp"$(INTDIR)\echox.pch" /YX /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\\" /FD /GZ /c + +.c{$(INTDIR)}.obj:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.cpp{$(INTDIR)}.obj:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.cxx{$(INTDIR)}.obj:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.c{$(INTDIR)}.sbr:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.cpp{$(INTDIR)}.sbr:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.cxx{$(INTDIR)}.sbr:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +MTL=midl.exe +MTL_PROJ=/nologo /D "_DEBUG" /mktyplib203 /win32 +RSC=rc.exe +BSC32=bscmake.exe +BSC32_FLAGS=/nologo /o"$(OUTDIR)\echox.bsc" +BSC32_SBRS= \ + "$(INTDIR)\echo-x.sbr" + +"$(OUTDIR)\echox.bsc" : "$(OUTDIR)" $(BSC32_SBRS) + $(BSC32) @<< + $(BSC32_FLAGS) $(BSC32_SBRS) +<< + +LINK32=link.exe +LINK32_FLAGS=libfcgi.lib /nologo /profile /debug /machine:IX86 /out:"$(OUTDIR)\echo-x.exe" /libpath:"..\libfcgi\Debug" +LINK32_OBJS= \ + "$(INTDIR)\echo-x.obj" \ + "..\libfcgi\Debug\libfcgi.lib" + +"$(OUTDIR)\echo-x.exe" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS) + $(LINK32) @<< + $(LINK32_FLAGS) $(LINK32_OBJS) +<< + +!ENDIF + + +"..\examples\echo-x.c" : \ + "..\include\fcgi_config.h"\ + "..\include\fcgiapp.h"\ + + +!IF "$(CFG)" == "release" || "$(CFG)" == "debug" +SOURCE="..\examples\echo-x.c" + +!IF "$(CFG)" == "release" + + +"$(INTDIR)\echo-x.obj" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +!ELSEIF "$(CFG)" == "debug" + + +"$(INTDIR)\echo-x.obj" "$(INTDIR)\echo-x.sbr" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +!ENDIF + +!ENDIF + diff --git a/iipsrv/fcgi/examples/size.mak b/iipsrv/fcgi/examples/size.mak new file mode 100644 index 0000000..6c11177 --- /dev/null +++ b/iipsrv/fcgi/examples/size.mak @@ -0,0 +1,202 @@ +# Microsoft Developer Studio Generated NMAKE File, Based on size.dsp + +!IF "$(CFG)" == "" +CFG=release +!ENDIF + +!IF "$(CFG)" != "release" && "$(CFG)" != "debug" +!MESSAGE Invalid configuration "$(CFG)" specified. +!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 "size.mak" CFG="debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "release" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE "debug" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE +!ERROR An invalid configuration is specified. +!ENDIF + +!IF "$(OS)" == "Windows_NT" +NULL= +!ELSE +NULL=nul +!ENDIF + +!IF "$(CFG)" == "release" + +OUTDIR=.\..\examples\size\Release +INTDIR=.\..\examples\size\Release +# Begin Custom Macros +OutDir=.\..\examples\size\Release +# End Custom Macros + +ALL : "$(OUTDIR)\size.exe" + +CLEAN : + -@erase "$(INTDIR)\size.obj" + -@erase "$(INTDIR)\vc60.idb" + -@erase "$(OUTDIR)\size.exe" + +"$(OUTDIR)" : + if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)" + +CPP=cl.exe +CPP_PROJ=/nologo /MD /W3 /Gi /O2 /Ob2 /I "..\include" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /Fp"$(INTDIR)\size.pch" /YX /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\\" /FD /c + +.c{$(INTDIR)}.obj:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.cpp{$(INTDIR)}.obj:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.cxx{$(INTDIR)}.obj:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.c{$(INTDIR)}.sbr:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.cpp{$(INTDIR)}.sbr:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.cxx{$(INTDIR)}.sbr:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +MTL=midl.exe +MTL_PROJ=/nologo /D "NDEBUG" /mktyplib203 /win32 +RSC=rc.exe +BSC32=bscmake.exe +BSC32_FLAGS=/nologo /o"$(OUTDIR)\size.bsc" +BSC32_SBRS= \ + +LINK32=link.exe +LINK32_FLAGS=libfcgi.lib /nologo /pdb:none /machine:IX86 /out:"$(OUTDIR)\size.exe" /libpath:"..\libfcgi\Release" +LINK32_OBJS= \ + "$(INTDIR)\size.obj" \ + "..\libfcgi\Release\libfcgi.lib" + +"$(OUTDIR)\size.exe" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS) + $(LINK32) @<< + $(LINK32_FLAGS) $(LINK32_OBJS) +<< + +!ELSEIF "$(CFG)" == "debug" + +OUTDIR=.\../examples/size\Debug +INTDIR=.\../examples/size\Debug +# Begin Custom Macros +OutDir=.\../examples/size\Debug +# End Custom Macros + +ALL : "$(OUTDIR)\size.exe" "$(OUTDIR)\size.bsc" + +CLEAN : + -@erase "$(INTDIR)\size.obj" + -@erase "$(INTDIR)\size.sbr" + -@erase "$(INTDIR)\vc60.idb" + -@erase "$(INTDIR)\vc60.pdb" + -@erase "$(OUTDIR)\size.bsc" + -@erase "$(OUTDIR)\size.exe" + +"$(OUTDIR)" : + if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)" + +CPP=cl.exe +CPP_PROJ=/nologo /MDd /W4 /Gm /Gi /ZI /Od /I "..\include" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /FR"$(INTDIR)\\" /Fp"$(INTDIR)\size.pch" /YX /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\\" /FD /GZ /c + +.c{$(INTDIR)}.obj:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.cpp{$(INTDIR)}.obj:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.cxx{$(INTDIR)}.obj:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.c{$(INTDIR)}.sbr:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.cpp{$(INTDIR)}.sbr:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.cxx{$(INTDIR)}.sbr:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +MTL=midl.exe +MTL_PROJ=/nologo /D "_DEBUG" /mktyplib203 /win32 +RSC=rc.exe +BSC32=bscmake.exe +BSC32_FLAGS=/nologo /o"$(OUTDIR)\size.bsc" +BSC32_SBRS= \ + "$(INTDIR)\size.sbr" + +"$(OUTDIR)\size.bsc" : "$(OUTDIR)" $(BSC32_SBRS) + $(BSC32) @<< + $(BSC32_FLAGS) $(BSC32_SBRS) +<< + +LINK32=link.exe +LINK32_FLAGS=libfcgi.lib /nologo /profile /debug /machine:IX86 /out:"$(OUTDIR)\size.exe" /libpath:"..\libfcgi\Debug" +LINK32_OBJS= \ + "$(INTDIR)\size.obj" \ + "..\libfcgi\Debug\libfcgi.lib" + +"$(OUTDIR)\size.exe" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS) + $(LINK32) @<< + $(LINK32_FLAGS) $(LINK32_OBJS) +<< + +!ENDIF + + +..\examples\size.c : \ + "..\include\fcgiapp.h"\ + + +!IF "$(CFG)" == "release" || "$(CFG)" == "debug" +SOURCE=..\examples\size.c + +!IF "$(CFG)" == "release" + + +"$(INTDIR)\size.obj" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +!ELSEIF "$(CFG)" == "debug" + + +"$(INTDIR)\size.obj" "$(INTDIR)\size.sbr" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +!ENDIF + +!ENDIF + diff --git a/iipsrv/fcgi/fcgi_config.h b/iipsrv/fcgi/fcgi_config.h new file mode 100644 index 0000000..c9183c8 --- /dev/null +++ b/iipsrv/fcgi/fcgi_config.h @@ -0,0 +1,127 @@ +/* fcgi_config.h. Generated by configure. */ +/* fcgi_config.h.in. Generated from configure.in by autoheader. */ + +/* Define to 1 if you have the header file. */ +#define HAVE_ARPA_INET_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_DLFCN_H 1 + +/* Define if there's a fileno() prototype in stdio.h */ +#define HAVE_FILENO_PROTO 1 + +/* Define if the fpos_t typedef is in stdio.h */ +#define HAVE_FPOS 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_INTTYPES_H 1 + +/* Define if cin/cout/cerr has a streambuf assignment operator */ +/* #undef HAVE_IOSTREAM_WITHASSIGN_STREAMBUF */ + +/* Define to 1 if you have the `nsl' library (-lnsl). */ +#define HAVE_LIBNSL 1 + +/* Define to 1 if you have the `socket' library (-lsocket). */ +/* #undef HAVE_LIBSOCKET */ + +/* Define to 1 if you have the header file. */ +#define HAVE_LIMITS_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_MEMORY_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_NETDB_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_NETINET_IN_H 1 + +/* Define if you have POSIX threads libraries and header files. */ +/* #undef HAVE_PTHREAD */ + +/* Define if sockaddr_un in sys/un.h contains a sun_len component */ +/* #undef HAVE_SOCKADDR_UN_SUN_LEN */ + +/* Define if the socklen_t typedef is in sys/socket.h */ +/* #undef HAVE_SOCKLEN */ + +/* Define to 1 if you have the header file. */ +#define HAVE_STDINT_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STDLIB_H 1 + +/* Define if char_type is defined in the context of streambuf */ +/* #undef HAVE_STREAMBUF_CHAR_TYPE */ + +/* Define to 1 if you have the `strerror' function. */ +#define HAVE_STRERROR 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STRINGS_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STRING_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_PARAM_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_SOCKET_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_STAT_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_TIME_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_TYPES_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_UNISTD_H 1 + +/* Define if va_arg(arg, long double) crashes the compiler */ +/* #undef HAVE_VA_ARG_LONG_DOUBLE_BUG */ + +/* Name of package */ +#define PACKAGE "fcgi" + +/* Define to the address where bug reports for this package should be sent. */ +#define PACKAGE_BUGREPORT "" + +/* Define to the full name of this package. */ +#define PACKAGE_NAME "" + +/* Define to the full name and version of this package. */ +#define PACKAGE_STRING "" + +/* Define to the one symbol short name of this package. */ +#define PACKAGE_TARNAME "" + +/* Define to the version of this package. */ +#define PACKAGE_VERSION "" + +/* Define to the necessary symbol if this constant uses a non-standard name on + your system. */ +/* #undef PTHREAD_CREATE_JOINABLE */ + +/* Define to 1 if you have the ANSI C header files. */ +#define STDC_HEADERS 1 + +/* Define if cross-process locking is required by accept() */ +/* #undef USE_LOCKING */ + +/* Version number of package */ +#define VERSION "2.4.0" + +/* Define to empty if `const' does not conform to ANSI C. */ +/* #undef const */ + +/* Define as `__inline' if that's what the C compiler calls it, or to nothing + if it is not supported. */ +/* #undef inline */ + +/* Define to `int' if does not define. */ +/* #undef ssize_t */ diff --git a/iipsrv/fcgi/images/aplib-hd.gif b/iipsrv/fcgi/images/aplib-hd.gif new file mode 100644 index 0000000000000000000000000000000000000000..8198890861e3b1559fcc678e60d1577ce30eb614 GIT binary patch literal 1840 zcmb8o`#;kQ1Hkd`zWZ)Amt(YQ;hZy!F_W#_((0LOd%)`yzjx`N90=)pBQmHT) zjG>_+l}dGTa`N-@3k?m8jg3uAOw7*CmdRud4Gj+;J{%btnVz0rTU!JE&&YrKzh3}C zg~#WxBg!~;8Y5R8@yJi&xHAcjYe{P=x_*xi+YB>+h_Nm>f^&BfZQu^!y8Um{m#+Mx zq!@Yn=-?%8xh#6uE6{n~Kwv%+{SjY5*Jo-YSt&uGLeUCF_suhj6BU4@r zcRQSnoULNC&m9+;`SWm@l|Vim`Wis%YK|7rvD)Vip^~?`;uJ)fs(ff7q^eI!>J3Xt zQ_gE3tAcmq_R3#-qBeEo-}C1HXI(P{#zyLG1{IOdJxa+`)R^Z|`o3P7k_b;BqcoGg zU9rKbOEK71z|-dYGi~G~zSyvEe@{HzJtLJg7i4sr|5xXzI!g{CAh#aQY5%1wid{!SWJ4WMaUPhcn!4544VskOL9GihzHYZV z)3oMOcFX*U_3_!C9@7vXHm%x;Jr^;nbfxihTilFF>r|2nLuA5vuBQ$5@yfs1TLi1P z%JHHyuaamI0hb>Kt3+u$pbD^|v&PP86t>xzKB}z7z}dD`K)+O>R0A@zdZ{eI`)72e z-$4UD2&b9O&7<_odL`5iAw+;Wmgd+RpCe7=`4X&04?JsGNiT6I{qa`8xa;Fl@ZXP> z1`uRM$I1?g1;fl>5HQx{H01Z_JB#H6VskfU@dtjNi`mU{-AcI*N+8tG{MRGKaoFLB zzU4C|PE*8!>jy~HwbHq}dZm`BQ=sGiam=@nd(rw-sX_G}POaGlvksL7Qq&qvCfw@L zjV+9l?;Rw|ZamVm}T#~oXjII5PA-1pYbE~frTUmCu@O+b7>4rQ(2(w3i zkQh+=aRShT(*uo`8A)%@mjBp8ufJ&F1ZRnH>+<2&(_e}K{tdbn5hSeFQDQHTx2i+Y zuJWdwBYop4(A)H{2FqkMd_O97JmQTQD#$SzJXp`{1k_xP2EI;1b7#kkaMjK5D|<(_r!W?LWrkJgzkv3)z0?9jp&_EOaE!w`Mi36ZRfx1 z{Z^_ko4-e^zHa~7q}uuNaZRNHASbwDuN(wt(LtGoPu0W0rhV%|c8$*%-qw-TtS-X6 z6hf~SI+5ooDfnk)oA}#gLT^9p9zGa#YM@cE0BDogER0)fk%LDL4uR>nm`m{h`hQoMu^wbeF4!tA-`j5L^ri@~o)!j=r+5 z6|xM2VTyHAIKW=-OX(*qVH;$f0)=I4UBJ{I)Xy8az`9wwxpL6?>C$dQ4seYuSot*N zaF=8+LBJmv_y^*Drzj$u5*rG>LzUZKo<#0TL)3@7owR3o)+iWo_}*y*TU5yZ>M)j$~<`XsWJk>%Op35JqgbT=AuQTXtntd;+06QcgNp}DM literal 0 HcmV?d00001 diff --git a/iipsrv/fcgi/images/fcgi-hd.gif b/iipsrv/fcgi/images/fcgi-hd.gif new file mode 100644 index 0000000000000000000000000000000000000000..5eab1c4e9d88f10201bb13f7c6bf5bc5fb2f27bf GIT binary patch literal 1364 zcmcJK`&Uv20LQPlE21;c1w;fzdH720NS0~YaiA!IR%m8q57AsRAElWVWdR~duAs0i zmJ{Epq-3Y879C(hX*QjitF)8(sLV92HRsMe-L*er-}CwT^EqD*Hzq7J?Iqv^3;_Uw zAaiqHnHwENMn^~c`;q?sexngF8jX5AqSx!ST12bWs#J(drIJV_Vlg5Xi}Ui3yu3W2 z5D^N6d_KbG^O;P9$z(DZ2!p|(P!I}*0>cOl!(R))|GB{b%}q-LDSNzDVMiLDV=tJ&AQgMIFwsw%LSg3 zq4PHTrrB^ruU9q+P@Wpk<9A!Tc|U2$$H}@l)BTpNC{!JBMB&yTRu1))_HOS}dSbF8 zLB}`m633hzeBug^1D`f7R58=1@4 zTO4Gq+2y)uo*smqw=Dc|Gy{yI#fF~^QE$#cH^o;)l$KkruF~>RCytF^rKyn8e~CO3 z>W;0Yx~{Q_52dGD;|+h8(=G=0o^(^7{P$^s!w1~byP!4rwGrcvz`NaS;sWa+ z_Qpr}1i9KZ=~ZQ+`eEeS(LP4)>v{)689Hyd$bJI$Jour)-{Fu8^ojzi3 zBM$zOGwFz&rQq*b_Sbp6%)zBe77GP*MaB0$b6Eyl1KuJ%DH2eAhkQD=PbkuOGi)o} zG2*sR36 zWsRq7sS-ip&ZhC#aJYw6y$%D~?nOV(oY;#a%?_C_Upvp01G;@IW^D?oKwI_6YE^@l z=&{{sB7^DDu-!r0zgq$V-p-1Z=dJWT4rZUA0T$-%0ZmM_e|<5FWg=pLlI70Yh=fPB zI|L8jr{DQyctus)b^qp$j`R-qx{c5X#NCvLNkwP6e0)*2!AFmQP zCH^#>7Vy9nV@ua?w{p;s8q0k+Sb*WmLJssEU2MFl5^v1+^QtU*BgyJmY=q8{GjeBR zz}4pd4cU)UY%UTBEbJltVlxxkSsyq;Cw?y8oQ!maJ$q6*knl8=JiTz{+j})4-^MG^ z3~5$TlsP2m$cn{b)cR%2RDb({;u*|F;{xl(54uR(eXU6p)6kRWODT350&7(eIc#3k z7FO}s<4&yC+y(Qk_IvlwgSkzg^dZ$^N)KF-m^Gs&I;(sKwghe~w!>K>Qa?1F%AFYQ zywtSXrrHjd$Y#6FCqj;fs&fyDDA!Iv4w-W=mU0CjPfAL9+1aEIQCh$*)&!E~CFuAX UkkD;Ht)G{|r)wY^7y`oo1y|57fdBvi literal 0 HcmV?d00001 diff --git a/iipsrv/fcgi/images/mail-hd.gif b/iipsrv/fcgi/images/mail-hd.gif new file mode 100644 index 0000000000000000000000000000000000000000..4ea84d2e08d16c2ce28dd43da9211cdd53ed3792 GIT binary patch literal 1605 zcmb8o|3A}-1Hke3-urHxrB%D8Yiu(c#YDua`Etm&$8fiki1~J_jEQ8WKJSJwvAHDN z_{{oH`CjQ$p&FAf_d#-3xAXWM+oU*M)+N<_;{AEtpK!0ApO42Y=s=*Cr*H=F1qJ~C zhG8O+XlG}~;c)!?{Gy_wl9Q9Ov$Id1K7HZB1(izG-rj!y{{4xGiJ6(1<>h7IZ|3}$ z|LX;yVJfvEy2r=23JTQXGjR=q&fDz2x8k*&Fg6a)0y{ z-omMe23Pyghz(R_phC#&{T1||vxQg_neVBMJc_^?BP>WrW}>B~a_Q033R(u<$GW6U zUhZUttS&vl#;dAp=$9H*F$zV-c`qx36cPWu{2Kd=6pRPUoYc*wS7=r;RIdnGn2>S% zdP?h_jtm4Y)ZW@+=s!+(LwDR0H zm<-GOZA%_xi%KG?8wmB-9(&t4Un;k|v{RRh3@#~Tn-c5~O8@AYv=C|$bj<2~BLSEf zxTF5vpS9uU@3;)`aLpk@RhGQRe)X_}L~W!XRY6>dRnzM9lGaI}u}!1*E{TFv5b6h*%rc`dq2sKRKdoC>6vz^xSDL!=;&PX%J4SrPGtg#k=gh)Z-{dp+GKT2sR%>ubqW)}4 zHKOs1D2yXG!{#a>u`~yv!4dj65GmP6^DlBuaeP9-HC(gx-(3gsPBa>@Kxx?^M+m+B ziD!t~Wh(`dTnEz}j?yrwVr;G7G_$JQjoo~`($uxJZb#uX=(}@@xD6FtZJw^PZEg`=chn17ab=(@wu7M$ zY{PflC{FYlfhyrr67Uvp)n^Np8*8xR7Dy!q-GKYjE$oW#J1jN zn-3*i-mMvyWiNCjhNW@dR1Vw}iHZko$7F>9U>4IsVDb76vXbE|9i$*FD& zROXl3&WgQ5Q!p6r@JIWOvsmgdE_>?8Z*o*s1!Htqo1h242JDM}QG^#8r>e=#H;`wG zZTMWeyO{`Da8-(j0@p4sNLYA1y%MfB7v?2}1{|@Opt-Dncz!u^{o}&b&hHRVc1D0w4sfWx~W@x^*=m2lZ9_6jf$FgGaEwp}YEZ<8R zi9oxI_y)CM5KE_IE`A}28t?~N zS|oIf=!KXcO+l&DB0}erO_% zL%Xc$D+N(=L>@^$x5a%yS+#g&JZXU87NK?`(W#RO-4eINmdx!1(Mc`^x9;p@Q&SPd w7-QVGMW(fKlqRPc?z3r4Bbkqz!mfJ%JUWrv^S0i6;VSp#fybxhR21Ozf7ke~RsaA1 literal 0 HcmV?d00001 diff --git a/iipsrv/fcgi/images/navbar.gif b/iipsrv/fcgi/images/navbar.gif new file mode 100644 index 0000000000000000000000000000000000000000..c2ada2e4e0ce0b93ba329a05c957bd86ffa50f79 GIT binary patch literal 2061 zcmb8o`#aN%1HkdmW{olInR76r%{7r+!i;L}=Ae>}(uEDVG?y@niNdCmXhsF2}#ZK%*rhA2nfDZLSUXRyIz`A zUBO7Mbt_}#b6hTRi<_O;tv6fRn77V$miOYx+`EpIor4a2cOKgJH;f!&wuL<%%N0I; z)-z$(eeSOr-0+jvHlsYT_0(MZ`~8U3&ui-&n_JsozJBxmCfWJ%bL;yrDInAJ#jvC1 zeiB4^-`Vn*S^x}II{X{rQh?Ld=c@QqXp-O#L>Jj%hbK8uDS9qaEMBPeUJk5U3HS;F zNiw@uhw(0zJn&@F1WG4!{p8BtX0q;F6_~P(k{W+?|GLr$s#VU2lS}Jg}+e zCL~crAA@Z$vHi-cBm#c?;Js_3s}xFJDg8 zIPIzWrJnNnZCYX45eEK(#KtKNyr344ZpuEfN19;<34&+tL&#wi`h@001*OzDjC`v- zp9ov7*{+qJ4a4fdv=U+$U>N@{oxJ&#Uef-7dvbM|uS62$K7#@Edb;6-@_J?>1*??t znzOlhjZh~ZvvpoCcPr7^tFBX;SSs->SpaMoihQGDM+-FXgc{hdRoR}eh)5l|PzmSA za<6>wqKViWqMQQuI^Q=WPH)qy%Fob2@CMlJ;&&F7!SdY;NuAfvCwV0q7(u$X9;uOK z5FsTT9hhMHxMR3S1lNVPG|36u9v%0G;U~RM`6>$7AtaEvQl{mw$Er*Zm}Pvr;|Y$} zLPIs~CMD&Fy>FFtJNW?d&*rM6-8#Nd2jX8^nrikC_21_rspe<_*r_z{`UQliYiTs= zdfs|iS;!-A{#x$R8glD>&zb0kgjzwPgM--_J4ML%utu5Uh>rGE$y3dtm6V@Mis?sw0(%(d*c37rsi7lzu2 z67nu4mRoB^MN6FqBFjKg zn=?-t_&Ixb0{UGDt|a#^rYR}M>%R6tg5^%VsRQ=ni<)+&Aj;p~8beZ7TV(M<+By;sTqlT}HVlf6dKT^M|>^j40v) zsX&s2m710|#i&^nsgA5z8MKM%VGy^MQNJntPTa5AprA3+^uF6F73Ow{R-hp>ioU-E z&!;&bD_iP;4sN;Uo?-i_w=Inb!g*1Ci>LEiC7csJp2iIPw+AV9pUw#jvLfRR6 z8p5Hn{*6#QtwEA$3pXI~$QITX^6+$OE`G$i< zkxIZlr02zSg15f~%8e4?1zUb3mxAQEp8*kO!}RN(EJq(#Y(`IAwjt`7*1MJL^*3yq z?p6w}SBd<9_<+mL8RL~2nJX#GzB3G+Gh_CZDc)E9(fm*Af`DnYlKINr7#tb z$f3?#)LgdGYABvdP3|FIr14MoFf3OzH*9_#EN%~*>1;EdQ07rXBLI^M^IpRTfL4T7|vFp%Q=B)VgF$C8z zYv+mwR$qcPy9F>jz6|RoXYoZgWzMQ}C_O)ixDaJ~g8ygFq<)MNVvktAuQ32#vD{&| z`%*Ane;~Qw$%=4wX^N=FcKxISPp+|o$_`L@hTp-%k&v&rqbls9I8V|oY5LRwCsAnc zsNfQ1lN|xhGv#LY`p;CEJs_7b1?wqHQ}&TJBk$RF3`!BTI7$(eV?dQ~?owJ~?XG#g zo9|dXRDHwgk$aHl$3ZImVt~+gBXLKwJ&lKX>Pc4nXA)b7Pg%nbA zksVB7T_jS)0uDb7Qj0XWM-iCCY3%%RUE>K;R>1Hr-Dt%`iORs%JY-pA&bXr#J&Y1;$oTt${VRWf>w#vGph22b;VYMO)L07$Y{7hgQ zs=bR@`K7mbIgm&Ey~U(M8G2Tz;|Sujqwt?=(vnbIfUc6|*2)EPM>Gp>I$Dix>wRV( z9#y`lc37CY)E*stit<6y-^FHM>9-ye=CFVj5T}Uby!IyE8zv7bgL~F3Sqi{0SY!pZ zHYoSMs;xK>;+PK=>pKNKPC+?AJvgecjQX-GQR6%Z>-6<9L98UBUKk55CavsW=u(cm zGlI_m#T!x@Ith_+2LP#d0A1+ zU82;5v;TbKkC-T>H+lp_eZ|YMR7FKQf$Lb=%p(r zOsc)R77glCWyQa;Tsx_t!P5KLwU8NYPDU)lKhb2u&Sm@aVtMlR#!_R)_TTS*S>66e zJM5y{Tzj6Z+xq;bL$|&8X;r5K4CR0xT?txh1;}7IXfdKhoYKT;ylH^Ez6x``4)~%b z$HMF9++%1tCS2+paN~ybM-x`fQR5kjG{YHN0>3K4q1jy*1UVePQQBx-FbE=`FVgPd87S!TgeRZS= z4C){GuzB&+pfI=2>Uc%%N_7SFcGf{G96Rl`WMg4^&*AX%PHWVVr0V)dal!X1FEJXV zfOcu1sC&kDWC;sBo!bgLiPpEAHHYVQ;<cOQ3EeQaZgw1z$Z?b+>~j|$$k)`&Mj L&%5&gVBh}$8~^m| literal 0 HcmV?d00001 diff --git a/iipsrv/fcgi/images/words-hd.gif b/iipsrv/fcgi/images/words-hd.gif new file mode 100644 index 0000000000000000000000000000000000000000..bd7a0ff4ef03a3fceb91ba20b7c53a6e9994502b GIT binary patch literal 1725 zcmb8o|3A}-1Hke3-kaHsGmGp@*Jc}=FWK@nt!~({e5v6cOG>^iH|5KAR95QVhGK+; ziCb=ToP5ve&Y>Fftve*2>f}+3A|lo|efgB#@ZH9ec4F%!_R!v{k@S?tTpVKCy=AV=3>5)ocRa6d98h6=!E4$&*Qr9w{Uzqj#F-=F2WP zn7|cz$L-Nd#U)BvwKBY@DEXYH2}}Zu{83hKe?|gEg82@ry1Xl76Dguw2+xj6zJ68E zxT7T*h6=PXH5&ZO;ddbneINKDNdg(hJRFX`=zyAXSREY`Ho4s$(o#%+6^_`Nq!=_P zwddmfcAiDf*77>%0;IGs5k9X5D1jqBhqJn`r9fpxf4n>y8-`8L4cW<^-IZn{7WAWphCCs%zXRMh&AN*Kf>XfO)FdMGI;yOxzkQ_47OL)mlR!FTbA|1HHb- z)`q%ROF%fwcJ2v^P}N_|e3^-$ApTgK6JS0jQq?8J=6f{o{3R{B!mIN8%cT?F42*+6 z4`{6s2pZd5xkCnx@}oh3Y%FXp(GYxPYKq;pUhMpLl0gpb$3wkZwHXS^#2Ei@lNSKn zIXSo#QQd<3SeG(+dilV-+PD?~516++Vr$z;-?67?5rrTB6rtSxu z4@Q-{*9=Kh7h9r(;+ZeyeeFWw`9A9rX*M5N28qp)Nef=~JwuKI>Y%Q5D}FOz7bGKq zjdkkX^EH?JgY9zR#YXgi|B2CbxLcAYBE7ckeAKAO*80SH85Ao|ua(AvPZO7S&$X*Z zT?2!T0!1GbY-}Pjy%PXgWXFdDL|R7h-Whk#2P1-zko(S`6V~%RE)ylx%jZcVD3-5L zyV!+aeK!eM!P${EOT3KdXs53?vzv}N_`qXic%6E*O{hG8KSh1dfTOm-vt8M3 zJ_|q*ja`xz_4({N*;4nHzkEf6IFD=G2I~nxhqUN#%5y6PA(N@ZZ;5Z45A36{hqbvq z`vnV|fAHjz@s`GN<2)y^3yk{K$Kt!3M&Mqw;G?e1fAU^6F3_>K=a3)x8;@DmxH2@2 ztLB7U+;>ITL*{B9l~^0B0TvV8p}D(w=GzGh(pog1F(Zl8}wNG@)H zvHHOuNdFcJ-(%+f>`^@i&yXQKH`N>#(@lC_H6p+5J?7N5G%pCaS7Y_Io*Uc{T3(rj I1%RFZ0JntLh5!Hn literal 0 HcmV?d00001 diff --git a/iipsrv/fcgi/include/Makefile.am b/iipsrv/fcgi/include/Makefile.am new file mode 100644 index 0000000..417a561 --- /dev/null +++ b/iipsrv/fcgi/include/Makefile.am @@ -0,0 +1,8 @@ +# $Id: Makefile.am,v 1.2 2001/09/24 18:03:05 skimo Exp $ +include_HEADERS = \ + fastcgi.h \ + fcgi_stdio.h \ + fcgiapp.h \ + fcgimisc.h \ + fcgio.h \ + fcgios.h diff --git a/iipsrv/fcgi/include/fastcgi.h b/iipsrv/fcgi/include/fastcgi.h new file mode 100644 index 0000000..d5b5468 --- /dev/null +++ b/iipsrv/fcgi/include/fastcgi.h @@ -0,0 +1,136 @@ +/* + * fastcgi.h -- + * + * Defines for the FastCGI protocol. + * + * + * Copyright (c) 1995-1996 Open Market, Inc. + * + * See the file "LICENSE.TERMS" for information on usage and redistribution + * of this file, and for a DISCLAIMER OF ALL WARRANTIES. + * + * $Id: fastcgi.h,v 1.1.1.1 1997/09/16 15:36:32 stanleyg Exp $ + */ + +#ifndef _FASTCGI_H +#define _FASTCGI_H + +/* + * Listening socket file number + */ +#define FCGI_LISTENSOCK_FILENO 0 + +typedef struct { + unsigned char version; + unsigned char type; + unsigned char requestIdB1; + unsigned char requestIdB0; + unsigned char contentLengthB1; + unsigned char contentLengthB0; + unsigned char paddingLength; + unsigned char reserved; +} FCGI_Header; + +#define FCGI_MAX_LENGTH 0xffff + +/* + * Number of bytes in a FCGI_Header. Future versions of the protocol + * will not reduce this number. + */ +#define FCGI_HEADER_LEN 8 + +/* + * Value for version component of FCGI_Header + */ +#define FCGI_VERSION_1 1 + +/* + * Values for type component of FCGI_Header + */ +#define FCGI_BEGIN_REQUEST 1 +#define FCGI_ABORT_REQUEST 2 +#define FCGI_END_REQUEST 3 +#define FCGI_PARAMS 4 +#define FCGI_STDIN 5 +#define FCGI_STDOUT 6 +#define FCGI_STDERR 7 +#define FCGI_DATA 8 +#define FCGI_GET_VALUES 9 +#define FCGI_GET_VALUES_RESULT 10 +#define FCGI_UNKNOWN_TYPE 11 +#define FCGI_MAXTYPE (FCGI_UNKNOWN_TYPE) + +/* + * Value for requestId component of FCGI_Header + */ +#define FCGI_NULL_REQUEST_ID 0 + + +typedef struct { + unsigned char roleB1; + unsigned char roleB0; + unsigned char flags; + unsigned char reserved[5]; +} FCGI_BeginRequestBody; + +typedef struct { + FCGI_Header header; + FCGI_BeginRequestBody body; +} FCGI_BeginRequestRecord; + +/* + * Mask for flags component of FCGI_BeginRequestBody + */ +#define FCGI_KEEP_CONN 1 + +/* + * Values for role component of FCGI_BeginRequestBody + */ +#define FCGI_RESPONDER 1 +#define FCGI_AUTHORIZER 2 +#define FCGI_FILTER 3 + + +typedef struct { + unsigned char appStatusB3; + unsigned char appStatusB2; + unsigned char appStatusB1; + unsigned char appStatusB0; + unsigned char protocolStatus; + unsigned char reserved[3]; +} FCGI_EndRequestBody; + +typedef struct { + FCGI_Header header; + FCGI_EndRequestBody body; +} FCGI_EndRequestRecord; + +/* + * Values for protocolStatus component of FCGI_EndRequestBody + */ +#define FCGI_REQUEST_COMPLETE 0 +#define FCGI_CANT_MPX_CONN 1 +#define FCGI_OVERLOADED 2 +#define FCGI_UNKNOWN_ROLE 3 + + +/* + * Variable names for FCGI_GET_VALUES / FCGI_GET_VALUES_RESULT records + */ +#define FCGI_MAX_CONNS "FCGI_MAX_CONNS" +#define FCGI_MAX_REQS "FCGI_MAX_REQS" +#define FCGI_MPXS_CONNS "FCGI_MPXS_CONNS" + + +typedef struct { + unsigned char type; + unsigned char reserved[7]; +} FCGI_UnknownTypeBody; + +typedef struct { + FCGI_Header header; + FCGI_UnknownTypeBody body; +} FCGI_UnknownTypeRecord; + +#endif /* _FASTCGI_H */ + diff --git a/iipsrv/fcgi/include/fcgi_config_x86.h b/iipsrv/fcgi/include/fcgi_config_x86.h new file mode 100644 index 0000000..c59cda8 --- /dev/null +++ b/iipsrv/fcgi/include/fcgi_config_x86.h @@ -0,0 +1,39 @@ +/* + * Copied to fcgi_config.h when building on WinNT without cygwin, + * i.e. configure is not run. See fcgi_config.h.in for details. + */ + +#define HAVE_FPOS 1 +#define HAVE_LIMITS_H 1 +#define HAVE_STREAMBUF_CHAR_TYPE 1 +#define HAVE_STRERROR 1 +#undef HAVE_ARPA_INET_H +#undef HAVE_DLFCN_H +#undef HAVE_FILENO_PROTO +#undef HAVE_INTTYPES_H +#undef HAVE_IOSTREAM_WITHASSIGN_STREAMBUF +#undef HAVE_LIBNSL +#undef HAVE_LIBSOCKET +#undef HAVE_MEMORY_H +#undef HAVE_NETDB_H +#undef HAVE_NETINET_IN_H +#undef HAVE_PTHREAD +#undef HAVE_SOCKADDR_UN_SUN_LEN +#undef HAVE_SOCKLEN +#undef HAVE_STDINT_H +#undef HAVE_STDLIB_H +#undef HAVE_STRING_H +#undef HAVE_STRINGS_H +#undef HAVE_SYS_PARAM_H +#undef HAVE_SYS_SOCKET_H +#undef HAVE_SYS_STAT_H +#undef HAVE_SYS_TIME_H +#undef HAVE_SYS_TYPES_H +#undef HAVE_UNISTD_H +#undef HAVE_VA_ARG_LONG_DOUBLE_BUG +#undef PTHREAD_CREATE_JOINABLE +#undef STDC_HEADERS +#undef USE_LOCKING +#undef const +#undef inline +#undef ssize_t diff --git a/iipsrv/fcgi/include/fcgi_stdio.h b/iipsrv/fcgi/include/fcgi_stdio.h new file mode 100644 index 0000000..de2af89 --- /dev/null +++ b/iipsrv/fcgi/include/fcgi_stdio.h @@ -0,0 +1,245 @@ +/* + * fcgi_stdio.h -- + * + * FastCGI-stdio compatibility package + * + * + * Copyright (c) 1996 Open Market, Inc. + * + * See the file "LICENSE.TERMS" for information on usage and redistribution + * of this file, and for a DISCLAIMER OF ALL WARRANTIES. + * + * $Id: fcgi_stdio.h,v 1.5 2001/06/22 13:21:15 robs Exp $ + */ + +#ifndef _FCGI_STDIO +#define _FCGI_STDIO 1 + +#include +#include +#include "fcgiapp.h" + +#if defined (c_plusplus) || defined (__cplusplus) +extern "C" { +#endif + +#ifndef DLLAPI +#ifdef _WIN32 +#define DLLAPI __declspec(dllimport) +#else +#define DLLAPI +#endif +#endif + +/* + * Wrapper type for FILE + */ + +typedef struct { + FILE *stdio_stream; + FCGX_Stream *fcgx_stream; +} FCGI_FILE; + +/* + * The four new functions and two new macros + */ + +DLLAPI int FCGI_Accept(void); +DLLAPI void FCGI_Finish(void); +DLLAPI int FCGI_StartFilterData(void); +DLLAPI void FCGI_SetExitStatus(int status); + +#define FCGI_ToFILE(fcgi_file) (fcgi_file->stdio_stream) +#define FCGI_ToFcgiStream(fcgi_file) (fcgi_file->fcgx_stream) + +/* + * Wrapper stdin, stdout, and stderr variables, set up by FCGI_Accept() + */ + +DLLAPI extern FCGI_FILE _fcgi_sF[]; +#define FCGI_stdin (&_fcgi_sF[0]) +#define FCGI_stdout (&_fcgi_sF[1]) +#define FCGI_stderr (&_fcgi_sF[2]) + +/* + * Wrapper function prototypes, grouped according to sections + * of Harbison & Steele, "C: A Reference Manual," fourth edition, + * Prentice-Hall, 1995. + */ + +DLLAPI void FCGI_perror(const char *str); + +DLLAPI FCGI_FILE *FCGI_fopen(const char *path, const char *mode); +DLLAPI int FCGI_fclose(FCGI_FILE *fp); +DLLAPI int FCGI_fflush(FCGI_FILE *fp); +DLLAPI FCGI_FILE *FCGI_freopen(const char *path, const char *mode, FCGI_FILE *fp); + +DLLAPI int FCGI_setvbuf(FCGI_FILE *fp, char *buf, int bufmode, size_t size); +DLLAPI void FCGI_setbuf(FCGI_FILE *fp, char *buf); + +DLLAPI int FCGI_fseek(FCGI_FILE *fp, long offset, int whence); +DLLAPI int FCGI_ftell(FCGI_FILE *fp); +DLLAPI void FCGI_rewind(FCGI_FILE *fp); +#ifdef HAVE_FPOS +DLLAPI int FCGI_fgetpos(FCGI_FILE *fp, fpos_t *pos); +DLLAPI int FCGI_fsetpos(FCGI_FILE *fp, const fpos_t *pos); +#endif +DLLAPI int FCGI_fgetc(FCGI_FILE *fp); +DLLAPI int FCGI_getchar(void); +DLLAPI int FCGI_ungetc(int c, FCGI_FILE *fp); + +DLLAPI char *FCGI_fgets(char *str, int size, FCGI_FILE *fp); +DLLAPI char *FCGI_gets(char *str); + +/* + * Not yet implemented + * + * int FCGI_fscanf(FCGI_FILE *fp, const char *format, ...); + * int FCGI_scanf(const char *format, ...); + * + */ + +DLLAPI int FCGI_fputc(int c, FCGI_FILE *fp); +DLLAPI int FCGI_putchar(int c); + +DLLAPI int FCGI_fputs(const char *str, FCGI_FILE *fp); +DLLAPI int FCGI_puts(const char *str); + +DLLAPI int FCGI_fprintf(FCGI_FILE *fp, const char *format, ...); +DLLAPI int FCGI_printf(const char *format, ...); + +DLLAPI int FCGI_vfprintf(FCGI_FILE *fp, const char *format, va_list ap); +DLLAPI int FCGI_vprintf(const char *format, va_list ap); + +DLLAPI size_t FCGI_fread(void *ptr, size_t size, size_t nmemb, FCGI_FILE *fp); +DLLAPI size_t FCGI_fwrite(void *ptr, size_t size, size_t nmemb, FCGI_FILE *fp); + +DLLAPI int FCGI_feof(FCGI_FILE *fp); +DLLAPI int FCGI_ferror(FCGI_FILE *fp); +DLLAPI void FCGI_clearerr(FCGI_FILE *fp); + +DLLAPI FCGI_FILE *FCGI_tmpfile(void); + +DLLAPI int FCGI_fileno(FCGI_FILE *fp); +DLLAPI FCGI_FILE *FCGI_fdopen(int fd, const char *mode); +DLLAPI FCGI_FILE *FCGI_popen(const char *cmd, const char *type); +DLLAPI int FCGI_pclose(FCGI_FILE *); + +/* + * The remaining definitions are for application programs, + * not for fcgi_stdio.c + */ + +#ifndef NO_FCGI_DEFINES + +/* + * Replace standard types, variables, and functions with FastCGI wrappers. + * Use undef in case a macro is already defined. + */ + +#undef FILE +#define FILE FCGI_FILE + +#undef stdin +#define stdin FCGI_stdin +#undef stdout +#define stdout FCGI_stdout +#undef stderr +#define stderr FCGI_stderr + +#undef perror +#define perror FCGI_perror + +#undef fopen +#define fopen FCGI_fopen +#undef fclose +#define fclose FCGI_fclose +#undef fflush +#define fflush FCGI_fflush +#undef freopen +#define freopen FCGI_freopen + +#undef setvbuf +#define setvbuf FCGI_setvbuf +#undef setbuf +#define setbuf FCGI_setbuf + +#undef fseek +#define fseek FCGI_fseek +#undef ftell +#define ftell FCGI_ftell +#undef rewind +#define rewind FCGI_rewind +#undef fgetpos +#define fgetpos FCGI_fgetpos +#undef fsetpos +#define fsetpos FCGI_fsetpos + +#undef fgetc +#define fgetc FCGI_fgetc +#undef getc +#define getc FCGI_fgetc +#undef getchar +#define getchar FCGI_getchar +#undef ungetc +#define ungetc FCGI_ungetc + +#undef fgets +#define fgets FCGI_fgets +#undef gets +#define gets FCGI_gets + +#undef fputc +#define fputc FCGI_fputc +#undef putc +#define putc FCGI_fputc +#undef putchar +#define putchar FCGI_putchar + +#undef fputs +#define fputs FCGI_fputs +#undef puts +#define puts FCGI_puts + +#undef fprintf +#define fprintf FCGI_fprintf +#undef printf +#define printf FCGI_printf + +#undef vfprintf +#define vfprintf FCGI_vfprintf +#undef vprintf +#define vprintf FCGI_vprintf + +#undef fread +#define fread FCGI_fread +#undef fwrite +#define fwrite FCGI_fwrite + +#undef feof +#define feof FCGI_feof +#undef ferror +#define ferror FCGI_ferror +#undef clearerr +#define clearerr FCGI_clearerr + +#undef tmpfile +#define tmpfile FCGI_tmpfile + +#undef fileno +#define fileno FCGI_fileno +#undef fdopen +#define fdopen FCGI_fdopen +#undef popen +#define popen FCGI_popen +#undef pclose +#define pclose FCGI_pclose + +#endif /* NO_FCGI_DEFINES */ + +#if defined (__cplusplus) || defined (c_plusplus) +} /* terminate extern "C" { */ +#endif + +#endif /* _FCGI_STDIO */ + diff --git a/iipsrv/fcgi/include/fcgiapp.h b/iipsrv/fcgi/include/fcgiapp.h new file mode 100644 index 0000000..d7236f6 --- /dev/null +++ b/iipsrv/fcgi/include/fcgiapp.h @@ -0,0 +1,622 @@ +/* + * fcgiapp.h -- + * + * Definitions for FastCGI application server programs + * + * + * Copyright (c) 1996 Open Market, Inc. + * + * See the file "LICENSE.TERMS" for information on usage and redistribution + * of this file, and for a DISCLAIMER OF ALL WARRANTIES. + * + * $Id: fcgiapp.h,v 1.12 2001/11/21 21:10:11 robs Exp $ + */ + +#ifndef _FCGIAPP_H +#define _FCGIAPP_H + +/* Hack to see if we are building TCL - TCL needs varargs not stdarg */ +#ifndef TCL_LIBRARY +#include +#else +#include +#endif + +#ifndef DLLAPI +#ifdef _WIN32 +#define DLLAPI __declspec(dllimport) +#else +#define DLLAPI +#endif +#endif + +#if defined (c_plusplus) || defined (__cplusplus) +extern "C" { +#endif + +/* + * Error codes. Assigned to avoid conflict with EOF and errno(2). + */ +#define FCGX_UNSUPPORTED_VERSION -2 +#define FCGX_PROTOCOL_ERROR -3 +#define FCGX_PARAMS_ERROR -4 +#define FCGX_CALL_SEQ_ERROR -5 + +/* + * This structure defines the state of a FastCGI stream. + * Streams are modeled after the FILE type defined in stdio.h. + * (We wouldn't need our own if platform vendors provided a + * standard way to subclass theirs.) + * The state of a stream is private and should only be accessed + * by the procedures defined below. + */ +typedef struct FCGX_Stream { + unsigned char *rdNext; /* reader: first valid byte + * writer: equals stop */ + unsigned char *wrNext; /* writer: first free byte + * reader: equals stop */ + unsigned char *stop; /* reader: last valid byte + 1 + * writer: last free byte + 1 */ + unsigned char *stopUnget; /* reader: first byte of current buffer + * fragment, for ungetc + * writer: undefined */ + int isReader; + int isClosed; + int wasFCloseCalled; + int FCGI_errno; /* error status */ + void (*fillBuffProc) (struct FCGX_Stream *stream); + void (*emptyBuffProc) (struct FCGX_Stream *stream, int doClose); + void *data; +} FCGX_Stream; + +/* + * An environment (as defined by environ(7)): A NULL-terminated array + * of strings, each string having the form name=value. + */ +typedef char **FCGX_ParamArray; + +/* + * FCGX_Request Flags + * + * Setting FCGI_FAIL_ACCEPT_ON_INTR prevents FCGX_Accept() from + * restarting upon being interrupted. + */ +#define FCGI_FAIL_ACCEPT_ON_INTR 1 + +/* + * FCGX_Request -- State associated with a request. + * + * Its exposed for API simplicity, I expect parts of it to change! + */ +typedef struct FCGX_Request { + int requestId; /* valid if isBeginProcessed */ + int role; + FCGX_Stream *in; + FCGX_Stream *out; + FCGX_Stream *err; + char **envp; + + /* Don't use anything below here */ + + struct Params *paramsPtr; + int ipcFd; /* < 0 means no connection */ + int isBeginProcessed; /* FCGI_BEGIN_REQUEST seen */ + int keepConnection; /* don't close ipcFd at end of request */ + int appStatus; + int nWriters; /* number of open writers (0..2) */ + int flags; + int listen_sock; +} FCGX_Request; + + +/* + *====================================================================== + * Control + *====================================================================== + */ + +/* + *---------------------------------------------------------------------- + * + * FCGX_IsCGI -- + * + * Returns TRUE iff this process appears to be a CGI process + * rather than a FastCGI process. + * + *---------------------------------------------------------------------- + */ +DLLAPI int FCGX_IsCGI(void); + +/* + *---------------------------------------------------------------------- + * + * FCGX_Init -- + * + * Initialize the FCGX library. Call in multi-threaded apps + * before calling FCGX_Accept_r(). + * + * Returns 0 upon success. + * + *---------------------------------------------------------------------- + */ +DLLAPI int FCGX_Init(void); + +/* + *---------------------------------------------------------------------- + * + * FCGX_OpenSocket -- + * + * Create a FastCGI listen socket. + * + * path is the Unix domain socket (named pipe for WinNT), or a colon + * followed by a port number. e.g. "/tmp/fastcgi/mysocket", ":5000" + * + * backlog is the listen queue depth used in the listen() call. + * + * Returns the socket's file descriptor or -1 on error. + * + *---------------------------------------------------------------------- + */ +DLLAPI int FCGX_OpenSocket(const char *path, int backlog); + +/* + *---------------------------------------------------------------------- + * + * FCGX_InitRequest -- + * + * Initialize a FCGX_Request for use with FCGX_Accept_r(). + * + * sock is a file descriptor returned by FCGX_OpenSocket() or 0 (default). + * The only supported flag at this time is FCGI_FAIL_ON_INTR. + * + * Returns 0 upon success. + *---------------------------------------------------------------------- + */ +DLLAPI int FCGX_InitRequest(FCGX_Request *request, int sock, int flags); + +/* + *---------------------------------------------------------------------- + * + * FCGX_Accept_r -- + * + * Accept a new request (multi-thread safe). Be sure to call + * FCGX_Init() first. + * + * Results: + * 0 for successful call, -1 for error. + * + * Side effects: + * + * Finishes the request accepted by (and frees any + * storage allocated by) the previous call to FCGX_Accept. + * Creates input, output, and error streams and + * assigns them to *in, *out, and *err respectively. + * Creates a parameters data structure to be accessed + * via getenv(3) (if assigned to environ) or by FCGX_GetParam + * and assigns it to *envp. + * + * DO NOT retain pointers to the envp array or any strings + * contained in it (e.g. to the result of calling FCGX_GetParam), + * since these will be freed by the next call to FCGX_Finish + * or FCGX_Accept. + * + * DON'T use the FCGX_Request, its structure WILL change. + * + *---------------------------------------------------------------------- + */ +DLLAPI int FCGX_Accept_r(FCGX_Request *request); + +/* + *---------------------------------------------------------------------- + * + * FCGX_Finish_r -- + * + * Finish the request (multi-thread safe). + * + * Side effects: + * + * Finishes the request accepted by (and frees any + * storage allocated by) the previous call to FCGX_Accept. + * + * DO NOT retain pointers to the envp array or any strings + * contained in it (e.g. to the result of calling FCGX_GetParam), + * since these will be freed by the next call to FCGX_Finish + * or FCGX_Accept. + * + *---------------------------------------------------------------------- + */ +DLLAPI void FCGX_Finish_r(FCGX_Request *request); + +/* + *---------------------------------------------------------------------- + * + * FCGX_Free -- + * + * Free the memory and, if close is true, + * IPC FD associated with the request (multi-thread safe). + * + *---------------------------------------------------------------------- + */ +DLLAPI void FCGX_Free(FCGX_Request * request, int close); + +/* + *---------------------------------------------------------------------- + * + * FCGX_Accept -- + * + * Accept a new request (NOT multi-thread safe). + * + * Results: + * 0 for successful call, -1 for error. + * + * Side effects: + * + * Finishes the request accepted by (and frees any + * storage allocated by) the previous call to FCGX_Accept. + * Creates input, output, and error streams and + * assigns them to *in, *out, and *err respectively. + * Creates a parameters data structure to be accessed + * via getenv(3) (if assigned to environ) or by FCGX_GetParam + * and assigns it to *envp. + * + * DO NOT retain pointers to the envp array or any strings + * contained in it (e.g. to the result of calling FCGX_GetParam), + * since these will be freed by the next call to FCGX_Finish + * or FCGX_Accept. + * + *---------------------------------------------------------------------- + */ +DLLAPI int FCGX_Accept( + FCGX_Stream **in, + FCGX_Stream **out, + FCGX_Stream **err, + FCGX_ParamArray *envp); + +/* + *---------------------------------------------------------------------- + * + * FCGX_Finish -- + * + * Finish the current request (NOT multi-thread safe). + * + * Side effects: + * + * Finishes the request accepted by (and frees any + * storage allocated by) the previous call to FCGX_Accept. + * + * DO NOT retain pointers to the envp array or any strings + * contained in it (e.g. to the result of calling FCGX_GetParam), + * since these will be freed by the next call to FCGX_Finish + * or FCGX_Accept. + * + *---------------------------------------------------------------------- + */ +DLLAPI void FCGX_Finish(void); + +/* + *---------------------------------------------------------------------- + * + * FCGX_StartFilterData -- + * + * stream is an input stream for a FCGI_FILTER request. + * stream is positioned at EOF on FCGI_STDIN. + * Repositions stream to the start of FCGI_DATA. + * If the preconditions are not met (e.g. FCGI_STDIN has not + * been read to EOF) sets the stream error code to + * FCGX_CALL_SEQ_ERROR. + * + * Results: + * 0 for a normal return, < 0 for error + * + *---------------------------------------------------------------------- + */ +DLLAPI int FCGX_StartFilterData(FCGX_Stream *stream); + +/* + *---------------------------------------------------------------------- + * + * FCGX_SetExitStatus -- + * + * Sets the exit status for stream's request. The exit status + * is the status code the request would have exited with, had + * the request been run as a CGI program. You can call + * SetExitStatus several times during a request; the last call + * before the request ends determines the value. + * + *---------------------------------------------------------------------- + */ +DLLAPI void FCGX_SetExitStatus(int status, FCGX_Stream *stream); + +/* + *====================================================================== + * Parameters + *====================================================================== + */ + +/* + *---------------------------------------------------------------------- + * + * FCGX_GetParam -- obtain value of FCGI parameter in environment + * + * + * Results: + * Value bound to name, NULL if name not present in the + * environment envp. Caller must not mutate the result + * or retain it past the end of this request. + * + *---------------------------------------------------------------------- + */ +DLLAPI char *FCGX_GetParam(const char *name, FCGX_ParamArray envp); + +/* + *====================================================================== + * Readers + *====================================================================== + */ + +/* + *---------------------------------------------------------------------- + * + * FCGX_GetChar -- + * + * Reads a byte from the input stream and returns it. + * + * Results: + * The byte, or EOF (-1) if the end of input has been reached. + * + *---------------------------------------------------------------------- + */ +DLLAPI int FCGX_GetChar(FCGX_Stream *stream); + +/* + *---------------------------------------------------------------------- + * + * FCGX_UnGetChar -- + * + * Pushes back the character c onto the input stream. One + * character of pushback is guaranteed once a character + * has been read. No pushback is possible for EOF. + * + * Results: + * Returns c if the pushback succeeded, EOF if not. + * + *---------------------------------------------------------------------- + */ +DLLAPI int FCGX_UnGetChar(int c, FCGX_Stream *stream); + +/* + *---------------------------------------------------------------------- + * + * FCGX_GetStr -- + * + * Reads up to n consecutive bytes from the input stream + * into the character array str. Performs no interpretation + * of the input bytes. + * + * Results: + * Number of bytes read. If result is smaller than n, + * the end of input has been reached. + * + *---------------------------------------------------------------------- + */ +DLLAPI int FCGX_GetStr(char *str, int n, FCGX_Stream *stream); + +/* + *---------------------------------------------------------------------- + * + * FCGX_GetLine -- + * + * Reads up to n-1 consecutive bytes from the input stream + * into the character array str. Stops before n-1 bytes + * have been read if '\n' or EOF is read. The terminating '\n' + * is copied to str. After copying the last byte into str, + * stores a '\0' terminator. + * + * Results: + * NULL if EOF is the first thing read from the input stream, + * str otherwise. + * + *---------------------------------------------------------------------- + */ +DLLAPI char *FCGX_GetLine(char *str, int n, FCGX_Stream *stream); + +/* + *---------------------------------------------------------------------- + * + * FCGX_HasSeenEOF -- + * + * Returns EOF if end-of-file has been detected while reading + * from stream; otherwise returns 0. + * + * Note that FCGX_HasSeenEOF(s) may return 0, yet an immediately + * following FCGX_GetChar(s) may return EOF. This function, like + * the standard C stdio function feof, does not provide the + * ability to peek ahead. + * + * Results: + * EOF if end-of-file has been detected, 0 if not. + * + *---------------------------------------------------------------------- + */ + +DLLAPI int FCGX_HasSeenEOF(FCGX_Stream *stream); + +/* + *====================================================================== + * Writers + *====================================================================== + */ + +/* + *---------------------------------------------------------------------- + * + * FCGX_PutChar -- + * + * Writes a byte to the output stream. + * + * Results: + * The byte, or EOF (-1) if an error occurred. + * + *---------------------------------------------------------------------- + */ +DLLAPI int FCGX_PutChar(int c, FCGX_Stream *stream); + +/* + *---------------------------------------------------------------------- + * + * FCGX_PutStr -- + * + * Writes n consecutive bytes from the character array str + * into the output stream. Performs no interpretation + * of the output bytes. + * + * Results: + * Number of bytes written (n) for normal return, + * EOF (-1) if an error occurred. + * + *---------------------------------------------------------------------- + */ +DLLAPI int FCGX_PutStr(const char *str, int n, FCGX_Stream *stream); + +/* + *---------------------------------------------------------------------- + * + * FCGX_PutS -- + * + * Writes a null-terminated character string to the output stream. + * + * Results: + * number of bytes written for normal return, + * EOF (-1) if an error occurred. + * + *---------------------------------------------------------------------- + */ +DLLAPI int FCGX_PutS(const char *str, FCGX_Stream *stream); + +/* + *---------------------------------------------------------------------- + * + * FCGX_FPrintF, FCGX_VFPrintF -- + * + * Performs printf-style output formatting and writes the results + * to the output stream. + * + * Results: + * number of bytes written for normal return, + * EOF (-1) if an error occurred. + * + *---------------------------------------------------------------------- + */ +DLLAPI int FCGX_FPrintF(FCGX_Stream *stream, const char *format, ...); + +DLLAPI int FCGX_VFPrintF(FCGX_Stream *stream, const char *format, va_list arg); + +/* + *---------------------------------------------------------------------- + * + * FCGX_FFlush -- + * + * Flushes any buffered output. + * + * Server-push is a legitimate application of FCGX_FFlush. + * Otherwise, FCGX_FFlush is not very useful, since FCGX_Accept + * does it implicitly. Calling FCGX_FFlush in non-push applications + * results in extra writes and therefore reduces performance. + * + * Results: + * EOF (-1) if an error occurred. + * + *---------------------------------------------------------------------- + */ +DLLAPI int FCGX_FFlush(FCGX_Stream *stream); + +/* + *====================================================================== + * Both Readers and Writers + *====================================================================== + */ + +/* + *---------------------------------------------------------------------- + * + * FCGX_FClose -- + * + * Closes the stream. For writers, flushes any buffered + * output. + * + * Close is not a very useful operation since FCGX_Accept + * does it implicitly. Closing the out stream before the + * err stream results in an extra write if there's nothing + * in the err stream, and therefore reduces performance. + * + * Results: + * EOF (-1) if an error occurred. + * + *---------------------------------------------------------------------- + */ +DLLAPI int FCGX_FClose(FCGX_Stream *stream); + +/* + *---------------------------------------------------------------------- + * + * FCGX_GetError -- + * + * Return the stream error code. 0 means no error, > 0 + * is an errno(2) error, < 0 is an FastCGI error. + * + *---------------------------------------------------------------------- + */ +DLLAPI int FCGX_GetError(FCGX_Stream *stream); + +/* + *---------------------------------------------------------------------- + * + * FCGX_ClearError -- + * + * Clear the stream error code and end-of-file indication. + * + *---------------------------------------------------------------------- + */ +DLLAPI void FCGX_ClearError(FCGX_Stream *stream); + +/* + *---------------------------------------------------------------------- + * + * FCGX_CreateWriter -- + * + * Create a FCGX_Stream (used by cgi-fcgi). This shouldn't + * be needed by a FastCGI applictaion. + * + *---------------------------------------------------------------------- + */ +DLLAPI FCGX_Stream *FCGX_CreateWriter( + int socket, + int requestId, + int bufflen, + int streamType); + +/* + *---------------------------------------------------------------------- + * + * FCGX_FreeStream -- + * + * Free a FCGX_Stream (used by cgi-fcgi). This shouldn't + * be needed by a FastCGI applictaion. + * + *---------------------------------------------------------------------- + */ +DLLAPI void FCGX_FreeStream(FCGX_Stream **stream); + +/* ---------------------------------------------------------------------- + * + * Prevent the lib from accepting any new requests. Signal handler safe. + * + * ---------------------------------------------------------------------- + */ +DLLAPI void FCGX_ShutdownPending(void); + +#if defined (__cplusplus) || defined (c_plusplus) +} /* terminate extern "C" { */ +#endif + +#endif /* _FCGIAPP_H */ diff --git a/iipsrv/fcgi/include/fcgimisc.h b/iipsrv/fcgi/include/fcgimisc.h new file mode 100644 index 0000000..0464455 --- /dev/null +++ b/iipsrv/fcgi/include/fcgimisc.h @@ -0,0 +1,38 @@ +/* + * fcgimisc.h -- + * + * Miscellaneous definitions + * + * + * Copyright (c) 1996 Open Market, Inc. + * + * See the file "LICENSE.TERMS" for information on usage and redistribution + * of this file, and for a DISCLAIMER OF ALL WARRANTIES. + * + * $Id: fcgimisc.h,v 1.3 2001/06/18 14:25:47 robs Exp $ + */ + +#ifndef _FCGIMISC_H +#define _FCGIMISC_H + +#ifndef FALSE +#define FALSE (0) +#endif + +#ifndef TRUE +#define TRUE (1) +#endif + +#ifndef min +#define min(a,b) ((a) < (b) ? (a) : (b)) +#endif + +#ifndef max +#define max(a,b) ((a) > (b) ? (a) : (b)) +#endif + +#ifndef ASSERT +#define ASSERT(assertion) assert(assertion) +#endif + +#endif /* _FCGIMISC_H */ diff --git a/iipsrv/fcgi/include/fcgio.h b/iipsrv/fcgi/include/fcgio.h new file mode 100644 index 0000000..20d222a --- /dev/null +++ b/iipsrv/fcgi/include/fcgio.h @@ -0,0 +1,151 @@ +// +// Provides support for FastCGI via C++ iostreams. +// +// $Id: fcgio.h,v 1.15 2002/02/25 13:16:11 robs Exp $ +// +// This work is based on routines written by George Feinberg. They +// have been mostly re-written and extensively changed by +// Michael Richards. +// +// Rewritten again with bug fixes and numerous enhancements by +// Michael Shell. +// +// And rewritten again by Rob Saccoccio. +// +// Special Thanks to Dietmar Kuehl for his help and the numerous custom +// streambuf examples on his web site. +// +// Copyright (c) 2000 Tux the Linux Penguin +// Copyright (c) 2001 Rob Saccoccio and Chelsea Networks +// +// You are free to use this software without charge or royalty +// as long as this notice is not removed or altered, and recognition +// is given to the author(s) +// +// This code is offered as-is without any warranty either expressed or +// implied; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. If it breaks, you get to keep +// both halves. + +#ifndef FCGIO_H +#define FCGIO_H + +#include + +#include "fcgiapp.h" + +#ifndef DLLAPI +#ifdef _WIN32 +#define DLLAPI __declspec(dllimport) +#else +#define DLLAPI +#endif +#endif + +#if ! HAVE_STREAMBUF_CHAR_TYPE +typedef char char_type; +#endif + +/* + * fcgi_streambuf + */ +class DLLAPI fcgi_streambuf : public std::streambuf +{ +public: + + // Note that if no buf is assigned (the default), iostream methods + // such as peek(), unget() and putback() will fail. If a buf is + // assigned, I/O is a bit less effecient and output streams will + // have to be flushed (or the streambuf destroyed) before the next + // call to "accept". + fcgi_streambuf(FCGX_Stream * fcgx, char * buf, int len); + + fcgi_streambuf(char_type * buf, std::streamsize len); + + fcgi_streambuf(FCGX_Stream * fcgx = 0); + + ~fcgi_streambuf(void); + + int attach(FCGX_Stream * fcgx); + +protected: + + // Consume the put area (if buffered) and c (if c is not EOF). + virtual int overflow(int); + + // Flush the put area (if buffered) and the FCGX buffer to the client. + virtual int sync(); + + // Remove and return the current character. + virtual int uflow(); + + // Fill the get area (if buffered) and return the current character. + virtual int underflow(); + + // Use a buffer. The only reasons that a buffer would be useful is + // to support the use of the unget()/putback() or seek() methods. Using + // a buffer will result in less efficient I/O. Note: the underlying + // FastCGI library (FCGX) maintains its own input and output buffers. + virtual std::streambuf * setbuf(char_type * buf, std::streamsize len); + + virtual std::streamsize xsgetn(char_type * s, std::streamsize n); + virtual std::streamsize xsputn(const char_type * s, std::streamsize n); + +private: + + FCGX_Stream * fcgx; + + // buf is just handy to have around + char_type * buf; + + // this isn't kept by the base class + std::streamsize bufsize; + + void init(FCGX_Stream * fcgx, char_type * buf, std::streamsize bufsize); + + void reset(void); +}; + +/* + * fcgi_istream - deprecated + */ +class DLLAPI fcgi_istream : public std::istream +{ +public: + + // deprecated + fcgi_istream(FCGX_Stream * fcgx = 0); + + // deprecated + ~fcgi_istream(void) {} + + // deprecated + virtual void attach(FCGX_Stream * fcgx); + +private: + + fcgi_streambuf fcgi_strmbuf; +}; + +/* + * fcgi_ostream - deprecated + */ +class DLLAPI fcgi_ostream : public std::ostream +{ +public: + + // deprecated + fcgi_ostream(FCGX_Stream * fcgx = 0); + + // deprecated + ~fcgi_ostream(void) {} + + // deprecated + virtual void attach(FCGX_Stream *fcgx); + +private: + + fcgi_streambuf fcgi_strmbuf; +}; + +#endif /* FCGIO_H */ diff --git a/iipsrv/fcgi/include/fcgios.h b/iipsrv/fcgi/include/fcgios.h new file mode 100644 index 0000000..de7c3c7 --- /dev/null +++ b/iipsrv/fcgi/include/fcgios.h @@ -0,0 +1,130 @@ +/* + * fcgios.h -- + * + * Description of file. + * + * + * Copyright (c) 1996 Open Market, Inc. + * All rights reserved. + * + * This file contains proprietary and confidential information and + * remains the unpublished property of Open Market, Inc. Use, + * disclosure, or reproduction is prohibited except as permitted by + * express written license agreement with Open Market, Inc. + * + * Bill Snapper + * snapper@openmarket.com + */ +#ifndef _FCGIOS_H +#define _FCGIOS_H + +#ifdef _WIN32 +#define WIN32_LEAN_AND_MEAN +#include +#include +#endif + +#include "fcgi_config.h" + +#ifdef HAVE_SYS_TIME_H +#include +#endif + +#ifdef HAVE_SYS_TYPES_H +#include +#endif + +#if defined (c_plusplus) || defined (__cplusplus) +extern "C" { +#endif + +#ifdef _WIN32 +#define OS_Errno GetLastError() +#define OS_SetErrno(err) SetLastError(err) +#ifndef O_NONBLOCK +#define O_NONBLOCK 0x0004 /* no delay */ +#endif +#else /* !_WIN32 */ +#define OS_Errno errno +#define OS_SetErrno(err) errno = (err) +#endif /* !_WIN32 */ + +#ifndef DLLAPI +#ifdef _WIN32 +#define DLLAPI __declspec(dllimport) +#else +#define DLLAPI +#endif +#endif + + +/* This is the initializer for a "struct timeval" used in a select() call + * right after a new request is accept()ed to determine readablity. Its + * a drop-dead timer. Its only used for AF_UNIX sockets (not TCP sockets). + * Its a workaround for a kernel bug in Linux 2.0.x and SCO Unixware. + * Making this as small as possible, yet remain reliable would be best. + * 2 seconds is very conservative. 0,0 is not reliable. The shorter the + * timeout, the faster request processing will recover. The longer the + * timeout, the more likely this application being "busy" will cause other + * requests to abort and cause more dead sockets that need this timeout. */ +#define READABLE_UNIX_FD_DROP_DEAD_TIMEVAL 2,0 + +#ifndef STDIN_FILENO +#define STDIN_FILENO 0 +#endif + +#ifndef STDOUT_FILENO +#define STDOUT_FILENO 1 +#endif + +#ifndef STDERR_FILENO +#define STDERR_FILENO 2 +#endif + +#ifndef MAXPATHLEN +#define MAXPATHLEN 1024 +#endif + +#ifndef X_OK +#define X_OK 0x01 +#endif + +#ifndef _CLIENTDATA +# if defined(__STDC__) || defined(__cplusplus) + typedef void *ClientData; +# else + typedef int *ClientData; +# endif /* __STDC__ */ +#define _CLIENTDATA +#endif + +typedef void (*OS_AsyncProc) (ClientData clientData, int len); + +DLLAPI int OS_LibInit(int stdioFds[3]); +DLLAPI void OS_LibShutdown(void); +DLLAPI int OS_CreateLocalIpcFd(const char *bindPath, int backlog); +DLLAPI int OS_FcgiConnect(char *bindPath); +DLLAPI int OS_Read(int fd, char * buf, size_t len); +DLLAPI int OS_Write(int fd, char * buf, size_t len); +DLLAPI int OS_SpawnChild(char *execPath, int listenFd); +DLLAPI int OS_AsyncReadStdin(void *buf, int len, OS_AsyncProc procPtr, + ClientData clientData); +DLLAPI int OS_AsyncRead(int fd, int offset, void *buf, int len, + OS_AsyncProc procPtr, ClientData clientData); +DLLAPI int OS_AsyncWrite(int fd, int offset, void *buf, int len, + OS_AsyncProc procPtr, ClientData clientData); +DLLAPI int OS_Close(int fd); +DLLAPI int OS_CloseRead(int fd); +DLLAPI int OS_DoIo(struct timeval *tmo); +DLLAPI int OS_Accept(int listen_sock, int fail_on_intr, const char *webServerAddrs); +DLLAPI int OS_IpcClose(int ipcFd); +DLLAPI int OS_IsFcgi(int sock); +DLLAPI void OS_SetFlags(int fd, int flags); + +DLLAPI void OS_ShutdownPending(void); + +#if defined (__cplusplus) || defined (c_plusplus) +} /* terminate extern "C" { */ +#endif + +#endif /* _FCGIOS_H */ diff --git a/iipsrv/fcgi/java/FCGIGlobalDefs.java b/iipsrv/fcgi/java/FCGIGlobalDefs.java new file mode 100644 index 0000000..04de745 --- /dev/null +++ b/iipsrv/fcgi/java/FCGIGlobalDefs.java @@ -0,0 +1,92 @@ +/* + * @(#)FCGIGlobalDefs.java + * + * + * FastCGi compatibility package Interface + * + * + * Copyright (c) 1996 Open Market, Inc. + * + * See the file "LICENSE.TERMS" for information on usage and redistribution + * of this file, and for a DISCLAIMER OF ALL WARRANTIES. + * + * $Id: FCGIGlobalDefs.java,v 1.3 2000/03/21 12:12:25 robs Exp $ + */ + +/* This class contains FCGI global definitions corresponding to + * the #defs in the C version. + */ + +package com.fastcgi; + +import java.io.PrintStream; + +public abstract class FCGIGlobalDefs +{ + private static final String RCSID = "$Id: FCGIGlobalDefs.java,v 1.3 2000/03/21 12:12:25 robs Exp $"; + + public static final int def_FCGIMaxLen = 0xffff; + /* + * Define Length of FCGI message bodies in bytes + */ + public static final int def_FCGIHeaderLen = 8; + public static final int def_FCGIEndReqBodyLen = 8; + public static final int def_FCGIBeginReqBodyLen = 8; + public static final int def_FCGIUnknownBodyTypeBodyLen = 8; + /* + * Header defines + */ + public static int def_FCGIVersion1 = 1; + /* FCGI Record Types */ + public static final int def_FCGIBeginRequest = 1; + public static final int def_FCGIAbortRequest = 2; + public static final int def_FCGIEndRequest = 3; + public static final int def_FCGIParams = 4; + public static final int def_FCGIStdin = 5; + public static final int def_FCGIStdout = 6; + public static final int def_FCGIStderr = 7; + public static final int def_FCGIData = 8; + public static final int def_FCGIGetValues = 9; + public static final int def_FCGIGetValuesResult = 10; + public static final int def_FCGIUnknownType = 11; + public static final int def_FCGIMaxType = def_FCGIUnknownType; + /* Request ID Values */ + public static final int def_FCGINullRequestID = 0; + /* + * Begin Request defines + */ + /* Mask flags */ + public static int def_FCGIKeepConn = 1; + /* Roles */ + public static final int def_FCGIResponder = 1; + public static final int def_FCGIAuthorizer = 2; + public static final int def_FCGIFilter = 3; + /* + * End Request defines + */ + /* Protocol status */ + public static final int def_FCGIRequestComplete = 0; + public static final int def_FCGICantMpxConn = 1; + public static final int def_FCGIOverload = 2; + public static final int def_FCGIUnknownRole = 3; + /* + * Get Values, Get Values Results defines + */ + public static final String def_FCGIMaxConns = "FCGI_MAX_CONNS"; + public static final String def_FCGIMaxReqs = "FCGI_MAX_REQS"; + public static final String def_FCGIMpxsConns = "FCGI_MPXS_CONNS"; + /* + * Return codes for Process* functions + */ + public static final int def_FCGIStreamRecord = 0; + public static final int def_FCGISkip = 1; + public static final int def_FCGIBeginRecord = 2; + public static final int def_FCGIMgmtRecord = 3; + /* + * Error Codes + */ + public static final int def_FCGIUnsupportedVersion = -2; + public static final int def_FCGIProtocolError = -3; + public static final int def_FCGIParamsError = -4; + public static final int def_FCGICallSeqError = -5; +} diff --git a/iipsrv/fcgi/java/FCGIInputStream.java b/iipsrv/fcgi/java/FCGIInputStream.java new file mode 100644 index 0000000..4d3550d --- /dev/null +++ b/iipsrv/fcgi/java/FCGIInputStream.java @@ -0,0 +1,381 @@ +/* + * @(#)FCGIInputStream.java + * + * FastCGi compatibility package Interface + * + * + * Copyright (c) 1996 Open Market, Inc. + * + * See the file "LICENSE.TERMS" for information on usage and redistribution + * of this file, and for a DISCLAIMER OF ALL WARRANTIES. + * + * $Id: FCGIInputStream.java,v 1.4 2000/03/21 12:12:25 robs Exp $ + */ +package com.fastcgi; + +import java.io.*; + +/** + * This stream manages buffered reads of FCGI messages. + */ +public class FCGIInputStream extends InputStream +{ + private static final String RCSID = "$Id: FCGIInputStream.java,v 1.4 2000/03/21 12:12:25 robs Exp $"; + + /* Stream vars */ + + public int rdNext; + public int stop; + public boolean isClosed; + + /* require methods to set, get and clear */ + private int errno; + private Exception errex; + + /* data vars */ + + public byte buff[]; + public int buffLen; + public int buffStop; + public int type; + public int contentLen; + public int paddingLen; + public boolean skip; + public boolean eorStop; + public FCGIRequest request; + + public InputStream in; + + + /** + * Creates a new input stream to manage fcgi prototcol stuff + * @param in the input stream bufLen length of buffer streamType + */ + public FCGIInputStream(FileInputStream inStream, int bufLen, + int streamType, + FCGIRequest inReq) { + + in = inStream; + buffLen = Math.min(bufLen,FCGIGlobalDefs.def_FCGIMaxLen); + buff = new byte[buffLen]; + type = streamType; + stop = rdNext = buffStop = 0; + isClosed = false; + contentLen = 0; + paddingLen = 0; + skip = false; + eorStop = false; + request = inReq; + + } + /** + * Reads a byte of data. This method will block if no input is + * available. + * @return the byte read, or -1 if the end of the + * stream is reached. + * @exception IOException If an I/O error has occurred. + */ + public int read() throws IOException { + if (rdNext != stop) { + return buff[rdNext++] & 0xff; + } + if (isClosed){ + return -1; + } + fill(); + if (rdNext != stop){ + return buff[rdNext++] & 0xff; + } + return -1; + } + /** + * Reads into an array of bytes. This method will + * block until some input is available. + * @param b the buffer into which the data is read + * @return the actual number of bytes read, -1 is + * returned when the end of the stream is reached. + * @exception IOException If an I/O error has occurred. + */ + public int read(byte b[]) throws IOException { + return read(b, 0, b.length); + } + + /** + * Reads into an array of bytes. + * Blocks until some input is available. + * @param b the buffer into which the data is read + * @param off the start offset of the data + * @param len the maximum number of bytes read + * @return the actual number of bytes read, -1 is + * returned when the end of the stream is reached. + * @exception IOException If an I/O error has occurred. + */ + public int read(byte b[], int off, int len) throws IOException { + int m, bytesMoved; + + if (len <= 0){ + return 0; + } + /* + *Fast path: len bytes already available. + */ + + if (len <= stop - rdNext){ + System.arraycopy(buff, rdNext, b, off, len); + rdNext += len; + return len; + } + /* + *General case: stream is closed or fill needs to be called + */ + bytesMoved = 0; + for(;;){ + if (rdNext != stop){ + m = Math.min(len - bytesMoved, stop - rdNext); + System.arraycopy(buff, rdNext, b, off, m); + bytesMoved += m; + rdNext += m; + if (bytesMoved == len) + return bytesMoved; + off += m; + } + if (isClosed){ + return bytesMoved; + } + fill(); + + } + } + /** + * Reads into an array of bytes. This method will + * block until some input is available. + * @param b the buffer into which the data is read + * @param off the start offset of the data + * @param len the maximum number of bytes read + * @return the actual number of bytes read, -1 is + * returned when the end of the stream is reached. + * @exception IOException If an I/O error has occurred. + */ + public void fill() throws IOException { + byte[] headerBuf = new byte[FCGIGlobalDefs.def_FCGIHeaderLen]; + int headerLen = 0; + int status = 0; + int count = 0; + for(;;) { + /* + * If buffer is empty, do a read + */ + if (rdNext == buffStop) { + try { + count = in.read(buff, 0, buffLen); + } catch (IOException e) { + setException(e); + return; + } + if (count == 0) { + setFCGIError(FCGIGlobalDefs.def_FCGIProtocolError); + return; + } + rdNext = 0; + buffStop = count; // 1 more than we read + } + /* Now buf is not empty: If the current record contains more content + * bytes, deliver all that are present in buff to callers buffer + * unless he asked for less than we have, in which case give him less + */ + if (contentLen > 0) { + count = Math.min(contentLen, buffStop - rdNext); + contentLen -= count; + if (!skip) { + stop = rdNext + count; + return; + } + else { + rdNext += count; + if (contentLen > 0) { + continue; + } + else { + skip = false; + } + } + } + /* Content has been consumed by client. + * If record was padded, skip over padding + */ + if (paddingLen > 0) { + count = Math.min(paddingLen, buffStop - rdNext); + paddingLen -= count; + rdNext += count; + if (paddingLen > 0) { + continue; // more padding to read + } + } + /* All done with current record, including the padding. + * If we are in a recursive call from Process Header, deliver EOF + */ + if (eorStop){ + stop = rdNext; + isClosed = true; + return; + } + /* + * Fill header with bytes from input buffer - get the whole header. + */ + count = Math.min(headerBuf.length - headerLen, buffStop - rdNext); + System.arraycopy(buff,rdNext, headerBuf, headerLen, count); + headerLen += count; + rdNext += count; + if (headerLen < headerBuf.length) { + continue; + } + headerLen = 0; + /* + * Interperet the header. eorStop prevents ProcessHeader from + * reading past the end of record when using stream to read content + */ + eorStop = true; + stop = rdNext; + status = 0; + status = new FCGIMessage(this).processHeader(headerBuf); + eorStop = false; + isClosed = false; + switch (status){ + case FCGIGlobalDefs.def_FCGIStreamRecord: + if (contentLen == 0) { + stop = rdNext; + isClosed = true; + return; + } + break; + case FCGIGlobalDefs.def_FCGISkip: + skip = true; + break; + case FCGIGlobalDefs.def_FCGIBeginRecord: + /* + * If this header marked the beginning of a new + * request, return role info to caller + */ + return; + case FCGIGlobalDefs.def_FCGIMgmtRecord: + break; + default: + /* + * ASSERT + */ + setFCGIError(status); + return; + + } + } + } + + /** + * Skips n bytes of input. + * @param n the number of bytes to be skipped + * @return the actual number of bytes skipped. + * @exception IOException If an I/O error has occurred. + */ + public long skip(long n) throws IOException { + byte data[] = new byte[(int)n]; + return in.read(data); + } + + /* + * An FCGI error has occurred. Save the error code in the stream + * for diagnostic purposes and set the stream state so that + * reads return EOF + */ + public void setFCGIError(int errnum) { + /* + * Preserve only the first error. + */ + if(errno == 0) { + errno = errnum; + } + isClosed = true; + } + /* + * An Exception has occurred. Save the Exception in the stream + * for diagnostic purposes and set the stream state so that + * reads return EOF + */ + public void setException(Exception errexpt) { + /* + * Preserve only the first error. + */ + if(errex == null) { + errex = errexpt; + } + isClosed = true; + } + + /* + * Clear the stream error code and end-of-file indication. + */ + public void clearFCGIError() { + errno = 0; + /* + * isClosed = false; + * XXX: should clear isClosed but work is needed to make it safe + * to do so. + */ + } + /* + * Clear the stream error code and end-of-file indication. + */ + public void clearException() { + errex = null; + /* + * isClosed = false; + * XXX: should clear isClosed but work is needed to make it safe + * to do so. + */ + } + + /* + * accessor method since var is private + */ + public int getFCGIError() { + return errno; + } + /* + * accessor method since var is private + */ + public Exception getException() { + return errex; + } + /* + * Re-initializes the stream to read data of the specified type. + */ + public void setReaderType(int streamType) { + + type = streamType; + eorStop = false; + skip = false; + contentLen = 0; + paddingLen = 0; + stop = rdNext; + isClosed = false; + } + + /* + * Close the stream. This method does not really exist for BufferedInputStream in java, + * but is implemented here for compatibility with the FCGI structures being used. It + * doent really throw any IOExceptions either, but that's there for compatiblity with + * the InputStreamInterface. + */ + public void close() throws IOException{ + isClosed = true; + stop = rdNext; + } + + /* + * Returns the number of bytes that can be read without blocking. + */ + + public int available() throws IOException { + return stop - rdNext + in.available(); + } + +} diff --git a/iipsrv/fcgi/java/FCGIInterface.java b/iipsrv/fcgi/java/FCGIInterface.java new file mode 100644 index 0000000..03e8caa --- /dev/null +++ b/iipsrv/fcgi/java/FCGIInterface.java @@ -0,0 +1,247 @@ +/* + * @(#)FCGIInterface.java + * + * + * FastCGi compatibility package Interface + * + * + * Copyright (c) 1996 Open Market, Inc. + * + * See the file "LICENSE.TERMS" for information on usage and redistribution + * of this file, and for a DISCLAIMER OF ALL WARRANTIES. + * + * $Id: FCGIInterface.java,v 1.4 2000/03/27 15:37:25 robs Exp $ + */ +package com.fastcgi; + +import java.net.*; +import java.io.*; +import java.util.Properties; + +/* + * This is the FastCGI interface that the application calls to communicate with the + * FastCGI web server. This version is single threaded, and handles one request at + * a time, which is why we can have a static variable for it. + */ +public class FCGIInterface +{ + private static final String RCSID = "$Id: FCGIInterface.java,v 1.4 2000/03/27 15:37:25 robs Exp $"; + + /* + * Class variables + */ + public static FCGIRequest request = null; + public static boolean acceptCalled = false; + public static boolean isFCGI = true; + public static Properties startupProps; + public static ServerSocket srvSocket; + + /* + * Accepts a new request from the HTTP server and creates + * a conventional execution environment for the request. + * If the application was invoked as a FastCGI server, + * the first call to FCGIaccept indicates that the application + * has completed its initialization and is ready to accept + * a request. Subsequent calls to FCGI_accept indicate that + * the application has completed its processing of the + * current request and is ready to accept a new request. + * If the application was invoked as a CGI program, the first + * call to FCGIaccept is essentially a no-op and the second + * call returns EOF (-1) as does an error. Application should exit. + * + * If the application was invoked as a FastCGI server, + * and this is not the first call to this procedure, + * FCGIaccept first flushes any buffered output to the HTTP server. + * + * On every call, FCGIaccept accepts the new request and + * reads the FCGI_PARAMS stream into System.props. It also creates + * streams that understand FastCGI protocol and take input from + * the HTTP server send output and error output to the HTTP server, + * and assigns these new streams to System.in, System.out and + * System.err respectively. + * + * For now, we will just return an int to the caller, which is why + * this method catches, but doen't throw Exceptions. + * + */ + public int FCGIaccept() { + int acceptResult = 0; + + /* + * If first call, mark it and if fcgi save original system properties, + * If not first call, and we are cgi, we should be gone. + */ + if (!acceptCalled){ + isFCGI = System.getProperties().containsKey("FCGI_PORT"); + acceptCalled = true; + if (isFCGI) { + /* + * save original system properties (nonrequest) + * and get a server socket + */ + startupProps = new Properties(System.getProperties()); + String str = + new String(System.getProperty("FCGI_PORT")); + if (str.length() <= 0) { + return -1; + } + int portNum = Integer.parseInt(str); + + try { + srvSocket = new ServerSocket(portNum); + } catch (IOException e) { + if (request != null) + { + request.socket = null; + } + srvSocket = null; + request = null; + return -1; + } + } + } + else { + if (!isFCGI){ + return -1; + } + } + /* + * If we are cgi, just leave everything as is, otherwise set up env + */ + if (isFCGI){ + try { + acceptResult = FCGIAccept(); + } catch (IOException e) { + return -1; + } + if (acceptResult < 0){ + return -1; + } + + /* + * redirect stdin, stdout and stderr to fcgi socket + */ + System.setIn(new BufferedInputStream(request.inStream, 8192)); + System.setOut(new PrintStream(new BufferedOutputStream( + request.outStream, 8192))); + System.setErr(new PrintStream(new BufferedOutputStream( + request.errStream, 512))); + System.setProperties(request.params); + } + return 0; + } + + /* + * Accepts a new request from the HTTP server. + * Finishes the request accepted by the previous call + * to FCGI_Accept. Sets up the FCGI environment and reads + * saved and per request environmental varaibles into + * the request object. (This is redundant on System.props + * as long as we can handle only one request object.) + */ + int FCGIAccept() throws IOException{ + + boolean isNewConnection; + boolean errCloseEx = false; + boolean outCloseEx = false; + + if (request != null) { + /* + * Complete the previous request + */ + System.err.close(); + System.out.close(); + boolean prevRequestfailed = (errCloseEx || outCloseEx || + request.inStream.getFCGIError() != 0 || + request.inStream.getException() != null); + if (prevRequestfailed || !request.keepConnection ) { + request.socket.close(); + request.socket = null; + } + if (prevRequestfailed) { + request = null; + return -1; + } + } + else { + /* + * Get a Request and initialize some variables + */ + request = new FCGIRequest(); + request.socket = null; + request.inStream = null; + } + isNewConnection = false; + + /* + * if connection isnt open accept a new connection (blocking) + */ + for(;;) { + if (request.socket == null){ + try { + request.socket = srvSocket.accept(); + } catch (IOException e) { + request.socket = null; + request = null; + return -1; + } + isNewConnection = true; + } + + /* Try reading from new connection. If the read fails and + * it was an old connection the web server probably closed it; + * try making a new connection before giving up + */ + request.isBeginProcessed = false; + request.inStream = + new FCGIInputStream((FileInputStream)request. + socket.getInputStream(), + 8192, 0, request); + request.inStream.fill(); + if (request.isBeginProcessed) { + break; + } + request.socket.close(); + + request.socket = null; + if (isNewConnection) { + return -1; + } + } + /* + * Set up the objects for the new request + */ + request.params = new Properties(startupProps); + switch(request.role) { + case FCGIGlobalDefs.def_FCGIResponder: + request.params.put("ROLE","RESPONDER"); + break; + case FCGIGlobalDefs.def_FCGIAuthorizer: + request.params.put("ROLE", "AUTHORIZER"); + break; + case FCGIGlobalDefs.def_FCGIFilter: + request.params.put("ROLE", "FILTER"); + break; + default: + return -1; + } + request.inStream.setReaderType(FCGIGlobalDefs.def_FCGIParams); + /* + * read the rest of request parameters + */ + if (new FCGIMessage(request.inStream).readParams(request.params) < 0) { + return -1; + } + request.inStream.setReaderType(FCGIGlobalDefs.def_FCGIStdin); + request.outStream + = new FCGIOutputStream((FileOutputStream)request.socket. + getOutputStream(), 8192, + FCGIGlobalDefs.def_FCGIStdout,request); + request.errStream + = new FCGIOutputStream((FileOutputStream)request.socket. + getOutputStream(), 512, + FCGIGlobalDefs.def_FCGIStderr,request); + request.numWriters = 2; + return 0; + } +} diff --git a/iipsrv/fcgi/java/FCGIMessage.java b/iipsrv/fcgi/java/FCGIMessage.java new file mode 100644 index 0000000..0f474a9 --- /dev/null +++ b/iipsrv/fcgi/java/FCGIMessage.java @@ -0,0 +1,411 @@ +/* + * @(#)FCGIMessage.java + * + * + * FastCGi compatibility package Interface + * + * + * Copyright (c) 1996 Open Market, Inc. + * + * See the file "LICENSE.TERMS" for information on usage and redistribution + * of this file, and for a DISCLAIMER OF ALL WARRANTIES. + * + * $Id: FCGIMessage.java,v 1.4 2000/10/02 15:09:07 robs Exp $ + */ +package com.fastcgi; + +import java.io.*; +import java.util.Properties; + +/* This class handles reading and building the fastcgi messages. + * For reading incoming mesages, we pass the input + * stream as a param to the constructor rather than to each method. + * Methods that build messages use and return internal buffers, so they + * dont need a stream. + */ + +public class FCGIMessage +{ + private static final String RCSID = "$Id: FCGIMessage.java,v 1.4 2000/10/02 15:09:07 robs Exp $"; + + /* + * Instance variables + */ + /* + * FCGI Message Records + * The logical structures of the FCGI Message Records. + * Fields are originally 1 unsigned byte in message + * unless otherwise noted. + */ + /* + * FCGI Header + */ + private int h_version; + private int h_type; + private int h_requestID; // 2 bytes + private int h_contentLength; // 2 bytes + private int h_paddingLength; + /* + * FCGI BeginRequest body. + */ + private int br_role; // 2 bytes + private int br_flags; + + private FCGIInputStream in; + + /* + * constructor - Java would do this implicitly. + */ + public FCGIMessage(){ + super(); + } + /* + * constructor - get the stream. + */ + public FCGIMessage(FCGIInputStream instream){ + in = instream; + } + + /* + * Message Reading Methods + */ + + /* + * Interpret the FCGI Message Header. Processes FCGI + * BeginRequest and Management messages. Param hdr is the header. + * The calling routine has to keep track of the stream reading + * management or use FCGIInputStream.fill() which does just that. + */ + public int processHeader(byte[] hdr) throws IOException{ + processHeaderBytes(hdr); + if (h_version != FCGIGlobalDefs.def_FCGIVersion1) { + return(FCGIGlobalDefs.def_FCGIUnsupportedVersion); + } + in.contentLen = h_contentLength; + in.paddingLen = h_paddingLength; + if (h_type == FCGIGlobalDefs.def_FCGIBeginRequest) { + return processBeginRecord(h_requestID); + } + if (h_requestID == FCGIGlobalDefs.def_FCGINullRequestID) { + return processManagementRecord(h_type); + } + if (h_requestID != in.request.requestID) { + return(FCGIGlobalDefs.def_FCGISkip); + } + if (h_type != in.type) { + return(FCGIGlobalDefs.def_FCGIProtocolError); + } + return(FCGIGlobalDefs.def_FCGIStreamRecord); + } + + /* Put the unsigned bytes in the incoming FCGI header into + * integer form for Java, concatinating bytes when needed. + * Because Java has no unsigned byte type, we have to be careful + * about signed numeric promotion to int. + */ + private void processHeaderBytes(byte[] hdrBuf){ + h_version = hdrBuf[0] & 0xFF; + h_type = hdrBuf[1] & 0xFF; + h_requestID = ((hdrBuf[2] & 0xFF) << 8) | (hdrBuf[3] & 0xFF); + h_contentLength = ((hdrBuf[4] & 0xFF) << 8) | (hdrBuf[5] & 0xFF); + h_paddingLength = hdrBuf[6] & 0xFF; + } + + /* + * Reads FCGI Begin Request Record. + */ + public int processBeginRecord(int requestID) throws IOException { + byte beginReqBody[]; + byte endReqMsg[]; + if (requestID == 0 || in.contentLen + != FCGIGlobalDefs.def_FCGIEndReqBodyLen) { + return FCGIGlobalDefs.def_FCGIProtocolError; + } + /* + * If the webserver is multiplexing the connection, + * this library can't deal with it, so repond with + * FCGIEndReq message with protocolStatus FCGICantMpxConn + */ + if (in.request.isBeginProcessed) { + endReqMsg = new byte[FCGIGlobalDefs.def_FCGIHeaderLen + + FCGIGlobalDefs.def_FCGIEndReqBodyLen]; + System.arraycopy(makeHeader( + FCGIGlobalDefs.def_FCGIEndRequest, + requestID, + FCGIGlobalDefs.def_FCGIEndReqBodyLen, + 0), 0, endReqMsg, 0, + FCGIGlobalDefs.def_FCGIHeaderLen); + System.arraycopy(makeEndrequestBody(0, + FCGIGlobalDefs.def_FCGICantMpxConn), 0, + endReqMsg, + FCGIGlobalDefs.def_FCGIHeaderLen, + FCGIGlobalDefs.def_FCGIEndReqBodyLen); + /* + * since isBeginProcessed is first set below,this + * can't be out first call, so request.out is properly set + */ + try { + in.request.outStream.write(endReqMsg, 0, + FCGIGlobalDefs.def_FCGIHeaderLen + + FCGIGlobalDefs.def_FCGIEndReqBodyLen); + } catch (IOException e){ + in.request.outStream.setException(e); + return -1; + } + } + /* + * Accept this new request. Read the record body + */ + in.request.requestID = requestID; + beginReqBody = + new byte[FCGIGlobalDefs.def_FCGIBeginReqBodyLen]; + if (in.read(beginReqBody, 0, + FCGIGlobalDefs.def_FCGIBeginReqBodyLen) != + FCGIGlobalDefs.def_FCGIBeginReqBodyLen) { + return FCGIGlobalDefs.def_FCGIProtocolError; + } + br_flags = beginReqBody[2] & 0xFF; + in.request.keepConnection + = (br_flags & FCGIGlobalDefs.def_FCGIKeepConn) != 0; + br_role = ((beginReqBody[0] & 0xFF) << 8) | (beginReqBody[1] & 0xFF); + in.request.role = br_role; + in.request.isBeginProcessed = true; + return FCGIGlobalDefs.def_FCGIBeginRecord; + } + + /* + * Reads and Responds to a Management Message. The only type of + * management message this library understands is FCGIGetValues. + * The only variables that this library's FCGIGetValues understands + * are def_FCGIMaxConns, def_FCGIMaxReqs, and def_FCGIMpxsConns. + * Ignore the other management variables, and repsond to other + * management messages with FCGIUnknownType. + */ + public int processManagementRecord(int type) throws IOException { + + byte[] response = new byte[64]; + int wrndx = response[FCGIGlobalDefs.def_FCGIHeaderLen]; + int value, len, plen; + if (type == FCGIGlobalDefs.def_FCGIGetValues) { + Properties tmpProps = new Properties(); + readParams(tmpProps); + + if (in.getFCGIError() != 0 || in.contentLen != 0) { + return FCGIGlobalDefs.def_FCGIProtocolError; + } + if (tmpProps.containsKey( + FCGIGlobalDefs.def_FCGIMaxConns)) { + makeNameVal( + FCGIGlobalDefs.def_FCGIMaxConns, "1", + response, wrndx); + } + else { + if (tmpProps.containsKey( + FCGIGlobalDefs.def_FCGIMaxReqs)) { + makeNameVal( + FCGIGlobalDefs.def_FCGIMaxReqs, "1", + response, wrndx); + } + else { + if (tmpProps.containsKey( + FCGIGlobalDefs.def_FCGIMaxConns)) { + makeNameVal( + FCGIGlobalDefs.def_FCGIMpxsConns, "0", + response, wrndx); + } + } + } + plen = 64 - wrndx; + len = wrndx - FCGIGlobalDefs.def_FCGIHeaderLen; + System.arraycopy(makeHeader( + FCGIGlobalDefs.def_FCGIGetValuesResult, + FCGIGlobalDefs.def_FCGINullRequestID, + len, plen), 0, + response, 0, + FCGIGlobalDefs.def_FCGIHeaderLen); + } + else { + plen = len = + FCGIGlobalDefs.def_FCGIUnknownBodyTypeBodyLen; + System.arraycopy(makeHeader( + FCGIGlobalDefs.def_FCGIUnknownType, + FCGIGlobalDefs.def_FCGINullRequestID, + len, 0), 0, + response, 0, + FCGIGlobalDefs.def_FCGIHeaderLen); + System.arraycopy(makeUnknownTypeBodyBody(h_type), 0, + response, + FCGIGlobalDefs.def_FCGIHeaderLen, + FCGIGlobalDefs.def_FCGIUnknownBodyTypeBodyLen); + } + /* + * No guarantee that we have a request yet, so + * dont use fcgi output stream to reference socket, instead + * use the FileInputStream that refrences it. Also + * nowhere to save exception, since this is not FCGI stream. + */ + + try { + in.request.socket.getOutputStream().write(response, 0, + FCGIGlobalDefs.def_FCGIHeaderLen + + FCGIGlobalDefs.def_FCGIUnknownBodyTypeBodyLen); + + } catch (IOException e){ + return -1; + } + return FCGIGlobalDefs.def_FCGIMgmtRecord; + } + + /* + * Makes a name/value with name = string of some length, and + * value a 1 byte integer. Pretty specific to what we are doing + * above. + */ + void makeNameVal(String name, String value, byte[] dest, int pos) { + int nameLen = name.length(); + if (nameLen < 0x80) { + dest[pos++] = (byte)nameLen; + }else { + dest[pos++] = (byte)(((nameLen >> 24) | 0x80) & 0xff); + dest[pos++] = (byte)((nameLen >> 16) & 0xff); + dest[pos++] = (byte)((nameLen >> 8) & 0xff); + dest[pos++] = (byte)nameLen; + } + int valLen = value.length(); + if (valLen < 0x80) { + dest[pos++] = (byte)valLen; + }else { + dest[pos++] = (byte)(((valLen >> 24) | 0x80) & 0xff); + dest[pos++] = (byte)((valLen >> 16) & 0xff); + dest[pos++] = (byte)((valLen >> 8) & 0xff); + dest[pos++] = (byte)valLen; + } + + try { + System.arraycopy(name.getBytes("UTF-8"), 0, dest, pos, nameLen); + pos += nameLen; + + System.arraycopy(value.getBytes("UTF-8"), 0, dest, pos, valLen); + pos += valLen; + } + catch (UnsupportedEncodingException x) {} + } + + /* + * Read FCGI name-value pairs from a stream until EOF. Put them + * into a Properties object, storing both as strings. + */ + public int readParams(Properties props) throws IOException{ + int nameLen, valueLen; + byte lenBuff[] = new byte[3]; + int i = 1; + + while ((nameLen = in.read()) != -1) { + i++; + if ((nameLen & 0x80) != 0) { + if ((in.read( lenBuff, 0, 3)) != 3) { + in.setFCGIError( + FCGIGlobalDefs.def_FCGIParamsError); + return -1; + } + nameLen = ((nameLen & 0x7f) << 24) + | ((lenBuff[0] & 0xFF) << 16) + | ((lenBuff[1] & 0xFF) << 8) + | (lenBuff[2] & 0xFF); + } + + if ((valueLen = in.read()) == -1) { + in.setFCGIError( + FCGIGlobalDefs.def_FCGIParamsError); + return -1; + } + if ((valueLen & 0x80) != 0) { + if ((in.read( lenBuff, 0, 3)) != 3) { + in.setFCGIError( + FCGIGlobalDefs.def_FCGIParamsError); + return -1; + } + valueLen = ((valueLen & 0x7f) << 24) + | ((lenBuff[0] & 0xFF) << 16) + | ((lenBuff[1] & 0xFF) << 8) + | (lenBuff[2] & 0xFF); + } + + /* + * nameLen and valueLen are now valid; read the name + * and the value from the stream and construct a standard + * environmental entity + */ + byte[] name = new byte[nameLen]; + byte[] value = new byte[valueLen]; + if (in.read(name ,0, nameLen) != nameLen) { + in.setFCGIError( + FCGIGlobalDefs.def_FCGIParamsError); + return -1; + } + + if(in.read(value, 0, valueLen) != valueLen) { + in.setFCGIError( + FCGIGlobalDefs.def_FCGIParamsError); + return -1; + } + String strName = new String(name); + String strValue = new String(value); + props.put(strName, strValue); + } + return 0; + + + } + /* + * Message Building Methods + */ + + /* + * Build an FCGI Message Header - + */ + public byte[] makeHeader(int type, + int requestId, + int contentLength, + int paddingLength) { + byte[] header = new byte[FCGIGlobalDefs.def_FCGIHeaderLen]; + header[0] = (byte)FCGIGlobalDefs.def_FCGIVersion1; + header[1] = (byte)type; + header[2] = (byte)((requestId >> 8) & 0xff); + header[3] = (byte)((requestId ) & 0xff); + header[4] = (byte)((contentLength >> 8) & 0xff); + header[5] = (byte)((contentLength ) & 0xff); + header[6] = (byte)paddingLength; + header[7] = 0; //reserved byte + return header; + } + /* + * Build an FCGI Message End Request Body + */ + public byte[] makeEndrequestBody(int appStatus,int protocolStatus){ + byte body[] = new byte[FCGIGlobalDefs.def_FCGIEndReqBodyLen]; + body[0] = (byte)((appStatus >> 24) & 0xff); + body[1] = (byte)((appStatus >> 16) & 0xff); + body[2] = (byte)((appStatus >> 8) & 0xff); + body[3] = (byte)((appStatus ) & 0xff); + body[4] = (byte)protocolStatus; + for (int i = 5; i < 8; i++) { + body[i] = 0; + } + return body; + } + /* + * Build an FCGI Message UnknownTypeBodyBody + */ + public byte[] makeUnknownTypeBodyBody(int type){ + byte body[] = + new byte[FCGIGlobalDefs.def_FCGIUnknownBodyTypeBodyLen]; + body[0] = (byte)type; + for (int i = 1; + i < FCGIGlobalDefs.def_FCGIUnknownBodyTypeBodyLen; i++) { + body[i] = 0; + } + return body; + } + +} //end class diff --git a/iipsrv/fcgi/java/FCGIOutputStream.java b/iipsrv/fcgi/java/FCGIOutputStream.java new file mode 100644 index 0000000..503bda1 --- /dev/null +++ b/iipsrv/fcgi/java/FCGIOutputStream.java @@ -0,0 +1,335 @@ +/* + * @(#)FCGIOutputStream.java + * + * FastCGi compatibility package Interface + * + * Copyright (c) 1996 Open Market, Inc. + * + * See the file "LICENSE.TERMS" for information on usage and redistribution + * of this file, and for a DISCLAIMER OF ALL WARRANTIES. + * + * $Id: FCGIOutputStream.java,v 1.3 2000/03/21 12:12:26 robs Exp $ + */ +package com.fastcgi; + +import java.io.*; + +/** + * This stream understands FCGI prototcol. + */ + +public class FCGIOutputStream + extends OutputStream +{ + private static final String RCSID = "$Id: FCGIOutputStream.java,v 1.3 2000/03/21 12:12:26 robs Exp $"; + + /* Stream vars */ + + public int wrNext; + public int stop; + public boolean isClosed; + + /* require methods to set, get and clear */ + private int errno; + private Exception errex; + + /* data vars */ + + public byte buff[]; + public int buffLen; + public int buffStop; + public int type; + public boolean isAnythingWritten; + public boolean rawWrite; + public FCGIRequest request; + + public FileOutputStream out; + + /** + * Creates a new output stream to manage fcgi prototcol stuff + * @param out the output stream buflen length of buffer streamType + */ + public FCGIOutputStream(FileOutputStream outStream, + int bufLen, int streamType, + FCGIRequest inreq) { + out = outStream; + buffLen = Math.min(bufLen, FCGIGlobalDefs.def_FCGIMaxLen); + buff = new byte[buffLen]; + type = streamType; + stop = buffStop = buffLen; + isAnythingWritten = false; + rawWrite = false; + wrNext = FCGIGlobalDefs.def_FCGIHeaderLen; + isClosed = false; + request = inreq; + } + + /** + * Writes a byte to the output stream. + */ + public void write(int c) throws IOException { + if(wrNext != stop) { + buff[wrNext++] = (byte)c; + return; + } + if(isClosed) { + throw new EOFException(); + } + empty(false); + if(wrNext != stop) { + buff[wrNext++] = (byte)c; + return; + } + /* NOTE: ASSERT(stream->isClosed); */ + /* bug in emptyBuffProc if not */ + throw new EOFException(); + } + + /** + * Writes an array of bytes. This method will block until the bytes + * are actually written. + * @param b the data to be written + */ + public void write(byte b[]) throws IOException{ + write(b, 0, b.length); + } + + /** + * Writes len consecutive bytes from off in the array b + * into the output stream. Performs no interpretation + * of the output bytes. Making the user convert the string to + * bytes is in line with current Java practice. + */ + public void write(byte b[], int off, int len) throws IOException { + int m, bytesMoved; + /* + * Fast path: room for n bytes in the buffer + */ + if(len <= (stop - wrNext)) { + System.arraycopy(b, off, buff, wrNext, len); + wrNext += len; + return; + } + /* + * General case: stream is closed or buffer empty procedure + * needs to be called + */ + bytesMoved = 0; + for (;;) { + if(wrNext != stop) { + m = Math.min(len - bytesMoved, stop - wrNext); + System.arraycopy(b, off, buff, wrNext, m); + bytesMoved += m; + wrNext += m; + if(bytesMoved == len) { + return; + } + off += m; + } + if(isClosed) { + throw new EOFException(); + } + empty(false); + } + } + + /** + * Encapsulates any buffered stream content in a FastCGI + * record. If !doClose, writes the data, making the buffer + * empty. + */ + public void empty(boolean doClose) throws IOException { + int cLen; + /* + * Alignment padding omitted in Java + */ + if (!rawWrite) { + cLen = wrNext - FCGIGlobalDefs.def_FCGIHeaderLen; + if(cLen > 0) { + System.arraycopy(new FCGIMessage().makeHeader(type, + request.requestID, cLen, 0), + 0, buff, 0, + FCGIGlobalDefs.def_FCGIHeaderLen); + } + else { + wrNext = 0; + } + } + if (doClose) { + writeCloseRecords(); + } + if (wrNext != 0) { + isAnythingWritten = true; + try { + out.write(buff, 0, wrNext); + } catch (IOException e) { + setException(e); + return; + } + wrNext = 0; + } + /* + * The buffer is empty. + */ + if(!rawWrite) { + wrNext += FCGIGlobalDefs.def_FCGIHeaderLen; + } + } + + /** + * Close the stream. + */ + public void close() throws IOException { + if (isClosed) { + return; + } + empty(true); + /* + * if isClosed, will return with EOFException from write. + */ + isClosed = true; + stop = wrNext; + return; + } + + /** + * Flushes any buffered output. + * Server-push is a legitimate application of flush. + * Otherwise, it is not very useful, since FCGIAccept + * does it implicitly. flush may reduce performance + * by increasing the total number of operating system calls + * the application makes. + */ + public void flush() throws IOException { + if (isClosed) { + return; + } + empty(false); + /* + * if isClosed, will return with EOFException from write. + */ + return; + } + + /** + * An FCGI error has occurred. Save the error code in the stream + * for diagnostic purposes and set the stream state so that + * reads return EOF + */ + public void setFCGIError(int errnum) { + /* + * Preserve only the first error. + */ + if (errno == 0) { + errno = errnum; + } + isClosed = true; + } + + /** + * An Exception has occurred. Save the Exception in the stream + * for diagnostic purposes and set the stream state so that + * reads return EOF + */ + public void setException(Exception errexpt) { + /* + * Preserve only the first error. + */ + if (errex == null) { + errex = errexpt; + } + isClosed = true; + } + + /** + * Clear the stream error code and end-of-file indication. + */ + public void clearFCGIError() { + errno = 0; + /* + * isClosed = false; + * XXX: should clear isClosed but work is needed to make it safe + * to do so. + */ + } + + /** + * Clear the stream error code and end-of-file indication. + */ + public void clearException() { + errex = null; + /* + * isClosed = false; + * XXX: should clear isClosed but work is needed to make it safe + * to do so. + */ + } + + /** + * accessor method since var is private + */ + public int etFCGIError() { + return errno; + } + + /** + * accessor method since var is private + */ + public Exception getException() { + return errex; + } + + /** + * Writes an EOF record for the stream content if necessary. + * If this is the last writer to close, writes an FCGI_END_REQUEST + * record. + */ + public void writeCloseRecords() throws IOException { + FCGIMessage msg = new FCGIMessage(); + /* + * Enter rawWrite mode so final records won't be + * encapsulated as + * stream data. + */ + rawWrite = true; + /* + * Generate EOF for stream content if needed. + */ + if(!(type == FCGIGlobalDefs.def_FCGIStderr + && wrNext == 0 + && !isAnythingWritten)) { + byte hdr[] = + new byte[FCGIGlobalDefs.def_FCGIHeaderLen]; + System.arraycopy(msg.makeHeader(type, + request.requestID, + 0, 0), + 0, hdr,0, + FCGIGlobalDefs.def_FCGIHeaderLen); + write(hdr, 0, hdr.length); + } + /* + * Generate FCGI_END_REQUEST record if needed. + */ + if(request.numWriters == 1) { + byte endReq[] = + new byte[FCGIGlobalDefs.def_FCGIHeaderLen + + FCGIGlobalDefs.def_FCGIEndReqBodyLen]; + System.arraycopy(msg.makeHeader( + FCGIGlobalDefs.def_FCGIEndRequest, + request.requestID, + FCGIGlobalDefs.def_FCGIEndReqBodyLen,0), + 0, endReq, 0, + FCGIGlobalDefs.def_FCGIHeaderLen); + System.arraycopy(msg.makeEndrequestBody( + request.appStatus, + FCGIGlobalDefs.def_FCGIRequestComplete), + 0,endReq, + FCGIGlobalDefs.def_FCGIHeaderLen, + FCGIGlobalDefs.def_FCGIEndReqBodyLen); + write(endReq,0, FCGIGlobalDefs.def_FCGIHeaderLen + + FCGIGlobalDefs.def_FCGIEndReqBodyLen); + } + request.numWriters--; + } +} + diff --git a/iipsrv/fcgi/java/FCGIRequest.java b/iipsrv/fcgi/java/FCGIRequest.java new file mode 100644 index 0000000..0237b3e --- /dev/null +++ b/iipsrv/fcgi/java/FCGIRequest.java @@ -0,0 +1,53 @@ +/* + * @(#)FCGIRequest.java + * + * FastCGi compatibility package Interface + * + * Copyright (c) 1996 Open Market, Inc. + * + * See the file "LICENSE.TERMS" for information on usage and redistribution + * of this file, and for a DISCLAIMER OF ALL WARRANTIES. + * + * $Id: FCGIRequest.java,v 1.3 2000/03/21 12:12:26 robs Exp $ + */ +package com.fastcgi; + +import java.net.*; +import java.io.FileDescriptor; +import java.util.Properties; + +public class FCGIRequest +{ + private static final String RCSID = "$Id: FCGIRequest.java,v 1.3 2000/03/21 12:12:26 robs Exp $"; + + /* This class has no methods. Right now we are single threaded + * so there is only one request object at any given time which + * is refrenced by an FCGIInterface class variable . All of this + * object's data could just as easily be declared directly there. + * When we thread, this will change, so we might as well use a + * seperate class. In line with this thinking, though somewhat + * more perversely, we kept the socket here. + */ + /* + * class variables + */ + /*public static Socket socket; */ + // same for all requests + + /* + * instance variables + */ + public Socket socket; + public boolean isBeginProcessed; + public int requestID; + public boolean keepConnection; + public int role; + public int appStatus; + public int numWriters; + public FCGIInputStream inStream; + public FCGIOutputStream outStream; + public FCGIOutputStream errStream; + public Properties params; +} + + diff --git a/iipsrv/fcgi/libfcgi/Makefile.am b/iipsrv/fcgi/libfcgi/Makefile.am new file mode 100644 index 0000000..e9d604b --- /dev/null +++ b/iipsrv/fcgi/libfcgi/Makefile.am @@ -0,0 +1,29 @@ +# $Id: Makefile.am,v 1.9 2001/12/22 03:16:20 robs Exp $ + +INCLUDEDIR = ../include +AM_CPPFLAGS = @CPPFLAGS@ -I$(top_srcdir)/fcgi/include -I$(top_srcdir)/fcgi + +INCLUDE_FILES = $(INCLUDEDIR)/fastcgi.h \ + $(INCLUDEDIR)/fcgiapp.h \ + $(INCLUDEDIR)/fcgimisc.h \ + $(INCLUDEDIR)/fcgi_stdio.h \ + $(INCLUDEDIR)/fcgios.h + +#lib_LTLIBRARIES = libfcgi.la @LIBFCGIXX@ +#EXTRA_LTLIBRARIES = libfcgi++.la + +noinst_LIBRARIES = libfcgi.a + +libfcgi_a_SOURCES = $(INCLUDE_FILES) \ + fcgiapp.c \ + fcgi_stdio.c \ + os_@SYSTEM@.c +libfcgi_a_CC = @PTHREAD_CC@ +libfcgi_a_CFLAGS = @PTHREAD_CFLAGS@ + +#libfcgi___a_SOURCES = $(INCLUDE_FILES) \ + $(INCLUDEDIR)/fcgio.h \ + fcgio.cpp +#libfcgi___a_CFLAGS = @PTHREAD_CFLAGS@ +#libfcgi___a_LDFLAGS = -lfcgi -rpath @libdir@ + diff --git a/iipsrv/fcgi/libfcgi/fcgi_stdio.c b/iipsrv/fcgi/libfcgi/fcgi_stdio.c new file mode 100644 index 0000000..e141e7f --- /dev/null +++ b/iipsrv/fcgi/libfcgi/fcgi_stdio.c @@ -0,0 +1,801 @@ +/* + * fcgi_stdio.c -- + * + * FastCGI-stdio compatibility package + * + * + * Copyright (c) 1996 Open Market, Inc. + * + * See the file "LICENSE.TERMS" for information on usage and redistribution + * of this file, and for a DISCLAIMER OF ALL WARRANTIES. + * + */ + +#ifndef lint +static const char rcsid[] = "$Id: fcgi_stdio.c,v 1.14 2001/09/01 01:09:30 robs Exp $"; +#endif /* not lint */ + +#include /* for errno */ +#include /* for va_arg */ +#include /* for malloc */ +#include /* for strerror */ + +#include "fcgi_config.h" + +#ifdef HAVE_UNISTD_H +#include +#endif + +#ifdef _WIN32 +#define DLLAPI __declspec(dllexport) +#endif + +#include "fcgiapp.h" +#include "fcgios.h" +#include "fcgimisc.h" + +#define NO_FCGI_DEFINES +#include "fcgi_stdio.h" +#undef NO_FCGI_DEFINES + +#ifndef _WIN32 + +extern char **environ; + +#ifdef HAVE_FILENO_PROTO +#include +#else +extern int fileno(FILE *stream); +#endif + +extern FILE *fdopen(int fildes, const char *type); +extern FILE *popen(const char *command, const char *type); +extern int pclose(FILE *stream); + +#else /* _WIN32 */ + +#define popen _popen +#define pclose _pclose + +#endif /* _WIN32 */ + +FCGI_FILE _fcgi_sF[3]; + + +/* + *---------------------------------------------------------------------- + * + * FCGI_Accept -- + * + * Accepts a new request from the HTTP server and creates + * a conventional execution environment for the request. + * + * If the application was invoked as a FastCGI server, + * the first call to FCGI_Accept indicates that the application + * has completed its initialization and is ready to accept + * a request. Subsequent calls to FCGI_Accept indicate that + * the application has completed its processing of the + * current request and is ready to accept a new request. + * + * If the application was invoked as a CGI program, the first + * call to FCGI_Accept is essentially a no-op and the second + * call returns EOF (-1). + * + * Results: + * 0 for successful call, -1 for error (application should exit). + * + * Side effects: + * If the application was invoked as a FastCGI server, + * and this is not the first call to this procedure, + * FCGI_Accept first performs the equivalent of FCGI_Finish. + * + * On every call, FCGI_Accept accepts the new request and + * reads the FCGI_PARAMS stream into an environment array, + * i.e. a NULL-terminated array of strings of the form + * ``name=value''. It assigns a pointer to this array + * to the global variable environ, used by the standard + * library function getenv. It creates new FCGI_FILE *s + * representing input from the HTTP server, output to the HTTP + * server, and error output to the HTTP server, and assigns these + * new files to stdin, stdout, and stderr respectively. + * + * DO NOT mutate or retain pointers to environ or any values + * contained in it (e.g. to the result of calling getenv(3)), + * since these are freed by the next call to FCGI_Finish or + * FCGI_Accept. In particular do not use setenv(3) or putenv(3) + * in conjunction with FCGI_Accept. + * + *---------------------------------------------------------------------- + */ +static int acceptCalled = FALSE; +static int isCGI = FALSE; + +int FCGI_Accept(void) +{ + if(!acceptCalled) { + /* + * First call to FCGI_Accept. Is application running + * as FastCGI or as CGI? + */ + isCGI = FCGX_IsCGI(); + acceptCalled = TRUE; + atexit(&FCGI_Finish); + } else if(isCGI) { + /* + * Not first call to FCGI_Accept and running as CGI means + * application is done. + */ + return(EOF); + } + if(isCGI) { + FCGI_stdin->stdio_stream = stdin; + FCGI_stdin->fcgx_stream = NULL; + FCGI_stdout->stdio_stream = stdout; + FCGI_stdout->fcgx_stream = NULL; + FCGI_stderr->stdio_stream = stderr; + FCGI_stderr->fcgx_stream = NULL; + } else { + FCGX_Stream *in, *out, *error; + FCGX_ParamArray envp; + int acceptResult = FCGX_Accept(&in, &out, &error, &envp); + if(acceptResult < 0) { + return acceptResult; + } + FCGI_stdin->stdio_stream = NULL; + FCGI_stdin->fcgx_stream = in; + FCGI_stdout->stdio_stream = NULL; + FCGI_stdout->fcgx_stream = out; + FCGI_stderr->stdio_stream = NULL; + FCGI_stderr->fcgx_stream = error; + environ = envp; + } + return 0; +} + +/* + *---------------------------------------------------------------------- + * + * FCGI_Finish -- + * + * Finishes the current request from the HTTP server. + * + * Side effects: + * + * Flushes any buffered output to the HTTP server. Then frees + * all storage allocated by the previous call, including all + * storage reachable from the value of environ set by the previous + * call to FCGI_Accept. + * + * DO NOT use stdin, stdout, stderr, or environ between calling + * FCGI_Finish and calling FCGI_Accept. + * + * DO NOT mutate or retain pointers to environ or any values + * contained in it (e.g. to the result of calling getenv(3)), + * since these are freed by the next call to FCGI_Finish or + * FCGI_Accept. In particular do not use setenv(3) or putenv(3) + * in conjunction with FCGI_Accept. + * + *---------------------------------------------------------------------- + */ +void FCGI_Finish(void) +{ + if(!acceptCalled || isCGI) { + return; + } + FCGX_Finish(); + FCGI_stdin->fcgx_stream = NULL; + FCGI_stdout->fcgx_stream = NULL; + FCGI_stderr->fcgx_stream = NULL; + environ = NULL; +} + +/* + *---------------------------------------------------------------------- + * + * FCGI_StartFilterData -- + * + * + * The current request is for the filter role, and stdin is + * positioned at EOF of FCGI_STDIN. The call repositions + * stdin to the start of FCGI_DATA. + * If the preconditions are not met (e.g. FCGI_STDIN has not + * been read to EOF), the call sets the stream error code to + * FCGX_CALL_SEQ_ERROR. + * + * Results: + * 0 for a normal return, < 0 for error + * + *---------------------------------------------------------------------- + */ +int FCGI_StartFilterData(void) +{ + if(FCGI_stdin->stdio_stream) { + return -1; + } else { + return FCGX_StartFilterData(FCGI_stdin->fcgx_stream); + } +} + +/* + *---------------------------------------------------------------------- + * + * FCGI_SetExitStatus -- + * + * Sets the exit status for the current request. The exit status + * is the status code the request would have exited with, had + * the request been run as a CGI program. You can call + * FCGI_SetExitStatus several times during a request; the last call + * before the request ends (by calling FCGI_Accept) determines the + * value. + * + *---------------------------------------------------------------------- + */ +void FCGI_SetExitStatus(int status) +{ + if(FCGI_stdin->fcgx_stream) { + FCGX_SetExitStatus(status, FCGI_stdin->fcgx_stream); + } +} + +/* + *---------------------------------------------------------------------- + * + * FCGI_perror -- + * + * Wrapper for function defined in H&S Section 11.2 + * + *---------------------------------------------------------------------- + */ +void FCGI_perror(const char *str) +{ + FCGI_fputs(str, FCGI_stderr); + FCGI_fputs(": ", FCGI_stderr); + FCGI_fputs(strerror(OS_Errno), FCGI_stderr); + return; +} + +/* + *---------------------------------------------------------------------- + * + * FCGI_OpenFromFILE -- + * + * Constructs a new FCGI_FILE * from the FILE *stream. + * + * Results: + * NULL if stream == NULL or storage could not be allocated, + * otherwise the new FCGI_FILE *. + * + *---------------------------------------------------------------------- + */ +static FCGI_FILE *FCGI_OpenFromFILE(FILE *stream) +{ + FCGI_FILE *fp; + + if (stream == NULL) + return NULL; + + fp = (FCGI_FILE *) malloc(sizeof(FCGI_FILE)); + if (fp != NULL) + { + fp->stdio_stream = stream; + fp->fcgx_stream = NULL; + } + + return fp; +} + +/* + *---------------------------------------------------------------------- + * + * FCGI_fopen, FCGI_fclose, FCGI_fflush, FCGI_freopen -- + * + * Wrappers for functions defined in H&S Section 15.2 + * + *---------------------------------------------------------------------- + */ +FCGI_FILE *FCGI_fopen(const char *path, const char *mode) +{ + FILE * file = fopen(path, mode); + FCGI_FILE * fcgi_file = FCGI_OpenFromFILE(file); + + if (file && !fcgi_file) + fclose(file); + + return fcgi_file; +} + +int FCGI_fclose(FCGI_FILE *fp) +{ + int n = EOF; + if(fp->stdio_stream) { + n = fclose(fp->stdio_stream); + fp->stdio_stream = NULL; + } else if(fp->fcgx_stream) { + n = FCGX_FClose(fp->fcgx_stream); + fp->fcgx_stream = NULL; + } + if((fp != FCGI_stdin) && (fp != FCGI_stdout) && (fp != FCGI_stderr)) { + free(fp); + } + return n; +} + +int FCGI_fflush(FCGI_FILE *fp) +{ + if(fp == NULL) + return fflush(NULL); + if(fp->stdio_stream) + return fflush(fp->stdio_stream); + else if(fp->fcgx_stream) + return FCGX_FFlush(fp->fcgx_stream); + return EOF; +} + +FCGI_FILE *FCGI_freopen(const char *path, const char *mode, + FCGI_FILE *fp) +{ + if(fp->stdio_stream) { + if(freopen(path, mode, fp->stdio_stream) == NULL) + return NULL; + else + return fp; + } else if(fp->fcgx_stream) { + (void) FCGX_FClose(fp->fcgx_stream); + fp->stdio_stream = fopen(path, mode); + if(fp->stdio_stream == NULL) + return NULL; + else { + fp->fcgx_stream = NULL; + return fp; + } + } + return NULL; +} + +/* + *---------------------------------------------------------------------- + * + * FCGI_setvbuf, FCGI_setbuf -- + * + * Wrappers for functions defined in H&S Section 15.3 + * + *---------------------------------------------------------------------- + */ +int FCGI_setvbuf(FCGI_FILE *fp, char *buf, int bufmode, size_t size) +{ + if(fp->stdio_stream) + return setvbuf(fp->stdio_stream, buf, bufmode, size); + else { + return -1; + } +} + +void FCGI_setbuf(FCGI_FILE *fp, char *buf) +{ + if(fp->stdio_stream) + setbuf(fp->stdio_stream, buf); +} + +/* + *---------------------------------------------------------------------- + * + * FCGI_fseek, FCGI_ftell, FCGI_rewind, FCGI_fgetpos, FCGI_fsetpos -- + * + * Wrappers for functions defined in H&S Section 15.5 + * + *---------------------------------------------------------------------- + */ +int FCGI_fseek(FCGI_FILE *fp, long offset, int whence) +{ + if(fp->stdio_stream) + return fseek(fp->stdio_stream, offset, whence); + else { + OS_SetErrno(ESPIPE); + return -1; + } +} + +int FCGI_ftell(FCGI_FILE *fp) +{ + if(fp->stdio_stream) + return ftell(fp->stdio_stream); + else { + OS_SetErrno(ESPIPE); + return -1; + } +} + +void FCGI_rewind(FCGI_FILE *fp) +{ + if(fp->stdio_stream) + rewind(fp->stdio_stream); + else + OS_SetErrno(ESPIPE); +} + +#ifdef HAVE_FPOS +int FCGI_fgetpos(FCGI_FILE *fp, fpos_t *pos) +{ + if(fp->stdio_stream) + return fgetpos(fp->stdio_stream, pos); + else { + OS_SetErrno(ESPIPE); + return -1; + } +} + +int FCGI_fsetpos(FCGI_FILE *fp, const fpos_t *pos) +{ + if(fp->stdio_stream) + return fsetpos(fp->stdio_stream, pos); + else { + OS_SetErrno(ESPIPE); + return -1; + } +} +#endif + +/* + *---------------------------------------------------------------------- + * + * FCGI_fgetc, FCGI_getchar, FCGI_ungetc -- + * + * Wrappers for functions defined in H&S Section 15.6 + * + * XXX: getc and getchar are generally defined as macros + * for performance reasons + * + *---------------------------------------------------------------------- + */ +int FCGI_fgetc(FCGI_FILE *fp) +{ + if(fp->stdio_stream) + return fgetc(fp->stdio_stream); + else if(fp->fcgx_stream) + return FCGX_GetChar(fp->fcgx_stream); + return EOF; +} + +int FCGI_getchar(void) +{ + return FCGI_fgetc(FCGI_stdin); +} + +int FCGI_ungetc(int c, FCGI_FILE *fp) +{ + if(fp->stdio_stream) + return ungetc(c, fp->stdio_stream); + else if(fp->fcgx_stream) + return FCGX_UnGetChar(c, fp->fcgx_stream); + return EOF; +} + +/* + *---------------------------------------------------------------------- + * + * FCGI_fgets, FCGI_gets -- + * + * Wrappers for functions defined in H&S Section 15.7 + * + *---------------------------------------------------------------------- + */ +char *FCGI_fgets(char *str, int size, FCGI_FILE *fp) +{ + if(fp->stdio_stream) + return fgets(str, size, fp->stdio_stream); + else if(fp->fcgx_stream) + return FCGX_GetLine(str, size, fp->fcgx_stream); + return NULL; +} + +/* + * The gets() function reads characters from the standard input stream + * into the array pointed to by str until a newline character is read + * or an end-of-file condition is encountered. The newline character + * is discarded and the string is terminated with a null character. + */ +char *FCGI_gets(char *str) +{ + char *s; + int c; + + for (s = str; ((c = FCGI_getchar()) != '\n');) { + if(c == EOF) { + if(s == str) + return NULL; + else + break; + } else + *s++ = (char) c; + } + *s = 0; + return str; +} + +/* + *---------------------------------------------------------------------- + * + * Wrappers for functions defined in H&S Section 15.8 + * + * XXX: missing: fscanf, scanf + * + *---------------------------------------------------------------------- + */ + +/* + *---------------------------------------------------------------------- + * + * FCGI_fputc, FCGI_putchar -- + * + * Wrappers for functions defined in H&S Section 15.9 + * + * XXX: putc and putchar are generally defined as macros + * for performance reasons + * + *---------------------------------------------------------------------- + */ +int FCGI_fputc(int c, FCGI_FILE *fp) +{ + if(fp->stdio_stream) + return fputc(c, fp->stdio_stream); + else if(fp->fcgx_stream) + return FCGX_PutChar(c, fp->fcgx_stream); + else return EOF; +} + +int FCGI_putchar(int c) +{ + return FCGI_fputc(c, FCGI_stdout); +} + +/* + *---------------------------------------------------------------------- + * + * FCGI_fputs, FCGI_puts + * + * Wrappers for functions defined in H&S Section 15.10 + * + *---------------------------------------------------------------------- + */ +int FCGI_fputs(const char *str, FCGI_FILE *fp) +{ + if(fp->stdio_stream) + return fputs(str, fp->stdio_stream); + else if(fp->fcgx_stream) + return FCGX_PutS(str, fp->fcgx_stream); + return EOF; +} + +int FCGI_puts(const char *str) +{ + int n; + if(FCGI_stdout->stdio_stream) { + n = fputs(str, FCGI_stdout->stdio_stream); + if(n < 0) + return n; + else + return fputc('\n', FCGI_stdout->stdio_stream); + } else if(FCGI_stdout->fcgx_stream) { + n = FCGX_PutS(str, FCGI_stdout->fcgx_stream); + if(n < 0) + return n; + else + return FCGX_PutChar('\n', FCGI_stdout->fcgx_stream); + } + return EOF; +} + +/* + *---------------------------------------------------------------------- + * + * FCGI_fprintf, FCGI_printf -- + * + * Wrappers for functions defined in H&S Section 15.11 + * + *---------------------------------------------------------------------- + */ +int FCGI_fprintf(FCGI_FILE *fp, const char *format, ...) +{ + va_list ap; + int n = 0; + va_start(ap, format); + if(fp->stdio_stream) + n = vfprintf(fp->stdio_stream, format, ap); + else if(fp->fcgx_stream) + n = FCGX_VFPrintF(fp->fcgx_stream, format, ap); + va_end(ap); + return n; +} + +int FCGI_printf(const char *format, ...) +{ + va_list ap; + int n; + va_start(ap, format); + n = FCGI_vfprintf(FCGI_stdout, format, ap); + va_end(ap); + return n; +} + +/* + *---------------------------------------------------------------------- + * + * FCGI_vfprintf, FCGI_vprintf -- + * + * Wrappers for functions defined in H&S Section 15.12 + * + *---------------------------------------------------------------------- + */ +int FCGI_vfprintf(FCGI_FILE *fp, const char *format, va_list ap) +{ + if(fp->stdio_stream) + return vfprintf(fp->stdio_stream, format, ap); + else if(fp->fcgx_stream) + return FCGX_VFPrintF(fp->fcgx_stream, format, ap); + return EOF; +} + +int FCGI_vprintf(const char *format, va_list ap) +{ + if(FCGI_stdout->stdio_stream) + return vfprintf(FCGI_stdout->stdio_stream, format, ap); + else if(FCGI_stdout->fcgx_stream) + return FCGX_VFPrintF(FCGI_stdout->fcgx_stream, format, ap); + return EOF; +} + +/* + *---------------------------------------------------------------------- + * + * FCGI_fread, FCGI_fwrite -- + * + * Wrappers for functions defined in H&S Section 15.13 + * + *---------------------------------------------------------------------- + */ +size_t FCGI_fread(void *ptr, size_t size, size_t nmemb, FCGI_FILE *fp) +{ + int n; + if(fp->stdio_stream) + return fread(ptr, size, nmemb, fp->stdio_stream); + else if(fp->fcgx_stream) { + if((size * nmemb) == 0) { + return 0; + } + n = FCGX_GetStr((char *) ptr, size * nmemb, fp->fcgx_stream); + return (n/size); + } + return (size_t)EOF; +} + +size_t FCGI_fwrite(void *ptr, size_t size, size_t nmemb, FCGI_FILE *fp) +{ + int n; + if(fp->stdio_stream) + return fwrite(ptr, size, nmemb, fp->stdio_stream); + else if(fp->fcgx_stream) { + if((size * nmemb) == 0) { + return 0; + } + n = FCGX_PutStr((char *) ptr, size * nmemb, fp->fcgx_stream); + return (n/size); + } + return (size_t)EOF; +} + +/* + *---------------------------------------------------------------------- + * + * FCGI_feof, FCGI_ferror, FCGI_clearerr -- + * + * Wrappers for functions defined in H&S Section 15.14 + * + *---------------------------------------------------------------------- + */ +int FCGI_feof(FCGI_FILE *fp) +{ + if(fp->stdio_stream) { + return feof(fp->stdio_stream); + } else if (fp->fcgx_stream){ + return FCGX_HasSeenEOF(fp->fcgx_stream); + } + return -1; + +} + +int FCGI_ferror(FCGI_FILE *fp) +{ + if(fp->stdio_stream) { + return ferror(fp->stdio_stream); + } else if(fp->fcgx_stream) { + return FCGX_GetError(fp->fcgx_stream); + } + return -1; +} + +void FCGI_clearerr(FCGI_FILE *fp) +{ + if(fp->stdio_stream) { + clearerr(fp->stdio_stream); + } else if(fp->fcgx_stream) { + FCGX_ClearError(fp->fcgx_stream); + } + return; +} + +/* + *---------------------------------------------------------------------- + * + * FCGI_tmpfile -- + * + * Wrappers for function defined in H&S Section 15.16 + * + *---------------------------------------------------------------------- + */ +FCGI_FILE *FCGI_tmpfile(void) +{ + FILE * file = tmpfile(); + FCGI_FILE * fcgi_file = FCGI_OpenFromFILE(file); + + if (file && !fcgi_file) + fclose(file); + + return fcgi_file; +} + +/* + *---------------------------------------------------------------------- + * + * FCGI_fileno, FCGI_fdopen, FCGI_popen, FCGI_pclose -- + * + * Wrappers for POSIX, X/OPEN functions not in ISO C + * + *---------------------------------------------------------------------- + */ +int FCGI_fileno(FCGI_FILE *fp) +{ + if(fp->stdio_stream) + return fileno(fp->stdio_stream); + else + return -1; +} + +FCGI_FILE *FCGI_fdopen(int fd, const char *mode) +{ + FILE * file = fdopen(fd, mode); + FCGI_FILE * fcgi_file = FCGI_OpenFromFILE(file); + + if (file && !fcgi_file) + fclose(file); + + return fcgi_file; +} + +FCGI_FILE *FCGI_popen(const char *cmd, const char *type) +{ + FILE * file = popen(cmd, type); + FCGI_FILE * fcgi_file = FCGI_OpenFromFILE(file); + + if (file && !fcgi_file) + pclose(file); + + return fcgi_file; +} + +int FCGI_pclose(FCGI_FILE *fp) +{ + int n = EOF; + if (fp->stdio_stream) { + n = pclose(fp->stdio_stream); + fp->stdio_stream = NULL; + } else if(fp->fcgx_stream) { + /* + * The caller is deeply confused; don't free the storage. + */ + return EOF; + } + if((fp != FCGI_stdin) && (fp != FCGI_stdout) && (fp != FCGI_stderr)) { + free(fp); + } + return n; +} diff --git a/iipsrv/fcgi/libfcgi/fcgiapp.c b/iipsrv/fcgi/libfcgi/fcgiapp.c new file mode 100644 index 0000000..178cfe4 --- /dev/null +++ b/iipsrv/fcgi/libfcgi/fcgiapp.c @@ -0,0 +1,2309 @@ +/* + * fcgiapp.c -- + * + * FastCGI application library: request-at-a-time + * + * + * Copyright (c) 1996 Open Market, Inc. + * + * See the file "LICENSE.TERMS" for information on usage and redistribution + * of this file, and for a DISCLAIMER OF ALL WARRANTIES. + * + */ +#ifndef lint +static const char rcsid[] = "$Id: fcgiapp.c,v 1.34 2001/12/12 22:54:10 robs Exp $"; +#endif /* not lint */ + +#include +#include +#include /* for fcntl */ +#include +#include /* for memchr() */ +#include +#include +#include +#include +#include + +#include "fcgi_config.h" + +#ifdef HAVE_SYS_SOCKET_H +#include /* for getpeername */ +#endif + +#ifdef HAVE_SYS_TIME_H +#include +#endif + +#ifdef HAVE_UNISTD_H +#include +#endif + +#ifdef HAVE_LIMITS_H +#include +#endif + +#ifdef _WIN32 +#define DLLAPI __declspec(dllexport) +#endif + +#include "fcgimisc.h" +#include "fastcgi.h" +#include "fcgios.h" +#include "fcgiapp.h" + +/* + * This is a workaround for one version of the HP C compiler + * (c89 on HP-UX 9.04, also Stratus FTX), which will dump core + * if given 'long double' for varargs. + */ +#ifdef HAVE_VA_ARG_LONG_DOUBLE_BUG +#define LONG_DOUBLE double +#else +#define LONG_DOUBLE long double +#endif + +/* + * Globals + */ +static int libInitialized = 0; +static int isFastCGI = -1; +static char *webServerAddressList = NULL; +static FCGX_Request the_request; + +void FCGX_ShutdownPending(void) +{ + OS_ShutdownPending(); +} + +static void *Malloc(size_t size) +{ + void *result = malloc(size); + ASSERT(size == 0 || result != NULL); + return result; +} + +static char *StringCopy(char *str) +{ + int strLen = strlen(str); + char *newString = (char *)Malloc(strLen + 1); + memcpy(newString, str, strLen); + newString[strLen] = '\000'; + return newString; +} + + +/* + *---------------------------------------------------------------------- + * + * FCGX_GetChar -- + * + * Reads a byte from the input stream and returns it. + * + * Results: + * The byte, or EOF (-1) if the end of input has been reached. + * + *---------------------------------------------------------------------- + */ +int FCGX_GetChar(FCGX_Stream *stream) +{ + if (stream->isClosed || ! stream->isReader) + return EOF; + + if (stream->rdNext != stream->stop) + return *stream->rdNext++; + + stream->fillBuffProc(stream); + if (stream->isClosed) + return EOF; + + stream->stopUnget = stream->rdNext; + if (stream->rdNext != stream->stop) + return *stream->rdNext++; + + ASSERT(stream->isClosed); /* bug in fillBufProc if not */ + return EOF; +} + +/* + *---------------------------------------------------------------------- + * + * FCGX_GetStr -- + * + * Reads up to n consecutive bytes from the input stream + * into the character array str. Performs no interpretation + * of the input bytes. + * + * Results: + * Number of bytes read. If result is smaller than n, + * the end of input has been reached. + * + *---------------------------------------------------------------------- + */ +int FCGX_GetStr(char *str, int n, FCGX_Stream *stream) +{ + int m, bytesMoved; + + if (stream->isClosed || ! stream->isReader || n <= 0) { + return 0; + } + /* + * Fast path: n bytes are already available + */ + if(n <= (stream->stop - stream->rdNext)) { + memcpy(str, stream->rdNext, n); + stream->rdNext += n; + return n; + } + /* + * General case: stream is closed or buffer fill procedure + * needs to be called + */ + bytesMoved = 0; + for (;;) { + if(stream->rdNext != stream->stop) { + m = min(n - bytesMoved, stream->stop - stream->rdNext); + memcpy(str, stream->rdNext, m); + bytesMoved += m; + stream->rdNext += m; + if(bytesMoved == n) + return bytesMoved; + str += m; + } + if(stream->isClosed || !stream->isReader) + return bytesMoved; + stream->fillBuffProc(stream); + if (stream->isClosed) + return bytesMoved; + + stream->stopUnget = stream->rdNext; + } +} + +/* + *---------------------------------------------------------------------- + * + * FCGX_GetLine -- + * + * Reads up to n-1 consecutive bytes from the input stream + * into the character array str. Stops before n-1 bytes + * have been read if '\n' or EOF is read. The terminating '\n' + * is copied to str. After copying the last byte into str, + * stores a '\0' terminator. + * + * Results: + * NULL if EOF is the first thing read from the input stream, + * str otherwise. + * + *---------------------------------------------------------------------- + */ +char *FCGX_GetLine(char *str, int n, FCGX_Stream *stream) +{ + int c; + char *p = str; + + n--; + while (n > 0) { + c = FCGX_GetChar(stream); + if(c == EOF) { + if(p == str) + return NULL; + else + break; + } + *p++ = (char) c; + n--; + if(c == '\n') + break; + } + *p = '\0'; + return str; +} + +/* + *---------------------------------------------------------------------- + * + * FCGX_UnGetChar -- + * + * Pushes back the character c onto the input stream. One + * character of pushback is guaranteed once a character + * has been read. No pushback is possible for EOF. + * + * Results: + * Returns c if the pushback succeeded, EOF if not. + * + *---------------------------------------------------------------------- + */ +int FCGX_UnGetChar(int c, FCGX_Stream *stream) { + if(c == EOF + || stream->isClosed + || !stream->isReader + || stream->rdNext == stream->stopUnget) + return EOF; + --(stream->rdNext); + *stream->rdNext = (unsigned char) c; + return c; +} + +/* + *---------------------------------------------------------------------- + * + * FCGX_HasSeenEOF -- + * + * Returns EOF if end-of-file has been detected while reading + * from stream; otherwise returns 0. + * + * Note that FCGX_HasSeenEOF(s) may return 0, yet an immediately + * following FCGX_GetChar(s) may return EOF. This function, like + * the standard C stdio function feof, does not provide the + * ability to peek ahead. + * + * Results: + * EOF if end-of-file has been detected, 0 if not. + * + *---------------------------------------------------------------------- + */ +int FCGX_HasSeenEOF(FCGX_Stream *stream) { + return (stream->isClosed) ? EOF : 0; +} + +/* + *---------------------------------------------------------------------- + * + * FCGX_PutChar -- + * + * Writes a byte to the output stream. + * + * Results: + * The byte, or EOF (-1) if an error occurred. + * + *---------------------------------------------------------------------- + */ +int FCGX_PutChar(int c, FCGX_Stream *stream) +{ + if(stream->wrNext != stream->stop) + return (*stream->wrNext++ = (unsigned char) c); + if(stream->isClosed || stream->isReader) + return EOF; + stream->emptyBuffProc(stream, FALSE); + if(stream->wrNext != stream->stop) + return (*stream->wrNext++ = (unsigned char) c); + ASSERT(stream->isClosed); /* bug in emptyBuffProc if not */ + return EOF; +} + +/* + *---------------------------------------------------------------------- + * + * FCGX_PutStr -- + * + * Writes n consecutive bytes from the character array str + * into the output stream. Performs no interpretation + * of the output bytes. + * + * Results: + * Number of bytes written (n) for normal return, + * EOF (-1) if an error occurred. + * + *---------------------------------------------------------------------- + */ +int FCGX_PutStr(const char *str, int n, FCGX_Stream *stream) +{ + int m, bytesMoved; + + /* + * Fast path: room for n bytes in the buffer + */ + if(n <= (stream->stop - stream->wrNext)) { + memcpy(stream->wrNext, str, n); + stream->wrNext += n; + return n; + } + /* + * General case: stream is closed or buffer empty procedure + * needs to be called + */ + bytesMoved = 0; + for (;;) { + if(stream->wrNext != stream->stop) { + m = min(n - bytesMoved, stream->stop - stream->wrNext); + memcpy(stream->wrNext, str, m); + bytesMoved += m; + stream->wrNext += m; + if(bytesMoved == n) + return bytesMoved; + str += m; + } + if(stream->isClosed || stream->isReader) + return -1; + stream->emptyBuffProc(stream, FALSE); + } +} + +/* + *---------------------------------------------------------------------- + * + * FCGX_PutS -- + * + * Writes a character string to the output stream. + * + * Results: + * number of bytes written for normal return, + * EOF (-1) if an error occurred. + * + *---------------------------------------------------------------------- + */ +int FCGX_PutS(const char *str, FCGX_Stream *stream) +{ + return FCGX_PutStr(str, strlen(str), stream); +} + +/* + *---------------------------------------------------------------------- + * + * FCGX_FPrintF -- + * + * Performs output formatting and writes the results + * to the output stream. + * + * Results: + * number of bytes written for normal return, + * EOF (-1) if an error occurred. + * + *---------------------------------------------------------------------- + */ +int FCGX_FPrintF(FCGX_Stream *stream, const char *format, ...) +{ + int result; + va_list ap; + va_start(ap, format); + result = FCGX_VFPrintF(stream, format, ap); + va_end(ap); + return result; +} + +/* + *---------------------------------------------------------------------- + * + * FCGX_VFPrintF -- + * + * Performs output formatting and writes the results + * to the output stream. + * + * Results: + * number of bytes written for normal return, + * EOF (-1) if an error occurred. + * + *---------------------------------------------------------------------- + */ + +#define PRINTF_BUFFLEN 100 + /* + * More than sufficient space for all unmodified conversions + * except %s and %f. + */ +#define FMT_BUFFLEN 25 + /* + * Max size of a format specifier is 1 + 5 + 7 + 7 + 2 + 1 + slop + */ +static void CopyAndAdvance(char **destPtr, char **srcPtr, int n); + +int FCGX_VFPrintF(FCGX_Stream *stream, const char *format, va_list arg) +{ + char *f, *fStop, *percentPtr, *p, *fmtBuffPtr, *buffPtr; + int op, performedOp, sizeModifier, buffCount = 0, buffLen, specifierLength; + int fastPath, n, auxBuffLen = 0, buffReqd, minWidth, precision, exp; + char *auxBuffPtr = NULL; + int streamCount = 0; + char fmtBuff[FMT_BUFFLEN]; + char buff[PRINTF_BUFFLEN]; + + int intArg; + short shortArg; + long longArg; + unsigned unsignedArg; + unsigned long uLongArg; + unsigned short uShortArg; + char *charPtrArg = NULL; + void *voidPtrArg; + int *intPtrArg; + long *longPtrArg; + short *shortPtrArg; + double doubleArg = 0.0; + LONG_DOUBLE lDoubleArg = 0.0L; + + fmtBuff[0] = '%'; + f = (char *) format; + fStop = f + strlen(f); + while (f != fStop) { + percentPtr = (char *)memchr(f, '%', fStop - f); + if(percentPtr == NULL) percentPtr = fStop; + if(percentPtr != f) { + if(FCGX_PutStr(f, percentPtr - f, stream) < 0) + goto ErrorReturn; + streamCount += percentPtr - f; + f = percentPtr; + if(f == fStop) break; + } + fastPath = TRUE; + /* + * The following loop always executes either once or twice. + */ + for (;;) { + if(fastPath) { + /* + * Fast path: Scan optimistically, hoping that no flags, + * minimum field width, or precision are specified. + * Use the preallocated buffer, which is large enough + * for all fast path cases. If the conversion specifier + * is really more complex, run the loop a second time + * using the slow path. + * Note that fast path execution of %s bypasses the buffer + * and %f is not attempted on the fast path due to + * its large buffering requirements. + */ + op = *(percentPtr + 1); + switch(op) { + case 'l': + case 'L': + case 'h': + sizeModifier = op; + op = *(percentPtr + 2); + fmtBuff[1] = (char) sizeModifier; + fmtBuff[2] = (char) op; + fmtBuff[3] = '\0'; + specifierLength = 3; + break; + default: + sizeModifier = ' '; + fmtBuff[1] = (char) op; + fmtBuff[2] = '\0'; + specifierLength = 2; + break; + } + buffPtr = buff; + buffLen = PRINTF_BUFFLEN; + } else { + /* + * Slow path: Scan the conversion specifier and construct + * a new format string, compute an upper bound on the + * amount of buffering that sprintf will require, + * and allocate a larger buffer if necessary. + */ + p = percentPtr + 1; + fmtBuffPtr = &fmtBuff[1]; + /* + * Scan flags + */ + n = strspn(p, "-0+ #"); + if(n > 5) + goto ErrorReturn; + CopyAndAdvance(&fmtBuffPtr, &p, n); + /* + * Scan minimum field width + */ + n = strspn(p, "0123456789"); + if(n == 0) { + if(*p == '*') { + minWidth = va_arg(arg, int); + if(abs(minWidth) > 999999) + goto ErrorReturn; + /* + * The following use of strlen rather than the + * value returned from sprintf is because SUNOS4 + * returns a char * instead of an int count. + */ + sprintf(fmtBuffPtr, "%d", minWidth); + fmtBuffPtr += strlen(fmtBuffPtr); + p++; + } else { + minWidth = 0; + } + } else if(n <= 6) { + minWidth = strtol(p, NULL, 10); + CopyAndAdvance(&fmtBuffPtr, &p, n); + } else { + goto ErrorReturn; + } + /* + * Scan precision + */ + if(*p == '.') { + CopyAndAdvance(&fmtBuffPtr, &p, 1); + n = strspn(p, "0123456789"); + if(n == 0) { + if(*p == '*') { + precision = va_arg(arg, int); + if(precision < 0) precision = 0; + if(precision > 999999) + goto ErrorReturn; + /* + * The following use of strlen rather than the + * value returned from sprintf is because SUNOS4 + * returns a char * instead of an int count. + */ + sprintf(fmtBuffPtr, "%d", precision); + fmtBuffPtr += strlen(fmtBuffPtr); + p++; + } else { + precision = 0; + } + } else if(n <= 6) { + precision = strtol(p, NULL, 10); + CopyAndAdvance(&fmtBuffPtr, &p, n); + } else { + goto ErrorReturn; + } + } else { + precision = -1; + } + /* + * Scan size modifier and conversion operation + */ + switch(*p) { + case 'l': + case 'L': + case 'h': + sizeModifier = *p; + CopyAndAdvance(&fmtBuffPtr, &p, 1); + break; + default: + sizeModifier = ' '; + break; + } + op = *p; + CopyAndAdvance(&fmtBuffPtr, &p, 1); + ASSERT(fmtBuffPtr - fmtBuff < FMT_BUFFLEN); + *fmtBuffPtr = '\0'; + specifierLength = p - percentPtr; + /* + * Bound the required buffer size. For s and f + * conversions this requires examining the argument. + */ + switch(op) { + case 'd': + case 'i': + case 'u': + case 'o': + case 'x': + case 'X': + case 'c': + case 'p': + buffReqd = max(precision, 46); + break; + case 's': + charPtrArg = va_arg(arg, char *); + if (!charPtrArg) charPtrArg = "(null)"; + if(precision == -1) { + buffReqd = strlen(charPtrArg); + } else { + p = (char *)memchr(charPtrArg, '\0', precision); + buffReqd = + (p == NULL) ? precision : p - charPtrArg; + } + break; + case 'f': + switch(sizeModifier) { + case ' ': + doubleArg = va_arg(arg, double); + frexp(doubleArg, &exp); + break; + case 'L': + lDoubleArg = va_arg(arg, LONG_DOUBLE); + /* XXX Need to check for the presence of + * frexpl() and use it if available */ + frexp((double) lDoubleArg, &exp); + break; + default: + goto ErrorReturn; + } + if(precision == -1) precision = 6; + buffReqd = precision + 3 + ((exp > 0) ? exp/3 : 0); + break; + case 'e': + case 'E': + case 'g': + case 'G': + if(precision == -1) precision = 6; + buffReqd = precision + 8; + break; + case 'n': + case '%': + default: + goto ErrorReturn; + break; + } + buffReqd = max(buffReqd + 10, minWidth); + /* + * Allocate the buffer + */ + if(buffReqd <= PRINTF_BUFFLEN) { + buffPtr = buff; + buffLen = PRINTF_BUFFLEN; + } else { + if(auxBuffPtr == NULL || buffReqd > auxBuffLen) { + if(auxBuffPtr != NULL) free(auxBuffPtr); + auxBuffPtr = (char *)Malloc(buffReqd); + auxBuffLen = buffReqd; + if(auxBuffPtr == NULL) + goto ErrorReturn; + } + buffPtr = auxBuffPtr; + buffLen = auxBuffLen; + } + } + /* + * This giant switch statement requires the following variables + * to be set up: op, sizeModifier, arg, buffPtr, fmtBuff. + * When fastPath == FALSE and op == 's' or 'f', the argument + * has been read into charPtrArg, doubleArg, or lDoubleArg. + * The statement produces the boolean performedOp, TRUE iff + * the op/sizeModifier were executed and argument consumed; + * if performedOp, the characters written into buffPtr[] + * and the character count buffCount (== EOF meaning error). + * + * The switch cases are arranged in the same order as in the + * description of fprintf in section 15.11 of Harbison and Steele. + */ + performedOp = TRUE; + switch(op) { + case 'd': + case 'i': + switch(sizeModifier) { + case ' ': + intArg = va_arg(arg, int); + sprintf(buffPtr, fmtBuff, intArg); + buffCount = strlen(buffPtr); + break; + case 'l': + longArg = va_arg(arg, long); + sprintf(buffPtr, fmtBuff, longArg); + buffCount = strlen(buffPtr); + break; + case 'h': + shortArg = (short) va_arg(arg, int); + sprintf(buffPtr, fmtBuff, shortArg); + buffCount = strlen(buffPtr); + break; + default: + goto ErrorReturn; + } + break; + case 'u': + case 'o': + case 'x': + case 'X': + switch(sizeModifier) { + case ' ': + unsignedArg = va_arg(arg, unsigned); + sprintf(buffPtr, fmtBuff, unsignedArg); + buffCount = strlen(buffPtr); + break; + case 'l': + uLongArg = va_arg(arg, unsigned long); + sprintf(buffPtr, fmtBuff, uLongArg); + buffCount = strlen(buffPtr); + break; + case 'h': + uShortArg = (unsigned short) va_arg(arg, int); + sprintf(buffPtr, fmtBuff, uShortArg); + buffCount = strlen(buffPtr); + break; + default: + goto ErrorReturn; + } + break; + case 'c': + switch(sizeModifier) { + case ' ': + intArg = va_arg(arg, int); + sprintf(buffPtr, fmtBuff, intArg); + buffCount = strlen(buffPtr); + break; + case 'l': + /* + * XXX: Allowed by ISO C Amendment 1, but + * many platforms don't yet support wint_t + */ + goto ErrorReturn; + default: + goto ErrorReturn; + } + break; + case 's': + switch(sizeModifier) { + case ' ': + if(fastPath) { + buffPtr = va_arg(arg, char *); + buffCount = strlen(buffPtr); + buffLen = buffCount + 1; + } else { + sprintf(buffPtr, fmtBuff, charPtrArg); + buffCount = strlen(buffPtr); + } + break; + case 'l': + /* + * XXX: Don't know how to convert a sequence + * of wide characters into a byte stream, or + * even how to predict the buffering required. + */ + goto ErrorReturn; + default: + goto ErrorReturn; + } + break; + case 'p': + if(sizeModifier != ' ') + goto ErrorReturn; + voidPtrArg = va_arg(arg, void *); + sprintf(buffPtr, fmtBuff, voidPtrArg); + buffCount = strlen(buffPtr); + break; + case 'n': + switch(sizeModifier) { + case ' ': + intPtrArg = va_arg(arg, int *); + *intPtrArg = streamCount; + break; + case 'l': + longPtrArg = va_arg(arg, long *); + *longPtrArg = streamCount; + break; + case 'h': + shortPtrArg = (short *) va_arg(arg, short *); + *shortPtrArg = (short) streamCount; + break; + default: + goto ErrorReturn; + } + buffCount = 0; + break; + case 'f': + if(fastPath) { + performedOp = FALSE; + break; + } + switch(sizeModifier) { + case ' ': + sprintf(buffPtr, fmtBuff, doubleArg); + buffCount = strlen(buffPtr); + break; + case 'L': + sprintf(buffPtr, fmtBuff, lDoubleArg); + buffCount = strlen(buffPtr); + break; + default: + goto ErrorReturn; + } + break; + case 'e': + case 'E': + case 'g': + case 'G': + switch(sizeModifier) { + case ' ': + doubleArg = va_arg(arg, double); + sprintf(buffPtr, fmtBuff, doubleArg); + buffCount = strlen(buffPtr); + break; + case 'L': + lDoubleArg = va_arg(arg, LONG_DOUBLE); + sprintf(buffPtr, fmtBuff, lDoubleArg); + buffCount = strlen(buffPtr); + break; + default: + goto ErrorReturn; + } + break; + case '%': + if(sizeModifier != ' ') + goto ErrorReturn; + buff[0] = '%'; + buffCount = 1; + break; + case '\0': + goto ErrorReturn; + default: + performedOp = FALSE; + break; + } /* switch(op) */ + if(performedOp) break; + if(!fastPath) + goto ErrorReturn; + fastPath = FALSE; + } /* for (;;) */ + ASSERT(buffCount < buffLen); + if(buffCount > 0) { + if(FCGX_PutStr(buffPtr, buffCount, stream) < 0) + goto ErrorReturn; + streamCount += buffCount; + } else if(buffCount < 0) { + goto ErrorReturn; + } + f += specifierLength; + } /* while(f != fStop) */ + goto NormalReturn; + ErrorReturn: + streamCount = -1; + NormalReturn: + if(auxBuffPtr != NULL) free(auxBuffPtr); + return streamCount; +} + +/* + * Copy n characters from *srcPtr to *destPtr, then increment + * both *srcPtr and *destPtr by n. + */ +static void CopyAndAdvance(char **destPtr, char **srcPtr, int n) +{ + char *dest = *destPtr; + char *src = *srcPtr; + int i; + for (i = 0; i < n; i++) + *dest++ = *src++; + *destPtr = dest; + *srcPtr = src; +} + +/* + *---------------------------------------------------------------------- + * + * FCGX_FFlush -- + * + * Flushes any buffered output. + * + * Server-push is a legitimate application of FCGX_FFlush. + * Otherwise, FCGX_FFlush is not very useful, since FCGX_Accept + * does it implicitly. FCGX_FFlush may reduce performance + * by increasing the total number of operating system calls + * the application makes. + * + * Results: + * EOF (-1) if an error occurred. + * + *---------------------------------------------------------------------- + */ +int FCGX_FFlush(FCGX_Stream *stream) +{ + if(stream->isClosed || stream->isReader) + return 0; + stream->emptyBuffProc(stream, FALSE); + return (stream->isClosed) ? -1 : 0; +} + +/* + *---------------------------------------------------------------------- + * + * FCGX_FClose -- + * + * Performs FCGX_FFlush and closes the stream. + * + * This is not a very useful operation, since FCGX_Accept + * does it implicitly. Closing the out stream before the + * err stream results in an extra write if there's nothing + * in the err stream, and therefore reduces performance. + * + * Results: + * EOF (-1) if an error occurred. + * + *---------------------------------------------------------------------- + */ +int FCGX_FClose(FCGX_Stream *stream) +{ + if (stream == NULL) return 0; + + if(!stream->wasFCloseCalled) { + if(!stream->isReader) { + stream->emptyBuffProc(stream, TRUE); + } + stream->wasFCloseCalled = TRUE; + stream->isClosed = TRUE; + if(stream->isReader) { + stream->wrNext = stream->stop = stream->rdNext; + } else { + stream->rdNext = stream->stop = stream->wrNext; + } + } + return (stream->FCGI_errno == 0) ? 0 : EOF; +} + +/* + *---------------------------------------------------------------------- + * + * SetError -- + * + * An error has occurred; save the error code in the stream + * for diagnostic purposes and set the stream state so that + * reads return EOF and writes have no effect. + * + *---------------------------------------------------------------------- + */ +static void SetError(FCGX_Stream *stream, int FCGI_errno) +{ + /* + * Preserve only the first error. + */ + if(stream->FCGI_errno == 0) { + stream->FCGI_errno = FCGI_errno; + } + + stream->isClosed = TRUE; +} + +/* + *---------------------------------------------------------------------- + * + * FCGX_GetError -- + * + * Return the stream error code. 0 means no error, > 0 + * is an errno(2) error, < 0 is an FCGX_errno error. + * + *---------------------------------------------------------------------- + */ +int FCGX_GetError(FCGX_Stream *stream) { + return stream->FCGI_errno; +} + +/* + *---------------------------------------------------------------------- + * + * FCGX_ClearError -- + * + * Clear the stream error code and end-of-file indication. + * + *---------------------------------------------------------------------- + */ +void FCGX_ClearError(FCGX_Stream *stream) { + stream->FCGI_errno = 0; + /* + * stream->isClosed = FALSE; + * XXX: should clear isClosed but work is needed to make it safe + * to do so. For example, if an application calls FClose, gets + * an I/O error on the write, calls ClearError and retries + * the FClose, FClose (really EmptyBuffProc) will write a second + * EOF record. If an application calls PutChar instead of FClose + * after the ClearError, the application will write more data. + * The stream's state must discriminate between various states + * of the stream that are now all lumped under isClosed. + */ +} + +/* + *====================================================================== + * Parameters + *====================================================================== + */ + +/* + * A vector of pointers representing the parameters received + * by a FastCGI application server, with the vector's length + * and last valid element so adding new parameters is efficient. + */ + +typedef struct Params { + FCGX_ParamArray vec; /* vector of strings */ + int length; /* number of string vec can hold */ + char **cur; /* current item in vec; *cur == NULL */ +} Params; +typedef Params *ParamsPtr; + +/* + *---------------------------------------------------------------------- + * + * NewParams -- + * + * Creates a new Params structure. + * + * Results: + * Pointer to the new structure. + * + *---------------------------------------------------------------------- + */ +static ParamsPtr NewParams(int length) +{ + ParamsPtr result; + result = (Params *)Malloc(sizeof(Params)); + result->vec = (char **)Malloc(length * sizeof(char *)); + result->length = length; + result->cur = result->vec; + *result->cur = NULL; + return result; +} + +/* + *---------------------------------------------------------------------- + * + * FreeParams -- + * + * Frees a Params structure and all the parameters it contains. + * + * Side effects: + * env becomes invalid. + * + *---------------------------------------------------------------------- + */ +static void FreeParams(ParamsPtr *paramsPtrPtr) +{ + ParamsPtr paramsPtr = *paramsPtrPtr; + char **p; + if(paramsPtr == NULL) { + return; + } + for (p = paramsPtr->vec; p < paramsPtr->cur; p++) { + free(*p); + } + free(paramsPtr->vec); + free(paramsPtr); + *paramsPtrPtr = NULL; +} + +/* + *---------------------------------------------------------------------- + * + * PutParam -- + * + * Add a name/value pair to a Params structure. + * + * Results: + * None. + * + * Side effects: + * Parameters structure updated. + * + *---------------------------------------------------------------------- + */ +static void PutParam(ParamsPtr paramsPtr, char *nameValue) +{ + int size; + + *paramsPtr->cur++ = nameValue; + size = paramsPtr->cur - paramsPtr->vec; + if(size >= paramsPtr->length) { + paramsPtr->length *= 2; + paramsPtr->vec = (FCGX_ParamArray)realloc(paramsPtr->vec, paramsPtr->length * sizeof(char *)); + paramsPtr->cur = paramsPtr->vec + size; + } + *paramsPtr->cur = NULL; +} + +/* + *---------------------------------------------------------------------- + * + * FCGX_GetParam -- obtain value of FCGI parameter in environment + * + * + * Results: + * Value bound to name, NULL if name not present in the + * environment envp. Caller must not mutate the result + * or retain it past the end of this request. + * + *---------------------------------------------------------------------- + */ +char *FCGX_GetParam(const char *name, FCGX_ParamArray envp) +{ + int len; + char **p; + + if (name == NULL || envp == NULL) return NULL; + + len = strlen(name); + + for (p = envp; *p; ++p) { + if((strncmp(name, *p, len) == 0) && ((*p)[len] == '=')) { + return *p+len+1; + } + } + return NULL; +} + +/* + *---------------------------------------------------------------------- + * + * Start of FastCGI-specific code + * + *---------------------------------------------------------------------- + */ + +/* + *---------------------------------------------------------------------- + * + * ReadParams -- + * + * Reads FastCGI name-value pairs from stream until EOF. Converts + * each pair to name=value format and adds it to Params structure. + * + *---------------------------------------------------------------------- + */ +static int ReadParams(Params *paramsPtr, FCGX_Stream *stream) +{ + int nameLen, valueLen; + unsigned char lenBuff[3]; + char *nameValue; + + while((nameLen = FCGX_GetChar(stream)) != EOF) { + /* + * Read name length (one or four bytes) and value length + * (one or four bytes) from stream. + */ + if((nameLen & 0x80) != 0) { + if(FCGX_GetStr((char *) &lenBuff[0], 3, stream) != 3) { + SetError(stream, FCGX_PARAMS_ERROR); + return -1; + } + nameLen = ((nameLen & 0x7f) << 24) + (lenBuff[0] << 16) + + (lenBuff[1] << 8) + lenBuff[2]; + } + if((valueLen = FCGX_GetChar(stream)) == EOF) { + SetError(stream, FCGX_PARAMS_ERROR); + return -1; + } + if((valueLen & 0x80) != 0) { + if(FCGX_GetStr((char *) &lenBuff[0], 3, stream) != 3) { + SetError(stream, FCGX_PARAMS_ERROR); + return -1; + } + valueLen = ((valueLen & 0x7f) << 24) + (lenBuff[0] << 16) + + (lenBuff[1] << 8) + lenBuff[2]; + } + /* + * nameLen and valueLen are now valid; read the name and value + * from stream and construct a standard environment entry. + */ + nameValue = (char *)Malloc(nameLen + valueLen + 2); + if(FCGX_GetStr(nameValue, nameLen, stream) != nameLen) { + SetError(stream, FCGX_PARAMS_ERROR); + free(nameValue); + return -1; + } + *(nameValue + nameLen) = '='; + if(FCGX_GetStr(nameValue + nameLen + 1, valueLen, stream) + != valueLen) { + SetError(stream, FCGX_PARAMS_ERROR); + free(nameValue); + return -1; + } + *(nameValue + nameLen + valueLen + 1) = '\0'; + PutParam(paramsPtr, nameValue); + } + return 0; +} + +/* + *---------------------------------------------------------------------- + * + * MakeHeader -- + * + * Constructs an FCGI_Header struct. + * + *---------------------------------------------------------------------- + */ +static FCGI_Header MakeHeader( + int type, + int requestId, + int contentLength, + int paddingLength) +{ + FCGI_Header header; + ASSERT(contentLength >= 0 && contentLength <= FCGI_MAX_LENGTH); + ASSERT(paddingLength >= 0 && paddingLength <= 0xff); + header.version = FCGI_VERSION_1; + header.type = (unsigned char) type; + header.requestIdB1 = (unsigned char) ((requestId >> 8) & 0xff); + header.requestIdB0 = (unsigned char) ((requestId ) & 0xff); + header.contentLengthB1 = (unsigned char) ((contentLength >> 8) & 0xff); + header.contentLengthB0 = (unsigned char) ((contentLength ) & 0xff); + header.paddingLength = (unsigned char) paddingLength; + header.reserved = 0; + return header; +} + +/* + *---------------------------------------------------------------------- + * + * MakeEndRequestBody -- + * + * Constructs an FCGI_EndRequestBody struct. + * + *---------------------------------------------------------------------- + */ +static FCGI_EndRequestBody MakeEndRequestBody( + int appStatus, + int protocolStatus) +{ + FCGI_EndRequestBody body; + body.appStatusB3 = (unsigned char) ((appStatus >> 24) & 0xff); + body.appStatusB2 = (unsigned char) ((appStatus >> 16) & 0xff); + body.appStatusB1 = (unsigned char) ((appStatus >> 8) & 0xff); + body.appStatusB0 = (unsigned char) ((appStatus ) & 0xff); + body.protocolStatus = (unsigned char) protocolStatus; + memset(body.reserved, 0, sizeof(body.reserved)); + return body; +} + +/* + *---------------------------------------------------------------------- + * + * MakeUnknownTypeBody -- + * + * Constructs an FCGI_MakeUnknownTypeBody struct. + * + *---------------------------------------------------------------------- + */ +static FCGI_UnknownTypeBody MakeUnknownTypeBody( + int type) +{ + FCGI_UnknownTypeBody body; + body.type = (unsigned char) type; + memset(body.reserved, 0, sizeof(body.reserved)); + return body; +} + +/* + *---------------------------------------------------------------------- + * + * AlignInt8 -- + * + * Returns the smallest integer greater than or equal to n + * that's a multiple of 8. + * + *---------------------------------------------------------------------- + */ +static int AlignInt8(unsigned n) { + return (n + 7) & (UINT_MAX - 7); +} + +/* + *---------------------------------------------------------------------- + * + * AlignPtr8 -- + * + * Returns the smallest pointer greater than or equal to p + * that's a multiple of 8. + * + *---------------------------------------------------------------------- + */ +static unsigned char *AlignPtr8(unsigned char *p) { + unsigned long u = (unsigned long) p; + u = ((u + 7) & (ULONG_MAX - 7)) - u; + return p + u; +} + + +/* + * State associated with a stream + */ +typedef struct FCGX_Stream_Data { + unsigned char *buff; /* buffer after alignment */ + int bufflen; /* number of bytes buff can store */ + unsigned char *mBuff; /* buffer as returned by Malloc */ + unsigned char *buffStop; /* reader: last valid byte + 1 of entire buffer. + * stop generally differs from buffStop for + * readers because of record structure. + * writer: buff + bufflen */ + int type; /* reader: FCGI_PARAMS or FCGI_STDIN + * writer: FCGI_STDOUT or FCGI_STDERR */ + int eorStop; /* reader: stop stream at end-of-record */ + int skip; /* reader: don't deliver content bytes */ + int contentLen; /* reader: bytes of unread content */ + int paddingLen; /* reader: bytes of unread padding */ + int isAnythingWritten; /* writer: data has been written to ipcFd */ + int rawWrite; /* writer: write data without stream headers */ + FCGX_Request *reqDataPtr; /* request data not specific to one stream */ +} FCGX_Stream_Data; + +/* + *---------------------------------------------------------------------- + * + * WriteCloseRecords -- + * + * Writes an EOF record for the stream content if necessary. + * If this is the last writer to close, writes an FCGI_END_REQUEST + * record. + * + *---------------------------------------------------------------------- + */ +static void WriteCloseRecords(struct FCGX_Stream *stream) +{ + FCGX_Stream_Data *data = (FCGX_Stream_Data *)stream->data; + /* + * Enter rawWrite mode so final records won't be encapsulated as + * stream data. + */ + data->rawWrite = TRUE; + /* + * Generate EOF for stream content if needed. + */ + if(!(data->type == FCGI_STDERR + && stream->wrNext == data->buff + && !data->isAnythingWritten)) { + FCGI_Header header; + header = MakeHeader(data->type, data->reqDataPtr->requestId, 0, 0); + FCGX_PutStr((char *) &header, sizeof(header), stream); + }; + /* + * Generate FCGI_END_REQUEST record if needed. + */ + if(data->reqDataPtr->nWriters == 1) { + FCGI_EndRequestRecord endRequestRecord; + endRequestRecord.header = MakeHeader(FCGI_END_REQUEST, + data->reqDataPtr->requestId, + sizeof(endRequestRecord.body), 0); + endRequestRecord.body = MakeEndRequestBody( + data->reqDataPtr->appStatus, FCGI_REQUEST_COMPLETE); + FCGX_PutStr((char *) &endRequestRecord, + sizeof(endRequestRecord), stream); + } + data->reqDataPtr->nWriters--; +} + + + +static int write_it_all(int fd, char *buf, int len) +{ + int wrote; + + while (len) { + wrote = OS_Write(fd, buf, len); + if (wrote < 0) + return wrote; + len -= wrote; + buf += wrote; + } + return len; +} + +/* + *---------------------------------------------------------------------- + * + * EmptyBuffProc -- + * + * Encapsulates any buffered stream content in a FastCGI + * record. Writes the data, making the buffer empty. + * + *---------------------------------------------------------------------- + */ +static void EmptyBuffProc(struct FCGX_Stream *stream, int doClose) +{ + FCGX_Stream_Data *data = (FCGX_Stream_Data *)stream->data; + int cLen, eLen; + /* + * If the buffer contains stream data, fill in the header. + * Pad the record to a multiple of 8 bytes in length. Padding + * can't overflow the buffer because the buffer is a multiple + * of 8 bytes in length. If the buffer contains no stream + * data, reclaim the space reserved for the header. + */ + if(!data->rawWrite) { + cLen = stream->wrNext - data->buff - sizeof(FCGI_Header); + if(cLen > 0) { + eLen = AlignInt8(cLen); + /* + * Giving the padding a well-defined value keeps Purify happy. + */ + memset(stream->wrNext, 0, eLen - cLen); + stream->wrNext += eLen - cLen; + *((FCGI_Header *) data->buff) + = MakeHeader(data->type, + data->reqDataPtr->requestId, cLen, eLen - cLen); + } else { + stream->wrNext = data->buff; + } + } + if(doClose) { + WriteCloseRecords(stream); + }; + if (stream->wrNext != data->buff) { + data->isAnythingWritten = TRUE; + if (write_it_all(data->reqDataPtr->ipcFd, (char *)data->buff, stream->wrNext - data->buff) < 0) { + SetError(stream, OS_Errno); + return; + } + stream->wrNext = data->buff; + } + /* + * The buffer is empty. + */ + if(!data->rawWrite) { + stream->wrNext += sizeof(FCGI_Header); + } +} + +/* + * Return codes for Process* functions + */ +#define STREAM_RECORD 0 +#define SKIP 1 +#define BEGIN_RECORD 2 +#define MGMT_RECORD 3 + +/* + *---------------------------------------------------------------------- + * + * ProcessManagementRecord -- + * + * Reads and responds to a management record. The only type of + * management record this library understands is FCGI_GET_VALUES. + * The only variables that this library's FCGI_GET_VALUES + * understands are FCGI_MAX_CONNS, FCGI_MAX_REQS, and FCGI_MPXS_CONNS. + * Ignore other FCGI_GET_VALUES variables; respond to other + * management records with a FCGI_UNKNOWN_TYPE record. + * + *---------------------------------------------------------------------- + */ +static int ProcessManagementRecord(int type, FCGX_Stream *stream) +{ + FCGX_Stream_Data *data = (FCGX_Stream_Data *)stream->data; + ParamsPtr paramsPtr = NewParams(3); + char **pPtr; + char response[64]; /* 64 = 8 + 3*(1+1+14+1)* + padding */ + char *responseP = &response[FCGI_HEADER_LEN]; + char *name, value = '\0'; + int len, paddedLen; + if(type == FCGI_GET_VALUES) { + ReadParams(paramsPtr, stream); + if((FCGX_GetError(stream) != 0) || (data->contentLen != 0)) { + FreeParams(¶msPtr); + return FCGX_PROTOCOL_ERROR; + } + for (pPtr = paramsPtr->vec; pPtr < paramsPtr->cur; pPtr++) { + name = *pPtr; + *(strchr(name, '=')) = '\0'; + if(strcmp(name, FCGI_MAX_CONNS) == 0) { + value = '1'; + } else if(strcmp(name, FCGI_MAX_REQS) == 0) { + value = '1'; + } else if(strcmp(name, FCGI_MPXS_CONNS) == 0) { + value = '0'; + } else { + name = NULL; + } + if(name != NULL) { + len = strlen(name); + sprintf(responseP, "%c%c%s%c", len, 1, name, value); + responseP += len + 3; + } + } + len = responseP - &response[FCGI_HEADER_LEN]; + paddedLen = AlignInt8(len); + *((FCGI_Header *) response) + = MakeHeader(FCGI_GET_VALUES_RESULT, FCGI_NULL_REQUEST_ID, + len, paddedLen - len); + FreeParams(¶msPtr); + } else { + paddedLen = len = sizeof(FCGI_UnknownTypeBody); + ((FCGI_UnknownTypeRecord *) response)->header + = MakeHeader(FCGI_UNKNOWN_TYPE, FCGI_NULL_REQUEST_ID, + len, 0); + ((FCGI_UnknownTypeRecord *) response)->body + = MakeUnknownTypeBody(type); + } + if (write_it_all(data->reqDataPtr->ipcFd, response, FCGI_HEADER_LEN + paddedLen) < 0) { + SetError(stream, OS_Errno); + return -1; + } + + return MGMT_RECORD; +} + +/* + *---------------------------------------------------------------------- + * + * ProcessBeginRecord -- + * + * Reads an FCGI_BEGIN_REQUEST record. + * + * Results: + * BEGIN_RECORD for normal return. FCGX_PROTOCOL_ERROR for + * protocol error. SKIP for attempt to multiplex + * connection. -1 for error from write (errno in stream). + * + * Side effects: + * In case of BEGIN_RECORD return, stores requestId, role, + * keepConnection values, and sets isBeginProcessed = TRUE. + * + *---------------------------------------------------------------------- + */ +static int ProcessBeginRecord(int requestId, FCGX_Stream *stream) +{ + FCGX_Stream_Data *data = (FCGX_Stream_Data *)stream->data; + FCGI_BeginRequestBody body; + if(requestId == 0 || data->contentLen != sizeof(body)) { + return FCGX_PROTOCOL_ERROR; + } + if(data->reqDataPtr->isBeginProcessed) { + /* + * The Web server is multiplexing the connection. This library + * doesn't know how to handle multiplexing, so respond with + * FCGI_END_REQUEST{protocolStatus = FCGI_CANT_MPX_CONN} + */ + FCGI_EndRequestRecord endRequestRecord; + endRequestRecord.header = MakeHeader(FCGI_END_REQUEST, + requestId, sizeof(endRequestRecord.body), 0); + endRequestRecord.body + = MakeEndRequestBody(0, FCGI_CANT_MPX_CONN); + if (write_it_all(data->reqDataPtr->ipcFd, (char *)&endRequestRecord, sizeof(endRequestRecord)) < 0) { + SetError(stream, OS_Errno); + return -1; + } + + return SKIP; + } + /* + * Accept this new request. Read the record body. + */ + data->reqDataPtr->requestId = requestId; + if(FCGX_GetStr((char *) &body, sizeof(body), stream) + != sizeof(body)) { + return FCGX_PROTOCOL_ERROR; + } + data->reqDataPtr->keepConnection = (body.flags & FCGI_KEEP_CONN); + data->reqDataPtr->role = (body.roleB1 << 8) + body.roleB0; + data->reqDataPtr->isBeginProcessed = TRUE; + return BEGIN_RECORD; +} + +/* + *---------------------------------------------------------------------- + * + * ProcessHeader -- + * + * Interprets FCGI_Header. Processes FCGI_BEGIN_REQUEST and + * management records here; extracts information from stream + * records (FCGI_PARAMS, FCGI_STDIN) into stream. + * + * Results: + * >= 0 for a normal return, < 0 for error + * + * Side effects: + * XXX: Many (more than there used to be). + * If !stream->isRequestIdSet, ProcessHeader initializes + * stream->requestId from header and sets stream->isRequestIdSet + * to TRUE. ProcessHeader also sets stream->contentLen to header's + * contentLength, and sets stream->paddingLen to the header's + * paddingLength. + * + *---------------------------------------------------------------------- + */ +static int ProcessHeader(FCGI_Header header, FCGX_Stream *stream) +{ + FCGX_Stream_Data *data = (FCGX_Stream_Data *)stream->data; + int requestId; + if(header.version != FCGI_VERSION_1) { + return FCGX_UNSUPPORTED_VERSION; + } + requestId = (header.requestIdB1 << 8) + + header.requestIdB0; + data->contentLen = (header.contentLengthB1 << 8) + + header.contentLengthB0; + data->paddingLen = header.paddingLength; + if(header.type == FCGI_BEGIN_REQUEST) { + return ProcessBeginRecord(requestId, stream); + } + if(requestId == FCGI_NULL_REQUEST_ID) { + return ProcessManagementRecord(header.type, stream); + } + if(requestId != data->reqDataPtr->requestId) { + return SKIP; + } + if(header.type != data->type) { + return FCGX_PROTOCOL_ERROR; + } + return STREAM_RECORD; +} + +/* + *---------------------------------------------------------------------- + * + * FillBuffProc -- + * + * Reads bytes from the ipcFd, supplies bytes to a stream client. + * + *---------------------------------------------------------------------- + */ +static void FillBuffProc(FCGX_Stream *stream) +{ + FCGX_Stream_Data *data = (FCGX_Stream_Data *)stream->data; + FCGI_Header header; + int headerLen = 0; + int status, count; + + for (;;) { + /* + * If data->buff is empty, do a read. + */ + if(stream->rdNext == data->buffStop) { + count = OS_Read(data->reqDataPtr->ipcFd, (char *)data->buff, + data->bufflen); + if(count <= 0) { + SetError(stream, (count == 0 ? FCGX_PROTOCOL_ERROR : OS_Errno)); + return; + } + stream->rdNext = data->buff; + data->buffStop = data->buff + count; + } + /* + * Now data->buff is not empty. If the current record contains + * more content bytes, deliver all that are present in data->buff. + */ + if(data->contentLen > 0) { + count = min(data->contentLen, data->buffStop - stream->rdNext); + data->contentLen -= count; + if(!data->skip) { + stream->wrNext = stream->stop = stream->rdNext + count; + return; + } else { + stream->rdNext += count; + if(data->contentLen > 0) { + continue; + } else { + data->skip = FALSE; + } + } + } + /* + * If the current record (whose content has been fully consumed by + * the client) was padded, skip over the padding bytes. + */ + if(data->paddingLen > 0) { + count = min(data->paddingLen, data->buffStop - stream->rdNext); + data->paddingLen -= count; + stream->rdNext += count; + if(data->paddingLen > 0) { + continue; + } + } + /* + * All done with the current record, including the padding. + * If we're in a recursive call from ProcessHeader, deliver EOF. + */ + if(data->eorStop) { + stream->stop = stream->rdNext; + stream->isClosed = TRUE; + return; + } + /* + * Fill header with bytes from the input buffer. + */ + count = min((int)sizeof(header) - headerLen, + data->buffStop - stream->rdNext); + memcpy(((char *)(&header)) + headerLen, stream->rdNext, count); + headerLen += count; + stream->rdNext += count; + if(headerLen < sizeof(header)) { + continue; + }; + headerLen = 0; + /* + * Interpret header. eorStop prevents ProcessHeader from reading + * past the end-of-record when using stream to read content. + */ + data->eorStop = TRUE; + stream->stop = stream->rdNext; + status = ProcessHeader(header, stream); + data->eorStop = FALSE; + stream->isClosed = FALSE; + switch(status) { + case STREAM_RECORD: + /* + * If this stream record header marked the end of stream + * data deliver EOF to the stream client, otherwise loop + * and deliver data. + * + * XXX: If this is final stream and + * stream->rdNext != data->buffStop, buffered + * data is next request (server pipelining)? + */ + if(data->contentLen == 0) { + stream->wrNext = stream->stop = stream->rdNext; + stream->isClosed = TRUE; + return; + } + break; + case SKIP: + data->skip = TRUE; + break; + case BEGIN_RECORD: + /* + * If this header marked the beginning of a new + * request, return role information to caller. + */ + return; + break; + case MGMT_RECORD: + break; + default: + ASSERT(status < 0); + SetError(stream, status); + return; + break; + } + } +} + +/* + *---------------------------------------------------------------------- + * + * NewStream -- + * + * Creates a stream to read or write from an open ipcFd. + * The stream performs reads/writes of up to bufflen bytes. + * + *---------------------------------------------------------------------- + */ +static FCGX_Stream *NewStream( + FCGX_Request *reqDataPtr, int bufflen, int isReader, int streamType) +{ + /* + * XXX: It would be a lot cleaner to have a NewStream that only + * knows about the type FCGX_Stream, with all other + * necessary data passed in. It appears that not just + * data and the two procs are needed for initializing stream, + * but also data->buff and data->buffStop. This has implications + * for procs that want to swap buffers, too. + */ + FCGX_Stream *stream = (FCGX_Stream *)Malloc(sizeof(FCGX_Stream)); + FCGX_Stream_Data *data = (FCGX_Stream_Data *)Malloc(sizeof(FCGX_Stream_Data)); + data->reqDataPtr = reqDataPtr; + bufflen = AlignInt8(min(max(bufflen, 32), FCGI_MAX_LENGTH + 1)); + data->bufflen = bufflen; + data->mBuff = (unsigned char *)Malloc(bufflen); + data->buff = AlignPtr8(data->mBuff); + if(data->buff != data->mBuff) { + data->bufflen -= 8; + } + if(isReader) { + data->buffStop = data->buff; + } else { + data->buffStop = data->buff + data->bufflen; + } + data->type = streamType; + data->eorStop = FALSE; + data->skip = FALSE; + data->contentLen = 0; + data->paddingLen = 0; + data->isAnythingWritten = FALSE; + data->rawWrite = FALSE; + + stream->data = data; + stream->isReader = isReader; + stream->isClosed = FALSE; + stream->wasFCloseCalled = FALSE; + stream->FCGI_errno = 0; + if(isReader) { + stream->fillBuffProc = FillBuffProc; + stream->emptyBuffProc = NULL; + stream->rdNext = data->buff; + stream->stop = stream->rdNext; + stream->stopUnget = data->buff; + stream->wrNext = stream->stop; + } else { + stream->fillBuffProc = NULL; + stream->emptyBuffProc = EmptyBuffProc; + stream->wrNext = data->buff + sizeof(FCGI_Header); + stream->stop = data->buffStop; + stream->stopUnget = NULL; + stream->rdNext = stream->stop; + } + return stream; +} + +/* + *---------------------------------------------------------------------- + * + * FCGX_FreeStream -- + * + * Frees all storage allocated when *streamPtr was created, + * and nulls out *streamPtr. + * + *---------------------------------------------------------------------- + */ +void FCGX_FreeStream(FCGX_Stream **streamPtr) +{ + FCGX_Stream *stream = *streamPtr; + FCGX_Stream_Data *data; + if(stream == NULL) { + return; + } + data = (FCGX_Stream_Data *)stream->data; + data->reqDataPtr = NULL; + free(data->mBuff); + free(data); + free(stream); + *streamPtr = NULL; +} + +/* + *---------------------------------------------------------------------- + * + * SetReaderType -- + * + * Re-initializes the stream to read data of the specified type. + * + *---------------------------------------------------------------------- + */ +static FCGX_Stream *SetReaderType(FCGX_Stream *stream, int streamType) +{ + FCGX_Stream_Data *data = (FCGX_Stream_Data *)stream->data; + ASSERT(stream->isReader); + data->type = streamType; + data->eorStop = FALSE; + data->skip = FALSE; + data->contentLen = 0; + data->paddingLen = 0; + stream->wrNext = stream->stop = stream->rdNext; + stream->isClosed = FALSE; + return stream; +} + +/* + *---------------------------------------------------------------------- + * + * NewReader -- + * + * Creates a stream to read streamType records for the given + * request. The stream performs OS reads of up to bufflen bytes. + * + *---------------------------------------------------------------------- + */ +static FCGX_Stream *NewReader(FCGX_Request *reqDataPtr, int bufflen, int streamType) +{ + return NewStream(reqDataPtr, bufflen, TRUE, streamType); +} + +/* + *---------------------------------------------------------------------- + * + * NewWriter -- + * + * Creates a stream to write streamType FastCGI records, using + * the ipcFd and RequestId contained in *reqDataPtr. + * The stream performs OS writes of up to bufflen bytes. + * + *---------------------------------------------------------------------- + */ +static FCGX_Stream *NewWriter(FCGX_Request *reqDataPtr, int bufflen, int streamType) +{ + return NewStream(reqDataPtr, bufflen, FALSE, streamType); +} + +/* + *---------------------------------------------------------------------- + * + * FCGX_CreateWriter -- + * + * Creates a stream to write streamType FastCGI records, using + * the given ipcFd and request Id. This function is provided + * for use by cgi-fcgi. In order to be defensive against misuse, + * this function leaks a little storage; cgi-fcgi doesn't care. + * + *---------------------------------------------------------------------- + */ +FCGX_Stream *FCGX_CreateWriter( + int ipcFd, + int requestId, + int bufflen, + int streamType) +{ + FCGX_Request *reqDataPtr = (FCGX_Request *)Malloc(sizeof(FCGX_Request)); + reqDataPtr->ipcFd = ipcFd; + reqDataPtr->requestId = requestId; + /* + * Suppress writing an FCGI_END_REQUEST record. + */ + reqDataPtr->nWriters = 2; + return NewWriter(reqDataPtr, bufflen, streamType); +} + +/* + *====================================================================== + * Control + *====================================================================== + */ + +/* + *---------------------------------------------------------------------- + * + * FCGX_IsCGI -- + * + * This routine determines if the process is running as a CGI or + * FastCGI process. The distinction is made by determining whether + * FCGI_LISTENSOCK_FILENO is a listener ipcFd or the end of a + * pipe (ie. standard in). + * + * Results: + * TRUE if the process is a CGI process, FALSE if FastCGI. + * + *---------------------------------------------------------------------- + */ +int FCGX_IsCGI(void) +{ + if (isFastCGI != -1) { + return !isFastCGI; + } + + if (!libInitialized) { + int rc = FCGX_Init(); + if (rc) { + /* exit() isn't great, but hey */ + exit((rc < 0) ? rc : -rc); + } + } + + isFastCGI = OS_IsFcgi(FCGI_LISTENSOCK_FILENO); + + return !isFastCGI; +} + +/* + *---------------------------------------------------------------------- + * + * FCGX_Finish -- + * + * Finishes the current request from the HTTP server. + * + * Side effects: + * + * Finishes the request accepted by (and frees any + * storage allocated by) the previous call to FCGX_Accept. + * + * DO NOT retain pointers to the envp array or any strings + * contained in it (e.g. to the result of calling FCGX_GetParam), + * since these will be freed by the next call to FCGX_Finish + * or FCGX_Accept. + * + *---------------------------------------------------------------------- + */ + +void FCGX_Finish(void) +{ + FCGX_Finish_r(&the_request); +} + +/* + *---------------------------------------------------------------------- + * + * FCGX_Finish_r -- + * + * Finishes the current request from the HTTP server. + * + * Side effects: + * + * Finishes the request accepted by (and frees any + * storage allocated by) the previous call to FCGX_Accept. + * + * DO NOT retain pointers to the envp array or any strings + * contained in it (e.g. to the result of calling FCGX_GetParam), + * since these will be freed by the next call to FCGX_Finish + * or FCGX_Accept. + * + *---------------------------------------------------------------------- + */ +void FCGX_Finish_r(FCGX_Request *reqDataPtr) +{ + int close; + + if (reqDataPtr == NULL) { + return; + } + + close = !reqDataPtr->keepConnection; + + /* This should probably use a 'status' member instead of 'in' */ + if (reqDataPtr->in) { + close |= FCGX_FClose(reqDataPtr->err); + close |= FCGX_FClose(reqDataPtr->out); + + close |= FCGX_GetError(reqDataPtr->in); + } + + FCGX_Free(reqDataPtr, close); +} + +void FCGX_Free(FCGX_Request * request, int close) +{ + if (request == NULL) + return; + + FCGX_FreeStream(&request->in); + FCGX_FreeStream(&request->out); + FCGX_FreeStream(&request->err); + FreeParams(&request->paramsPtr); + + if (close) { + OS_IpcClose(request->ipcFd); + request->ipcFd = -1; + } +} + +int FCGX_OpenSocket(const char *path, int backlog) +{ + int rc = OS_CreateLocalIpcFd(path, backlog); + if (rc == FCGI_LISTENSOCK_FILENO && isFastCGI == 0) { + /* XXX probably need to call OS_LibInit() again for Win */ + isFastCGI = 1; + } + return rc; +} + +int FCGX_InitRequest(FCGX_Request *request, int sock, int flags) +{ + memset(request, 0, sizeof(FCGX_Request)); + + /* @@@ Should check that sock is open and listening */ + request->listen_sock = sock; + + /* @@@ Should validate against "known" flags */ + request->flags = flags; + + request->ipcFd = -1; + + return 0; +} + +/* + *---------------------------------------------------------------------- + * + * FCGX_Init -- + * + * Initilize the FCGX library. This is called by FCGX_Accept() + * but must be called by the user when using FCGX_Accept_r(). + * + * Results: + * 0 for successful call. + * + *---------------------------------------------------------------------- + */ +int FCGX_Init(void) +{ + char *p; + + if (libInitialized) { + return 0; + } + + FCGX_InitRequest(&the_request, FCGI_LISTENSOCK_FILENO, 0); + + if (OS_LibInit(NULL) == -1) { + return OS_Errno ? OS_Errno : -9997; + } + + p = getenv("FCGI_WEB_SERVER_ADDRS"); + webServerAddressList = p ? StringCopy(p) : NULL; + + libInitialized = 1; + return 0; +} + +/* + *---------------------------------------------------------------------- + * + * FCGX_Accept -- + * + * Accepts a new request from the HTTP server. + * + * Results: + * 0 for successful call, -1 for error. + * + * Side effects: + * + * Finishes the request accepted by (and frees any + * storage allocated by) the previous call to FCGX_Accept. + * Creates input, output, and error streams and + * assigns them to *in, *out, and *err respectively. + * Creates a parameters data structure to be accessed + * via getenv(3) (if assigned to environ) or by FCGX_GetParam + * and assigns it to *envp. + * + * DO NOT retain pointers to the envp array or any strings + * contained in it (e.g. to the result of calling FCGX_GetParam), + * since these will be freed by the next call to FCGX_Finish + * or FCGX_Accept. + * + *---------------------------------------------------------------------- + */ + +int FCGX_Accept( + FCGX_Stream **in, + FCGX_Stream **out, + FCGX_Stream **err, + FCGX_ParamArray *envp) +{ + int rc; + + if (! libInitialized) { + rc = FCGX_Init(); + if (rc) { + return rc; + } + } + + rc = FCGX_Accept_r(&the_request); + + *in = the_request.in; + *out = the_request.out; + *err = the_request.err; + *envp = the_request.envp; + + return rc; +} + +/* + *---------------------------------------------------------------------- + * + * FCGX_Accept_r -- + * + * Accepts a new request from the HTTP server. + * + * Results: + * 0 for successful call, -1 for error. + * + * Side effects: + * + * Finishes the request accepted by (and frees any + * storage allocated by) the previous call to FCGX_Accept. + * Creates input, output, and error streams and + * assigns them to *in, *out, and *err respectively. + * Creates a parameters data structure to be accessed + * via getenv(3) (if assigned to environ) or by FCGX_GetParam + * and assigns it to *envp. + * + * DO NOT retain pointers to the envp array or any strings + * contained in it (e.g. to the result of calling FCGX_GetParam), + * since these will be freed by the next call to FCGX_Finish + * or FCGX_Accept. + * + *---------------------------------------------------------------------- + */ +int FCGX_Accept_r(FCGX_Request *reqDataPtr) +{ + if (!libInitialized) { + return -9998; + } + + /* Finish the current request, if any. */ + FCGX_Finish_r(reqDataPtr); + + for (;;) { + /* + * If a connection isn't open, accept a new connection (blocking). + * If an OS error occurs in accepting the connection, + * return -1 to the caller, who should exit. + */ + if (reqDataPtr->ipcFd < 0) { + int fail_on_intr = reqDataPtr->flags & FCGI_FAIL_ACCEPT_ON_INTR; + + reqDataPtr->ipcFd = OS_Accept(reqDataPtr->listen_sock, fail_on_intr, webServerAddressList); + if (reqDataPtr->ipcFd < 0) { + return (errno > 0) ? (0 - errno) : -9999; + } + } + /* + * A connection is open. Read from the connection in order to + * get the request's role and environment. If protocol or other + * errors occur, close the connection and try again. + */ + reqDataPtr->isBeginProcessed = FALSE; + reqDataPtr->in = NewReader(reqDataPtr, 8192, 0); + FillBuffProc(reqDataPtr->in); + if(!reqDataPtr->isBeginProcessed) { + goto TryAgain; + } + { + char *roleStr; + switch(reqDataPtr->role) { + case FCGI_RESPONDER: + roleStr = "FCGI_ROLE=RESPONDER"; + break; + case FCGI_AUTHORIZER: + roleStr = "FCGI_ROLE=AUTHORIZER"; + break; + case FCGI_FILTER: + roleStr = "FCGI_ROLE=FILTER"; + break; + default: + goto TryAgain; + } + reqDataPtr->paramsPtr = NewParams(30); + PutParam(reqDataPtr->paramsPtr, StringCopy(roleStr)); + } + SetReaderType(reqDataPtr->in, FCGI_PARAMS); + if(ReadParams(reqDataPtr->paramsPtr, reqDataPtr->in) >= 0) { + /* + * Finished reading the environment. No errors occurred, so + * leave the connection-retry loop. + */ + break; + } + + /* + * Close the connection and try again. + */ +TryAgain: + FCGX_Free(reqDataPtr, 1); + + } /* for (;;) */ + /* + * Build the remaining data structures representing the new + * request and return successfully to the caller. + */ + SetReaderType(reqDataPtr->in, FCGI_STDIN); + reqDataPtr->out = NewWriter(reqDataPtr, 8192, FCGI_STDOUT); + reqDataPtr->err = NewWriter(reqDataPtr, 512, FCGI_STDERR); + reqDataPtr->nWriters = 2; + reqDataPtr->envp = reqDataPtr->paramsPtr->vec; + return 0; +} + +/* + *---------------------------------------------------------------------- + * + * FCGX_StartFilterData -- + * + * stream is an input stream for a FCGI_FILTER request. + * stream is positioned at EOF on FCGI_STDIN. + * Repositions stream to the start of FCGI_DATA. + * If the preconditions are not met (e.g. FCGI_STDIN has not + * been read to EOF) sets the stream error code to + * FCGX_CALL_SEQ_ERROR. + * + * Results: + * 0 for a normal return, < 0 for error + * + *---------------------------------------------------------------------- + */ + +int FCGX_StartFilterData(FCGX_Stream *stream) +{ + FCGX_Stream_Data *data = (FCGX_Stream_Data *)stream->data; + if(data->reqDataPtr->role != FCGI_FILTER + || !stream->isReader + || !stream->isClosed + || data->type != FCGI_STDIN) { + SetError(stream, FCGX_CALL_SEQ_ERROR); + return -1; + } + SetReaderType(stream, FCGI_DATA); + return 0; +} + +/* + *---------------------------------------------------------------------- + * + * FCGX_SetExitStatus -- + * + * Sets the exit status for stream's request. The exit status + * is the status code the request would have exited with, had + * the request been run as a CGI program. You can call + * SetExitStatus several times during a request; the last call + * before the request ends determines the value. + * + *---------------------------------------------------------------------- + */ + +void FCGX_SetExitStatus(int status, FCGX_Stream *stream) +{ + FCGX_Stream_Data *data = (FCGX_Stream_Data *)stream->data; + data->reqDataPtr->appStatus = status; +} + diff --git a/iipsrv/fcgi/libfcgi/libfcgi.mak b/iipsrv/fcgi/libfcgi/libfcgi.mak new file mode 100644 index 0000000..1aab410 --- /dev/null +++ b/iipsrv/fcgi/libfcgi/libfcgi.mak @@ -0,0 +1,311 @@ +# Microsoft Developer Studio Generated NMAKE File, Based on libfcgi.dsp + +!IF "$(CFG)" == "" +CFG=release +!ENDIF + +!IF "$(CFG)" != "release" && "$(CFG)" != "debug" +!MESSAGE Invalid configuration "$(CFG)" specified. +!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 "libfcgi.mak" CFG="debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "release" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE "debug" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE +!ERROR An invalid configuration is specified. +!ENDIF + +!IF "$(OS)" == "Windows_NT" +NULL= +!ELSE +NULL=nul +!ENDIF + +!IF "$(CFG)" == "release" + +OUTDIR=.\..\libfcgi\Release +INTDIR=.\..\libfcgi\Release +# Begin Custom Macros +OutDir=.\..\libfcgi\Release +# End Custom Macros + +ALL : "$(OUTDIR)\libfcgi.dll" + + +CLEAN : + -@erase "$(INTDIR)\fcgi_stdio.obj" + -@erase "$(INTDIR)\fcgiapp.obj" + -@erase "$(INTDIR)\fcgio.obj" + -@erase "$(INTDIR)\os_win32.obj" + -@erase "$(INTDIR)\vc60.idb" + -@erase "$(OUTDIR)\libfcgi.dll" + -@erase "$(OUTDIR)\libfcgi.exp" + -@erase "$(OUTDIR)\libfcgi.lib" + +"$(OUTDIR)" : + if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)" + +CPP=cl.exe +CPP_PROJ=/nologo /MD /W3 /O2 /Ob2 /I "..\include" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /Fp"$(INTDIR)\libfcgi.pch" /YX /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\\" /FD /c + +.c{$(INTDIR)}.obj:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.cpp{$(INTDIR)}.obj:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.cxx{$(INTDIR)}.obj:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.c{$(INTDIR)}.sbr:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.cpp{$(INTDIR)}.sbr:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.cxx{$(INTDIR)}.sbr:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +MTL=midl.exe +MTL_PROJ=/nologo /D "NDEBUG" /mktyplib203 /win32 +RSC=rc.exe +BSC32=bscmake.exe +BSC32_FLAGS=/nologo /o"$(OUTDIR)\libfcgi.bsc" +BSC32_SBRS= \ + +LINK32=link.exe +LINK32_FLAGS=Ws2_32.lib /nologo /dll /pdb:none /machine:I386 /out:"$(OUTDIR)\libfcgi.dll" /implib:"$(OUTDIR)\libfcgi.lib" +LINK32_OBJS= \ + "$(INTDIR)\fcgi_stdio.obj" \ + "$(INTDIR)\fcgiapp.obj" \ + "$(INTDIR)\fcgio.obj" \ + "$(INTDIR)\os_win32.obj" + +"$(OUTDIR)\libfcgi.dll" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS) + $(LINK32) @<< + $(LINK32_FLAGS) $(LINK32_OBJS) +<< + +!ELSEIF "$(CFG)" == "debug" + +OUTDIR=.\..\libfcgi\Debug +INTDIR=.\..\libfcgi\Debug +# Begin Custom Macros +OutDir=.\..\libfcgi\Debug +# End Custom Macros + +ALL : "$(OUTDIR)\libfcgi.dll" "$(OUTDIR)\libfcgi.bsc" + + +CLEAN : + -@erase "$(INTDIR)\fcgi_stdio.obj" + -@erase "$(INTDIR)\fcgi_stdio.sbr" + -@erase "$(INTDIR)\fcgiapp.obj" + -@erase "$(INTDIR)\fcgiapp.sbr" + -@erase "$(INTDIR)\fcgio.obj" + -@erase "$(INTDIR)\fcgio.sbr" + -@erase "$(INTDIR)\os_win32.obj" + -@erase "$(INTDIR)\os_win32.sbr" + -@erase "$(INTDIR)\vc60.idb" + -@erase "$(INTDIR)\vc60.pdb" + -@erase "$(OUTDIR)\libfcgi.bsc" + -@erase "$(OUTDIR)\libfcgi.dll" + -@erase "$(OUTDIR)\libfcgi.exp" + -@erase "$(OUTDIR)\libfcgi.lib" + -@erase "$(OUTDIR)\libfcgi.map" + +"$(OUTDIR)" : + if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)" + +CPP=cl.exe +CPP_PROJ=/nologo /MDd /W4 /Gm /Gi /ZI /Od /I "..\include" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /FR"$(INTDIR)\\" /Fp"$(INTDIR)\libfcgi.pch" /YX /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\\" /FD /GZ /c + +.c{$(INTDIR)}.obj:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.cpp{$(INTDIR)}.obj:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.cxx{$(INTDIR)}.obj:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.c{$(INTDIR)}.sbr:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.cpp{$(INTDIR)}.sbr:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.cxx{$(INTDIR)}.sbr:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +MTL=midl.exe +MTL_PROJ=/nologo /D "_DEBUG" /mktyplib203 /win32 +RSC=rc.exe +BSC32=bscmake.exe +BSC32_FLAGS=/nologo /o"$(OUTDIR)\libfcgi.bsc" +BSC32_SBRS= \ + "$(INTDIR)\fcgi_stdio.sbr" \ + "$(INTDIR)\fcgiapp.sbr" \ + "$(INTDIR)\fcgio.sbr" \ + "$(INTDIR)\os_win32.sbr" + +"$(OUTDIR)\libfcgi.bsc" : "$(OUTDIR)" $(BSC32_SBRS) + $(BSC32) @<< + $(BSC32_FLAGS) $(BSC32_SBRS) +<< + +LINK32=link.exe +LINK32_FLAGS=Ws2_32.lib /nologo /dll /profile /map:"$(INTDIR)\libfcgi.map" /debug /machine:I386 /out:"$(OUTDIR)\libfcgi.dll" /implib:"$(OUTDIR)\libfcgi.lib" +LINK32_OBJS= \ + "$(INTDIR)\fcgi_stdio.obj" \ + "$(INTDIR)\fcgiapp.obj" \ + "$(INTDIR)\fcgio.obj" \ + "$(INTDIR)\os_win32.obj" + +"$(OUTDIR)\libfcgi.dll" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS) + $(LINK32) @<< + $(LINK32_FLAGS) $(LINK32_OBJS) +<< + +!ENDIF + + +..\libfcgi\fcgi_stdio.c : \ + "..\include\fcgi_config.h"\ + "..\include\fcgi_stdio.h"\ + "..\include\fcgiapp.h"\ + "..\include\fcgimisc.h"\ + "..\include\fcgios.h"\ + + +..\libfcgi\fcgiapp.c : \ + "..\include\fastcgi.h"\ + "..\include\fcgi_config.h"\ + "..\include\fcgiapp.h"\ + "..\include\fcgimisc.h"\ + "..\include\fcgios.h"\ + + +..\libfcgi\fcgio.cpp : \ + "..\include\fcgiapp.h"\ + "..\include\fcgio.h"\ + + +..\libfcgi\os_win32.c : \ + "..\include\fcgi_config.h"\ + "..\include\fcgimisc.h"\ + "..\include\fcgios.h"\ + + +!IF "$(CFG)" == "release" || "$(CFG)" == "debug" +SOURCE=..\libfcgi\fcgi_stdio.c + +!IF "$(CFG)" == "release" + + +"$(INTDIR)\fcgi_stdio.obj" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +!ELSEIF "$(CFG)" == "debug" + + +"$(INTDIR)\fcgi_stdio.obj" "$(INTDIR)\fcgi_stdio.sbr" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +!ENDIF + +SOURCE=..\libfcgi\fcgiapp.c + +!IF "$(CFG)" == "release" + + +"$(INTDIR)\fcgiapp.obj" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +!ELSEIF "$(CFG)" == "debug" + + +"$(INTDIR)\fcgiapp.obj" "$(INTDIR)\fcgiapp.sbr" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +!ENDIF + +SOURCE=..\libfcgi\fcgio.cpp + +!IF "$(CFG)" == "release" + +CPP_SWITCHES=/nologo /MD /W3 /GX /O2 /Ob2 /I "..\include" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /Fp"$(INTDIR)\libfcgi.pch" /YX /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\\" /FD /c + +"$(INTDIR)\fcgio.obj" : $(SOURCE) "$(INTDIR)" + $(CPP) @<< + $(CPP_SWITCHES) $(SOURCE) +<< + + +!ELSEIF "$(CFG)" == "debug" + +CPP_SWITCHES=/nologo /MDd /W3 /Gm /Gi /GX /ZI /Od /I "..\include" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /FR"$(INTDIR)\\" /Fp"$(INTDIR)\libfcgi.pch" /YX /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\\" /FD /GZ /c + +"$(INTDIR)\fcgio.obj" "$(INTDIR)\fcgio.sbr" : $(SOURCE) "$(INTDIR)" + $(CPP) @<< + $(CPP_SWITCHES) $(SOURCE) +<< + + +!ENDIF + +SOURCE=..\libfcgi\os_unix.c +SOURCE=..\libfcgi\os_win32.c + +!IF "$(CFG)" == "release" + + +"$(INTDIR)\os_win32.obj" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +!ELSEIF "$(CFG)" == "debug" + + +"$(INTDIR)\os_win32.obj" "$(INTDIR)\os_win32.sbr" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +!ENDIF + +SOURCE=..\libfcgi\strerror.c + +!ENDIF + diff --git a/iipsrv/fcgi/libfcgi/os_unix.c b/iipsrv/fcgi/libfcgi/os_unix.c new file mode 100644 index 0000000..73e6a7f --- /dev/null +++ b/iipsrv/fcgi/libfcgi/os_unix.c @@ -0,0 +1,1293 @@ +/* + * os_unix.c -- + * + * Description of file. + * + * + * Copyright (c) 1995 Open Market, Inc. + * All rights reserved. + * + * This file contains proprietary and confidential information and + * remains the unpublished property of Open Market, Inc. Use, + * disclosure, or reproduction is prohibited except as permitted by + * express written license agreement with Open Market, Inc. + * + * Bill Snapper + * snapper@openmarket.com + */ + +#ifndef lint +static const char rcsid[] = "$Id: os_unix.c,v 1.37 2002/03/05 19:14:49 robs Exp $"; +#endif /* not lint */ + +#include "fcgi_config.h" + +#include + +#ifdef HAVE_NETINET_IN_H +#include +#endif + +#include +#include +#include +#include /* for fcntl */ +#include +#include /* for memchr() */ +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef HAVE_NETDB_H +#include +#endif + +#ifdef HAVE_SYS_SOCKET_H +#include /* for getpeername */ +#endif + +#ifdef HAVE_UNISTD_H +#include +#endif + +#include "fastcgi.h" +#include "fcgimisc.h" +#include "fcgios.h" + +#ifndef INADDR_NONE +#define INADDR_NONE ((unsigned long) -1) +#endif + +/* + * This structure holds an entry for each oustanding async I/O operation. + */ +typedef struct { + OS_AsyncProc procPtr; /* callout completion procedure */ + ClientData clientData; /* caller private data */ + int fd; + int len; + int offset; + void *buf; + int inUse; +} AioInfo; + +/* + * Entries in the async I/O table are allocated 2 per file descriptor. + * + * Read Entry Index = fd * 2 + * Write Entry Index = (fd * 2) + 1 + */ +#define AIO_RD_IX(fd) (fd * 2) +#define AIO_WR_IX(fd) ((fd * 2) + 1) + +static int asyncIoInUse = FALSE; +static int asyncIoTableSize = 16; +static AioInfo *asyncIoTable = NULL; + +static int libInitialized = FALSE; + +static fd_set readFdSet; +static fd_set writeFdSet; + +static fd_set readFdSetPost; +static int numRdPosted = 0; +static fd_set writeFdSetPost; +static int numWrPosted = 0; +static int volatile maxFd = -1; + +static int shutdownPending = FALSE; +static int shutdownNow = FALSE; + +void OS_ShutdownPending() +{ + shutdownPending = TRUE; +} + +static void OS_Sigusr1Handler(int signo) +{ + OS_ShutdownPending(); +} + +static void OS_SigpipeHandler(int signo) +{ + ; +} + +static void installSignalHandler(int signo, const struct sigaction * act, int force) +{ + struct sigaction sa; + + sigaction(signo, NULL, &sa); + + if (force || sa.sa_handler == SIG_DFL) + { + sigaction(signo, act, NULL); + } +} + +static void OS_InstallSignalHandlers(int force) +{ + struct sigaction sa; + + sigemptyset(&sa.sa_mask); + sa.sa_flags = 0; + + sa.sa_handler = OS_SigpipeHandler; + installSignalHandler(SIGPIPE, &sa, force); + + sa.sa_handler = OS_Sigusr1Handler; + installSignalHandler(SIGUSR1, &sa, force); +} + +/* + *-------------------------------------------------------------- + * + * OS_LibInit -- + * + * Set up the OS library for use. + * + * NOTE: This function is really only needed for application + * asynchronous I/O. It will most likely change in the + * future to setup the multi-threaded environment. + * + * Results: + * Returns 0 if success, -1 if not. + * + * Side effects: + * Async I/O table allocated and initialized. + * + *-------------------------------------------------------------- + */ +int OS_LibInit(int stdioFds[3]) +{ + if(libInitialized) + return 0; + + asyncIoTable = (AioInfo *)malloc(asyncIoTableSize * sizeof(AioInfo)); + if(asyncIoTable == NULL) { + errno = ENOMEM; + return -1; + } + memset((char *) asyncIoTable, 0, + asyncIoTableSize * sizeof(AioInfo)); + + FD_ZERO(&readFdSet); + FD_ZERO(&writeFdSet); + FD_ZERO(&readFdSetPost); + FD_ZERO(&writeFdSetPost); + + OS_InstallSignalHandlers(FALSE); + + libInitialized = TRUE; + + return 0; +} + +/* + *-------------------------------------------------------------- + * + * OS_LibShutdown -- + * + * Shutdown the OS library. + * + * Results: + * None. + * + * Side effects: + * Memory freed, fds closed. + * + *-------------------------------------------------------------- + */ +void OS_LibShutdown() +{ + if(!libInitialized) + return; + + free(asyncIoTable); + asyncIoTable = NULL; + libInitialized = FALSE; + return; +} + +/* + *---------------------------------------------------------------------- + * + * OS_BuildSockAddrUn -- + * + * Using the pathname bindPath, fill in the sockaddr_un structure + * *servAddrPtr and the length of this structure *servAddrLen. + * + * The format of the sockaddr_un structure changed incompatibly in + * 4.3BSD Reno. Digital UNIX supports both formats, other systems + * support one or the other. + * + * Results: + * 0 for normal return, -1 for failure (bindPath too long). + * + *---------------------------------------------------------------------- + */ + +static int OS_BuildSockAddrUn(const char *bindPath, + struct sockaddr_un *servAddrPtr, + int *servAddrLen) +{ + int bindPathLen = strlen(bindPath); + +#ifdef HAVE_SOCKADDR_UN_SUN_LEN /* 4.3BSD Reno and later: BSDI, DEC */ + if(bindPathLen >= sizeof(servAddrPtr->sun_path)) { + return -1; + } +#else /* 4.3 BSD Tahoe: Solaris, HPUX, DEC, ... */ + if(bindPathLen > sizeof(servAddrPtr->sun_path)) { + return -1; + } +#endif + memset((char *) servAddrPtr, 0, sizeof(*servAddrPtr)); + servAddrPtr->sun_family = AF_UNIX; + memcpy(servAddrPtr->sun_path, bindPath, bindPathLen); +#ifdef HAVE_SOCKADDR_UN_SUN_LEN /* 4.3BSD Reno and later: BSDI, DEC */ + *servAddrLen = sizeof(servAddrPtr->sun_len) + + sizeof(servAddrPtr->sun_family) + + bindPathLen + 1; + servAddrPtr->sun_len = *servAddrLen; +#else /* 4.3 BSD Tahoe: Solaris, HPUX, DEC, ... */ + *servAddrLen = sizeof(servAddrPtr->sun_family) + bindPathLen; +#endif + return 0; +} +union SockAddrUnion { + struct sockaddr_un unixVariant; + struct sockaddr_in inetVariant; +}; + +/* + * OS_CreateLocalIpcFd -- + * + * This procedure is responsible for creating the listener socket + * on Unix for local process communication. It will create a + * domain socket or a TCP/IP socket bound to "localhost" and return + * a file descriptor to it to the caller. + * + * Results: + * Listener socket created. This call returns either a valid + * file descriptor or -1 on error. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ +int OS_CreateLocalIpcFd(const char *bindPath, int backlog) +{ + int listenSock, servLen; + union SockAddrUnion sa; + int tcp = FALSE; + unsigned long tcp_ia = 0; + char *tp; + short port = 0; + char host[MAXPATHLEN]; + + strcpy(host, bindPath); + if((tp = strchr(host, ':')) != 0) { + *tp++ = 0; + if((port = atoi(tp)) == 0) { + *--tp = ':'; + } else { + tcp = TRUE; + } + } + if(tcp) { + if (!*host || !strcmp(host,"*")) { + tcp_ia = htonl(INADDR_ANY); + } else { + tcp_ia = inet_addr(host); + if (tcp_ia == INADDR_NONE) { + struct hostent * hep; + hep = gethostbyname(host); + if ((!hep) || (hep->h_addrtype != AF_INET || !hep->h_addr_list[0])) { + fprintf(stderr, "Cannot resolve host name %s -- exiting!\n", host); + exit(1); + } + if (hep->h_addr_list[1]) { + fprintf(stderr, "Host %s has multiple addresses ---\n", host); + fprintf(stderr, "you must choose one explicitly!!!\n"); + exit(1); + } + tcp_ia = ((struct in_addr *) (hep->h_addr))->s_addr; + } + } + } + + if(tcp) { + listenSock = socket(AF_INET, SOCK_STREAM, 0); + if(listenSock >= 0) { + int flag = 1; + if(setsockopt(listenSock, SOL_SOCKET, SO_REUSEADDR, + (char *) &flag, sizeof(flag)) < 0) { + fprintf(stderr, "Can't set SO_REUSEADDR.\n"); + exit(1001); + } + } + } else { + listenSock = socket(AF_UNIX, SOCK_STREAM, 0); + } + if(listenSock < 0) { + return -1; + } + + /* + * Bind the listening socket. + */ + if(tcp) { + memset((char *) &sa.inetVariant, 0, sizeof(sa.inetVariant)); + sa.inetVariant.sin_family = AF_INET; + sa.inetVariant.sin_addr.s_addr = tcp_ia; + sa.inetVariant.sin_port = htons(port); + servLen = sizeof(sa.inetVariant); + } else { + unlink(bindPath); + if(OS_BuildSockAddrUn(bindPath, &sa.unixVariant, &servLen)) { + fprintf(stderr, "Listening socket's path name is too long.\n"); + exit(1000); + } + } + if(bind(listenSock, (struct sockaddr *) &sa.unixVariant, servLen) < 0 + || listen(listenSock, backlog) < 0) { + perror("bind/listen"); + exit(errno); + } + + return listenSock; +} + +/* + *---------------------------------------------------------------------- + * + * OS_FcgiConnect -- + * + * Create the socket and connect to the remote application if + * possible. + * + * This was lifted from the cgi-fcgi application and was abstracted + * out because Windows NT does not have a domain socket and must + * use a named pipe which has a different API altogether. + * + * Results: + * -1 if fail or a valid file descriptor if connection succeeds. + * + * Side effects: + * Remote connection established. + * + *---------------------------------------------------------------------- + */ +int OS_FcgiConnect(char *bindPath) +{ + union SockAddrUnion sa; + int servLen, resultSock; + int connectStatus; + char *tp; + char host[MAXPATHLEN]; + short port = 0; + int tcp = FALSE; + + strcpy(host, bindPath); + if((tp = strchr(host, ':')) != 0) { + *tp++ = 0; + if((port = atoi(tp)) == 0) { + *--tp = ':'; + } else { + tcp = TRUE; + } + } + if(tcp == TRUE) { + struct hostent *hp; + if((hp = gethostbyname((*host ? host : "localhost"))) == NULL) { + fprintf(stderr, "Unknown host: %s\n", bindPath); + exit(1000); + } + sa.inetVariant.sin_family = AF_INET; + memcpy(&sa.inetVariant.sin_addr, hp->h_addr, hp->h_length); + sa.inetVariant.sin_port = htons(port); + servLen = sizeof(sa.inetVariant); + resultSock = socket(AF_INET, SOCK_STREAM, 0); + } else { + if(OS_BuildSockAddrUn(bindPath, &sa.unixVariant, &servLen)) { + fprintf(stderr, "Listening socket's path name is too long.\n"); + exit(1000); + } + resultSock = socket(AF_UNIX, SOCK_STREAM, 0); + } + + ASSERT(resultSock >= 0); + connectStatus = connect(resultSock, (struct sockaddr *) &sa.unixVariant, + servLen); + if(connectStatus >= 0) { + return resultSock; + } else { + /* + * Most likely (errno == ENOENT || errno == ECONNREFUSED) + * and no FCGI application server is running. + */ + close(resultSock); + return -1; + } +} + +/* + *-------------------------------------------------------------- + * + * OS_Read -- + * + * Pass through to the unix read function. + * + * Results: + * Returns number of byes read, 0, or -1 failure: errno + * contains actual error. + * + * Side effects: + * None. + * + *-------------------------------------------------------------- + */ +int OS_Read(int fd, char * buf, size_t len) +{ + if (shutdownNow) return -1; + return(read(fd, buf, len)); +} + +/* + *-------------------------------------------------------------- + * + * OS_Write -- + * + * Pass through to unix write function. + * + * Results: + * Returns number of byes read, 0, or -1 failure: errno + * contains actual error. + * + * Side effects: + * none. + * + *-------------------------------------------------------------- + */ +int OS_Write(int fd, char * buf, size_t len) +{ + if (shutdownNow) return -1; + return(write(fd, buf, len)); +} + +/* + *---------------------------------------------------------------------- + * + * OS_SpawnChild -- + * + * Spawns a new FastCGI listener process. + * + * Results: + * 0 if success, -1 if error. + * + * Side effects: + * Child process spawned. + * + *---------------------------------------------------------------------- + */ +int OS_SpawnChild(char *appPath, int listenFd) +{ + int forkResult; + + forkResult = fork(); + if(forkResult < 0) { + exit(errno); + } + + if(forkResult == 0) { + /* + * Close STDIN unconditionally. It's used by the parent + * process for CGI communication. The FastCGI applciation + * will be replacing this with the FastCGI listenFd IF + * STDIN_FILENO is the same as FCGI_LISTENSOCK_FILENO + * (which it is on Unix). Regardless, STDIN, STDOUT, and + * STDERR will be closed as the FastCGI process uses a + * multiplexed socket in their place. + */ + close(STDIN_FILENO); + + /* + * If the listenFd is already the value of FCGI_LISTENSOCK_FILENO + * we're set. If not, change it so the child knows where to + * get the listen socket from. + */ + if(listenFd != FCGI_LISTENSOCK_FILENO) { + dup2(listenFd, FCGI_LISTENSOCK_FILENO); + close(listenFd); + } + + close(STDOUT_FILENO); + close(STDERR_FILENO); + + /* + * We're a child. Exec the application. + * + * XXX: entire environment passes through + */ + execl(appPath, appPath, NULL); + /* + * XXX: Can't do this as we've already closed STDERR!!! + * + * perror("exec"); + */ + exit(errno); + } + return 0; +} + +/* + *-------------------------------------------------------------- + * + * OS_AsyncReadStdin -- + * + * This initiates an asynchronous read on the standard + * input handle. + * + * The abstraction is necessary because Windows NT does not + * have a clean way of "select"ing a file descriptor for + * I/O. + * + * Results: + * -1 if error, 0 otherwise. + * + * Side effects: + * Asynchronous bit is set in the readfd variable and + * request is enqueued. + * + *-------------------------------------------------------------- + */ +int OS_AsyncReadStdin(void *buf, int len, OS_AsyncProc procPtr, + ClientData clientData) +{ + int index = AIO_RD_IX(STDIN_FILENO); + + asyncIoInUse = TRUE; + ASSERT(asyncIoTable[index].inUse == 0); + asyncIoTable[index].procPtr = procPtr; + asyncIoTable[index].clientData = clientData; + asyncIoTable[index].fd = STDIN_FILENO; + asyncIoTable[index].len = len; + asyncIoTable[index].offset = 0; + asyncIoTable[index].buf = buf; + asyncIoTable[index].inUse = 1; + FD_SET(STDIN_FILENO, &readFdSet); + if(STDIN_FILENO > maxFd) + maxFd = STDIN_FILENO; + return 0; +} + +static void GrowAsyncTable(void) +{ + int oldTableSize = asyncIoTableSize; + + asyncIoTableSize = asyncIoTableSize * 2; + asyncIoTable = (AioInfo *)realloc(asyncIoTable, asyncIoTableSize * sizeof(AioInfo)); + if(asyncIoTable == NULL) { + errno = ENOMEM; + exit(errno); + } + memset((char *) &asyncIoTable[oldTableSize], 0, + oldTableSize * sizeof(AioInfo)); + +} + +/* + *-------------------------------------------------------------- + * + * OS_AsyncRead -- + * + * This initiates an asynchronous read on the file + * handle which may be a socket or named pipe. + * + * We also must save the ProcPtr and ClientData, so later + * when the io completes, we know who to call. + * + * We don't look at any results here (the ReadFile may + * return data if it is cached) but do all completion + * processing in OS_Select when we get the io completion + * port done notifications. Then we call the callback. + * + * Results: + * -1 if error, 0 otherwise. + * + * Side effects: + * Asynchronous I/O operation is queued for completion. + * + *-------------------------------------------------------------- + */ +int OS_AsyncRead(int fd, int offset, void *buf, int len, + OS_AsyncProc procPtr, ClientData clientData) +{ + int index = AIO_RD_IX(fd); + + ASSERT(asyncIoTable != NULL); + asyncIoInUse = TRUE; + + if(fd > maxFd) + maxFd = fd; + + while (index >= asyncIoTableSize) { + GrowAsyncTable(); + } + + ASSERT(asyncIoTable[index].inUse == 0); + asyncIoTable[index].procPtr = procPtr; + asyncIoTable[index].clientData = clientData; + asyncIoTable[index].fd = fd; + asyncIoTable[index].len = len; + asyncIoTable[index].offset = offset; + asyncIoTable[index].buf = buf; + asyncIoTable[index].inUse = 1; + FD_SET(fd, &readFdSet); + return 0; +} + +/* + *-------------------------------------------------------------- + * + * OS_AsyncWrite -- + * + * This initiates an asynchronous write on the "fake" file + * descriptor (which may be a file, socket, or named pipe). + * We also must save the ProcPtr and ClientData, so later + * when the io completes, we know who to call. + * + * We don't look at any results here (the WriteFile generally + * completes immediately) but do all completion processing + * in OS_DoIo when we get the io completion port done + * notifications. Then we call the callback. + * + * Results: + * -1 if error, 0 otherwise. + * + * Side effects: + * Asynchronous I/O operation is queued for completion. + * + *-------------------------------------------------------------- + */ +int OS_AsyncWrite(int fd, int offset, void *buf, int len, + OS_AsyncProc procPtr, ClientData clientData) +{ + int index = AIO_WR_IX(fd); + + asyncIoInUse = TRUE; + + if(fd > maxFd) + maxFd = fd; + + while (index >= asyncIoTableSize) { + GrowAsyncTable(); + } + + ASSERT(asyncIoTable[index].inUse == 0); + asyncIoTable[index].procPtr = procPtr; + asyncIoTable[index].clientData = clientData; + asyncIoTable[index].fd = fd; + asyncIoTable[index].len = len; + asyncIoTable[index].offset = offset; + asyncIoTable[index].buf = buf; + asyncIoTable[index].inUse = 1; + FD_SET(fd, &writeFdSet); + return 0; +} + +/* + *-------------------------------------------------------------- + * + * OS_Close -- + * + * Closes the descriptor. This is a pass through to the + * Unix close. + * + * Results: + * 0 for success, -1 on failure + * + * Side effects: + * None. + * + *-------------------------------------------------------------- + */ +int OS_Close(int fd) +{ + if (fd == -1) + return 0; + + if (asyncIoInUse) { + int index = AIO_RD_IX(fd); + + FD_CLR(fd, &readFdSet); + FD_CLR(fd, &readFdSetPost); + if (asyncIoTable[index].inUse != 0) { + asyncIoTable[index].inUse = 0; + } + + FD_CLR(fd, &writeFdSet); + FD_CLR(fd, &writeFdSetPost); + index = AIO_WR_IX(fd); + if (asyncIoTable[index].inUse != 0) { + asyncIoTable[index].inUse = 0; + } + + if (maxFd == fd) { + maxFd--; + } + } + + /* + * shutdown() the send side and then read() from client until EOF + * or a timeout expires. This is done to minimize the potential + * that a TCP RST will be sent by our TCP stack in response to + * receipt of additional data from the client. The RST would + * cause the client to discard potentially useful response data. + */ + + if (shutdown(fd, 1) == 0) + { + struct timeval tv; + fd_set rfds; + int rv; + char trash[1024]; + + FD_ZERO(&rfds); + + do + { + FD_SET(fd, &rfds); + tv.tv_sec = 2; + tv.tv_usec = 0; + rv = select(fd + 1, &rfds, NULL, NULL, &tv); + } + while (rv > 0 && read(fd, trash, sizeof(trash)) > 0); + } + + return close(fd); +} + +/* + *-------------------------------------------------------------- + * + * OS_CloseRead -- + * + * Cancel outstanding asynchronous reads and prevent subsequent + * reads from completing. + * + * Results: + * Socket or file is shutdown. Return values mimic Unix shutdown: + * 0 success, -1 failure + * + *-------------------------------------------------------------- + */ +int OS_CloseRead(int fd) +{ + if(asyncIoTable[AIO_RD_IX(fd)].inUse != 0) { + asyncIoTable[AIO_RD_IX(fd)].inUse = 0; + FD_CLR(fd, &readFdSet); + } + + return shutdown(fd, 0); +} + +/* + *-------------------------------------------------------------- + * + * OS_DoIo -- + * + * This function was formerly OS_Select. It's purpose is + * to pull I/O completion events off the queue and dispatch + * them to the appropriate place. + * + * Results: + * Returns 0. + * + * Side effects: + * Handlers are called. + * + *-------------------------------------------------------------- + */ +int OS_DoIo(struct timeval *tmo) +{ + int fd, len, selectStatus; + OS_AsyncProc procPtr; + ClientData clientData; + AioInfo *aioPtr; + fd_set readFdSetCpy; + fd_set writeFdSetCpy; + + asyncIoInUse = TRUE; + FD_ZERO(&readFdSetCpy); + FD_ZERO(&writeFdSetCpy); + + for(fd = 0; fd <= maxFd; fd++) { + if(FD_ISSET(fd, &readFdSet)) { + FD_SET(fd, &readFdSetCpy); + } + if(FD_ISSET(fd, &writeFdSet)) { + FD_SET(fd, &writeFdSetCpy); + } + } + + /* + * If there were no completed events from a prior call, see if there's + * any work to do. + */ + if(numRdPosted == 0 && numWrPosted == 0) { + selectStatus = select((maxFd+1), &readFdSetCpy, &writeFdSetCpy, + NULL, tmo); + if(selectStatus < 0) { + exit(errno); + } + + for(fd = 0; fd <= maxFd; fd++) { + /* + * Build up a list of completed events. We'll work off of + * this list as opposed to looping through the read and write + * fd sets since they can be affected by a callbacl routine. + */ + if(FD_ISSET(fd, &readFdSetCpy)) { + numRdPosted++; + FD_SET(fd, &readFdSetPost); + FD_CLR(fd, &readFdSet); + } + + if(FD_ISSET(fd, &writeFdSetCpy)) { + numWrPosted++; + FD_SET(fd, &writeFdSetPost); + FD_CLR(fd, &writeFdSet); + } + } + } + + if(numRdPosted == 0 && numWrPosted == 0) + return 0; + + for(fd = 0; fd <= maxFd; fd++) { + /* + * Do reads and dispatch callback. + */ + if(FD_ISSET(fd, &readFdSetPost) + && asyncIoTable[AIO_RD_IX(fd)].inUse) { + + numRdPosted--; + FD_CLR(fd, &readFdSetPost); + aioPtr = &asyncIoTable[AIO_RD_IX(fd)]; + + len = read(aioPtr->fd, aioPtr->buf, aioPtr->len); + + procPtr = aioPtr->procPtr; + aioPtr->procPtr = NULL; + clientData = aioPtr->clientData; + aioPtr->inUse = 0; + + (*procPtr)(clientData, len); + } + + /* + * Do writes and dispatch callback. + */ + if(FD_ISSET(fd, &writeFdSetPost) && + asyncIoTable[AIO_WR_IX(fd)].inUse) { + + numWrPosted--; + FD_CLR(fd, &writeFdSetPost); + aioPtr = &asyncIoTable[AIO_WR_IX(fd)]; + + len = write(aioPtr->fd, aioPtr->buf, aioPtr->len); + + procPtr = aioPtr->procPtr; + aioPtr->procPtr = NULL; + clientData = aioPtr->clientData; + aioPtr->inUse = 0; + (*procPtr)(clientData, len); + } + } + return 0; +} + +/* + * Not all systems have strdup(). + * @@@ autoconf should determine whether or not this is needed, but for now.. + */ +static char * str_dup(const char * str) +{ + char * sdup = (char *) malloc(strlen(str) + 1); + + if (sdup) + strcpy(sdup, str); + + return sdup; +} + +/* + *---------------------------------------------------------------------- + * + * ClientAddrOK -- + * + * Checks if a client address is in a list of allowed addresses + * + * Results: + * TRUE if address list is empty or client address is present + * in the list, FALSE otherwise. + * + *---------------------------------------------------------------------- + */ +static int ClientAddrOK(struct sockaddr_in *saPtr, const char *clientList) +{ + int result = FALSE; + char *clientListCopy, *cur, *next; + + if (clientList == NULL || *clientList == '\0') { + return TRUE; + } + + clientListCopy = str_dup(clientList); + + for (cur = clientListCopy; cur != NULL; cur = next) { + next = strchr(cur, ','); + if (next != NULL) { + *next++ = '\0'; + } + if (inet_addr(cur) == saPtr->sin_addr.s_addr) { + result = TRUE; + break; + } + } + + free(clientListCopy); + return result; +} + +/* + *---------------------------------------------------------------------- + * + * AcquireLock -- + * + * On platforms that implement concurrent calls to accept + * on a shared listening ipcFd, returns 0. On other platforms, + * acquires an exclusive lock across all processes sharing a + * listening ipcFd, blocking until the lock has been acquired. + * + * Results: + * 0 for successful call, -1 in case of system error (fatal). + * + * Side effects: + * This process now has the exclusive lock. + * + *---------------------------------------------------------------------- + */ +static int AcquireLock(int sock, int fail_on_intr) +{ +#ifdef USE_LOCKING + do { + struct flock lock; + lock.l_type = F_WRLCK; + lock.l_start = 0; + lock.l_whence = SEEK_SET; + lock.l_len = 0; + + if (fcntl(sock, F_SETLKW, &lock) != -1) + return 0; + } while (errno == EINTR + && ! fail_on_intr + && ! shutdownPending); + + return -1; + +#else + return 0; +#endif +} + +/* + *---------------------------------------------------------------------- + * + * ReleaseLock -- + * + * On platforms that implement concurrent calls to accept + * on a shared listening ipcFd, does nothing. On other platforms, + * releases an exclusive lock acquired by AcquireLock. + * + * Results: + * 0 for successful call, -1 in case of system error (fatal). + * + * Side effects: + * This process no longer holds the lock. + * + *---------------------------------------------------------------------- + */ +static int ReleaseLock(int sock) +{ +#ifdef USE_LOCKING + do { + struct flock lock; + lock.l_type = F_UNLCK; + lock.l_start = 0; + lock.l_whence = SEEK_SET; + lock.l_len = 0; + + if (fcntl(sock, F_SETLK, &lock) != -1) + return 0; + } while (errno == EINTR); + + return -1; + +#else + return 0; +#endif +} + +/********************************************************************** + * Determine if the errno resulting from a failed accept() warrants a + * retry or exit(). Based on Apache's http_main.c accept() handling + * and Stevens' Unix Network Programming Vol 1, 2nd Ed, para. 15.6. + */ +static int is_reasonable_accept_errno (const int error) +{ + switch (error) { +#ifdef EPROTO + /* EPROTO on certain older kernels really means ECONNABORTED, so + * we need to ignore it for them. See discussion in new-httpd + * archives nh.9701 search for EPROTO. Also see nh.9603, search + * for EPROTO: There is potentially a bug in Solaris 2.x x<6, and + * other boxes that implement tcp sockets in userland (i.e. on top of + * STREAMS). On these systems, EPROTO can actually result in a fatal + * loop. See PR#981 for example. It's hard to handle both uses of + * EPROTO. */ + case EPROTO: +#endif +#ifdef ECONNABORTED + case ECONNABORTED: +#endif + /* Linux generates the rest of these, other tcp stacks (i.e. + * bsd) tend to hide them behind getsockopt() interfaces. They + * occur when the net goes sour or the client disconnects after the + * three-way handshake has been done in the kernel but before + * userland has picked up the socket. */ +#ifdef ECONNRESET + case ECONNRESET: +#endif +#ifdef ETIMEDOUT + case ETIMEDOUT: +#endif +#ifdef EHOSTUNREACH + case EHOSTUNREACH: +#endif +#ifdef ENETUNREACH + case ENETUNREACH: +#endif + return 1; + + default: + return 0; + } +} + +/********************************************************************** + * This works around a problem on Linux 2.0.x and SCO Unixware (maybe + * others?). When a connect() is made to a Unix Domain socket, but its + * not accept()ed before the web server gets impatient and close()s, an + * accept() results in a valid file descriptor, but no data to read. + * This causes a block on the first read() - which never returns! + * + * Another approach to this is to write() to the socket to provoke a + * SIGPIPE, but this is a pain because of the FastCGI protocol, the fact + * that whatever is written has to be universally ignored by all FastCGI + * web servers, and a SIGPIPE handler has to be installed which returns + * (or SIGPIPE is ignored). + * + * READABLE_UNIX_FD_DROP_DEAD_TIMEVAL = 2,0 by default. + * + * Making it shorter is probably safe, but I'll leave that to you. Making + * it 0,0 doesn't work reliably. The shorter you can reliably make it, + * the faster your application will be able to recover (waiting 2 seconds + * may _cause_ the problem when there is a very high demand). At any rate, + * this is better than perma-blocking. + */ +static int is_af_unix_keeper(const int fd) +{ + struct timeval tval = { READABLE_UNIX_FD_DROP_DEAD_TIMEVAL }; + fd_set read_fds; + + FD_ZERO(&read_fds); + FD_SET(fd, &read_fds); + + return select(fd + 1, &read_fds, NULL, NULL, &tval) >= 0 && FD_ISSET(fd, &read_fds); +} + +/* + *---------------------------------------------------------------------- + * + * OS_Accept -- + * + * Accepts a new FastCGI connection. This routine knows whether + * we're dealing with TCP based sockets or NT Named Pipes for IPC. + * + * Results: + * -1 if the operation fails, otherwise this is a valid IPC fd. + * + * Side effects: + * New IPC connection is accepted. + * + *---------------------------------------------------------------------- + */ +int OS_Accept(int listen_sock, int fail_on_intr, const char *webServerAddrs) +{ + int socket = -1; + union { + struct sockaddr_un un; + struct sockaddr_in in; + } sa; + + for (;;) { + if (AcquireLock(listen_sock, fail_on_intr)) + return -1; + + for (;;) { + do { +#ifdef HAVE_SOCKLEN + socklen_t len = sizeof(sa); +#else + int len = sizeof(sa); +#endif + if (shutdownPending) break; + /* There's a window here */ + + socket = accept(listen_sock, (struct sockaddr *)&sa, &len); + } while (socket < 0 + && errno == EINTR + && ! fail_on_intr + && ! shutdownPending); + + if (socket < 0) { + if (shutdownPending || ! is_reasonable_accept_errno(errno)) { + int errnoSave = errno; + + ReleaseLock(listen_sock); + + if (! shutdownPending) { + errno = errnoSave; + } + + return (-1); + } + errno = 0; + } + else { /* socket >= 0 */ + int set = 1; + + if (sa.in.sin_family != AF_INET) + break; + +#ifdef TCP_NODELAY + /* No replies to outgoing data, so disable Nagle */ + setsockopt(socket, IPPROTO_TCP, TCP_NODELAY, (char *)&set, sizeof(set)); +#endif + + /* Check that the client IP address is approved */ + if (ClientAddrOK(&sa.in, webServerAddrs)) + break; + + close(socket); + } /* socket >= 0 */ + } /* for(;;) */ + + if (ReleaseLock(listen_sock)) + return (-1); + + if (sa.in.sin_family != AF_UNIX || is_af_unix_keeper(socket)) + break; + + close(socket); + } /* while(1) - lock */ + + return (socket); +} + +/* + *---------------------------------------------------------------------- + * + * OS_IpcClose + * + * OS IPC routine to close an IPC connection. + * + * Results: + * + * + * Side effects: + * IPC connection is closed. + * + *---------------------------------------------------------------------- + */ +int OS_IpcClose(int ipcFd) +{ + return OS_Close(ipcFd); +} + +/* + *---------------------------------------------------------------------- + * + * OS_IsFcgi -- + * + * Determines whether this process is a FastCGI process or not. + * + * Results: + * Returns 1 if FastCGI, 0 if not. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ +int OS_IsFcgi(int sock) +{ + union { + struct sockaddr_in in; + struct sockaddr_un un; + } sa; +#ifdef HAVE_SOCKLEN + socklen_t len = sizeof(sa); +#else + int len = sizeof(sa); +#endif + + errno = 0; + + if (getpeername(sock, (struct sockaddr *)&sa, &len) != 0 && errno == ENOTCONN) { + return TRUE; + } + else { + return FALSE; + } +} + +/* + *---------------------------------------------------------------------- + * + * OS_SetFlags -- + * + * Sets selected flag bits in an open file descriptor. + * + *---------------------------------------------------------------------- + */ +void OS_SetFlags(int fd, int flags) +{ + int val; + if((val = fcntl(fd, F_GETFL, 0)) < 0) { + exit(errno); + } + val |= flags; + if(fcntl(fd, F_SETFL, val) < 0) { + exit(errno); + } +} diff --git a/iipsrv/fcgi/libfcgi/os_win32.c b/iipsrv/fcgi/libfcgi/os_win32.c new file mode 100644 index 0000000..294b17f --- /dev/null +++ b/iipsrv/fcgi/libfcgi/os_win32.c @@ -0,0 +1,1887 @@ +/* + * os_win32.c -- + * + * + * Copyright (c) 1995 Open Market, Inc. + * All rights reserved. + * + * This file contains proprietary and confidential information and + * remains the unpublished property of Open Market, Inc. Use, + * disclosure, or reproduction is prohibited except as permitted by + * express written license agreement with Open Market, Inc. + * + * Bill Snapper + * snapper@openmarket.com + * + * (Special thanks to Karen and Bill. They made my job much easier and + * significantly more enjoyable.) + */ +#ifndef lint +static const char rcsid[] = "$Id: os_win32.c,v 1.33 2002/03/05 18:15:15 robs Exp $"; +#endif /* not lint */ + +#define WIN32_LEAN_AND_MEAN +#include +#include +#include +#include +#include +#include +#include + +#define DLLAPI __declspec(dllexport) + +#include "fcgimisc.h" +#include "fcgios.h" + +#define WIN32_OPEN_MAX 128 /* XXX: Small hack */ + +/* + * millisecs to wait for a client connection before checking the + * shutdown flag (then go back to waiting for a connection, etc). + */ +#define ACCEPT_TIMEOUT 1000 + +#define MUTEX_VARNAME "_FCGI_MUTEX_" +#define SHUTDOWN_EVENT_NAME "_FCGI_SHUTDOWN_EVENT_" +#define LOCALHOST "localhost" + +static HANDLE hIoCompPort = INVALID_HANDLE_VALUE; +static HANDLE hStdinCompPort = INVALID_HANDLE_VALUE; +static HANDLE hStdinThread = INVALID_HANDLE_VALUE; + +static HANDLE stdioHandles[3] = {INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE, + INVALID_HANDLE_VALUE}; + +// This is a nail for listening to more than one port.. +static HANDLE acceptMutex = INVALID_HANDLE_VALUE; + +static BOOLEAN shutdownPending = FALSE; +static BOOLEAN shutdownNow = FALSE; + +/* + * An enumeration of the file types + * supported by the FD_TABLE structure. + * + * XXX: Not all currently supported. This allows for future + * functionality. + */ +typedef enum { + FD_UNUSED, + FD_FILE_SYNC, + FD_FILE_ASYNC, + FD_SOCKET_SYNC, + FD_SOCKET_ASYNC, + FD_PIPE_SYNC, + FD_PIPE_ASYNC +} FILE_TYPE; + +typedef union { + HANDLE fileHandle; + SOCKET sock; + unsigned int value; +} DESCRIPTOR; + +/* + * Structure used to map file handle and socket handle + * values into values that can be used to create unix-like + * select bitmaps, read/write for both sockets/files. + */ +struct FD_TABLE { + DESCRIPTOR fid; + FILE_TYPE type; + char *path; + DWORD Errno; + unsigned long instance; + int status; + int offset; /* only valid for async file writes */ + LPDWORD offsetHighPtr; /* pointers to offset high and low words */ + LPDWORD offsetLowPtr; /* only valid for async file writes (logs) */ + HANDLE hMapMutex; /* mutex handle for multi-proc offset update */ + LPVOID ovList; /* List of associated OVERLAPPED_REQUESTs */ +}; + +/* + * XXX Note there is no dyanmic sizing of this table, so if the + * number of open file descriptors exceeds WIN32_OPEN_MAX the + * app will blow up. + */ +static struct FD_TABLE fdTable[WIN32_OPEN_MAX]; + +static CRITICAL_SECTION fdTableCritical; + +struct OVERLAPPED_REQUEST { + OVERLAPPED overlapped; + unsigned long instance; /* file instance (won't match after a close) */ + OS_AsyncProc procPtr; /* callback routine */ + ClientData clientData; /* callback argument */ + ClientData clientData1; /* additional clientData */ +}; +typedef struct OVERLAPPED_REQUEST *POVERLAPPED_REQUEST; + +static const char *bindPathPrefix = "\\\\.\\pipe\\FastCGI\\"; + +static FILE_TYPE listenType = FD_UNUSED; + +// XXX This should be a DESCRIPTOR +static HANDLE hListen = INVALID_HANDLE_VALUE; + +static BOOLEAN libInitialized = FALSE; + +/* + *-------------------------------------------------------------- + * + * Win32NewDescriptor -- + * + * Set up for I/O descriptor masquerading. + * + * Results: + * Returns "fake id" which masquerades as a UNIX-style "small + * non-negative integer" file/socket descriptor. + * Win32_* routine below will "do the right thing" based on the + * descriptor's actual type. -1 indicates failure. + * + * Side effects: + * Entry in fdTable is reserved to represent the socket/file. + * + *-------------------------------------------------------------- + */ +static int Win32NewDescriptor(FILE_TYPE type, int fd, int desiredFd) +{ + int index = -1; + + EnterCriticalSection(&fdTableCritical); + + /* + * If desiredFd is set, try to get this entry (this is used for + * mapping stdio handles). Otherwise try to get the fd entry. + * If this is not available, find a the first empty slot. . + */ + if (desiredFd >= 0 && desiredFd < WIN32_OPEN_MAX) + { + if (fdTable[desiredFd].type == FD_UNUSED) + { + index = desiredFd; + } + } + else if (fd > 0) + { + if (fd < WIN32_OPEN_MAX && fdTable[fd].type == FD_UNUSED) + { + index = fd; + } + else + { + int i; + + for (i = 1; i < WIN32_OPEN_MAX; ++i) + { + if (fdTable[i].type == FD_UNUSED) + { + index = i; + break; + } + } + } + } + + if (index != -1) + { + fdTable[index].fid.value = fd; + fdTable[index].type = type; + fdTable[index].path = NULL; + fdTable[index].Errno = NO_ERROR; + fdTable[index].status = 0; + fdTable[index].offset = -1; + fdTable[index].offsetHighPtr = fdTable[index].offsetLowPtr = NULL; + fdTable[index].hMapMutex = NULL; + fdTable[index].ovList = NULL; + } + + LeaveCriticalSection(&fdTableCritical); + return index; +} + +/* + *-------------------------------------------------------------- + * + * StdinThread-- + * + * This thread performs I/O on stadard input. It is needed + * because you can't guarantee that all applications will + * create standard input with sufficient access to perform + * asynchronous I/O. Since we don't want to block the app + * reading from stdin we make it look like it's using I/O + * completion ports to perform async I/O. + * + * Results: + * Data is read from stdin and posted to the io completion + * port. + * + * Side effects: + * None. + * + *-------------------------------------------------------------- + */ +static void StdinThread(void * startup) +{ + int doIo = TRUE; + unsigned long fd; + unsigned long bytesRead; + POVERLAPPED_REQUEST pOv; + + // Touch the arg to prevent warning + startup = NULL; + + while(doIo) { + /* + * Block until a request to read from stdin comes in or a + * request to terminate the thread arrives (fd = -1). + */ + if (!GetQueuedCompletionStatus(hStdinCompPort, &bytesRead, &fd, + (LPOVERLAPPED *)&pOv, (DWORD)-1) && !pOv) { + doIo = 0; + break; + } + + ASSERT((fd == STDIN_FILENO) || (fd == -1)); + if(fd == -1) { + doIo = 0; + break; + } + ASSERT(pOv->clientData1 != NULL); + + if(ReadFile(stdioHandles[STDIN_FILENO], pOv->clientData1, bytesRead, + &bytesRead, NULL)) { + PostQueuedCompletionStatus(hIoCompPort, bytesRead, + STDIN_FILENO, (LPOVERLAPPED)pOv); + } else { + doIo = 0; + break; + } + } + + ExitThread(0); +} + +void OS_ShutdownPending(void) +{ + shutdownPending = TRUE; +} + +static void ShutdownRequestThread(void * arg) +{ + HANDLE shutdownEvent = (HANDLE) arg; + + WaitForSingleObject(shutdownEvent, INFINITE); + + shutdownPending = TRUE; + + if (listenType == FD_PIPE_SYNC) + { + // Its a hassle to get ConnectNamedPipe to return early, + // so just wack the whole process - yes, this will toast + // any requests in progress, but at least its a clean + // shutdown (its better than TerminateProcess()) + exit(0); + } + + // FD_SOCKET_SYNC: When in Accept(), select() is used to poll + // the shutdownPending flag - yeah this isn't pretty either + // but its only one process doing it if an Accept mutex is used. + // This at least buys no toasted requests. +} + +/* + *-------------------------------------------------------------- + * + * OS_LibInit -- + * + * Set up the OS library for use. + * + * Results: + * Returns 0 if success, -1 if not. + * + * Side effects: + * Sockets initialized, pseudo file descriptors setup, etc. + * + *-------------------------------------------------------------- + */ +int OS_LibInit(int stdioFds[3]) +{ + WORD wVersion; + WSADATA wsaData; + int err; + int fakeFd; + char *cLenPtr = NULL; + char *val = NULL; + + if(libInitialized) + return 0; + + InitializeCriticalSection(&fdTableCritical); + + /* + * Initialize windows sockets library. + */ + wVersion = MAKEWORD(2,0); + err = WSAStartup( wVersion, &wsaData ); + if (err) { + fprintf(stderr, "Error starting Windows Sockets. Error: %d", + WSAGetLastError()); + exit(111); + } + + /* + * Create the I/O completion port to be used for our I/O queue. + */ + if (hIoCompPort == INVALID_HANDLE_VALUE) { + hIoCompPort = CreateIoCompletionPort (INVALID_HANDLE_VALUE, NULL, + 0, 1); + if(hIoCompPort == INVALID_HANDLE_VALUE) { + printf("

OS_LibInit Failed CreateIoCompletionPort! ERROR: %d

\r\n\r\n", + GetLastError()); + return -1; + } + } + + /* + * If a shutdown event is in the env, save it (I don't see any to + * remove it from the environment out from under the application). + * Spawn a thread to wait on the shutdown request. + */ + val = getenv(SHUTDOWN_EVENT_NAME); + if (val != NULL) + { + HANDLE shutdownEvent = (HANDLE) atoi(val); + + if (_beginthread(ShutdownRequestThread, 0, shutdownEvent) == -1) + { + return -1; + } + } + + if (acceptMutex == INVALID_HANDLE_VALUE) + { + /* If an accept mutex is in the env, use it */ + val = getenv(MUTEX_VARNAME); + if (val != NULL) + { + acceptMutex = (HANDLE) atoi(val); + } + } + + /* + * Determine if this library is being used to listen for FastCGI + * connections. This is communicated by STDIN containing a + * valid handle to a listener object. In this case, both the + * "stdout" and "stderr" handles will be INVALID (ie. closed) by + * the starting process. + * + * The trick is determining if this is a pipe or a socket... + * + * XXX: Add the async accept test to determine socket or handle to a + * pipe!!! + */ + if((GetStdHandle(STD_OUTPUT_HANDLE) == INVALID_HANDLE_VALUE) && + (GetStdHandle(STD_ERROR_HANDLE) == INVALID_HANDLE_VALUE) && + (GetStdHandle(STD_INPUT_HANDLE) != INVALID_HANDLE_VALUE) ) + { + DWORD pipeMode = PIPE_READMODE_BYTE | PIPE_WAIT; + HANDLE oldStdIn = GetStdHandle(STD_INPUT_HANDLE); + + // Move the handle to a "low" number + if (! DuplicateHandle(GetCurrentProcess(), oldStdIn, + GetCurrentProcess(), &hListen, + 0, TRUE, DUPLICATE_SAME_ACCESS)) + { + return -1; + } + + if (! SetStdHandle(STD_INPUT_HANDLE, hListen)) + { + return -1; + } + + CloseHandle(oldStdIn); + + /* + * Set the pipe handle state so that it operates in wait mode. + * + * NOTE: The listenFd is not mapped to a pseudo file descriptor + * as all work done on it is contained to the OS library. + * + * XXX: Initial assumption is that SetNamedPipeHandleState will + * fail if this is an IP socket... + */ + if (SetNamedPipeHandleState(hListen, &pipeMode, NULL, NULL)) + { + listenType = FD_PIPE_SYNC; + } + else + { + listenType = FD_SOCKET_SYNC; + } + } + + /* + * If there are no stdioFds passed in, we're done. + */ + if(stdioFds == NULL) { + libInitialized = 1; + return 0; + } + + /* + * Setup standard input asynchronous I/O. There is actually a separate + * thread spawned for this purpose. The reason for this is that some + * web servers use anonymous pipes for the connection between itself + * and a CGI application. Anonymous pipes can't perform asynchronous + * I/O or use I/O completion ports. Therefore in order to present a + * consistent I/O dispatch model to an application we emulate I/O + * completion port behavior by having the standard input thread posting + * messages to the hIoCompPort which look like a complete overlapped + * I/O structure. This keeps the event dispatching simple from the + * application perspective. + */ + stdioHandles[STDIN_FILENO] = GetStdHandle(STD_INPUT_HANDLE); + + if(!SetHandleInformation(stdioHandles[STDIN_FILENO], + HANDLE_FLAG_INHERIT, 0)) { +/* + * XXX: Causes error when run from command line. Check KB + err = GetLastError(); + DebugBreak(); + exit(99); + */ + } + + if ((fakeFd = Win32NewDescriptor(FD_PIPE_SYNC, + (int)stdioHandles[STDIN_FILENO], + STDIN_FILENO)) == -1) { + return -1; + } else { + /* + * Set stdin equal to our pseudo FD and create the I/O completion + * port to be used for async I/O. + */ + stdioFds[STDIN_FILENO] = fakeFd; + } + + /* + * Create the I/O completion port to be used for communicating with + * the thread doing I/O on standard in. This port will carry read + * and possibly thread termination requests to the StdinThread. + */ + if (hStdinCompPort == INVALID_HANDLE_VALUE) { + hStdinCompPort = CreateIoCompletionPort (INVALID_HANDLE_VALUE, NULL, + 0, 1); + if(hStdinCompPort == INVALID_HANDLE_VALUE) { + printf("

OS_LibInit Failed CreateIoCompletionPort: STDIN! ERROR: %d

\r\n\r\n", + GetLastError()); + return -1; + } + } + + /* + * Create the thread that will read stdin if the CONTENT_LENGTH + * is non-zero. + */ + if((cLenPtr = getenv("CONTENT_LENGTH")) != NULL && + atoi(cLenPtr) > 0) { + hStdinThread = (HANDLE) _beginthread(StdinThread, 0, NULL); + if (hStdinThread == (HANDLE) -1) { + printf("

OS_LibInit Failed to create STDIN thread! ERROR: %d

\r\n\r\n", + GetLastError()); + return -1; + } + } + + /* + * STDOUT will be used synchronously. + * + * XXX: May want to convert this so that it could be used for OVERLAPPED + * I/O later. If so, model it after the Stdin I/O as stdout is + * also incapable of async I/O on some servers. + */ + stdioHandles[STDOUT_FILENO] = GetStdHandle(STD_OUTPUT_HANDLE); + if(!SetHandleInformation(stdioHandles[STDOUT_FILENO], + HANDLE_FLAG_INHERIT, FALSE)) { + DebugBreak(); + exit(99); + } + + if ((fakeFd = Win32NewDescriptor(FD_PIPE_SYNC, + (int)stdioHandles[STDOUT_FILENO], + STDOUT_FILENO)) == -1) { + return -1; + } else { + /* + * Set stdout equal to our pseudo FD + */ + stdioFds[STDOUT_FILENO] = fakeFd; + } + + stdioHandles[STDERR_FILENO] = GetStdHandle(STD_ERROR_HANDLE); + if(!SetHandleInformation(stdioHandles[STDERR_FILENO], + HANDLE_FLAG_INHERIT, FALSE)) { + DebugBreak(); + exit(99); + } + if ((fakeFd = Win32NewDescriptor(FD_PIPE_SYNC, + (int)stdioHandles[STDERR_FILENO], + STDERR_FILENO)) == -1) { + return -1; + } else { + /* + * Set stderr equal to our pseudo FD + */ + stdioFds[STDERR_FILENO] = fakeFd; + } + + return 0; +} + +/* + *-------------------------------------------------------------- + * + * OS_LibShutdown -- + * + * Shutdown the OS library. + * + * Results: + * None. + * + * Side effects: + * Memory freed, handles closed. + * + *-------------------------------------------------------------- + */ +void OS_LibShutdown() +{ + + if (hIoCompPort != INVALID_HANDLE_VALUE) + { + CloseHandle(hIoCompPort); + hIoCompPort = INVALID_HANDLE_VALUE; + } + + if (hStdinCompPort != INVALID_HANDLE_VALUE) + { + CloseHandle(hStdinCompPort); + hStdinCompPort = INVALID_HANDLE_VALUE; + } + + if (acceptMutex != INVALID_HANDLE_VALUE) + { + ReleaseMutex(acceptMutex); + } + + DisconnectNamedPipe(hListen); + + CancelIo(hListen); + + + WSACleanup(); +} + +/* + *-------------------------------------------------------------- + * + * Win32FreeDescriptor -- + * + * Free I/O descriptor entry in fdTable. + * + * Results: + * Frees I/O descriptor entry in fdTable. + * + * Side effects: + * None. + * + *-------------------------------------------------------------- + */ +static void Win32FreeDescriptor(int fd) +{ + /* Catch it if fd is a bogus value */ + ASSERT((fd >= 0) && (fd < WIN32_OPEN_MAX)); + + EnterCriticalSection(&fdTableCritical); + + if (fdTable[fd].type != FD_UNUSED) + { + switch (fdTable[fd].type) + { + case FD_FILE_SYNC: + case FD_FILE_ASYNC: + + /* Free file path string */ + ASSERT(fdTable[fd].path != NULL); + free(fdTable[fd].path); + fdTable[fd].path = NULL; + break; + + default: + break; + } + + ASSERT(fdTable[fd].path == NULL); + + fdTable[fd].type = FD_UNUSED; + fdTable[fd].path = NULL; + fdTable[fd].Errno = NO_ERROR; + fdTable[fd].offsetHighPtr = fdTable[fd].offsetLowPtr = NULL; + + if (fdTable[fd].hMapMutex != NULL) + { + CloseHandle(fdTable[fd].hMapMutex); + fdTable[fd].hMapMutex = NULL; + } + } + + LeaveCriticalSection(&fdTableCritical); + + return; +} + +static short getPort(const char * bindPath) +{ + short port = 0; + char * p = strchr(bindPath, ':'); + + if (p && *++p) + { + char buf[6]; + + strncpy(buf, p, 6); + buf[5] = '\0'; + + port = (short) atoi(buf); + } + + return port; +} + +/* + * OS_CreateLocalIpcFd -- + * + * This procedure is responsible for creating the listener pipe + * on Windows NT for local process communication. It will create a + * named pipe and return a file descriptor to it to the caller. + * + * Results: + * Listener pipe created. This call returns either a valid + * pseudo file descriptor or -1 on error. + * + * Side effects: + * Listener pipe and IPC address are stored in the FCGI info + * structure. + * 'errno' will set on errors (-1 is returned). + * + *---------------------------------------------------------------------- + */ +int OS_CreateLocalIpcFd(const char *bindPath, int backlog) +{ + int pseudoFd = -1; + short port = getPort(bindPath); + + if (acceptMutex == INVALID_HANDLE_VALUE) + { + acceptMutex = CreateMutex(NULL, FALSE, NULL); + if (acceptMutex == NULL) return -2; + if (! SetHandleInformation(acceptMutex, HANDLE_FLAG_INHERIT, TRUE)) return -3; + } + + // There's nothing to be gained (at the moment) by a shutdown Event + + if (port && *bindPath != ':' && strncmp(bindPath, LOCALHOST, strlen(LOCALHOST))) + { + fprintf(stderr, "To start a service on a TCP port can not " + "specify a host name.\n" + "You should either use \"localhost:\" or " + " just use \":.\"\n"); + exit(1); + } + + listenType = (port) ? FD_SOCKET_SYNC : FD_PIPE_ASYNC; + + if (port) + { + SOCKET listenSock; + struct sockaddr_in sockAddr; + int sockLen = sizeof(sockAddr); + + memset(&sockAddr, 0, sizeof(sockAddr)); + sockAddr.sin_family = AF_INET; + sockAddr.sin_addr.s_addr = htonl(INADDR_ANY); + sockAddr.sin_port = htons(port); + + listenSock = socket(AF_INET, SOCK_STREAM, 0); + if (listenSock == INVALID_SOCKET) + { + return -4; + } + + if (bind(listenSock, (struct sockaddr *) &sockAddr, sockLen) ) + { + return -12; + } + + if (listen(listenSock, backlog)) + { + return -5; + } + + pseudoFd = Win32NewDescriptor(listenType, listenSock, -1); + + if (pseudoFd == -1) + { + closesocket(listenSock); + return -6; + } + + hListen = (HANDLE) listenSock; + } + else + { + HANDLE hListenPipe = INVALID_HANDLE_VALUE; + char *pipePath = malloc(strlen(bindPathPrefix) + strlen(bindPath) + 1); + + if (! pipePath) + { + return -7; + } + + strcpy(pipePath, bindPathPrefix); + strcat(pipePath, bindPath); + + hListenPipe = CreateNamedPipe(pipePath, + PIPE_ACCESS_DUPLEX, + PIPE_TYPE_BYTE | PIPE_WAIT | PIPE_READMODE_BYTE, + PIPE_UNLIMITED_INSTANCES, + 4096, 4096, 0, NULL); + + free(pipePath); + + if (hListenPipe == INVALID_HANDLE_VALUE) + { + return -8; + } + + if (! SetHandleInformation(hListenPipe, HANDLE_FLAG_INHERIT, TRUE)) + { + return -9; + } + + pseudoFd = Win32NewDescriptor(listenType, (int) hListenPipe, -1); + + if (pseudoFd == -1) + { + CloseHandle(hListenPipe); + return -10; + } + + hListen = (HANDLE) hListenPipe; + } + + return pseudoFd; +} + +/* + *---------------------------------------------------------------------- + * + * OS_FcgiConnect -- + * + * Create the pipe pathname connect to the remote application if + * possible. + * + * Results: + * -1 if fail or a valid handle if connection succeeds. + * + * Side effects: + * Remote connection established. + * + *---------------------------------------------------------------------- + */ +int OS_FcgiConnect(char *bindPath) +{ + short port = getPort(bindPath); + int pseudoFd = -1; + + if (port) + { + struct hostent *hp; + char *host = NULL; + struct sockaddr_in sockAddr; + int sockLen = sizeof(sockAddr); + SOCKET sock; + + if (*bindPath != ':') + { + char * p = strchr(bindPath, ':'); + int len = p - bindPath + 1; + + host = malloc(len); + strncpy(host, bindPath, len); + host[len] = '\0'; + } + + hp = gethostbyname(host ? host : LOCALHOST); + + if (host) + { + free(host); + } + + if (hp == NULL) + { + fprintf(stderr, "Unknown host: %s\n", bindPath); + return -1; + } + + memset(&sockAddr, 0, sizeof(sockAddr)); + sockAddr.sin_family = AF_INET; + memcpy(&sockAddr.sin_addr, hp->h_addr, hp->h_length); + sockAddr.sin_port = htons(port); + + sock = socket(AF_INET, SOCK_STREAM, 0); + if (sock == INVALID_SOCKET) + { + return -1; + } + + if (! connect(sock, (struct sockaddr *) &sockAddr, sockLen)) + { + closesocket(sock); + return -1; + } + + pseudoFd = Win32NewDescriptor(FD_SOCKET_SYNC, sock, -1); + if (pseudoFd == -1) + { + closesocket(sock); + return -1; + } + } + else + { + char *pipePath = malloc(strlen(bindPathPrefix) + strlen(bindPath) + 1); + HANDLE hPipe; + + if (! pipePath) + { + return -1; + } + + strcpy(pipePath, bindPathPrefix); + strcat(pipePath, bindPath); + + hPipe = CreateFile(pipePath, + GENERIC_WRITE | GENERIC_READ, + FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, + OPEN_EXISTING, + FILE_FLAG_OVERLAPPED, + NULL); + + free(pipePath); + + if( hPipe == INVALID_HANDLE_VALUE) + { + return -1; + } + + pseudoFd = Win32NewDescriptor(FD_PIPE_ASYNC, (int) hPipe, -1); + + if (pseudoFd == -1) + { + CloseHandle(hPipe); + return -1; + } + + /* + * Set stdin equal to our pseudo FD and create the I/O completion + * port to be used for async I/O. + */ + if (! CreateIoCompletionPort(hPipe, hIoCompPort, pseudoFd, 1)) + { + Win32FreeDescriptor(pseudoFd); + CloseHandle(hPipe); + return -1; + } + } + + return pseudoFd; +} + +/* + *-------------------------------------------------------------- + * + * OS_Read -- + * + * Pass through to the appropriate NT read function. + * + * Results: + * Returns number of byes read. Mimics unix read:. + * n bytes read, 0 or -1 failure: errno contains actual error + * + * Side effects: + * None. + * + *-------------------------------------------------------------- + */ +int OS_Read(int fd, char * buf, size_t len) +{ + DWORD bytesRead; + int ret = -1; + + ASSERT((fd >= 0) && (fd < WIN32_OPEN_MAX)); + + if (shutdownNow) return -1; + + switch (fdTable[fd].type) + { + case FD_FILE_SYNC: + case FD_FILE_ASYNC: + case FD_PIPE_SYNC: + case FD_PIPE_ASYNC: + + if (ReadFile(fdTable[fd].fid.fileHandle, buf, len, &bytesRead, NULL)) + { + ret = bytesRead; + } + else + { + fdTable[fd].Errno = GetLastError(); + } + + break; + + case FD_SOCKET_SYNC: + case FD_SOCKET_ASYNC: + + ret = recv(fdTable[fd].fid.sock, buf, len, 0); + if (ret == SOCKET_ERROR) + { + fdTable[fd].Errno = WSAGetLastError(); + ret = -1; + } + + break; + + default: + + ASSERT(0); + } + + return ret; +} + +/* + *-------------------------------------------------------------- + * + * OS_Write -- + * + * Perform a synchronous OS write. + * + * Results: + * Returns number of bytes written. Mimics unix write: + * n bytes written, 0 or -1 failure (??? couldn't find man page). + * + * Side effects: + * none. + * + *-------------------------------------------------------------- + */ +int OS_Write(int fd, char * buf, size_t len) +{ + DWORD bytesWritten; + int ret = -1; + + ASSERT(fd >= 0 && fd < WIN32_OPEN_MAX); + + if (shutdownNow) return -1; + + switch (fdTable[fd].type) + { + case FD_FILE_SYNC: + case FD_FILE_ASYNC: + case FD_PIPE_SYNC: + case FD_PIPE_ASYNC: + + if (WriteFile(fdTable[fd].fid.fileHandle, buf, len, &bytesWritten, NULL)) + { + ret = bytesWritten; + } + else + { + fdTable[fd].Errno = GetLastError(); + } + + break; + + case FD_SOCKET_SYNC: + case FD_SOCKET_ASYNC: + + ret = send(fdTable[fd].fid.sock, buf, len, 0); + if (ret == SOCKET_ERROR) + { + fdTable[fd].Errno = WSAGetLastError(); + ret = -1; + } + + break; + + default: + + ASSERT(0); + } + + return ret; +} + +/* + *---------------------------------------------------------------------- + * + * OS_SpawnChild -- + * + * Spawns a new server listener process, and stores the information + * relating to the child in the supplied record. A wait handler is + * registered on the child's completion. This involves creating + * a process on NT and preparing a command line with the required + * state (currently a -childproc flag and the server socket to use + * for accepting connections). + * + * Results: + * 0 if success, -1 if error. + * + * Side effects: + * Child process spawned. + * + *---------------------------------------------------------------------- + */ +int OS_SpawnChild(char *execPath, int listenFd) +{ + STARTUPINFO StartupInfo; + PROCESS_INFORMATION pInfo; + BOOL success; + + memset((void *)&StartupInfo, 0, sizeof(STARTUPINFO)); + StartupInfo.cb = sizeof (STARTUPINFO); + StartupInfo.lpReserved = NULL; + StartupInfo.lpReserved2 = NULL; + StartupInfo.cbReserved2 = 0; + StartupInfo.lpDesktop = NULL; + + /* + * FastCGI on NT will set the listener pipe HANDLE in the stdin of + * the new process. The fact that there is a stdin and NULL handles + * for stdout and stderr tells the FastCGI process that this is a + * FastCGI process and not a CGI process. + */ + StartupInfo.dwFlags = STARTF_USESTDHANDLES; + /* + * XXX: Do I have to dup the handle before spawning the process or is + * it sufficient to use the handle as it's reference counted + * by NT anyway? + */ + StartupInfo.hStdInput = fdTable[listenFd].fid.fileHandle; + StartupInfo.hStdOutput = INVALID_HANDLE_VALUE; + StartupInfo.hStdError = INVALID_HANDLE_VALUE; + + /* + * Make the listener socket inheritable. + */ + success = SetHandleInformation(StartupInfo.hStdInput, HANDLE_FLAG_INHERIT, + TRUE); + if(!success) { + exit(99); + } + + /* + * XXX: Might want to apply some specific security attributes to the + * processes. + */ + success = CreateProcess(execPath, /* LPCSTR address of module name */ + NULL, /* LPCSTR address of command line */ + NULL, /* Process security attributes */ + NULL, /* Thread security attributes */ + TRUE, /* Inheritable Handes inherited. */ + 0, /* DWORD creation flags */ + NULL, /* Use parent environment block */ + NULL, /* Address of current directory name */ + &StartupInfo, /* Address of STARTUPINFO */ + &pInfo); /* Address of PROCESS_INFORMATION */ + if(success) { + return 0; + } else { + return -1; + } +} + +/* + *-------------------------------------------------------------- + * + * OS_AsyncReadStdin -- + * + * This initiates an asynchronous read on the standard + * input handle. This handle is not guaranteed to be + * capable of performing asynchronous I/O so we send a + * message to the StdinThread to do the synchronous read. + * + * Results: + * -1 if error, 0 otherwise. + * + * Side effects: + * Asynchronous message is queued to the StdinThread and an + * overlapped structure is allocated/initialized. + * + *-------------------------------------------------------------- + */ +int OS_AsyncReadStdin(void *buf, int len, OS_AsyncProc procPtr, + ClientData clientData) +{ + POVERLAPPED_REQUEST pOv; + + ASSERT(fdTable[STDIN_FILENO].type != FD_UNUSED); + + pOv = (POVERLAPPED_REQUEST)malloc(sizeof(struct OVERLAPPED_REQUEST)); + ASSERT(pOv); + memset((void *)pOv, 0, sizeof(struct OVERLAPPED_REQUEST)); + pOv->clientData1 = (ClientData)buf; + pOv->instance = fdTable[STDIN_FILENO].instance; + pOv->procPtr = procPtr; + pOv->clientData = clientData; + + PostQueuedCompletionStatus(hStdinCompPort, len, STDIN_FILENO, + (LPOVERLAPPED)pOv); + return 0; +} + +/* + *-------------------------------------------------------------- + * + * OS_AsyncRead -- + * + * This initiates an asynchronous read on the file + * handle which may be a socket or named pipe. + * + * We also must save the ProcPtr and ClientData, so later + * when the io completes, we know who to call. + * + * We don't look at any results here (the ReadFile may + * return data if it is cached) but do all completion + * processing in OS_Select when we get the io completion + * port done notifications. Then we call the callback. + * + * Results: + * -1 if error, 0 otherwise. + * + * Side effects: + * Asynchronous I/O operation is queued for completion. + * + *-------------------------------------------------------------- + */ +int OS_AsyncRead(int fd, int offset, void *buf, int len, + OS_AsyncProc procPtr, ClientData clientData) +{ + DWORD bytesRead; + POVERLAPPED_REQUEST pOv; + + /* + * Catch any bogus fd values + */ + ASSERT((fd >= 0) && (fd < WIN32_OPEN_MAX)); + /* + * Confirm that this is an async fd + */ + ASSERT(fdTable[fd].type != FD_UNUSED); + ASSERT(fdTable[fd].type != FD_FILE_SYNC); + ASSERT(fdTable[fd].type != FD_PIPE_SYNC); + ASSERT(fdTable[fd].type != FD_SOCKET_SYNC); + + pOv = (POVERLAPPED_REQUEST)malloc(sizeof(struct OVERLAPPED_REQUEST)); + ASSERT(pOv); + memset((void *)pOv, 0, sizeof(struct OVERLAPPED_REQUEST)); + /* + * Only file offsets should be non-zero, but make sure. + */ + if (fdTable[fd].type == FD_FILE_ASYNC) + if (fdTable[fd].offset >= 0) + pOv->overlapped.Offset = fdTable[fd].offset; + else + pOv->overlapped.Offset = offset; + pOv->instance = fdTable[fd].instance; + pOv->procPtr = procPtr; + pOv->clientData = clientData; + bytesRead = fd; + /* + * ReadFile returns: TRUE success, FALSE failure + */ + if (!ReadFile(fdTable[fd].fid.fileHandle, buf, len, &bytesRead, + (LPOVERLAPPED)pOv)) { + fdTable[fd].Errno = GetLastError(); + if(fdTable[fd].Errno == ERROR_NO_DATA || + fdTable[fd].Errno == ERROR_PIPE_NOT_CONNECTED) { + PostQueuedCompletionStatus(hIoCompPort, 0, fd, (LPOVERLAPPED)pOv); + return 0; + } + if(fdTable[fd].Errno != ERROR_IO_PENDING) { + PostQueuedCompletionStatus(hIoCompPort, 0, fd, (LPOVERLAPPED)pOv); + return -1; + } + fdTable[fd].Errno = 0; + } + return 0; +} + +/* + *-------------------------------------------------------------- + * + * OS_AsyncWrite -- + * + * This initiates an asynchronous write on the "fake" file + * descriptor (which may be a file, socket, or named pipe). + * We also must save the ProcPtr and ClientData, so later + * when the io completes, we know who to call. + * + * We don't look at any results here (the WriteFile generally + * completes immediately) but do all completion processing + * in OS_DoIo when we get the io completion port done + * notifications. Then we call the callback. + * + * Results: + * -1 if error, 0 otherwise. + * + * Side effects: + * Asynchronous I/O operation is queued for completion. + * + *-------------------------------------------------------------- + */ +int OS_AsyncWrite(int fd, int offset, void *buf, int len, + OS_AsyncProc procPtr, ClientData clientData) +{ + DWORD bytesWritten; + POVERLAPPED_REQUEST pOv; + + /* + * Catch any bogus fd values + */ + ASSERT((fd >= 0) && (fd < WIN32_OPEN_MAX)); + /* + * Confirm that this is an async fd + */ + ASSERT(fdTable[fd].type != FD_UNUSED); + ASSERT(fdTable[fd].type != FD_FILE_SYNC); + ASSERT(fdTable[fd].type != FD_PIPE_SYNC); + ASSERT(fdTable[fd].type != FD_SOCKET_SYNC); + + pOv = (POVERLAPPED_REQUEST)malloc(sizeof(struct OVERLAPPED_REQUEST)); + ASSERT(pOv); + memset((void *)pOv, 0, sizeof(struct OVERLAPPED_REQUEST)); + /* + * Only file offsets should be non-zero, but make sure. + */ + if (fdTable[fd].type == FD_FILE_ASYNC) + /* + * Only file opened via OS_AsyncWrite with + * O_APPEND will have an offset != -1. + */ + if (fdTable[fd].offset >= 0) + /* + * If the descriptor has a memory mapped file + * handle, take the offsets from there. + */ + if (fdTable[fd].hMapMutex != NULL) { + /* + * Wait infinitely; this *should* not cause problems. + */ + WaitForSingleObject(fdTable[fd].hMapMutex, INFINITE); + + /* + * Retrieve the shared offset values. + */ + pOv->overlapped.OffsetHigh = *(fdTable[fd].offsetHighPtr); + pOv->overlapped.Offset = *(fdTable[fd].offsetLowPtr); + + /* + * Update the shared offset values for the next write + */ + *(fdTable[fd].offsetHighPtr) += 0; /* XXX How do I handle overflow */ + *(fdTable[fd].offsetLowPtr) += len; + + ReleaseMutex(fdTable[fd].hMapMutex); + } else + pOv->overlapped.Offset = fdTable[fd].offset; + else + pOv->overlapped.Offset = offset; + pOv->instance = fdTable[fd].instance; + pOv->procPtr = procPtr; + pOv->clientData = clientData; + bytesWritten = fd; + /* + * WriteFile returns: TRUE success, FALSE failure + */ + if (!WriteFile(fdTable[fd].fid.fileHandle, buf, len, &bytesWritten, + (LPOVERLAPPED)pOv)) { + fdTable[fd].Errno = GetLastError(); + if(fdTable[fd].Errno != ERROR_IO_PENDING) { + PostQueuedCompletionStatus(hIoCompPort, 0, fd, (LPOVERLAPPED)pOv); + return -1; + } + fdTable[fd].Errno = 0; + } + if (fdTable[fd].offset >= 0) + fdTable[fd].offset += len; + return 0; +} + +/* + *-------------------------------------------------------------- + * + * OS_Close -- + * + * Closes the descriptor with routine appropriate for + * descriptor's type. + * + * Results: + * Socket or file is closed. Return values mimic Unix close: + * 0 success, -1 failure + * + * Side effects: + * Entry in fdTable is marked as free. + * + *-------------------------------------------------------------- + */ +int OS_Close(int fd) +{ + int ret = 0; + + /* + * Catch it if fd is a bogus value + */ + ASSERT((fd >= 0) && (fd < WIN32_OPEN_MAX)); + ASSERT(fdTable[fd].type != FD_UNUSED); + + switch (fdTable[fd].type) { + case FD_PIPE_SYNC: + case FD_PIPE_ASYNC: + case FD_FILE_SYNC: + case FD_FILE_ASYNC: + + break; + + case FD_SOCKET_SYNC: + case FD_SOCKET_ASYNC: + + /* + * shutdown() the send side and then read() from client until EOF + * or a timeout expires. This is done to minimize the potential + * that a TCP RST will be sent by our TCP stack in response to + * receipt of additional data from the client. The RST would + * cause the client to discard potentially useful response data. + */ + + if (shutdown(fdTable[fd].fid.sock, SD_SEND) == 0) + { + struct timeval tv; + fd_set rfds; + int sock = fdTable[fd].fid.sock; + int rv; + char trash[1024]; + + FD_ZERO(&rfds); + + do + { + FD_SET(sock, &rfds); + tv.tv_sec = 2; + tv.tv_usec = 0; + rv = select(sock + 1, &rfds, NULL, NULL, &tv); + } + while (rv > 0 && recv(sock, trash, sizeof(trash), 0) > 0); + } + + closesocket(fdTable[fd].fid.sock); + + break; + + default: + + ret = -1; /* fake failure */ + } + + Win32FreeDescriptor(fd); + return ret; +} + +/* + *-------------------------------------------------------------- + * + * OS_CloseRead -- + * + * Cancel outstanding asynchronous reads and prevent subsequent + * reads from completing. + * + * Results: + * Socket or file is shutdown. Return values mimic Unix shutdown: + * 0 success, -1 failure + * + *-------------------------------------------------------------- + */ +int OS_CloseRead(int fd) +{ + int ret = 0; + + /* + * Catch it if fd is a bogus value + */ + ASSERT((fd >= 0) && (fd < WIN32_OPEN_MAX)); + ASSERT(fdTable[fd].type == FD_SOCKET_ASYNC + || fdTable[fd].type == FD_SOCKET_SYNC); + + if (shutdown(fdTable[fd].fid.sock,0) == SOCKET_ERROR) + ret = -1; + return ret; +} + +/* + *-------------------------------------------------------------- + * + * OS_DoIo -- + * + * This function was formerly OS_Select. It's purpose is + * to pull I/O completion events off the queue and dispatch + * them to the appropriate place. + * + * Results: + * Returns 0. + * + * Side effects: + * Handlers are called. + * + *-------------------------------------------------------------- + */ +int OS_DoIo(struct timeval *tmo) +{ + unsigned long fd; + unsigned long bytes; + POVERLAPPED_REQUEST pOv; + struct timeb tb; + int ms; + int ms_last; + int err; + + /* XXX + * We can loop in here, but not too long, as wait handlers + * must run. + * For cgi stdin, apparently select returns when io completion + * ports don't, so don't wait the full timeout. + */ + if(tmo) + ms = (tmo->tv_sec*1000 + tmo->tv_usec/1000) / 2; + else + ms = 1000; + ftime(&tb); + ms_last = tb.time*1000 + tb.millitm; + while (ms >= 0) { + if(tmo && (ms = tmo->tv_sec*1000 + tmo->tv_usec/1000)> 100) + ms = 100; + if (!GetQueuedCompletionStatus(hIoCompPort, &bytes, &fd, + (LPOVERLAPPED *)&pOv, ms) && !pOv) { + err = WSAGetLastError(); + return 0; /* timeout */ + } + + ASSERT((fd >= 0) && (fd < WIN32_OPEN_MAX)); + /* call callback if descriptor still valid */ + ASSERT(pOv); + if(pOv->instance == fdTable[fd].instance) + (*pOv->procPtr)(pOv->clientData, bytes); + free(pOv); + + ftime(&tb); + ms -= (tb.time*1000 + tb.millitm - ms_last); + ms_last = tb.time*1000 + tb.millitm; + } + return 0; +} + +static int isAddrOK(struct sockaddr_in * inet_sockaddr, const char * okAddrs) +{ + static const char *token = " ,;:\t"; + char *ipaddr; + char *p; + + if (okAddrs == NULL) return TRUE; + + ipaddr = inet_ntoa(inet_sockaddr->sin_addr); + p = strstr(okAddrs, ipaddr); + + if (p == NULL) return FALSE; + + if (p == okAddrs) + { + p += strlen(ipaddr); + return (strchr(token, *p) != NULL); + } + + if (strchr(token, *--p) != NULL) + { + p += strlen(ipaddr) + 1; + return (strchr(token, *p) != NULL); + } + + return FALSE; +} + +#ifndef NO_WSAACEPT +static int CALLBACK isAddrOKCallback(LPWSABUF lpCallerId, + LPWSABUF dc0, + LPQOS dc1, + LPQOS dc2, + LPWSABUF dc3, + LPWSABUF dc4, + GROUP *dc5, + DWORD data) +{ + struct sockaddr_in *sockaddr = (struct sockaddr_in *) lpCallerId->buf; + + // Touch the args to avoid warnings + dc0 = NULL; dc1 = NULL; dc2 = NULL; dc3 = NULL; dc4 = NULL; dc5 = NULL; + + if ((void *) data == NULL) return CF_ACCEPT; + + if (sockaddr->sin_family != AF_INET) return CF_ACCEPT; + + return isAddrOK(sockaddr, (const char *) data) ? CF_ACCEPT : CF_REJECT; +} +#endif + +static void printLastError(const char * text) +{ + LPVOID buf; + + FormatMessage( + FORMAT_MESSAGE_ALLOCATE_BUFFER | + FORMAT_MESSAGE_FROM_SYSTEM | + FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, + GetLastError(), + 0, + (LPTSTR) &buf, + 0, + NULL + ); + + fprintf(stderr, "%s: %s\n", text, (LPCTSTR) buf); + LocalFree(buf); +} + +static int acceptNamedPipe() +{ + int ipcFd = -1; + + if (! ConnectNamedPipe(hListen, NULL)) + { + switch (GetLastError()) + { + case ERROR_PIPE_CONNECTED: + + // A client connected after CreateNamedPipe but + // before ConnectNamedPipe. Its a good connection. + + break; + + case ERROR_IO_PENDING: + + // The NamedPipe was opened with an Overlapped structure + // and there is a pending io operation. mod_fastcgi + // did this in 2.2.12 (fcgi_pm.c v1.52). + + case ERROR_PIPE_LISTENING: + + // The pipe handle is in nonblocking mode. + + case ERROR_NO_DATA: + + // The previous client closed its handle (and we failed + // to call DisconnectNamedPipe) + + default: + + printLastError("unexpected ConnectNamedPipe() error"); + } + } + + ipcFd = Win32NewDescriptor(FD_PIPE_SYNC, (int) hListen, -1); + if (ipcFd == -1) + { + DisconnectNamedPipe(hListen); + } + + return ipcFd; +} + +static int acceptSocket(const char *webServerAddrs) +{ + SOCKET hSock; + int ipcFd = -1; + + for (;;) + { + struct sockaddr sockaddr; + int sockaddrLen = sizeof(sockaddr); + + for (;;) + { + const struct timeval timeout = {1, 0}; + fd_set readfds; + + FD_ZERO(&readfds); + +#pragma warning( disable : 4127 ) + FD_SET((unsigned int) hListen, &readfds); +#pragma warning( default : 4127 ) + + if (select(0, &readfds, NULL, NULL, &timeout) == 0) + { + if (shutdownPending) + { + OS_LibShutdown(); + return -1; + } + } + else + { + break; + } + } + +#if NO_WSAACEPT + hSock = accept((SOCKET) hListen, &sockaddr, &sockaddrLen); + + if (hSock == INVALID_SOCKET) + { + break; + } + + if (isAddrOK((struct sockaddr_in *) &sockaddr, webServerAddrs)) + { + break; + } + + closesocket(hSock); +#else + hSock = WSAAccept((unsigned int) hListen, + &sockaddr, + &sockaddrLen, + isAddrOKCallback, + (DWORD) webServerAddrs); + + if (hSock != INVALID_SOCKET) + { + break; + } + + if (WSAGetLastError() != WSAECONNREFUSED) + { + break; + } +#endif + } + + if (hSock == INVALID_SOCKET) + { + /* Use FormatMessage() */ + fprintf(stderr, "accept()/WSAAccept() failed: %d", WSAGetLastError()); + return -1; + } + + ipcFd = Win32NewDescriptor(FD_SOCKET_SYNC, hSock, -1); + if (ipcFd == -1) + { + closesocket(hSock); + } + + return ipcFd; +} + +/* + *---------------------------------------------------------------------- + * + * OS_Accept -- + * + * Accepts a new FastCGI connection. This routine knows whether + * we're dealing with TCP based sockets or NT Named Pipes for IPC. + * + * fail_on_intr is ignored in the Win lib. + * + * Results: + * -1 if the operation fails, otherwise this is a valid IPC fd. + * + *---------------------------------------------------------------------- + */ +int OS_Accept(int listen_sock, int fail_on_intr, const char *webServerAddrs) +{ + int ipcFd = -1; + + // Touch args to prevent warnings + listen_sock = 0; fail_on_intr = 0; + + // @todo Muliple listen sockets and sockets other than 0 are not + // supported due to the use of globals. + + if (shutdownPending) + { + OS_LibShutdown(); + return -1; + } + + // The mutex is to keep other processes (and threads, when supported) + // from going into the accept cycle. The accept cycle needs to + // periodically break out to check the state of the shutdown flag + // and there's no point to having more than one thread do that. + + if (acceptMutex != INVALID_HANDLE_VALUE) + { + if (WaitForSingleObject(acceptMutex, INFINITE) == WAIT_FAILED) + { + printLastError("WaitForSingleObject() failed"); + return -1; + } + } + + if (shutdownPending) + { + OS_LibShutdown(); + } + else if (listenType == FD_PIPE_SYNC) + { + ipcFd = acceptNamedPipe(); + } + else if (listenType == FD_SOCKET_SYNC) + { + ipcFd = acceptSocket(webServerAddrs); + } + else + { + fprintf(stderr, "unknown listenType (%d)\n", listenType); + } + + if (acceptMutex != INVALID_HANDLE_VALUE) + { + ReleaseMutex(acceptMutex); + } + + return ipcFd; +} + +/* + *---------------------------------------------------------------------- + * + * OS_IpcClose + * + * OS IPC routine to close an IPC connection. + * + * Results: + * + * + * Side effects: + * IPC connection is closed. + * + *---------------------------------------------------------------------- + */ +int OS_IpcClose(int ipcFd) +{ + if (ipcFd == -1) return 0; + + /* + * Catch it if fd is a bogus value + */ + ASSERT((ipcFd >= 0) && (ipcFd < WIN32_OPEN_MAX)); + ASSERT(fdTable[ipcFd].type != FD_UNUSED); + + switch (listenType) + { + case FD_PIPE_SYNC: + /* + * Make sure that the client (ie. a Web Server in this case) has + * read all data from the pipe before we disconnect. + */ + if (! FlushFileBuffers(fdTable[ipcFd].fid.fileHandle)) return -1; + + if (! DisconnectNamedPipe(fdTable[ipcFd].fid.fileHandle)) return -1; + + /* fall through */ + + case FD_SOCKET_SYNC: + + OS_Close(ipcFd); + break; + + case FD_UNUSED: + default: + + exit(106); + break; + } + + return 0; +} + +/* + *---------------------------------------------------------------------- + * + * OS_IsFcgi -- + * + * Determines whether this process is a FastCGI process or not. + * + * Results: + * Returns 1 if FastCGI, 0 if not. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ +int OS_IsFcgi(int sock) +{ + // Touch args to prevent warnings + sock = 0; + + /* XXX This is broken for sock */ + + return (listenType != FD_UNUSED); +} + +/* + *---------------------------------------------------------------------- + * + * OS_SetFlags -- + * + * Sets selected flag bits in an open file descriptor. Currently + * this is only to put a SOCKET into non-blocking mode. + * + *---------------------------------------------------------------------- + */ +void OS_SetFlags(int fd, int flags) +{ + unsigned long pLong = 1L; + int err; + + if (fdTable[fd].type == FD_SOCKET_SYNC && flags == O_NONBLOCK) { + if (ioctlsocket(fdTable[fd].fid.sock, FIONBIO, &pLong) == + SOCKET_ERROR) { + exit(WSAGetLastError()); + } + if (!CreateIoCompletionPort((HANDLE)fdTable[fd].fid.sock, + hIoCompPort, fd, 1)) { + err = GetLastError(); + exit(err); + } + + fdTable[fd].type = FD_SOCKET_ASYNC; + } + return; +} + diff --git a/iipsrv/fcgi/ltmain.sh b/iipsrv/fcgi/ltmain.sh new file mode 100644 index 0000000..5959c47 --- /dev/null +++ b/iipsrv/fcgi/ltmain.sh @@ -0,0 +1,4946 @@ +# ltmain.sh - Provide generalized library-building support services. +# NOTE: Changing this file will not affect anything until you rerun configure. +# +# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001 +# 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 + +# 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) + execute_dlfiles="$execute_dlfiles $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= + prev= + lastarg= + srcfile="$nonopt" + suppress_output= + + user_target=no + for arg + do + case $prev in + "") ;; + xcompiler) + # Aesthetically quote the previous argument. + prev= + lastarg=`$echo "X$arg" | $Xsed -e "$sed_quote_subst"` + + case $arg in + # Double-quote args containing other shell metacharacters. + # Many Bourne shells cannot handle close brackets correctly + # in scan sets, so we specify it separately. + *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") + arg="\"$arg\"" + ;; + esac + + # Add the previous argument to base_compile. + if test -z "$base_compile"; then + base_compile="$lastarg" + else + base_compile="$base_compile $lastarg" + fi + continue + ;; + esac + + # 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 + ;; + + -prefer-pic) + pic_mode=yes + continue + ;; + + -prefer-non-pic) + pic_mode=no + continue + ;; + + -Xcompiler) + prev=xcompiler + continue + ;; + + -Wc,*) + args=`$echo "X$arg" | $Xsed -e "s/^-Wc,//"` + lastarg= + IFS="${IFS= }"; save_ifs="$IFS"; IFS=',' + for arg in $args; do + IFS="$save_ifs" + + # Double-quote args containing other shell metacharacters. + # Many Bourne shells cannot handle close brackets correctly + # in scan sets, so we specify it separately. + case $arg in + *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") + arg="\"$arg\"" + ;; + esac + lastarg="$lastarg $arg" + done + IFS="$save_ifs" + lastarg=`$echo "X$lastarg" | $Xsed -e "s/^ //"` + + # Add the arguments to base_compile. + if test -z "$base_compile"; then + base_compile="$lastarg" + else + base_compile="$base_compile $lastarg" + fi + 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 + + # On Cygwin there's no "real" PIC flag so we must build both object types + case $host_os in + cygwin* | mingw* | pw32* | os2*) + pic_mode=default + ;; + esac + if test $pic_mode = no && test "$deplibs_check_method" != pass_all; then + # non-PIC code in shared libraries is not supported + pic_mode=default + fi + + # 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 $run 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 + + if test "$pic_mode" != no; then + # All platforms use -DPIC, to notify preprocessed assembler code. + command="$base_compile $srcfile $pic_flag -DPIC" + else + # Don't build PIC code + command="$base_compile $srcfile" + fi + 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 "$pic_mode" != default) && + 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 + if test "$pic_mode" != yes; then + # Don't build PIC code + command="$base_compile $srcfile" + else + # All platforms use -DPIC, to notify preprocessed assembler code. + command="$base_compile $srcfile $pic_flag -DPIC" + fi + 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 + $run $rm "$lockfile" + fi + + exit 0 + ;; + + # libtool link mode + link | relink) + modename="$modename: link" + case $host in + *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-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 + ;; + *) + allow_undefined=yes + ;; + esac + libtool_args="$nonopt" + compile_command="$nonopt" + finalize_command="$nonopt" + + compile_rpath= + finalize_rpath= + compile_shlibpath= + finalize_shlibpath= + convenience= + old_convenience= + deplibs= + old_deplibs= + compiler_flags= + linker_flags= + dllsearchpath= + lib_search_path=`pwd` + + avoid_version=no + dlfiles= + dlprefiles= + dlself=no + export_dynamic=no + export_symbols= + export_symbols_regex= + generated= + libobjs= + ltlibs= + module=no + no_install=no + objs= + prefer_static_libs=no + preload=no + prev= + prevarg= + release= + rpath= + xrpath= + perm_rpath= + temp_rpath= + thread_safe=no + vinfo= + + # We need to know -static, to get the right output filenames. + for arg + do + case $arg in + -all-static | -static) + if test "X$arg" = "X-all-static"; then + if test "$build_libtool_libs" = yes && test -z "$link_static_flag"; then + $echo "$modename: warning: complete static linking is impossible in this configuration" 1>&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 + case $arg in + *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") + qarg=\"`$echo "X$arg" | $Xsed -e "$sed_quote_subst"`\" ### testsuite: skip nested quoting test + ;; + *) qarg=$arg ;; + esac + libtool_args="$libtool_args $qarg" + + # 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= + continue + ;; + 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 + ;; + xcompiler) + compiler_flags="$compiler_flags $qarg" + prev= + compile_command="$compile_command $qarg" + finalize_command="$finalize_command $qarg" + continue + ;; + xlinker) + linker_flags="$linker_flags $qarg" + compiler_flags="$compiler_flags $wl$qarg" + prev= + compile_command="$compile_command $wl$qarg" + finalize_command="$finalize_command $wl$qarg" + continue + ;; + *) + eval "$prev=\"\$arg\"" + prev= + continue + ;; + esac + fi # test -n $prev + + 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: more than one -exported-symbols argument is not allowed" + exit 1 + fi + if test "X$arg" = "X-export-symbols"; then + prev=expsyms + else + prev=expsyms_regex + fi + continue + ;; + + # The native IRIX linker understands -LANG:*, -LIST:* and -LNO:* + # so, if we see these flags be careful not to treat them like -L + -L[A-Z][A-Z]*:*) + case $with_gcc/$host in + no/*-*-irix*) + compile_command="$compile_command $arg" + finalize_command="$finalize_command $arg" + ;; + esac + 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: cannot determine absolute directory name of \`$dir'" 1>&2 + exit 1 + fi + dir="$absdir" + ;; + esac + case "$deplibs " in + *" -L$dir "*) ;; + *) + deplibs="$deplibs -L$dir" + lib_search_path="$lib_search_path $dir" + ;; + esac + case $host in + *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2*) + case :$dllsearchpath: in + *":$dir:"*) ;; + *) dllsearchpath="$dllsearchpath:$dir";; + esac + ;; + esac + continue + ;; + + -l*) + if test "X$arg" = "X-lc" || test "X$arg" = "X-lm"; then + case $host in + *-*-cygwin* | *-*-pw32* | *-*-beos*) + # These systems don't actually have a C or math library (as such) + continue + ;; + *-*-mingw* | *-*-os2*) + # These systems don't actually have a C library (as such) + test "X$arg" = "X-lc" && continue + ;; + esac + fi + deplibs="$deplibs $arg" + continue + ;; + + -module) + module=yes + continue + ;; + + -no-fast-install) + fast_install=no + continue + ;; + + -no-install) + case $host in + *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2*) + # The PATH hackery in wrapper scripts is required on Windows + # in order for the loader to find any dlls it needs. + $echo "$modename: warning: \`-no-install' is ignored for $host" 1>&2 + $echo "$modename: warning: assuming \`-no-fast-install' instead" 1>&2 + fast_install=no + ;; + *) no_install=yes ;; + esac + 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) + # The effects of -static are defined in a previous loop. + # We used to do the same as -all-static on platforms that + # didn't have a PIC flag, but the assumption that the effects + # would be equivalent was wrong. It would break on at least + # Digital Unix and AIX. + continue + ;; + + -thread-safe) + thread_safe=yes + continue + ;; + + -version-info) + prev=vinfo + continue + ;; + + -Wc,*) + args=`$echo "X$arg" | $Xsed -e "$sed_quote_subst" -e 's/^-Wc,//'` + arg= + IFS="${IFS= }"; save_ifs="$IFS"; IFS=',' + for flag in $args; do + IFS="$save_ifs" + case $flag in + *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") + flag="\"$flag\"" + ;; + esac + arg="$arg $wl$flag" + compiler_flags="$compiler_flags $flag" + done + IFS="$save_ifs" + arg=`$echo "X$arg" | $Xsed -e "s/^ //"` + ;; + + -Wl,*) + args=`$echo "X$arg" | $Xsed -e "$sed_quote_subst" -e 's/^-Wl,//'` + arg= + IFS="${IFS= }"; save_ifs="$IFS"; IFS=',' + for flag in $args; do + IFS="$save_ifs" + case $flag in + *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") + flag="\"$flag\"" + ;; + esac + arg="$arg $wl$flag" + compiler_flags="$compiler_flags $wl$flag" + linker_flags="$linker_flags $flag" + done + IFS="$save_ifs" + arg=`$echo "X$arg" | $Xsed -e "s/^ //"` + ;; + + -Xcompiler) + prev=xcompiler + continue + ;; + + -Xlinker) + prev=xlinker + 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 + ;; + + *.lo | *.$objext) + # A library or standard object. + if test "$prev" = dlfiles; then + # This file was specified with -dlopen. + if test "$build_libtool_libs" = yes && test "$dlopen_support" = yes; then + dlfiles="$dlfiles $arg" + 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= + else + case $arg in + *.lo) libobjs="$libobjs $arg" ;; + *) objs="$objs $arg" ;; + esac + fi + ;; + + *.$libext) + # An archive. + deplibs="$deplibs $arg" + old_deplibs="$old_deplibs $arg" + continue + ;; + + *.la) + # A libtool-controlled library. + + if test "$prev" = dlfiles; then + # This library was specified with -dlopen. + dlfiles="$dlfiles $arg" + prev= + elif test "$prev" = dlprefiles; then + # The library was specified with -dlpreopen. + dlprefiles="$dlprefiles $arg" + prev= + else + deplibs="$deplibs $arg" + fi + 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 # arg + + # 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 # argument parsing loop + + 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 + + # calculate the name of the file, without its directory + outputname=`$echo "X$output" | $Xsed -e 's%^.*/%%'` + libobjs_save="$libobjs" + + if test -n "$shlibpath_var"; then + # get the directories listed in $shlibpath_var + eval shlib_search_path=\`\$echo \"X\${$shlibpath_var}\" \| \$Xsed -e \'s/:/ /g\'\` + else + shlib_search_path= + fi + eval sys_lib_search_path=\"$sys_lib_search_path_spec\" + eval sys_lib_dlsearch_path=\"$sys_lib_dlsearch_path_spec\" + + 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 object directory. + 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 + + # Determine the type of output + case $output in + "") + $echo "$modename: you must specify an output file" 1>&2 + $echo "$help" 1>&2 + exit 1 + ;; + *.$libext) linkmode=oldlib ;; + *.lo | *.$objext) linkmode=obj ;; + *.la) linkmode=lib ;; + *) linkmode=prog ;; # Anything else should be a program. + esac + + specialdeplibs= + libs= + # Find all interdependent deplibs by searching for libraries + # that are linked more than once (e.g. -la -lb -la) + for deplib in $deplibs; do + case "$libs " in + *" $deplib "*) specialdeplibs="$specialdeplibs $deplib" ;; + esac + libs="$libs $deplib" + done + deplibs= + newdependency_libs= + newlib_search_path= + need_relink=no # whether we're linking any uninstalled libtool libraries + notinst_deplibs= # not-installed libtool libraries + notinst_path= # paths that contain not-installed libtool libraries + case $linkmode in + lib) + passes="conv link" + for file in $dlfiles $dlprefiles; do + case $file in + *.la) ;; + *) + $echo "$modename: libraries can \`-dlopen' only libtool libraries: $file" 1>&2 + exit 1 + ;; + esac + done + ;; + prog) + compile_deplibs= + finalize_deplibs= + alldeplibs=no + newdlfiles= + newdlprefiles= + passes="conv scan dlopen dlpreopen link" + ;; + *) passes="conv" + ;; + esac + for pass in $passes; do + if test $linkmode = prog; then + # Determine which files to process + case $pass in + dlopen) + libs="$dlfiles" + save_deplibs="$deplibs" # Collect dlpreopened libraries + deplibs= + ;; + dlpreopen) libs="$dlprefiles" ;; + link) libs="$deplibs %DEPLIBS% $dependency_libs" ;; + esac + fi + for deplib in $libs; do + lib= + found=no + case $deplib in + -l*) + if test $linkmode = oldlib && test $linkmode = obj; then + $echo "$modename: warning: \`-l' is ignored for archives/objects: $deplib" 1>&2 + continue + fi + if test $pass = conv; then + deplibs="$deplib $deplibs" + continue + fi + name=`$echo "X$deplib" | $Xsed -e 's/^-l//'` + for searchdir in $newlib_search_path $lib_search_path $sys_lib_search_path $shlib_search_path; do + # Search the libtool library + lib="$searchdir/lib${name}.la" + if test -f "$lib"; then + found=yes + break + fi + done + if test "$found" != yes; then + # deplib doesn't seem to be a libtool library + if test "$linkmode,$pass" = "prog,link"; then + compile_deplibs="$deplib $compile_deplibs" + finalize_deplibs="$deplib $finalize_deplibs" + else + deplibs="$deplib $deplibs" + test $linkmode = lib && newdependency_libs="$deplib $newdependency_libs" + fi + continue + fi + ;; # -l + -L*) + case $linkmode in + lib) + deplibs="$deplib $deplibs" + test $pass = conv && continue + newdependency_libs="$deplib $newdependency_libs" + newlib_search_path="$newlib_search_path "`$echo "X$deplib" | $Xsed -e 's/^-L//'` + ;; + prog) + if test $pass = conv; then + deplibs="$deplib $deplibs" + continue + fi + if test $pass = scan; then + deplibs="$deplib $deplibs" + newlib_search_path="$newlib_search_path "`$echo "X$deplib" | $Xsed -e 's/^-L//'` + else + compile_deplibs="$deplib $compile_deplibs" + finalize_deplibs="$deplib $finalize_deplibs" + fi + ;; + *) + $echo "$modename: warning: \`-L' is ignored for archives/objects: $deplib" 1>&2 + ;; + esac # linkmode + continue + ;; # -L + -R*) + if test $pass = link; then + dir=`$echo "X$deplib" | $Xsed -e 's/^-R//'` + # Make sure the xrpath contains only unique directories. + case "$xrpath " in + *" $dir "*) ;; + *) xrpath="$xrpath $dir" ;; + esac + fi + deplibs="$deplib $deplibs" + continue + ;; + *.la) lib="$deplib" ;; + *.$libext) + if test $pass = conv; then + deplibs="$deplib $deplibs" + continue + fi + case $linkmode in + lib) + if test "$deplibs_check_method" != pass_all; then + echo + echo "*** Warning: This library needs some functionality provided by $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." + else + echo + echo "*** Warning: Linking the shared library $output against the" + echo "*** static library $deplib is not portable!" + deplibs="$deplib $deplibs" + fi + continue + ;; + prog) + if test $pass != link; then + deplibs="$deplib $deplibs" + else + compile_deplibs="$deplib $compile_deplibs" + finalize_deplibs="$deplib $finalize_deplibs" + fi + continue + ;; + esac # linkmode + ;; # *.$libext + *.lo | *.$objext) + if test $pass = dlpreopen || test "$dlopen_support" != yes || test "$build_libtool_libs" = no; then + # If there is no dlopen support or we're linking statically, + # we need to preload. + newdlprefiles="$newdlprefiles $deplib" + compile_deplibs="$deplib $compile_deplibs" + finalize_deplibs="$deplib $finalize_deplibs" + else + newdlfiles="$newdlfiles $deplib" + fi + continue + ;; + %DEPLIBS%) + alldeplibs=yes + continue + ;; + esac # case $deplib + if test $found = yes || test -f "$lib"; then : + else + $echo "$modename: cannot find the library \`$lib'" 1>&2 + exit 1 + fi + + # Check to see that this really is a libtool archive. + if (sed -e '2q' $lib | egrep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then : + else + $echo "$modename: \`$lib' is not a valid libtool archive" 1>&2 + exit 1 + fi + + ladir=`$echo "X$lib" | $Xsed -e 's%/[^/]*$%%'` + test "X$ladir" = "X$lib" && ladir="." + + dlname= + dlopen= + dlpreopen= + libdir= + library_names= + old_library= + # If the library was installed with an old release of libtool, + # it will not redefine variable installed. + installed=yes + + # Read the .la file + case $lib in + */* | *\\*) . $lib ;; + *) . ./$lib ;; + esac + + if test "$linkmode,$pass" = "lib,link" || + test "$linkmode,$pass" = "prog,scan" || + { test $linkmode = oldlib && test $linkmode = obj; }; then + # Add dl[pre]opened files of deplib + test -n "$dlopen" && dlfiles="$dlfiles $dlopen" + test -n "$dlpreopen" && dlprefiles="$dlprefiles $dlpreopen" + fi + + if test $pass = conv; then + # Only check for convenience libraries + deplibs="$lib $deplibs" + if test -z "$libdir"; then + if test -z "$old_library"; then + $echo "$modename: cannot find name of link library for \`$lib'" 1>&2 + exit 1 + fi + # It is a libtool convenience library, so add in its objects. + convenience="$convenience $ladir/$objdir/$old_library" + old_convenience="$old_convenience $ladir/$objdir/$old_library" + tmp_libs= + for deplib in $dependency_libs; do + deplibs="$deplib $deplibs" + case "$tmp_libs " in + *" $deplib "*) specialdeplibs="$specialdeplibs $deplib" ;; + esac + tmp_libs="$tmp_libs $deplib" + done + elif test $linkmode != prog && test $linkmode != lib; then + $echo "$modename: \`$lib' is not a convenience library" 1>&2 + exit 1 + fi + continue + fi # $pass = conv + + # 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 \`$lib'" 1>&2 + exit 1 + fi + + # This library was specified with -dlopen. + if test $pass = dlopen; then + if test -z "$libdir"; then + $echo "$modename: cannot -dlopen a convenience library: \`$lib'" 1>&2 + exit 1 + fi + if test -z "$dlname" || test "$dlopen_support" != yes || test "$build_libtool_libs" = no; then + # If there is no dlname, no dlopen support or we're linking + # statically, we need to preload. + dlprefiles="$dlprefiles $lib" + else + newdlfiles="$newdlfiles $lib" + fi + continue + fi # $pass = dlopen + + # We need an absolute path. + case $ladir in + [\\/]* | [A-Za-z]:[\\/]*) abs_ladir="$ladir" ;; + *) + abs_ladir=`cd "$ladir" && pwd` + if test -z "$abs_ladir"; then + $echo "$modename: warning: cannot determine absolute directory name of \`$ladir'" 1>&2 + $echo "$modename: passing it literally to the linker, although it might fail" 1>&2 + abs_ladir="$ladir" + fi + ;; + esac + laname=`$echo "X$lib" | $Xsed -e 's%^.*/%%'` + + # Find the relevant object directory and library name. + if test "X$installed" = Xyes; then + if test ! -f "$libdir/$linklib" && test -f "$abs_ladir/$linklib"; then + $echo "$modename: warning: library \`$lib' was moved." 1>&2 + dir="$ladir" + absdir="$abs_ladir" + libdir="$abs_ladir" + else + dir="$libdir" + absdir="$libdir" + fi + else + dir="$ladir/$objdir" + absdir="$abs_ladir/$objdir" + # Remove this search path later + notinst_path="$notinst_path $abs_ladir" + fi # $installed = yes + name=`$echo "X$laname" | $Xsed -e 's/\.la$//' -e 's/^lib//'` + + # This library was specified with -dlpreopen. + if test $pass = dlpreopen; then + if test -z "$libdir"; then + $echo "$modename: cannot -dlpreopen a convenience library: \`$lib'" 1>&2 + exit 1 + fi + # Prefer using a static library (so that no silly _DYNAMIC symbols + # are required to link). + if test -n "$old_library"; then + newdlprefiles="$newdlprefiles $dir/$old_library" + # Otherwise, use the dlname, so that lt_dlopen finds it. + elif test -n "$dlname"; then + newdlprefiles="$newdlprefiles $dir/$dlname" + else + newdlprefiles="$newdlprefiles $dir/$linklib" + fi + fi # $pass = dlpreopen + + if test -z "$libdir"; then + # Link the convenience library + if test $linkmode = lib; then + deplibs="$dir/$old_library $deplibs" + elif test "$linkmode,$pass" = "prog,link"; then + compile_deplibs="$dir/$old_library $compile_deplibs" + finalize_deplibs="$dir/$old_library $finalize_deplibs" + else + deplibs="$lib $deplibs" + fi + continue + fi + + if test $linkmode = prog && test $pass != link; then + newlib_search_path="$newlib_search_path $ladir" + deplibs="$lib $deplibs" + + linkalldeplibs=no + if test "$link_all_deplibs" != no || test -z "$library_names" || + test "$build_libtool_libs" = no; then + linkalldeplibs=yes + fi + + tmp_libs= + for deplib in $dependency_libs; do + case $deplib in + -L*) newlib_search_path="$newlib_search_path "`$echo "X$deplib" | $Xsed -e 's/^-L//'`;; ### testsuite: skip nested quoting test + esac + # Need to link against all dependency_libs? + if test $linkalldeplibs = yes; then + deplibs="$deplib $deplibs" + else + # Need to hardcode shared library paths + # or/and link against static libraries + newdependency_libs="$deplib $newdependency_libs" + fi + case "$tmp_libs " in + *" $deplib "*) specialdeplibs="$specialdeplibs $deplib" ;; + esac + tmp_libs="$tmp_libs $deplib" + done # for deplib + continue + fi # $linkmode = prog... + + link_static=no # Whether the deplib will be linked statically + if test -n "$library_names" && + { test "$prefer_static_libs" = no || test -z "$old_library"; }; then + # Link against this shared library + + if test "$linkmode,$pass" = "prog,link" || + { test $linkmode = lib && test $hardcode_into_libs = yes; }; then + # Hardcode the library path. + # Skip directories that are in the system default run-time + # search path. + 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 + if test $linkmode = prog; then + # We need to hardcode the library path + if test -n "$shlibpath_var"; then + # Make sure the rpath contains only unique directories. + case "$temp_rpath " in + *" $dir "*) ;; + *" $absdir "*) ;; + *) temp_rpath="$temp_rpath $dir" ;; + esac + fi + fi + fi # $linkmode,$pass = prog,link... + + if test "$alldeplibs" = yes && + { test "$deplibs_check_method" = pass_all || + { test "$build_libtool_libs" = yes && + test -n "$library_names"; }; }; then + # We only need to search for static libraries + continue + fi + + if test "$installed" = no; then + notinst_deplibs="$notinst_deplibs $lib" + need_relink=yes + fi + + if test -n "$old_archive_from_expsyms_cmds"; then + # figure out the soname + set dummy $library_names + realname="$2" + shift; shift + libname=`eval \\$echo \"$libname_spec\"` + # use dlname if we got it. it's perfectly good, no? + if test -n "$dlname"; then + soname="$dlname" + elif test -n "$soname_spec"; then + # bleh windows + case $host in + *cygwin*) + major=`expr $current - $age` + versuffix="-$major" + ;; + esac + eval soname=\"$soname_spec\" + else + soname="$realname" + fi + + # Make a new name for the extract_expsyms_cmds to use + soroot="$soname" + soname=`echo $soroot | sed -e 's/^.*\///'` + newlib="libimp-`echo $soname | sed 's/^lib//;s/\.dll$//'`.a" + + # If the library has no export list, then create one now + if test -f "$output_objdir/$soname-def"; then : + else + $show "extracting exported symbol list from \`$soname'" + IFS="${IFS= }"; save_ifs="$IFS"; IFS='~' + eval cmds=\"$extract_expsyms_cmds\" + for cmd in $cmds; do + IFS="$save_ifs" + $show "$cmd" + $run eval "$cmd" || exit $? + done + IFS="$save_ifs" + fi + + # Create $newlib + if test -f "$output_objdir/$newlib"; then :; else + $show "generating import library for \`$soname'" + IFS="${IFS= }"; save_ifs="$IFS"; IFS='~' + eval cmds=\"$old_archive_from_expsyms_cmds\" + for cmd in $cmds; do + IFS="$save_ifs" + $show "$cmd" + $run eval "$cmd" || exit $? + done + IFS="$save_ifs" + fi + # make sure the library variables are pointing to the new library + dir=$output_objdir + linklib=$newlib + fi # test -n $old_archive_from_expsyms_cmds + + if test $linkmode = prog || test "$mode" != relink; then + add_shlibpath= + add_dir= + add= + lib_linked=yes + case $hardcode_action in + immediate | unsupported) + if test "$hardcode_direct" = no; then + add="$dir/$linklib" + elif test "$hardcode_minus_L" = no; then + case $host in + *-*-sunos*) add_shlibpath="$dir" ;; + esac + add_dir="-L$dir" + add="-l$name" + elif test "$hardcode_shlibpath_var" = no; then + add_shlibpath="$dir" + add="-l$name" + else + lib_linked=no + fi + ;; + relink) + if test "$hardcode_direct" = yes; then + add="$dir/$linklib" + elif test "$hardcode_minus_L" = yes; then + add_dir="-L$dir" + add="-l$name" + elif test "$hardcode_shlibpath_var" = yes; then + add_shlibpath="$dir" + add="-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 + + if test -n "$add_shlibpath"; then + case :$compile_shlibpath: in + *":$add_shlibpath:"*) ;; + *) compile_shlibpath="$compile_shlibpath$add_shlibpath:" ;; + esac + fi + if test $linkmode = prog; then + test -n "$add_dir" && compile_deplibs="$add_dir $compile_deplibs" + test -n "$add" && compile_deplibs="$add $compile_deplibs" + else + test -n "$add_dir" && deplibs="$add_dir $deplibs" + test -n "$add" && deplibs="$add $deplibs" + if test "$hardcode_direct" != yes && \ + test "$hardcode_minus_L" != yes && \ + test "$hardcode_shlibpath_var" = yes; then + case :$finalize_shlibpath: in + *":$libdir:"*) ;; + *) finalize_shlibpath="$finalize_shlibpath$libdir:" ;; + esac + fi + fi + fi + + if test $linkmode = prog || test "$mode" = relink; then + add_shlibpath= + add_dir= + add= + # Finalize command for both is simple: just hardcode it. + if test "$hardcode_direct" = yes; then + add="$libdir/$linklib" + elif test "$hardcode_minus_L" = yes; then + add_dir="-L$libdir" + add="-l$name" + elif test "$hardcode_shlibpath_var" = yes; then + case :$finalize_shlibpath: in + *":$libdir:"*) ;; + *) finalize_shlibpath="$finalize_shlibpath$libdir:" ;; + esac + add="-l$name" + else + # We cannot seem to hardcode it, guess we'll fake it. + add_dir="-L$libdir" + add="-l$name" + fi + + if test $linkmode = prog; then + test -n "$add_dir" && finalize_deplibs="$add_dir $finalize_deplibs" + test -n "$add" && finalize_deplibs="$add $finalize_deplibs" + else + test -n "$add_dir" && deplibs="$add_dir $deplibs" + test -n "$add" && deplibs="$add $deplibs" + fi + fi + elif test $linkmode = prog; then + if test "$alldeplibs" = yes && + { test "$deplibs_check_method" = pass_all || + { test "$build_libtool_libs" = yes && + test -n "$library_names"; }; }; then + # We only need to search for static libraries + continue + fi + + # Try to link the static library + # 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_deplibs="$dir/$linklib $compile_deplibs" + finalize_deplibs="$dir/$linklib $finalize_deplibs" + else + compile_deplibs="-l$name -L$dir $compile_deplibs" + finalize_deplibs="-l$name -L$dir $finalize_deplibs" + fi + elif test "$build_libtool_libs" = yes; then + # Not a shared library + if test "$deplibs_check_method" != pass_all; then + # We're trying link a shared library against a static one + # but the system doesn't support it. + + # Just print a warning and add the library to dependency_libs so + # that the program can be linked against the static library. + echo + echo "*** Warning: This library needs some functionality provided by $lib." + 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." + if test "$module" = yes; then + echo "*** Therefore, libtool will create a static module, that should work " + echo "*** as long as the dlopening 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 + build_libtool_libs=module + build_old_libs=yes + else + build_libtool_libs=no + fi + fi + else + convenience="$convenience $dir/$old_library" + old_convenience="$old_convenience $dir/$old_library" + deplibs="$dir/$old_library $deplibs" + link_static=yes + fi + fi # link shared/static library? + + if test $linkmode = lib; then + if test -n "$dependency_libs" && + { test $hardcode_into_libs != yes || test $build_old_libs = yes || + test $link_static = yes; }; then + # Extract -R from dependency_libs + temp_deplibs= + for libdir in $dependency_libs; do + case $libdir in + -R*) temp_xrpath=`$echo "X$libdir" | $Xsed -e 's/^-R//'` + case " $xrpath " in + *" $temp_xrpath "*) ;; + *) xrpath="$xrpath $temp_xrpath";; + esac;; + *) temp_deplibs="$temp_deplibs $libdir";; + esac + done + dependency_libs="$temp_deplibs" + fi + + newlib_search_path="$newlib_search_path $absdir" + # Link against this library + test "$link_static" = no && newdependency_libs="$abs_ladir/$laname $newdependency_libs" + # ... and its dependency_libs + tmp_libs= + for deplib in $dependency_libs; do + newdependency_libs="$deplib $newdependency_libs" + case "$tmp_libs " in + *" $deplib "*) specialdeplibs="$specialdeplibs $deplib" ;; + esac + tmp_libs="$tmp_libs $deplib" + done + + if test $link_all_deplibs != no; then + # Add the search paths of all dependency libraries + for deplib in $dependency_libs; do + case $deplib in + -L*) path="$deplib" ;; + *.la) + dir=`$echo "X$deplib" | $Xsed -e 's%/[^/]*$%%'` + test "X$dir" = "X$deplib" && dir="." + # 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 + absdir="$dir" + fi + ;; + esac + if grep "^installed=no" $deplib > /dev/null; then + path="-L$absdir/$objdir" + else + eval libdir=`sed -n -e 's/^libdir=\(.*\)$/\1/p' $deplib` + if test -z "$libdir"; then + $echo "$modename: \`$deplib' is not a valid libtool archive" 1>&2 + exit 1 + fi + if test "$absdir" != "$libdir"; then + $echo "$modename: warning: \`$deplib' seems to be moved" 1>&2 + fi + path="-L$absdir" + fi + ;; + *) continue ;; + esac + case " $deplibs " in + *" $path "*) ;; + *) deplibs="$deplibs $path" ;; + esac + done + fi # link_all_deplibs != no + fi # linkmode = lib + done # for deplib in $libs + if test $pass = dlpreopen; then + # Link the dlpreopened libraries before other libraries + for deplib in $save_deplibs; do + deplibs="$deplib $deplibs" + done + fi + if test $pass != dlopen; then + test $pass != scan && dependency_libs="$newdependency_libs" + if test $pass != conv; then + # Make sure lib_search_path contains only unique directories. + lib_search_path= + for dir in $newlib_search_path; do + case "$lib_search_path " in + *" $dir "*) ;; + *) lib_search_path="$lib_search_path $dir" ;; + esac + done + newlib_search_path= + fi + + if test "$linkmode,$pass" != "prog,link"; then + vars="deplibs" + else + vars="compile_deplibs finalize_deplibs" + fi + for var in $vars dependency_libs; do + # Add libraries to $var in reverse order + eval tmp_libs=\"\$$var\" + new_libs= + for deplib in $tmp_libs; do + case $deplib in + -L*) new_libs="$deplib $new_libs" ;; + *) + case " $specialdeplibs " in + *" $deplib "*) new_libs="$deplib $new_libs" ;; + *) + case " $new_libs " in + *" $deplib "*) ;; + *) new_libs="$deplib $new_libs" ;; + esac + ;; + esac + ;; + esac + done + tmp_libs= + for deplib in $new_libs; do + case $deplib in + -L*) + case " $tmp_libs " in + *" $deplib "*) ;; + *) tmp_libs="$tmp_libs $deplib" ;; + esac + ;; + *) tmp_libs="$tmp_libs $deplib" ;; + esac + done + eval $var=\"$tmp_libs\" + done # for var + fi + if test "$pass" = "conv" && + { test "$linkmode" = "lib" || test "$linkmode" = "prog"; }; then + libs="$deplibs" # reset libs + deplibs= + fi + done # for pass + if test $linkmode = prog; then + dlfiles="$newdlfiles" + dlprefiles="$newdlprefiles" + fi + + case $linkmode in + oldlib) + 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" + objs="$objs$old_deplibs" + ;; + + lib) + # 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 + + if test -n "$objs"; then + if test "$deplibs_check_method" != pass_all; then + $echo "$modename: cannot build libtool library \`$output' from non-libtool objects on this host:$objs" 2>&1 + exit 1 + else + echo + echo "*** Warning: Linking the shared library $output against the non-libtool" + echo "*** objects $objs is not portable!" + libobjs="$libobjs $objs" + fi + fi + + if test "$dlself" != no; then + $echo "$modename: warning: \`-dlopen self' 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 + + 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] | [1-9][0-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] | [1-9][0-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] | [1-9][0-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) ;; + + darwin) + # Like Linux, but with the current version available in + # verstring for coding it into the library header + major=.`expr $current - $age` + versuffix="$major.$age.$revision" + # Darwin ld doesn't like 0 for these options... + minor_current=`expr $current + 1` + verstring="-compatibility_version $minor_current -current_version $minor_current.$revision" + ;; + + freebsd-aout) + major=".$current" + versuffix=".$current.$revision"; + ;; + + freebsd-elf) + major=".$current" + versuffix=".$current"; + ;; + + irix) + major=`expr $current - $age + 1` + 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 + + # Before this point, $major must not contain `.'. + major=.$major + versuffix="$major.$revision" + ;; + + 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" + ;; + + windows) + # Use '-' rather than '.', since we only want one + # extension on DOS 8.3 filesystems. + major=`expr $current - $age` + versuffix="-$major" + ;; + + *) + $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 + fi + + if test "$mode" != relink; then + # Remove our outputs. + $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}.* + 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 + + # Eliminate all temporary directories. + for path in $notinst_path; do + lib_search_path=`echo "$lib_search_path " | sed -e 's% $path % %g'` + deplibs=`echo "$deplibs " | sed -e 's% -L$path % %g'` + dependency_libs=`echo "$dependency_libs " | sed -e 's% -L$path % %g'` + done + + if test -n "$xrpath"; then + # If the user specified any rpath flags, then add them. + temp_xrpath= + for libdir in $xrpath; do + temp_xrpath="$temp_xrpath -R$libdir" + case "$finalize_rpath " in + *" $libdir "*) ;; + *) finalize_rpath="$finalize_rpath $libdir" ;; + esac + done + if test $hardcode_into_libs != yes || test $build_old_libs = yes; then + dependency_libs="$temp_xrpath $dependency_libs" + fi + fi + + # Make sure dlfiles contains only unique files that won't be dlpreopened + old_dlfiles="$dlfiles" + dlfiles= + for lib in $old_dlfiles; do + case " $dlprefiles $dlfiles " in + *" $lib "*) ;; + *) dlfiles="$dlfiles $lib" ;; + esac + done + + # Make sure dlprefiles contains only unique files + old_dlprefiles="$dlprefiles" + dlprefiles= + for lib in $old_dlprefiles; do + case "$dlprefiles " in + *" $lib "*) ;; + *) dlprefiles="$dlprefiles $lib" ;; + esac + done + + if test "$build_libtool_libs" = yes; then + if test -n "$rpath"; then + case $host in + *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-*-beos*) + # these systems don't actually have a c library (as such)! + ;; + *-*-rhapsody* | *-*-darwin1.[012]) + # Rhapsody C library is in the System framework + deplibs="$deplibs -framework System" + ;; + *-*-netbsd*) + # Don't link with libc until the a.out ld.so is fixed. + ;; + *) + # Add libc to deplibs on all other systems if necessary. + if test $build_libtool_need_lc = "yes"; then + deplibs="$deplibs -lc" + fi + ;; + esac + fi + + # 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. + ;; + match_pattern*) + set dummy $deplibs_check_method + match_pattern_regex=`expr "$deplibs_check_method" : "$2 \(.*\)"` + for a_deplib in $deplibs; do + name="`expr $a_deplib : '-l\(.*\)'`" + # If $name is empty we are operating on a -L argument. + if test -n "$name" && test "$name" != "0"; then + libname=`eval \\$echo \"$libname_spec\"` + for i in $lib_search_path $sys_lib_search_path $shlib_search_path; do + potential_libs=`ls $i/$libname[.-]* 2>/dev/null` + for potent_lib in $potential_libs; do + if eval echo \"$potent_lib\" 2>/dev/null \ + | sed 10q \ + | egrep "$match_pattern_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 + + case $host in + *-*-rhapsody* | *-*-darwin1.[012]) + # On Rhapsody replace the C library is the System framework + newdeplibs=`$echo "X $newdeplibs" | $Xsed -e 's/ -lc / -framework System /'` + ;; + esac + + 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." + + if test $allow_undefined = no; then + echo + echo "*** Since this library must not contain undefined symbols," + echo "*** because either the platform does not support them or" + echo "*** it was explicitly requested with -no-undefined," + echo "*** libtool will only create a static version of it." + 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 + fi + 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 + if test $hardcode_into_libs = yes; then + # Hardcode the library paths + hardcode_libdirs= + dep_rpath= + rpath="$finalize_rpath" + test "$mode" != relink && rpath="$compile_rpath$rpath" + for libdir in $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\" + dep_rpath="$dep_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 dep_rpath=\"$hardcode_libdir_flag_spec\" + fi + if test -n "$runpath_var" && test -n "$perm_rpath"; then + # We should set the runpath_var. + rpath= + for dir in $perm_rpath; do + rpath="$rpath$dir:" + done + eval "$runpath_var='$rpath\$$runpath_var'; export $runpath_var" + fi + test -n "$dep_rpath" && deplibs="$dep_rpath $deplibs" + fi + + shlibpath="$finalize_shlibpath" + test "$mode" != relink && shlibpath="$compile_shlibpath$shlibpath" + if test -n "$shlibpath"; then + eval "$shlibpath_var='$shlibpath\$$shlibpath_var'; export $shlibpath_var" + fi + + # 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 + test -z "$dlname" && dlname=$soname + + 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\" + linker_flags="$linker_flags $flag" + fi + + # Make a backup of the uninstalled library when relinking + if test "$mode" = relink; then + $run eval '(cd $output_objdir && $rm ${realname}U && $mv $realname ${realname}U)' || exit $? + 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" + + # Restore the uninstalled library and exit + if test "$mode" = relink; then + $run eval '(cd $output_objdir && $rm ${realname}T && $mv $realname ${realname}T && $mv "$realname"U $realname)' || exit $? + exit 0 + fi + + # 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 + ;; + + obj) + 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$old_deplibs"; 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$old_deplibs "`$echo "X$libobjs" | $SP2NL | $Xsed -e '/\.'${libext}$'/d' -e '/\.lib$/d' -e "$lo2o" | $NL2SP`" $reload_conv_objs" ### testsuite: skip nested quoting test + + 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" || test "$pic_mode" != default; 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 + ;; + + prog) + case $host in + *cygwin*) output=`echo $output | sed -e 's,.exe$,,;s,$,.exe,'` ;; + esac + 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_support" = 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 + + case $host in + *-*-rhapsody* | *-*-darwin1.[012]) + # On Rhapsody replace the C library is the System framework + compile_deplibs=`$echo "X $compile_deplibs" | $Xsed -e 's/ -lc / -framework System /'` + finalize_deplibs=`$echo "X $finalize_deplibs" | $Xsed -e 's/ -lc / -framework System /'` + ;; + esac + + compile_command="$compile_command $compile_deplibs" + finalize_command="$finalize_command $finalize_deplibs" + + 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 "$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 + case $host in + *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2*) + case :$dllsearchpath: in + *":$libdir:"*) ;; + *) dllsearchpath="$dllsearchpath:$libdir";; + esac + ;; + esac + 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" + + 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$old_deplibs" | $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 $need_relink = no || 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 "$no_install" = yes; then + # We don't need to create a wrapper script. + link_command="$compile_var$compile_command$compile_rpath" + # Replace the output file specification. + link_command=`$echo "X$link_command" | $Xsed -e 's%@OUTPUT@%'"$output"'%g'` + # Delete the old output file. + $run $rm $output + # Link the executable and exit + $show "$link_command" + $run eval "$link_command" || exit $? + exit 0 + 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 + # Preserve any variables that may affect compiler behavior + for var in $variables_saved_for_relink; do + if eval test -z \"\${$var+set}\"; then + relink_command="{ test -z \"\${$var+set}\" || unset $var || { $var=; export $var; }; }; $relink_command" + elif eval var_value=\$$var; test -z "$var_value"; then + relink_command="$var=; export $var; $relink_command" + else + var_value=`$echo "X$var_value" | $Xsed -e "$sed_quote_subst"` + relink_command="$var=\"$var_value\"; export $var; $relink_command" + fi + done + relink_command="cd `pwd`; $relink_command" + 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 + # test for cygwin because mv fails w/o .exe extensions + case $host in + *cygwin*) exeext=.exe ;; + *) exeext= ;; + 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: + notinst_deplibs='$notinst_deplibs' +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'$exeext + 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 (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 + # win32 systems need to use the prog path for dll + # lookup to work + *-*-cygwin* | *-*-pw32*) + $echo >> $output "\ + exec \$progdir/\$program \${1+\"\$@\"} +" + ;; + + # Backslashes separate directories on plain windows + *-*-mingw | *-*-os2*) + $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$old_deplibs "`$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" + + # Preserve any variables that may affect compiler behavior + for var in $variables_saved_for_relink; do + if eval test -z \"\${$var+set}\"; then + relink_command="{ test -z \"\${$var+set}\" || unset $var || { $var=; export $var; }; }; $relink_command" + elif eval var_value=\$$var; test -z "$var_value"; then + relink_command="$var=; export $var; $relink_command" + else + var_value=`$echo "X$var_value" | $Xsed -e "$sed_quote_subst"` + relink_command="$var=\"$var_value\"; export $var; $relink_command" + fi + done + # Quote the link command for shipping. + relink_command="cd `pwd`; $SHELL $0 --mode=relink $libtool_args" + relink_command=`$echo "X$relink_command" | $Xsed -e "$sed_quote_subst"` + + # 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 + # Replace all uninstalled libtool libraries with the installed ones + newdependency_libs= + for deplib in $dependency_libs; do + case $deplib in + *.la) + name=`$echo "X$deplib" | $Xsed -e 's%^.*/%%'` + eval libdir=`sed -n -e 's/^libdir=\(.*\)$/\1/p' $deplib` + if test -z "$libdir"; then + $echo "$modename: \`$deplib' is not a valid libtool archive" 1>&2 + exit 1 + fi + newdependency_libs="$newdependency_libs $libdir/$name" + ;; + *) newdependency_libs="$newdependency_libs $deplib" ;; + esac + done + dependency_libs="$newdependency_libs" + newdlfiles= + for lib in $dlfiles; do + name=`$echo "X$lib" | $Xsed -e 's%^.*/%%'` + eval libdir=`sed -n -e 's/^libdir=\(.*\)$/\1/p' $lib` + if test -z "$libdir"; then + $echo "$modename: \`$lib' is not a valid libtool archive" 1>&2 + exit 1 + fi + newdlfiles="$newdlfiles $libdir/$name" + done + dlfiles="$newdlfiles" + newdlprefiles= + for lib in $dlprefiles; do + name=`$echo "X$lib" | $Xsed -e 's%^.*/%%'` + eval libdir=`sed -n -e 's/^libdir=\(.*\)$/\1/p' $lib` + if test -z "$libdir"; then + $echo "$modename: \`$lib' is not a valid libtool archive" 1>&2 + exit 1 + fi + newdlprefiles="$newdlprefiles $libdir/$name" + done + dlprefiles="$newdlprefiles" + fi + $rm $output + # place dlname in correct position for cygwin + tdlname=$dlname + case $host,$output,$installed,$module,$dlname in + *cygwin*,*lai,yes,no,*.dll) tdlname=../bin/$dlname ;; + esac + $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='$tdlname' + +# 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 + +# Files to dlopen/dlpreopen +dlopen='$dlfiles' +dlpreopen='$dlprefiles' + +# Directory that this library needs to be installed in: +libdir='$install_libdir'" + if test "$installed" = no && test $need_relink = yes; then + $echo >> $output "\ +relink_command=\"$relink_command\"" + fi + 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 || + # Allow the use of GNU shtool's install command. + $echo "X$nonopt" | $Xsed | grep shtool > /dev/null; 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 + *.$libext) + # 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= + relink_command= + # 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" + + if test -n "$relink_command"; then + $echo "$modename: warning: relinking \`$file'" 1>&2 + $show "$relink_command" + if $run eval "$relink_command"; then : + else + $echo "$modename: error: relink \`$file' with the above command before installing it" 1>&2 + continue + fi + fi + + # See the names of the shared library. + set dummy $library_names + if test -n "$2"; then + realname="$2" + shift + shift + + srcname="$realname" + test -n "$relink_command" && srcname="$realname"T + + # Install the shared library and build the symlinks. + $show "$install_prog $dir/$srcname $destdir/$realname" + $run eval "$install_prog $dir/$srcname $destdir/$realname" || exit $? + if test -n "$stripme" && test -n "$striplib"; then + $show "$striplib $destdir/$realname" + $run eval "$striplib $destdir/$realname" || exit $? + fi + + 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"` + ;; + *.$objext) + 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 + notinst_deplibs= + 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 "$notinst_deplibs"; then + $echo "$modename: invalid libtool wrapper script \`$file'" 1>&2 + exit 1 + fi + + finalize=yes + for lib in $notinst_deplibs; 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'` ### testsuite: skip nested quoting test + if test -n "$libdir" && test ! -f "$libfile"; then + $echo "$modename: warning: \`$lib' has not been installed in \`$libdir'" 1>&2 + finalize=no + fi + done + + relink_command= + # If there is no directory component, then add one. + case $file in + */* | *\\*) . $file ;; + *) . ./$file ;; + esac + + 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 + file=`$echo "X$file" | $Xsed -e 's%^.*/%%'` + 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 + + # remove .exe since cygwin /usr/bin/install will append another + # one anyways + case $install_prog,$host in + /usr/bin/install*,*cygwin*) + case $file:$destfile in + *.exe:*.exe) + # this is ok + ;; + *.exe:*) + destfile=$destfile.exe + ;; + *:*.exe) + destfile=`echo $destfile | sed -e 's,.exe$,,'` + ;; + esac + ;; + esac + $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 $? + + if test -n "$stripme" && test -n "$striplib"; then + $show "$old_striplib $oldlib" + $run eval "$old_striplib $oldlib" || exit $? + fi + + # 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 the \`-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 clean and uninstall mode + clean | uninstall) + modename="$modename: $mode" + rm="$nonopt" + files= + rmforce= + exit_status=0 + + # This variable tells wrapper scripts just to set variables rather + # than running their programs. + libtool_install_magic="$magic" + + for arg + do + case $arg in + -f) rm="$rm $arg"; rmforce=yes ;; + -*) 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 + + rmdirs= + + for file in $files; do + dir=`$echo "X$file" | $Xsed -e 's%/[^/]*$%%'` + if test "X$dir" = "X$file"; then + dir=. + objdir="$objdir" + else + objdir="$dir/$objdir" + fi + name=`$echo "X$file" | $Xsed -e 's%^.*/%%'` + test $mode = uninstall && objdir="$dir" + + # Remember objdir for removal later, being careful to avoid duplicates + if test $mode = clean; then + case " $rmdirs " in + *" $objdir "*) ;; + *) rmdirs="$rmdirs $objdir" ;; + esac + fi + + # Don't error if the file doesn't exist and rm -f was used. + if (test -L "$file") >/dev/null 2>&1 \ + || (test -h "$file") >/dev/null 2>&1 \ + || test -f "$file"; then + : + elif test -d "$file"; then + exit_status=1 + continue + elif test "$rmforce" = yes; then + continue + fi + + 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 $objdir/$n" + done + test -n "$old_library" && rmfiles="$rmfiles $objdir/$old_library" + test $mode = clean && rmfiles="$rmfiles $objdir/$name $objdir/${name}i" + + if test $mode = uninstall; then + 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" + if test $? != 0 && test "$rmforce" != yes; then + exit_status=1 + fi + 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" + if test $? != 0 && test "$rmforce" != yes; then + exit_status=1 + fi + done + IFS="$save_ifs" + fi + # FIXME: should reinstall the best remaining shared library. + fi + fi + ;; + + *.lo) + if test "$build_old_libs" = yes; then + oldobj=`$echo "X$name" | $Xsed -e "$lo2o"` + rmfiles="$rmfiles $dir/$oldobj" + fi + ;; + + *) + # Do a test to see if this is a libtool program. + if test $mode = clean && + (sed -e '4q' $file | egrep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then + relink_command= + . $dir/$file + + rmfiles="$rmfiles $objdir/$name $objdir/${name}S.${objext}" + if test "$fast_install" = yes && test -n "$relink_command"; then + rmfiles="$rmfiles $objdir/lt-$name" + fi + fi + ;; + esac + $show "$rm $rmfiles" + $run $rm $rmfiles || exit_status=1 + done + + # Try to remove the ${objdir}s in the directories where we deleted files + for dir in $rmdirs; do + if test -d "$dir"; then + $show "rmdir $dir" + $run rmdir $dir >/dev/null 2>&1 + fi + done + + exit $exit_status + ;; + + "") + $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: + + clean remove files from the build directory + 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 + ;; + +clean) + $echo \ +"Usage: $modename [OPTION]... --mode=clean RM [RM-OPTION]... FILE... + +Remove files from the build 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, object or program, all the files associated +with it are deleted. Otherwise, only FILE itself is deleted using RM." + ;; + +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 + -prefer-pic try to building PIC objects only + -prefer-non-pic try to building non-PIC objects only + -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-fast-install disable the fast-install mode + -no-install link a not-installable executable + -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/iipsrv/fcgi/perl/ChangeLog b/iipsrv/fcgi/perl/ChangeLog new file mode 100644 index 0000000..bb5046b --- /dev/null +++ b/iipsrv/fcgi/perl/ChangeLog @@ -0,0 +1,229 @@ +Version 0.67 -- 22 December 2002 Sven Verdoolaege + + o Fixes for pure perl version based on report and patch + from "Kurtis D. Rader" + o FCGI_UndoBinding perl 5.8.0 compatibility + Reported by Marko Asplund + o Fix problem with fcgi_config.h on win32. + Reported by Igor Franchuk + o Add minimal tests + +Version 0.66 -- 5 September 2002 Sven Verdoolaege + + o perl 5.8.0 compatibility fix by Autrijus + o library fixes from Rob + +Version 0.65 -- 19 February 2002 Sven Verdoolaege + + o fix perl 5.005 compatibility problem + o fix strict warning + +Version 0.64 -- 25 September 2001 Sven Verdoolaege +Version 0.63 -- 24 September 2001 Sven Verdoolaege + + o Update build process + +Version 0.62 -- 21 September 2001 Sven Verdoolaege + + o Move version number to separate file + +Version 0.61 -- 20 September 2001 Sven Verdoolaege + + o Fix refcounting bug + o Add GetEnvironment for pure version + o Add LastCall method + o Allow filehandle for Request's socket parameter + o library fixes ("Rob Saccoccio" ) + +Version 0.60 -- 8 July 2001 Sven Verdoolaege + + o Allow specification of purity on command line + (suggested by Rob Brown ) + o Fix bug in pure perl implementation + o Don't try to compile anything on pure perl build + o Add BINMODE method + o Add comment on socket permissions + +Version 0.59 -- 31 December 2000 Sven Verdoolaege + + o preliminary pure perl implementation + o copy win32 configuration file instead of moving it + o convert echo.fpl to new interface + +Version 0.58 -- 15 November 2000 Sven Verdoolaege + + o fix bug introduced in 0.57 + +Version 0.57 -- 12 November 2000 Sven Verdoolaege + + o don't flush unbound request + +Version 0.56 -- 3 November 2000 Sven Verdoolaege + + o add example remote.fpl + o provide access to the Request parameters + o add IsFastCGI method + o fix warn handler (Andrew Pimlott ) + +Version 0.55 -- 18 October 2000 Sven Verdoolaege + + o small documentation fix + o compilation issues with older perls fixed + o library initialization when using sockets fixed + +Version 0.54 -- 8 October 2000 Sven Verdoolaege + + o library fixes ("Rob Saccoccio" ) + o compilation issues with newer gcc + o completely untested OPEN and READLINE methods + +Version 0.53 -- 10 July 2000 Sven Verdoolaege + + o sfio version compiles again + +Version 0.52 -- 12 April 2000 Sven Verdoolaege + +Version 0.51 -- 12 April 2000 Sven Verdoolaege + +Version 0.50 -- 10 April 2000 Sven Verdoolaege + +Version 0.49 -- 9 April 2000 Sven Verdoolaege + + o General clean-ups + o Allow attaching/detaching + o Changed DESTROY behaviour + o Fixed default warn/die handler of old interface + o Document new interface + +Version 0.48 -- 27 August 1999 Sven Verdoolaege + + o perl 5.005_60 compatibility + o locking on platforms that need it + o support for remote connections + +Version 0.47 -- 31 July 1999 Sven Verdoolaege + + o move PRINTF into correct package + o deprecated set_exit_status + o general cleanup, moving old non thread safe interface + from xs to perl + +Version 0.46 -- 30 July 1999 Sven Verdoolaege + + o new thread safe interface + o new threaded example program + +Version 0.45 -- 8 March 1999 Sven Verdoolaege + + o FCGI.pm now part of the devel kit + o library fixes ("Rob Saccoccio" ) + o allow bypassing of installation of handlers + o ActivePerl compatibility (Murray Nesbitt ) + +Version 0.43 -- 22 December 1998 Sven Verdoolaege + + o POST on bigendians (Paul GABORIT ) + o Some win32 changes (Monty ) + o library fixes ("Rob Saccoccio" ) + +Version 0.42 -- 28 August 1998 Sven Verdoolaege + + o environ fixes ? + o print NULLs (Ken Alexander ) + o PRINTF support + o set version in FCGI.pm + o library fixes ("Rob Saccoccio" ) + +Version 0.41 -- 29 July 1998 Sven Verdoolaege + + o Compiles with perl 5.005 + +Version 0.40 -- 15 July 1998 Sven Verdoolaege + + o Added default die hook + o Minimal documentation + +Version 0.39 -- 3 July 1998 Sven Verdoolaege + + o Fixed read bug + +Version 0.38 -- 28 June 1998 Sven Verdoolaege + + o Fixed flush bug + o Added default warn hook + +Version 0.37 -- 27 June 1998 Sven Verdoolaege + + o More support for tied handles + o Added flush function + +Version 0.36 -- 23 June 1998 Sven Verdoolaege + + o More support for tied handles (GETC and autoflushing) + +Version 0.35 -- 22 June 1998 Sven Verdoolaege + + o Added forgotten typemap + +Version 0.34 -- 17 June 1998 Sven Verdoolaege + + o No longer force sfio less compile + o Update os_unix.c from fcgi2.0b2.1 + o Small documentation changes + +Version 0.33 -- 16 June 1998 Sven Verdoolaege + + o More support for tied handles + +Version 0.32 -- 16 June 1998 Sven Verdoolaege + + o Preliminary support for tied handles (doesn't require sfio) + o Force sfio less compile + o Changed protoype of set_exit_status + +Version 0.31 -- 13 July 1997 Sven Verdoolaege + + o Applied solaris accept patch from + Chip Salzenberg + o Preliminary support glibc's cookie mechanism + +Version 0.30 -- 24 June 1997 Sven Verdoolaege + + o Added forgotten library files + +Version 0.29 -- 10 June 1997 Sven Verdoolaege + + o Updated library files from fastcgi 2.02b + o Use installed library/include file if found + +Version 0.28 -- 24 February 1997 Sven Verdoolaege + + o Intialization of %ENV did not change environ. Fixed. + Problem reported by Jan Drehmer + +Version 0.26 -- 19 February 1997 Sven Verdoolaege + + o Flush output when $| is set to eliminate a problem reported + by echo@echo.cica.fr + +Version 0.25 -- 13 October 1996 Sven Verdoolaege + + o Eliminate some warnings + o Check whether perl is compiled with sfio support + +Version 0.25 -- 25 September 1996 Sven Verdoolaege + + o First public release + o Additional bugfixes + +Version 0.21 -- 20 September 1996 Sven Verdoolaege + + o Bugfix + +Version 0.2 -- 19 September 1996 Sven Verdoolaege + + o First Version based on sfio + +Version 0.1 -- 12 June 1996 + + o Original version from Open Market's FastCGI Developer's Kit diff --git a/iipsrv/fcgi/perl/FCGI.PL b/iipsrv/fcgi/perl/FCGI.PL new file mode 100644 index 0000000..b1b4dfc --- /dev/null +++ b/iipsrv/fcgi/perl/FCGI.PL @@ -0,0 +1,570 @@ +use Config; +use ExtUtils::MakeMaker; + +do 'FCGI.cfg' or die "no FCGI.cfg"; + +open OUT, ">FCGI.pm"; + +print "Generating FCGI.pm\n"; +print OUT <<'EOP'; +# $Id: FCGI.PL,v 1.37 2002/12/15 20:02:48 skimo Exp $ + +package FCGI; + +require Exporter; +require DynaLoader; + +@ISA = qw(Exporter DynaLoader); +# Items to export into callers namespace by default. Note: do not export +# names by default without a very good reason. Use EXPORT_OK instead. +# Do not simply export all your public functions/methods/constants. +@EXPORT = qw( + +); + +EOP + +print OUT '$VERSION = '.MM->parse_version('version.pm').";\n\n"; + +print OUT "bootstrap FCGI;\n" unless ($pure); + +print OUT <<'EOP' if ($pure); +use Symbol; +use POSIX 'ENOTCONN'; + +use constant VERSION_1 => 1; + +use constant BEGIN_REQUEST => 1; +use constant PARAMS => 4; +use constant FCGI_STDIN => 5; +use constant FCGI_STDOUT => 6; +use constant FCGI_STDERR => 7; + +use constant RESPONDER => 1; +use constant AUTHORIZER => 2; +use constant FILTER => 3; + +%FCGI::rolenames = (RESPONDER, "RESPONDER", + AUTHORIZER, "AUTHORIZER", + FILTER, "FILTER", + ); + +# This only works on Unix; anyone familiar with Windows is welcome +# to give a hand here +sub IsFastCGI { + my ($req) = @_; + $req->{isfastcgi} = + (!defined getpeername shift->{listen_sock}) && $! == ENOTCONN + unless exists $req->{isfastcgi}; + return $req->{isfastcgi}; +} + +sub GetEnvironment { + return shift->{'env'}; +} + +sub read_nv_len { + my ($stream) = @_; + my $buf; + return undef unless read $stream, $buf, 1, 0; + my ($len) = unpack("C", $buf); + if ($len & 0x80) { + $buf = pack("C", $len & 0x7F); + return undef unless read $stream, $buf, 3, 1; + $len = unpack("N", $buf); + } + $len; +} + +sub RequestX { + my $self = { + in => shift, + out => shift, + err => shift, + env => shift, + socket => shift, + flags => shift, + last => 0, + }; + open $self->{listen_sock}, "<&=0"; + bless $self, "FCGI"; +} + +my $run_once = 0; + +sub Accept { + my ($req) = @_; + + unless ($req->IsFastCGI()) { + return -1 if $run_once; + + $run_once = 1; + return 0; + } + $req->Finish(); + $req->{socket} = gensym(); + if ($req->{last} || !accept($req->{socket}, $req->{listen_sock})) { + $req->{error} = "accept"; + return -1; + } + my ($type, $id, $body) = $req->read_record(); + if ($type != BEGIN_REQUEST) { + $req->{error} = "begin request"; + return -1; + } + my ($role, $flags) = unpack("nC", $body); + $req->{role} = $role; + $req->{flags} = $flags; + $req->{id} = $id; + + %{$req->{env}} = (); + $req->{env}{FCGI_ROLE} = $FCGI::rolenames{$req->{role}}; + my $param = FCGI::Stream->new($req, PARAMS); + my ($nlen, $vlen); + while (defined($nlen = read_nv_len($param)) && + defined($vlen = read_nv_len($param))) { + my ($name, $val); + read $param, $name, $nlen; + read $param, $val, $vlen; + $req->{env}{$name} = $val; + } + $req->Bind; + $req->{accepted} = 1; + + return 0; +} + +sub UndoBindings { + my ($req) = @_; + untie ${$req->{in}}; + untie ${$req->{out}}; + untie ${$req->{err}}; + $req->{bound} = 0; +} + +sub Bind { + my ($req) = @_; + tie ${$req->{in}}, 'FCGI::Stream', $req, FCGI_STDIN; + tie ${$req->{out}}, 'FCGI::Stream', $req, FCGI_STDOUT; + tie ${$req->{err}}, 'FCGI::Stream', $req, FCGI_STDERR; + $req->{bound} = 1; +} + +sub Attach { + my ($req) = @_; + $req->Bind() if ($req->{accepted} && !$req->{bound}); +} + +sub Detach { + my ($req) = @_; + $req->UndoBindings() if ($req->{accepted} && $req->{bound}); +} + +sub Finish { + my ($req) = @_; + return unless $req->{accepted}; + if ($req->{bound}) { + $req->UndoBindings(); + # apparently these are harmful + # close ${$req->{out}}; + # close ${$req->{err}}; + } + $req->{accepted} = 0; +} + +sub LastCall { + shift->{last} = 1; +} + +sub DESTROY { + shift->Finish(); +} + +sub read_record { + my ($self) = @_; + my ($header, $body); + + read($self->{socket}, $header, 8); + my ($version, $type, $id, $clen, $plen) = unpack("CCnnC", $header); + read($self->{socket}, $body, $clen+$plen); + $body = undef if $clen == 0; + ($type, $id, $body); +} + +sub read { + my ($self, $rtype, $len) = @_; + while (length $self->{buf} < $len) { + my ($type, $id, $buf) = $self->read_record(); + return undef unless defined $buf; + if ($type != $rtype) { + $self->{error} = "unexpected stream type"; + return 0; + } + $self->{buf} .= $buf; + } + my ($newbuf, $result) = (substr($self->{buf}, $len), + substr($self->{buf}, 0, $len)); + $self->{buf} = $newbuf; + $result; +} + +sub Flush { + my ($req) = @_; +} + +sub write { + my ($self, $type, $content, $len) = @_; + return unless $len > 0; + $self->write_record($type, $content, $len); +} + +sub write_record { + my ($self, $type, $content, $length) = @_; + my $offset = 0; + while ($length > 0) { + my $len = $length > 32*1024 ? 32*1024 : $length; + my $padlen = (8 - ($len % 8)) % 8; + my $templ = "CCnnCxa${len}x$padlen"; + my $data = pack($templ, + VERSION_1, $type, $self->{id}, $len, $padlen, + substr($content, $offset, $len)); + syswrite $self->{socket}, $data; + $length -= $len; + $offset += $len; + } +} + +{ package FCGI::Stream; + +sub new { + my ($class, $src, $type) = @_; + my $handle = do { \local *FH }; + tie($$handle, $class, $src, $type); + $handle; +} + +sub TIEHANDLE { + my ($class, $src, $type) = @_; + bless { src => $src, type => $type }, $class; +} + +sub READ { + my ($stream, undef, $len, $offset) = @_; + my ($ref) = \$_[1]; + my $buf = $stream->{src}->read($stream->{type}, $len); + return undef unless defined $buf; + substr($$ref, $offset, 0, $buf); + length $buf; +} + +sub PRINT { + my ($stream) = shift; + for (@_) { + $stream->{src}->write($stream->{type}, $_, length($_)); + } +} + +sub CLOSE { + my ($stream) = @_; + $stream->{src}->write_record($stream->{type}, undef, 0); +} + +} + +EOP +print OUT while ; +close OUT; +__END__ + +# Preloaded methods go here. + +# Autoload methods go after __END__, and are processed by the autosplit program. + +*FAIL_ACCEPT_ON_INTR = sub() { 1 }; + +sub Request(;***$*$) { + my @defaults = (\*STDIN, \*STDOUT, \*STDERR, \%ENV, 0, 0); + $_[4] = fileno($_[4]) if defined($_[4]) && defined(fileno($_[4])); + splice @defaults,0,@_,@_; + RequestX(@defaults); +} + +sub accept() { + warn "accept called as a method; you probably wanted to call Accept" if @_; + if (defined %FCGI::ENV) { + %ENV = %FCGI::ENV; + } else { + %FCGI::ENV = %ENV; + } + my $rc = Accept($global_request); + for (keys %FCGI::ENV) { + $ENV{$_} = $FCGI::ENV{$_} unless exists $ENV{$_}; + } + + # not SFIO + $SIG{__WARN__} = $warn_handler if (tied (*STDIN)); + $SIG{__DIE__} = $die_handler if (tied (*STDIN)); + + return $rc; +} + +sub finish() { + warn "finish called as a method; you probably wanted to call Finish" if @_; + %ENV = %FCGI::ENV if (defined %FCGI::ENV); + + # not SFIO + if (tied (*STDIN)) { + delete $SIG{__WARN__} if ($SIG{__WARN__} == $warn_handler); + delete $SIG{__DIE__} if ($SIG{__DIE__} == $die_handler); + } + + Finish ($global_request); +} + +sub flush() { + warn "flush called as a method; you probably wanted to call Flush" if @_; + Flush($global_request); +} + +sub detach() { + warn "detach called as a method; you probably wanted to call Detach" if @_; + Detach($global_request); +} + +sub attach() { + warn "attach called as a method; you probably wanted to call Attach" if @_; + Attach($global_request); +} + +# deprecated +sub set_exit_status { +} + +sub start_filter_data() { + StartFilterData($global_request); +} + +$global_request = Request(); +$warn_handler = sub { print STDERR @_ }; +$die_handler = sub { print STDERR @_ unless $^S }; + +package FCGI::Stream; + +sub PRINTF { + shift->PRINT(sprintf(shift, @_)); +} + +sub BINMODE { +} + +sub READLINE { + my $stream = shift; + my ($s, $c); + my $rs = $/ eq '' ? "\n\n" : $/; + my $l = substr $rs, -1; + my $len = length $rs; + + $c = $stream->GETC(); + if ($/ eq '') { + while ($c eq "\n") { + $c = $stream->GETC(); + } + } + while (defined $c) { + $s .= $c; + last if $c eq $l and substr($s, -$len) eq $rs; + $c = $stream->GETC(); + } + $s; +} + +sub OPEN { + $_[0]->CLOSE; + if (@_ == 2) { + return open($_[0], $_[1]); + } else { + my $rc; + eval("$rc = open($_[0], $_[1], $_[2])"); + die $@ if $@; + return $rc; + } +} + +# Apparently some use fileno to determine if a filehandle is open, +# so we might want to return a defined, but meaningless value. +# An alternative would be to return the fcgi stream fd. +# sub FILENO { -2 } + +1; + +=pod + +=head1 NAME + +FCGI - Fast CGI module + +=head1 SYNOPSIS + + use FCGI; + + my $count = 0; + my $request = FCGI::Request(); + + while($request->Accept() >= 0) { + print("Content-type: text/html\r\n\r\n", ++$count); + } + +=head1 DESCRIPTION + +Functions: + +=over 4 + +=item FCGI::Request + +Creates a request handle. It has the following optional parameters: + +=over 8 + +=item input perl file handle (default: \*STDIN) + +=item output perl file handle (default: \*STDOUT) + +=item error perl file handle (default: \*STDERR) + +These filehandles will be setup to act as input/output/error +on succesful Accept. + +=item environment hash reference (default: \%ENV) + +The hash will be populated with the environment. + +=item socket (default: 0) + +Socket to communicate with the server. +Can be the result of the OpenSocket function. +For the moment, it's the file descriptor of the socket +that should be passed. This may change in the future. + +You should only use your own socket if your program +is not started by a process manager such as mod_fastcgi +(except for the FastCgiExternalServer case) or cgi-fcgi. +If you use the option, you have to let your FastCGI +server know which port (and possibly server) your program +is listening on. +See remote.pl for an example. + +=item flags (default: 0) + +Possible values: + +=over 12 + +=item FCGI::FAIL_ACCEPT_ON_INTR + +If set, Accept will fail if interrupted. +It not set, it will just keep on waiting. + +=back + +=back + +Example usage: + my $req = FCGI::Request; + +or: + my %env; + my $in = new IO::Handle; + my $out = new IO::Handle; + my $err = new IO::Handle; + my $req = FCGI::Request($in, $out, $err, \%env); + +=item FCGI::OpenSocket(path, backlog) + +Creates a socket suitable to use as an argument to Request. + +=over 8 + +=item path + +Pathname of socket or colon followed by local tcp port. +Note that some systems take file permissions into account +on Unix domain sockets, so you'll have to make sure that +the server can write to the created file, by changing +the umask before the call and/or changing permissions and/or +group of the file afterwards. + +=item backlog + +Maximum length of the queue of pending connections. +If a connection +request arrives with the queue full the client may receive +an error with an indication of ECONNREFUSED. + +=back + +=item FCGI::CloseSocket(socket) + +Close a socket opened with OpenSocket. + +=item $req->Accept() + +Accepts a connection on $req, attaching the filehandles and +populating the environment hash. +Returns 0 on success. +If a connection has been accepted before, the old +one will be finished first. + +Note that unlike with the old interface, no die and warn +handlers are installed by default. This means that if +you are not running an sfio enabled perl, any warn or +die message will not end up in the server's log by default. +It is advised you set up die and warn handlers yourself. +FCGI.pm contains an example of die and warn handlers. + +=item $req->Finish() + +Finishes accepted connection. +Also detaches filehandles. + +=item $req->Flush() + +Flushes accepted connection. + +=item $req->Detach() + +Temporarily detaches filehandles on an accepted connection. + +=item $req->Attach() + +Re-attaches filehandles on an accepted connection. + +=item $req->LastCall() + +Tells the library not to accept any more requests on this handle. +It should be safe to call this method from signal handlers. + +Note that this method is still experimental and everything +about it, including its name, is subject to change. + +=item $env = $req->GetEnvironment() + +Returns the environment parameter passed to FCGI::Request. + +=item ($in, $out, $err) = $req->GetHandles() + +Returns the file handle parameters passed to FCGI::Request. + +=item $isfcgi = $req->IsFastCGI() + +Returns whether or not the program was run as a FastCGI. + +=back + +=head1 AUTHOR + +Sven Verdoolaege + +=cut + +__END__ diff --git a/iipsrv/fcgi/perl/FCGI.XL b/iipsrv/fcgi/perl/FCGI.XL new file mode 100644 index 0000000..01742cc --- /dev/null +++ b/iipsrv/fcgi/perl/FCGI.XL @@ -0,0 +1,625 @@ +use Config; + +open OUT, ">FCGI.xs"; + +print "Generating FCGI.xs for Perl version $]\n"; +#unless (exists $Config{apiversion} && $Config{apiversion} >= 5.005) +unless ($] >= 5.005) { + for (qw(sv_undef diehook warnhook in_eval)) { + print OUT "#define PL_$_ $_\n" + } +} +print OUT while ; +close OUT; +__END__ +/* $Id: FCGI.XL,v 1.9 2002/11/11 13:51:20 skimo Exp $ */ + +#include "EXTERN.h" +#include "perl.h" +#include "XSUB.h" + +#include "fcgi_config.h" +#include "fcgiapp.h" +#include "fastcgi.h" + +#ifndef FALSE +#define FALSE (0) +#endif + +#ifndef TRUE +#define TRUE (1) +#endif + +#ifndef dTHX +#define dTHX +#endif + +#ifndef INT2PTR +#define INT2PTR(a,b) ((a) (b)) +#endif + +#ifdef USE_SFIO +typedef struct +{ + Sfdisc_t disc; + FCGX_Stream *stream; +} FCGI_Disc; + +static ssize_t +sffcgiread(f, buf, n, disc) +Sfio_t* f; /* stream involved */ +Void_t* buf; /* buffer to read into */ +size_t n; /* number of bytes to read */ +Sfdisc_t* disc; /* discipline */ +{ + return FCGX_GetStr(buf, n, ((FCGI_Disc *)disc)->stream); +} + +static ssize_t +sffcgiwrite(f, buf, n, disc) +Sfio_t* f; /* stream involved */ +const Void_t* buf; /* buffer to read into */ +size_t n; /* number of bytes to read */ +Sfdisc_t* disc; /* discipline */ +{ + n = FCGX_PutStr(buf, n, ((FCGI_Disc *)disc)->stream); + FCGX_FFlush(((FCGI_Disc *)disc)->stream); + return n; +} + +Sfdisc_t * +sfdcnewfcgi(stream) + FCGX_Stream *stream; +{ + FCGI_Disc* disc; + + New(1000,disc,1,FCGI_Disc); + if (!disc) return (Sfdisc_t *)disc; + + disc->disc.exceptf = (Sfexcept_f)NULL; + disc->disc.seekf = (Sfseek_f)NULL; + disc->disc.readf = sffcgiread; + disc->disc.writef = sffcgiwrite; + disc->stream = stream; + return (Sfdisc_t *)disc; +} + +Sfdisc_t * +sfdcdelfcgi(disc) + Sfdisc_t* disc; +{ + Safefree(disc); + return 0; +} +#endif + +#if defined(USE_LOCKING) && defined(USE_THREADS) +static perl_mutex accept_mutex; +#endif + +typedef struct FCGP_Request { + int accepted; + int bound; + SV* svin; + SV* svout; + SV* sverr; + GV* gv[3]; + HV* hvEnv; + FCGX_Request* requestPtr; +#ifdef USE_SFIO + int sfcreated[3]; + IO* io[3]; +#endif +} FCGP_Request; + +static void FCGI_Finish(FCGP_Request* request); + +static void +FCGI_Flush(FCGP_Request* request) +{ + dTHX; + + if(!request->bound) { + return; + } +#ifdef USE_SFIO + sfsync(IoOFP(GvIOp(request->gv[1]))); + sfsync(IoOFP(GvIOp(request->gv[2]))); +#else + FCGX_FFlush(INT2PTR(FCGX_Stream *, SvIV((SV*) SvRV(request->svout)))); + FCGX_FFlush(INT2PTR(FCGX_Stream *, SvIV((SV*) SvRV(request->sverr)))); +#endif +} + +static void +FCGI_UndoBinding(FCGP_Request* request) +{ + dTHX; + +#ifdef USE_SFIO + sfdcdelfcgi(sfdisc(IoIFP(request->io[0]), SF_POPDISC)); + sfdcdelfcgi(sfdisc(IoOFP(request->io[1]), SF_POPDISC)); + sfdcdelfcgi(sfdisc(IoOFP(request->io[2]), SF_POPDISC)); +#else +# ifdef USE_PERLIO + sv_unmagic((SV *)GvIOp(request->gv[0]), 'q'); + sv_unmagic((SV *)GvIOp(request->gv[1]), 'q'); + sv_unmagic((SV *)GvIOp(request->gv[2]), 'q'); +# else + sv_unmagic((SV *)request->gv[0], 'q'); + sv_unmagic((SV *)request->gv[1], 'q'); + sv_unmagic((SV *)request->gv[2], 'q'); +# endif +#endif + request->bound = FALSE; +} + +static void +FCGI_Bind(FCGP_Request* request) +{ + dTHX; + +#ifdef USE_SFIO + sfdisc(IoIFP(request->io[0]), sfdcnewfcgi(request->requestPtr->in)); + sfdisc(IoOFP(request->io[1]), sfdcnewfcgi(request->requestPtr->out)); + sfdisc(IoOFP(request->io[2]), sfdcnewfcgi(request->requestPtr->err)); +#else +# ifdef USE_PERLIO + /* For tied filehandles, we apply tiedscalar magic to the IO + slot of the GP rather than the GV itself. */ + + if (!GvIOp(request->gv[1])) + GvIOp(request->gv[1]) = newIO(); + if (!GvIOp(request->gv[2])) + GvIOp(request->gv[2]) = newIO(); + if (!GvIOp(request->gv[0])) + GvIOp(request->gv[0]) = newIO(); + + sv_magic((SV *)GvIOp(request->gv[1]), request->svout, 'q', Nullch, 0); + sv_magic((SV *)GvIOp(request->gv[2]), request->sverr, 'q', Nullch, 0); + sv_magic((SV *)GvIOp(request->gv[0]), request->svin, 'q', Nullch, 0); +# else + sv_magic((SV *)request->gv[1], request->svout, 'q', Nullch, 0); + sv_magic((SV *)request->gv[2], request->sverr, 'q', Nullch, 0); + sv_magic((SV *)request->gv[0], request->svin, 'q', Nullch, 0); +# endif +#endif + request->bound = TRUE; +} + +static void +populate_env(envp, hv) +char **envp; +HV *hv; +{ + int i; + char *p, *p1; + SV *sv; + dTHX; + + hv_clear(hv); + for(i = 0; ; i++) { + if((p = envp[i]) == NULL) { + break; + } + p1 = strchr(p, '='); + assert(p1 != NULL); + sv = newSVpv(p1 + 1, 0); + /* call magic for this value ourselves */ + hv_store(hv, p, p1 - p, sv, 0); + SvSETMAGIC(sv); + } +} + +static int +FCGI_IsFastCGI(FCGP_Request* request) +{ + static int isCGI = -1; /* -1: not checked; 0: FCGI; 1: CGI */ + + if (request->requestPtr->listen_sock == FCGI_LISTENSOCK_FILENO) { + if (isCGI == -1) + isCGI = FCGX_IsCGI(); + return !isCGI; + } + + /* A explicit socket is being used -> assume FastCGI */ + return 1; +} + +static int +FCGI_Accept(FCGP_Request* request) +{ + dTHX; + + if (!FCGI_IsFastCGI(request)) { + static int been_here = 0; + + /* + * Not first call to FCGI_Accept and running as CGI means + * application is done. + */ + if (been_here) + return EOF; + + been_here = 1; + } else { +#ifdef USE_SFIO + int i; +#endif + FCGX_Request *fcgx_req = request->requestPtr; + int acceptResult; + + FCGI_Finish(request); +#if defined(USE_LOCKING) && defined(USE_THREADS) + MUTEX_LOCK(&accept_mutex); +#endif + acceptResult = FCGX_Accept_r(fcgx_req); +#if defined(USE_LOCKING) && defined(USE_THREADS) + MUTEX_UNLOCK(&accept_mutex); +#endif + if(acceptResult < 0) { + return acceptResult; + } + + populate_env(fcgx_req->envp, request->hvEnv); + +#ifdef USE_SFIO + for (i = 0; i < 3; ++i) { + request->io[i] = GvIOn(request->gv[i]); + if (!(i == 0 ? IoIFP(request->io[i]) + : IoOFP(request->io[i]))) { + IoIFP(request->io[i]) = sftmp(0); + /*IoIFP(request->io[i]) = sfnew(NULL, NULL, SF_UNBOUND, 0, + SF_STRING | (i ? SF_WRITE : SF_READ));*/ + if (i != 0) + IoOFP(request->io[i]) = IoIFP(request->io[i]); + request->sfcreated[i] = TRUE; + } + } +#else + if (!request->svout) { + newSVrv(request->svout = newSV(0), "FCGI::Stream"); + newSVrv(request->sverr = newSV(0), "FCGI::Stream"); + newSVrv(request->svin = newSV(0), "FCGI::Stream"); + } + sv_setiv(SvRV(request->svout), INT2PTR(IV, fcgx_req->out)); + sv_setiv(SvRV(request->sverr), INT2PTR(IV, fcgx_req->err)); + sv_setiv(SvRV(request->svin), INT2PTR(IV, fcgx_req->in)); +#endif + FCGI_Bind(request); + request->accepted = TRUE; + } + return 0; +} + +static void +FCGI_Finish(FCGP_Request* request) +{ +#ifdef USE_SFIO + int i; +#endif + int was_bound; + dTHX; + + if(!request->accepted) { + return; + } + + if (was_bound = request->bound) { + FCGI_UndoBinding(request); + } +#ifdef USE_SFIO + for (i = 0; i < 3; ++i) { + if (request->sfcreated[i]) { + sfclose(IoIFP(request->io[i])); + IoIFP(request->io[i]) = IoOFP(request->io[i]) = Nullfp; + request->sfcreated[i] = FALSE; + } + } +#endif + if (was_bound) + FCGX_Finish_r(request->requestPtr); + else + FCGX_Free(request->requestPtr, 1); + request->accepted = FALSE; +} + +static int +FCGI_StartFilterData(FCGP_Request* request) +{ + return request->requestPtr->in ? + FCGX_StartFilterData(request->requestPtr->in) : -1; +} + +static FCGP_Request * +FCGI_Request(in, out, err, env, socket, flags) + GV* in; + GV* out; + GV* err; + HV* env; + int socket; + int flags; +{ + FCGX_Request* fcgx_req; + FCGP_Request* req; + + Newz(551, fcgx_req, 1, FCGX_Request); + FCGX_InitRequest(fcgx_req, socket, flags); + Newz(551, req, 1, FCGP_Request); + req->requestPtr = fcgx_req; + SvREFCNT_inc(in); + req->gv[0] = in; + SvREFCNT_inc(out); + req->gv[1] = out; + SvREFCNT_inc(err); + req->gv[2] = err; + SvREFCNT_inc(env); + req->hvEnv = env; + + return req; +} + +static void +FCGI_Release_Request(FCGP_Request *req) +{ + SvREFCNT_dec(req->gv[0]); + SvREFCNT_dec(req->gv[1]); + SvREFCNT_dec(req->gv[2]); + SvREFCNT_dec(req->hvEnv); + FCGI_Finish(req); + Safefree(req->requestPtr); + Safefree(req); +} + +static void +FCGI_Init() +{ +#if defined(USE_LOCKING) && defined(USE_THREADS) + dTHX; + + MUTEX_INIT(&accept_mutex); +#endif + + FCGX_Init(); +} + +typedef FCGX_Stream * FCGI__Stream; +typedef FCGP_Request * FCGI; +typedef GV* GLOBREF; +typedef HV* HASHREF; + +MODULE = FCGI PACKAGE = FCGI PREFIX = FCGI_ + +BOOT: + FCGI_Init(); + +SV * +RequestX(in, out, err, env, socket, flags) + GLOBREF in; + GLOBREF out; + GLOBREF err; + HASHREF env; + int socket; + int flags; + + PROTOTYPE: ***$$$ + CODE: + RETVAL = sv_setref_pv(newSV(0), "FCGI", + FCGI_Request(in, out, err, env, socket, flags)); + + OUTPUT: + RETVAL + +int +OpenSocket(path, backlog) + char* path; + int backlog; + + PROTOTYPE: $$ + CODE: + RETVAL = FCGX_OpenSocket(path, backlog); + OUTPUT: + RETVAL + +void +CloseSocket(socket) + int socket; + + PROTOTYPE: $ + CODE: + close(socket); + +int +FCGI_Accept(request) + + FCGI request; + + PROTOTYPE: $ + +void +FCGI_Finish(request) + FCGI request; + + PROTOTYPE: $ + +void +FCGI_Flush(request) + FCGI request; + + PROTOTYPE: $ + +HV * +GetEnvironment(request) + FCGI request; + + PROTOTYPE: $ + + CODE: + RETVAL = request->hvEnv; + + OUTPUT: + RETVAL + +void +GetHandles(request) + FCGI request; + + PROTOTYPE: $ + + PREINIT: + int i; + + PPCODE: + EXTEND(sp,3); + for (i = 0; i < 3; ++i) + PUSHs(sv_2mortal(newRV((SV *) request->gv[i]))); + +int +FCGI_IsFastCGI(request) + FCGI request; + + PROTOTYPE: $ + +void +Detach(request) + FCGI request; + + PROTOTYPE: $ + + CODE: + if (request->accepted && request->bound) + FCGI_UndoBinding(request); + +void +Attach(request) + FCGI request; + + PROTOTYPE: $ + + CODE: + if (request->accepted && !request->bound) + FCGI_Bind(request); + +void +LastCall(request) + FCGI request; + + PROTOTYPE: $ + + CODE: + FCGX_ShutdownPending(); + +int +FCGI_StartFilterData(request) + + FCGI request; + + PROTOTYPE: $ + +void +DESTROY(request) + FCGI request; + + CODE: + FCGI_Release_Request(request); + + + +MODULE = FCGI PACKAGE = FCGI::Stream + +#ifndef USE_SFIO + +void +PRINT(stream, ...) + FCGI::Stream stream; + + PREINIT: + int n; + + CODE: + for (n = 1; n < items; ++n) { + STRLEN len; + register char *tmps = (char *)SvPV(ST(n),len); + FCGX_PutStr(tmps, len, stream); + } + if (SvTRUEx(perl_get_sv("|", FALSE))) + FCGX_FFlush(stream); + +int +WRITE(stream, bufsv, len, ...) + FCGI::Stream stream; + SV * bufsv; + int len; + + PREINIT: + int offset; + char * buf; + STRLEN blen; + int n; + + CODE: + offset = (items == 4) ? (int)SvIV(ST(3)) : 0; + buf = SvPV(bufsv, blen); + if (offset < 0) offset += blen; + if (len > blen - offset) + len = blen - offset; + if (offset < 0 || offset >= blen || + (n = FCGX_PutStr(buf+offset, len, stream)) < 0) + ST(0) = &PL_sv_undef; + else { + ST(0) = sv_newmortal(); + sv_setpvf(ST(0), "%c", n); + } + +int +READ(stream, bufsv, len, ...) + FCGI::Stream stream; + SV * bufsv; + int len; + + PREINIT: + int offset; + char * buf; + + CODE: + offset = (items == 4) ? (int)SvIV(ST(3)) : 0; + if (! SvOK(bufsv)) + sv_setpvn(bufsv, "", 0); + buf = SvGROW(bufsv, len+offset+1); + len = FCGX_GetStr(buf+offset, len, stream); + SvCUR_set(bufsv, len+offset); + *SvEND(bufsv) = '\0'; + (void)SvPOK_only(bufsv); + SvSETMAGIC(bufsv); + RETVAL = len; + + OUTPUT: + RETVAL + +SV * +GETC(stream) + FCGI::Stream stream; + + PREINIT: + int retval; + + CODE: + if ((retval = FCGX_GetChar(stream)) != -1) { + ST(0) = sv_newmortal(); + sv_setpvf(ST(0), "%c", retval); + } else ST(0) = &PL_sv_undef; + +bool +CLOSE(stream) + FCGI::Stream stream; + +# ALIAS: +# DESTROY = 1 + + CODE: + RETVAL = FCGX_FClose(stream) != -1; + + OUTPUT: + RETVAL + +#endif diff --git a/iipsrv/fcgi/perl/MANIFEST b/iipsrv/fcgi/perl/MANIFEST new file mode 100644 index 0000000..07ded82 --- /dev/null +++ b/iipsrv/fcgi/perl/MANIFEST @@ -0,0 +1,16 @@ +ChangeLog +FCGI.PL +FCGI.XL +MANIFEST +Makefile.PL +README +configure +configure.in +configure.readme +echo.PL +fcgi_config.h.in +remote.PL +test.pl +threaded.PL +typemap +version.pm diff --git a/iipsrv/fcgi/perl/Makefile.PL b/iipsrv/fcgi/perl/Makefile.PL new file mode 100644 index 0000000..380e5f8 --- /dev/null +++ b/iipsrv/fcgi/perl/Makefile.PL @@ -0,0 +1,156 @@ +# $Id: Makefile.PL,v 1.33 2002/12/15 19:40:19 skimo Exp $ + +use ExtUtils::MakeMaker; +use IO::File; +use Config; +use Cwd 'cwd'; +use Getopt::Long; + +@h1 = qw(fastcgi.h fcgiapp.h fcgimisc.h fcgios.h); +@h = (@h1, 'fcgi_config.h'); +@o = qw(FCGI.o); +@dist1 = qw(LICENSE.TERMS); +@dist2 = qw(fcgiapp.c os_unix.c os_win32.c); +@dist3 = (@h1, qw(fcgi_config_x86.h)); + +GetOptions ("pure-perl!" => \$pure, + "use-installed:s" => \$useinstalled); +$pure = "0" unless defined $pure; +open(CFG,">FCGI.cfg"); +print CFG "\$pure = $pure;1;\n"; +close CFG; + +$libfound = 0; +@libs = (); + +if (! $pure) { + my $cwd = cwd(); + my $devkit = "$cwd/.."; + + if (defined $useinstalled) { + require ExtUtils::Liblist; + my $libspec = $useinstalled ? "-L$useinstalled/lib " : ""; + $libspec .= "-lfcgi"; + my @l = MM->ext($libspec); + if ($l[0] || $l[1] || $l[2]) { + $prefix = "$useinstalled/include" if $useinstalled; + $libfound = 1; + push @libs, $libspec; + } + } + if (!$libfound && -d "$devkit/libfcgi" && -d "$devkit/include") { + # devkit + if (grep { ! -f "$devkit/include/$_" } @dist3 + or grep { ! -f "$devkit/libfcgi/$_" } @dist2) + { + warn "This appears to be a FastCGI devkit distribution, " . + "but one or more FastCGI library files are missing. \n" . + "Please check the integrity of the distribution.\n"; + exit -1; + } + + my $extrarules = join "\n", + map { $b = $_; $b =~ s/\.c$//; my $s="$devkit/libfcgi/$b.c"; + "$b\$(OBJ_EXT): $s\n\t". + '$(CCCMD) $(CCCDLFLAGS) -I$(PERL_INC) $(DEFINE) '."$s\n"; } + @dist2; + eval 'package MY; sub postamble { $extrarules; }'; + $prefix = $devkit; + } +} + +$sys = $^O eq 'MSWin32' ? 'win32' : 'unix'; +push @o, "fcgiapp.o", "os_$sys.o" unless $libfound; +$inc = '-I.' unless $libfound; +$inc .= " -I$prefix/include" if $prefix; + +push(@extras, CAPI => 'TRUE') + if ($] >= 5.005 and $^O eq 'MSWin32' + and $Config{archname} =~ /-object\b/i); + +push(@extras, + ABSTRACT => 'Fast CGI module', + AUTHOR => 'Sven Verdoolaege (skimo@kotnet.org)') + if ($ExtUtils::MakeMaker::VERSION >= 5.4301); + +$plfiles = { 'echo.PL' => 'echo.fpl', + 'remote.PL' => 'remote.fpl', + 'threaded.PL' => 'threaded.fpl', + 'FCGI.PL' => 'FCGI.pm', + }; +$plfiles->{'FCGI.XL'} = 'FCGI.xs' unless $pure; +if ($pure) { + push @extras, + LINKTYPE => ' '; +} else { + + if ("$sys" eq "win32") { + push @libs, ":nosearch -lws2_32"; + push @extras, 'DEFINE' => '-DDLLAPI=__declspec(dllexport)'; + } + + push @extras, + 'LIBS' => [ "@libs" ], + 'OBJECT' => "@o", + 'INC' => $inc; +} + +# See lib/ExtUtils/MakeMaker.pm for details of how to influence +# the contents of the Makefile that is written. + +# Work around bug in previous versions of MakeMaker +WriteMakefile(NAME => 'FCGI') + if $ExtUtils::MakeMaker::VERSION <= 5.4302; + +$mm = MM->new({ + 'NAME' => 'FCGI', + 'VERSION_FROM' => 'version.pm', + 'dist' => { 'COMPRESS' => 'gzip -9f', + 'SUFFIX' => 'gz', + 'PREOP' => '$(CP) '.join(' ', + map {"../$_"} @dist1, + (map {"libfcgi/$_"} @dist2), + map {"include/$_"} @dist3).' $(DISTVNAME);'. + '$(CP) MANIFEST MANIFEST.old;'. + 'echo -e '. join('\\\n',@dist1,@dist2,@dist3) . + '>> $(DISTVNAME)/MANIFEST', + 'POSTOP' => + '$(MV) MANIFEST.old MANIFEST', + }, + 'clean' => { FILES => 'config.cache fcgi_config.h' . + ' FCGI.xs FCGI.c FCGI.cfg ' . + (join ' ', values %$plfiles)}, + 'PL_FILES' => $plfiles, + PM => {'FCGI.pm' => '$(INST_ARCHLIBDIR)/FCGI.pm'}, + @extras, +}); +# don't install oldinterface pod +delete $mm->{MAN3PODS}{oldinterface.pod}; +$mm->flush; + +exit if -f 'fcgi_config.h' or $libfound or $pure; + +# CPAN and no installed lib found +if ($sys eq "win32") { + # configure will almost certainly not run on a normal NT install, + # use the pregenerated configuration file + + use File::Copy qw(copy); + print "Using prebuilt fcgi_config.h file for Windows\n"; + unlink("fcgi_config.h"); + my $confdir = $prefix ? "$prefix/include/" : ''; + die $! unless copy("${confdir}fcgi_config_x86.h","fcgi_config.h"); + + # Win can't deal with existence of FCGI.xs or absence of FCGI.c + unlink("FCGI.xs"); + open(F, ">FCGI.c"); close(F); + $now = time; $before = $now - 600; + utime $before, $before, "FCGI.c"; + utime $now, $now, "FCGI.PL"; +} else { + print "Running ./configure for you\n"; + print "Please read configure.readme for information on how to run it yourself\n"; + + $ENV{'CC'} = $Config{'cc'}; + system("$Config{sh} configure"); +} diff --git a/iipsrv/fcgi/perl/README b/iipsrv/fcgi/perl/README new file mode 100644 index 0000000..50d96ee --- /dev/null +++ b/iipsrv/fcgi/perl/README @@ -0,0 +1,64 @@ +$Id: README,v 1.7 2001/10/04 08:08:34 skimo Exp $ + + Copyright (c) 1996 Open Market, Inc. + See the file "LICENSE.TERMS" for information on usage and redistribution + of this file, and for a DISCLAIMER OF ALL WARRANTIES. + + Copyright (c) 1996-1998 Sven Verdoolaege + No additional restrictions/warranties. + +This is a Fast CGI module for perl. It's based on the FCGI module +that comes with Open Market's FastCGI Developer's Kit, but does +not require you to recompile perl. + +It even no longer requires perl to be compiled with sfio. +To compile with sfio you'll need at least perl 5.003_02 and you'll have +to have configured it with eg './Configure -Duseperlio -Dusesfio'. +(See the INSTALL file that comes with the perl distribution.) +To compile without sfio you'll need an even more recent perl version. +(perl 5.004 and up should be fine.) + +See http://www.fastcgi.com/ for more information about fastcgi. +Lincoln D. Stein's perl CGI module also contains some information +about fastcgi programming. + +See echo.fpl for an example on how to use this module. + +To install, do the usual + +perl Makefile.PL +make +make install + +If you want to use the (experimental) pure perl version, that +doesn't require a compiler and currently only works on Unix, +you have to pass the --pure-perl option as in +"perl Makefile.PL --pure-perl". + +Note that the pure version does not support Window's Named Pipes. +Support for Named Pipes is not a requirement of the FastCGI specification. +Named Pipes are used by mod_fastcgi and the FastCGI application library as a +replacement for Unix sockets. mod_fastcgi uses Named Pipes on Windows (Unix +sockets on Unix) by default (see the mod_fastcgi docs for more information). + +If you want the module to use a previously installed fcgi library +instead of the included files, use the --use-installed option, +optionally followed by the name of the directory in which it can +be found. + +To configure the library Makefile.PL will run ./configure . +You may want to run it yourself beforehand because its findings +may not always be correct. +The configure.readme file describes how to run ./configure (and only that). + +If you're on a solaris system and your installed fcgi library is 2.02b +or earlier, you'll probably want to use the included files. + +The old interface of the FCGI module installs die and warn +handlers that merely print the error/warning to STDERR (the +default handlers print directly to stderr, which isn't redirected +in the non sfio case). I'm not very happy with the result. +Suggestions welcome. + +Sven Verdoolaege +skimo@kotnet.org diff --git a/iipsrv/fcgi/perl/aclocal.m4 b/iipsrv/fcgi/perl/aclocal.m4 new file mode 100644 index 0000000..1cdf23f --- /dev/null +++ b/iipsrv/fcgi/perl/aclocal.m4 @@ -0,0 +1,472 @@ +# aclocal.m4 generated automatically by aclocal 1.5 + +# Copyright 1996, 1997, 1998, 1999, 2000, 2001 +# Free Software Foundation, Inc. +# This file 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. + +# Like AC_CONFIG_HEADER, but automatically create stamp file. + +# serial 3 + +# When config.status generates a header, we must update the stamp-h file. +# This file resides in the same directory as the config header +# that is generated. We must strip everything past the first ":", +# and everything past the last "/". + +AC_PREREQ([2.12]) + +AC_DEFUN([AM_CONFIG_HEADER], +[ifdef([AC_FOREACH],dnl + [dnl init our file count if it isn't already + m4_ifndef([_AM_Config_Header_Index], m4_define([_AM_Config_Header_Index], [0])) + dnl prepare to store our destination file list for use in config.status + AC_FOREACH([_AM_File], [$1], + [m4_pushdef([_AM_Dest], m4_patsubst(_AM_File, [:.*])) + m4_define([_AM_Config_Header_Index], m4_incr(_AM_Config_Header_Index)) + dnl and add it to the list of files AC keeps track of, along + dnl with our hook + AC_CONFIG_HEADERS(_AM_File, +dnl COMMANDS, [, INIT-CMDS] +[# update the timestamp +echo timestamp >"AS_ESCAPE(_AM_DIRNAME(]_AM_Dest[))/stamp-h]_AM_Config_Header_Index[" +][$2]m4_ifval([$3], [, [$3]]))dnl AC_CONFIG_HEADERS + m4_popdef([_AM_Dest])])],dnl +[AC_CONFIG_HEADER([$1]) + AC_OUTPUT_COMMANDS( + ifelse(patsubst([$1], [[^ ]], []), + [], + [test -z "$CONFIG_HEADERS" || echo timestamp >dnl + patsubst([$1], [^\([^:]*/\)?.*], [\1])stamp-h]),dnl +[am_indx=1 +for am_file in $1; do + case " \$CONFIG_HEADERS " in + *" \$am_file "*) + am_dir=\`echo \$am_file |sed 's%:.*%%;s%[^/]*\$%%'\` + if test -n "\$am_dir"; then + am_tmpdir=\`echo \$am_dir |sed 's%^\(/*\).*\$%\1%'\` + for am_subdir in \`echo \$am_dir |sed 's%/% %'\`; do + am_tmpdir=\$am_tmpdir\$am_subdir/ + if test ! -d \$am_tmpdir; then + mkdir \$am_tmpdir + fi + done + fi + echo timestamp > "\$am_dir"stamp-h\$am_indx + ;; + esac + am_indx=\`expr \$am_indx + 1\` +done]) +])]) # AM_CONFIG_HEADER + +# _AM_DIRNAME(PATH) +# ----------------- +# Like AS_DIRNAME, only do it during macro expansion +AC_DEFUN([_AM_DIRNAME], + [m4_if(m4_regexp([$1], [^.*[^/]//*[^/][^/]*/*$]), -1, + m4_if(m4_regexp([$1], [^//\([^/]\|$\)]), -1, + m4_if(m4_regexp([$1], [^/.*]), -1, + [.], + m4_patsubst([$1], [^\(/\).*], [\1])), + m4_patsubst([$1], [^\(//\)\([^/].*\|$\)], [\1])), + m4_patsubst([$1], [^\(.*[^/]\)//*[^/][^/]*/*$], [\1]))[]dnl +]) # _AM_DIRNAME + +dnl $Id: acinclude.m4,v 1.2 2001/12/21 03:12:50 robs Exp $ + +AC_DEFUN(FCGI_COMMON_CHECKS, [ + AC_CHECK_TYPE([ssize_t], [int]) + + AC_MSG_CHECKING([for sun_len in sys/un.h]) + AC_EGREP_HEADER([sun_len], [sys/un.h], + [AC_MSG_RESULT([yes]) + AC_DEFINE([HAVE_SOCKADDR_UN_SUN_LEN], [1], + [Define if sockaddr_un in sys/un.h contains a sun_len component])], + AC_MSG_RESULT([no])) + + AC_MSG_CHECKING([for fpos_t in stdio.h]) + AC_EGREP_HEADER([fpos_t], [stdio.h], + [AC_MSG_RESULT([yes]) + AC_DEFINE([HAVE_FPOS], [1], + [Define if the fpos_t typedef is in stdio.h])], + AC_MSG_RESULT([no])) + + AC_CHECK_HEADERS([sys/socket.h netdb.h netinet/in.h arpa/inet.h]) + AC_CHECK_HEADERS([sys/time.h limits.h sys/param.h unistd.h]) + + AC_MSG_CHECKING([for a fileno() prototype in stdio.h]) + AC_EGREP_HEADER([fileno], [stdio.h], + [AC_MSG_RESULT([yes]) + AC_DEFINE([HAVE_FILENO_PROTO], [1], + [Define if there's a fileno() prototype in stdio.h])], + AC_MSG_RESULT([no])) + + if test "$HAVE_SYS_SOCKET_H"; then + AC_MSG_CHECKING([for socklen_t in sys/socket.h]) + AC_EGREP_HEADER([socklen_t], [sys/socket.h], + [AC_MSG_RESULT([yes]) + AC_DEFINE([HAVE_SOCKLEN], [1], + [Define if the socklen_t typedef is in sys/socket.h])], + AC_MSG_RESULT([no])) + fi + + #-------------------------------------------------------------------- + # Do we need cross-process locking on this platform? + #-------------------------------------------------------------------- + AC_MSG_CHECKING([whether cross-process locking is required by accept()]) + case "`uname -sr`" in + IRIX\ 5.* | SunOS\ 5.* | UNIX_System_V\ 4.0) + AC_MSG_RESULT([yes]) + AC_DEFINE([USE_LOCKING], [1], + [Define if cross-process locking is required by accept()]) + ;; + *) + AC_MSG_RESULT([no]) + ;; + esac + + #-------------------------------------------------------------------- + # Does va_arg(arg, long double) crash the compiler? + # hpux 9.04 compiler does and so does Stratus FTX (uses HP's compiler) + #-------------------------------------------------------------------- + AC_MSG_CHECKING([whether va_arg(arg, long double) crashes the compiler]) + AC_TRY_COMPILE([#include ], + [long double lDblArg; va_list arg; lDblArg = va_arg(arg, long double);], + AC_MSG_RESULT([no]), + [AC_MSG_RESULT([yes]) + AC_DEFINE([HAVE_VA_ARG_LONG_DOUBLE_BUG], [1], + [Define if va_arg(arg, long double) crashes the compiler])]) + + AC_C_CONST +]) + + +dnl @synopsis ACX_PTHREAD([ACTION-IF-FOUND[, ACTION-IF-NOT-FOUND]]) +dnl +dnl This macro figures out how to build C programs using POSIX +dnl threads. It sets the PTHREAD_LIBS output variable to the threads +dnl library and linker flags, and the PTHREAD_CFLAGS output variable +dnl to any special C compiler flags that are needed. (The user can also +dnl force certain compiler flags/libs to be tested by setting these +dnl environment variables.) +dnl +dnl Also sets PTHREAD_CC to any special C compiler that is needed for +dnl multi-threaded programs (defaults to the value of CC otherwise). +dnl (This is necessary on AIX to use the special cc_r compiler alias.) +dnl +dnl If you are only building threads programs, you may wish to +dnl use these variables in your default LIBS, CFLAGS, and CC: +dnl +dnl LIBS="$PTHREAD_LIBS $LIBS" +dnl CFLAGS="$CFLAGS $PTHREAD_CFLAGS" +dnl CC="$PTHREAD_CC" +dnl +dnl In addition, if the PTHREAD_CREATE_JOINABLE thread-attribute +dnl constant has a nonstandard name, defines PTHREAD_CREATE_JOINABLE +dnl to that name (e.g. PTHREAD_CREATE_UNDETACHED on AIX). +dnl +dnl ACTION-IF-FOUND is a list of shell commands to run if a threads +dnl library is found, and ACTION-IF-NOT-FOUND is a list of commands +dnl to run it if it is not found. If ACTION-IF-FOUND is not specified, +dnl the default action will define HAVE_PTHREAD. +dnl +dnl Please let the authors know if this macro fails on any platform, +dnl or if you have any other suggestions or comments. This macro was +dnl based on work by SGJ on autoconf scripts for FFTW (www.fftw.org) +dnl (with help from M. Frigo), as well as ac_pthread and hb_pthread +dnl macros posted by AFC to the autoconf macro repository. We are also +dnl grateful for the helpful feedback of numerous users. +dnl +dnl @version $Id: acinclude.m4,v 1.2 2001/12/21 03:12:50 robs Exp $ +dnl @author Steven G. Johnson and Alejandro Forero Cuervo + +AC_DEFUN([ACX_PTHREAD], [ +AC_REQUIRE([AC_CANONICAL_HOST]) +acx_pthread_ok=no + +# First, check if the POSIX threads header, pthread.h, is available. +# If it isn't, don't bother looking for the threads libraries. +AC_CHECK_HEADER(pthread.h, , acx_pthread_ok=noheader) + +# We must check for the threads library under a number of different +# names; the ordering is very important because some systems +# (e.g. DEC) have both -lpthread and -lpthreads, where one of the +# libraries is broken (non-POSIX). + +# First of all, check if the user has set any of the PTHREAD_LIBS, +# etcetera environment variables, and if threads linking works using +# them: +if test x"$PTHREAD_LIBS$PTHREAD_CFLAGS" != x; then + save_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS $PTHREAD_CFLAGS" + save_LIBS="$LIBS" + LIBS="$PTHREAD_LIBS $LIBS" + AC_MSG_CHECKING([for pthread_join in LIBS=$PTHREAD_LIBS with CFLAGS=$PTHREAD_CFLAGS]) + AC_TRY_LINK_FUNC(pthread_join, acx_pthread_ok=yes) + AC_MSG_RESULT($acx_pthread_ok) + if test x"$acx_pthread_ok" = xno; then + PTHREAD_LIBS="" + PTHREAD_CFLAGS="" + fi + LIBS="$save_LIBS" + CFLAGS="$save_CFLAGS" +fi + +# Create a list of thread flags to try. Items starting with a "-" are +# C compiler flags, and other items are library names, except for "none" +# which indicates that we try without any flags at all. + +acx_pthread_flags="pthreads none -Kthread -kthread lthread -pthread -pthreads -mthreads pthread --thread-safe -mt" + +# The ordering *is* (sometimes) important. Some notes on the +# individual items follow: + +# pthreads: AIX (must check this before -lpthread) +# none: in case threads are in libc; should be tried before -Kthread and +# other compiler flags to prevent continual compiler warnings +# -Kthread: Sequent (threads in libc, but -Kthread needed for pthread.h) +# -kthread: FreeBSD kernel threads (preferred to -pthread since SMP-able) +# lthread: LinuxThreads port on FreeBSD (also preferred to -pthread) +# -pthread: Linux/gcc (kernel threads), BSD/gcc (userland threads) +# -pthreads: Solaris/gcc +# -mthreads: Mingw32/gcc, Lynx/gcc +# -mt: Sun Workshop C (may only link SunOS threads [-lthread], but it +# doesn't hurt to check since this sometimes defines pthreads too; +# also defines -D_REENTRANT) +# pthread: Linux, etcetera +# --thread-safe: KAI C++ + +case "${host_cpu}-${host_os}" in + *solaris*) + + # On Solaris (at least, for some versions), libc contains stubbed + # (non-functional) versions of the pthreads routines, so link-based + # tests will erroneously succeed. (We need to link with -pthread or + # -lpthread.) (The stubs are missing pthread_cleanup_push, or rather + # a function called by this macro, so we could check for that, but + # who knows whether they'll stub that too in a future libc.) So, + # we'll just look for -pthreads and -lpthread first: + + acx_pthread_flags="-pthread -pthreads pthread -mt $acx_pthread_flags" + ;; +esac + +if test x"$acx_pthread_ok" = xno; then +for flag in $acx_pthread_flags; do + + case $flag in + none) + AC_MSG_CHECKING([whether pthreads work without any flags]) + ;; + + -*) + AC_MSG_CHECKING([whether pthreads work with $flag]) + PTHREAD_CFLAGS="$flag" + ;; + + *) + AC_MSG_CHECKING([for the pthreads library -l$flag]) + PTHREAD_LIBS="-l$flag" + ;; + esac + + save_LIBS="$LIBS" + save_CFLAGS="$CFLAGS" + LIBS="$PTHREAD_LIBS $LIBS" + CFLAGS="$CFLAGS $PTHREAD_CFLAGS" + + # Check for various functions. We must include pthread.h, + # since some functions may be macros. (On the Sequent, we + # need a special flag -Kthread to make this header compile.) + # We check for pthread_join because it is in -lpthread on IRIX + # while pthread_create is in libc. We check for pthread_attr_init + # due to DEC craziness with -lpthreads. We check for + # pthread_cleanup_push because it is one of the few pthread + # functions on Solaris that doesn't have a non-functional libc stub. + # We try pthread_create on general principles. + AC_TRY_LINK([#include ], + [pthread_t th; pthread_join(th, 0); + pthread_attr_init(0); pthread_cleanup_push(0, 0); + pthread_create(0,0,0,0); pthread_cleanup_pop(0); ], + [acx_pthread_ok=yes]) + + LIBS="$save_LIBS" + CFLAGS="$save_CFLAGS" + + AC_MSG_RESULT($acx_pthread_ok) + if test "x$acx_pthread_ok" = xyes; then + break; + fi + + PTHREAD_LIBS="" + PTHREAD_CFLAGS="" +done +fi + +# Various other checks: +if test "x$acx_pthread_ok" = xyes; then + save_LIBS="$LIBS" + LIBS="$PTHREAD_LIBS $LIBS" + save_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS $PTHREAD_CFLAGS" + + # Detect AIX lossage: threads are created detached by default + # and the JOINABLE attribute has a nonstandard name (UNDETACHED). + AC_MSG_CHECKING([for joinable pthread attribute]) + AC_TRY_LINK([#include ], + [int attr=PTHREAD_CREATE_JOINABLE;], + ok=PTHREAD_CREATE_JOINABLE, ok=unknown) + if test x"$ok" = xunknown; then + AC_TRY_LINK([#include ], + [int attr=PTHREAD_CREATE_UNDETACHED;], + ok=PTHREAD_CREATE_UNDETACHED, ok=unknown) + fi + if test x"$ok" != xPTHREAD_CREATE_JOINABLE; then + AC_DEFINE(PTHREAD_CREATE_JOINABLE, $ok, + [Define to the necessary symbol if this constant + uses a non-standard name on your system.]) + fi + AC_MSG_RESULT(${ok}) + if test x"$ok" = xunknown; then + AC_MSG_WARN([we do not know how to create joinable pthreads]) + fi + + AC_MSG_CHECKING([if more special flags are required for pthreads]) + flag=no + case "${host_cpu}-${host_os}" in + *-aix* | *-freebsd*) flag="-D_THREAD_SAFE";; + *solaris* | alpha*-osf*) flag="-D_REENTRANT";; + esac + AC_MSG_RESULT(${flag}) + if test "x$flag" != xno; then + PTHREAD_CFLAGS="$flag $PTHREAD_CFLAGS" + fi + + LIBS="$save_LIBS" + CFLAGS="$save_CFLAGS" + + # More AIX lossage: must compile with cc_r + AC_CHECK_PROG(PTHREAD_CC, cc_r, cc_r, ${CC}) +else + PTHREAD_CC="$CC" +fi + +AC_SUBST(PTHREAD_LIBS) +AC_SUBST(PTHREAD_CFLAGS) +AC_SUBST(PTHREAD_CC) + +# Finally, execute ACTION-IF-FOUND/ACTION-IF-NOT-FOUND: +if test x"$acx_pthread_ok" = xyes; then + ifelse([$1],,AC_DEFINE(HAVE_PTHREAD,1,[Define if you have POSIX threads libraries and header files.]),[$1]) + : +else + acx_pthread_ok=no + $2 +fi + +])dnl ACX_PTHREAD + + + +dnl @synopsis AC_PROG_CC_WARNINGS([ANSI]) +dnl +dnl Enables a reasonable set of warnings for the C compiler. Optionally, +dnl if the first argument is nonempty, turns on flags which enforce and/or +dnl enable proper ANSI C if such flags are known to the compiler used. +dnl +dnl Currently this macro knows about GCC, Solaris C compiler, +dnl Digital Unix C compiler, C for AIX Compiler, HP-UX C compiler, +dnl and IRIX C compiler. +dnl +dnl @version $Id: acinclude.m4,v 1.2 2001/12/21 03:12:50 robs Exp $ +dnl @author Ville Laurikari +dnl +AC_DEFUN([AC_PROG_CC_WARNINGS], [ + ansi=$1 + if test -z "$ansi"; then + msg="for C compiler warning flags" + else + msg="for C compiler warning and ANSI conformance flags" + fi + AC_CACHE_CHECK($msg, ac_cv_prog_cc_warnings, [ + if test -n "$CC"; then + cat > conftest.c <&1 | grep "Xc.*strict ANSI C" > /dev/null 2>&1 && + $CC -c -v -Xc conftest.c > /dev/null 2>&1 && + test -f conftest.o; then + if test -z "$ansi"; then + ac_cv_prog_cc_warnings="-v" + else + ac_cv_prog_cc_warnings="-v -Xc" + fi + + dnl HP-UX C compiler + elif $CC > /dev/null 2>&1 && + $CC -c -Aa +w1 conftest.c > /dev/null 2>&1 && + test -f conftest.o; then + if test -z "$ansi"; then + ac_cv_prog_cc_warnings="+w1" + else + ac_cv_prog_cc_warnings="+w1 -Aa" + fi + + dnl Digital Unix C compiler + elif ! $CC > /dev/null 2>&1 && + $CC -c -verbose -w0 -warnprotos -std1 conftest.c > /dev/null 2>&1 && + test -f conftest.o; then + if test -z "$ansi"; then + ac_cv_prog_cc_warnings="-verbose -w0 -warnprotos" + else + ac_cv_prog_cc_warnings="-verbose -w0 -warnprotos -std1" + fi + + dnl C for AIX Compiler + elif $CC > /dev/null 2>&1 | grep AIX > /dev/null 2>&1 && + $CC -c -qlanglvl=ansi -qinfo=all conftest.c > /dev/null 2>&1 && + test -f conftest.o; then + if test -z "$ansi"; then + ac_cv_prog_cc_warnings="-qsrcmsg -qinfo=all:noppt:noppc:noobs:nocnd" + else + ac_cv_prog_cc_warnings="-qsrcmsg -qinfo=all:noppt:noppc:noobs:nocnd -qlanglvl=ansi" + fi + + dnl IRIX C compiler + elif $CC -fullwarn -ansi -ansiE > /dev/null 2>&1 && + test -f conftest.o; then + if test -z "$ansi"; then + ac_cv_prog_cc_warnings="-fullwarn" + else + ac_cv_prog_cc_warnings="-fullwarn -ansi -ansiE" + fi + + fi + rm -f conftest.* + fi + if test -n "$ac_cv_prog_cc_warnings"; then + CFLAGS="$CFLAGS $ac_cv_prog_cc_warnings" + else + ac_cv_prog_cc_warnings="unknown" + fi + ]) +]) + + + diff --git a/iipsrv/fcgi/perl/configure b/iipsrv/fcgi/perl/configure new file mode 100755 index 0000000..cdf6f46 --- /dev/null +++ b/iipsrv/fcgi/perl/configure @@ -0,0 +1,3116 @@ +#! /bin/sh +# Guess values for system-dependent variables and create Makefiles. +# Generated by Autoconf 2.52. +# +# Copyright 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001 +# Free Software Foundation, Inc. +# This configure script is free software; the Free Software Foundation +# gives unlimited permission to copy, distribute and modify it. + +# 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 + +# Sed expression to map a string onto a valid variable name. +as_tr_sh="sed y%*+%pp%;s%[^_$as_cr_alnum]%_%g" + +# Sed expression to map a string onto a valid CPP name. +as_tr_cpp="sed y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g" + +# Be Bourne compatible +if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then + emulate sh + NULLCMD=: +elif test -n "${BASH_VERSION+set}" && (set -o posix) >/dev/null 2>&1; then + set -o posix +fi + +# Name of the executable. +as_me=`echo "$0" |sed 's,.*[\\/],,'` + +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 + +as_executable_p="test -f" + +# Support unset when possible. +if (FOO=FOO; unset FOO) >/dev/null 2>&1; then + as_unset=unset +else + as_unset=false +fi + +# NLS nuisances. +$as_unset LANG || test "${LANG+set}" != set || { LANG=C; export LANG; } +$as_unset LC_ALL || test "${LC_ALL+set}" != set || { LC_ALL=C; export LC_ALL; } +$as_unset LC_TIME || test "${LC_TIME+set}" != set || { LC_TIME=C; export LC_TIME; } +$as_unset LC_CTYPE || test "${LC_CTYPE+set}" != set || { LC_CTYPE=C; export LC_CTYPE; } +$as_unset LANGUAGE || test "${LANGUAGE+set}" != set || { LANGUAGE=C; export LANGUAGE; } +$as_unset LC_COLLATE || test "${LC_COLLATE+set}" != set || { LC_COLLATE=C; export LC_COLLATE; } +$as_unset LC_NUMERIC || test "${LC_NUMERIC+set}" != set || { LC_NUMERIC=C; export LC_NUMERIC; } +$as_unset LC_MESSAGES || test "${LC_MESSAGES+set}" != set || { LC_MESSAGES=C; export LC_MESSAGES; } + +# IFS +# We need space, tab and new line, in precisely that order. +as_nl=' +' +IFS=" $as_nl" + +# CDPATH. +$as_unset CDPATH || test "${CDPATH+set}" != set || { CDPATH=:; export 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 +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} + +# 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" + +# 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' + +# Identity of this package. +PACKAGE_NAME= +PACKAGE_TARNAME= +PACKAGE_VERSION= +PACKAGE_STRING= +PACKAGE_BUGREPORT= + +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) + 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 path 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 path 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. +build=$build_alias +host=$host_alias +target=$target_alias + +# FIXME: should be removed in autoconf 3.0. +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_prog=$0 + ac_confdir=`echo "$ac_prog" | sed 's%[\\/][^\\/][^\\/]*$%%'` + test "x$ac_confdir" = "x$ac_prog" && ac_confdir=. + 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 in $ac_confdir or .." >&2 + { (exit 1); exit 1; }; } + else + { echo "$as_me: error: cannot find sources in $srcdir" >&2 + { (exit 1); exit 1; }; } + fi +fi +srcdir=`echo "$srcdir" | sed 's%\([^\\/]\)[\\/]*$%\1%'` +ac_env_build_alias_set=${build_alias+set} +ac_env_build_alias_value=$build_alias +ac_cv_env_build_alias_set=${build_alias+set} +ac_cv_env_build_alias_value=$build_alias +ac_env_host_alias_set=${host_alias+set} +ac_env_host_alias_value=$host_alias +ac_cv_env_host_alias_set=${host_alias+set} +ac_cv_env_host_alias_value=$host_alias +ac_env_target_alias_set=${target_alias+set} +ac_env_target_alias_value=$target_alias +ac_cv_env_target_alias_set=${target_alias+set} +ac_cv_env_target_alias_value=$target_alias +ac_env_CC_set=${CC+set} +ac_env_CC_value=$CC +ac_cv_env_CC_set=${CC+set} +ac_cv_env_CC_value=$CC +ac_env_CFLAGS_set=${CFLAGS+set} +ac_env_CFLAGS_value=$CFLAGS +ac_cv_env_CFLAGS_set=${CFLAGS+set} +ac_cv_env_CFLAGS_value=$CFLAGS +ac_env_LDFLAGS_set=${LDFLAGS+set} +ac_env_LDFLAGS_value=$LDFLAGS +ac_cv_env_LDFLAGS_set=${LDFLAGS+set} +ac_cv_env_LDFLAGS_value=$LDFLAGS +ac_env_CPPFLAGS_set=${CPPFLAGS+set} +ac_env_CPPFLAGS_value=$CPPFLAGS +ac_cv_env_CPPFLAGS_set=${CPPFLAGS+set} +ac_cv_env_CPPFLAGS_value=$CPPFLAGS +ac_env_CPP_set=${CPP+set} +ac_env_CPP_value=$CPP +ac_cv_env_CPP_set=${CPP+set} +ac_cv_env_CPP_value=$CPP + +# +# Report the --help message. +# +if test "$ac_init_help" = "long"; then + # Omit some internal or obsolete options to make the list less imposing. + # This message is too long to be a string in the A/UX 3.1 sh. + cat < if you have libraries in a + nonstandard directory + CPPFLAGS C/C++ preprocessor flags, e.g. -I if you have + headers in a nonstandard directory + 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. + +EOF +fi + +if test "$ac_init_help" = "recursive"; then + # If there are subdirs, report their specific --help. + ac_popdir=`pwd` + for ac_subdir in : $ac_subdirs_all; do test "x$ac_subdir" = x: && continue + cd $ac_subdir + # A "../" for each directory in /$ac_subdir. + ac_dots=`echo $ac_subdir | + sed 's,^\./,,;s,[^/]$,&/,;s,[^/]*/,../,g'` + + case $srcdir in + .) # No --srcdir option. We are building in place. + ac_sub_srcdir=$srcdir ;; + [\\/]* | ?:[\\/]* ) # Absolute path. + ac_sub_srcdir=$srcdir/$ac_subdir ;; + *) # Relative path. + ac_sub_srcdir=$ac_dots$srcdir/$ac_subdir ;; + esac + + # Check for guested configure; otherwise get Cygnus style configure. + if test -f $ac_sub_srcdir/configure.gnu; then + echo + $SHELL $ac_sub_srcdir/configure.gnu --help=recursive + elif test -f $ac_sub_srcdir/configure; then + echo + $SHELL $ac_sub_srcdir/configure --help=recursive + elif test -f $ac_sub_srcdir/configure.ac || + test -f $ac_sub_srcdir/configure.in; then + echo + $ac_configure --help + else + echo "$as_me: WARNING: no configuration information is in $ac_subdir" >&2 + fi + cd $ac_popdir + done +fi + +test -n "$ac_init_help" && exit 0 +if $ac_init_version; then + cat <<\EOF + +Copyright 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001 +Free Software Foundation, Inc. +This configure script is free software; the Free Software Foundation +gives unlimited permission to copy, distribute and modify it. +EOF + exit 0 +fi +exec 5>config.log +cat >&5 </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` + +PATH = $PATH + +_ASUNAME +} >&5 + +cat >&5 <\?\"\']*) + ac_arg=`echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` + ac_configure_args="$ac_configure_args$ac_sep'$ac_arg'" + ac_sep=" " ;; + *) ac_configure_args="$ac_configure_args$ac_sep$ac_arg" + ac_sep=" " ;; + esac + # Get rid of the leading space. +done + +# 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. +trap 'exit_status=$? + # Save into config.log some information that might help in debugging. + echo >&5 + echo "## ----------------- ##" >&5 + echo "## Cache variables. ##" >&5 + echo "## ----------------- ##" >&5 + echo >&5 + # 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; +} >&5 + sed "/^$/d" confdefs.h >conftest.log + if test -s conftest.log; then + echo >&5 + echo "## ------------ ##" >&5 + echo "## confdefs.h. ##" >&5 + echo "## ------------ ##" >&5 + echo >&5 + cat conftest.log >&5 + fi + (echo; echo) >&5 + test "$ac_signal" != 0 && + echo "$as_me: caught signal $ac_signal" >&5 + echo "$as_me: exit $exit_status" >&5 + rm -rf conftest* confdefs* core core.* *.core 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 + +# 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:854: loading site script $ac_site_file" >&5 +echo "$as_me: loading site script $ac_site_file" >&6;} + cat "$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:865: 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:873: 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:889: 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:893: 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:899: 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:901: former value: $ac_old_val" >&5 +echo "$as_me: former value: $ac_old_val" >&2;} + { echo "$as_me:903: 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. It doesn't matter if + # we pass some twice (in addition to the command line arguments). + if test "$ac_new_set" = set; then + case $ac_new_val in + *" "*|*" "*|*[\[\]\~\#\$\^\&\*\(\)\{\}\\\|\;\<\>\?\"\']*) + ac_arg=$ac_var=`echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` + ac_configure_args="$ac_configure_args '$ac_arg'" + ;; + *) ac_configure_args="$ac_configure_args $ac_var=$ac_new_val" + ;; + esac + fi +done +if $ac_cache_corrupted; then + { echo "$as_me:922: 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:924: 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 + +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 +echo "#! $SHELL" >conftest.sh +echo "exit 0" >>conftest.sh +chmod +x conftest.sh +if { (echo "$as_me:944: PATH=\".;.\"; conftest.sh") >&5 + (PATH=".;."; conftest.sh) 2>&5 + ac_status=$? + echo "$as_me:947: \$? = $ac_status" >&5 + (exit $ac_status); }; then + ac_path_separator=';' +else + ac_path_separator=: +fi +PATH_SEPARATOR="$ac_path_separator" +rm -f conftest.sh + + ac_config_headers="$ac_config_headers fcgi_config.h" + +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:966: 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_save_IFS=$IFS; IFS=$ac_path_separator +ac_dummy="$PATH" +for ac_dir in $ac_dummy; do + IFS=$ac_save_IFS + test -z "$ac_dir" && ac_dir=. + $as_executable_p "$ac_dir/$ac_word" || continue +ac_cv_prog_CC="${ac_tool_prefix}gcc" +echo "$as_me:981: found $ac_dir/$ac_word" >&5 +break +done + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + echo "$as_me:989: result: $CC" >&5 +echo "${ECHO_T}$CC" >&6 +else + echo "$as_me:992: 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:1001: 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 + ac_save_IFS=$IFS; IFS=$ac_path_separator +ac_dummy="$PATH" +for ac_dir in $ac_dummy; do + IFS=$ac_save_IFS + test -z "$ac_dir" && ac_dir=. + $as_executable_p "$ac_dir/$ac_word" || continue +ac_cv_prog_ac_ct_CC="gcc" +echo "$as_me:1016: found $ac_dir/$ac_word" >&5 +break +done + +fi +fi +ac_ct_CC=$ac_cv_prog_ac_ct_CC +if test -n "$ac_ct_CC"; then + echo "$as_me:1024: result: $ac_ct_CC" >&5 +echo "${ECHO_T}$ac_ct_CC" >&6 +else + echo "$as_me:1027: 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:1040: 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_save_IFS=$IFS; IFS=$ac_path_separator +ac_dummy="$PATH" +for ac_dir in $ac_dummy; do + IFS=$ac_save_IFS + test -z "$ac_dir" && ac_dir=. + $as_executable_p "$ac_dir/$ac_word" || continue +ac_cv_prog_CC="${ac_tool_prefix}cc" +echo "$as_me:1055: found $ac_dir/$ac_word" >&5 +break +done + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + echo "$as_me:1063: result: $CC" >&5 +echo "${ECHO_T}$CC" >&6 +else + echo "$as_me:1066: 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:1075: 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 + ac_save_IFS=$IFS; IFS=$ac_path_separator +ac_dummy="$PATH" +for ac_dir in $ac_dummy; do + IFS=$ac_save_IFS + test -z "$ac_dir" && ac_dir=. + $as_executable_p "$ac_dir/$ac_word" || continue +ac_cv_prog_ac_ct_CC="cc" +echo "$as_me:1090: found $ac_dir/$ac_word" >&5 +break +done + +fi +fi +ac_ct_CC=$ac_cv_prog_ac_ct_CC +if test -n "$ac_ct_CC"; then + echo "$as_me:1098: result: $ac_ct_CC" >&5 +echo "${ECHO_T}$ac_ct_CC" >&6 +else + echo "$as_me:1101: 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:1114: 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 + ac_save_IFS=$IFS; IFS=$ac_path_separator +ac_dummy="$PATH" +for ac_dir in $ac_dummy; do + IFS=$ac_save_IFS + test -z "$ac_dir" && ac_dir=. + $as_executable_p "$ac_dir/$ac_word" || continue +if test "$ac_dir/$ac_word" = "/usr/ucb/cc"; then + ac_prog_rejected=yes + continue +fi +ac_cv_prog_CC="cc" +echo "$as_me:1134: found $ac_dir/$ac_word" >&5 +break +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 + set dummy "$ac_dir/$ac_word" ${1+"$@"} + shift + ac_cv_prog_CC="$@" + fi +fi +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + echo "$as_me:1156: result: $CC" >&5 +echo "${ECHO_T}$CC" >&6 +else + echo "$as_me:1159: 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:1170: 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_save_IFS=$IFS; IFS=$ac_path_separator +ac_dummy="$PATH" +for ac_dir in $ac_dummy; do + IFS=$ac_save_IFS + test -z "$ac_dir" && ac_dir=. + $as_executable_p "$ac_dir/$ac_word" || continue +ac_cv_prog_CC="$ac_tool_prefix$ac_prog" +echo "$as_me:1185: found $ac_dir/$ac_word" >&5 +break +done + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + echo "$as_me:1193: result: $CC" >&5 +echo "${ECHO_T}$CC" >&6 +else + echo "$as_me:1196: 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:1209: 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 + ac_save_IFS=$IFS; IFS=$ac_path_separator +ac_dummy="$PATH" +for ac_dir in $ac_dummy; do + IFS=$ac_save_IFS + test -z "$ac_dir" && ac_dir=. + $as_executable_p "$ac_dir/$ac_word" || continue +ac_cv_prog_ac_ct_CC="$ac_prog" +echo "$as_me:1224: found $ac_dir/$ac_word" >&5 +break +done + +fi +fi +ac_ct_CC=$ac_cv_prog_ac_ct_CC +if test -n "$ac_ct_CC"; then + echo "$as_me:1232: result: $ac_ct_CC" >&5 +echo "${ECHO_T}$ac_ct_CC" >&6 +else + echo "$as_me:1235: 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:1247: error: no acceptable cc found in \$PATH" >&5 +echo "$as_me: error: no acceptable cc found in \$PATH" >&2;} + { (exit 1); exit 1; }; } + +# Provide some information about the compiler. +echo "$as_me:1252:" \ + "checking for C compiler version" >&5 +ac_compiler=`set X $ac_compile; echo $2` +{ (eval echo "$as_me:1255: \"$ac_compiler --version &5\"") >&5 + (eval $ac_compiler --version &5) 2>&5 + ac_status=$? + echo "$as_me:1258: \$? = $ac_status" >&5 + (exit $ac_status); } +{ (eval echo "$as_me:1260: \"$ac_compiler -v &5\"") >&5 + (eval $ac_compiler -v &5) 2>&5 + ac_status=$? + echo "$as_me:1263: \$? = $ac_status" >&5 + (exit $ac_status); } +{ (eval echo "$as_me:1265: \"$ac_compiler -V &5\"") >&5 + (eval $ac_compiler -V &5) 2>&5 + ac_status=$? + echo "$as_me:1268: \$? = $ac_status" >&5 + (exit $ac_status); } + +cat >conftest.$ac_ext <<_ACEOF +#line 1272 "configure" +#include "confdefs.h" + +int +main () +{ + + ; + return 0; +} +_ACEOF +ac_clean_files_save=$ac_clean_files +ac_clean_files="$ac_clean_files a.out a.exe" +# 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:1288: checking for C compiler default output" >&5 +echo $ECHO_N "checking for C compiler default output... $ECHO_C" >&6 +ac_link_default=`echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'` +if { (eval echo "$as_me:1291: \"$ac_link_default\"") >&5 + (eval $ac_link_default) 2>&5 + ac_status=$? + echo "$as_me:1294: \$? = $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. +for ac_file in `ls a.exe conftest.exe 2>/dev/null; + ls a.out conftest 2>/dev/null; + ls a.* conftest.* 2>/dev/null`; do + case $ac_file in + *.$ac_ext | *.o | *.obj | *.xcoff | *.tds | *.d | *.pdb ) ;; + a.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 --akim. + export ac_cv_exeext + break;; + * ) break;; + esac +done +else + echo "$as_me: failed program was:" >&5 +cat conftest.$ac_ext >&5 +{ { echo "$as_me:1317: error: C compiler cannot create executables" >&5 +echo "$as_me: error: C compiler cannot create executables" >&2;} + { (exit 77); exit 77; }; } +fi + +ac_exeext=$ac_cv_exeext +echo "$as_me:1323: 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:1328: 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:1334: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:1337: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + cross_compiling=no + else + if test "$cross_compiling" = maybe; then + cross_compiling=yes + else + { { echo "$as_me:1344: error: cannot run C compiled programs. +If you meant to cross compile, use \`--host'." >&5 +echo "$as_me: error: cannot run C compiled programs. +If you meant to cross compile, use \`--host'." >&2;} + { (exit 1); exit 1; }; } + fi + fi +fi +echo "$as_me:1352: result: yes" >&5 +echo "${ECHO_T}yes" >&6 + +rm -f a.out a.exe conftest$ac_cv_exeext +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:1359: checking whether we are cross compiling" >&5 +echo $ECHO_N "checking whether we are cross compiling... $ECHO_C" >&6 +echo "$as_me:1361: result: $cross_compiling" >&5 +echo "${ECHO_T}$cross_compiling" >&6 + +echo "$as_me:1364: checking for executable suffix" >&5 +echo $ECHO_N "checking for executable suffix... $ECHO_C" >&6 +if { (eval echo "$as_me:1366: \"$ac_link\"") >&5 + (eval $ac_link) 2>&5 + ac_status=$? + echo "$as_me:1369: \$? = $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 `(ls conftest.exe; ls conftest; ls conftest.*) 2>/dev/null`; do + case $ac_file in + *.$ac_ext | *.o | *.obj | *.xcoff | *.tds | *.d | *.pdb ) ;; + *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` + export ac_cv_exeext + break;; + * ) break;; + esac +done +else + { { echo "$as_me:1385: error: cannot compute EXEEXT: cannot compile and link" >&5 +echo "$as_me: error: cannot compute EXEEXT: cannot compile and link" >&2;} + { (exit 1); exit 1; }; } +fi + +rm -f conftest$ac_cv_exeext +echo "$as_me:1391: 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:1397: checking for object suffix" >&5 +echo $ECHO_N "checking for object suffix... $ECHO_C" >&6 +if test "${ac_cv_objext+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +#line 1403 "configure" +#include "confdefs.h" + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.o conftest.obj +if { (eval echo "$as_me:1415: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + echo "$as_me:1418: \$? = $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 ) ;; + *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'` + break;; + esac +done +else + echo "$as_me: failed program was:" >&5 +cat conftest.$ac_ext >&5 +{ { echo "$as_me:1430: error: cannot compute OBJEXT: cannot compile" >&5 +echo "$as_me: error: cannot compute OBJEXT: cannot compile" >&2;} + { (exit 1); exit 1; }; } +fi + +rm -f conftest.$ac_cv_objext conftest.$ac_ext +fi +echo "$as_me:1437: result: $ac_cv_objext" >&5 +echo "${ECHO_T}$ac_cv_objext" >&6 +OBJEXT=$ac_cv_objext +ac_objext=$OBJEXT +echo "$as_me:1441: 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 +#line 1447 "configure" +#include "confdefs.h" + +int +main () +{ +#ifndef __GNUC__ + choke me +#endif + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:1462: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + echo "$as_me:1465: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:1468: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:1471: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_compiler_gnu=yes +else + echo "$as_me: failed program was:" >&5 +cat conftest.$ac_ext >&5 +ac_compiler_gnu=no +fi +rm -f conftest.$ac_objext conftest.$ac_ext +ac_cv_c_compiler_gnu=$ac_compiler_gnu + +fi +echo "$as_me:1483: 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:1489: 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 +#line 1495 "configure" +#include "confdefs.h" + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:1507: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + echo "$as_me:1510: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:1513: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:1516: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_prog_cc_g=yes +else + echo "$as_me: failed program was:" >&5 +cat conftest.$ac_ext >&5 +ac_cv_prog_cc_g=no +fi +rm -f conftest.$ac_objext conftest.$ac_ext +fi +echo "$as_me:1526: 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 +# 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:1553: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + echo "$as_me:1556: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:1559: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:1562: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + for ac_declaration in \ + ''\ + '#include ' \ + '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 +#line 1574 "configure" +#include "confdefs.h" +#include +$ac_declaration +int +main () +{ +exit (42); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:1587: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + echo "$as_me:1590: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:1593: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:1596: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + : +else + echo "$as_me: failed program was:" >&5 +cat conftest.$ac_ext >&5 +continue +fi +rm -f conftest.$ac_objext conftest.$ac_ext + cat >conftest.$ac_ext <<_ACEOF +#line 1606 "configure" +#include "confdefs.h" +$ac_declaration +int +main () +{ +exit (42); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:1618: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + echo "$as_me:1621: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:1624: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:1627: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + break +else + echo "$as_me: failed program was:" >&5 +cat conftest.$ac_ext >&5 +fi +rm -f 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 +cat conftest.$ac_ext >&5 +fi +rm -f 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 + +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:1659: 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. + # 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 +#line 1680 "configure" +#include "confdefs.h" +#include + Syntax error +_ACEOF +if { (eval echo "$as_me:1685: \"$ac_cpp conftest.$ac_ext\"") >&5 + (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 + ac_status=$? + egrep -v '^ *\+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:1691: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null; then + if test -s conftest.err; then + ac_cpp_err=$ac_c_preproc_warn_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 + cat 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 +#line 1714 "configure" +#include "confdefs.h" +#include +_ACEOF +if { (eval echo "$as_me:1718: \"$ac_cpp conftest.$ac_ext\"") >&5 + (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 + ac_status=$? + egrep -v '^ *\+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:1724: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null; then + if test -s conftest.err; then + ac_cpp_err=$ac_c_preproc_warn_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 + cat 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:1761: 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. + # 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 +#line 1771 "configure" +#include "confdefs.h" +#include + Syntax error +_ACEOF +if { (eval echo "$as_me:1776: \"$ac_cpp conftest.$ac_ext\"") >&5 + (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 + ac_status=$? + egrep -v '^ *\+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:1782: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null; then + if test -s conftest.err; then + ac_cpp_err=$ac_c_preproc_warn_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 + cat 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 +#line 1805 "configure" +#include "confdefs.h" +#include +_ACEOF +if { (eval echo "$as_me:1809: \"$ac_cpp conftest.$ac_ext\"") >&5 + (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 + ac_status=$? + egrep -v '^ *\+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:1815: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null; then + if test -s conftest.err; then + ac_cpp_err=$ac_c_preproc_warn_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 + cat 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:1843: error: C preprocessor \"$CPP\" fails sanity check" >&5 +echo "$as_me: error: C preprocessor \"$CPP\" fails sanity check" >&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:1854: 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 +#line 1860 "configure" +#include "confdefs.h" +#include +#include +#include +#include + +_ACEOF +if { (eval echo "$as_me:1868: \"$ac_cpp conftest.$ac_ext\"") >&5 + (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 + ac_status=$? + egrep -v '^ *\+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:1874: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null; then + if test -s conftest.err; then + ac_cpp_err=$ac_c_preproc_warn_flag + else + ac_cpp_err= + fi +else + ac_cpp_err=yes +fi +if test -z "$ac_cpp_err"; then + ac_cv_header_stdc=yes +else + echo "$as_me: failed program was:" >&5 + cat conftest.$ac_ext >&5 + ac_cv_header_stdc=no +fi +rm -f conftest.err 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 +#line 1896 "configure" +#include "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 +#line 1914 "configure" +#include "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 +#line 1935 "configure" +#include "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:1961: \"$ac_link\"") >&5 + (eval $ac_link) 2>&5 + ac_status=$? + echo "$as_me:1964: \$? = $ac_status" >&5 + (exit $ac_status); } && { ac_try='./conftest$ac_exeext' + { (eval echo "$as_me:1966: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:1969: \$? = $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 +cat conftest.$ac_ext >&5 +ac_cv_header_stdc=no +fi +rm -f core core.* *.core conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext +fi +fi +fi +echo "$as_me:1982: 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 <<\EOF +#define STDC_HEADERS 1 +EOF + +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:1998: 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 +#line 2004 "configure" +#include "confdefs.h" +$ac_includes_default +#include <$ac_header> +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:2010: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + echo "$as_me:2013: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:2016: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:2019: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + eval "$as_ac_Header=yes" +else + echo "$as_me: failed program was:" >&5 +cat conftest.$ac_ext >&5 +eval "$as_ac_Header=no" +fi +rm -f conftest.$ac_objext conftest.$ac_ext +fi +echo "$as_me:2029: 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 <&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 +#line 2047 "configure" +#include "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; +} +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:2096: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + echo "$as_me:2099: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:2102: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:2105: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_prog_cc_stdc=$ac_arg +break +else + echo "$as_me: failed program was:" >&5 +cat conftest.$ac_ext >&5 +fi +rm -f 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:2122: result: none needed" >&5 +echo "${ECHO_T}none needed" >&6 ;; + *) + echo "$as_me:2125: result: $ac_cv_prog_cc_stdc" >&5 +echo "${ECHO_T}$ac_cv_prog_cc_stdc" >&6 + CC="$CC $ac_cv_prog_cc_stdc" ;; +esac + + echo "$as_me:2130: checking for ssize_t" >&5 +echo $ECHO_N "checking for ssize_t... $ECHO_C" >&6 +if test "${ac_cv_type_ssize_t+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +#line 2136 "configure" +#include "confdefs.h" +$ac_includes_default +int +main () +{ +if ((ssize_t *) 0) + return 0; +if (sizeof (ssize_t)) + return 0; + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:2151: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + echo "$as_me:2154: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:2157: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:2160: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_type_ssize_t=yes +else + echo "$as_me: failed program was:" >&5 +cat conftest.$ac_ext >&5 +ac_cv_type_ssize_t=no +fi +rm -f conftest.$ac_objext conftest.$ac_ext +fi +echo "$as_me:2170: result: $ac_cv_type_ssize_t" >&5 +echo "${ECHO_T}$ac_cv_type_ssize_t" >&6 +if test $ac_cv_type_ssize_t = yes; then + : +else + +cat >>confdefs.h <&5 +echo $ECHO_N "checking for sun_len in sys/un.h... $ECHO_C" >&6 + cat >conftest.$ac_ext <<_ACEOF +#line 2185 "configure" +#include "confdefs.h" +#include + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + egrep "sun_len" >/dev/null 2>&1; then + echo "$as_me:2192: result: yes" >&5 +echo "${ECHO_T}yes" >&6 + +cat >>confdefs.h <<\EOF +#define HAVE_SOCKADDR_UN_SUN_LEN 1 +EOF + +else + echo "$as_me:2200: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi +rm -f conftest* + + echo "$as_me:2205: checking for fpos_t in stdio.h" >&5 +echo $ECHO_N "checking for fpos_t in stdio.h... $ECHO_C" >&6 + cat >conftest.$ac_ext <<_ACEOF +#line 2208 "configure" +#include "confdefs.h" +#include + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + egrep "fpos_t" >/dev/null 2>&1; then + echo "$as_me:2215: result: yes" >&5 +echo "${ECHO_T}yes" >&6 + +cat >>confdefs.h <<\EOF +#define HAVE_FPOS 1 +EOF + +else + echo "$as_me:2223: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi +rm -f conftest* + +for ac_header in sys/socket.h netdb.h netinet/in.h arpa/inet.h +do +as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh` +echo "$as_me:2231: 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 +#line 2237 "configure" +#include "confdefs.h" +#include <$ac_header> +_ACEOF +if { (eval echo "$as_me:2241: \"$ac_cpp conftest.$ac_ext\"") >&5 + (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 + ac_status=$? + egrep -v '^ *\+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:2247: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null; then + if test -s conftest.err; then + ac_cpp_err=$ac_c_preproc_warn_flag + else + ac_cpp_err= + fi +else + ac_cpp_err=yes +fi +if test -z "$ac_cpp_err"; then + eval "$as_ac_Header=yes" +else + echo "$as_me: failed program was:" >&5 + cat conftest.$ac_ext >&5 + eval "$as_ac_Header=no" +fi +rm -f conftest.err conftest.$ac_ext +fi +echo "$as_me:2266: 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 <&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 +#line 2285 "configure" +#include "confdefs.h" +#include <$ac_header> +_ACEOF +if { (eval echo "$as_me:2289: \"$ac_cpp conftest.$ac_ext\"") >&5 + (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 + ac_status=$? + egrep -v '^ *\+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:2295: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null; then + if test -s conftest.err; then + ac_cpp_err=$ac_c_preproc_warn_flag + else + ac_cpp_err= + fi +else + ac_cpp_err=yes +fi +if test -z "$ac_cpp_err"; then + eval "$as_ac_Header=yes" +else + echo "$as_me: failed program was:" >&5 + cat conftest.$ac_ext >&5 + eval "$as_ac_Header=no" +fi +rm -f conftest.err conftest.$ac_ext +fi +echo "$as_me:2314: 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 <&5 +echo $ECHO_N "checking for a fileno() prototype in stdio.h... $ECHO_C" >&6 + cat >conftest.$ac_ext <<_ACEOF +#line 2327 "configure" +#include "confdefs.h" +#include + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + egrep "fileno" >/dev/null 2>&1; then + echo "$as_me:2334: result: yes" >&5 +echo "${ECHO_T}yes" >&6 + +cat >>confdefs.h <<\EOF +#define HAVE_FILENO_PROTO 1 +EOF + +else + echo "$as_me:2342: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi +rm -f conftest* + + if test "$HAVE_SYS_SOCKET_H"; then + echo "$as_me:2348: checking for socklen_t in sys/socket.h" >&5 +echo $ECHO_N "checking for socklen_t in sys/socket.h... $ECHO_C" >&6 + cat >conftest.$ac_ext <<_ACEOF +#line 2351 "configure" +#include "confdefs.h" +#include + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + egrep "socklen_t" >/dev/null 2>&1; then + echo "$as_me:2358: result: yes" >&5 +echo "${ECHO_T}yes" >&6 + +cat >>confdefs.h <<\EOF +#define HAVE_SOCKLEN 1 +EOF + +else + echo "$as_me:2366: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi +rm -f conftest* + + fi + + #-------------------------------------------------------------------- + # Do we need cross-process locking on this platform? + #-------------------------------------------------------------------- + echo "$as_me:2376: checking whether cross-process locking is required by accept()" >&5 +echo $ECHO_N "checking whether cross-process locking is required by accept()... $ECHO_C" >&6 + case "`uname -sr`" in + IRIX\ 5.* | SunOS\ 5.* | UNIX_System_V\ 4.0) + echo "$as_me:2380: result: yes" >&5 +echo "${ECHO_T}yes" >&6 + +cat >>confdefs.h <<\EOF +#define USE_LOCKING 1 +EOF + + ;; + *) + echo "$as_me:2389: result: no" >&5 +echo "${ECHO_T}no" >&6 + ;; + esac + + #-------------------------------------------------------------------- + # Does va_arg(arg, long double) crash the compiler? + # hpux 9.04 compiler does and so does Stratus FTX (uses HP's compiler) + #-------------------------------------------------------------------- + echo "$as_me:2398: checking whether va_arg(arg, long double) crashes the compiler" >&5 +echo $ECHO_N "checking whether va_arg(arg, long double) crashes the compiler... $ECHO_C" >&6 + cat >conftest.$ac_ext <<_ACEOF +#line 2401 "configure" +#include "confdefs.h" +#include +int +main () +{ +long double lDblArg; va_list arg; lDblArg = va_arg(arg, long double); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:2413: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + echo "$as_me:2416: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:2419: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:2422: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + echo "$as_me:2424: result: no" >&5 +echo "${ECHO_T}no" >&6 +else + echo "$as_me: failed program was:" >&5 +cat conftest.$ac_ext >&5 +echo "$as_me:2429: result: yes" >&5 +echo "${ECHO_T}yes" >&6 + +cat >>confdefs.h <<\EOF +#define HAVE_VA_ARG_LONG_DOUBLE_BUG 1 +EOF + +fi +rm -f conftest.$ac_objext conftest.$ac_ext + + echo "$as_me:2439: checking for an ANSI C-conforming const" >&5 +echo $ECHO_N "checking for an ANSI C-conforming const... $ECHO_C" >&6 +if test "${ac_cv_c_const+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +#line 2445 "configure" +#include "confdefs.h" + +int +main () +{ +/* FIXME: Include the comments suggested by Paul. */ +#ifndef __cplusplus + /* Ultrix mips cc rejects this. */ + typedef int charset[2]; + const charset x; + /* SunOS 4.1.1 cc rejects this. */ + char const *const *ccp; + char **p; + /* NEC SVR4.0.2 mips cc rejects this. */ + struct point {int x, y;}; + static struct point const zero = {0,0}; + /* AIX XL C 1.02.0.0 rejects this. + It does not let you subtract one const X* pointer from another in + an arm of an if-expression whose if-part is not a constant + expression */ + const char *g = "string"; + ccp = &g + (g ? g-g : 0); + /* HPUX 7.0 cc rejects these. */ + ++ccp; + p = (char**) ccp; + ccp = (char const *const *) p; + { /* SCO 3.2v4 cc rejects this. */ + char *t; + char const *s = 0 ? (char *) 0 : (char const *) 0; + + *t++ = 0; + } + { /* Someone thinks the Sun supposedly-ANSI compiler will reject this. */ + int x[] = {25, 17}; + const int *foo = &x[0]; + ++foo; + } + { /* Sun SC1.0 ANSI compiler rejects this -- but not the above. */ + typedef const int *iptr; + iptr p = 0; + ++p; + } + { /* AIX XL C 1.02.0.0 rejects this saying + "k.c", line 2.27: 1506-025 (S) Operand must be a modifiable lvalue. */ + struct s { int j; const int *ap[3]; }; + struct s *b; b->j = 5; + } + { /* ULTRIX-32 V3.1 (Rev 9) vcc rejects this */ + const int foo = 10; + } +#endif + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:2503: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + echo "$as_me:2506: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:2509: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:2512: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_c_const=yes +else + echo "$as_me: failed program was:" >&5 +cat conftest.$ac_ext >&5 +ac_cv_c_const=no +fi +rm -f conftest.$ac_objext conftest.$ac_ext +fi +echo "$as_me:2522: result: $ac_cv_c_const" >&5 +echo "${ECHO_T}$ac_cv_c_const" >&6 +if test $ac_cv_c_const = no; then + +cat >>confdefs.h <<\EOF +#define const +EOF + +fi + +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 overriden 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 cmp -s $cache_file confcache; 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 + +: ${CONFIG_STATUS=./config.status} +ac_clean_files_save=$ac_clean_files +ac_clean_files="$ac_clean_files $CONFIG_STATUS" +{ echo "$as_me:2611: creating $CONFIG_STATUS" >&5 +echo "$as_me: creating $CONFIG_STATUS" >&6;} +cat >$CONFIG_STATUS <<_ACEOF +#! $SHELL +# Generated automatically by configure. +# 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 +SHELL=\${CONFIG_SHELL-$SHELL} +ac_cs_invocation="\$0 \$@" + +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF +# Be Bourne compatible +if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then + emulate sh + NULLCMD=: +elif test -n "${BASH_VERSION+set}" && (set -o posix) >/dev/null 2>&1; then + set -o posix +fi + +# Name of the executable. +as_me=`echo "$0" |sed 's,.*[\\/],,'` + +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 + +as_executable_p="test -f" + +# Support unset when possible. +if (FOO=FOO; unset FOO) >/dev/null 2>&1; then + as_unset=unset +else + as_unset=false +fi + +# NLS nuisances. +$as_unset LANG || test "${LANG+set}" != set || { LANG=C; export LANG; } +$as_unset LC_ALL || test "${LC_ALL+set}" != set || { LC_ALL=C; export LC_ALL; } +$as_unset LC_TIME || test "${LC_TIME+set}" != set || { LC_TIME=C; export LC_TIME; } +$as_unset LC_CTYPE || test "${LC_CTYPE+set}" != set || { LC_CTYPE=C; export LC_CTYPE; } +$as_unset LANGUAGE || test "${LANGUAGE+set}" != set || { LANGUAGE=C; export LANGUAGE; } +$as_unset LC_COLLATE || test "${LC_COLLATE+set}" != set || { LC_COLLATE=C; export LC_COLLATE; } +$as_unset LC_NUMERIC || test "${LC_NUMERIC+set}" != set || { LC_NUMERIC=C; export LC_NUMERIC; } +$as_unset LC_MESSAGES || test "${LC_MESSAGES+set}" != set || { LC_MESSAGES=C; export LC_MESSAGES; } + +# IFS +# We need space, tab and new line, in precisely that order. +as_nl=' +' +IFS=" $as_nl" + +# CDPATH. +$as_unset CDPATH || test "${CDPATH+set}" != set || { CDPATH=:; export CDPATH; } + +exec 6>&1 + +_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 <<\EOF + +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 + -d, --debug don't remove temporary files + --recheck update $as_me by reconfiguring in the same conditions + --header=FILE[:TEMPLATE] + instantiate the configuration header FILE + +Configuration headers: +$config_headers + +Report bugs to ." +EOF + +cat >>$CONFIG_STATUS <>$CONFIG_STATUS <<\EOF +# 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[^=]*=\(.*\)'` + shift + set dummy "$ac_option" "$ac_optarg" ${1+"$@"} + shift + ;; + -*);; + *) # This is not an option, so the user has probably given explicit + # arguments. + ac_need_defaults=false;; + esac + + case $1 in + # Handling of the options. +EOF +cat >>$CONFIG_STATUS <>$CONFIG_STATUS <<\EOF + --version | --vers* | -V ) + echo "$ac_cs_version"; exit 0 ;; + --he | --h) + # Conflict between --help and --header + { { echo "$as_me:2778: 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 ) + shift + CONFIG_FILES="$CONFIG_FILES $1" + ac_need_defaults=false;; + --header | --heade | --head | --hea ) + shift + CONFIG_HEADERS="$CONFIG_HEADERS $1" + ac_need_defaults=false;; + + # This is an error. + -*) { { echo "$as_me:2797: 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 + +exec 5>>config.log +cat >&5 << _ACEOF + +## ----------------------- ## +## Running config.status. ## +## ----------------------- ## + +This file was extended by $as_me 2.52, executed with + CONFIG_FILES = $CONFIG_FILES + CONFIG_HEADERS = $CONFIG_HEADERS + CONFIG_LINKS = $CONFIG_LINKS + CONFIG_COMMANDS = $CONFIG_COMMANDS + > $ac_cs_invocation +on `(hostname || uname -n) 2>/dev/null | sed 1q` + +_ACEOF +EOF + +cat >>$CONFIG_STATUS <<\EOF +for ac_config_target in $ac_config_targets +do + case "$ac_config_target" in + # Handling of arguments. + "fcgi_config.h" ) CONFIG_HEADERS="$CONFIG_HEADERS fcgi_config.h" ;; + *) { { echo "$as_me:2833: 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_HEADERS+set}" = set || CONFIG_HEADERS=$config_headers +fi + +# 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. +: ${TMPDIR=/tmp} +{ + tmp=`(umask 077 && mktemp -d -q "$TMPDIR/csXXXXXX") 2>/dev/null` && + test -n "$tmp" && test -d "$tmp" +} || +{ + tmp=$TMPDIR/cs$$-$RANDOM + (umask 077 && mkdir $tmp) +} || +{ + echo "$me: cannot create a temporary directory in $TMPDIR" >&2 + { (exit 1); exit 1; } +} + +EOF + +cat >>$CONFIG_STATUS <<\EOF + +# +# 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:2903: 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:2914: 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:2927: 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 + +EOF + +# 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 <<\EOF +s/[\\&,]/\\&/g +s,[\\$`],\\&,g +t clear +: clear +s,^[ ]*#[ ]*define[ ][ ]*\(\([^ (][^ (]*\)([^)]*)\)[ ]*\(.*\)$,${ac_dA}\2${ac_dB}\1${ac_dC}\3${ac_dD},gp +t end +s,^[ ]*#[ ]*define[ ][ ]*\([^ ][^ ]*\)[ ]*\(.*\)$,${ac_dA}\1${ac_dB}\1${ac_dC}\2${ac_dD},gp +: end +EOF +# 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 <<\EOF +s,^[ ]*#[ ]*undef[ ][ ]*[a-zA-Z_][a-zA-Z_0-9]*,/* & */, +EOF + +# 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 egrep "^[ ]*#[ ]*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 # egrep' >>$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 <<\EOF + # 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 automatically by config.status. */ + if test x"$ac_file" = x-; then + echo "/* Generated automatically by configure. */" >$tmp/config.h + else + echo "/* $ac_file. Generated automatically by configure. */" >$tmp/config.h + fi + cat $tmp/in >>$tmp/config.h + rm -f $tmp/in + if test x"$ac_file" != x-; then + if cmp -s $ac_file $tmp/config.h 2>/dev/null; then + { echo "$as_me:3044: $ac_file is unchanged" >&5 +echo "$as_me: $ac_file is unchanged" >&6;} + else + ac_dir=`$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 test "$ac_dir" != "$ac_file" && test "$ac_dir" != .; then + { case "$ac_dir" in + [\\/]* | ?:[\\/]* ) as_incr_dir=;; + *) as_incr_dir=.;; +esac +as_dummy="$ac_dir" +for as_mkdir_dir in `IFS='/\\'; set X $as_dummy; shift; echo "$@"`; do + case $as_mkdir_dir in + # Skip DOS drivespec + ?:) as_incr_dir=$as_mkdir_dir ;; + *) + as_incr_dir=$as_incr_dir/$as_mkdir_dir + test -d "$as_incr_dir" || mkdir "$as_incr_dir" + ;; + esac +done; } + + fi + rm -f $ac_file + mv $tmp/config.h $ac_file + fi + else + cat $tmp/config.h + rm -f $tmp/config.h + fi + # Run the commands associated with the file. + case $ac_file in + fcgi_config.h ) # update the timestamp +echo timestamp >"./stamp-h1" + ;; + esac +done +EOF + +cat >>$CONFIG_STATUS <<\EOF + +{ (exit 0); exit 0; } +EOF +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=: + exec 5>/dev/null + $SHELL $CONFIG_STATUS || ac_cs_success=false + exec 5>>config.log + # Use ||, not &&, to avoid exiting from the if with $? = 1, which + # would make configure fail if this is the last instruction. + $ac_cs_success || { (exit 1); exit 1; } +fi + diff --git a/iipsrv/fcgi/perl/configure.in b/iipsrv/fcgi/perl/configure.in new file mode 100644 index 0000000..4f5240f --- /dev/null +++ b/iipsrv/fcgi/perl/configure.in @@ -0,0 +1,16 @@ +dnl $Id: configure.in,v 1.9 2001/09/22 09:30:45 skimo Exp $ +dnl +dnl This file is an input file used by the GNU "autoconf" program to +dnl generate the file "configure", which is run during the build +dnl to configure the system for the local environment. + +AC_INIT + +AM_CONFIG_HEADER([fcgi_config.h]) + +AC_PROG_CC +AC_PROG_CPP + +FCGI_COMMON_CHECKS + +AC_OUTPUT diff --git a/iipsrv/fcgi/perl/echo.PL b/iipsrv/fcgi/perl/echo.PL new file mode 100644 index 0000000..a8f9dec --- /dev/null +++ b/iipsrv/fcgi/perl/echo.PL @@ -0,0 +1,67 @@ +use Config; + +open OUT, ">echo.fpl"; +print OUT "#!$Config{perlpath}\n"; +print OUT while ; +close OUT; +chmod 0755, "echo.fpl"; +__END__ +# +# echo-perl -- +# +# Produce a page containing all FastCGI inputs +# +# Copyright (c) 1996 Open Market, Inc. +# +# See the file "LICENSE.TERMS" for information on usage and redistribution +# of this file, and for a DISCLAIMER OF ALL WARRANTIES. +# +# $Id: echo.PL,v 1.2 2000/12/14 13:46:23 skimo Exp $ +# +# Changed by skimo to demostrate autoflushing 1997/02/19 +# + +use FCGI; +use strict; + +sub print_env { + my($label, $envp) = @_; + print("$label:
\n
\n");
+    my @keys = sort keys(%$envp);
+    foreach my $key (@keys) {
+        print("$key=$$envp{$key}\n");
+    }
+    print("

\n"); +} + +my %env; +my $req = FCGI::Request(\*STDIN, \*STDOUT, \*STDERR, \%env); +my $count = 0; +while($req->Accept() >= 0) { + print("Content-type: text/html\r\n\r\n", + "FastCGI echo (Perl)\n", + "

FastCGI echo (Perl)

\n", + "Request number ", ++$count, "

\n"); + my $len = 0 + $env{'CONTENT_LENGTH'}; + if($len == 0) { + print("No data from standard input.

\n"); + } else { + print("Standard input:
\n

\n");
+        for(my $i = 0; $i < $len; $i++) {
+            my $ch = getc(STDIN);
+            if($ch eq "") {
+                print("Error: Not enough bytes received ",
+                      "on standard input

\n"); + last; + } + print($ch); + } + print("\n

\n"); + } + print_env("Request environment", \%env); + print "More on its way ... wait a few seconds\n
\n
"; + $req->Flush(); + sleep(3); + print_env("Initial environment", \%ENV); + $req->Finish(); +} diff --git a/iipsrv/fcgi/perl/fcgi_config.h.in b/iipsrv/fcgi/perl/fcgi_config.h.in new file mode 100644 index 0000000..c32284d --- /dev/null +++ b/iipsrv/fcgi/perl/fcgi_config.h.in @@ -0,0 +1,76 @@ +/* fcgi_config.h.in. Generated automatically from configure.in by autoheader. */ + +/* Define if you have the header file. */ +#undef HAVE_ARPA_INET_H + +/* Define if there's a fileno() prototype in stdio.h */ +#undef HAVE_FILENO_PROTO + +/* Define if the fpos_t typedef is in stdio.h */ +#undef HAVE_FPOS + +/* Define if you have the header file. */ +#undef HAVE_INTTYPES_H + +/* Define if you have the header file. */ +#undef HAVE_LIMITS_H + +/* Define if you have the header file. */ +#undef HAVE_MEMORY_H + +/* Define if you have the header file. */ +#undef HAVE_NETDB_H + +/* Define if you have the header file. */ +#undef HAVE_NETINET_IN_H + +/* Define if sockaddr_un in sys/un.h contains a sun_len component */ +#undef HAVE_SOCKADDR_UN_SUN_LEN + +/* Define if the socklen_t typedef is in sys/socket.h */ +#undef HAVE_SOCKLEN + +/* Define if you have the header file. */ +#undef HAVE_STDINT_H + +/* Define if you have the header file. */ +#undef HAVE_STDLIB_H + +/* Define if you have the header file. */ +#undef HAVE_STRINGS_H + +/* Define if you have the header file. */ +#undef HAVE_STRING_H + +/* Define if you have the header file. */ +#undef HAVE_SYS_PARAM_H + +/* Define if you have the header file. */ +#undef HAVE_SYS_SOCKET_H + +/* Define if you have the header file. */ +#undef HAVE_SYS_STAT_H + +/* Define if you have the header file. */ +#undef HAVE_SYS_TIME_H + +/* Define if you have the header file. */ +#undef HAVE_SYS_TYPES_H + +/* Define if you have the header file. */ +#undef HAVE_UNISTD_H + +/* Define if va_arg(arg, long double) crashes the compiler */ +#undef HAVE_VA_ARG_LONG_DOUBLE_BUG + +/* Define if you have the ANSI C header files. */ +#undef STDC_HEADERS + +/* Define if cross-process locking is required by accept() */ +#undef USE_LOCKING + +/* Define to empty if `const' does not conform to ANSI C. */ +#undef const + +/* Define to `int' if does not define. */ +#undef ssize_t diff --git a/iipsrv/fcgi/perl/oldinterface.pod b/iipsrv/fcgi/perl/oldinterface.pod new file mode 100644 index 0000000..bb288a1 --- /dev/null +++ b/iipsrv/fcgi/perl/oldinterface.pod @@ -0,0 +1,50 @@ +=head1 NAME + +FCGI - Fast CGI module + +=head1 SYNOPSIS + + use FCGI; + + $count = 0; + while(FCGI::accept() >= 0) { + print("Content-type: text/html\r\n\r\n", ++$count); + } + +=head1 DESCRIPTION + +Functions: + +=over 4 + +=item FCGI::accept() + +Accepts a connection. Returns 0 on success. +If a connection has been accepted before, the old +one will be finished first. + +=item FCGI::finish() + +Finishes accepted connection. + +=item FCGI::flush() + +Flushes accepted connection. + +=item FCGI::set_exit_status(status) + +Sets the exit status that finish returns to the server. + +=item FCGI::start_filter_data() + +Does anyone use this function ? + +=back + +=head1 AUTHOR + +Sven Verdoolaege + +=cut + +__END__ diff --git a/iipsrv/fcgi/perl/remote.PL b/iipsrv/fcgi/perl/remote.PL new file mode 100644 index 0000000..bcfdd7f --- /dev/null +++ b/iipsrv/fcgi/perl/remote.PL @@ -0,0 +1,36 @@ +use Config; + +open OUT, ">remote.fpl"; +print OUT "#!$Config{perlpath}\n"; +print OUT while ; +close OUT; +chmod 0755, "remote.fpl"; +__END__ +# An example of using a remote script with an Apache webserver. +# Run this Perl program on "otherhost" to bind port 8888 and wait +# for FCGI requests from the webserver. + +## Sample Apache configuration on the webserver to refer to the +## remote script on "otherhost" +# +# AddHandler fastcgi-script fcgi +# FastCgiExternalServer /path-to/cgi-bin/external.fcgi -host otherhost:8888 +# + +# Access the URL: http://webserver/cgi-bin/external.fcgi + +# Contributed by Don Bindner + +use FCGI; + +my $socket = FCGI::OpenSocket( ":8888", 5 ); +my $request = FCGI::Request( \*STDIN, \*STDOUT, \*STDERR, + \%ENV, $socket ); + +my $count; +while( $request->Accept() >= 0 ) { + print "Content-type: text/html\r\n\r\n"; + print ++$count; +} + +FCGI::CloseSocket( $socket ); diff --git a/iipsrv/fcgi/perl/threaded.PL b/iipsrv/fcgi/perl/threaded.PL new file mode 100644 index 0000000..f8a8c62 --- /dev/null +++ b/iipsrv/fcgi/perl/threaded.PL @@ -0,0 +1,52 @@ +use Config; + +open OUT, ">threaded.fpl"; +print OUT "#!$Config{perlpath}\n"; +print OUT while ; +close OUT; +chmod 0755, "threaded.fpl"; +__END__ + +use FCGI; +use Thread; +use IO::Handle; + +use constant THREAD_COUNT => 5; + +sub doit { + my $k = shift; + my %env; + my $in = new IO::Handle; + my $out = new IO::Handle; + my $err = new IO::Handle; + + my $request = FCGI::Request($in, $out, $err, \%env); + + while ($request->Accept() >= 0) { + print $out + "Content-type: text/html\r\n", + "\r\n", + "FastCGI Hello! (multi-threaded perl, fcgiapp library)", + "

FastCGI Hello! (multi-threaded perl, fcgiapp library)

", + "Request counts for ", THREAD_COUNT ," threads ", + "running on host $env{SERVER_NAME}

"; + + { + lock(@count); + + ++$count[$k]; + + for(my $i = 0; $i < THREAD_COUNT; ++$i) { + print $out $count[$i]; + print $out " "; + } + } + $request->Flush(); + sleep(1); + } +} + +for ($t = 1; $t < THREAD_COUNT; ++$t) { + new Thread \&doit, $t; +} +doit(0); diff --git a/iipsrv/fcgi/perl/typemap b/iipsrv/fcgi/perl/typemap new file mode 100644 index 0000000..62618be --- /dev/null +++ b/iipsrv/fcgi/perl/typemap @@ -0,0 +1,17 @@ +TYPEMAP +FCGI T_PTROBJ +FCGI::Stream T_PTROBJ +GLOBREF T_GLOBREF +HASHREF T_HASHREF + +INPUT +T_GLOBREF + if (SvROK($arg) && isGV(SvRV($arg))) { + $var = (GV*)SvRV($arg); + } else + croak(\"$var is not a GLOB reference\"); +T_HASHREF + if (SvROK($arg) && SvTYPE(SvRV($arg)) == SVt_PVHV) { + $var = (HV*)SvRV($arg); + } else + croak(\"$var is not a reference to a hash\"); diff --git a/iipsrv/fcgi/perl/version.pm b/iipsrv/fcgi/perl/version.pm new file mode 100644 index 0000000..1f2ec8d --- /dev/null +++ b/iipsrv/fcgi/perl/version.pm @@ -0,0 +1,3 @@ +package FCGI; + +$VERSION = '0.67'; diff --git a/iipsrv/man/Makefile.am b/iipsrv/man/Makefile.am new file mode 100644 index 0000000..a9740fa --- /dev/null +++ b/iipsrv/man/Makefile.am @@ -0,0 +1,4 @@ +man_MANS = \ + iipsrv.8 + +EXTRA_DIST = ${man_MANS} diff --git a/iipsrv/man/iipsrv.8 b/iipsrv/man/iipsrv.8 new file mode 100644 index 0000000..1e4d0a8 --- /dev/null +++ b/iipsrv/man/iipsrv.8 @@ -0,0 +1,180 @@ +.TH IIPSRV 8 "AUGUST 2014" Linux "User Manuals" +.SH NAME + +IIPSRV \- IIPImage Image Server + +.SH DESCRIPTION +IIPImage is an advanced high-performance feature-rich multi-protocol image server for web-based streamed viewing and zooming of ultra high-resolution +images. It is designed to be fast and bandwidth-efficient with low processor and memory requirements. The system can comfortably handle gigapixel size images as +well as advanced image features such as 8, 16 and 32 bit depths, CIELAB colorimetric images and scientific imagery such as multispectral images. +Source images can be either TIFF (tiled multi-resolution) or JPEG2000 (if enabled). + +The imaging server can also dynamically export images in JPEG format and perform basic image processing, such as contrast adjustment, gamma control, conversion from color to greyscale, color twist, region extraction and arbitrary rescaling. The server can also export spectral point or profile data from multispectral data and apply color maps or perform hillshading rendering. + +.SH SYNOPSIS + +Command line use: + +.B iipsrv.fcgi --bind +.I host +: +.I port + + +.SH FILES + +.IR iipsrv.fcgi +main executable + +.IR iipsrv.log +log file: usually in +.IR /var/log/ +or +.IR /tmp/ + + +.SH OPTIONS + +There are several parameters that can be supplied to +.B iipsrv.fcgi +These should be set via the appropriate web server configuration directives if running via Apache or Lighttpd. See +.B EXAMPLES +for details of web server configuations. +Alternatively these parameters can be set via environment settings if running directly from the command line or from +.B spawn-fcgi. + +.IP LOGFILE +The log file the module will (attempt) to write to. If no +value is given, no log will be written. Make sure the server +process has write access to this directory. Paths with spaces +in them may not work correctly. +.IP VERBOSITY +The level of logging. 0 means no logging, 1 is minimal logging, +2 lots of debugging stuff and 3 even more debugging stuff and 4 +a very large amount indeed. Logging is only enabled if +.BR LOGFILE +has also been defined. +.IP JPEG_QUALITY +The default JPEG quality factor for compression when the client +does not specify one. The value should be between 1 (highest level +of compression) and 100 (highest image quality). The default is 75. +.IP MAX_IMAGE_CACHE_SIZE +Max image cache size to be held in RAM in MB. This is a cache of +the compressed JPEG image tiles requested by the client. The default +is 5MB. +.IP FILESYSTEM_PREFIX +This is a prefix automatically added by the server to the +beginning of each file system path. This can be useful for security reasons to +limit access to certain sub-directories. For example, with a prefix of +"/home/images/" set on the server, a request by a client for "image.tif" will +point to the path "/home/images/image.tif". Any reverse directory path +component such as ../ is also filtered out. No default value. +.IP MAX_CVT +The maximum permitted image pixel size returned by the CVT command +in conjunction with WID or HEI or RGN. The default is 5000. This +prevents huge requests from overloading the server +.IP LAYERS +The number of quality layers to decode for image that support +progressive quality encoding, such as JPEG2000. Ignored for other file +formats. The default is 1. +.IP WATERMARK +TIFF image to use as watermark file. This image should be not be +bigger the tile size used for TIFF tiling. If bigger, it will simply be +cropped to the tile size. If smaller, the watermark will be positioned +randomly within the available space. The image can be either colour or +grayscale. +.IP WATERMARK_PROBABILITY +The probability that a particilar tile will have a watermark +applied to it. 0 means never, 1 means always. +.IP WATERMARK_OPACITY +The opacity (between 0 and 1) applied to the watermark image. +.IP MEMCACHED_SERVERS +A comma-delimitted list of memcached servers with optional +port numbers. For example: localhost,192.168.0.1:8888,192.168.0.2. +.IP MEMCACHED_TIMEOUT +Time in seconds that cache remains fresh. Default is 86400 seconds (24 hours). +.IP FILENAME_PATTERN +Pattern that follows the name stem for a panoramic image sequence. +eg: "_pyr_" for +.IR FZ1_pyr_000_090.tif . +In this example, just supply FZ1 to the FIF command. The "000" +indicates the vertical angle and "090" the horizontal. This is only +relevant to 3D image sequences. The default is "_pyr_". +.IP CORS +Cross Origin Resource Sharing setting. Disabled by default. +Set to "*" to enable for all domains or specify a single domain. +See http://www.w3.org/TR/cors/ for more details on CORS. +.IP BASE_URL +Set a base URL for use in certain protocol requests if web server rewriting has taken place and the public URL is not the same as that supplied to +.B iipsrv + + +.SH EXAMPLES + +.B iipsrv +will be automatically started by both Apache and Lighttpd. But not by Nginx or Java Application Servers. +See the example configuration in the README or included with your distribution for the appropriate syntax. +Note that Apache has two FCGI modules: mod_fastcgi and mod_fcgid which are configured differently. + +You may also wish to +run +.B iipsrv +as a standalone program. To do this, use the following syntax to bind to a particular port and listen for FCGI (not HTTP) requests. +In the following example, +.B iipsrv +will bind to port 9000 on the machine's IP address 192.168.0.1: + +% iipsrv.fcgi --bind 192.168.0.1:9000 + +It is also possible to run +.Iiipsrv +via the +.I spawn-fcgi +program. Set up any parameters via environment variables and run the command as follows to bind, as in the previous example to port 9000 on IP address 192.168.0.1: + +% spawn-fcgi -f src/iipsrv.fcgi -a 192.168.0.1 -p 9000 + +For use in stand alone or spawn-fcgi mode, you will then need to configure your webserver on the same machine or another to direct FCGI protocol requests to this IP address and port. + +For web servers such as Nginx or Java Application Servers such as Tomcat, JBoss or Jetty, which cannot automatically start FCGI processes, +.B iipsrv +will need to be started in stand alone mode or via spawn-fcgi. + + +.SH PROTOCOLS + +The IIPImage server supports the +.B Internet Imaging Protocol (IIP) +, the +.B Zoomify +protocol, the +.B DeepZoom +and the +.B International Image Interoperability Framework (IIIF) +protocols. Client applications supporting these protocols should be able to use +.B iipsrv +as their back-end server. +.B IIP +is the most feature rich of the 4 protocols and allows access to the more advanced imaging server features. + + + +.SH IMAGE PATHS + +The image paths given to the server must be absolute paths on the server machine (eg. via the FIF variable for the IIP protocol: FIF=/images/test.tif) and +.I not +paths +relative to the web server document root location. If the FILESYSTEM_PREFIX server directive has been set (see OPTIONS above), then this prefix is automatically pre-pended to all requests +to generate the absolute image path. Make sure that the server process owner is able to access and read the images. + +Note that images do +.I not +need to be directly accessible externally by the client via the web server. + + +.SH SEE ALSO +IIPImage website: http://iipimage.sourceforge.net + +.SH AUTHORS +Ruven Pillay + diff --git a/iipsrv/src/CVT.cc b/iipsrv/src/CVT.cc new file mode 100644 index 0000000..db87a1c --- /dev/null +++ b/iipsrv/src/CVT.cc @@ -0,0 +1,478 @@ +/* + IIP CVT Command Handler Class Member Function + + Copyright (C) 2006-2014 Ruven Pillay. + + 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 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +#include "Task.h" +#include "Transforms.h" +#include "Environment.h" +#include +#include + +//#define CHUNKED 1 + +using namespace std; + + + +void CVT::send( Session* session ){ + + if( session->loglevel >= 2 ) *(session->logfile) << "CVT handler reached" << endl; + + this->session = session; + checkImage(); + + + // Time this command + if( session->loglevel >= 2 ) command_timer.start(); + + + // Reload info in case we are dealing with a sequence + //(session->image)->loadImageInfo( session->view->xangle, session->view->yangle ); + + + // Calculate the number of tiles at the requested resolution + unsigned int im_width = (session->image)->getImageWidth(); + unsigned int im_height = (session->image)->getImageHeight(); + int num_res = (session->image)->getNumResolutions(); + + // Setup our view with some basic info + session->view->setImageSize( im_width, im_height ); + session->view->setMaxResolutions( num_res ); + + // Get the resolution, width and height for this view + int requested_res = session->view->getResolution(); + im_width = (session->image)->image_widths[num_res-requested_res-1]; + im_height = (session->image)->image_heights[num_res-requested_res-1]; + + + if( session->loglevel >= 3 ){ + *(session->logfile) << "CVT :: Using resolution " << requested_res << " with size " << im_width << "x" << im_height << endl; + } + + + // Data length + int len; + + // Set up our final image sizes and if we have a region defined, + // calculate our viewport + unsigned int resampled_width, resampled_height; + unsigned int view_left, view_top, view_width, view_height; + + if( session->view->viewPortSet() ){ + + // Set the absolute viewport size and extract the co-ordinates + view_left = session->view->getViewLeft(); + view_top = session->view->getViewTop(); + view_width = session->view->getViewWidth(); + view_height = session->view->getViewHeight(); + resampled_width = session->view->getRequestWidth(); + resampled_height = session->view->getRequestHeight(); + + if( session->loglevel >= 3 ){ + *(session->logfile) << "CVT :: Region: " << view_left << "," << view_top + << "," << view_width << "," << view_height << endl; + } + } + else{ + if( session->loglevel >= 4 ) *(session->logfile) << "CVT :: No view port set" << endl; + view_left = 0; + view_top = 0; + view_width = im_width; + view_height = im_height; + resampled_width = session->view->getRequestWidth(); + resampled_height = session->view->getRequestHeight(); + } + + + // If we have requested that the aspect ratio be maintained, make sure the final image fits *within* the requested size + if( session->view->maintain_aspect ){ + if( ((float)resampled_height/(float)view_height) > ((float)resampled_width/(float)view_width) ){ + resampled_height = (unsigned int) round((((float)resampled_width/(float)view_width) * view_height)); + } + else if( ((float)resampled_width/(float)view_width) > ((float)resampled_height/(float)view_height) ){ + resampled_width = (unsigned int) round((((float)resampled_height/(float)view_height) * view_width)); + } + } + + + if( session->loglevel >= 3 ){ + *(session->logfile) << "CVT :: Requested scaled region size is " << resampled_width << "x" << resampled_height + << " at resolution " << requested_res + << ". Nearest existing resolution is " << view_width << "x" << view_height << endl; + } + + +#ifndef DEBUG + + // Define our separator depending on the OS +#ifdef WIN32 + const string separator = "\\"; +#else + const string separator = "/"; +#endif + + + // Get our image file name and strip of the directory path and any suffix + string filename = (session->image)->getImagePath(); + int pos = filename.rfind(separator)+1; + string basename = filename.substr( pos, filename.rfind(".")-pos ); + + char str[1024]; + snprintf( str, 1024, "Server: iipsrv/%s\r\n" + "Cache-Control: max-age=%d\r\n" + "Last-Modified: %s\r\n" + "Content-Type: image/jpeg\r\n" + "Content-Disposition: inline;filename=\"%s.jpg\"\r\n" +#ifdef CHUNKED + "Transfer-Encoding: chunked\r\n" +#endif + "\r\n", + VERSION, MAX_AGE, (session->image)->getTimestamp().c_str(), basename.c_str() ); + + session->out->printf( (const char*) str ); +#endif + + + // Get our requested region from our TileManager + TileManager tilemanager( session->tileCache, session->image, session->watermark, session->jpeg, session->logfile, session->loglevel ); + RawTilePtr complete_image = tilemanager.getRegion( requested_res, + session->view->xangle, session->view->yangle, + session->view->getLayers(), + view_left, view_top, view_width, view_height ); + + + + // Convert CIELAB to sRGB + if( (session->image)->getColourSpace() == CIELAB ){ + Timer cielab_timer; + if( session->loglevel >= 3 ){ + *(session->logfile) << "CVT :: Converting from CIELAB->sRGB" << endl; + cielab_timer.start(); + } + filter_LAB2sRGB( complete_image ); + if( session->loglevel >= 3 ){ + *(session->logfile) << "CVT :: CIELAB->sRGB conversion in " << cielab_timer.getTime() + << " microseconds" << endl; + } + } + + + + // Only use our float pipeline if necessary + if( complete_image->bpc > 8 || session->view->getContrast() != 1.0 || session->view->getGamma() != 1.0 || + session->view->cmapped || session->view->shaded || session->view->inverted || session->view->ctw.size() ){ + + // Apply normalization and float conversion + if( session->loglevel >= 4 ){ + *(session->logfile) << "CVT :: Normalizing and converting to float"; + } + + // Apply normalization and float conversion + filter_normalize( complete_image, (session->image)->max, (session->image)->min ); + + + // Apply hill shading if requested + if( session->view->shaded ){ + if( session->loglevel >= 3 ){ + *(session->logfile) << "CVT :: Applying hill-shading" << endl; + } + filter_shade( complete_image, session->view->shade[0], session->view->shade[1] ); + } + + + // Apply color twist if requested + if( session->view->ctw.size() ){ + if( session->loglevel >= 3 ){ + *(session->logfile) << "CVT :: Applying color twist" << endl; + } + filter_twist( complete_image, session->view->ctw ); + } + + + // Apply any gamma correction + if( session->view->getGamma() != 1.0 ){ + float gamma = session->view->getGamma(); + if( session->loglevel >= 3 ){ + *(session->logfile) << "CVT :: Applying gamma of " << gamma << endl; + } + filter_gamma( complete_image, gamma ); + } + + + // Apply inversion if requested + if( session->view->inverted ){ + if( session->loglevel >= 3 ){ + *(session->logfile) << "CVT :: Applying inversion" << endl; + } + filter_inv( complete_image ); + } + + + // Apply color mapping if requested + if( session->view->cmapped ){ + if( session->loglevel >= 3 ){ + *(session->logfile) << "CVT :: Applying color map" << endl; + } + filter_cmap( complete_image, session->view->cmap ); + } + + + // Apply any contrast adjustments and/or clipping to 8bit from 16bit or 32bit + if( session->loglevel >= 3 ){ + *(session->logfile) << "CVT :: Applying contrast of " << session->view->getContrast() << endl; + } + filter_contrast( complete_image, session->view->getContrast() ); + + } + + + + // Resize our image as requested. Use the interpolation method requested in the server configuration. + // - Use bilinear interpolation by default + if( (view_width!=resampled_width) || (view_height!=resampled_height) ){ + Timer interpolation_timer; + string interpolation_type; + if( session->loglevel >= 5 ){ + interpolation_timer.start(); + } + unsigned int interpolation = Environment::getInterpolation(); + switch( interpolation ){ + case 0: + interpolation_type = "nearest neighbour"; + filter_interpolate_nearestneighbour( complete_image, resampled_width, resampled_height ); + break; + default: + interpolation_type = "bilinear"; + filter_interpolate_bilinear( complete_image, resampled_width, resampled_height ); + break; + } + if( session->loglevel >= 5 ){ + *(session->logfile) << "CVT :: Resizing using " << interpolation_type << " interpolation in " + << interpolation_timer.getTime() << " microseconds" << endl; + } + } + + + // Reduce to 1 or 3 bands if we have an alpha channel or a multi-band image + if( complete_image->channels == 2 ){ + if( session->loglevel >= 3 ){ + *(session->logfile) << "CVT :: Flattening to 1 channel" << endl; + } + filter_flatten( complete_image, 1 ); + } + else if( complete_image->channels > 3 ){ + if( session->loglevel >= 3 ){ + *(session->logfile) << "CVT :: Flattening to 3 channels" << endl; + } + filter_flatten( complete_image, 3 ); + } + + + + // Convert to greyscale if requested + if( (session->image)->getColourSpace() == sRGB && session->view->colourspace == GREYSCALE ){ + + Timer greyscale_timer; + if( session->loglevel >= 5 ){ + greyscale_timer.start(); + } + + filter_greyscale( complete_image ); + + if( session->loglevel >= 5 ){ + *(session->logfile) << "CVT :: Converting to greyscale in " + << greyscale_timer.getTime() << " microseconds" << endl; + } + } + + + + // Apply flip + if( session->view->flip != 0 ){ + Timer flip_timer; + if( session->loglevel >= 5 ){ + flip_timer.start(); + } + + filter_flip( complete_image, session->view->flip ); + + if( session->loglevel >= 5 ){ + string direction = session->view->flip==1 ? "horizontally" : "vertically"; + *(session->logfile) << "JTL :: Flipping image " << direction << " in " + << flip_timer.getTime() << " microseconds" << endl; + } + } + + + + // Apply rotation - can apply this safely after gamma and contrast adjustment + if( session->view->getRotation() != 0.0 ){ + Timer rotation_timer; + if( session->loglevel >= 5 ){ + rotation_timer.start(); + } + + float rotation = session->view->getRotation(); + filter_rotate( complete_image, rotation ); + + // For 90 and 270 rotation swap width and height + resampled_width = complete_image->width; + resampled_height = complete_image->height; + + if( session->loglevel >= 5 ){ + *(session->logfile) << "CVT :: Rotating image by " << rotation << " degrees in " + << rotation_timer.getTime() << " microseconds" << endl; + } + } + + + + // Initialise our JPEG compression object + session->jpeg->InitCompression( complete_image, resampled_height ); + + // Add XMP metadata if this exists + if( (session->image)->getMetadata("xmp").size() > 0 ){ + if( session->loglevel >= 4 ) *(session->logfile) << "CVT :: Adding XMP metadata" << endl; + session->jpeg->addMetadata( (session->image)->getMetadata("xmp") ); + } + + len = session->jpeg->getHeaderSize(); + +#ifdef CHUNKED + snprintf( str, 1024, "%X\r\n", len ); + if( session->loglevel >= 4 ) *(session->logfile) << "CVT :: JPEG Header Chunk : " << str; + session->out->printf( str ); +#endif + + if( session->out->putStr( (const char*) session->jpeg->getHeader(), len ) != len ){ + if( session->loglevel >= 1 ){ + *(session->logfile) << "CVT :: Error writing jpeg header" << endl; + } + } + +#ifdef CHUNKED + session->out->printf( "\r\n" ); +#endif + + // Flush our block of data + if( session->out->flush() == -1 ) { + if( session->loglevel >= 1 ){ + *(session->logfile) << "CVT :: Error flushing jpeg data" << endl; + } + } + + + // Send out the data per strip of fixed height. + // Allocate enough memory for this plus an extra 16k for instances where compressed + // data is greater than uncompressed + unsigned int strip_height = 128; + unsigned int channels = complete_image->channels; + unsigned char* output = new unsigned char[resampled_width*channels*strip_height+16536]; + int strips = (resampled_height/strip_height) + (resampled_height%strip_height == 0 ? 0 : 1); + + for( int n=0; ndata)[n*strip_height*resampled_width*channels]; + + // The last strip may have a different height + if( (n==strips-1) && (resampled_height%strip_height!=0) ) strip_height = resampled_height % strip_height; + + if( session->loglevel >= 3 ){ + *(session->logfile) << "CVT :: About to JPEG compress strip with height " << strip_height << endl; + } + + // Compress the strip + len = session->jpeg->CompressStrip( input, output, strip_height ); + + if( session->loglevel >= 3 ){ + *(session->logfile) << "CVT :: Compressed data strip length is " << len << endl; + } + +#ifdef CHUNKED + // Send chunk length in hex + snprintf( str, 1024, "%X\r\n", len ); + if( session->loglevel >= 4 ) *(session->logfile) << "CVT :: Chunk : " << str; + session->out->printf( str ); +#endif + + // Send this strip out to the client + if( len != session->out->putStr( (const char*) output, len ) ){ + if( session->loglevel >= 1 ){ + *(session->logfile) << "CVT :: Error writing jpeg strip data: " << len << endl; + } + } + +#ifdef CHUNKED + // Send closing chunk CRLF + session->out->printf( "\r\n" ); +#endif + + // Flush our block of data + if( session->out->flush() == -1 ) { + if( session->loglevel >= 1 ){ + *(session->logfile) << "CVT :: Error flushing jpeg data" << endl; + } + } + + } + + // Finish off the image compression + len = session->jpeg->Finish( output ); + +#ifdef CHUNKED + snprintf( str, 1024, "%X\r\n", len ); + if( session->loglevel >= 4 ) *(session->logfile) << "CVT :: Final Data Chunk : " << str << endl; + session->out->printf( str ); +#endif + + if( session->out->putStr( (const char*) output, len ) != len ){ + if( session->loglevel >= 1 ){ + *(session->logfile) << "CVT :: Error writing jpeg EOI markers" << endl; + } + } + + delete[] output; + + +#ifdef CHUNKED + // Send closing chunk CRLF + session->out->printf( "\r\n" ); + // Send closing blank chunk + session->out->printf( "0\r\n\r\n" ); +#endif + + if( session->out->flush() == -1 ) { + if( session->loglevel >= 1 ){ + *(session->logfile) << "CVT :: Error flushing jpeg tile" << endl; + } + } + + // Inform our response object that we have sent something to the client + session->response->setImageSent(); + + + + // Total CVT response time + if( session->loglevel >= 2 ){ + *(session->logfile) << "CVT :: Total command time " << command_timer.getTime() << " microseconds" << endl; + } + + +} diff --git a/iipsrv/src/Cache.h b/iipsrv/src/Cache.h new file mode 100644 index 0000000..c499784 --- /dev/null +++ b/iipsrv/src/Cache.h @@ -0,0 +1,455 @@ +// Tile Cache Class + +/* IIP Image Server + + Copyright (C) 2005-2014 Ruven Pillay. + Based on an LRU cache by Patrick Audley + Copyright (C) 2004 by Patrick Audley + + 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 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +/* + * Cache Modified by Tony Pan, 2014. + * templated cache to support caching both tile pointers and image pointers. + */ + +#ifndef _CACHE_H +#define _CACHE_H + + +// Fix missing snprintf in Windows +#if _MSC_VER +#define snprintf _snprintf +#endif + +#include + +// Test for available map types. Try to use an efficient hashed map type if possible +// and define this as HASHMAP, which we can then use elsewhere. +#if defined(HAVE_UNORDERED_MAP) +#include +#define HASHMAP std::unordered_map + +#elif defined(HAVE_TR1_UNORDERED_MAP) +#include +#define HASHMAP std::tr1::unordered_map + +// Use the gcc hash_map extension if we have it +#elif defined(HAVE_EXT_HASH_MAP) +#include +#define HASHMAP __gnu_cxx::hash_map + +/* Explicit template specialization of hash of a string class, + which just uses the internal char* representation as a wrapper. + Required for older versions of gcc as hashing on a string is + not supported. + */ +namespace __gnu_cxx { + template <> + struct hash { + size_t operator() (const std::string& x) const { + // TCP: compare content. + return __stl_hash_string(x.c_str()); + } + }; +} + +// If no hash type available, just use map +#else +#include +#define HASHMAP std::map + +#endif // End of #if defined + + + +// Try to use the gcc high performance memory pool allocator (available in gcc >= 3.4) +#ifdef HAVE_EXT_POOL_ALLOCATOR +#include +#endif + + + +#include +#include +#include +#include "RawTile.h" +#include "IIPImage.h" + + + +/// Cache to store raw tile data +template +class Cache { + + protected: + +#if defined(HAS_SHARED_PTR) + typedef std::shared_ptr ValuePtr; +#else + typedef Value* ValuePtr; +#endif + + + /// Max memory size in bytes + const size_t maxSize; + + /// Current memory running total + size_t currentSize; + + /// Main cache storage typedef Don't need to store key in list again. + #ifdef HAVE_EXT_POOL_ALLOCATOR + // typedef std::list < std::pair, + // __gnu_cxx::__pool_alloc< std::pair > > ObjectList; + typedef std::list < ValuePtr , + __gnu_cxx::__pool_alloc< ValuePtr > > ObjectList; + #else + // typedef std::list < std::pair > ObjectList; + typedef std::list < ValuePtr > ObjectList; + #endif + + /// Main cache list iterator typedef + typedef typename ObjectList::iterator List_Iter; + + // can store list iterators in map because list iterators are not affected by insert/delete etc to list. + + /// Index typedef + #ifdef HAVE_EXT_POOL_ALLOCATOR + typedef HASHMAP < std::string, List_Iter, + __gnu_cxx::hash< std::string >, + std::equal_to< std::string >, + __gnu_cxx::__pool_alloc< std::pair > + > ObjectMap; + #else + typedef HASHMAP < std::string, List_Iter > ObjectMap; + #endif + + + /// Main cache storage object + ObjectList objList; + + /// Main Cache storage index object + ObjectMap objMap; + + + /// Internal touch function + /** Touches a key in the Cache and makes it the most recently used + * @param key to be touched + * @return a Map_Iter pointing to the key that was touched. + */ + typename ObjectMap::iterator _touch( const std::string &key ) { + typename ObjectMap::iterator miter = objMap.find( key ); + if( miter == objMap.end() ) return miter; + // Move the found node to the head of the list. + objList.splice( objList.begin(), objList, miter->second ); + return miter; + } + + + /// Internal remove function + /** + * @param miter Map_Iter that points to the key to remove + * @warning miter is no longer usable after being passed to this function. + */ + void _remove( const typename ObjectMap::iterator &miter ) { + // Reduce our current size counter + currentSize -= getRecordSize(miter); + objList.erase( miter->second ); + +#if !defined(HAS_SHARED_PTR) + delete *(miter->second); +#endif + + objMap.erase( miter ); + + // internal shared pointer should have reference count decremented automatically. + } + + /// Interal remove function + /** @param key to remove */ + void _remove( const std::string &key ) { + typename ObjectMap::iterator miter = objMap.find( key ); + this->_remove( miter ); + } + + // remember to add objSize. + size_t getRecordSize( const typename ObjectMap::iterator &miter ) { + return getRecordSize(miter->first, *(miter->second)); + } + + virtual size_t getRecordSize( const std::string &key, const ValuePtr val ) = 0; + + virtual std::string getIndex( const ValuePtr r ) = 0; + + virtual time_t getTimestamp ( const ValuePtr r ) = 0; + + /// Constructor + /** @param max Maximum cache size in bytes or count */ + explicit Cache( const size_t max ) : + maxSize(max), + currentSize(0), + objList(), + objMap() + {}; + + + public: + + + + /// Destructor + virtual ~Cache() { + clear(); + } + + void clear() { +#if !defined(HAS_SHARED_PTR) + for (List_Iter it = objList.begin(); it != objList.end(); ++it) { + delete *it; + } +#endif + + objList.clear(); + objMap.clear(); + + // shared pointers deleter called automatically. + } + + /// Insert a tile + /** @param r Tile to be inserted. shared pointer copied in.*/ + void insert( const ValuePtr rt ) { + + if( maxSize == 0 ) return; + + if (!rt) return; // pointer expired. + + // make a local copy of the POINTER + ValuePtr r(rt); + + std::string key = this->getIndex( r ); + + // Touch the key, if it exists + typename ObjectMap::iterator miter = this->_touch( key ); + + // Check whether this tile exists in our cache + if( miter != objMap.end() ){ + // Check the timestamp and delete if necessary + if( getTimestamp(*(miter->second)) < getTimestamp(r) ){ + this->_remove( miter ); // old RawTile will be destroyed when no one else is using it. + } + // If this index already exists and it is up to date, do nothing + else return; // r will be destroyed properly, leaving miter. + } + + // Update our total current size variable BEFORE moving it. Use the string::capacity function + // rather than length() as std::string can allocate slightly more than necessary + // The +1 is for the terminating null byte + currentSize += getRecordSize(key, r); + + // Store the key if it doesn't already exist in our cache + // Ok, do the actual insert at the head of the list + objList.push_front( r ); + + // And store this in our map + List_Iter liter = objList.begin(); + objMap[ key ] = liter; + + + + // Check to see if we need to remove an element due to exceeding max_size + while( currentSize > maxSize ) { + // Remove the last element + liter = objList.end(); + --liter; + key = this->getIndex( *liter ); + this->_remove( key ); + } + + } + + + /// Return the number of tiles in the cache + unsigned int getNumElements() { return objList.size(); } + + + /// Get a tile from the cache + /** + * @param f filename + * @param r resolution number + * @param t tile number + * @param h horizontal sequence number + * @param v vertical sequence number + * @param c compression type + * @param q compression quality + * @return pointer to data or NULL on error + */ + ValuePtr getObject( const std::string &key ) { + + if( maxSize == 0 ) return NULL; + + typename ObjectMap::iterator miter = objMap.find( key ); + if( miter == objMap.end() ) return ValuePtr(); + + this->_touch( key ); + + return ValuePtr(*(miter->second)); + } + + + void evict( const ValuePtr rt ) { + std::string key = this->getIndex( rt ); + this->_remove( key ); + } + + /// Return the amount of cache used, in units defined by the subclass. + virtual float getMemorySize() = 0; + +}; + +class TileCache : public Cache { + + protected: + + typedef Cache BaseCacheType; + + /// Main cache storage typedef Don't need to store key in list again. + typedef BaseCacheType::ObjectList ObjectList; + /// Main cache list iterator typedef + typedef BaseCacheType::List_Iter List_Iter; + /// Index typedef + typedef BaseCacheType::ObjectMap ObjectMap; + + + /// Basic object storage size + const int objSize; + + // can store list iterators in map because list iterators are not affected by insert/delete etc to list. + + // remember to add objSize. + virtual size_t getRecordSize( const std::string &key, const RawTilePtr val ) { + return ( val->dataLength + + ( val->filename.capacity() + key.capacity() ) * sizeof(char) + + this->objSize ); + } + + + virtual std::string getIndex( const RawTilePtr r ) { + return TileCache::getIndex( r->filename, r->resolution, r->tileNum, + r->hSequence, r->vSequence, r->compressionType, r->quality ); + } + + virtual time_t getTimestamp ( const RawTilePtr r ) { + return r->timestamp; + } + + + public: + + /// Constructor + /** @param max Maximum cache size in MBs */ + explicit TileCache( float max ) : + objSize(sizeof( RawTile ) + + sizeof( RawTilePtr ) + + sizeof( List_Iter ) + + sizeof( std::pair ) + + sizeof(char) * 64), BaseCacheType(ceil(max * 1024.0 * 1024.0)) {}; + // 64 chars added at the end represents an average string length + + + /// Destructor + virtual ~TileCache() {} + + + /// Create a hash index + /** + * @param f filename + * @param r resolution number + * @param t tile number + * @param h horizontal sequence number + * @param v vertical sequence number + * @param c compression type + * @param q compression quality + * @return string + */ + static std::string getIndex( std::string f, int r, int t, int h, int v, CompressionType c, int q ) { + char tmp[1024]; + snprintf( tmp, 1024, "%s:%d:%d:%d:%d:%d:%d", f.c_str(), r, t, h, v, c, q ); + return std::string( tmp ); + } + + virtual float getMemorySize() { + return currentSize / (1024.0 * 1024.0); + } + + +}; + + + + +class ImageCache : public Cache { + + protected: + + typedef Cache BaseCacheType; + + + /// Main cache storage typedef Don't need to store key in list again. + typedef BaseCacheType::ObjectList ObjectList; + /// Main cache list iterator typedef + typedef BaseCacheType::List_Iter List_Iter; + /// Index typedef + typedef BaseCacheType::ObjectMap ObjectMap; + + + // can store list iterators in map because list iterators are not affected by insert/delete etc to list. + + // remember to add objSize. + virtual size_t getRecordSize( const std::string &key, const IIPImagePtr val ) { + return 1; + } + + virtual std::string getIndex( const IIPImagePtr r ) { + return r->getImagePath(); + } + + + virtual time_t getTimestamp ( const IIPImagePtr r ) { + return r->timestamp; + } + + + public: + + /// Constructor + /** @param max Maximum cache size in number of IIPImage Objects */ + explicit ImageCache( int max ) : BaseCacheType(max) {}; + // 64 chars added at the end represents an average string length + + + /// Destructor + virtual ~ImageCache() {} + + // get number of image objects. + virtual float getMemorySize() { + return currentSize; + } + +}; + + + +#endif diff --git a/iipsrv/src/DSOImage.cc b/iipsrv/src/DSOImage.cc new file mode 100644 index 0000000..a0e9d17 --- /dev/null +++ b/iipsrv/src/DSOImage.cc @@ -0,0 +1,280 @@ + +/* DSO module loader for external image types + + Copyright (C) 2000-2012 Ruven Pillay. + + 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 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + + +#ifdef ENABLE_DL + +#include "DSOImage.h" + +#include + + +using namespace std; + + +// Typedefs for typecasting our loaded module functions +// - there's probably a more elegant way to do this :/ + +typedef char* (*tile_func) (int, int, int*, int*, int*); +typedef void* (*func) (void*); + + + + + + +void DSOImage::Load( const string& s ) throw (string) +{ + modulePath = s; + + char* error; + libHandle = NULL; + + loadLibrary(); + + + // Check for the file extension it handles + + void *getParameter; + getParameter = dlsym( libHandle, "get_file_extension" ); + error = dlerror(); + if( error != 0 ){ + throw string( error ); + } + + // This doesn't seem to work! So use typedef casting instead :o +// char *ext = static_cast (getParameter) (); + + func f = (func) getParameter; + + type = (char*) (*f) (NULL); + + + // Check for the description + + getParameter = dlsym( libHandle, "get_description" ); + error = dlerror(); + if( error != 0 ){ + throw string( error ); + } + f = (func) getParameter; + description = (char*) (*f) (NULL); + + + unloadLibrary(); +} + + + + +// Unload the library on destruction + +DSOImage::~DSOImage() +{ + closeImage(); + unloadLibrary(); +} + + + + +void DSOImage::loadLibrary() throw (string) +{ + libHandle = dlopen( modulePath.c_str(), RTLD_NOW ); + + if( libHandle == NULL ){ + char* error = dlerror(); + if( error != NULL ) throw string( error ); + else throw string( "Error in loading module " + modulePath ); + } +} + + + + +void DSOImage::unloadLibrary() throw (string) +{ + if( libHandle ){ + dlclose( libHandle ); + char* error = dlerror(); + if( error != NULL ) throw string( error ); + libHandle = NULL; + } +} + + + + +// Get the error string from the module +string DSOImage::getError() +{ + void *getParameter; + getParameter = dlsym( libHandle, "get_error" ); + char* error = dlerror(); + if( error != NULL ){ + return string( error ); + } + func g = (func) getParameter; + char *result = (char*) (*g) (NULL); + return string( result ); +} + + + + +// Open the image specified by path and get the image and tile +// widths and heights + +void DSOImage::openImage() throw (string) +{ + loadLibrary(); + + string path = getFileName( currentX, 90 ); + + void *getParameter; + getParameter = dlsym( libHandle, "open_image" ); + char* error = dlerror(); + if( error != NULL ){ + throw string( error ); + } + func f = (func) getParameter; + int result = (int) (*f) ( (void*) path.c_str() ); + if( result ) throw getError(); + + + getParameter = dlsym( libHandle, "get_tile_width" ); + error = dlerror(); + if( error != NULL ){ + throw string( error ); + } + f = (func) getParameter; + tile_width = (int) (*f) (NULL); + + + getParameter = dlsym( libHandle, "get_tile_width" ); + error = dlerror(); + if( error != NULL ){ + throw string( error ); + } + f = (func) getParameter; + tile_height = (int) (*f) (NULL); + + + getParameter = dlsym( libHandle, "get_image_width" ); + error = dlerror(); + if( error != NULL ){ + throw string( error ); + } + f = (func) getParameter; + image_widths.push_back( (int) (*f) (NULL) ); + + + getParameter = dlsym( libHandle, "get_image_height" ); + error = dlerror(); + if( error != NULL ){ + throw string( error ); + } + f = (func) getParameter; + image_heights.push_back( (int) (*f) (NULL) ); + + + getParameter = dlsym( libHandle, "get_num_resolutions" ); + error = dlerror(); + if( error != NULL ){ + throw string( error ); + } + f = (func) getParameter; + numResolutions = (int) (*f) (NULL); + + +} + + + + + +void DSOImage::closeImage() throw (string) +{ + if( libHandle ){ + + void *getParameter; + getParameter = dlsym( libHandle, "close_image" ); + + char *error = dlerror(); + if( error != 0 ){ + throw string( error ); + } + + func f = (func) getParameter; + int result = (int) (*f) (NULL); + if( result ) throw getError(); + } +} + + + + + +RawTilePtr DSOImage::getTile( int seq, int angle, unsigned int resolution, int layer, unsigned int tile ) throw (string) +{ + // Make sure we are on the correct image + if( (currentX != seq) && (currentY != angle) ){ + + closeImage(); + + // Get the right file name + string path = getFileName( seq, angle ); + + // Open the image again + void *getParameter; + getParameter = dlsym( libHandle, "open_image" ); + char* error = dlerror(); + if( error != NULL ){ + throw string( error ); + } + func f = (func) getParameter; + int result = (int) (*f) ( (void*) path.c_str() ); + if( result ) throw getError(); + } + + + void *getParameter; + getParameter = dlsym( libHandle, "get_tile" ); + + char *error = dlerror(); + if( error != 0 ){ + throw string( error ); + } + + tile_func f = (tile_func) getParameter; + int data_len, w, h; + unsigned char *data = (unsigned char*) (*f) ( tile, resolution, &w, &h, &data_len ); + + if( !data ) throw getError(); + + RawTilePtr rawtile(new RawTile( tile, resolution, seq, angle, + w, h, 3, 8 )); + rawtile->data = data; + rawtile->dataLength = data_len; + return rawtile; +} + + +#endif diff --git a/iipsrv/src/DSOImage.h b/iipsrv/src/DSOImage.h new file mode 100644 index 0000000..4312c1e --- /dev/null +++ b/iipsrv/src/DSOImage.h @@ -0,0 +1,120 @@ + +/* IIP fcgi server module + + Copyright (C) 2000-2012 Ruven Pillay. + + 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 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + + +#ifdef ENABLE_DL + +#ifndef _DSOIMAGE_H +#define _DSOIMAGE_H + + +#include +#include "IIPImage.h" + + +/// Class to handle dynamically loaded image codecs: Inherits from IIPImage + + +class DSOImage : public IIPImage{ + + private: + + /// Path of the module + std::string modulePath; + + /// Module description + std::string description; + + /// Handle to the module + void *libHandle; + + /// Overloaded function to load the module + void loadLibrary() throw (std::string); + + /// Overloaded function to unload the module + void unloadLibrary() throw (std::string); + + /// Get error messages from the module + std::string getError(); + + + public: + + /// Constructor + DSOImage() : IIPImage() { + libHandle = NULL; + tile_width = 0; tile_height = 0; + numResolutions = 0; + }; + + /// Constructor + /** \param s image path + */ + DSOImage( const std::string& s ) : IIPImage( s ) { + libHandle = NULL; + tile_width = 0; tile_height = 0; + numResolutions = 0; + }; + + /// Copy Constructor + /** \param image IIPImage object + */ + DSOImage( const IIPImage& image ) : IIPImage( image ) { + libHandle = NULL; + tile_width = 0; tile_height = 0; + numResolutions = 0; + }; + + /// Destructor + ~DSOImage(); + + + /// Return description of the module + const std::string getDescription() { return description; }; + + /// Load the module + /** \param p module path + */ + void Load( const std::string& p ) throw (std::string); + + /// Overloaded function to open and read the image + void openImage() throw (std::string); + + /// Overloaded function to close the image + void closeImage() throw (std::string); + + + /// Overloaded function to get a specific tile + /** Return a RawTile object: Overloaded by child class. + \param h horizontal angle + \param v vertical angle + \param r resolution + \param l quality layers + \param t tile number + */ + virtual RawTilePtr getTile( int h, int v, unsigned int r, int l, unsigned int t ) throw(std::string); + + +}; + + +#endif + +#endif diff --git a/iipsrv/src/DeepZoom.cc b/iipsrv/src/DeepZoom.cc new file mode 100644 index 0000000..eb17d70 --- /dev/null +++ b/iipsrv/src/DeepZoom.cc @@ -0,0 +1,198 @@ +/* + IIP DeepZoom Request Command Handler Class Member Function + + Development supported by Moravian Library in Brno (Moravska zemska + knihovna v Brne, http://www.mzk.cz/) R&D grant MK00009494301 & Old + Maps Online (http://www.oldmapsonline.org/) from the Ministry of + Culture of the Czech Republic. + + + Copyright (C) 2009-2014 Ruven Pillay. + + 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 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +#include + +#include "Task.h" +#include "Transforms.h" + + + +using namespace std; + + +// Windows does not provide a log2 function! +#if (!defined HAVE_LOG2) || (defined _MSC_VER) +double log2(double max){ + return log((double)max)/log((double)2); +} +#endif + + +void DeepZoom::run( Session* session, const std::string& argument ){ + + if( session->loglevel >= 3 ) (*session->logfile) << "DeepZoom handler reached" << endl; + + // Time this command + if( session->loglevel >= 2 ) command_timer.start(); + + + // A DeepZoom request consists of 2 types of request. The first for the .dzi xml file + // containing image metadata and the second of the form _files/r/x_y.jpg for the tiles + // themselves where r is the resolution number and x and y are the tile coordinates + // starting from the bottom left. + + string prefix, suffix; + suffix = argument.substr( argument.find_last_of( "." )+1, argument.length() ); + + // We need to extract the image path, which is not always the same + if( suffix == "dzi" ) + prefix = argument.substr( 0, argument.length()-4 ); + else + prefix = argument.substr( 0, argument.rfind( "_files/" ) ); + + + + // As we don't have an independent FIF request, we need to run it now + FIF fif; + fif.run( session, prefix ); + + + // Get the full image size and the total number of resolutions available +// unsigned int width = (session->image)->getImageWidth(); +// unsigned int height = (session->image)->getImageHeight(); + + + unsigned int tw = (session->image)->getTileWidth(); + unsigned int numResolutions = (session->image)->getNumResolutions(); + + + // DeepZoom does not accept arbitrary numbers of resolutions. The number of levels + // is calculated by rounding up the log_2 of the larger of image height and image width; +// unsigned int dzi_res; +// unsigned int max = width; +// if( height > width ) max = height; +// dzi_res = (int) ceil( log2(max) ); + + // alternatively, we can calculate the number of res that would have existed below the smallest available image + unsigned int width = (session->image)->getImageWidth(); + unsigned int height = (session->image)->getImageHeight(); + unsigned int maxdim = height > width ? height : width; + + // include level 0 which is 1 pixel wide, up to dzi_res which is nearest power of 2 to max(width, height) + //unsigned int discard = (unsigned int) ceil( log2(maxdim) ) + 1; // +1, because 1 pixel gives a log2 of 0, is also a res. + unsigned int resOffset = (unsigned int) ceil( log2(maxdim) ) + 1 - numResolutions; // no +1 because we keep the lowest res. + + if( session->loglevel >= 4 ){ + *(session->logfile) << "DeepZoom :: virtually existing " << resOffset << " lower resolutions below real: " << numResolutions << endl; + } + + + // DeepZoom clients have 2 phases, the initialization phase where they request + // an XML file containing image data and the tile requests themselves. + // These 2 phases are handled separately + if( suffix == "dzi" ){ + + if( session->loglevel >= 2 ) + *(session->logfile) << "DeepZoom :: DZI header request" << endl; + + if( session->loglevel >= 4 ){ + *(session->logfile) << "DeepZoom :: Total resolutions: " << numResolutions << ", virtual resolutions: " << resOffset << " image width: " << (session->image)->getImageWidth() + << ", image height: " << (session->image)->getImageHeight() << endl; + } + + char str[1024]; + snprintf( str, 1024, + "Server: iipsrv/%s\r\n" + "Content-Type: application/xml\r\n" + "Cache-Control: max-age=%d\r\n" + "Last-Modified: %s\r\n" + "\r\n" + "\r\n" + "" + "" + "", + VERSION, MAX_AGE, (session->image)->getTimestamp().c_str(), tw, (session->image)->getImageWidth(), (session->image)->getImageHeight() ); + + session->out->printf( (const char*) str ); + session->response->setImageSent(); + + return; + } + + + // Get the tile coordinates. DeepZoom requests are of the form $image_files/r/x_y.jpg + // where r is the resolution number and x and y are the tile coordinates + + int resolution, x, y; + unsigned int n, n1, n2; + + // Extract resolution + n1 = argument.find_last_of("/"); + n2 = argument.substr(0,n1).find_last_of("/")+1; + resolution = atoi( argument.substr(n2,n1-n2).c_str() ); + + // Extract tile x,y coordinates + n = argument.find_last_of(".")-n1-1; + suffix = argument.substr( n1+1, n ); + n = suffix.find_first_of("_"); + x = atoi( suffix.substr(0,n).c_str() ); + y = atoi( suffix.substr(n+1,suffix.length()).c_str() ); + + + // deepzoom res 0 to ( (dzi_res - numResolutions)-1 = discard ) are too small. + // dzi_res is ceil(log2(maxres)), which is number of deepzoom resolutions. + // resolution has [0, dzi_res), and (dzi_res-numResolutions) is the offset, then -1 is incorrect. + // Take into account the extra zoom levels required by the DeepZoom spec +// resolution = resolution - (dzi_res-numResolutions) - 1; + resolution -= resOffset; + if( resolution < 0 ) resolution = 0; + if( (unsigned int)resolution >= numResolutions ) resolution = numResolutions-1; + + if( session->loglevel >= 2 ){ + *(session->logfile) << "DeepZoom :: Tile request for resolution: " + << resolution << " at tile x: " << x << ", y: " << y << endl; + } + + + // Get the width and height for the requested resolution + width = (session->image)->getImageWidth(numResolutions-resolution-1); + height = (session->image)->getImageHeight(numResolutions-resolution-1); + + + // Get the width of the tiles and calculate the number + // of tiles in each direction + unsigned int rem_x = width % tw; + unsigned int ntlx = (width / tw) + (rem_x == 0 ? 0 : 1); + + + // Calculate the tile index for this resolution from our x, y + unsigned int tile = y*ntlx + x; + + + // Simply pass this on to our JTL send command + JTL jtl; + jtl.send( session, resolution, tile ); + + + // Total DeepZoom response time + if( session->loglevel >= 2 ){ + *(session->logfile) << "DeepZoom :: Total command time " << command_timer.getTime() << " microseconds" << endl; + } + + +} diff --git a/iipsrv/src/Environment.h b/iipsrv/src/Environment.h new file mode 100644 index 0000000..8cb6275 --- /dev/null +++ b/iipsrv/src/Environment.h @@ -0,0 +1,247 @@ +/* + IIP Environment Variable Class + + Copyright (C) 2006-2014 Ruven Pillay. + + 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 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +#ifndef _ENVIRONMENT_H +#define _ENVIRONMENT_H + + +/* Define some default values + */ +#define VERBOSITY 1 +#define LOGFILE "/tmp/iipsrv.log" +#define MAX_IMAGE_CACHE_SIZE 100 +#define MAX_TILE_CACHE_SIZE 10 +#define FILENAME_PATTERN "_pyr_" +#define JPEG_QUALITY 75 +#define MAX_CVT 5000 +#define MAX_LAYERS 0 +#define FILESYSTEM_PREFIX "" +#define WATERMARK "" +#define WATERMARK_PROBABILITY 1.0 +#define WATERMARK_OPACITY 1.0 +#define LIBMEMCACHED_SERVERS "localhost" +#define LIBMEMCACHED_TIMEOUT 86400 // 24 hours +#define INTERPOLATION 1 +#define CORS ""; +#define BASE_URL ""; + + +#include + + +/// Class to obtain environment variables +class Environment { + + + public: + + static int getVerbosity(){ + int loglevel = VERBOSITY; + char *envpara = getenv( "VERBOSITY" ); + if( envpara ){ + loglevel = atoi( envpara ); + // If not a realistic level, set to zero + if( loglevel < 0 ) loglevel = 0; + } + return loglevel; + } + + + static std::string getLogFile(){ + char* envpara = getenv( "LOGFILE" ); + if( envpara ) return std::string( envpara ); + else return LOGFILE; + } + + + static size_t getMaxImageCacheSize(){ + int max_image_cache_size = MAX_IMAGE_CACHE_SIZE; + char* envpara = getenv( "MAX_IMAGE_CACHE_SIZE" ); + if( envpara ){ + max_image_cache_size = atoi( envpara ); + } + return max_image_cache_size; + } + + static float getMaxTileCacheSize(){ + float max_tile_cache_size = MAX_TILE_CACHE_SIZE; + char* envpara = getenv( "MAX_TILE_CACHE_SIZE" ); + if( envpara ){ + max_tile_cache_size = atof( envpara ); + } + return max_tile_cache_size; + } + + + static std::string getFileNamePattern(){ + char* envpara = getenv( "FILENAME_PATTERN" ); + std::string filename_pattern; + if( envpara ){ + filename_pattern = std::string( envpara ); + } + else filename_pattern = FILENAME_PATTERN; + + return filename_pattern; + } + + + static int getJPEGQuality(){ + char* envpara = getenv( "JPEG_QUALITY" ); + int jpeg_quality; + if( envpara ){ + jpeg_quality = atoi( envpara ); + if( jpeg_quality > 100 ) jpeg_quality = 100; + if( jpeg_quality < 1 ) jpeg_quality = 1; + } + else jpeg_quality = JPEG_QUALITY; + + return jpeg_quality; + } + + + static int getMaxCVT(){ + char* envpara = getenv( "MAX_CVT" ); + int max_CVT; + if( envpara ){ + max_CVT = atoi( envpara ); + if( max_CVT < 64 ) max_CVT = 64; + if( max_CVT == -1 ) max_CVT = -1; + } + else max_CVT = MAX_CVT; + + return max_CVT; + } + + + static int getMaxLayers(){ + char* envpara = getenv( "MAX_LAYERS" ); + int layers; + if( envpara ) layers = atoi( envpara ); + else layers = MAX_LAYERS; + + return layers; + } + + + static std::string getFileSystemPrefix(){ + char* envpara = getenv( "FILESYSTEM_PREFIX" ); + std::string filesystem_prefix; + if( envpara ){ + filesystem_prefix = std::string( envpara ); + } + else filesystem_prefix = FILESYSTEM_PREFIX; + + return filesystem_prefix; + } + + + static std::string getWatermark(){ + char* envpara = getenv( "WATERMARK" ); + std::string watermark; + if( envpara ){ + watermark = std::string( envpara ); + } + else watermark = WATERMARK; + + return watermark; + } + + + static float getWatermarkProbability(){ + float watermark_probability = WATERMARK_PROBABILITY; + char* envpara = getenv( "WATERMARK_PROBABILITY" ); + + if( envpara ){ + watermark_probability = atof( envpara ); + if( watermark_probability > 1.0 ) watermark_probability = 1.0; + if( watermark_probability < 0 ) watermark_probability = 0.0; + } + + return watermark_probability; + } + + + static float getWatermarkOpacity(){ + float watermark_opacity = WATERMARK_OPACITY; + char* envpara = getenv( "WATERMARK_OPACITY" ); + + if( envpara ){ + watermark_opacity = atof( envpara ); + if( watermark_opacity > 1.0 ) watermark_opacity = 1.0; + if( watermark_opacity < 0 ) watermark_opacity = 0.0; + } + + return watermark_opacity; + } + + + static std::string getMemcachedServers(){ + char* envpara = getenv( "MEMCACHED_SERVERS" ); + std::string memcached_servers; + if( envpara ){ + memcached_servers = std::string( envpara ); + } + else memcached_servers = LIBMEMCACHED_SERVERS; + + return memcached_servers; + } + + + static unsigned int getMemcachedTimeout(){ + char* envpara = getenv( "MEMCACHED_TIMEOUT" ); + unsigned int memcached_timeout; + if( envpara ) memcached_timeout = atoi( envpara ); + else memcached_timeout = LIBMEMCACHED_TIMEOUT; + + return memcached_timeout; + } + + + static unsigned int getInterpolation(){ + char* envpara = getenv( "INTERPOLATION" ); + unsigned int interpolation; + if( envpara ) interpolation = atoi( envpara ); + else interpolation = INTERPOLATION; + + return interpolation; + } + + + static std::string getCORS(){ + char* envpara = getenv( "CORS" ); + std::string cors; + if( envpara ) cors = std::string( envpara ); + else cors = CORS; + return cors; + } + + + static std::string getBaseURL(){ + char* envpara = getenv( "BASE_URL" ); + std::string base_url; + if( envpara ) base_url = std::string( envpara ); + else base_url = BASE_URL; + return base_url; + } + +}; + + +#endif diff --git a/iipsrv/src/FIF.cc b/iipsrv/src/FIF.cc new file mode 100644 index 0000000..5f2f2f8 --- /dev/null +++ b/iipsrv/src/FIF.cc @@ -0,0 +1,249 @@ +/* + IIP FIF Command Handler Class Member Function + + Copyright (C) 2006-2014 Ruven Pillay. + + 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 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + + +#include +#include "OpenSlideImage.h" +#include +#include + +#include +#include "Task.h" +#include "URL.h" +#include "Environment.h" +#include "TPTImage.h" + +#ifdef HAVE_KAKADU +#include "KakaduImage.h" +#endif + +#define MAXIMAGECACHE 500 // Max number of items in image cache + + + +using namespace std; + + + +void FIF::run( Session* session, const string& src ){ + + if( session->loglevel >= 3 ) *(session->logfile) << "FIF handler reached" << endl; + + // Time this command + if( session->loglevel >= 2 ) command_timer.start(); + + + // Decode any URL-encoded characters from our path + URL url( src ); + string argument = url.decode(); + + + // Filter out any ../ to prevent users by-passing any file system prefix + unsigned int n; + while( (n=argument.find("../")) < argument.length() ) argument.erase(n,3); + + if( session->loglevel >=1 ){ + if( url.warning().length() > 0 ) *(session->logfile) << "FIF :: " << url.warning() << endl; + if( session->loglevel >= 5 ){ + *(session->logfile) << "FIF :: URL decoding/filtering: " << src << " => " << argument << endl; + } + } + + + // Create our IIPImage object + IIPImage test; + + // Get our image pattern variable + string filesystem_prefix = Environment::getFileSystemPrefix(); + + // Get our image pattern variable + string filename_pattern = Environment::getFileNamePattern(); + + // Put the image setup into a try block as object creation can throw an exception + try{ + + auto temp = session->imageCache->getObject(argument); + // Cache Hit + if( temp ){ + if( session->loglevel >= 2 ){ + *(session->logfile) << "FIF :: Image cache hit. Number of elements: " << session->imageCache->getNumElements() << endl; + } + + // get the image, then check it's timestamp. + if (difftime(IIPImage::getFileTimestamp(temp->getFileName(temp->currentX, temp->currentY)), + temp->timestamp) > + std::numeric_limits::round_error()) { + // file on filesystem newer. so reopen it. + + if( session->loglevel >= 2 ){ + *(session->logfile) << "FIF :: Newer file on FS. reloading " << endl; + } + temp->closeImage(); + temp->openImage(); + } + } + // Cache Miss + else{ + if( session->loglevel >= 2 ) *(session->logfile) << "FIF :: Image cache miss" << endl; + // eviction handled by ImageCache. + + //==== Create our test IIPImage object to get timestamp and image type. + IIPImage test = IIPImage( argument ); + test.setFileNamePattern( filename_pattern ); + test.setFileSystemPrefix( filesystem_prefix ); + test.Initialise(); // also gathers the timestamp here. + + /*************************************************************** + Test for different image types - only TIFF is native for now + ***************************************************************/ + + ImageFormat format = test.getImageFormat(); + + if( format == TIF ){ + if( session->loglevel >= 2 ) *(session->logfile) << "FIF :: TIFF image detected" << endl; + temp = IIPImagePtr(new TPTImage( test )); + } +#pragma mark Adding in basic openslide functionality + else if( format == OPENSLIDE ){ + if( session->loglevel >= 2 ) *(session->logfile) << "FIF :: OpenSlide image detected" << endl; + temp = IIPImagePtr(new OpenSlideImage( test, session->tileCache )); + } + #ifdef HAVE_KAKADU + else if( format == JPEG2000 ){ + if( session->loglevel >= 2 ) *(session->logfile) << "FIF :: JPEG2000 image detected" << endl; + temp = IIPImagePtr(new KakaduImage( test )); + } + #endif + else throw string( "Unsupported image type: " + argument ); + + //==== create format specific iipimage subclass instance as pointer. + + // Open image, and add it to our cache + temp->openImage(); + session->imageCache->insert(temp); // insert into cache. + + if( session->loglevel >= 3 ){ + *(session->logfile) << "FIF :: Created and cached image object with key = \"" << argument << "\"" << endl; + } + } + + + // for now, store pointer. + // temp already points to an IIPImage instance. + + session->image = temp; + + + /* Disable module loading for now! + else{ + +#ifdef ENABLE_DL + + // Check our map list for the requested type + if( moduleList.empty() ){ + throw string( "Unsupported image type: " + imtype ); + } + else{ + + map :: iterator mod_it = moduleList.find( imtype ); + + if( mod_it == moduleList.end() ){ + throw string( "Unsupported image type: " + imtype ); + } + else{ + // Construct our dynamic loading image decoder + session->image = new DSOImage( test ); + (session->image)->Load( (*mod_it).second ); + + if( session->loglevel >= 2 ){ + *(session->logfile) << "FIF :: Image type: '" << imtype + << "' requested ... using handler " + << (session->image)->getDescription() << endl; + } + } + } +#else + throw string( "Unsupported image type: " + imtype ); +#endif + } + */ + + + + + // Set the timestamp for the reply + session->response->setLastModified( (session->image)->getTimestamp() ); + + if( session->loglevel >= 2 ){ + *(session->logfile) << "FIF :: Image dimensions are " << (session->image)->getImageWidth() + << " x " << (session->image)->getImageHeight() << endl + << "FIF :: Image contains " << (session->image)->channels + << " channels with " << (session->image)->bpc << " bits per channel" << endl; + tm *t = gmtime( &(session->image)->timestamp ); + char strt[64]; + strftime( strt, 64, "%a, %d %b %Y %H:%M:%S GMT", t ); + *(session->logfile) << "FIF :: Image timestamp: " << strt << endl; + } + + } + catch( const file_error& error ){ + // Unavailable file error code is 1 3 + session->response->setError( "1 3", "FIF" ); + throw error; + } + + + // Check whether we have had an if_modified_since header. If so, compare to our image timestamp + if( session->headers.find("HTTP_IF_MODIFIED_SINCE") != session->headers.end() ){ + + tm mod_t; + time_t t; + + strptime( (session->headers)["HTTP_IF_MODIFIED_SINCE"].c_str(), "%a, %d %b %Y %H:%M:%S %Z", &mod_t ); + + // Use POSIX cross-platform mktime() function to generate a timestamp. + // This needs UTC, but to avoid a slow TZ environment reset for each request, we set this once globally in Main.cc + t = mktime(&mod_t); + if( (session->loglevel >= 1) && (t == -1) ) *(session->logfile) << "FIF :: Error creating timestamp" << endl; + + if( (session->image)->timestamp <= t ){ + if( session->loglevel >= 2 ){ + *(session->logfile) << "FIF :: Unmodified content" << endl; + *(session->logfile) << "FIF :: Total command time " << command_timer.getTime() << " microseconds" << endl; + } + throw( 304 ); + } + else{ + if( session->loglevel >= 2 ){ + *(session->logfile) << "FIF :: Content modified" << endl; + } + } + } + + // Reset our angle values + session->view->xangle = 0; + session->view->yangle = 90; + + + if( session->loglevel >= 2 ){ + *(session->logfile) << "FIF :: Total command time " << command_timer.getTime() << " microseconds" << endl; + } + +} diff --git a/iipsrv/src/ICC.cc b/iipsrv/src/ICC.cc new file mode 100644 index 0000000..cdba5e4 --- /dev/null +++ b/iipsrv/src/ICC.cc @@ -0,0 +1,79 @@ +/* + IIP ICC Command Handler + + Copyright (C) 2006-2013 Ruven Pillay. + + 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 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + + +#include "Task.h" + +// lcms not finished at the moment. Disable it for now. +#undef LCMS + +#ifdef LCMS +#include + + + +using namespace std; + + +void ICC::run( Session* session, const std::string& argument ){ + + unsigned char icc_profile[1024]; + + // Parse the argument list + delimitter = argument.find( "," ); + string tmp = argument.substr( 0, delimitter ); + unsigned int icc_len = atoi( tmp.c_str() ); + argument = argument.substr( delimitter + 1, argument.length() ); + + delimitter = argument.find( "," ); + tmp = argument.substr( 0, delimitter ); +// icc_profile = tmp.c_str(); + argument = argument.substr( delimitter + 1, argument.length() ); + + cmsHPROFILE out_profile, lab_profile, sRGB_profile; + cmsHTRANSFORM hTransform; + LPcmsCIExyY WhitePoint; + + out_profile = cmsOpenProfileFromMem( (LPVOID) tmp.c_str(), + (DWORD) icc_len ); + lab_profile = cmsCreateLabProfile( WhitePoint ); + sRGB_profile = cmsCreate_sRGBProfile(); + + cmsWhitePointFromTemp( 6504, WhitePoint ); + lab_profile = cmsCreateLabProfile( WhitePoint ); + hTransform = cmsCreateTransform( sRGB_profile, TYPE_RGB_8, + out_profile, TYPE_RGB_8, + INTENT_ABSOLUTE_COLORIMETRIC, 0); + cmsDoTransform( ); + cmsDeleteTransform( hTransform ); + cmsCloseProfile( out_profile ); + cmsCloseProfile( lab_profile ); + cmsCloseProfile( sRGB_profile ); + +} + + +#else + + +void ICC::run( Session* session, const std::string& argument ){ ; } + + +#endif diff --git a/iipsrv/src/IIIF.cc b/iipsrv/src/IIIF.cc new file mode 100644 index 0000000..e8f036f --- /dev/null +++ b/iipsrv/src/IIIF.cc @@ -0,0 +1,552 @@ +/* + + IIIF Request Command Handler Class Member Function + + Copyright (C) 2014 Ruven Pillay + + 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +#include +#include +#include +#include +#include "Task.h" +#include "Tokenizer.h" +#include "Transforms.h" +#include "URL.h" + +#if _MSC_VER +#include "../windows/Time.h" +#endif + + +// Define several IIIF strings +#define IIIF_SYNTAX "IIIF syntax is {identifier}/{region}/{size}/{rotation}/{quality}{.format}" +#define IIIF_PROFILE "http://iiif.io/api/image/2/level1.json" +#define IIIF_CONTEXT "http://iiif.io/api/image/2/context.json" +#define IIIF_PROTOCOL "http://iiif.io/api/image" + + +using namespace std; + + + +// The request is in the form {identifier}/{region}/{size}/{rotation}/{quality}{.format} +// eg. filename.tif/full/full/0/native.jpg +// or in the form {identifier}/info.json +// eg. filename.jp2/info.json + +void IIIF::run( Session* session, const string& src ){ + + if( session->loglevel >= 3 ) *(session->logfile) << "IIIF handler reached" << endl; + + // Time this command + if( session->loglevel >= 2 ) command_timer.start(); + + + // Various string variables + string suffix, filename, params; + + + // First filter and decode our URL + URL url( src ); + string argument = url.decode(); + + if( session->loglevel >=1 ){ + if( url.warning().length() > 0 ) *(session->logfile) << "IIIF :: " << url.warning() << endl; + if( session->loglevel >= 5 ){ + *(session->logfile) << "IIIF :: URL decoded to " << argument << endl; + } + } + + + // Check if there is slash in argument and if it is not last / first character, extract identifier and suffix + size_t lastSlashPos = argument.find_last_of("/"); + if( lastSlashPos < argument.length() && lastSlashPos > 0 ){ + + suffix = argument.substr( lastSlashPos+1, string::npos ); + + // If we have an info command, file name must be everything + if( suffix.substr(0,4) == "info" ){ + filename = argument.substr(0,lastSlashPos); + } + else{ + size_t positionTmp = lastSlashPos; + for( int i=0; i<3; i++ ){ + positionTmp = argument.substr(0,positionTmp).find_last_of("/"); + } + if( positionTmp > 0 ){ + filename = argument.substr(0,positionTmp); + params = argument.substr(positionTmp + 1, string::npos); + } + else{ + // No extra parameters + throw invalid_argument( "IIIF: Not enough parameters" ); + } + } + } + else{ + // No parameters, so redirect to info request + string id; + string host = session->headers["BASE_URL"]; + if( host.length() > 0 ){ + id = host + (session->headers["QUERY_STRING"]).substr(5,string::npos); + } + else{ + string request_uri = session->headers["REQUEST_URI"]; + request_uri.erase( request_uri.length() - suffix.length(), string::npos ); + id = "http://" + session->headers["HTTP_HOST"] + request_uri; + } + string header = string( "Status: 303 See Other\r\n" ) + + "Location: " + id + "/info.json\r\n" + + "Server: iipsrv/" + VERSION + "\r\n" + + "\r\n"; + session->out->printf( (const char*) header.c_str() ); + session->response->setImageSent(); + if( session->loglevel >= 2 ){ + *(session->logfile) << "IIIF :: Sending HTTP 303 See Other : " << id + "/info.json" << endl; + } + return; + } + + + // Check whether requested image exists + FIF fif; + fif.run( session, filename ); + + // Reload our filename + filename = (session->image)->getImagePath(); + + // Get the information about image, that can be shown in info.json + unsigned int requested_width; + unsigned int requested_height; + unsigned int width = (session->image)->getImageWidth(); + unsigned int height = (session->image)->getImageHeight(); + unsigned tw = (session->image)->getTileWidth(); + unsigned th = (session->image)->getTileHeight(); + unsigned numResolutions = (session->image)->getNumResolutions(); + + session->view->setImageSize( width, height ); + session->view->setMaxResolutions( numResolutions ); + + + // PARSE INPUT PARAMETERS + + // info.json + if( suffix == "info.json" ){ + + // Our string buffer + stringstream infoStringStream; + + // Generate our @id - use our BASE_URL environment variable if we are + // behind a web server rewrite function + string id; + string host = session->headers["BASE_URL"]; + if( host.length() > 0 ){ + string query = (session->headers["QUERY_STRING"]); + query = query.substr( 5, query.length()-suffix.length()-6 ); + id = host + query; + } + else{ + string request_uri = session->headers["REQUEST_URI"]; + request_uri.erase( request_uri.length()-suffix.length()-1, string::npos ); + id = "http://" + session->headers["HTTP_HOST"] + request_uri; + } + + // Escape file name for JSON + URL json(id); + string escapedFilename = json.Escape(); + + + infoStringStream << "{" << endl + << " \"@context\" : \"" << IIIF_CONTEXT << "\"," << endl + << " \"@id\" : \"" << escapedFilename << "\"," << endl + << " \"protocol\" : \"" << IIIF_PROTOCOL << "\"," << endl + << " \"width\" : " << width << "," << endl + << " \"height\" : " << height << "," << endl + << " \"tiles\" : [" << endl + << " { \"width\" : " << tw << ", \"height\" : " << th + << ", \"scaleFactors\" : [ 1"; // Scale 1 is original image + + for( unsigned int i=1; i < numResolutions; i++ ){ + infoStringStream << ", " << pow(2.0,(double)i); + } + + infoStringStream << " ] }" << endl + << " ]," << endl + << " \"profile\" : [" << endl + << " \"" << IIIF_PROFILE << "\"," << endl + << " { \"formats\" : [ \"jpg\" ]," << endl + << " \"qualities\" : [ \"native\",\"color\",\"gray\" ]," << endl + << " \"supports\" : [\"regionByPct\",\"sizeByForcedWh\",\"sizeByWh\",\"sizeAboveFull\",\"rotationBy90s\",\"mirroring\",\"gray\"] }" << endl + << " ]" << endl + << "}"; + + + // Get our Access-Control-Allow-Origin value, if any + string cors = session->response->getCORS(); + string eof = "\r\n"; + + // Now output the info text + stringstream header; + header << "Server: iipsrv/" << VERSION << eof + << "Content-Type: application/ld+json" << eof + << "Cache-Control: max-age=" << MAX_AGE << eof + << "Last-Modified: " << (session->image)->getTimestamp() << eof; + if( !cors.empty() ) header << cors << eof; + header << eof << infoStringStream.str(); + + session->out->printf( (const char*) header.str().c_str() ); + session->response->setImageSent(); + + return; + + } + + + // Parse image request - any other than info requests are considered image requests + else{ + + // IIIF requests are / separated with no CGI style '&' separators + Tokenizer izer( params, "/" ); + + // Keep track of the number of parameters than have been given + int numOfTokens = 0; + + + // Region Parameter: { "full"; "x,y,w,h"; "pct:x,y,w,h" } + if( izer.hasMoreTokens() ){ + + // Our region parameters + float region[4]; + + // Get our region string and convert to lower case if necessary + string regionString = izer.nextToken(); + transform( regionString.begin(), regionString.end(), regionString.begin(), ::tolower ); + + // Full export request + if( regionString == "full" ){ + region[0] = 0.0; + region[1] = 0.0; + region[2] = 1.0; + region[3] = 1.0; + } + + // Region export request + else{ + + // Check for pct (%) and strip it from the beginning + bool isPCT = false; + if( regionString.substr(0,4) == "pct:" ){ + isPCT = true; + // Strip this from our string + regionString.erase( 0, 4 ); + } + + // Extract x,y,w,h tokenizing on "," + Tokenizer regionIzer(regionString, ","); + int n = 0; + + // Extract our region values + while( regionIzer.hasMoreTokens() && n < 4 ){ + region[n++] = atof( regionIzer.nextToken().c_str() ); + } + + // Define our denominators as our session view expects a ratio, not pixel values + float wd = (float)width; + float hd = (float)height; + + if( isPCT ){ + wd = 100.0; + hd = 100.0; + } + + session->view->setViewLeft( region[0] / wd ); + session->view->setViewTop( region[1] / hd ); + session->view->setViewWidth( region[2] / wd ); + session->view->setViewHeight( region[3] / hd ); + + // Incorrect region request + if( regionIzer.hasMoreTokens() || n < 4 ){ + throw invalid_argument( "IIIF: incorrect region format: " + regionString ); + } + + } // end of else - end of parsing x,y,w,h + + numOfTokens++; + + if( session->loglevel > 4 ){ + *(session->logfile) << "IIIF :: Requested Region: x:" << region[0] << ", y:" << region[1] + << ", w:" << region[2] << ", h:" << region[3] << endl; + } + + } + + + + // Size Parameter: { "full"; "w,"; ",h"; "pct:n"; "w,h"; "!w,h" } + if( izer.hasMoreTokens() ){ + + string sizeString = izer.nextToken(); + transform( sizeString.begin(), sizeString.end(), sizeString.begin(), ::tolower ); + + // Calculate the width and height of our region + requested_width = session->view->getViewWidth(); + requested_height = session->view->getViewHeight(); + + // "full" request + if( sizeString == "full" ){ + // No need to do anything + } + + // "pct:n" request + else if( sizeString.substr(0,4) == "pct:" ){ + + float scale; + istringstream i( sizeString.substr( sizeString.find_first_of(":")+1, string::npos ) ); + if( !(i >> scale) ) throw invalid_argument( "invalid size" ); + + requested_width = round( requested_width * scale / 100.0 ); + requested_height = round( requested_height * scale / 100.0 ); + } + + // "w,h", "w,", ",h", "!w,h" requests + else{ + + // !w,h request - remove !, remember it and continue as if w,h request + if( sizeString.substr(0,1) == "!" ) sizeString.erase(0,1); + // Otherwise tell our view to break aspect ratio + else session->view->maintain_aspect = false; + + size_t pos = sizeString.find_first_of(","); + + // If no comma, size is invalid + if( pos == string::npos ){ + throw invalid_argument( "invalid size: no comma found" ); + } + + // If comma is at the beginning, we have a ",height" request + else if( pos == 0 ){ + istringstream i( sizeString.substr( 1, string::npos ) ); + if( !(i >> requested_height) ) throw invalid_argument( "invalid height" ); + requested_width = round( (float)requested_height*session->view->getViewWidth()/session->view->getViewHeight() ); + } + + // If comma is not at the beginning, we must have a "width,height" or "width," request + // Test first for the "width," request + else if( pos == sizeString.length()-1 ){ + istringstream i( sizeString.substr( 0, string::npos - 1 ) ); + if( !(i >> requested_width ) ) throw invalid_argument( "invalid width" ); + requested_height = round( (float)requested_width*session->view->getViewHeight()/session->view->getViewWidth() ); + } + + // Remaining case is "width,height" + else{ + istringstream i( sizeString.substr( 0, pos ) ); + if( !(i >> requested_width) ) throw invalid_argument( "invalid width" ); + i.clear(); + i.str( sizeString.substr( pos+1, string::npos ) ); + if( !(i >> requested_height) ) throw invalid_argument( "invalid height" ); + } + } + + + if( requested_width==0 || requested_height==0 ){ + throw invalid_argument( "IIIF: invalid size" ); + } + + session->view->setRequestWidth( requested_width ); + session->view->setRequestHeight( requested_height ); + + numOfTokens++; + + if( session->loglevel >= 4 ){ + *(session->logfile) << "IIIF :: Requested Size: " << requested_width << "x" << requested_height << endl; + } + + } + + + + // Rotation Parameter + if( izer.hasMoreTokens() ){ + + string rotationString = izer.nextToken(); + + // Flip requests (IIIF 2.0 API) + if( rotationString.substr(0,1) == "!" ){ + session->view->flip = 1; + rotationString.erase(0,1); + } + + + // Convert our string to a float + float rotation = 0; + istringstream i( rotationString ); + if( !(i >> rotation) ) throw invalid_argument( "IIIF: invalid rotation" ); + + + // Check if converted value is supported + if(!( rotation == 0 || rotation == 90 || rotation == 180 || rotation == 270 || rotation == 360 )){ + throw invalid_argument( "IIIF: currently implemented rotation angles are 0, 90, 180 and 270 degrees" ); + } + + // Set rotation - watch for a '!180' request, which is simply a vertical flip + if( rotation == 180 && session->view->flip == 1 ) session->view->flip = 2; + else session->view->setRotation( rotation ); + + numOfTokens++; + + if( session->loglevel >= 4 ){ + *(session->logfile) << "IIIF :: Requested Rotation: " << rotation << " degrees"; + if( session->view->flip != 0 ) *(session->logfile) << " with horizontal flip"; + *(session->logfile) << endl; + } + + } + + + + // Quality and Format Parameters + if( izer.hasMoreTokens() ){ + + string format = "jpg"; + string quality = izer.nextToken(); + transform( quality.begin(), quality.end(), quality.begin(), ::tolower ); + + size_t pos = quality.find_last_of("."); + + // Format - if dot is not present, we use default and currently only supported format - JPEG + if( pos != string::npos ){ + format = quality.substr( pos+1, string::npos ); + quality.erase( pos, string::npos ); + if( format != "jpg" ){ + throw invalid_argument( "IIIF :: Only JPEG output supported" ); + } + } + + // Quality + if( quality == "native" || quality == "color" || quality == "default" ){ + // Do nothing + } + else if( quality == "grey" || quality == "gray" ){ + session->view->colourspace = GREYSCALE; + } + else{ + throw invalid_argument( "unsupported quality parameter - must be one of native, color or grey" ); + } + + numOfTokens++; + + if( session->loglevel >= 4 ){ + *(session->logfile) << "IIIF :: Requested Quality: " << quality << " with format: " << format << endl; + } + } + + + + // Too many parameters + if( izer.hasMoreTokens() ){ + throw invalid_argument( "IIIF: Query has too many parameters. " IIIF_SYNTAX ); + } + + + // Not enough parameters + if( numOfTokens < 4 ){ + throw invalid_argument( "IIIF: Query has too few parameters. " IIIF_SYNTAX ); + } + + } + // End of parsing input parameters + + + + // Write info about request to log + if( session->loglevel >= 3 ){ + if( suffix == "info.json" ){ + *(session->logfile) << "IIIF :: " << suffix << " request for " << (session->image)->getImagePath() << endl; + } + else{ + *(session->logfile) << "IIIF :: image request for " << (session->image)->getImagePath() + << " with arguments: region: " << session->view->getViewLeft() << "," << session->view->getViewTop() << "," + << session->view->getViewWidth() << "," << session->view->getViewHeight() + << "; size: " << requested_width << "x" << requested_height + << "; rotation: " << session->view->getRotation() + << "; mirroring: " << session->view->flip + << endl; + } + } + + + + // Get most suitable resolution and recalculate width and height of region in this resolution + int requested_res = session->view->getResolution(); + + unsigned int im_width = (session->image)->image_widths[numResolutions-requested_res-1]; + unsigned int im_height = (session->image)->image_heights[numResolutions-requested_res-1]; + + unsigned int view_left, view_top; + + if( session->view->viewPortSet() ){ + // Set the absolute viewport size and extract the co-ordinates + view_left = session->view->getViewLeft(); + view_top = session->view->getViewTop(); + } + else{ + view_left = 0; + view_top = 0; + } + + + // Determine whether this is a tile request which coincides with our tile boundaries + if( ( session->view->maintain_aspect && (requested_res>0) && + (requested_width == tw) && (requested_height == th) && + (view_left%tw == 0) && (view_top%th == 0) && + (session->view->getViewWidth()view->getViewHeight()view->maintain_aspect && (requested_res==0) && + (requested_width==im_width) && (requested_height==im_height) ) + ){ + + // Get the width and height for last row and column tiles + unsigned int rem_x = im_width % tw; + + // Calculate the number of tiles in each direction + unsigned int ntlx = (im_width / tw) + (rem_x == 0 ? 0 : 1); + + // Calculate tile index + unsigned int i = view_left/tw; + unsigned int j = view_top/th; + unsigned int tile = (j*ntlx) + i; + + // Simply pass this on to our JTL send command + JTL jtl; + jtl.send( session, requested_res, tile ); + + } + else{ + // Otherwise do a CVT style region request + CVT cvt; + cvt.send( session ); + } + + + // Total IIIF response time + if( session->loglevel >= 2 ){ + *(session->logfile) << "IIIF :: Total command time " << command_timer.getTime() << " microseconds" << endl; + } + +} diff --git a/iipsrv/src/IIPImage.cc b/iipsrv/src/IIPImage.cc new file mode 100644 index 0000000..f8e556a --- /dev/null +++ b/iipsrv/src/IIPImage.cc @@ -0,0 +1,358 @@ +// IIPImage.cc + + +/* IIP fcgi server module + + Copyright (C) 2000-2014 Ruven Pillay. + + 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 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + + +#include "IIPImage.h" + +#ifdef HAVE_GLOB_H +#include +#endif + +#if _MSC_VER +#define S_ISREG(mode) (((mode) & S_IFMT) == S_IFREG) +#endif + +#include +#include +#include +#include +#include +#include +#include +#include + + +using namespace std; + + + +// Swap function +void IIPImage::swap( IIPImage& first, IIPImage& second ) // nothrow +{ + // Swap the members of the two objects + std::swap( first.imagePath, second.imagePath ); + std::swap( first.isFile, second.isFile ); + std::swap( first.suffix, second.suffix ); + std::swap( first.virtual_levels, second.virtual_levels ); + std::swap( first.format, second.format ); + std::swap( first.fileSystemPrefix, second.fileSystemPrefix ); + std::swap( first.fileNamePattern, second.fileNamePattern ); + std::swap( first.horizontalAnglesList, second.horizontalAnglesList ); + std::swap( first.verticalAnglesList, second.verticalAnglesList ); + std::swap( first.image_widths, second.image_widths ); + std::swap( first.image_heights, second.image_heights ); + std::swap( first.tile_width, second.tile_width ); + std::swap( first.tile_height, second.tile_height ); + std::swap( first.numResolutions, second.numResolutions ); + std::swap( first.bpc, second.bpc ); + std::swap( first.channels, second.channels ); + std::swap( first.sampleType, second.sampleType ); + std::swap( first.quality_layers, second.quality_layers ); + std::swap( first.colourspace, second.colourspace ); + std::swap( first.isSet, second.isSet ); + std::swap( first.currentX, second.currentX ); + std::swap( first.currentY, second.currentY ); + std::swap( first.metadata, second.metadata ); + std::swap( first.timestamp, second.timestamp ); + std::swap( first.min, second.min ); + std::swap( first.max, second.max ); +} + + + +void IIPImage::testImageType() throw(file_error) +{ + // Check whether it is a regular file + struct stat sb; + + string path = fileSystemPrefix + imagePath; + + if( (stat(path.c_str(),&sb)==0) && S_ISREG(sb.st_mode) ){ + + isFile = true; + int dot = imagePath.find_last_of( "." ); + suffix = imagePath.substr( dot + 1, imagePath.length() ); + timestamp = sb.st_mtime; + + // Determine our file format using magic file signatures + unsigned char header[10]; + FILE *im = fopen( path.c_str(), "rb" ); + if( im == NULL ){ + string message = "Unable to open file '" + path + "'"; + throw file_error( message ); + } + + // Read and close immediately + int len = fread( header, 1, 10, im ); + fclose( im ); + + // Make sure we were able to read enough bytes + if( len < 10 ){ + string message = "Unable to read initial byte sequence from file '" + path + "'"; + throw file_error( message ); + } + + // Magic file signature for JPEG2000 + unsigned char j2k[10] = {0x00,0x00,0x00,0x0C,0x6A,0x50,0x20,0x20,0x0D,0x0A}; + + // Magic file signatures for TIFF (See http://www.garykessler.net/library/file_sigs.html) + unsigned char stdtiff[3] = {0x49,0x20,0x49}; // TIFF + unsigned char lsbtiff[4] = {0x49,0x49,0x2A,0x00}; // Little Endian TIFF + unsigned char msbtiff[4] = {0x49,0x49,0x2A,0x00}; // Big Endian TIFF + unsigned char lbigtiff[4] = {0x4D,0x4D,0x00,0x2B}; // Little Endian BigTIFF + unsigned char bbigtiff[4] = {0x49,0x49,0x2B,0x00}; // Big Endian BigTIFF + + + // Compare our header sequence to our magic byte signatures + if (suffix=="vtif" || + suffix=="svs" || + suffix=="ndpi" || + suffix=="mrxs" || + suffix=="vms" || + suffix=="scn" || + suffix=="bif") + format = OPENSLIDE; + else if( memcmp( header, j2k, 10 ) == 0 ) format = JPEG2000; + else if( memcmp( header, stdtiff, 3 ) == 0 + || memcmp( header, lsbtiff, 4 ) == 0 || memcmp( header, msbtiff, 4 ) == 0 + || memcmp( header, lbigtiff, 4 ) == 0 || memcmp( header, bbigtiff, 4 ) == 0 ){ + format = TIF; + } + else format = UNSUPPORTED; + + } + else{ + +#ifdef HAVE_GLOB_H + + // Check for sequence + glob_t gdat; + string filename = path + fileNamePattern + "000_090.*"; + + if( glob( filename.c_str(), 0, NULL, &gdat ) != 0 ){ + globfree( &gdat ); + string message = path + string( " is neither a file nor part of an image sequence" ); + throw file_error( message ); + } + if( gdat.gl_pathc != 1 ){ + globfree( &gdat ); + string message = string( "There are multiple file extensions matching " ) + filename; + throw file_error( message ); + } + + string tmp( gdat.gl_pathv[0] ); + globfree( &gdat ); + + isFile = false; + + int dot = tmp.find_last_of( "." ); + int len = tmp.length(); + + suffix = tmp.substr( dot + 1, len ); + if (suffix=="vtif" || + suffix=="svs" || + suffix=="ndpi" || + suffix=="mrxs" || + suffix=="vms" || + suffix=="scn" || + suffix=="bif") + format = OPENSLIDE; + else if( suffix == "jp2" || suffix == "jpx" || suffix == "j2k" ) format = JPEG2000; + else if( suffix == "ptif" || suffix == "tif" || suffix == "tiff" ) format = TIF; + else format = UNSUPPORTED; + + updateTimestamp( tmp ); + +#else + string message = path + string( " is not a regular file and no glob support enabled" ); + throw file_error( message ); +#endif + + } + +} + +time_t IIPImage::getFileTimestamp(const string& path) throw(file_error) +{ + // Get a modification time for our image + struct stat sb; + + if( stat( path.c_str(), &sb ) == -1 ){ + string message = string( "Unable to open file " ) + path; + throw file_error( message ); + } + return sb.st_mtime; +} + + +bool IIPImage::updateTimestamp( const string& path ) throw(file_error) +{ + + time_t newtime = IIPImage::getFileTimestamp(path); + double modified = difftime(newtime, timestamp); + timestamp = newtime; + if (modified > std::numeric_limits::round_error()) return true; + else return false; +} + + + +const std::string IIPImage::getTimestamp() +{ + tm *t; + const time_t tm1 = timestamp; + t = gmtime( &tm1 ); + char strt[64]; + strftime( strt, 64, "%a, %d %b %Y %H:%M:%S GMT", t ); + + return string(strt); +} + + + +void IIPImage::measureVerticalAngles() +{ + verticalAnglesList.clear(); + +#ifdef HAVE_GLOB_H + + glob_t gdat; + unsigned int i; + + string filename = fileSystemPrefix + imagePath + fileNamePattern + "000_*." + suffix; + + if( glob( filename.c_str(), 0, NULL, &gdat ) != 0 ){ + globfree( &gdat ); + } + + for( i=0; i < gdat.gl_pathc; i++ ){ + + // Extract angle no from path name. + int angle; + string tmp( gdat.gl_pathv[i] ); + int len = tmp.length() - suffix.length() - 1; + string sequence_no = tmp.substr( len-3, 3 ); + istringstream(sequence_no) >> angle; + verticalAnglesList.push_front( angle ); + } + + verticalAnglesList.sort(); + + globfree( &gdat ); + +#endif + +} + + + +void IIPImage::measureHorizontalAngles() +{ + horizontalAnglesList.clear(); + +#ifdef HAVE_GLOB_H + + glob_t gdat; + unsigned int i; + + string filename = fileSystemPrefix + imagePath + fileNamePattern + "*_090." + suffix; + + if( glob( filename.c_str(), 0, NULL, &gdat ) != 0 ){ + globfree( &gdat ); + } + + for( i=0; i < gdat.gl_pathc; i++ ){ + + // Extract angle no from path name. + int angle; + string tmp( gdat.gl_pathv[i] ); + int start = string(fileSystemPrefix + imagePath + fileNamePattern).length(); + int end = tmp.find_last_of("_"); + string n = tmp.substr( start, end-start ); + istringstream(n) >> angle; + horizontalAnglesList.push_front( angle ); + } + + horizontalAnglesList.sort(); + + globfree( &gdat ); + +#endif + +} + + + +void IIPImage::Initialise() +{ + testImageType(); + + if( !isFile ){ + // Measure sequence angles + measureHorizontalAngles(); + + // Measure vertical view angles + measureVerticalAngles(); + } + // If it's a single value, give the view default angles of 0 and 90 + else{ + horizontalAnglesList.push_front( 0 ); + verticalAnglesList.push_front( 90 ); + } + +} + + + +const string IIPImage::getFileName( int seq, int ang ) +{ + char name[1024]; + + if( isFile ){ + return fileSystemPrefix+imagePath; + } + else{ + // The angle or spectral band indices should be a minimum of 3 digits when padded + snprintf( name, 1024, + "%s%s%03d_%03d.%s", (fileSystemPrefix+imagePath).c_str(), fileNamePattern.c_str(), + seq, ang, suffix.c_str() ); + return string( name ); + } +} + + + +int operator == ( const IIPImage& A, const IIPImage& B ) +{ + if( A.imagePath == B.imagePath ) return( 1 ); + else return( 0 ); +} + + + +int operator != ( const IIPImage& A, const IIPImage& B ) +{ + if( A.imagePath != B.imagePath ) return( 1 ); + else return( 0 ); +} + + diff --git a/iipsrv/src/IIPImage.h b/iipsrv/src/IIPImage.h new file mode 100644 index 0000000..9e399cf --- /dev/null +++ b/iipsrv/src/IIPImage.h @@ -0,0 +1,378 @@ +// IIPImage class + +/* IIP fcgi server module + + Copyright (C) 2000-2014 Ruven Pillay. + + 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 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + + +#ifndef _IIPIMAGE_H +#define _IIPIMAGE_H + + +// Fix missing snprintf in Windows +#if _MSC_VER +#define snprintf _snprintf +#endif + + +#include +#include +#include +#include +#include + +#include "RawTile.h" + + +/// Define our own derived exception class for file errors +class file_error : public std::runtime_error { + public: + file_error(std::string s) : std::runtime_error(s) { } +}; + + +// Supported image formats +enum ImageFormat { TIF, JPEG2000, OPENSLIDE, UNSUPPORTED }; + + + +/// Main class to handle the pyramidal image source +/** Provides functions to open, get various information from an image source + and get individual tiles. This class is the base class for specific image + file formats such as Tiled Pyramidal TIFF images via TPTImage.h and + JPEG2000 via Kakadu.h + */ + +class IIPImage { + + private: + + /// Image path supplied + std::string imagePath; + + /// Prefix to add to paths + std::string fileSystemPrefix; + + /// Pattern for sequences + std::string fileNamePattern; + + /// Indicates whether our image is a single file or part or a sequence + bool isFile; + + /// Image file name suffix + std::string suffix; + + /// Private function to determine the image type + void testImageType() throw( file_error ); + + /// If we have a sequence of images, determine which horizontal angles exist + void measureHorizontalAngles(); + + /// If we have a sequence of images, determine which vertical angles exist + void measureVerticalAngles(); + + /// The list of available horizontal angles (for image sequences) + std::list horizontalAnglesList; + + /// The list of available vertical angles (for image sequences) + std::list verticalAnglesList; + + + public: + + /// Number of resolution levels that don't physically exist in file + unsigned int virtual_levels; + + /// Return the image format e.g. tif + ImageFormat format; + + /// The image pixel dimensions + std::vector image_widths, image_heights; + + /// The base tile pixel dimensions + unsigned int tile_width, tile_height; + + /// The colour space of the image + ColourSpaces colourspace; + + /// The number of available resolutions in this image + unsigned int numResolutions; + + /// The bits per channel for this image + unsigned int bpc; + + /// The number of channels for this image + unsigned int channels; + + /// The sample format type (fixed or floating point) + SampleType sampleType; + + /// The min and max sample value for each channel + std::vector min, max; + + /// Quality layers + unsigned int quality_layers; + + /// Indicate whether we have opened and initialised some paramters for this image + bool isSet; + + /// If we have an image sequence, the current X and Y position + int currentX, currentY; + + /// STL map to hold string metadata + std::map metadata; + + /// Image modification timestamp + time_t timestamp; + + + public: + + /// Default Constructor + IIPImage() + : isFile( false ), + tile_width( 0 ), + tile_height( 0 ), + bpc( 0 ), + channels( 0 ), + quality_layers( 0 ), + isSet( false ), + currentX( 0 ), + currentY( 90 ), + timestamp( 0 ) {}; + + /// Constructer taking the image path as parameter + /** @param s image path + */ + IIPImage( const std::string& s ) + : imagePath( s ), + isFile( false ), + virtual_levels( 0 ), + tile_width( 0 ), + tile_height( 0 ), + bpc( 0 ), + channels( 0 ), + quality_layers( 0 ), + isSet( false ), + currentX( 0 ), + currentY( 90 ), + timestamp( 0 ) {}; + + /// Copy Constructor taking reference to another IIPImage object + /** @param im IIPImage object + */ + IIPImage( const IIPImage& image ) + : imagePath( image.imagePath ), + fileSystemPrefix( image.fileSystemPrefix ), + fileNamePattern( image.fileNamePattern ), + isFile( image.isFile ), + suffix( image.suffix ), + horizontalAnglesList( image.horizontalAnglesList ), + verticalAnglesList( image.verticalAnglesList ), + virtual_levels( image.virtual_levels ), + format( image.format ), + image_widths( image.image_widths ), + image_heights( image.image_heights ), + tile_width( image.tile_width ), + tile_height( image.tile_height ), + colourspace( image.colourspace ), + numResolutions( image.numResolutions ), + bpc( image.bpc ), + channels( image.channels ), + sampleType( image.sampleType ), + min( image.min ), + max( image.max ), + quality_layers( image.quality_layers ), + isSet( image.isSet ), + currentX( image.currentX ), + currentY( image.currentY ), + metadata( image.metadata ), + timestamp( image.timestamp ) {}; + + /// Virtual Destructor + virtual ~IIPImage() { ; }; + + /// Test the image and initialise some parameters + void Initialise(); + + /// Swap function + /** @param a Object to copy to + @param b Object to copy from + */ + void swap( IIPImage& a, IIPImage& b ); + + /// Return a list of available vertical angles + std::list getVerticalViewsList(){ return verticalAnglesList; }; + + /// Return a list of horizontal angles + std::list getHorizontalViewsList(){ return horizontalAnglesList; }; + + /// Return the image path + const std::string& getImagePath() { return imagePath; }; + + /// Return the full file path for a particular horizontal and vertical angle + /** @param x horizontal sequence angle + @param y vertical sequence angle + */ + const std::string getFileName( int x, int y ); + + /// Get the image format + // const std::string& getImageFormat() { return format; }; + ImageFormat getImageFormat() { return format; }; + + /// get the image timestamp from file system + static time_t getFileTimestamp(const std::string& s) throw( file_error ); + + time_t getRawTimestamp() { return timestamp; }; + + /// Get the image timestamp and update the stored var + /** @param s file path + */ + bool updateTimestamp( const std::string& s ) throw( file_error ); + + /// Get a HTTP RFC 1123 formatted timestamp + const std::string getTimestamp(); + + /// Check whether this object has been initialised + bool set() { return isSet; }; + + /// Set a file system prefix for added security + void setFileSystemPrefix( const std::string& prefix ) { fileSystemPrefix = prefix; }; + + /// Set the file name pattern used in image sequences + void setFileNamePattern( const std::string& pattern ) { fileNamePattern = pattern; }; + + /// Return the number of available resolutions in the image + unsigned int getNumResolutions() { return numResolutions; }; + + /// Return the number of bits per pixel for this image + unsigned int getNumBitsPerPixel() { return bpc; }; + + /// Return the number of channels for this image + unsigned int getNumChannels() { return channels; }; + + /// Return the minimum sample value for each channel + /** @param n channel index + */ + float getMinValue( int n=0 ) { return min[n]; }; + + /// Return the minimum sample value for each channel + /** @param n channel index + */ + float getMaxValue( int n=0 ) { return max[n]; }; + + /// Return the sample format type + SampleType getSampleType(){ return sampleType; }; + + /// Return the image width in pixels for a given resolution + /** @param n resolution number (0 is default and full size image) + */ + unsigned int getImageWidth( int n=0 ) { return image_widths[n]; }; + + /// Return the image height in pixels for a given resolution + /** @param n resolution number (0 is default and full size image) + */ + unsigned int getImageHeight( int n=0 ) { return image_heights[n]; }; + + /// Return the base tile height in pixels for a given resolution + unsigned int getTileHeight() { return tile_height; }; + + /// Return the base tile width in pixels + unsigned int getTileWidth() { return tile_width; }; + + /// Return the colour space for this image + ColourSpaces getColourSpace() { return colourspace; }; + + /// Return image metadata + /** @param index metadata field name */ + const std::string& getMetadata( const std::string& index ) { + return metadata[index]; + }; + + /// Return whether this image type directly handles region decoding + virtual bool regionDecoding(){ return false; }; + + /// Load the appropriate codec module for this image type + /** Used only for dynamically loading codec modules. Overloaded by DSOImage class. + @param module the codec module path + */ + virtual void Load( const std::string& module ) {;}; + + /// Return codec description: Overloaded by child class. + virtual const std::string getDescription() { return std::string( "IIPImage Base Class" ); }; + + /// Open the image: Overloaded by child class. + virtual void openImage() { throw file_error( "IIPImage openImage called" ); }; + + /// Load information about the image eg. number of channels, tile size etc. + /** @param x horizontal sequence angle + @param y vertical sequence angle + */ + virtual void loadImageInfo( int x, int y ) { ; }; + + /// Close the image: Overloaded by child class. + virtual void closeImage() {;}; + + + /// Return an individual tile for a given angle and resolution + /** Return a RawTile object: Overloaded by child class. + @param h horizontal angle + @param v vertical angle + @param r resolution + @param l quality layers + @param t tile number + */ + virtual RawTilePtr getTile( int h, int v, unsigned int r, int l, unsigned int t ) { return RawTilePtr(); }; + + + /// Return a region for a given angle and resolution + /** Return a RawTile object: Overloaded by child class. + @param ha horizontal angle + @param va vertical angle + @param r resolution + @param layers number of layers to decode + @param x offset in x direction at resolution r + @param y offset in y direction at resolution r + @param w width of region at resolution r + @param h height of region at resolution r + @param b image buffer + */ + virtual RawTilePtr getRegion( int ha, int va, unsigned int r, int layers, int x, int y, unsigned int w, unsigned int h ){ return RawTilePtr(); }; + + /// Assignment operator + /** @param im IIPImage object */ + IIPImage& operator = ( IIPImage image ){ + swap( *this, image ); + return *this; + }; + + /// Comparison equality operator + friend int operator == ( const IIPImage&, const IIPImage& ); + + /// Comparison non-equality operator + friend int operator != ( const IIPImage&, const IIPImage& ); + +}; + +#if defined(HAS_SHARED_PTR) + typedef std::shared_ptr IIPImagePtr; +#else + typedef IIPImage* IIPImagePtr; +#endif + +#endif diff --git a/iipsrv/src/IIPResponse.cc b/iipsrv/src/IIPResponse.cc new file mode 100644 index 0000000..335602d --- /dev/null +++ b/iipsrv/src/IIPResponse.cc @@ -0,0 +1,128 @@ +/* + IIP Response Handler Class + + Copyright (C) 2003-2014 Ruven Pillay. + + 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 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +#include "IIPResponse.h" +#include +#include + +using namespace std; + + + +IIPResponse::IIPResponse(){ + + responseBody = ""; + error = ""; + protocol = ""; + server = "Server: iipsrv/" + string(VERSION); + modified = ""; + cache = "Cache-Control: max-age=86400"; + mimeType = "Content-Type: application/vnd.netfpx"; + cors = ""; + eof = "\r\n"; + sent = false; +} + + +void IIPResponse::addResponse( const string& r ){ + + responseBody.append( r ); + responseBody.append( eof ); +} + + +void IIPResponse::addResponse( const char* c ){ + + responseBody.append( c ); + responseBody.append( eof ); +} + + +void IIPResponse::addResponse( const char* c, int a ){ + + char tmp[64]; + snprintf( tmp, 64, "%s:%d", c, a ); + responseBody.append( tmp ); + responseBody.append( eof ); +} + + +void IIPResponse::addResponse( string arg, const string& s ){ + + char tmp[8]; + snprintf( tmp, 8, "/%d:", (int) s.size() ); + responseBody.append( arg ); + responseBody.append( tmp ); + responseBody.append( s ); + responseBody.append( eof ); +} + + +void IIPResponse::addResponse( const char* c, int a, int b ){ + + char tmp[64]; + snprintf( tmp, 64, "%s:%d %d", c, a, b ); + responseBody.append( tmp ); + responseBody.append( eof ); +} + + +void IIPResponse::setError( const string& code, const string& arg ){ + + char tmp[32]; + snprintf( tmp, 32, "Error/%ld:%s %s", (long)(code.length() + arg.length() + 1), code.c_str(), arg.c_str() ); + error += tmp + eof; +} + + +string IIPResponse::formatResponse() { + + /* We always need 2 sets of eof after the headers before body/response + */ + string response; + if( error.length() ){ + response = server + eof + "Cache-Control: no-cache" + eof + mimeType + eof + + "Status: 400 Bad Request" + eof + + "Content-Disposition: inline;filename=\"IIPisAMadGameClosedToOurUnderstanding.netfpx\"" + + eof + eof + error; + } + else{ + response = server + eof + cache + eof + modified + eof + mimeType + eof; + if( !cors.empty() ) response += cors + eof; + response += eof + protocol + eof + responseBody; + } + + return response; +} + + + +string IIPResponse::getAdvert( const string& version ){ + + string advert = server + eof + "Content-Type: text/html" + eof; + advert += "Status: 400 Bad Request" + eof; + advert += "Content-Disposition: inline;filename=\"iipsrv.html\"" + eof + eof; + advert += "IIPImage Server

IIPImage Server

Version " + + version + + "


Project Home Page: http://iipimage.sourceforge.net


by
Ruven Pillay

"; + + return advert; + +} diff --git a/iipsrv/src/IIPResponse.h b/iipsrv/src/IIPResponse.h new file mode 100644 index 0000000..bb36966 --- /dev/null +++ b/iipsrv/src/IIPResponse.h @@ -0,0 +1,155 @@ +/* + IIP Response Handler Class + + Copyright (C) 2003-2014 Ruven Pillay. + + 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 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + + +#ifndef _IIPRESPONSE_H +#define _IIPRESPONSE_H + +#ifndef VERSION +#define VERSION "0.9.9.9" +#endif + +// Fix missing snprintf in Windows +#if _MSC_VER +#define snprintf _snprintf +#endif + + +#include + + +/// Class to handle non-image IIP responses including errors + +class IIPResponse{ + + + private: + + std::string server; // Server header + std::string modified; // Last modified header + std::string cache; // Cache control header + std::string mimeType; // Mime type header + std::string eof; // End of response delimitter eg "\r\n" + std::string protocol; // IIP protocol version + std::string responseBody; // The main response + std::string error; // Error message + std::string cors; // CORS (Cross-Origin Resource Sharing) setting + bool sent; // Indicate whether a response has been sent + + + public: + + /// Constructor + IIPResponse(); + + + /// Set the IIP protocol version + /** @param p IIP protocol version */ + void setProtocol( const std::string& p ) { protocol = p; }; + + + /// Set the Last Modified header + /** @param m Last modifed date as a HTTP RFC 1123 formatted timestamp */ + void setLastModified( const std::string& m ) { modified = "Last-Modified: " + m; }; + + + /// Add a response string + /** @param r response string */ + void addResponse( const std::string& r ); + + + /// Add a response string + /** @param c response string */ + void addResponse( const char* c ); + + + /// Add a response string + /** @param c response string + @param a integer value + */ + void addResponse( const char* c, int a ); + + + /// Add a response string + /** @param c response string + @param a string reply + */ + void addResponse( std::string c, const std::string& a ); + + + /// Add a response string + /** @param c response string + @param a integer value + @param b another integer value + */ + void addResponse( const char* c, int a, int b ); + + + /// Set an error + /** @param code error code + @param arg the argument supplied by the client + */ + void setError( const std::string& code, const std::string& arg ); + + + /// Set CORS setting + /** @param cors setting */ + void setCORS( const std::string& c ){ if(!c.empty()) cors = "Access-Control-Allow-Origin: " + c; }; + + + /// Get CORS setting + std::string getCORS(){ return cors; }; + + + /// Get a formatted string to send back + std::string formatResponse(); + + + /// Indicate whether this object has had any arguments passed to it + bool isSet(){ + if( error.length() || responseBody.length() || protocol.length() ) return true; + else return false; + } + + + /// Indicate whether we have an error message + bool errorIsSet(){ + if( error.length() ) return true; + else return false; + } + + + /// Set the sent flag indicating that some sort of response has been sent + void setImageSent() { sent = true; }; + + + /// Indicate whether a response has been sent + bool imageSent() { return sent; }; + + + /// Display our advertising banner ;-) + /** @param version server version */ + std::string getAdvert( const std::string& version ); + + +}; + + +#endif diff --git a/iipsrv/src/JPEGCompressor.cc b/iipsrv/src/JPEGCompressor.cc new file mode 100644 index 0000000..95e71e0 --- /dev/null +++ b/iipsrv/src/JPEGCompressor.cc @@ -0,0 +1,446 @@ +/* JPEG class wrapper to ijg jpeg library + + Copyright (C) 2000-2012 Ruven Pillay. + + 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 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + + + +#include "JPEGCompressor.h" + + +using namespace std; + + +#define MX 16536 + + +/* My version of the JPEG error_exit function. We want to pass control back + to the program, so simply throw an exception +*/ + +METHODDEF(void) iip_error_exit( j_common_ptr cinfo ) +{ + char buffer[ JMSG_LENGTH_MAX ]; + + /* Create the message + */ + (*cinfo->err->format_message) ( cinfo, buffer ); + + /* Let the memory manager delete any temp files before we die + */ + jpeg_destroy( cinfo ); + + /* throw an exception rather than print out a message and exit + */ + throw string( buffer ); +} + + + +extern "C" { + + void setup_error_functions( jpeg_compress_struct *a ){ + a->err->error_exit = iip_error_exit; + } +} + + + + +/* + * Initialize destination --- called by jpeg_start_compress + * before any data is actually written. + */ + +METHODDEF(void) +iip_init_destination (j_compress_ptr cinfo) +{ + size_t mx; + iip_dest_ptr dest = (iip_dest_ptr) cinfo->dest; + + /* If we have set the strip height, we must be doing a buffer to buffer + compression, so only allocate enough for this strip. Otherwise allocate + memory for the whole image + */ + if( dest->strip_height > 0 ){ + mx = cinfo->image_width * dest->strip_height * cinfo->input_components; + } + else{ + mx = cinfo->image_width * cinfo->image_height * cinfo->input_components; + } + + /* Add some extra because when we have very small tiles, the JPEG data + including header can end up being larger than the original raw + data size, especially at high quality factors! + */ + mx += MX; + + /* Allocate the output buffer --- it will be released when done with image + dest->buffer = (JOCTET *) + (*cinfo->mem->alloc_small) ( (j_common_ptr) cinfo, JPOOL_IMAGE, + mx * sizeof(JOCTET) ); + */ + + // In fact just allocate with new + dest->buffer = new JOCTET[mx]; + dest->size = mx; + + // Set compressor pointers for library + dest->pub.next_output_byte = dest->buffer; + dest->pub.free_in_buffer = mx; +} + + + + +METHODDEF(boolean) +iip_empty_output_buffer( j_compress_ptr cinfo ) +{ + iip_dest_ptr dest = (iip_dest_ptr) cinfo->dest; + size_t datacount = dest->size; + + // Copy the JPEG data to our output tile buffer + if( datacount > 0 ){ + if( datacount > cinfo->image_width*dest->strip_height*cinfo->input_components + MX ){ + datacount = cinfo->image_width*dest->strip_height*cinfo->input_components + MX; + } + memcpy( dest->source, dest->buffer, datacount ); + } + + // Reset the pointer to the beginning of the buffer + dest->pub.next_output_byte = dest->buffer; + dest->pub.free_in_buffer = datacount; + + return TRUE; +} + + + + +/* + * Terminate destination --- called by jpeg_finish_compress + * after all data has been written. Usually needs to flush buffer. + * + * NB: *not* called by jpeg_abort or jpeg_destroy; surrounding + * application must deal with any cleanup that should happen even + * for error exit. + */ + +void iip_term_destination( j_compress_ptr cinfo ) +{ + iip_dest_ptr dest = (iip_dest_ptr) cinfo->dest; + size_t datacount = dest->size - dest->pub.free_in_buffer; + + // Copy the JPEG data to our output tile buffer + if( datacount > 0 ){ + memcpy( dest->source, dest->buffer, datacount ); + } + + dest->size = datacount; + + delete[] dest->buffer; +} + + + + +void JPEGCompressor::InitCompression( const RawTilePtr rawtile, unsigned int strip_height ) throw (string) +{ + // Do some initialisation + dest = &dest_mgr; + + // Set up the correct width and height for this particular tile + width = rawtile->width; + height = rawtile->height; + channels = rawtile->channels; + + + // Make sure we only try to compress images with 1 or 3 channels + if( ! ( (channels==1) || (channels==3) ) ){ + throw string( "JPEGCompressor: JPEG can only handle images of either 1 or 3 channels" ); + } + + + // We set up the normal JPEG error routines, then override error_exit. + cinfo.err = jpeg_std_error( &jerr ); + + + // Overide the error_exit function with our own. + // Hmmm, we have to do this assignment in C due to the strong type checking of C++ + // or something like that. So, we use an extern "C" function declared at the top + // of this file and pass our arguments through this. I'm sure there's a better + // way of doing this, but this seems to work :/ + + // cinfo.err.error_exit = iip_error_exit; + setup_error_functions( &cinfo ); + + jpeg_create_compress( &cinfo ); + + + /* The destination object is made permanent so that multiple JPEG images + * can be written to the same file without re-executing jpeg_stdio_dest. + * This makes it dangerous to use this manager and a different destination + * manager serially with the same JPEG object, because their private object + * sizes may be different. Caveat programmer. + */ + if( !cinfo.dest ){ + // first time for this JPEG object? + cinfo.dest = ( struct jpeg_destination_mgr* ) + ( *cinfo.mem->alloc_small ) + ( (j_common_ptr) &cinfo, JPOOL_PERMANENT, sizeof( iip_destination_mgr ) ); + } + + + dest = (iip_dest_ptr) cinfo.dest; + dest->pub.init_destination = iip_init_destination; + //dest->pub.empty_output_buffer = iip_empty_output_buffer; + dest->pub.term_destination = iip_term_destination; + dest->strip_height = strip_height; + + cinfo.image_width = width; + cinfo.image_height = height; + cinfo.input_components = channels; + cinfo.in_color_space = ( channels == 3 ? JCS_RGB : JCS_GRAYSCALE ); + jpeg_set_defaults( &cinfo ); + + // Set compression point quality (highest, but possibly slower depending + // on hardware) - must do this after we've set the defaults! + cinfo.dct_method = JDCT_FASTEST; + + jpeg_set_quality( &cinfo, Q, TRUE ); + + jpeg_start_compress( &cinfo, TRUE ); + + + // Copy the JPEG header data to our output tile buffer + size_t datacount = dest->size - dest->pub.free_in_buffer; + header_size = datacount; + if( datacount > 0 ){ + memcpy( header, dest->buffer, datacount ); + } + + + // Reset the pointers + size_t mx = cinfo.image_width * strip_height * cinfo.input_components; + dest->size = mx + MX; + dest->pub.next_output_byte = dest->buffer; + dest->pub.free_in_buffer = mx + MX; + + // Add an identifying comment + jpeg_write_marker( &cinfo, JPEG_COM, (const JOCTET*) "Generated by IIPImage", 21 ); + +} + + + +/* + We use a separate tile_height from the predefined strip_height because + the tile height for the final row can be different + */ +unsigned int JPEGCompressor::CompressStrip( unsigned char* input, unsigned char* output, unsigned int tile_height ) throw (string) +{ + JSAMPROW row[1]; + int row_stride = width * channels; + dest->source = output; + + while( cinfo.next_scanline < tile_height ) { + row[0] = &input[ cinfo.next_scanline * row_stride ]; + jpeg_write_scanlines( &cinfo, row, 1 ); + } + + // Copy the JPEG data to our output tile buffer + size_t datacount = dest->size - dest->pub.free_in_buffer; + if( datacount > 0 ){ + // Be careful not to overun our buffer + if( datacount > tile_height*width*channels + MX ) datacount = tile_height*width*channels + MX; + memcpy( output, dest->buffer, datacount ); + } + + // Set compressor pointers for library + size_t mx = cinfo.image_width * dest->strip_height * cinfo.input_components; + dest->pub.next_output_byte = dest->buffer; + dest->pub.free_in_buffer = mx + MX; + cinfo.next_scanline = 0; + dest->size = mx + MX; + + return datacount; +} + + + + +unsigned int JPEGCompressor::Finish( unsigned char* output ) throw (string) +{ + dest->source = output; + + // Tidy up and de-allocate memory + dest->pub.next_output_byte = dest->buffer; + cinfo.next_scanline = dest->strip_height; + jpeg_finish_compress( &cinfo ); + + size_t datacount = dest->size; + + jpeg_destroy_compress( &cinfo ); + + return datacount; +} + + +int JPEGCompressor::Compress( RawTilePtr rawtile ) throw (string) +{ + + // Do some initialisation + data = (unsigned char*) rawtile->data; + struct jpeg_compress_struct cinfo; + struct jpeg_error_mgr jerr; + iip_destination_mgr dest_mgr; + iip_dest_ptr dest = &dest_mgr; + + + // Set up the correct width and height for this particular tile + width = rawtile->width; + height = rawtile->height; + channels = rawtile->channels; + + + // Make sure we only try to compress images with 1 or 3 channels + if( ! ( (channels==1) || (channels==3) ) ){ + throw string( "JPEGCompressor: JPEG can only handle images of either 1 or 3 channels" ); + } + + + // We set up the normal JPEG error routines, then override error_exit. + cinfo.err = jpeg_std_error( &jerr ); + + + // Overide the error_exit function with our own. + // Hmmm, we have to do this assignment in C due to the strong type checking of C++ + // or something like that. So, we use an extern "C" function declared at the top + // of this file and pass our arguments through this. I'm sure there's a better + // way of doing this, but this seems to work :/ + + // cinfo.err.error_exit = iip_error_exit; + setup_error_functions( &cinfo ); + + jpeg_create_compress( &cinfo ); + + + /* The destination object is made permanent so that multiple JPEG images + * can be written to the same file without re-executing jpeg_stdio_dest. + * This makes it dangerous to use this manager and a different destination + * manager serially with the same JPEG object, because their private object + * sizes may be different. Caveat programmer. + */ + + if( !cinfo.dest ){ + + // first time for this JPEG object? + cinfo.dest = ( struct jpeg_destination_mgr* ) + ( *cinfo.mem->alloc_small ) + ( (j_common_ptr) &cinfo, JPOOL_PERMANENT, sizeof( iip_destination_mgr ) ); + } + + + dest = (iip_dest_ptr) cinfo.dest; + dest->pub.init_destination = iip_init_destination; + dest->pub.empty_output_buffer = iip_empty_output_buffer; + dest->pub.term_destination = iip_term_destination; + dest->strip_height = 0; + + // Allocate memory for our destination + dest->source = new unsigned char[width*height*channels + MX]; // Add some extra buffering + + // Set floating point quality (highest, but possibly slower depending + // on hardware) + cinfo.image_width = width; + cinfo.image_height = height; + cinfo.input_components = channels; + cinfo.in_color_space = ( channels == 3 ? JCS_RGB : JCS_GRAYSCALE ); + jpeg_set_defaults( &cinfo ); + + // Set compression quality (highest, but possibly slower depending + // on hardware) - must do this after we've set the defaults! + cinfo.dct_method = JDCT_FASTEST; + + jpeg_set_quality( &cinfo, Q, TRUE ); + + jpeg_start_compress( &cinfo, TRUE ); + + // Add an identifying comment + jpeg_write_marker( &cinfo, JPEG_COM, (const JOCTET*) "Generated by IIPImage", 21 ); + //jpeg_write_marker( &cinfo, JPEG_APP0+1, (const JOCTET*) , ) + + // Send the tile data + unsigned int y; + int row_stride = width * channels; + + + // Try to pass the whole image array at once if it is less than 512x512 pixels: + // Should be faster than scanlines. + if( (row_stride * height) <= (512*512*channels) ){ + + JSAMPROW *array = new JSAMPROW[height]; + for( y=0; y < height; y++ ){ + array[y] = &data[ y * row_stride ]; + } + jpeg_write_scanlines( &cinfo, array, height ); + delete[] array; + + } + else{ + JSAMPROW row[1]; + while( cinfo.next_scanline < cinfo.image_height ) { + row[0] = &data[ cinfo.next_scanline * row_stride ]; + jpeg_write_scanlines( &cinfo, row, 1 ); + } + } + + + // Tidy up, get the compressed data size and de-allocate memory + jpeg_finish_compress( &cinfo ); + + // Check that we have enough memory in our tile for the JPEG data. + // This can happen on small tiles with high quality factors. If so + // delete and reallocate memory. + y = dest->size; + if( y > rawtile->width*rawtile->height*rawtile->channels ){ + delete[] (unsigned char*) rawtile->data; + rawtile->data = new unsigned char[y]; + } + + // Copy memory back to the tile + memcpy( rawtile->data, dest->source, y ); + delete[] dest->source; + jpeg_destroy_compress( &cinfo ); + + + // Set the tile compression parameters + rawtile->dataLength = y; + rawtile->compressionType = JPEG; + rawtile->quality = Q; + + + // Return the size of the data we have compressed + return y; + +} + + + +void JPEGCompressor::addMetadata( const string& metadata ){ + jpeg_write_marker( &cinfo, JPEG_APP0, (const JOCTET*) metadata.c_str(), metadata.size() ); +} diff --git a/iipsrv/src/JPEGCompressor.h b/iipsrv/src/JPEGCompressor.h new file mode 100644 index 0000000..7728dbd --- /dev/null +++ b/iipsrv/src/JPEGCompressor.h @@ -0,0 +1,149 @@ +/* JPEG class wrapper to ijg jpeg library + + Copyright (C) 2000-2012 Ruven Pillay. + + 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 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + + + +#ifndef _JPEGCOMPRESSOR_H +#define _JPEGCOMPRESSOR_H + + + +#include +#include +#include "RawTile.h" + + +extern "C"{ +/* Undefine this to prevent compiler warning + */ +#undef HAVE_STDLIB_H +#include +} + + + +/// Expanded data destination object for buffered output used by IJG JPEG library + + +typedef struct { + struct jpeg_destination_mgr pub; /**< public fields */ + + size_t size; /**< size of source data */ + JOCTET *buffer; /**< working buffer */ + unsigned char* source; /**< source data */ + unsigned int strip_height; /**< used for stream-based encoding */ + +} iip_destination_mgr; + +typedef iip_destination_mgr * iip_dest_ptr; + + + +/// Wrapper class to the IJG JPEG library + +class JPEGCompressor{ + + private: + + /// the width, height and number of channels per sample for the image + unsigned int width, height, channels; + + /// The JPEG quality factor + int Q; + + /// Buffer for the JPEG header + unsigned char header[1024]; + + /// Buffer for the image data + unsigned char *data; + + /// Size of the JPEG header + unsigned int header_size; + + /// JPEG library objects + struct jpeg_compress_struct cinfo; + struct jpeg_error_mgr jerr; + iip_destination_mgr dest_mgr; + iip_dest_ptr dest; + + + public: + + /// Constructor + /** @param quality JPEG Quality factor (0-100) */ + JPEGCompressor( int quality ) { Q = quality; }; + + + /// Set the compression quality + /** @param factor Quality factor (0-100) */ + void setQuality( int factor ) { + if( factor < 0 ) Q = 0; + else if( factor > 100 ) Q = 100; + else Q = factor; + }; + + + /// Get the current quality level + int getQuality() { return Q; } + + + /// Initialise strip based compression + /** If we are doing a strip based encoding, we need to first initialise + with InitCompression, then compress a single strip at a time using + CompressStrip and finally clean up using Finish + @param rawtile tile containing the image to be compressed + @param strip_height pixel height of the strip we want to compress + @return header size + */ + void InitCompression( const RawTilePtr rawtile, unsigned int strip_height ) throw (std::string); + + /// Compress a strip of image data + /** @param s source image data + @param o output buffer + @param tile_height pixel height of the tile we are compressing + */ + unsigned int CompressStrip( unsigned char* s, unsigned char* o, unsigned int tile_height ) throw (std::string); + + /// Finish the strip based compression and free memory + /** @param output output buffer + @return size of output generated + */ + unsigned int Finish( unsigned char* output ) throw (std::string); + + + /// Compress an entire buffer of image data at once in one command + /** @param t tile of image data */ + int Compress( RawTilePtr t ) throw (std::string); + + /// Add metadata to the JPEG header + /** @param m metadata */ + void addMetadata( const std::string& m ); + + + /// Return the JPEG header size + unsigned int getHeaderSize() { return header_size; } + + /// Return a pointer to the header itself + inline unsigned char* getHeader() { return header; } + + +}; + + +#endif diff --git a/iipsrv/src/JTL.cc b/iipsrv/src/JTL.cc new file mode 100644 index 0000000..9224ce9 --- /dev/null +++ b/iipsrv/src/JTL.cc @@ -0,0 +1,311 @@ +/* + IIP JTL Command Handler Class Member Function + + Copyright (C) 2006-2014 Ruven Pillay. + + 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 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +#include "Task.h" +#include "Transforms.h" + +#include +#include + +using namespace std; + + +void JTL::send( Session* session, int resolution, int tile ){ + + if( session->loglevel >= 3 ) (*session->logfile) << "JTL handler reached" << endl; + + Timer function_timer; + + + // Time this command + if( session->loglevel >= 2 ) command_timer.start(); + + + // If we have requested a rotation, remap the tile index to rotated coordinates + if( (int)((session->view)->getRotation()) % 360 == 90 ){ + + } + else if( (int)((session->view)->getRotation()) % 360 == 270 ){ + + } + else if( (int)((session->view)->getRotation()) % 360 == 180 ){ + int num_res = (session->image)->getNumResolutions(); + unsigned int im_width = (session->image)->image_widths[num_res-resolution-1]; + unsigned int im_height = (session->image)->image_heights[num_res-resolution-1]; + unsigned int tw = (session->image)->getTileWidth(); + // unsigned int th = (session->image)->getTileHeight(); + int ntiles = (int) ceil( (double)im_width/tw ) * (int) ceil( (double)im_height/tw ); + tile = ntiles - tile - 1; + } + + + // Sanity check + if( (resolution<0) || (tile<0) ){ + ostringstream error; + error << "JTL :: Invalid resolution/tile number: " << resolution << "," << tile; + throw error.str(); + } + + TileManager tilemanager( session->tileCache, session->image, session->watermark, session->jpeg, session->logfile, session->loglevel ); + + CompressionType ct; + if( (session->image)->getNumBitsPerPixel() > 8 || (session->image)->getColourSpace() == CIELAB + || (session->image)->getNumChannels() == 2 || (session->image)->getNumChannels() > 3 + || session->view->getContrast() != 1.0 || session->view->getGamma() != 1.0 + || session->view->getRotation() != 0.0 || session->view->shaded + || session->view->cmapped || session->view->inverted + || session->view->ctw.size() ) ct = UNCOMPRESSED; + else ct = JPEG; + + + RawTilePtr rawtile = tilemanager.getTile( resolution, tile, session->view->xangle, + session->view->yangle, session->view->getLayers(), ct ); + + + int len = rawtile->dataLength; + + if( session->loglevel >= 2 ){ + *(session->logfile) << "JTL :: Tile size: " << rawtile->width << " x " << rawtile->height << endl + << "JTL :: Channels per sample: " << rawtile->channels << endl + << "JTL :: Bits per channel: " << rawtile->bpc << endl + << "JTL :: Data size is " << len << " bytes" << endl; + } + + + // Convert CIELAB to sRGB + if( (session->image)->getColourSpace() == CIELAB ){ + + if( session->loglevel >= 4 ){ + *(session->logfile) << "JTL :: Converting from CIELAB->sRGB"; + function_timer.start(); + } + filter_LAB2sRGB( rawtile ); + if( session->loglevel >= 4 ){ + *(session->logfile) << " in " << function_timer.getTime() << " microseconds" << endl; + } + } + + + // Only use our float pipeline if necessary + if( rawtile->bpc > 8 || session->view->getContrast() != 1.0 || session->view->getGamma() != 1.0 || + session->view->cmapped || session->view->shaded || session->view->inverted || session->view->ctw.size() ){ + + // Apply normalization and float conversion + if( session->loglevel >= 4 ){ + *(session->logfile) << "JTL :: Normalizing and converting to float"; + function_timer.start(); + } + filter_normalize( rawtile, (session->image)->max, (session->image)->min ); + if( session->loglevel >= 4 ){ + *(session->logfile) << " in " << function_timer.getTime() << " microseconds" << endl; + } + + + // Apply hill shading if requested + if( session->view->shaded ){ + if( session->loglevel >= 4 ){ + *(session->logfile) << "JTL :: Applying hill-shading"; + function_timer.start(); + } + filter_shade( rawtile, session->view->shade[0], session->view->shade[1] ); + if( session->loglevel >= 4 ){ + *(session->logfile) << " in " << function_timer.getTime() << " microseconds" << endl; + } + } + + + // Apply color twist if requested + if( session->view->ctw.size() ){ + if( session->loglevel >= 4 ){ + *(session->logfile) << "JTL :: Applying color twist"; + function_timer.start(); + } + filter_twist( rawtile, session->view->ctw ); + if( session->loglevel >= 4 ){ + *(session->logfile) << " in " << function_timer.getTime() << " microseconds" << endl; + } + } + + + // Apply any gamma correction + if( session->view->getGamma() != 1.0 ){ + float gamma = session->view->getGamma(); + if( session->loglevel >= 4 ){ + *(session->logfile) << "JTL :: Applying gamma of " << gamma; + function_timer.start(); + } + filter_gamma( rawtile, gamma); + if( session->loglevel >= 4 ){ + *(session->logfile) << " in " << function_timer.getTime() << " microseconds" << endl; + } + } + + + // Apply inversion if requested + if( session->view->inverted ){ + if( session->loglevel >= 4 ){ + *(session->logfile) << "JTL :: Applying inversion"; + function_timer.start(); + } + filter_inv( rawtile ); + if( session->loglevel >= 4 ){ + *(session->logfile) << " in " << function_timer.getTime() << " microseconds" << endl; + } + } + + + // Apply color mapping if requested + if( session->view->cmapped ){ + if( session->loglevel >= 4 ){ + *(session->logfile) << "JTL :: Applying color map"; + function_timer.start(); + } + filter_cmap( rawtile, session->view->cmap ); + if( session->loglevel >= 4 ){ + *(session->logfile) << " in " << function_timer.getTime() << " microseconds" << endl; + } + } + + + // Apply any contrast adjustments and/or clip to 8bit from 16 or 32 bit + float contrast = session->view->getContrast(); + if( session->loglevel >= 4 ){ + *(session->logfile) << "JTL :: Applying contrast of " << contrast << " and converting to 8 bit"; + function_timer.start(); + } + filter_contrast( rawtile, contrast ); + if( session->loglevel >= 4 ){ + *(session->logfile) << " in " << function_timer.getTime() << " microseconds" << endl; + } + + } + + + // Reduce to 1 or 3 bands if we have an alpha channel or a multi-band image + if( rawtile->channels == 2 || rawtile->channels > 3 ){ + unsigned int bands = (rawtile->channels==2) ? 1 : 3; + if( session->loglevel >= 4 ){ + *(session->logfile) << "JTL :: Flattening channels to " << bands; + function_timer.start(); + } + filter_flatten( rawtile, bands ); + if( session->loglevel >= 4 ){ + *(session->logfile) << " in " << function_timer.getTime() << " microseconds" << endl; + } + } + + + // Convert to greyscale if requested + if( (session->image)->getColourSpace() == sRGB && session->view->colourspace == GREYSCALE ){ + if( session->loglevel >= 4 ){ + *(session->logfile) << "JTL :: Converting to greyscale"; + function_timer.start(); + } + filter_greyscale( rawtile ); + if( session->loglevel >= 4 ){ + *(session->logfile) << " in " << function_timer.getTime() << " microseconds" << endl; + } + } + + + // Apply flip + if( session->view->flip != 0 ){ + Timer flip_timer; + if( session->loglevel >= 5 ){ + flip_timer.start(); + } + + filter_flip( rawtile, session->view->flip ); + + if( session->loglevel >= 5 ){ + *(session->logfile) << "JTL :: Flipping image "; + if( session->view->flip == 1 ) *(session->logfile) << "horizontally"; + else *(session->logfile) << "vertically"; + *(session->logfile) << " in " << flip_timer.getTime() << " microseconds" << endl; + } + } + + + // Apply rotation - can apply this safely after gamma and contrast adjustment + if( session->view->getRotation() != 0.0 ){ + float rotation = session->view->getRotation(); + if( session->loglevel >= 4 ){ + *(session->logfile) << "JTL :: Rotating image by " << rotation << " degrees"; + function_timer.start(); + } + filter_rotate( rawtile, rotation ); + if( session->loglevel >= 4 ){ + *(session->logfile) << " in " << function_timer.getTime() << " microseconds" << endl; + } + } + + + // Compress to JPEG + if( rawtile->compressionType == UNCOMPRESSED ){ + if( session->loglevel >= 4 ){ + *(session->logfile) << "JTL :: Compressing UNCOMPRESSED to JPEG"; + function_timer.start(); + } + len = session->jpeg->Compress( rawtile ); + if( session->loglevel >= 4 ){ + *(session->logfile) << " in " << function_timer.getTime() << " microseconds" << endl; + } + } + + +#ifndef DEBUG + char str[1024]; + + snprintf( str, 1024, + "Server: iipsrv/%s\r\n" + "Content-Type: image/jpeg\r\n" + "Content-Length: %d\r\n" + "Cache-Control: max-age=%d\r\n" + "Last-Modified: %s\r\n" + "\r\n", + VERSION, len, MAX_AGE, (session->image)->getTimestamp().c_str() ); + + session->out->printf( str ); +#endif + + + if( session->out->putStr( static_cast(rawtile->data), len ) != len ){ + if( session->loglevel >= 1 ){ + *(session->logfile) << "JTL :: Error writing jpeg tile" << endl; + } + } + + + if( session->out->flush() == -1 ) { + if( session->loglevel >= 1 ){ + *(session->logfile) << "JTL :: Error flushing jpeg tile" << endl; + } + } + + + // Inform our response object that we have sent something to the client + session->response->setImageSent(); + + // Total JTL response time + if( session->loglevel >= 2 ){ + *(session->logfile) << "JTL :: Total command time " << command_timer.getTime() << " microseconds" << endl; + } + +} diff --git a/iipsrv/src/KakaduImage.cc b/iipsrv/src/KakaduImage.cc new file mode 100644 index 0000000..d248e53 --- /dev/null +++ b/iipsrv/src/KakaduImage.cc @@ -0,0 +1,643 @@ +/* IIP Server: Kakadu JPEG2000 handler + + + Development supported by Moravian Library in Brno (Moravska zemska + knihovna v Brne, http://www.mzk.cz/) R&D grant MK00009494301 & Old + Maps Online (http://www.oldmapsonline.org/) from the Ministry of + Culture of the Czech Republic. + + + Copyright (C) 2009-2014 IIPImage. + Author: Ruven Pillay + + 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 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + + +#include "KakaduImage.h" +#include +#include +#include + +// Required for get_nprocs_conf() on Linux +#ifdef NPROCS +#include +#endif + +// On Mac OS X, define our own get_nprocs_conf() +#if defined (__APPLE__) || defined(__FreeBSD__) +#include +#include +unsigned int get_nprocs_conf(){ + int numProcessors = 0; + size_t size = sizeof(numProcessors); + int returnCode = sysctlbyname("hw.ncpu", &numProcessors, &size, NULL, 0); + if( returnCode != 0 ) return 1; + else return (unsigned int)numProcessors; +} +#define NPROCS +#endif + + +#include "Timer.h" +//#define DEBUG 1 + + +using namespace std; + + +#ifdef DEBUG +extern std::ofstream logfile; +#endif + + +void KakaduImage::openImage() throw (file_error) +{ + string filename = getFileName( currentX, currentY ); + + // Update our timestamp + updateTimestamp( filename ); + + // Set our error handlers + kdu_customize_warnings(&pretty_cout); + kdu_customize_errors(&pretty_cerr); + +#ifdef DEBUG + Timer timer; + timer.start(); +#endif + + // Open the JPX or JP2 file + try{ + src.open( filename.c_str(), true ); + if( jpx_input.open( &src, false ) != 1 ) throw 1; + } + catch (...){ + throw file_error( "Kakadu :: Unable to open '"+filename+"'"); // Rethrow the exception + } + + // Get our JPX codestream + jpx_stream = jpx_input.access_codestream(0); + if( !jpx_stream.exists() ) throw file_error( "Kakadu :: No codestream in file '"+filename+"'"); // Throw exception + + // Open the underlying JPEG2000 codestream + input = NULL; + input = jpx_stream.open_stream(); + + // Create codestream + codestream.create(input); + if( !codestream.exists() ) throw file_error( "Kakadu :: Unable to create codestream for '"+filename+"'"); // Throw exception + + // Set up the cache size and allow restarting + //codestream.augment_cache_threshold(1024); + codestream.set_fast(); + codestream.set_persistent(); + // codestream.enable_restart(); + + // Load our metadata if not already loaded + if( bpc == 0 ) loadImageInfo( currentX, currentY ); + +#ifdef DEBUG + logfile << "Kakadu :: openImage() :: " << timer.getTime() << " microseconds" << endl; +#endif + +} + + +void KakaduImage::loadImageInfo( int seq, int ang ) throw(file_error) +{ + jp2_channels j2k_channels; + jp2_palette j2k_palette; + jp2_resolution j2k_resolution; + jp2_colour j2k_colour; + kdu_coords layer_size; + + jpx_layer_source jpx_layer = jpx_input.access_layer(0); + + j2k_channels = jpx_layer.access_channels(); + j2k_resolution = jpx_layer.access_resolution(); + j2k_colour = jpx_layer.access_colour(0); + layer_size = jpx_layer.get_layer_size(); + + int cmp, plt, stream_id; + j2k_channels.get_colour_mapping(0,cmp,plt,stream_id); + j2k_palette = jpx_stream.access_palette(); + + image_widths.push_back(layer_size.x); + image_heights.push_back(layer_size.y); + channels = codestream.get_num_components(); + numResolutions = codestream.get_min_dwt_levels(); + bpc = codestream.get_bit_depth(0,true); + + unsigned int w = layer_size.x; + unsigned int h = layer_size.y; + +#ifdef DEBUG + logfile << "Kakadu :: DWT Levels: " << numResolutions << endl; + logfile << "Kakadu :: Resolution : " << w << "x" << h << endl; +#endif + + // Loop through each resolution and calculate the image dimensions - + // We calculate ourselves rather than relying on get_dims() to force a similar + // behaviour to TIFF with resolutions at floor(x/2) rather than Kakadu's default ceil(x/2) + for( unsigned int c=1; ctile_width) || (h>tile_height) ){ + n++; + w = floor( w/2.0 ); + h = floor( h/2.0 ); + if( n > numResolutions ){ + image_widths.push_back(w); + image_heights.push_back(h); + } + } + + if( n > numResolutions ){ +#ifdef DEBUG + logfile << "Kakadu :: Warning! Insufficient resolution levels in JPEG2000 stream. Will generate " << n-numResolutions << " extra levels dynamically -" << endl + << "Kakadu :: However, you are advised to regenerate the file with at least " << n << " levels" << endl; +#endif + } + + if( n > numResolutions ) virtual_levels = n-numResolutions-1; + numResolutions = n; + + + // Set our colour space - we let Kakadu automatically handle CIELAB->sRGB conversion for the time being + if( channels == 1 ) colourspace = GREYSCALE; + else{ + jp2_colour_space cs = j2k_colour.get_space(); + if( cs == JP2_sRGB_SPACE || cs == JP2_CIELab_SPACE ) colourspace = sRGB; + //else if ( cs == JP2_CIELab_SPACE ) colourspace = CIELAB; + } + + + // Get the number of quality layers - must first open a tile, however + kdu_tile kt = codestream.open_tile(kdu_coords(0,0),NULL); + quality_layers = codestream.get_max_tile_layers(); +#ifdef DEBUG + string cs; + switch( j2k_colour.get_space() ){ + case JP2_sRGB_SPACE: + cs = "JP2_sRGB_SPACE"; + break; + case JP2_sLUM_SPACE: + cs = "JP2_sLUM_SPACE"; + break; + case JP2_CIELab_SPACE: + cs = "JP2_CIELab_SPACE"; + break; + default: + cs = j2k_colour.get_space(); + break; + } + logfile << "Kakadu :: " << bpc << " bit data" << endl + << "Kakadu :: " << channels << " channels" << endl + << "Kakadu :: colour space: " << cs << endl + << "Kakadu :: " << quality_layers << " quality layers detected" << endl; +#endif + kt.close(); + + // For bilevel images, force channels to 1 as we sometimes come across such images which claim 3 channels + if( bpc == 1 ) channels = 1; + + // Get the max and min values for our data type + //double sminvalue[4], smaxvalue[4]; + for( unsigned int i=0; i 8 && bpc <= 16 ) max.push_back( 65535.0 ); + else max.push_back( 255.0 ); + } + + isSet = true; +} + + +// Close our image descriptors +void KakaduImage::closeImage() +{ +#ifdef DEBUG + Timer timer; + timer.start(); +#endif + + // Close our codestream - need to make sure it exists or it'll crash + if( codestream.exists() ) codestream.destroy(); + + // Close our JP2 family and JPX files + src.close(); + jpx_input.close(); + +#ifdef DEBUG + logfile << "Kakadu :: closeImage() :: " << timer.getTime() << " microseconds" << endl; +#endif +} + + +// Get an invidual tile +RawTilePtr KakaduImage::getTile( int seq, int ang, unsigned int res, int layers, unsigned int tile ) throw (file_error) +{ + + // Scale up our output bit depth to the nearest factor of 8 + unsigned obpc = bpc; + if( bpc <= 16 && bpc > 8 ) obpc = 16; + else if( bpc <= 8 ) obpc = 8; + +#ifdef DEBUG + Timer timer; + timer.start(); +#endif + + if( res >= numResolutions ){ + ostringstream tile_no; + tile_no << "Kakadu :: Asked for non-existant resolution: " << res; + throw file_error( tile_no.str() ); + } + + int vipsres = ( numResolutions - 1 ) - res; + + unsigned int tw = tile_width; + unsigned int th = tile_height; + + + // Get the width and height for last row and column tiles + unsigned int rem_x = image_widths[vipsres] % tile_width; + unsigned int rem_y = image_heights[vipsres] % tile_height; + + + // Calculate the number of tiles in each direction + unsigned int ntlx = (image_widths[vipsres] / tw) + (rem_x == 0 ? 0 : 1); + unsigned int ntly = (image_heights[vipsres] / th) + (rem_y == 0 ? 0 : 1); + + if( tile >= ntlx*ntly ){ + ostringstream tile_no; + tile_no << "Kakadu :: Asked for non-existant tile: " << tile; + throw file_error( tile_no.str() ); + } + + // Alter the tile size if it's in the last column + if( ( tile % ntlx == ntlx - 1 ) && ( rem_x != 0 ) ) { + tw = rem_x; + } + + // Alter the tile size if it's in the bottom row + if( ( tile / ntlx == ntly - 1 ) && rem_y != 0 ) { + th = rem_y; + } + + + // Calculate the pixel offsets for this tile + int xoffset = (tile % ntlx) * tile_width; + int yoffset = (unsigned int) floor((double)(tile/ntlx)) * tile_height; + +#ifdef DEBUG + logfile << "Kakadu :: Tile size: " << tw << "x" << th << "@" << channels << endl; +#endif + + + // Create our Rawtile object and initialize with data + RawTilePtr rawtile( tile, res, seq, ang, tw, th, channels, obpc ); + + + // Create our raw tile buffer and initialize some values + if( obpc == 16 ) rawtile->data = new unsigned short[tw*th*channels]; + else if( obpc == 8 ) rawtile->data = new unsigned char[tw*th*channels]; + else throw file_error( "Kakadu :: Unsupported number of bits" ); + + rawtile->dataLength = tw*th*channels*obpc/8; + rawtile->filename = getImagePath(); + rawtile->timestamp = timestamp; + + // Process the tile + process( res, layers, xoffset, yoffset, tw, th, rawtile->data ); + + +#ifdef DEBUG + logfile << "Kakadu :: bytes parsed: " << codestream.get_total_bytes(true) << endl; + logfile << "Kakadu :: getTile() :: " << timer.getTime() << " microseconds" << endl; +#endif + + return rawtile; + +} + + +// Get an entire region and not just a tile +RawTilePtr KakaduImage::getRegion( int seq, int ang, unsigned int res, int layers, int x, int y, unsigned int w, unsigned int h ) throw (file_error) +{ + // Scale up our output bit depth to the nearest factor of 8 + unsigned int obpc = bpc; + if( bpc <= 16 && bpc > 8 ) obpc = 16; + else if( bpc <= 8 ) obpc = 8; + +#ifdef DEBUG + Timer timer; + timer.start(); +#endif + + RawTilePtr rawtile( 0, res, seq, ang, w, h, channels, obpc ); + + if( obpc == 16 ) rawtile->data = new unsigned short[w*h*channels]; + else if( obpc == 8 ) rawtile->data = new unsigned char[w*h*channels]; + else throw file_error( "Kakadu :: Unsupported number of bits" ); + + rawtile->dataLength = w*h*channels*obpc/8; + rawtile->filename = getImagePath(); + rawtile->timestamp = timestamp; + + process( res, layers, x, y, w, h, rawtile->data ); + +#ifdef DEBUG + logfile << "Kakadu :: getRegion() :: " << timer.getTime() << " microseconds" << endl; +#endif + + return rawtile; + +} + + +// Main processing function +void KakaduImage::process( unsigned int res, int layers, int xoffset, int yoffset, unsigned int tw, unsigned int th, void *d ) throw (file_error) +{ + // Scale up our output bit depth to the nearest factor of 8 + unsigned int obpc = bpc; + if( bpc <= 16 && bpc > 8 ) obpc = 16; + else if( bpc <= 8 ) obpc = 8; + + int vipsres = ( numResolutions - 1 ) - res; + + // Handle virtual resolutions + if( res < virtual_levels ){ + unsigned int factor = pow( 2, virtual_levels-res ); + xoffset *= factor; + yoffset *= factor; + tw *= factor; + th *= factor; + vipsres = numResolutions - 1 - virtual_levels; +#ifdef DEBUG + logfile << "Kakadu :: using smallest existing resolution " << virtual_levels << endl; +#endif + } + + // Set the number of layers to half of the number of detected layers if we have not set the + // layers parameter manually. If layers is set to less than 0, use all layers. + if( layers < 0 ) layers = quality_layers; + else if( layers == 0 ) layers = ceil( quality_layers/2.0 ); + + // Also make sure we have at least 1 layer + if( layers < 1 ) layers = 1; + + + // Set up the bounding box for our tile + kdu_dims image_dims, canvas_dims; + canvas_dims.pos = kdu_coords( xoffset, yoffset ); + canvas_dims.size = kdu_coords( tw, th ); + + // Check our codestream status - throw exception for malformed codestreams + if( !codestream.exists() ) throw file_error( "Kakadu :: Malformed JPEG2000 - unable to access codestream"); + + // Apply our resolution restrictions to calculate the rendering zone on the highest resolution + // canvas + codestream.apply_input_restrictions( 0,0,vipsres,layers,&canvas_dims,KDU_WANT_OUTPUT_COMPONENTS ); + codestream.map_region( 0, canvas_dims, image_dims, true ); + + + // Create some worker threads +#ifdef NPROCS + int num_threads = get_nprocs_conf(); +#else + int num_threads = 0; +#endif + + + kdu_thread_env env, *env_ref = NULL; + if( num_threads > 0 ){ + env.create(); + for (int nt=0; nt < num_threads; nt++){ + // Unable to create all the threads requested + if( !env.add_thread() ) num_threads = nt; + } + env_ref = &env; + } + + + +#ifdef DEBUG + logfile << "Kakadu :: decompressor init with " << num_threads << " threads" << endl; + logfile << "Kakadu :: decoding " << layers << " quality layers" << endl; +#endif + + + // Setup tile and stripe buffers + void *buffer = NULL; + void *stripe_buffer = NULL; + int *stripe_heights = NULL; + + try{ + + // Note that we set max channels rather than leave the default to strip off alpha channels + codestream.apply_input_restrictions( 0, channels, vipsres, layers, &image_dims, KDU_WANT_OUTPUT_COMPONENTS ); + + decompressor.start( codestream, false, true, env_ref, NULL ); + + stripe_heights = new int[channels]; + codestream.get_dims(0,comp_dims,true); + +#ifdef DEBUG + logfile << "Kakadu :: decompressor starting" << endl; + + logfile << "Kakadu :: requested region on high resolution canvas: position: " + << image_dims.pos.x << "x" << image_dims.pos.y + << ". size: " << image_dims.size.x << "x" << image_dims.size.y << endl; + + logfile << "Kakadu :: mapped resolution region size: " << comp_dims.size.x << "x" << comp_dims.size.y << endl; + logfile << "Kakadu :: About to pull stripes" << endl; +#endif + + + int index = 0; + bool continues = true; + + // Get our stripe heights so that we can allocate our stripe buffer + // Assume that first stripe height is largest + decompressor.get_recommended_stripe_heights( comp_dims.size.y, + 1024, stripe_heights, NULL ); + +#ifdef DEBUG + logfile << "Kakadu :: Allocating memory for stripe height " << stripe_heights[0] << endl; +#endif + + // Create our buffers + if( obpc == 16 ){ + stripe_buffer = new kdu_uint16[tw*stripe_heights[0]*channels]; + buffer = new unsigned short[tw*th*channels]; + } + else if( obpc == 8 ){ + stripe_buffer = new kdu_byte[tw*stripe_heights[0]*channels]; + buffer = new unsigned char[tw*th*channels]; + } + + + while( continues ){ + + decompressor.get_recommended_stripe_heights( comp_dims.size.y, + 1024, stripe_heights, NULL ); + + if( obpc == 16 ){ + // Set these to false to get unsigned 16 bit values + bool s[3] = {false,false,false}; + continues = decompressor.pull_stripe( (kdu_int16*) stripe_buffer, stripe_heights, NULL, NULL, NULL, NULL, s ); + } + else if( obpc == 8 ){ + continues = decompressor.pull_stripe( (kdu_byte*) stripe_buffer, stripe_heights, NULL, NULL, NULL ); + } + + +#ifdef DEBUG + logfile << "Kakadu :: stripe pulled" << endl; +#endif + + // Copy the data into the supplied buffer + void *b1 = NULL, *b2 = NULL; + if( obpc == 16 ){ + b1 = &( ((kdu_uint16*)stripe_buffer)[0] ); + b2 = &( ((unsigned short*)buffer)[index] ); + } + else if( obpc == 8 ){ + b1 = &( ((kdu_byte*)stripe_buffer)[0] ); + b2 = &( ((unsigned char*)buffer)[index] ); + if( bpc == 1 ){ + // Expand bilevel images to full 8 bit range + // - ideally we would do this in the Kakadu pull_stripe function, + // but the precisions parameter seems not to work as expected. + unsigned int k = tw * stripe_heights[0] * channels; + // Deal with rare 1 bit "sRGB space" first + if( colourspace == sRGB ){ + for( unsigned int n=0; n>2) ); + } + } + // The usual 1 channel 1 band case + else{ + for( unsigned int n=0; n> 8); + } + } + } + } + + memcpy( b2, b1, tw * stripe_heights[0] * channels * obpc/8 ); + + // Advance our output buffer pointer + index += tw * stripe_heights[0] * channels; + +#ifdef DEBUG + logfile << "Kakadu :: stripe complete with height " << stripe_heights[0] << endl; +#endif + + } + + + if( !decompressor.finish() ){ + throw file_error( "Kakadu :: Error indicated by finish()" ); + } + + + // Shrink virtual resolution tiles + if( res < virtual_levels ){ + +#ifdef DEBUG + logfile << "Kakadu :: resizing tile to virtual resolution" << endl; +#endif + + unsigned int n = 0; + unsigned int factor = pow( 2.0, virtual_levels-res ); + for( unsigned int j=0; j 8 ) delete[] (kdu_uint16*) buffer; + else if( bpc<=8 ) delete[] (kdu_byte*) buffer; + } + + +} diff --git a/iipsrv/src/KakaduImage.h b/iipsrv/src/KakaduImage.h new file mode 100644 index 0000000..19f98ce --- /dev/null +++ b/iipsrv/src/KakaduImage.h @@ -0,0 +1,210 @@ +// Kakadu JPEG2000 Image class Interface + +/* IIP Kakadu JPEG2000 Class + + + Development supported by Moravian Library in Brno (Moravska zemska + knihovna v Brne, http://www.mzk.cz/) R&D grant MK00009494301 & Old + Maps Online (http://www.oldmapsonline.org/) from the Ministry of + Culture of the Czech Republic. + + + Copyright (C) 2009-2014 IIPImage. + Author: Ruven Pillay + + 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 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + + +#ifndef _KAKADUIMAGE_H +#define _KAKADUIMAGE_H + + +#include "IIPImage.h" + +#include +#include +#include +#include + +#define TILESIZE 256 + +// Kakadu 7.5 uses namespaces +#if KDU_MAJOR_VERSION > 7 || (KDU_MAJOR_VERSION == 7 && KDU_MINOR_VERSION >= 5) +using namespace kdu_supp; // Also includes the `kdu_core' namespace +#endif + +extern std::ofstream logfile; + + +/// Wrapper class to handle error messages from Kakadu +class kdu_stream_message : public kdu_message { + private: // Data + std::ostream *stream; + std::string message; + + public: // Member classes + kdu_stream_message(std::ostream *stream) + { this->stream = stream; } + void put_text(const char *string) + { logfile << string; } + void flush(bool end_of_message=false){ + logfile << message; + if( end_of_message ) throw 1; + } +}; + + +//static kdu_stream_message cout_message(&std::cout); +//static kdu_stream_message cerr_message(&std::cerr); + +static kdu_stream_message cout_message(&logfile); +static kdu_stream_message cerr_message(&logfile); + +static kdu_message_formatter pretty_cout(&cout_message); +static kdu_message_formatter pretty_cerr(&cerr_message); + + + + + +/// Image class for Kakadu JPEG2000 Images: Inherits from IIPImage. Uses the Kakadu library. +class KakaduImage : public IIPImage { + + private: + + /// Kakadu codestream object + kdu_codestream codestream; + + /// Codestream source + kdu_compressed_source *input; + + /// JPX format object + jpx_source jpx_input; + + /// JP2 file format object + jp2_family_src src; + + /// JPX codestream source + jpx_codestream_source jpx_stream; + + /// Kakadu decompressor object + kdu_stripe_decompressor decompressor; + + /// Tile or Strip region + kdu_dims comp_dims; + + /// Main processing function + /** @param r resolution + @param l number of quality levels to decode + @param x x coordinate + @param y y coordinate + @param w width of region + @param h height of region + @param d buffer to fill + */ + void process( unsigned int r, int l, int x, int y, unsigned int w, unsigned int h, void* d ) throw (file_error); + + /// Convenience function to delete allocated buffers + /** @param b pointer to buffer + */ + void delete_buffer( void* b ); + + + public: + + /// Constructor + KakaduImage(): IIPImage(){ + tile_width = TILESIZE; tile_height = TILESIZE; + }; + + /// Constructor + /** @param path image path + */ + KakaduImage( const std::string& path ): IIPImage( path ){ + tile_width = TILESIZE; tile_height = TILESIZE; + }; + + /// Copy Constructor + /** @param image Kakadu object + */ + KakaduImage( const KakaduImage& image ): IIPImage( image ) {}; + + /// Constructor from IIPImage object + /** @param image IIPImage object + */ + KakaduImage( const IIPImage& image ): IIPImage( image ){ + tile_width = TILESIZE; tile_height = TILESIZE; + }; + + /// Assignment Operator + /** @param TPTImage object + */ + KakaduImage& operator = ( KakaduImage image ) { + if( this != &image ){ + closeImage(); + IIPImage::operator=(image); + } + return *this; + } + + + /// Destructor + ~KakaduImage() { closeImage(); }; + + /// Overloaded function for opening a TIFF image + void openImage() throw (file_error); + + + /// Overloaded function for loading TIFF image information + /** @param x horizontal sequence angle + @param y vertical sequence angle + */ + void loadImageInfo( int x, int y ) throw (file_error); + + /// Overloaded function for closing a JPEG2000 image + void closeImage(); + + /// Return whether this image type directly handles region decoding + bool regionDecoding(){ return true; }; + + /// Overloaded function for getting a particular tile + /** @param x horizontal sequence angle + @param y vertical sequence angle + @param r resolution + @param l number of quality layers to decode + @param t tile number + */ + virtual RawTilePtr getTile( int x, int y, unsigned int r, int l, unsigned int t ) throw (file_error); + + /// Overloaded function for returning a region for a given angle and resolution + /** Return a RawTile object: Overloaded by child class. + @param ha horizontal angle + @param va vertical angle + @param r resolution + @param l number of quality layers to decode + @param x x coordinate + @param y y coordinate + @param w width of region + @param h height of region + @param b buffer to fill + */ + virtual RawTilePtr getRegion( int ha, int va, unsigned int r, int l, int x, int y, unsigned int w, unsigned int h ) throw (file_error); + + +}; + + +#endif diff --git a/iipsrv/src/Main.cc b/iipsrv/src/Main.cc new file mode 100644 index 0000000..afe86fd --- /dev/null +++ b/iipsrv/src/Main.cc @@ -0,0 +1,764 @@ +/* + IIP FCGI server module - Main loop. + + Copyright (C) 2000-2014 Ruven Pillay + + 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 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +//#define DEBUG 1 +// specify -DDEBUG as CXXFLAGS is better. + + + +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "TPTImage.h" +#include "JPEGCompressor.h" +#include "Tokenizer.h" +#include "IIPResponse.h" +#include "View.h" +#include "Timer.h" +#include "TileManager.h" +#include "Task.h" +#include "Environment.h" +#include "Writer.h" + +#ifndef DEBUG + +#ifdef HAVE_MEMCACHED +#ifdef WIN32 +#include "../windows/MemcachedWindows.h" +#else +#include "Memcached.h" +#endif +#endif +#endif + +#ifdef ENABLE_DL +#include "DSOImage.h" +#endif + + +// If necessary, define missing setenv and unsetenv functions +#ifndef HAVE_SETENV +static void setenv(char *n, char *v, int x) { + char buf[256]; + snprintf(buf,sizeof(buf),"%s=%s",n,v); + putenv(buf); +} +static void unsetenv(char *env_name) { + extern char **environ; + char **cc; + int l; + l=strlen(env_name); + for (cc=environ;*cc!=NULL;cc++) { + if (strncmp(env_name,*cc,l)==0 && ((*cc)[l]=='='||(*cc)[l]=='\0')) break; + } for (; *cc != NULL; cc++) *cc=cc[1]; +} +#endif + + + + +using namespace std; + + + +/* We need to define some variables globally so that the signal handler + can have access to them +*/ +int loglevel; +ofstream logfile; +unsigned long IIPcount; +char *tz = NULL; + + + +/* Handle a signal - print out some stats and exit + */ +void IIPSignalHandler( int signal ) +{ + if( loglevel >= 1 ){ + + // Reset our time zone environment + if(tz) setenv("TZ", tz, 1); + else unsetenv("TZ"); + tzset(); + + time_t current_time = time( NULL ); + char *date = ctime( ¤t_time ); + + // No strsignal on Windows +#ifdef WIN32 + int sigstr = signal; +#else + char *sigstr = strsignal( signal ); +#endif + + logfile << endl << "Caught " << sigstr << " signal. " + << "Terminating after " << IIPcount << " accesses" << endl + << date + << "<----------------------------------->" << endl << endl; + logfile.close(); + } + + exit( 1 ); +} + + + + + +int main( int argc, char *argv[] ) +{ + + IIPcount = 0; + int i; + + + // Define ourselves a version + string version = string( VERSION ); + + + + /************************************************* + Initialise some variables from our environment + *************************************************/ + + + // Check for a verbosity env variable and open an appendable logfile + // if we want logging ie loglevel >= 0 + + loglevel = Environment::getVerbosity(); + + if( loglevel >= 1 ){ + + // Check for the requested log file path + string lf = Environment::getLogFile(); + + logfile.open( lf.c_str(), ios::app ); + // If we cannot open this, set the loglevel to 0 + if( !logfile ){ + loglevel = 0; + } + + // Put a header marker and credit in the file + else{ + + // Get current time + time_t current_time = time( NULL ); + char *date = ctime( ¤t_time ); + + logfile << "<----------------------------------->" << endl + << date << endl + << "IIPImage Server. Version " << version << endl + << "*** Ruven Pillay ***" << endl << endl + << "Verbosity level set to " << loglevel << endl; + } + + } + + + // Set our environment to UTC as all file modification times are GMT, + // but save our current state to allow us to reset before quitting + tz = getenv("TZ"); + setenv("TZ","",1); + tzset(); + + + + // Set up some FCGI items and make sure we are in FCGI mode + +#ifndef DEBUG + + FCGX_Request request; + int listen_socket = 0; + bool standalone = false; + + if( argv[1] && (string(argv[1]) == "--bind") ){ + string socket = argv[2]; + if( !socket.length() ){ + logfile << "No socket specified" << endl << endl; + exit(1); + } + listen_socket = FCGX_OpenSocket( socket.c_str(), 10 ); + if( listen_socket < 0 ){ + logfile << "Unable to open socket '" << socket << "'" << endl << endl; + exit(1); + } + standalone = true; + logfile << "Running in standalone mode on socket: " << socket << endl << endl; + } + + if( FCGX_InitRequest( &request, listen_socket, 0 ) ) return(1); + + // Check whether we are really in FCGI mode - only if we are not in standalone mode + if( FCGX_IsCGI() ){ + if( !standalone ){ + if( loglevel >= 1 ) logfile << "CGI-only mode detected" << endl << endl; + return( 1 ); + } + } + else{ + if( loglevel >= 1 ) logfile << "Running in FCGI mode" << endl << endl; + } + +#endif + + + // Set our maximum image cache size + int max_image_cache_size = Environment::getMaxImageCacheSize(); + float max_tile_cache_size = Environment::getMaxTileCacheSize(); + + + imageCacheMapType imageCache(max_image_cache_size); + + + // Get our image pattern variable + string filename_pattern = Environment::getFileNamePattern(); + + + // Get our default quality variable + int jpeg_quality = Environment::getJPEGQuality(); + + + // Get our max CVT size + int max_CVT = Environment::getMaxCVT(); + + + // Get the default number of quality layers to decode + int max_layers = Environment::getMaxLayers(); + + + // Get the filesystem prefix if any + string filesystem_prefix = Environment::getFileSystemPrefix(); + + + // Set up our watermark object + Watermark watermark( Environment::getWatermark(), + Environment::getWatermarkOpacity(), + Environment::getWatermarkProbability() ); + + + // Get the CORS setting + string cors = Environment::getCORS(); + + + // Get any Base URL setting + string base_url = Environment::getBaseURL(); + + + // Print out some information + if( loglevel >= 1 ){ + logfile << "Setting maximum image cache size to " << max_image_cache_size << endl; + logfile << "Setting maximum tile cache size to " << max_tile_cache_size << "MB" << endl; + logfile << "Setting filesystem prefix to '" << filesystem_prefix << "'" << endl; + logfile << "Setting default JPEG quality to " << jpeg_quality << endl; + logfile << "Setting maximum CVT size to " << max_CVT << endl; + logfile << "Setting 3D file sequence name pattern to '" << filename_pattern << "'" << endl; + if( !cors.empty() ) logfile << "Setting Cross Origin Resource Sharing to '" << cors << "'" << endl; + if( !base_url.empty() ) logfile << "Setting base URL to '" << base_url << "'" << endl; + if( max_layers != 0 ){ + logfile << "Setting max quality layers (for supported file formats) to "; + if( max_layers < 0 ) logfile << "all layers" << endl; + else logfile << max_layers << endl; + } +#ifdef HAVE_KAKADU + logfile << "Setting up JPEG2000 support via Kakadu SDK" << endl; +#endif + } + + + // Try to load our watermark + if( watermark.getImage().length() > 0 ){ + watermark.init(); + if( loglevel >= 1 ){ + if( watermark.isSet() ){ + logfile << "Loaded watermark image '" << watermark.getImage() + << "': setting probability to " << watermark.getProbability() + << " and opacity to " << watermark.getOpacity() << endl; + } + else{ + logfile << "Unable to load watermark image '" << watermark.getImage() << "'" << endl; + } + } + } + +#ifndef DEBUG +#ifdef HAVE_MEMCACHED + + // Get our list of memcached servers if we have any and the timeout + string memcached_servers = Environment::getMemcachedServers(); + unsigned int memcached_timeout = Environment::getMemcachedTimeout(); + + // Create our memcached object + Memcache memcached( memcached_servers, memcached_timeout ); + if( loglevel >= 1 ){ + if( memcached.connected() ){ + logfile << "Memcached support enabled. Connected to servers: '" << memcached_servers + << "' with timeout " << memcached_timeout << endl; + } + else logfile << "Unable to connect to Memcached servers: '" << memcached.error() << "'" << endl; + } + +#endif +#endif + + + // Add a new line + if( loglevel >= 1 ) logfile << endl; + + + /*********************************************************** + Check for loadable modules - only if enabled by configure + ***********************************************************/ + +#ifdef ENABLE_DL + + map moduleList; + string modulePath; + char* envpara = getenv( "DECODER_MODULES" ); + + if( envpara ){ + + modulePath = string( envpara ); + + // Try to open the module + + Tokenizer izer( modulePath, "," ); + + while( izer.hasMoreTokens() ){ + + try{ + string token = izer.nextToken(); + DSOImage module; + module.Load( token ); + string type = module.getImageType(); + if( loglevel >= 1 ){ + logfile << "Loading external module: " << module.getDescription() << endl; + } + moduleList[ type ] = token; + } + catch( const string& error ){ + if( loglevel >= 1 ) logfile << error << endl; + } + + } + + // Tell us what's happened + if( loglevel >= 1 ) logfile << moduleList.size() << " external modules loaded" << endl; + + } + +#endif + + + + /*********************************************************** + Set up a signal handler for USR1, TERM, HUP and INT signals + - to simplify things, they can all just shutdown the + server. We can rely on mod_fastcgi to restart us. + - SIGUSR1 and SIGHUP don't exist on Windows, though. + ***********************************************************/ + +#ifndef WIN32 + signal( SIGUSR1, IIPSignalHandler ); + signal( SIGHUP, IIPSignalHandler ); +#endif + + signal( SIGTERM, IIPSignalHandler ); + signal( SIGINT, IIPSignalHandler ); + + + + if( loglevel >= 1 ){ + logfile << endl << "Initialisation Complete." << endl + << "<----------------------------------->" + << endl << endl; + } + + + // Set up our request timers and seed our random number generator with the millisecond count from it + Timer request_timer; + srand( request_timer.getTime() ); + + // Create our tile cache + TileCache tileCache( max_tile_cache_size ); + Task* task = NULL; + + + + /**************** + Main FCGI loop + ****************/ + +#ifdef DEBUG + for (int ii = 0; ii < 1000; ++ii) { + + tileCache.clear(); + + FILE *f = fopen( "test.jpg", "w" ); + FileWriter writer( f ); + +#else + + while( FCGX_Accept_r( &request ) >= 0 ){ + + FCGIWriter writer( request.out ); + +#endif + + + // Time each request + if( loglevel >= 2 ) request_timer.start(); + + + // Declare our image pointer here outside of the try scope + // so that we can close the image on exceptions + Session session; // putting session object out here does the same thing. +// IIPImagePtr image; + JPEGCompressor jpeg( jpeg_quality ); + + + // View object for use with the CVT command etc + View view; + if( max_CVT != -1 ) view.setMaxSize( max_CVT ); + if( max_layers != 0 ) view.setMaxLayers( max_layers ); + + + + // Create an IIPResponse object - we use this for the OBJ requests. + // As the commands return images etc, they handle their own responses. + IIPResponse response; + response.setCORS( cors ); + + try{ + + // Get the query into a string +#ifdef DEBUG + const string request_string = argv[1]; +#else + const string request_string = FCGX_GetParam( "QUERY_STRING", request.envp ); +#endif + + // Check that we actually have a request string + if( request_string.length() == 0 ) { + throw string( "QUERY_STRING not set" ); + } + + if( loglevel >=2 ){ + logfile << "Full Request is " << request_string << endl; + } + + + + // Set up our session data object + //session.image = image; + session.response = &response; + session.view = &view; + session.jpeg = &jpeg; + session.loglevel = loglevel; + session.logfile = &logfile; + session.imageCache = &imageCache; + session.tileCache = &tileCache; + session.out = &writer; + session.watermark = &watermark; + session.headers.empty(); + + // Get certain HTTP headers, such as if_modified_since and the query_string +#ifndef DEBUG + + char* header = NULL; + if( (header = FCGX_GetParam("HTTP_IF_MODIFIED_SINCE", request.envp)) ){ + session.headers["HTTP_IF_MODIFIED_SINCE"] = string(header); + if( loglevel >= 2 ){ + logfile << "HTTP Header: If-Modified-Since: " << session.headers["HTTP_IF_MODIFIED_SINCE"] << endl; + } + } +#endif + session.headers["QUERY_STRING"] = request_string; + +#ifndef DEBUG + session.headers["SERVER_PROTOCOL"] = FCGX_GetParam("SERVER_PROTOCOL", request.envp); + session.headers["HTTP_HOST"] = FCGX_GetParam("HTTP_HOST", request.envp); + session.headers["REQUEST_URI"] = FCGX_GetParam("REQUEST_URI", request.envp); +#endif + session.headers["BASE_URL"] = base_url; + + +#ifndef DEBUG + +#ifdef HAVE_MEMCACHED + // Check whether this exists in memcached, but only if we haven't had an if_modified_since + // request, which should always be faster to send + if( !header ){ + char* memcached_response = NULL; + if( (memcached_response = memcached.retrieve( request_string )) ){ + writer.putStr( memcached_response, memcached.length() ); + writer.flush(); + free( memcached_response ); + throw( 100 ); + } + } +#endif +#endif + + // Parse up the command list + + list < pair > requests; + list < pair > :: const_iterator commands; + + Tokenizer izer( request_string, "&" ); + while( izer.hasMoreTokens() ){ + pair p; + string token = izer.nextToken(); + int n = token.find_first_of( "=" ); + p.first = token.substr( 0, n ); + p.second = token.substr( n+1, token.length() ); + if( p.first.length() && p.second.length() ) requests.push_back( p ); + } + + + i = 0; + for( commands = requests.begin(); commands != requests.end(); commands++ ){ + + string command = (*commands).first; + string argument = (*commands).second; + + if( loglevel >= 2 ){ + logfile << "[" << i+1 << "/" << requests.size() << "]: Command / Argument is " << command << " : " << argument << endl; + i++; + } + + task = Task::factory( command ); + if( task ) task->run( &session, argument ); + + if( !task ){ + if( loglevel >= 1 ) logfile << "Unsupported command: " << command << endl; + // Unsupported command error code is 2 2 + response.setError( "2 2", command ); + } + + + // Delete our task + if( task ){ + delete task; + task = NULL; + } + + } + + + + //////////////////////////////////////////////////////// + ////////// Send out our Errors if necessary //////////// + //////////////////////////////////////////////////////// + + /* Make sure something has actually been sent to the client + If no response has been sent by now, we must have a malformed command + */ + if( (!response.imageSent()) && (!response.isSet()) ){ + // Malformed command syntax error code is 2 1 + response.setError( "2 1", request_string ); + } + + + /* Once we have finished parsing all our OBJ and COMMAND requests + send out our response. + */ + if( response.isSet() ){ + if( loglevel >= 4 ){ + logfile << "---" << endl << + response.formatResponse() << + endl << "---" << endl; + } + if( writer.printf( response.formatResponse().c_str() ) == -1 ){ + if( loglevel >= 1 ) logfile << "Error sending IIPResponse" << endl; + } + } + + + //////////////////////////////////////////////////////// + ////////// Insert the result into Memcached /////////// + ////////// - Note that we never store errors /////////// + ////////// or 304 replies /////////// + //////////////////////////////////////////////////////// +#ifndef DEBUG + +#ifdef HAVE_MEMCACHED + if( memcached.connected() ){ + Timer memcached_timer; + memcached_timer.start(); + memcached.store( session.headers["QUERY_STRING"], writer.buffer, writer.sz ); + if( loglevel >= 3 ){ + logfile << "Memcached :: stored " << writer.sz << " bytes in " + << memcached_timer.getTime() << " microseconds" << endl; + } + } +#endif +#endif + + + ////////////////////////////////////////////////////// + //////////////// End of try block //////////////////// + ////////////////////////////////////////////////////// + } + + /* Use this for sending various HTTP status codes + */ + catch( const int& code ){ + + string status; + + switch( code ){ + + case 304: + status = "Status: 304 Not Modified\r\nServer: iipsrv/" + version + "\r\n\r\n"; + writer.printf( status.c_str() ); + writer.flush(); + if( loglevel >= 2 ){ + logfile << "Sending HTTP 304 Not Modified" << endl; + } + break; + + case 100: + if( loglevel >= 2 ){ + logfile << "Memcached hit" << endl; + } + break; + + default: + if( loglevel >= 1 ){ + logfile << "Unsupported HTTP status code: " << code << endl << endl; + } + } + } + + /* Catch any errors + */ + catch( const string& error ){ + + if( loglevel >= 1 ){ + logfile << error << endl << endl; + } + + if( response.errorIsSet() ){ + if( loglevel >= 4 ){ + logfile << "---" << endl << + response.formatResponse() << + endl << "---" << endl; + } + if( writer.printf( response.formatResponse().c_str() ) == -1 ){ + if( loglevel >= 1 ) logfile << "Error sending IIPResponse" << endl; + } + } + else{ + /* Display our advertising banner ;-) + */ + writer.printf( response.getAdvert( version ).c_str() ); + } + + } + + // Image file errors + catch( const file_error& error ){ + string status = "Status: 404 Not Found\r\nServer: iipsrv/" + version + "\r\n\r\n" + error.what(); + writer.printf( status.c_str() ); + writer.flush(); + if( loglevel >= 2 ){ + logfile << "Sending HTTP 404 Not Found" << endl; + } + } + + // Parameter errors + catch( const invalid_argument& error ){ + string status = "Status: 400 Bad Request\r\nServer: iipsrv/" + version + "\r\n\r\n" + error.what(); + writer.printf( status.c_str() ); + writer.flush(); + if( loglevel >= 2 ){ + logfile << "Sending HTTP 400 Bad Request" << endl; + } + } + + /* Default catch + */ + catch( ... ){ + + if( loglevel >= 1 ){ + logfile << "Error: Default Catch: " << endl << endl; + } + + /* Display our advertising banner ;-) + */ + writer.printf( response.getAdvert( version ).c_str() ); + + } + + + /* Do some cleaning up etc. here after all the potential exceptions + have been handled + */ + if( task ){ + delete task; + task = NULL; + } + //delete image; // TODO: don't delete this. delete via imageCache cleanup. + //image = NULL; + IIPcount ++; + +#ifdef DEBUG + fclose( f ); +#endif + + + + // How long did this request take? + if( loglevel >= 2 ){ + logfile << "Total Request Time: " << request_timer.getTime() << " microseconds" << endl; + } + + + if( loglevel >= 2 ){ + logfile << "image cache size is " << imageCache.getNumElements() << endl + << "Server count is " << IIPcount << endl << endl; + + } + + + + ///////// End of FCGI_ACCEPT while loop or for loop in debug mode ////////// + } + + + // cleanup. + // ImageCache should clean up automatically. + + if( loglevel >= 1 ){ + logfile << endl << "Terminating after " << IIPcount << " iterations" << endl; + logfile.close(); + } + + return( 0 ); + +} diff --git a/iipsrv/src/Makefile.am b/iipsrv/src/Makefile.am new file mode 100644 index 0000000..6169e88 --- /dev/null +++ b/iipsrv/src/Makefile.am @@ -0,0 +1,66 @@ +## Process this file with automake to produce Makefile.in + +noinst_PROGRAMS = iipsrv.fcgi + + +INCLUDES = @INCLUDES@ @LIBFCGI_INCLUDES@ @JPEG_INCLUDES@ @TIFF_INCLUDES@ +LIBS = @LIBS@ @LIBFCGI_LIBS@ @DL_LIBS@ @JPEG_LIBS@ @TIFF_LIBS@ -lm -lopenslide -lopenjp2 +AM_LDFLAGS = @LIBFCGI_LDFLAGS@ +AM_CPPFLAGS = -I/usr/local/include/openslide + +iipsrv_fcgi_LDADD = Main.o + +if ENABLE_KAKADU +iipsrv_fcgi_LDADD += KakaduImage.o +endif + +if ENABLE_PNG +#iipsrv_fcgi_LDADD += PNGCompressor.o PTL.o +endif + +if ENABLE_MODULES +iipsrv_fcgi_LDADD += DSOImage.o +endif + +EXTRA_iipsrv_fcgi_SOURCES = DSOImage.h DSOImage.cc KakaduImage.h KakaduImage.cc PNGCompressor.h PNGCompressor.cc PTL.cc Main.cc + +iipsrv_fcgi_SOURCES = \ + IIPImage.h \ + IIPImage.cc \ + TPTImage.h \ + TPTImage.cc \ + OpenSlideImage.h \ + OpenSlideImage.cc \ + JPEGCompressor.h \ + JPEGCompressor.cc \ + RawTile.h \ + Timer.h \ + Cache.h \ + TileManager.h \ + TileManager.cc \ + Tokenizer.h \ + IIPResponse.h \ + IIPResponse.cc \ + View.h \ + View.cc \ + Transforms.h \ + Transforms.cc \ + Environment.h \ + URL.h \ + Writer.h \ + Task.h \ + Task.cc \ + OBJ.cc \ + FIF.cc \ + JTL.cc \ + TIL.cc \ + ICC.cc \ + CVT.cc \ + Zoomify.cc \ + DeepZoom.cc \ + SPECTRA.cc \ + PFL.cc \ + IIIF.cc \ + Watermark.h \ + Watermark.cc \ + Memcached.h diff --git a/iipsrv/src/Memcached.h b/iipsrv/src/Memcached.h new file mode 100644 index 0000000..5d67fa7 --- /dev/null +++ b/iipsrv/src/Memcached.h @@ -0,0 +1,148 @@ +// Simple Wrapper to libMemcached + +/* IIP Image Server + + Copyright (C) 2010-2013 Ruven Pillay. + + 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 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + + + +#ifndef _MEMCACHED_H +#define _MEMCACHED_H + +#include +#include + + + +/// Cache to store raw tile data + +class Memcache { + + + private: + + /// Memcached structure + memcached_st *_memc; + + /// Memcached return value + memcached_return_t _rc; + + /// Memcached servers + memcached_server_st *_servers; + + /// Cache expiry set to 1 hour + time_t _timeout; + + /// Length of data returned + size_t _length; + + /// Flag whether we are connected + bool _connected; + + + public: + + /// Constructor + /** @param servernames list of memcached servers + @param timeout memcached timeout - defaults to 1 hour (3600 seconds) + */ + Memcache( const std::string& servernames = "localhost", unsigned int timeout = 3600 ) { + + // Set our timeout + _timeout = timeout; + + // Create our memcached object + _memc = memcached_create(NULL); + + // Create a list of servers + _servers = memcached_servers_parse( servernames.c_str() ); + + // Try to set some memcached behaviour settings for performance. For example, + // using the binary protocol, non-blocking IO, and no reply for add commands + _rc = memcached_behavior_set( _memc, MEMCACHED_BEHAVIOR_BINARY_PROTOCOL, 1 ); + _rc = memcached_behavior_set( _memc, MEMCACHED_BEHAVIOR_NO_BLOCK, 1 ); + _rc = memcached_behavior_set( _memc, MEMCACHED_BEHAVIOR_TCP_NODELAY, 1 ); + _rc = memcached_behavior_set( _memc, MEMCACHED_BEHAVIOR_NOREPLY, 1 ); + + // Connect to the servers + _rc = memcached_server_push( _memc, _servers ); + if(_rc == MEMCACHED_SUCCESS ) _connected = true; + else _connected = false; + + if( memcached_server_count(_memc) > 0 ) _connected = true; + else _connected = false; + }; + + + /// Destructor + ~Memcache() { + // Disconnect from our servers and free our memcached structure + if( _servers ) memcached_server_free(_servers); + if( _memc ) memcached_free(_memc); + } + + + /// Insert data into our cache + /** @param key key used for cache + @param data pointer to the data to be stored + @param length length of data to be stored + */ + void store( const std::string& key, void* data, unsigned int length ){ + + if( !_connected ) return; + + std::string k = "iipsrv::" + key; + _rc = memcached_set( _memc, k.c_str(), k.length(), + (char*) data, length, + _timeout, 0 ); + } + + + /// Retrieve data from our cache + /** @param key key for cache data + @return pointer to data + */ + char* retrieve( const std::string& key ){ + + if( !_connected ) return NULL; + + uint32_t flags; + std::string k = "iipsrv::" + key; + return memcached_get( _memc, k.c_str(), k.length(), &_length, &flags, &_rc ); + } + + + /// Get error string + const char* error(){ + return memcached_strerror( _memc, _rc ); + }; + + + /// Return the number of bytes in the result + unsigned int length(){ return _length; }; + + + /// Tell us whether we are connected to any memcached servers + bool connected(){ return _connected; }; + + +}; + + + +#endif diff --git a/iipsrv/src/OBJ.cc b/iipsrv/src/OBJ.cc new file mode 100644 index 0000000..399b2a8 --- /dev/null +++ b/iipsrv/src/OBJ.cc @@ -0,0 +1,298 @@ +/* + IIP OJB Command Handler Class Member Functions + + Copyright (C) 2006-2014 Ruven Pillay. + + 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 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + + +#include "Task.h" +#include +#include + + +using namespace std; + + + +void OBJ::run( Session* s, const std::string& a ) +{ + + argument = a; + // Convert to lower case the argument supplied to the OBJ command + transform( argument.begin(), argument.end(), argument.begin(), ::tolower ); + + session = s; + + // Log this + if( session->loglevel >= 3 ) *(session->logfile) << "OBJ :: " << argument << " to be handled" << endl; + + // Time this command + if( session->loglevel >= 2 ) command_timer.start(); + + + if( argument == "iip,1.0" ) iip(); + else if( argument == "basic-info" ){ + iip_server(); + max_size(); + resolution_number(); + colorspace( "*,*" ); + } + else if( argument == "iip-server" ) iip_server(); + // IIP optional commands + else if( argument == "iip-opt-comm" ) session->response->addResponse( "IIP-opt-comm:CVT CNT QLT JTL JTLS WID HEI RGN MINMAX SHD CMP INV CTW" ); + // IIP optional objects + else if( argument == "iip-opt-obj" ) session->response->addResponse( "IIP-opt-obj:Horizontal-views Vertical-views Tile-size Bits-per-channel Min-Max-sample-values" ); + // Resolution-number + else if( argument == "resolution-number" ) resolution_number(); + // Max-size + else if( argument == "max-size" ) max_size(); + // Tile-size + else if( argument == "tile-size" ) tile_size(); + // Bits per pixel + else if( argument == "bits-per-channel" ) bits_per_channel(); + // Vertical-views + else if( argument == "vertical-views" ) vertical_views(); + // Horizontal-views + else if( argument == "horizontal-views" ) horizontal_views(); + // Minimum and maximum provided by TIFF tags + else if( argument == "min-max-sample-values" ) min_max_values(); + + // Colorspace + /* The request can have a suffix, which we don't need, so do a + like scan + */ + else if( argument.find( "colorspace" ) != string::npos ){ + colorspace( "*,*" ); + } + + // Image Metadata + else if( argument == "summary-info" ){ + + metadata( "copyright" ); + metadata( "subject" ); + metadata( "author" ); + metadata( "create-dtm" ); + metadata( "app-name" ); + } + + else if( argument == "copyright" || argument == "title" || + argument == "subject" || argument == "author" || + argument == "keywords" || argument == "comment" || + argument == "last-author" || argument == "rev-number" || + argument == "edit-time" || argument == "last-printed" || + argument == "create-dtm" || argument == "last-save-dtm" || + argument == "app-name" ){ + + metadata( argument ); + } + + + // None of the above! + else{ + + if( session->loglevel >= 1 ){ + *(session->logfile) << "OBJ :: Unsupported argument: " << argument << " received" << endl; + } + + // Unsupported object error code is 3 2 + session->response->setError( "3 2", argument ); + } + + + if( session->loglevel >= 2 ){ + *(session->logfile) << "OBJ :: Total command time " << command_timer.getTime() << " microseconds" << endl; + } + + +} + + + +void OBJ::iip(){ + session->response->setProtocol( "IIP:1.0" ); +} + + +void OBJ::iip_server(){ + // The binary capability code is 1000001 == 65 in integer + // ie can do CVT jpeg and JTL, but no transforms + session->response->addResponse( "IIP-server:3.65" ); +} + + +void OBJ::max_size(){ + checkImage(); + int x = (session->image)->getImageWidth(); + int y = (session->image)->getImageHeight(); + + // For 90 and 270 rotation swap width and height + if( (int)((session->view)->getRotation()) % 180 == 90 ){ + unsigned int tmp = x; + x = y; + y = tmp; + } + + if( session->loglevel >= 2 ){ + *(session->logfile) << "OBJ :: Max-size is " << x << " " << y << endl; + } + session->response->addResponse( "Max-size", x, y ); +} + + +void OBJ::resolution_number(){ + + checkImage(); + int no_res = (session->image)->getNumResolutions(); + if( session->loglevel >= 2 ){ + *(session->logfile) << "OBJ :: Resolution-number handler returning " << no_res << endl; + } + session->response->addResponse( "Resolution-number", no_res ); + +} + + +void OBJ::tile_size(){ + checkImage(); + + int x = (session->image)->getTileWidth(); + int y = (session->image)->getTileHeight(); + if( session->loglevel >= 2 ){ + *(session->logfile) << "OBJ :: Tile-size is " << x << " " << y << endl; + } + session->response->addResponse( "Tile-size", x, y ); +} + + +void OBJ::bits_per_channel(){ + + checkImage(); + int bpc = (session->image)->getNumBitsPerPixel(); + if( session->loglevel >= 2 ){ + *(session->logfile) << "OBJ :: Bits-per-channel handler returning " << bpc << endl; + } + session->response->addResponse( "Bits-per-channel", bpc ); + +} + + +void OBJ::vertical_views(){ + checkImage(); + list views = (session->image)->getVerticalViewsList(); + list :: const_iterator i; + string tmp = "Vertical-views:"; + char val[8]; + for( i = views.begin(); i != views.end(); i++ ){ + snprintf( val, 8, "%d ", *i ); + tmp += val; + } + // Chop off the final space + tmp.resize( tmp.length() - 1 ); + session->response->addResponse( tmp ); +} + + +void OBJ::horizontal_views(){ + checkImage(); + list views = (session->image)->getHorizontalViewsList(); + list :: const_iterator i; + string tmp = "Horizontal-views:"; + char val[8]; + for( i = views.begin(); i != views.end(); i++ ){ + snprintf( val, 8, "%d ", *i ); + tmp += val; + } + // Chop off the final space + tmp.resize( tmp.length() - 1 ); + session->response->addResponse( tmp ); +} + +void OBJ::min_max_values(){ + + checkImage(); + unsigned int n = (session->image)->getNumChannels(); + string tmp = "Min-Max-sample-values:"; + char val[24]; + float minimum, maximum; + for( unsigned int i=0; iimage)->getMinValue(i); + maximum = (session->image)->getMaxValue(i); + snprintf( val, 24, " %.9g ", minimum ); + tmp += val; + snprintf( val, 24, " %.9g ", maximum ); + tmp += val; + } + // Chop off the final space + tmp.resize( tmp.length() - 1 ); + session->response->addResponse( tmp ); + if( session->loglevel >= 2 ){ + *(session->logfile) << "OBJ :: Min-Max-sample-values handler returning " << tmp << endl; + } + +} + +void OBJ::colorspace( std::string arg ){ + + checkImage(); + + /* Assign the colourspace tag: 1 for greyscale, 3 for RGB and + a colourspace of 4 to LAB images + WARNING: LAB support is an extension and is not in the + IIP protocol standard (as of version 1.05) + */ + const char *planes = "3 0 1 2"; + int calibrated = 0; + int colourspace; + if( (session->image)->getColourSpace() == CIELAB ){ + colourspace = 4; + calibrated = 1; + } + else if( (session->image)->getColourSpace() == GREYSCALE ){ + colourspace = 1; + planes = "1 0"; + } + else colourspace = 3; + + int no_res = (session->image)->getNumResolutions(); + char tmp[32]; + snprintf( tmp, 32, "Colorspace,0-%d,0:%d 0 %d %s", no_res-1, + calibrated, colourspace, planes ); + + if( session->loglevel >= 2 ){ + *(session->logfile) << "OBJ :: Colourspace handler returning " << tmp << endl; + } + + session->response->addResponse( tmp ); +} + + +void OBJ::metadata( string field ){ + + checkImage(); + + string metadata = (session->image)->getMetadata( field ); + if( session->loglevel >= 3 ){ + *(session->logfile) << "OBJ :: " << field << " handler returning '" << metadata << "'" << endl; + } + + if( metadata.length() ){ + session->response->addResponse( field, metadata ); + } + + +} + + diff --git a/iipsrv/src/OpenSlideImage.cc b/iipsrv/src/OpenSlideImage.cc new file mode 100644 index 0000000..23fa017 --- /dev/null +++ b/iipsrv/src/OpenSlideImage.cc @@ -0,0 +1,935 @@ +#include "OpenSlideImage.h" +#include "Timer.h" +#include +#include +#include +#include + +#include +#include + +#include +//#define DEBUG_OSI 1 +using namespace std; + +extern std::ofstream logfile; + +/// Overloaded function for opening a TIFF image +void OpenSlideImage::openImage() throw (file_error) { + + string filename = getFileName(currentX, currentY); + + // get the file modification date/time. return false if not changed, return true if change compared to the stored info. + bool modified = updateTimestamp(filename); + + // if (modified && isSet) { +#ifdef DEBUG_OSI + Timer timer; + timer.start(); + + logfile << "OpenSlide :: openImage() :: start" << endl << flush; + +#endif + // close previous + closeImage(); + + osr = openslide_open(filename.c_str()); + + const char* error = openslide_get_error(osr); +#ifdef DEBUG_OSI + logfile << "OpenSlide :: openImage() get error :: completed " << filename << endl << flush; +#endif + + if (error) { + logfile << "ERROR: encountered error: " << error << " while opening " << filename << " with OpenSlide: " << endl << flush; + throw file_error(string("Error opening '" + filename + "' with OpenSlide, error " + error)); + } +#ifdef DEBUG_OSI + logfile << "OpenSlide :: openImage() :: " << timer.getTime() << " microseconds" << endl << flush; +#endif + + +#ifdef DEBUG_OSI + logfile << "OpenSlide :: openImage() :: completed " << filename << endl << flush; +#endif + if (osr == NULL) { + logfile << "ERROR: can't open " << filename << " with OpenSlide" << endl << flush; + throw file_error(string("Error opening '" + filename + "' with OpenSlide")); + } + + + + if (bpc == 0) { + loadImageInfo(currentX, currentY); + } + + + + isSet = true; + // } else { + //#ifdef DEBUG_OSI + // logfile << "OpenSlide :: openImage() :: not newer. reuse openslide object." << endl << flush; + //#endif + // } +} + +/// given an open OSI file, get information from the image. +void OpenSlideImage::loadImageInfo(int x, int y) throw (file_error) { + +#ifdef DEBUG_OSI + logfile << "OpenSlideImage :: loadImageInfo()" << endl; + + if (!osr) { + logfile << "loadImageInfo called before openImage()" << endl; + } +#endif + + int64_t w = 0, h = 0; + currentX = x; + currentY = y; + + const char* error; + +#ifdef DEBUG_OSI + const char* const* prop_names = openslide_get_property_names(osr); + error = openslide_get_error(osr); + if (error) { + logfile << "ERROR: encountered error: " << error << " while getting property names: " << error << endl; + } + + int i= 0; + + logfile << "Properties:" << endl; + while (prop_names[i]) { + logfile << "" << i << " : " << prop_names[i] << " = " << openslide_get_property_value(osr, prop_names[i]) << endl; + error = openslide_get_error(osr); + if (error) { + logfile << "ERROR: encountered error: " << error << " while getting property: " << error << endl; + } + + ++i; + } +#endif + + + const char* prop_val; + // // TODO: use actual tile width. default is 256 + // prop_val = openslide_get_property_value(osr, "openslide.level[0].tile-width"); + // error = openslide_get_error(osr); + // if (error) { + // logfile << "ERROR: encountered error: " << error << " while getting property: " << error << endl; + // } + // + // if (prop_val) tile_width = atoi(prop_val); + // else tile_width = 256; + tile_width = 256; // default to power of 2 to make downsample simpler. + + // prop_val = openslide_get_property_value(osr, "openslide.level[0].tile-height"); + // error = openslide_get_error(osr); + // if (error) { + // logfile << "ERROR: encountered error: " << error << " while getting property: " << error << endl; + // } + // if (prop_val) tile_height = atoi(prop_val); + // else tile_height = 256; + tile_height = 256; // default to power of 2 to make downsample simpler. + + + openslide_get_level0_dimensions(osr, &w, &h); + error = openslide_get_error(osr); + if (error) { + logfile << "ERROR: encountered error: " << error << " while getting level0 dim: " << error << endl; + } + +#ifdef DEBUG_OSI + logfile << "dimensions :" << w << " x " << h << endl; + //logfile << "comment : " << comment << endl; +#endif + + + + // TODO Openslide outputs 8 bit ABGR always. + channels = 3; + bpc = 8; + colourspace = sRGB; + + // const char* comment = openslide_get_comment(osr); + + // save the openslide dimensions. + std::vector openslide_widths, openslide_heights; + openslide_widths.clear(); + openslide_heights.clear(); + + + + int32_t openslide_levels = openslide_get_level_count(osr); + error = openslide_get_error(osr); + if (error) { + logfile << "ERROR: encountered error: " << error << " while getting level count: " << error << endl; + } + +#ifdef DEBUG_OSI + logfile << "number of levels = " << openslide_levels << endl; + double tempdownsample; +#endif + int64_t ww, hh; + for (int32_t i = 0; i < openslide_levels; i++) { + openslide_get_level_dimensions(osr, i, &ww, &hh); + error = openslide_get_error(osr); + if (error) { + logfile << "ERROR: encountered error: " << error << " while getting level dims: " << error << endl; + } + + openslide_widths.push_back(ww); + openslide_heights.push_back(hh); +#ifdef DEBUG_OSI + tempdownsample = openslide_get_level_downsample(osr, i); + error = openslide_get_error(osr); + if (error) { + logfile << "ERROR: encountered error: " << error << " while getting level downsamples: " << error << endl; + } + + logfile << "\tlevel " << i << "\t(w,h) = (" << ww << "," << hh << ")\tdownsample=" << tempdownsample << endl; +#endif + } + + openslide_widths.push_back(0); + openslide_heights.push_back(0); + + + image_widths.clear(); + image_heights.clear(); + + //======== virtual levels because getTile specifies res as powers of 2. + // precompute and store addition info about the tiles + lastTileXDim.clear(); + lastTileYDim.clear(); + numTilesX.clear(); + numTilesY.clear(); + + openslide_level_to_use.clear(); + openslide_downsample_in_level.clear(); + unsigned int os_level = 0; + unsigned int os_downsample_in_level = 1; + + // store the original size. + image_widths.push_back(w); + image_heights.push_back(h); + lastTileXDim.push_back(w % tile_width); + lastTileYDim.push_back(h % tile_height); + numTilesX.push_back((w + tile_width - 1) / tile_width); + numTilesY.push_back((h + tile_height - 1) / tile_height); + openslide_level_to_use.push_back(os_level); + openslide_downsample_in_level.push_back(os_downsample_in_level); + + + // what if there are openslide levels with dim smaller than this? + + // populate at 1/2 size steps + while ((w > tile_width) || (h > tile_height)) { + // need a level that's has image completely inside 1 tile. + // (stop with both w and h less than tile_w/h, previous iteration divided by 2. + + w >>= 1; // divide by 2 and floor. losing 1 pixel from higher res. + h >>= 1; + + // compare to next level width and height. if smaller, next level is better for supporting the w/h + // so switch level. + if (w <= openslide_widths[os_level+1] && h <= openslide_heights[os_level +1]) { + ++os_level; + os_downsample_in_level = 1; // just went to next smaller level, don't downsample internally yet. + } else { + os_downsample_in_level <<= 1; // next one, downsample internally by 2. + } + openslide_level_to_use.push_back(os_level); + openslide_downsample_in_level.push_back(os_downsample_in_level); + + image_widths.push_back(w); + image_heights.push_back(h); + lastTileXDim.push_back(w % tile_width); + lastTileYDim.push_back(h % tile_height); + numTilesX.push_back((w + tile_width - 1) / tile_width); + numTilesY.push_back((h + tile_height - 1) / tile_height); + +#ifdef DEBUG_OSI + logfile << "Create virtual layer : " << w << "x" << h << std::endl; +#endif + } + +#ifdef DEBUG_OSI + for (int t = 0; t < image_widths.size(); t++) { + logfile << "virtual level " << t << " (w,h)=(" << image_widths[t] << "," << image_heights[t] << "),"; + logfile << " (last_tw,last_th)=(" << lastTileXDim[t] << "," << lastTileYDim[t] << "),"; + logfile << " (ntx,nty)=(" << numTilesX[t] << "," << numTilesY[t] << "),"; + logfile << " os level=" << openslide_level_to_use[t] << " downsample from os_level=" << openslide_downsample_in_level[t] << endl; + } +#endif + + numResolutions = numTilesX.size(); + + // only support bpp of 8 (255 max), and 3 channels + min.assign(channels, 0.0f); + max.assign(channels, 255.0f); +} + +/// Overloaded function for closing a TIFF image +void OpenSlideImage::closeImage() { +#ifdef DEBUG_OSI + Timer timer; + timer.start(); +#endif + + if (osr != NULL) { + openslide_close(osr); + osr = NULL; + } + +#ifdef DEBUG_OSI + logfile << "OpenSlide :: closeImage() :: " << timer.getTime() << " microseconds" << endl; +#endif +} + + + + +// +//// TCP: support get region (internally, already doing it. +///// Overloaded function for returning a region for a given angle and resolution +///** Return a RawTile object: Overloaded by child class. +// \param ha horizontal angle +// \param va vertical angle +// \param res resolution +// \param layers number of quality layers to decode +// \param x x coordinate at resolution r +// \param y y coordinate at resolution r +// \param w width of region at resolution r +// \param h height of region at resolution r +// */ +//RawTile OpenSlideImage::getRegion( int ha, int va, unsigned int res, int layers, int x, int y, unsigned int w, unsigned int h ) { +// // ignore ha, va, layers. important things are r, x, y, w, and h. +// +// +//#ifdef DEBUG_OSI +// Timer timer; +// timer.start(); +//#endif +// +// if (res > (numResolutions-1)) { +// ostringstream tile_no; +// tile_no << "OpenSlide :: Asked for non-existant resolution: " << res; +// throw tile_no.str(); +// return 0; +// } +// +// // convert r to zoom +// +// // res is specified in opposite order from image levels: image level 0 has highest res, +// // image level nRes-1 has res of 0. +// uint32_t openslide_zoom = this->numResolutions - 1 - res; +// +//#ifdef DEBUG_OSI +// logfile << "OpenSlide :: getRegion() :: res=" << res << " pos " << x << "x" << y << " size " << w << "x" << h << " is_zoom= " << openslide_zoom << endl; +// +//#endif +// +// +// +// uint32_t lw, lh; +// int32_t lx, ly; +// +// unsigned int res_width = image_widths[openslide_zoom]; +// unsigned int res_height = image_heights[openslide_zoom]; +// +// // bound the x,y position +// lx = std::max(0, x); lx = std::min(lx, static_cast(res_width)); +// ly = std::max(0, y); ly = std::min(ly, static_cast(res_height)); +// +// // next bound the w and height. +// lw = std::min(w, res_width - lx); +// lh = std::min(h, res_height - ly); +// +// +// +// // convert x ,y, to the right coordinate system +// if (lw == 0 || lh == 0) { +// ostringstream tile_no; +// tile_no << "OpenSlideImage :: Asked for zero-sized region " << x << "x" << y << ", size " << w << "x" << h << ", res dim=" << res_width << "x" << res_height; +// throw tile_no.str(); +// } +// +// // Create our raw tile buffer and initialize some values +// RawTile region(0, res, ha, va, w, h, channels, bpp); +// region.dataLength = w * h * channels * sizeof(unsigned char); +// region.filename = getImagePath(); +// region.timestamp = timestamp; +// // new a block that is larger for openslide library to directly copy in. +// // then shuffle from BGRA to RGB. relying on delete [] to do the right thing. +// region.data = new unsigned char[w * h * 4 * sizeof(unsigned char)]; // TODO: avoid reallocation? +// region.memoryManaged = 1; // allocated data, so use this flag to indicate that it needs to be cleared on destruction +// //rawtile->padded = false; +//#ifdef DEBUG_OSI +// logfile << "Allocating tw * th * channels * sizeof(char) : " << w << " * " << h << " * " << channels << " * sizeof(char) " << endl << flush; +//#endif +// +// // call read +// read(openslide_zoom, w, h, x, y, region.data); +// +// +//#ifdef DEBUG_OSI +// logfile << "OpenSlide :: getRegion() :: " << timer.getTime() << " microseconds" << endl << flush; +// logfile << "REGION RENDERED" << std::endl; +//#endif +// +// return ( region ); +// +//} + + +/// Overloaded function for getting a particular tile +/** \param x horizontal sequence angle (for microscopy, ignored.) + \param y vertical sequence angle (for microscopy, ignored.) + \param r resolution - specified as -log_2(mag factor), where mag_factor ~= highest res width / target res width. 0 to numResolutions - 1. + \param l number of quality layers to decode - for jpeg2000 + \param t tile number (within the resolution level.) specified as a sequential number = y * width + x; + */ +RawTilePtr OpenSlideImage::getTile(int seq, int ang, unsigned int iipres, int layers, unsigned int tile) throw (file_error) { + +#ifdef DEBUG_OSI + Timer timer; + timer.start(); +#endif + + if (iipres > (numResolutions-1)) { + ostringstream tile_no; + tile_no << "OpenSlide :: Asked for non-existant resolution: " << iipres; + throw file_error(tile_no.str()); + return 0; + } + + // res is specified in opposite order from openslide virtual image levels: image level 0 has highest res, + // image level nRes-1 has res of 0. + uint32_t osi_level = numResolutions - 1 - iipres; + +#ifdef DEBUG_OSI + logfile << "OpenSlide :: getTile() :: res=" << iipres << " tile= " << tile << " is_zoom= " << osi_level << endl; + +#endif + + //======= get the dimensions in pixels and num tiles for the current resolution + + // int64_t layer_width = image_widths[openslide_zoom]; + // int64_t layer_height = image_heights[openslide_zoom]; + //openslide_get_layer_dimensions(osr, layers, &layer_width, &layer_height); + + + // Calculate the number of tiles in each direction + size_t ntlx = numTilesX[osi_level]; + size_t ntly = numTilesY[osi_level]; + + if (tile >= ntlx * ntly) { + ostringstream tile_no; + tile_no << "OpenSlideImage :: Asked for non-existant tile: " << tile; + throw file_error(tile_no.str()); + } + + // tile x. + size_t tx = tile % ntlx; + size_t ty = tile / ntlx; + + RawTilePtr ttt = getCachedTile(tx, ty, iipres); + +#ifdef DEBUG_OSI + logfile << "OpenSlide :: getTile() :: total " << timer.getTime() << " microseconds" << endl << flush; + logfile << "TILE RENDERED" << std::endl; +#endif + return ttt; // return cached instance. TileManager's job to copy it.. +} + +/** + * check if cache has tile. + * if yes, return it. + * if not, + * if a native layer, getNativeTile, + * else call halfsampleAndComposeTile + * @param res iipsrv's resolution id. openslide's level is inverted from this. + */ +RawTilePtr OpenSlideImage::getCachedTile(const size_t tilex, const size_t tiley, const uint32_t iipres) { + +#ifdef DEBUG_OSI + Timer timer; + timer.start(); +#endif + + assert(tileCache); + + // check if cache has tile + uint32_t osi_level = numResolutions - 1 - iipres; + uint32_t tid = tiley * numTilesX[osi_level] + tilex; + RawTilePtr ttt = tileCache->getObject(TileCache::getIndex(getImagePath(), iipres, tid, 0, 0, UNCOMPRESSED, 0)); + + // if cache has file, return it + if (ttt) { +#ifdef DEBUG_OSI + logfile << "OpenSlide :: getCachedTile() :: Cache Hit " << tilex << "x" << tiley << "@" << iipres << " osi tile bounds: " << numTilesX[osi_level] << "x" << numTilesY[osi_level] << " " << timer.getTime() << " microseconds" << endl << flush; +#endif + + return ttt; + } + // else caches does not have it. +#ifdef DEBUG_OSI + logfile << "OpenSlide :: getCachedTile() :: Cache Miss " << tilex << "x" << tiley << "@" << iipres << " osi tile bounds: " << numTilesX[osi_level] << "x" << numTilesY[osi_level] << " " << timer.getTime() << " microseconds" << endl << flush; +#endif + + // is this a native layer? + if (openslide_downsample_in_level[osi_level] == 1) { + // supported by native openslide layer + // tile manager will cache if needed + return getNativeTile(tilex, tiley, iipres); + + + } else { + // not supported by native openslide layer, so need to compose from next level up, + return halfsampleAndComposeTile(tilex, tiley, iipres); + + // tile manager will cache this one. + } + +} + + +/** + * read from file, color convert, store in cache, and return tile. + * + * @param res iipsrv's resolution id. openslide's level is inverted from this. + */ +RawTilePtr OpenSlideImage::getNativeTile(const size_t tilex, const size_t tiley, const uint32_t iipres) { + + +#ifdef DEBUG_OSI + Timer timer; + timer.start(); +#endif + + if (!osr) { + logfile << "openslide image not yet loaded " << endl; + } + + + // compute the parameters (i.e. x and y offsets, w/h, and bestlayer to use. + uint32_t osi_level = numResolutions - 1 - iipres; + + // find the next layer to downsample to desired zoom level z + // + uint32_t bestLayer = openslide_level_to_use[osi_level]; + + size_t ntlx = numTilesX[osi_level]; + size_t ntly = numTilesY[osi_level]; + + + + // compute the correct width and height + size_t tw = tile_width; + size_t th = tile_height; + + // Get the width and height for last row and column tiles + size_t rem_x = this->lastTileXDim[osi_level]; + size_t rem_y = this->lastTileYDim[osi_level]; + + // Alter the tile size if it's in the rightmost column + if ((tilex == ntlx - 1) && (rem_x != 0)) { + tw = rem_x; + } + // Alter the tile size if it's in the bottom row + if ((tiley == ntly - 1) && (rem_y != 0)) { + th = rem_y; + } + + + // create the RawTile object + RawTilePtr rt(new RawTile(tiley * ntlx + tilex, iipres, 0, 0, tw, th, channels, bpc)); + + // compute the size, etc + rt->dataLength = tw * th * channels * sizeof(unsigned char); + rt->filename = getImagePath(); + rt->timestamp = timestamp; + + // new a block that is larger for openslide library to directly copy in. + // then shuffle from BGRA to RGB. relying on delete [] to do the right thing. + rt->data = new unsigned char[tw * th * 4 * sizeof(unsigned char)]; + rt->memoryManaged = 1; // allocated data, so use this flag to indicate that it needs to be cleared on destruction + //rawtile->padded = false; +#ifdef DEBUG_OSI + logfile << "Allocating tw * th * channels * sizeof(char) : " << tw << " * " << th << " * " << 4 << " * sizeof(char) " << endl << flush; +#endif + + + // READ FROM file + + //======= next compute the x and y coordinates (top left corner) in level 0 coordinates + //======= expected by openslide_read_region. + size_t tx0 = (tilex * tile_width) << osi_level; // same as multiply by z power of 2 + size_t ty0 = (tiley * tile_height) << osi_level; + + openslide_read_region(osr, reinterpret_cast(rt->data), tx0, ty0, bestLayer, tw, th); + const char* error = openslide_get_error(osr); + if (error) { + logfile << "ERROR: encountered error: " << error << " while reading region exact at " << tx0 << "x" << ty0 << " dim " << tw << "x" << th << " with OpenSlide: " << error << endl; + } + +#ifdef DEBUG_OSI + logfile << "OpenSlide :: getNativeTile() :: read_region() :: " << tilex << "x" << tiley << "@" << iipres << " " << timer.getTime() << " microseconds" << endl << flush; +#endif + + if (!rt->data) throw string("FATAL : OpenSlideImage read_region => allocation memory ERROR"); + +#ifdef DEBUG_OSI + timer.start(); +#endif + + + // COLOR CONVERT in place BGRA->RGB conversion + this->bgra2rgb(reinterpret_cast(rt->data), tw, th); + +#ifdef DEBUG_OSI + logfile << "OpenSlide :: getNativeTile() :: bgra2rgb() :: " << timer.getTime() << " microseconds" << endl << flush; +#endif + + + // and return it. + return rt; +} + + +/** + * @detail return from the local cache a tile. + * The tile may be native (directly from file), + * previously downsampled and cached, + * downsampled from existing cached tile (and cached now for later use), or + * downsampled from native tile (from file. both native and downsampled tiles will be cached for later use) + * + * note that tilex and tiley can be found by multiplying by 2 raised to power of the difference in levels. + * 2 versions - direct and recursive. direct should have slightly lower latency. + + * This function + * automatically downsample a region in the missing zoom level z, if needed. + * Arguments are exactly as what would be given to openslide_read_region(). + * Note that z is not the openslide layer, but the desired zoom level, because + * the slide may not have all the layers that correspond to all the + * zoom levels. The number of layers is equal or less than the number of + * zoom levels in an equivalent zoomify format. + * This downsampling method simply does area averaging. If interpolation is desired, + * an image processing library could be used. + + * go to next level in size, get 4 tiles, downsample and compose. + * + * call 4x (getCachedTile at next res, downsample, compose), + * store in cache, and return tile. (causes recursion, stops at native layer or in cache.) + */ +RawTilePtr OpenSlideImage::halfsampleAndComposeTile(const size_t tilex, const size_t tiley, const uint32_t iipres) { + // not in cache and not a native tile, so create one from higher sampling. +#ifdef DEBUG_OSI + Timer timer; + timer.start(); +#endif + + // compute the parameters (i.e. x and y offsets, w/h, and bestlayer to use. + uint32_t osi_level = numResolutions - 1 - iipres; + + +#ifdef DEBUG_OSI + logfile << "OpenSlide :: halfsampleAndComposeTile() :: zoom=" << osi_level << " from " << (osi_level -1) << endl; +#endif + + + + size_t ntlx = numTilesX[osi_level]; + size_t ntly = numTilesY[osi_level]; + + // compute the correct width and height + size_t tw = tile_width; + size_t th = tile_height; + + // Get the width and height for last row and column tiles + size_t rem_x = this->lastTileXDim[osi_level]; + size_t rem_y = this->lastTileYDim[osi_level]; + + // Alter the tile size if it's in the rightmost column + if ((tilex == ntlx - 1) && (rem_x != 0)) { + tw = rem_x; + } + // Alter the tile size if it's in the bottom row + if ((tiley == ntly - 1) && (rem_y != 0)) { + th = rem_y; + } + + + + // allocate raw tile. + RawTilePtr rt(new RawTile(tiley * ntlx + tilex, iipres, 0, 0, tw, th, channels, bpc)); + + // compute the size, etc + rt->dataLength = tw * th * channels; + rt->filename = getImagePath(); + rt->timestamp = timestamp; + + // new a block that is larger for openslide library to directly copy in. + // then shuffle from BGRA to RGB. relying on delete [] to do the right thing. + rt->data = new unsigned char[rt->dataLength]; + rt->memoryManaged = 1; // allocated data, so use this flag to indicate that it needs to be cleared on destruction + //rawtile->padded = false; +#ifdef DEBUG_OSI + logfile << "Allocating tw * th * channels * sizeof(char) : " << tw << " * " << th << " * " << channels << " * sizeof(char) " << endl << flush; +#endif + + // new iipres - next res. recall that larger res corresponds to higher mag, with largest res being max resolution. + uint32_t tt_iipres = iipres + 1; + RawTilePtr tt; + // temp storage. + uint8_t *tt_data = new uint8_t[(tile_width >> 1) * (tile_height >> 1) * channels]; + size_t tt_out_w, tt_out_h; + + // uses 4 tiles to create new. + for (int j = 0; j < 2; ++j) { + + size_t tty = tiley * 2 + j; + + if (tty >= numTilesY[osi_level - 1]) break; // at edge, this may not be a 2x2 block. + + for (int i = 0; i < 2; ++i) { + // compute new tile x and y and iipres. + size_t ttx = tilex * 2 + i; + if (ttx >= numTilesX[osi_level - 1]) break; // at edge, this may not be a 2x2 block. + + +#ifdef DEBUG_OSI + logfile << "OpenSlide :: halfsampleAndComposeTile() :: call getCachedTile " << endl << flush; +#endif + + + // get the tile + tt = getCachedTile(ttx, tty, tt_iipres); + + if (tt) { + + // cache the next res tile + +#ifdef DEBUG_OSI + timer.start(); +#endif + + // cache it + tileCache->insert(tt); // copy is made? + +#ifdef DEBUG_OSI + logfile << "OpenSlide :: halfsampleAndComoseTile() :: cache insert res " << tt_iipres << " " << ttx << "x" << tty << " :: " << timer.getTime() << " microseconds" << endl << flush; +#endif + + + // downsample into a temp storage. + halfsample_3(reinterpret_cast(tt->data), tt->width, tt->height, + tt_data, tt_out_w, tt_out_h); + + // compose into raw tile. note that tile 0,0 in a 2x2 block always have size tw/2 x th/2 + compose(tt_data, tt_out_w, tt_out_h, (tile_width / 2) * i, (tile_height / 2) * j, + reinterpret_cast(rt->data), tw, th); + } +#ifdef DEBUG_OSI + logfile << "OpenSlide :: halfsampleAndComposeTile() :: called getCachedTile " << endl << flush; +#endif + } + + } + delete [] tt_data; +#ifdef DEBUG_OSI + logfile << "OpenSlide :: halfsampleAndComposeTile() :: downsample " << osi_level << " from " << (osi_level -1) << " :: " << timer.getTime() << " microseconds" << endl << flush; +#endif + + + // and return it. + return rt; + + +} + + + +// h is number of rows to process. w is number of columns to process. +void OpenSlideImage::bgra2rgb(uint8_t* data, const size_t w, const size_t h) { + // swap bytes in place. we can because we are going from 4 bytes to 3, and because we are using a register to bswap + // 0000111122223333 + // in: BGRABGRABGRA + // out: RGBRGBRGB + // 000111222333 + + + // this version relies on compiler to generate bswap code. + // bswap is only very slightly slower than SSSE3 and AVX2 code, and about 2x faster than naive single byte copies on core i5 ivy bridge. + uint8_t *out = data; + uint32_t* in = reinterpret_cast(data); + uint32_t* end = in + w*h; + + uint32_t t; + + // remaining + for (; in < end; ++in) { + *(reinterpret_cast(out)) = bgra2rgb_kernel(*in); + + out += channels; + } +} + +/** + * performs 1/2 size downsample on rgb 24bit images + * @details usingg the following property, + * (a + b) / 2 = ((a ^ b) >> 1) + (a & b) + * which does not cause overflow. + * + * mask with 0xFEFEFEFE to revent underflow during bitshift, allowing 4 compoents + * to be processed concurrently in same register without SSE instructions. + * + * output size is computed the same way as the virtual level dims - round down + * if not even. + * + * @param in + * @param in_w + * @param in_h + * @param out + * @param out_w + * @param out_h + * @param downSamplingFactor always power of 2. + */ +void OpenSlideImage::halfsample_3(const uint8_t* in, const size_t in_w, const size_t in_h, + uint8_t* out, size_t& out_w, size_t& out_h) { + + +#ifdef DEBUG_OSI + logfile << "OpenSlide :: halfsample_3() :: start :: in " << (void*)in << " out " << (void*)out << endl << flush; + logfile << " :: in wxh " << in_w << "x" << in_h << endl << flush; +#endif + + // do one 1/2 sample run + out_w = in_w >> 1; + out_h = in_h >> 1; + + if ((out_w == 0) || (out_h == 0)) { + logfile << "OpenSlide :: halfsample_3() :: ERROR: zero output width or height " << endl << flush; + return; + } + + if (!(in)) { + logfile << "OpenSlide :: halfsample_3() :: ERROR: null input " << endl << flush; + return; + } + + uint8_t const *row1, *row2; + uint8_t *dest = out; // if last recursion, put in out, else do it in place + +#ifdef DEBUG_OSI + logfile << "OpenSlide :: halfsample_3() :: top " << endl << flush; +#endif + + // walk through all pixels in output, except last. + size_t max_h = out_h - 1, + max_w = out_w; + size_t inRowStride = in_w * channels; + size_t inRowStride2 = 2 * inRowStride; + size_t inColStride2 = 2 * channels; + // skip last row, as the very last dest element may have overflow. + for (size_t j = 0; j < max_h; ++j) { + // move row pointers forward 2 rows at a time - in_w may not be multiple of 2. + row1 = in + j * inRowStride2; + row2 = row1 + inRowStride; + + for (size_t i = 0; i < max_w; ++i) { + *(reinterpret_cast(dest)) = halfsample_kernel_3(row1, row2); + // output is contiguous. + dest += channels ; + row1 += inColStride2; + row2 += inColStride2; + } + } + +#ifdef DEBUG_OSI + logfile << "OpenSlide :: halfsample_3() :: last row " << endl << flush; +#endif + + // for last row, skip the last element + row1 = in + max_h * inRowStride2; + row2 = row1 + inRowStride; + + --max_w; + for (size_t i = 0; i < max_w; ++i) { + *(reinterpret_cast(dest)) = halfsample_kernel_3(row1, row2); + dest += channels ; + row1 += inColStride2; + row2 += inColStride2; + } + +#ifdef DEBUG_OSI + logfile << "OpenSlide :: halfsample_3() :: last one " << endl << flush; +#endif + + // for last pixel, use memcpy to avoid writing out of bounds. + uint32_t v = halfsample_kernel_3(row1, row2); + memcpy(dest, reinterpret_cast(&v), channels); + + + + // at this point, in has been averaged and stored . + // since we stride forward 2 col and rows at a time, we don't need to worry about overwriting an unread pixel. +#ifdef DEBUG_OSI + logfile << "OpenSlide :: halfsample_3() :: done" << endl << flush; +#endif + +} + +// in is contiguous, out will be when done. +void OpenSlideImage::compose(const uint8_t *in, const size_t in_w, const size_t in_h, + const size_t& xoffset, const size_t& yoffset, + uint8_t* out, const size_t& out_w, const size_t& out_h) { + +#ifdef DEBUG_OSI + logfile << "OpenSlide :: compose() :: start " << endl << flush; +#endif + + if ((in_w == 0) || (in_h == 0)) { +#ifdef DEBUG_OSI + logfile << "OpenSlide :: compose() :: zero width or height " << endl << flush; +#endif + return; + } + if (!(in)) { +#ifdef DEBUG_OSI + logfile << "OpenSlide :: compose() :: nullptr input " << endl << flush; +#endif + return; + } + + if (out_h < yoffset + in_h) { + logfile << "COMPOSE ERROR: out_h, yoffset, in_h: " << out_h << "," << yoffset << "," << in_h << endl; + assert(out_h >= yoffset + in_h); + } + if (out_w < xoffset + in_w) { + logfile << "COMPOSE ERROR: out_w, xoffset, in_w: " << out_w << "," << xoffset << "," << in_w << endl; + assert(out_w >= xoffset + in_w); + } + + size_t dest_stride = out_w*channels; + size_t src_stride = in_w*channels; + + uint8_t *dest = out + yoffset * dest_stride + xoffset * channels; + uint8_t const *src = in; + + for (int k = 0; k < in_h; ++k) { + memcpy(dest, src, in_w * channels); + dest += dest_stride; + src += src_stride; + } + +#ifdef DEBUG_OSI + logfile << "OpenSlide :: compose() :: start " << endl << flush; +#endif + +} + + + diff --git a/iipsrv/src/OpenSlideImage.h b/iipsrv/src/OpenSlideImage.h new file mode 100644 index 0000000..85b8bae --- /dev/null +++ b/iipsrv/src/OpenSlideImage.h @@ -0,0 +1,206 @@ +/* + * File: OpenSlideImage.h + * Author: Tony Pan + * + * rewrite, loosely based on https://github.com/cytomine/iipsrv + * + * + */ + + +#ifndef OPENSLIDEIMAGE_H +#define OPENSLIDEIMAGE_H + +#include "IIPImage.h" +#include +#include +#include +#include +#include +#include +#include + +#include "Cache.h" // for local cache of raw tiles. + + +extern "C" { +#include "openslide.h" +#include "openslide-features.h" +} + + +#define OPENSLIDE_TILESIZE 256 +#define OPENSLIDE_TILE_CACHE_SIZE 32 + +/// Image class for OpenSlide supported Images: Inherits from IIPImage. Uses the OpenSlide library. + +class OpenSlideImage : public IIPImage { +private: + openslide_t* osr; //the openslide reader + /// Tile data buffer pointer + + TileCache *tileCache; + + //uint32_t *osr_buf; + // tdata_t tile_buf; + + std::vector numTilesX, numTilesY; + std::vector lastTileXDim, lastTileYDim; + std::vector openslide_level_to_use, openslide_downsample_in_level; + +// /// get a region from file - downsample_region. color convert +// void read(const uint32_t zoom, const uint32_t w, const uint32_t h, const uint64_t x, const uint64_t y, void* data); +// +// /// downsample - read from file region, downsample +// void downsample_region(uint32_t *buf, const uint64_t x, const uint64_t y, const int32_t z, const uint32_t w, const uint32_t h); + + /** + * @brief get cached tile. + * @detail return from the local cache a tile. + * The tile may be native (directly from file), + * previously cached, + * or downsampled (recursively called. + * note that tilex and tiley can be found by multiplying by 2 raised to power of the difference in levels. + * 2 versions - direct and recursive. direct should have slightly lower latency. + * + * @param tilex + * @param tiley + * @param res + * @return + */ + /// check if cache has tile. if yes, return it. if not, and is a native layer, getNativeTile, else call halfsampleAndComposeTile + RawTilePtr getCachedTile(const size_t tilex, const size_t tiley, const uint32_t iipres); + + /// read from file, color convert, store in cache, and return tile. + RawTilePtr getNativeTile(const size_t tilex, const size_t tiley, const uint32_t iipres); + + /// call 4x (getCachedTile at next res, downsample, compose), store in cache, and return tile. (causes recursion, stops at native layer or in cache.) + RawTilePtr halfsampleAndComposeTile(const size_t tilex, const size_t tiley, const uint32_t iipres); + + + + inline uint32_t bgra2rgb_kernel(const uint32_t& bgra) { + uint32_t t = bgra; + t = (t & 0x000000ff)<<24 | (t & 0x0000ff00)<<8 | (t & 0x00ff0000)>>8 | (t & 0xff000000)>>24; + return t >> 8; + } + + /** + * @brief in place bgra to rgb conversion. + * @details relies on compiler to generate bswap code. uses endian conversion to swap bgra to argb, then bit shift by 8 to get rid of a. + * + * @param data + */ + void bgra2rgb(uint8_t* data, const size_t w, const size_t h); + + /// average 2 rows, then average 2 pixels + inline uint32_t halfsample_kernel_3(const uint8_t *r1, const uint8_t *r2) { + uint64_t a = *(reinterpret_cast(r1)); + uint64_t c = *(reinterpret_cast(r2)); + uint64_t t1 = (((a ^ c) & 0xFEFEFEFEFEFEFEFE) >> 1) + (a & c); + uint32_t t2 = t1 & 0x0000000000FFFFFF; + uint32_t t3 = (t1 >> 24) & 0x0000000000FFFFFF; + return (((t3 ^ t2) & 0xFEFEFEFE) >> 1) + (t3 & t2); + } + + /// downsample by 2 + void halfsample_3(const uint8_t* in, const size_t in_w, const size_t in_h, + uint8_t* out, size_t& out_w, size_t& out_h); + + + void compose(const uint8_t *in, const size_t in_w, const size_t in_h, + const size_t& xoffset, const size_t& yoffset, + uint8_t* out, const size_t& out_w, const size_t& out_h); + + /// Constructor + OpenSlideImage() : IIPImage() { + tile_width = OPENSLIDE_TILESIZE; + tile_height = OPENSLIDE_TILESIZE; + osr = NULL; + }; + +public: + + + /// Constructor + /** \param path image path + */ + OpenSlideImage(const std::string& path, TileCache* tile_cache) : IIPImage(path), tileCache(tile_cache) { + tile_width = OPENSLIDE_TILESIZE; + tile_height = OPENSLIDE_TILESIZE; + osr = NULL; + }; + + /// Copy Constructor + + /** \param image IIPImage object + */ + OpenSlideImage(const IIPImage& image, TileCache* tile_cache) : IIPImage(image), tileCache(tile_cache) { + osr = NULL; + }; + + + /** \param image IIPImage object + */ + explicit OpenSlideImage(const OpenSlideImage& image) : IIPImage(image), + osr(image.osr), tileCache(image.tileCache), + numTilesX(image.numTilesX), + numTilesY(image.numTilesY), + lastTileXDim(image.lastTileXDim), + lastTileYDim(image.lastTileYDim), + openslide_level_to_use(image.openslide_level_to_use), + openslide_downsample_in_level(image.openslide_downsample_in_level) + {}; + /// Destructor + + virtual ~OpenSlideImage() { + closeImage(); + }; + + /// Overloaded function for opening a TIFF image + virtual void openImage() throw (file_error); + + + /// Overloaded function for loading TIFF image information + /** \param x horizontal sequence angle + \param y vertical sequence angle + */ + virtual void loadImageInfo(int x, int y) throw (file_error); + + /// Overloaded function for closing a TIFF image + virtual void closeImage(); + + + /// Overloaded function for getting a particular tile + /** \param x horizontal sequence angle + \param y vertical sequence angle + \param r resolution + \param l number of quality layers to decode + \param t tile number + */ + virtual RawTilePtr getTile(int x, int y, unsigned int r, int l, unsigned int t) throw (file_error); + +// // TCP: turn on region decoding. problem is that this bypasses tile caching, so overall it's not faster. +// /// Return whether this image type directly handles region decoding +// virtual bool regionDecoding(){ return false; }; +// // TCP: support getGegion (internally, openslide already is composing regions. however, this bypasses tile caching so is slower) +// /// Overloaded function for returning a region for a given angle and resolution +// /** Return a RawTile object: Overloaded by child class. +// \param ha horizontal angle +// \param va vertical angle +// \param r resolution +// \param layers number of quality layers to decode +// \param x x coordinate +// \param y y coordinate +// \param w width of region +// \param h height of region +// */ +// virtual RawTile getRegion( int ha, int va, unsigned int r, int layers, int x, int y, unsigned int w, unsigned int h ); + + + +// void readProperties(openslide_t* osr); +}; + +#endif /* OPENSLIDEIMAGE_H */ + diff --git a/iipsrv/src/PFL.cc b/iipsrv/src/PFL.cc new file mode 100644 index 0000000..d82c512 --- /dev/null +++ b/iipsrv/src/PFL.cc @@ -0,0 +1,222 @@ +/* + IIP Profile Command Handler Class Member Function + + Copyright (C) 2013 Ruven Pillay. + + 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 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +#include "Task.h" +#include +#include +#include + +using namespace std; + + +/// Return the profile for a line in JSON format +void PFL::run( Session* session, const std::string& argument ){ + + /* The argument should be of the form :,-, + 1) resolution + 2) start pixel index in x direction + 3) start pixel index in y direction + 4) end pixel index in x direction + 5) end pixel index in y direction + */ + + if( session->loglevel >= 3 ) (*session->logfile) << "PFL handler reached" << endl; + + int resolution, x1, y1, x2, y2, width, height; + + + // Time this command + if( session->loglevel >= 2 ) command_timer.start(); + + + // Parse the argument list + string arg = argument; + int delimitter = arg.find( ":" ); + resolution = atoi( arg.substr(0,delimitter).c_str() ); + + arg = arg.substr( delimitter + 1, arg.length() ); + delimitter = arg.find( "," ); + x1 = atoi( arg.substr(0,delimitter).c_str() ); + + arg = arg.substr( delimitter + 1, arg.length() ); + delimitter = arg.find( "-" ); + y1 = atoi( arg.substr(0,delimitter).c_str() ); + + if( delimitter == -1 ){ + (*session->logfile) << "PFL :: Single point requested" << endl; + x2 = x1; + y2 = y1; + } + else{ + arg = arg.substr( delimitter + 1, arg.length() ); + delimitter = arg.find( "," ); + x2 = atoi( arg.substr(0,delimitter).c_str() ); + + arg = arg.substr( delimitter + 1, arg.length() ); + y2 = atoi( arg.substr(0,arg.length()).c_str() ); + } + + + if( session->loglevel >= 5 ){ + (*session->logfile) << "PFL :: Resolution: " << resolution + << ", Position: " << x1 << "," << y1 << " - " + << x2 << "," << y2 << endl; + } + + + // Make sure we don't request impossible resolutions + if( resolution<0 || resolution>=(int)(session->image)->getNumResolutions() ){ + ostringstream error; + error << "PFL :: Invalid resolution number: " << resolution; + throw error.str(); + } + // Or impossible coordinates + if( x1<0 || x2<0 || y1<0 || y2<0 ){ + ostringstream error; + error << "PFL :: Invalid coordinates: " << x1 << "," << y1 << "-" << x2 << "," << y2 << endl; + throw error.str(); + } + + + // Determine whether we have a horizontal or vertical profile or just a single point + if( x2 > x1 ){ + width = x2-x1; + height = 1; + } + else if( y2 > y1 ){ + width = 1; + height = y2-y1; + } + else{ + width = 1; + height = 1; + } + unsigned long length = width * height; + + + // Create our tilemanager object + TileManager tilemanager( session->tileCache, session->image, session->watermark, session->jpeg, session->logfile, session->loglevel ); + + + // Use our horizontal views function to get a list of available spectral images + list views = (session->image)->getHorizontalViewsList(); + list :: const_iterator i; + unsigned int n = views.size(); + + + // Put the results into a string stream + ostringstream profile; + profile.precision(6); + + // Insert our opening braces + profile << "{\n\t\"profile\": "; + if( n > 1 ) profile << "{\n"; + + unsigned int k = 0; + + // Loop through our spectral bands + for( i = views.begin(); i != views.end(); i++ ){ + + int wavelength = *i; + + // Add our opening brackets and prefix with the wavelenth if we have multi-spectral data + if( n > 1 ) profile << "\t\t" << wavelength << ": "; + profile << "["; + + // Get the region of data for this wavelength and line profile + RawTilePtr rawtile = tilemanager.getRegion( resolution, wavelength, session->view->yangle, session->view->getLayers(), x1, y1, width, height ); + + // Loop through our pixels + for( unsigned int j=0; jbpc == 8 ){ + ptr = (unsigned char*) (rawtile->data); + intensity = (float)((unsigned char*)ptr)[j]; + } + else if( rawtile->bpc == 16 ){ + ptr = (unsigned short*) (rawtile->data); + intensity = (float)((unsigned short*)ptr)[j]; + } + else if( rawtile->bpc == 32 ){ + if( rawtile->sampleType == FIXEDPOINT ){ + ptr = (unsigned int*) rawtile->data; + intensity = (float)((unsigned int*)ptr)[j]; + } + else{ + ptr = (float*) rawtile->data; + intensity = (float)((float*)ptr)[j]; + } + } + + if( rawtile->sampleType == FLOATINGPOINT ) profile << fixed << setprecision(9); + profile << intensity; + if( j < length-1 ) profile << ","; + + } + + // Don't add trailing commas to the final sequence + if( k++ < n-1 ) profile << "],\n"; + else profile << "]\n"; + + } + + // Add our closing braces + if( n > 1 ) profile << "\t}\n"; + profile << "}"; + + + // Send out our JSON header +#ifndef DEBUG + char str[1024]; + snprintf( str, 1024, + "Server: iipsrv/%s\r\n" + "Content-Type: application/json\r\n" + "Cache-Control: max-age=%d\r\n" + "Last-Modified: %s\r\n" + "\r\n", + VERSION, MAX_AGE, (session->image)->getTimestamp().c_str() ); + + session->out->printf( (const char*) str ); + session->out->flush(); +#endif + + // Send the data itself + session->out->printf( profile.str().c_str() ); + session->out->flush(); + + if( session->out->flush() == -1 ) { + if( session->loglevel >= 1 ){ + *(session->logfile) << "PFL :: Error flushing JSON" << endl; + } + } + + // Inform our response object that we have sent something to the client + session->response->setImageSent(); + + // Total profile response time + if( session->loglevel >= 2 ){ + *(session->logfile) << "PFL :: Total command time " << command_timer.getTime() << " microseconds" << endl; + } + +} diff --git a/iipsrv/src/RawTile.h b/iipsrv/src/RawTile.h new file mode 100644 index 0000000..875c505 --- /dev/null +++ b/iipsrv/src/RawTile.h @@ -0,0 +1,304 @@ +// RawTile class + +/* IIP Image Server + + Copyright (C) 2000-2013 Ruven Pillay. + + 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 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + + +#ifndef _RAWTILE_H +#define _RAWTILE_H + + +#if __cplusplus >= 201103L +#define HAS_SHARED_PTR 1 +#endif + + +#if defined(HAS_SHARED_PTR) +#include +#endif + + +#include +#include +#include +#include +#include "Timer.h" + +//#define DEBUG_RT 1 + + + +#ifdef DEBUG_RT +#include +#include + +extern std::ofstream logfile; +#endif + +/// Colour spaces - GREYSCALE, sRGB and CIELAB +enum ColourSpaces { NONE, GREYSCALE, sRGB, CIELAB }; + +/// Compression Types +enum CompressionType { UNCOMPRESSED, JPEG, DEFLATE, PNG }; + +/// Sample Types +enum SampleType { FIXEDPOINT, FLOATINGPOINT }; + + +/// Class to represent a single image tile + +class RawTile{ + + public: + + /// The tile number for this tile + int tileNum; + + /// The resolution to which this tile belongs + int resolution; + + /// The horizontal angle to which this tile belongs + int hSequence; + + /// The vertical angle to which this tile belongs + int vSequence; + + /// Compression type + CompressionType compressionType; + + /// Compression rate or quality + int quality; + + /// Name of the file from which this tile comes + std::string filename; + + /// Tile timestamp + time_t timestamp; + + /// Pointer to the image data + void *data; + + /// This tracks whether we have allocated memory locally for data + /// or whether it is simply a pointer + /** This is used in the destructor to make sure we deallocate correctly */ + int memoryManaged; + + /// The size of the data pointed to by data + int dataLength; + + /// The width in pixels of this tile + unsigned int width; + + /// The height in pixels of this tile + unsigned int height; + + /// The number of channels for this tile + int channels; + + /// The number of bits per channel for this tile + int bpc; + + /// Sample format type (fixed or floating point) + SampleType sampleType; + + /// Padded + bool padded; + + + /// Main constructor + /** @param tn tile number + @param res resolution + @param hs horizontal sequence angle + @param vs vertical sequence angle + @param w tile width + @param h tile height + @param c number of channels + @param b bits per channel per sample + */ + RawTile( int tn = 0, int res = 0, int hs = 0, int vs = 0, + int w = 0, int h = 0, int c = 0, int b = 0 ) { + width = w; height = h; bpc = b; dataLength = 0; data = NULL; + tileNum = tn; resolution = res; hSequence = hs ; vSequence = vs; + memoryManaged = 1; channels = c; compressionType = UNCOMPRESSED; quality = 0; + timestamp = 0; sampleType = FIXEDPOINT; padded = false; + }; + + + /// Destructor to free the data array if is has previously be allocated locally + ~RawTile() { + if( data && memoryManaged ){ + switch( bpc ){ + case 32: + if( sampleType == FLOATINGPOINT ) delete[] (float*) data; + else delete[] (unsigned int*) data; + break; + case 16: + delete[] (unsigned short*) data; + break; + default: + delete[] (unsigned char*) data; + break; + } + } + } + + + /// Copy constructor - handles copying of data buffer + RawTile( const RawTile& tile ) { + + dataLength = tile.dataLength; + width = tile.width; + height = tile.height; + channels = tile.channels; + bpc = tile.bpc; + tileNum = tile.tileNum; + resolution = tile.resolution; + hSequence = tile.hSequence; + vSequence = tile.vSequence; + compressionType = tile.compressionType; + quality = tile.quality; + filename = tile.filename; + timestamp = tile.timestamp; + sampleType = tile.sampleType; + padded = tile.padded; + + switch( bpc ){ + case 32: + if( sampleType == FLOATINGPOINT ) data = new float[dataLength/4]; + else data = new unsigned int[dataLength/4]; + break; + case 16: + data = new unsigned short[dataLength/2]; + break; + default: + data = new unsigned char[dataLength]; + break; + } + +#ifdef DEBUG_RT + Timer timer; + timer.start(); +#endif + + + if( data && (dataLength > 0) && tile.data ){ + memcpy( data, tile.data, dataLength ); + memoryManaged = 1; + } +#ifdef DEBUG_RT + logfile << "RawTile :: copy ctor :: memcpy :: " << timer.getTime() << " microseconds" << std::endl << std::flush; +#endif + + } + + + /// Copy assignment constructor + RawTile& operator= ( const RawTile& tile ) { + + dataLength = tile.dataLength; + width = tile.width; + height = tile.height; + channels = tile.channels; + bpc = tile.bpc; + tileNum = tile.tileNum; + resolution = tile.resolution; + hSequence = tile.hSequence; + vSequence = tile.vSequence; + compressionType = tile.compressionType; + quality = tile.quality; + filename = tile.filename; + timestamp = tile.timestamp; + sampleType = tile.sampleType; + padded = tile.padded; + + switch( bpc ){ + case 32: + if( sampleType == FLOATINGPOINT ) data = new float[dataLength/4]; + else data = new int[dataLength/4]; + break; + case 16: + data = new unsigned short[dataLength/2]; + break; + default: + data = new unsigned char[dataLength]; + break; + } + +#ifdef DEBUG_RT + Timer timer; + timer.start(); +#endif + + if( data && (dataLength > 0) && tile.data ){ + memcpy( data, tile.data, dataLength ); + memoryManaged = 1; + } +#ifdef DEBUG_RT + logfile << "RawTile :: copy assign :: memcpy :: " << timer.getTime() << " microseconds" << std::endl << std::flush; +#endif + + return *this; + } + + + /// Return the size of the data + int size() { return dataLength; } + + + /// Overloaded equality operator + friend int operator == ( const RawTile& A, const RawTile& B ) { + if( (A.tileNum == B.tileNum) && + (A.resolution == B.resolution) && + (A.hSequence == B.hSequence) && + (A.vSequence == B.vSequence) && + (A.compressionType == B.compressionType) && + (A.quality == B.quality) && + (A.filename == B.filename) ){ + return( 1 ); + } + else return( 0 ); + } + + + /// Overloaded non-equality operator + friend int operator != ( const RawTile& A, const RawTile& B ) { + if( (A.tileNum == B.tileNum) && + (A.resolution == B.resolution) && + (A.hSequence == B.hSequence) && + (A.vSequence == B.vSequence) && + (A.compressionType == B.compressionType) && + (A.quality == B.quality) && + (A.filename == B.filename) ){ + return( 0 ); + } + else return( 1 ); + } + + +}; + +// pointer type definition belongs here. +#if defined(HAS_SHARED_PTR) + typedef std::shared_ptr RawTilePtr; +#else + typedef RawTile* RawTilePtr; +#endif + + +#endif diff --git a/iipsrv/src/SPECTRA.cc b/iipsrv/src/SPECTRA.cc new file mode 100644 index 0000000..a912771 --- /dev/null +++ b/iipsrv/src/SPECTRA.cc @@ -0,0 +1,163 @@ +/* + IIP SPECTRA Command Handler Class Member Function + + Copyright (C) 2009-2013 Ruven Pillay. + + 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 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +#include "Task.h" +#include + +using namespace std; + + +/// Return the spectral reflectance for a particular point in XML format +void SPECTRA::run( Session* session, const std::string& argument ){ + + /* The argument should consist of 2 comma separated values: + 1) resolution + 2) tile number + 3) pixel index in x direction + 4) pixel index in y direction + */ + + if( session->loglevel >= 3 ) (*session->logfile) << "SPECTRA handler reached" << endl; + + int resolution, tile, x, y; + + + // Time this command + if( session->loglevel >= 2 ) command_timer.start(); + + + // Parse the argument list + string arg = argument; + int delimitter = arg.find( "," ); + resolution = atoi( arg.substr(0,delimitter).c_str() ); + + arg = arg.substr( delimitter + 1, arg.length() ); + delimitter = arg.find( "," ); + tile = atoi( arg.substr(0,delimitter).c_str() ); + + arg = arg.substr( delimitter + 1, arg.length() ); + delimitter = arg.find( "," ); + x = atoi( arg.substr(0,delimitter).c_str() ); + + arg = arg.substr( delimitter + 1, arg.length() ); + delimitter = arg.find( "," ); + y = atoi( arg.substr(0,arg.length()).c_str() ); + + if( session->loglevel >= 5 ){ + (*session->logfile) << "SPECTRA :: resolution:" << resolution + << ",tile: " << tile + << ",x:" << x + << ",y:" << y << endl; + } + + + TileManager tilemanager( session->tileCache, session->image, session->watermark, session->jpeg, session->logfile, session->loglevel ); + + // Use our horizontal views function to get a list of available spectral images + list views = (session->image)->getHorizontalViewsList(); + list :: const_iterator i; + + // Our list of spectral reflectance values for the requested point + list spectrum; + + +#ifndef DEBUG + char str[1024]; + snprintf( str, 1024, + "Server: iipsrv/%s\r\n" + "Content-Type: application/xml\r\n" + "Cache-Control: max-age=%d\r\n" + "Last-Modified: %s\r\n" + "\r\n", + VERSION, MAX_AGE, (session->image)->getTimestamp().c_str() ); + + session->out->printf( (const char*) str ); + session->out->flush(); +#endif + + session->out->printf( "\n" ); + session->out->printf( "\n" ); + session->out->flush(); + + for( i = views.begin(); i != views.end(); i++ ){ + + int n = *i; + + RawTilePtr rawtile = tilemanager.getTile( resolution, tile, n, session->view->yangle, session->view->getLayers(), UNCOMPRESSED ); + + unsigned int tw = (session->image)->getTileWidth(); + unsigned int index = y*tw + x; + + void *ptr; + float reflectance = 0.0; + + if( session->loglevel >= 5 ) (*session->logfile) << "SPECTRA :: " << rawtile->bpc << " bits per channel data" << endl; + + // Handle depending on bit depth + if( rawtile->bpc == 8 ){ + ptr = (unsigned char*) (rawtile->data); + reflectance = static_cast((float)((unsigned char*)ptr)[index]) / 255.0; + } + else if( rawtile->bpc == 16 ){ + ptr = (unsigned short*) (rawtile->data); + reflectance = static_cast((float)((unsigned short*)ptr)[index]) / 65535.0; + } + else if( rawtile->bpc == 32 ){ + if( rawtile->sampleType == FIXEDPOINT ) { + ptr = (unsigned int*) rawtile->data; + reflectance = static_cast((float)((unsigned int*)ptr)[index]); + } + else { + ptr = (float*) rawtile->data; + reflectance = static_cast((float)((float*)ptr)[index]); + } + } + + spectrum.push_front( reflectance ); + + string metadata = (session->image)->getMetadata( "subject" ); + + char tmp[1024]; + snprintf( tmp, 1024, "\t\n\t\t%d\n\t\t%f\n\t\n", n, reflectance ); + session->out->printf( tmp ); + session->out->flush(); + + if( session->loglevel >= 3 ) (*session->logfile) << "SPECTRA :: " << n << " with reflectance " << reflectance << endl; + } + + + session->out->printf( "" ); + + if( session->out->flush() == -1 ) { + if( session->loglevel >= 1 ){ + *(session->logfile) << "SPECTRA :: Error flushing jpeg tile" << endl; + } + } + + + // Inform our response object that we have sent something to the client + session->response->setImageSent(); + + // Total SPECTRA response time + if( session->loglevel >= 2 ){ + *(session->logfile) << "SPECTRA :: Total command time " << command_timer.getTime() << " microseconds" << endl; + } + +} diff --git a/iipsrv/src/TIL.cc b/iipsrv/src/TIL.cc new file mode 100644 index 0000000..e032ed2 --- /dev/null +++ b/iipsrv/src/TIL.cc @@ -0,0 +1,243 @@ +/* + IIP TIL Command Handler Class Member Function + + Copyright (C) 2006-2013 Ruven Pillay. + + 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 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + + +#include "Task.h" + +using namespace std; + + + +void TIL::run( Session* session, const std::string& a ){ + + int resolution, start_tile, end_tile; + this->session = session; + + if( session->loglevel >= 3 ) *(session->logfile) << "TIL handler reached" << endl; + + checkImage(); + + + // Time this command + if( session->loglevel >= 2 ) command_timer.start(); + + + /* Parse the argument list of the form 'resolution,range' + */ + string argument = a; + int delimitter = argument.find( "," ); + string tmp = argument.substr( 0, delimitter ); + resolution = atoi( tmp.c_str() ); + argument = argument.substr( delimitter + 1, argument.length() ); + + delimitter = argument.find( "-" ); + tmp = argument.substr( 0, delimitter ); + start_tile = atoi( tmp.c_str() ); + argument = argument.substr( delimitter + 1, argument.length() ); + + if( argument.length() ){ + tmp = argument.substr( 0, argument.length() ); + end_tile = atoi( tmp.c_str() ); + } + else end_tile = start_tile; + + // Make sure our range is logical + if( end_tile < start_tile ) end_tile = start_tile; + + /* But we don't necessarily want all of these tiles. The spec requires + us to return the tiles within the square formed by the first and + last tiles. So, create a list of the tiles we need. + */ + + // Calculate the number of tiles at the requested resolution + int num_res = (session->image)->getNumResolutions(); + int requested_res = resolution; + + // Get the image width and height for this resolution + unsigned int im_width = (session->image)->getImageWidth(num_res-requested_res-1); + unsigned int im_height = (session->image)->getImageHeight(num_res-requested_res-1); + + unsigned int tile_width = (session->image)->getTileWidth(); + unsigned int tile_height = (session->image)->getTileHeight(); + unsigned int rem_x = im_width % tile_width; + unsigned int rem_y = im_height % tile_height; + int ntlx = (im_width / tile_width) + (rem_x == 0 ? 0 : 1); + int ntly = (im_height / tile_height) + (rem_y == 0 ? 0 : 1); + + int startx = start_tile % ntlx; + int starty = (int) start_tile / ntlx; + int endx = end_tile % ntlx; + int endy = (int) end_tile / ntlx; + + /* Our end tile can be 'behind' the end tile, so swap them over + to make sure our rectangle is properly formed + */ + if( endx < startx ){ + int tmp = startx; + startx = endx; + endx = tmp; + } + + if( session->loglevel >= 3 ){ + *(session->logfile) << "TIL :: resolution requested: " << resolution << endl + << "total tiles horizontally: " << ntlx + << ", vertically: " << ntly << endl + << "TIL :: start tile: " << start_tile + << ", end tile: " << end_tile << endl + << "TIL :: Rectangle: " << startx << "," << starty + << " - " << endx << "," << endy << endl; + } + + + /* Only send our MIME type once + */ + if( (endx >= startx) && (endy >= starty) ){ + char str[1024]; + snprintf( str, 1024, + "Server: iipsrv/%s\r\n" + "Content-Type: application/vnd.netfpx\r\n" + "Cache-Control: max-age=%d\r\n" + "Last-Modified: %s\r\n" + "\r\n", + VERSION, MAX_AGE, (session->image)->getTimestamp().c_str() ); + + session->out->printf( (const char*)str ); + } + + + for( int i = startx; i <= endx; i++ ){ + for( int j = starty; j <= endy; j++ ){ + + int n = i + (j*ntlx); + + // Get our tile using our tile manager + TileManager tilemanager( session->tileCache, session->image, session->watermark, session->jpeg, session->logfile, session->loglevel ); + RawTilePtr rawtile = tilemanager.getTile( resolution, n, session->view->xangle, + session->view->yangle, session->view->getLayers(), JPEG ); + + int len = rawtile->dataLength; + + + if( session->loglevel >= 2 ){ + *(session->logfile) << "TIL :: Sending tile " << n << " at: " << i << "," << j << endl + << "TIL :: Number of channels per sample is " << rawtile->channels << endl + << "TIL :: Raw data bits per channel is " << rawtile->bpc << endl + << "TIL :: Raw data length is " << len << endl; + } + + + /* The IIP compression type. Set a default no compression type + + The compression type is a 32 bit unsigned int: + 0x0: none (8 bit) + 0x1: single colour compression + 0x2: JPEG compression + 0x3: none 16 bit -- not a part of the IIP specification version 1.05 + 0xFFFFFFFF: invalid tile + */ + unsigned char compType[4] = { 0x00,0x00,0x00,0x00 }; + + + /* Do JPEG compression if we have an 8 bit image and set the IIP compression type + */ + if( rawtile->bpc == 8 ) compType[0] = 0x02; + else if( rawtile->bpc == 16 ) compType[0] = 0x03; + + if( session->loglevel >= 2 )* (session->logfile) << "TIL :: Compressed tile size is " << len << endl; + + + /* Send the tile prefix, indicating which resolution, + tile number and data length + */ + char buf[1024]; + snprintf( buf, 1024, "Tile,%d,%d,0/%d:", resolution, n, len + 8 ); + session->out->printf( (const char*) buf ); + + /* Send out the IIP compression type + */ + if( session->out->putStr( (const char*) compType, 4 ) != 4 ){ + if( session->loglevel >= 1 ){ + *(session->logfile) << "TIL :: Error writing compression type " << endl; + } + } + + /* Send the compression subtype defined within the FlashPix specification + + The 4 bytes represent the following: + i) Interleave Type + - 0x00 for 8x8 block interleaving or 0x01 for separate scans + ii) Chroma Subsampling + - 0x11 or 0x22 etc. + iii) Internal Colour Conversion + - 0x00 for none or 0x01 + iv) JPEG table selector + - index of previously downloaded table or 0x00 for table + included in datastream + */ + + unsigned char compSubType[4] = { 0x00,0x11,0x00,0x00 }; + if( session->out->putStr( (const char*) compSubType, 4 ) != 4 ){ + if( session->loglevel >= 1 ){ + *(session->logfile) << "TIL :: Error writing compression sub-type " << endl; + } + } + + /* Send the actual tile data + */ + if( session->out->putStr( (const char*) rawtile->data, len ) != len ){ + if( session->loglevel >= 1 ){ + *(session->logfile) << "TIL :: Error writing jpeg tile" << endl; + } + } + + /* And finally send the CRLF terminator for each tile + */ + session->out->printf( "\r\n" ); + + if( session->out->flush() == -1 ) { + if( session->loglevel >= 1 ){ + *(session->logfile) << "TIL :: Error flushing jpeg tile" << endl; + } + } + + } // End of for( starty, endy ) + } // End of for( startx, endx ) + + + if( session->out->flush() == -1 ) { + if( session->loglevel >= 1 ){ + *(session->logfile) << "TIL :: Error flushing jpeg tile" << endl; + } + } + + + /* Inform our response object that we have sent something to the client + */ + session->response->setImageSent(); + + + // Total TIL response time + if( session->loglevel >= 2 ){ + *(session->logfile) << "TIL :: Total command time " << command_timer.getTime() << " microseconds" << endl; + } + + +} + diff --git a/iipsrv/src/TPTImage.cc b/iipsrv/src/TPTImage.cc new file mode 100644 index 0000000..94de36f --- /dev/null +++ b/iipsrv/src/TPTImage.cc @@ -0,0 +1,325 @@ +// Member functions for TPTImage.h + +/* IIP Server: Tiled Pyramidal TIFF handler + + Copyright (C) 2000-2014 Ruven Pillay. + + 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 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. + +*/ + + +#include "TPTImage.h" +#include + + +using namespace std; + + +void TPTImage::openImage() throw (file_error) +{ + + // Insist that the tiff and tile_buf be non-NULL + if( tiff || tile_buf ){ + throw file_error( "TPT::openImage: tiff or tile_buf is not NULL" ); + } + + string filename = getFileName( currentX, currentY ); + + // Update our timestamp + updateTimestamp( filename ); + + // Try to open and allocate a buffer + if( ( tiff = TIFFOpen( filename.c_str(), "r" ) ) == NULL ){ + throw file_error( "tiff open failed for: " + filename ); + } + + // Load our metadata if not already loaded + if( bpc == 0 ) loadImageInfo( currentX, currentY ); + + // Insist on a tiled image + if( (tile_width == 0) && (tile_height == 0) ){ + throw file_error( "TIFF image is not tiled" ); + } + + isSet = true; + +} + + +void TPTImage::loadImageInfo( int seq, int ang ) throw(file_error) +{ + tdir_t current_dir; + int count; + uint16 colour, samplesperpixel, bitspersample, sampleformat; + double sminvaluearr[4] = {0.0}, smaxvaluearr[4] = {0.0}; + double *sminvalue = NULL, *smaxvalue = NULL; + unsigned int w, h; + string filename; + char *tmp = NULL; + + currentX = seq; + currentY = ang; + + // Get the tile and image sizes + TIFFGetField( tiff, TIFFTAG_TILEWIDTH, &tile_width ); + TIFFGetField( tiff, TIFFTAG_TILELENGTH, &tile_height ); + TIFFGetField( tiff, TIFFTAG_IMAGEWIDTH, &w ); + TIFFGetField( tiff, TIFFTAG_IMAGELENGTH, &h ); + TIFFGetField( tiff, TIFFTAG_SAMPLESPERPIXEL, &samplesperpixel ); + TIFFGetField( tiff, TIFFTAG_BITSPERSAMPLE, &bitspersample ); + TIFFGetField( tiff, TIFFTAG_PHOTOMETRIC, &colour ); + TIFFGetField( tiff, TIFFTAG_SAMPLEFORMAT, &sampleformat ); + + // We have to do this conversion explicitly to avoid problems on Mac OS X + channels = (unsigned int) samplesperpixel; + bpc = (unsigned int) bitspersample; + sampleType = (sampleformat==3) ? FLOATINGPOINT : FIXEDPOINT; + + // Check for the no. of resolutions in the pyramidal image + current_dir = TIFFCurrentDirectory( tiff ); + TIFFSetDirectory( tiff, 0 ); + + // Store the list of image dimensions available + image_widths.push_back( w ); + image_heights.push_back( h ); + + for( count = 0; TIFFReadDirectory( tiff ); count++ ){ + TIFFGetField( tiff, TIFFTAG_IMAGEWIDTH, &w ); + TIFFGetField( tiff, TIFFTAG_IMAGELENGTH, &h ); + image_widths.push_back( w ); + image_heights.push_back( h ); + } + // Reset the TIFF directory + TIFFSetDirectory( tiff, current_dir ); + + numResolutions = count+1; + + // Handle various colour spaces + if( colour == PHOTOMETRIC_CIELAB ) colourspace = CIELAB; + else if( colour == PHOTOMETRIC_MINISBLACK ) colourspace = GREYSCALE; + else if( colour == PHOTOMETRIC_PALETTE ){ + // Watch out for colourmapped images. These are stored as 1 sample per pixel, + // but are decoded to 3 channels by libtiff, so declare them as sRGB + colourspace = sRGB; + channels = 3; + } + else if( colour == PHOTOMETRIC_YCBCR ){ + // JPEG encoded tiles can be subsampled YCbCr encoded. Ask to decode these to RGB + TIFFSetField( tiff, TIFFTAG_JPEGCOLORMODE, JPEGCOLORMODE_RGB ); + colourspace = sRGB; + } + else colourspace = sRGB; + + // Get the max and min values for our data type - required for floats + // This are usually single values per image, but can also be per channel + // in libtiff > 4.0.2 via http://www.asmail.be/msg0055458208.html + +#ifdef TIFFTAG_PERSAMPLE + if( channels > 1 ){ + TIFFSetField(tiff, TIFFTAG_PERSAMPLE, PERSAMPLE_MULTI); + TIFFGetFieldDefaulted( tiff, TIFFTAG_SMINSAMPLEVALUE, &sminvalue ); + TIFFGetFieldDefaulted( tiff, TIFFTAG_SMAXSAMPLEVALUE, &smaxvalue ); + TIFFSetField(tiff, TIFFTAG_PERSAMPLE, PERSAMPLE_MERGED); + if (!sminvalue) sminvalue = sminvaluearr; + if (!smaxvalue) smaxvalue = smaxvaluearr; + } + else{ +#endif + sminvalue = sminvaluearr; + smaxvalue = smaxvaluearr; + TIFFGetFieldDefaulted( tiff, TIFFTAG_SMINSAMPLEVALUE, sminvalue ); + TIFFGetFieldDefaulted( tiff, TIFFTAG_SMAXSAMPLEVALUE, smaxvalue ); +#ifdef TIFFTAG_PERSAMPLE + } +#endif + + // Clear our arrays + min.clear(); + max.clear(); + + for( unsigned int i=0; i= numResolutions ){ + ostringstream error; + error << "TPTImage :: Asked for non-existant resolution: " << res; + throw file_error( error.str() ); + } + + + // If we are currently working on a different sequence number, then + // close and reload the image. + if( (currentX != seq) || (currentY != ang) ){ + closeImage(); + } + + + // Open the TIFF if it's not already open + if( !tiff ){ + filename = getFileName( seq, ang ); + if( ( tiff = TIFFOpen( filename.c_str(), "r" ) ) == NULL ){ + throw file_error( "tiff open failed for:" + filename ); + } + } + + + // Reload our image information in case the tile size etc is different + if( (currentX != seq) || (currentY != ang) ){ + loadImageInfo( seq, ang ); + } + + + // The first resolution is the highest, so we need to invert + // the resolution - can avoid this if we store our images with + // the smallest image first. + int vipsres = ( numResolutions - 1 ) - res; + + + // Change to the right directory for the resolution + if( !TIFFSetDirectory( tiff, vipsres ) ) { + throw file_error( "TIFFSetDirectory failed" ); + } + + + // Check that a valid tile number was given + if( tile >= TIFFNumberOfTiles( tiff ) ) { + ostringstream tile_no; + tile_no << "Asked for non-existant tile: " << tile; + throw file_error( tile_no.str() ); + } + + + // Get the size of this tile, the current image, + // the number of samples and the colourspace. + // TIFFTAG_TILEWIDTH give us the values for the resolution, + // not for the tile itself + TIFFGetField( tiff, TIFFTAG_TILEWIDTH, &tw ); + TIFFGetField( tiff, TIFFTAG_TILELENGTH, &th ); + TIFFGetField( tiff, TIFFTAG_IMAGEWIDTH, &im_width ); + TIFFGetField( tiff, TIFFTAG_IMAGELENGTH, &im_height ); + TIFFGetField( tiff, TIFFTAG_PHOTOMETRIC, &colour ); +// TIFFGetField( tiff, TIFFTAG_SAMPLESPERPIXEL, &channels ); +// TIFFGetField( tiff, TIFFTAG_BITSPERSAMPLE, &bpc ); + + + // Get the width and height for last row and column tiles + rem_x = im_width % tw; + rem_y = im_height % th; + + + // Calculate the number of tiles in each direction + ntlx = (im_width / tw) + (rem_x == 0 ? 0 : 1); + ntly = (im_height / th) + (rem_y == 0 ? 0 : 1); + + + // Alter the tile size if it's in the last column + if( ( tile % ntlx == ntlx - 1 ) && ( rem_x != 0 ) ) { + tw = rem_x; + } + + + // Alter the tile size if it's in the bottom row + if( ( tile / ntlx == ntly - 1 ) && rem_y != 0 ) { + th = rem_y; + } + + + // Handle various colour spaces + if( colour == PHOTOMETRIC_CIELAB ) colourspace = CIELAB; + else if( colour == PHOTOMETRIC_MINISBLACK ) colourspace = GREYSCALE; + else if( colour == PHOTOMETRIC_PALETTE ){ + // Watch out for colourmapped images. There are stored as 1 sample per pixel, + // but are decoded to 3 channels by libtiff, so declare them as sRGB + colourspace = GREYSCALE; + channels = 1; + } + else if( colour == PHOTOMETRIC_YCBCR ){ + // JPEG encoded tiles can be subsampled YCbCr encoded. Ask to decode these to RGB + TIFFSetField( tiff, TIFFTAG_JPEGCOLORMODE, JPEGCOLORMODE_RGB ); + colourspace = sRGB; + } + else colourspace = sRGB; + + + // Allocate memory for our tile. + if( !tile_buf ){ + if( ( tile_buf = _TIFFmalloc( TIFFTileSize(tiff) ) ) == NULL ){ + throw file_error( "tiff malloc tile failed" ); + } + } + + // Decode and read the tile + int length = TIFFReadEncodedTile( tiff, (ttile_t) tile, + tile_buf, (tsize_t) - 1 ); + if( length == -1 ) { + throw file_error( "TIFFReadEncodedTile failed for " + getFileName( seq, ang ) ); + } + + + RawTilePtr rawtile(new RawTile( tile, res, seq, ang, tw, th, channels, bpc )); + rawtile->data = tile_buf; + rawtile->dataLength = length; + rawtile->filename = getImagePath(); + rawtile->timestamp = timestamp; + rawtile->memoryManaged = 0; + rawtile->padded = true; + rawtile->sampleType = sampleType; + + return( rawtile ); + +} + diff --git a/iipsrv/src/TPTImage.h b/iipsrv/src/TPTImage.h new file mode 100644 index 0000000..1515f21 --- /dev/null +++ b/iipsrv/src/TPTImage.h @@ -0,0 +1,108 @@ +// Tiled Pyramidal Tiff class interface + +/* IIPImage Tiled Pyramidal TIFF Class + + Copyright (C) 2000-2014 Ruven Pillay. + + 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 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + + +#ifndef _TPTIMAGE_H +#define _TPTIMAGE_H + + +#include "IIPImage.h" +#include +#include + + + + +/// Image class for Tiled Pyramidal Images: Inherits from IIPImage. Uses libtiff +class TPTImage : public IIPImage { + + private: + + /// Pointer to the TIFF library struct + TIFF *tiff; + + /// Tile data buffer pointer + tdata_t tile_buf; + + + public: + + /// Constructor + TPTImage():IIPImage(), tiff( NULL ), tile_buf( NULL ) {}; + + /// Constructor + /** @param path image path + */ + TPTImage( const std::string& path ): IIPImage( path ), tiff( NULL ), tile_buf( NULL ) {}; + + /// Copy Constructor + /** @param image IIPImage object + */ + TPTImage( const TPTImage& image ): IIPImage( image ), tiff( NULL ),tile_buf( NULL ) {}; + + /// Assignment Operator + /** @param TPTImage object + */ + TPTImage& operator = ( TPTImage image ) { + if( this != &image ){ + closeImage(); + IIPImage::operator=(image); + tiff = image.tiff; + tile_buf = image.tile_buf; + } + return *this; + } + + /// Construct from an IIPImage object + /** @param image IIPImage object + */ + TPTImage( const IIPImage& image ): IIPImage( image ) { + tiff = NULL; tile_buf = NULL; + }; + + /// Destructor + ~TPTImage() { closeImage(); }; + + /// Overloaded function for opening a TIFF image + void openImage() throw (file_error); + + /// Overloaded function for loading TIFF image information + /** @param x horizontal sequence angle + @param y vertical sequence angle + */ + void loadImageInfo( int x, int y ) throw (file_error); + + /// Overloaded function for closing a TIFF image + void closeImage(); + + /// Overloaded function for getting a particular tile + /** @param x horizontal sequence angle + @param y vertical sequence angle + @param r resolution + @param l quality layers + @param t tile number + */ + virtual RawTilePtr getTile( int x, int y, unsigned int r, int l, unsigned int t ) throw (file_error); + +}; + + +#endif diff --git a/iipsrv/src/Task.cc b/iipsrv/src/Task.cc new file mode 100644 index 0000000..3377475 --- /dev/null +++ b/iipsrv/src/Task.cc @@ -0,0 +1,458 @@ +/* + IIP Command Handler Member Functions + + Copyright (C) 2006-2014 Ruven Pillay. + + 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 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + + +#include "Task.h" +#include "Tokenizer.h" +#include +#include + + +using namespace std; + + + +Task* Task::factory( const string& t ){ + + // Convert the command string to lower case to handle incorrect + // viewer implementations + + string type = t; + transform( type.begin(), type.end(), type.begin(), ::tolower ); + + if( type == "obj" ) return new OBJ; + else if( type == "fif" ) return new FIF; + else if( type == "qlt" ) return new QLT; + else if( type == "sds" ) return new SDS; + else if( type == "minmax" ) return new MINMAX; + else if( type == "cnt" ) return new CNT; + else if( type == "gam" ) return new GAM; + else if( type == "wid" ) return new WID; + else if( type == "hei" ) return new HEI; + else if( type == "rgn" ) return new RGN; + else if( type == "rot" ) return new ROT; + else if( type == "til" ) return new TIL; +// else if( type == "ptl" ) return new PTL; + else if( type == "jtl" ) return new JTL; + else if( type == "jtls" ) return new JTLS; + else if( type == "icc" ) return new ICC; + else if( type == "cvt" ) return new CVT; + else if( type == "shd" ) return new SHD; + else if( type == "cmp" ) return new CMP; + else if( type == "inv" ) return new INV; + else if( type == "zoomify" ) return new Zoomify; + else if( type == "spectra" ) return new SPECTRA; + else if( type == "pfl" ) return new PFL; + else if( type == "lyr" ) return new LYR; + else if( type == "deepzoom" ) return new DeepZoom; + else if( type == "ctw" ) return new CTW; + else if( type == "iiif" ) return new IIIF; + else return NULL; + +} + + +void Task::checkImage(){ + if( !(session->image) ){ + session->response->setError( "1 3", argument ); + throw string( "image not set" ); + } +} + + + +void QLT::run( Session* session, const std::string& argument ){ + + if( argument.length() ){ + + int factor = atoi( argument.c_str() ); + + // Check the value is realistic + if( factor < 0 || factor > 100 ){ + if( session->loglevel >= 2 ){ + *(session->logfile) << "QLT :: JPEG Quality factor of " << argument + << " out of bounds. Must be 0-100" << endl; + } + } + + session->jpeg->setQuality( factor ); + } + +} + + +void SDS::run( Session* session, const std::string& argument ){ + + if( session->loglevel >= 3 ) *(session->logfile) << "SDS handler reached" << endl; + + // Parse the argument list + int delimitter = argument.find( "," ); + string tmp = argument.substr( 0, delimitter ); + session->view->xangle = atoi( tmp.c_str() ); + string arg2 = argument.substr( delimitter + 1, argument.length() ); + + delimitter = arg2.find( "," ); + tmp = arg2.substr( 0, delimitter ); + session->view->yangle = atoi( tmp.c_str() ); + + if( session->loglevel >= 2 ) *(session->logfile) << "SDS :: set to " << session->view->xangle << ", " + << session->view->yangle << endl; + +} + + +void MINMAX::run( Session* session, const std::string& argument ){ + + if( session->loglevel >= 3 ) *(session->logfile) << "MINMAX handler reached" << endl; + + // Parse the argument list + int delimitter = argument.find( ":" ); + string tmp = argument.substr( 0, delimitter ); + int nchan = atoi( tmp.c_str() ) - 1; + string arg2 = argument.substr( delimitter + 1, argument.length() ); + + delimitter = arg2.find( "," ); + tmp = arg2.substr( 0, delimitter ); + ((session->image))->min[nchan] = atof( tmp.c_str() ); + string arg3 = arg2.substr( delimitter + 1, arg2.length() ); + + delimitter = arg3.find( "," ); + tmp = arg3.substr( 0, delimitter ); + ((session->image))->max[nchan] = atof( tmp.c_str() ); + + if( session->loglevel >= 2 ) *(session->logfile) << "MINMAX :: set to " << ((session->image))->min[nchan] << ", " + << ((session->image))->max[nchan] << " for channel " << nchan << endl; +} + + +void CNT::run( Session* session, const std::string& argument ){ + + float contrast = 1.0; // hack to get this value exact. + if (argument != "1" && argument != "1.0") { + contrast = (float) atof( argument.c_str() ); + } + + if( session->loglevel >= 2 ) *(session->logfile) << "CNT handler reached" << endl; + if( session->loglevel >= 3 ) *(session->logfile) << "CNT :: requested contrast adjustment is " << contrast << endl; + + session->view->setContrast( contrast ); +} + + +void GAM::run( Session* session, const std::string& argument ){ + + float gamma = 1.0; // hack to get this value exact. + if (argument != "1" && argument != "1.0") { + gamma = (float) atof( argument.c_str() ); + } + + if( session->loglevel >= 2 ) *(session->logfile) << "GAM handler reached" << endl; + if( session->loglevel >= 3 ) *(session->logfile) << "GAM :: requested gamma adjustment is " << gamma << endl; + + session->view->setGamma( gamma ); +} + + +void CVT::run( Session* session, const std::string& src ){ + + // Put the argument into lower case + string argument = src; + transform( argument.begin(), argument.end(), argument.begin(), ::tolower ); + + // For the moment, only deal with JPEG. If we have specified something else, give a warning + // and send JPEG anyway + if( argument != "jpeg" ){ + if( session->loglevel >= 1 ) *(session->logfile) << "CVT :: Unsupported request: '" << argument << "'. Sending JPEG." << endl; + } + else{ + if( session->loglevel >= 3 ) *(session->logfile) << "CVT :: JPEG output" << endl; + } + + this->send( session ); +} + + +void WID::run( Session* session, const std::string& argument ){ + + int requested_width = atoi( argument.c_str() ); + + if( session->loglevel >= 2 ) *(session->logfile) << "WID handler reached" << endl; + if( session->loglevel >= 3 ) *(session->logfile) << "WID :: requested width is " << requested_width << endl; + + session->view->setRequestWidth( requested_width ); + +} + + +void HEI::run( Session* session, const std::string& argument ){ + + int requested_height = atoi( argument.c_str() ); + + if( session->loglevel >= 2 ) *(session->logfile) << "HEI handler reached" << endl; + if( session->loglevel >= 3 ) *(session->logfile) << "HEI :: requested height is " << requested_height << endl; + + session->view->setRequestHeight( requested_height ); + +} + + +void RGN::run( Session* session, const std::string& argument ){ + + Tokenizer izer( argument, "," ); + int i = 0; + + if( session->loglevel >= 2 ) *(session->logfile) << "RGN handler reached" << endl; + + float region[4]; + while( izer.hasMoreTokens() && i<4 ){ + try{ + region[i++] = atof( izer.nextToken().c_str() ); + } + catch( const string& error ){ + if( session->loglevel >= 1 ) *(session->logfile) << error << endl; + } + } + + // Only load this information if our argument was correctly parsed to + // give 4 values and that we have a width and height greater than zero + if( i == 4 && region[2]>0 && region[3]>0){ + session->view->setViewLeft( region[0] ); + session->view->setViewTop( region[1] ); + session->view->setViewWidth( region[2] ); + session->view->setViewHeight( region[3] ); + } + + if( session->loglevel >= 3 ){ + *(session->logfile) << "RGN :: requested region is " << region[0] << ", " + << region[1] << ", " << region[2] << ", " << region[3] << endl; + } + +} + + +void ROT::run( Session* session, const std::string& argument ){ + + float rotation = 0.0; // hack to get this value exact. + if (argument != "0" && argument != "0.0") { + rotation = (float) atof( argument.c_str() ); + } + + if( session->loglevel >= 2 ) *(session->logfile) << "ROT handler reached" << endl; + if( session->loglevel >= 3 ) *(session->logfile) << "ROT :: requested rotation is " << rotation << " degrees" << endl; + + session->view->setRotation( rotation ); +} + + +void JTLS::run( Session* session, const std::string& argument ){ + + /* The argument is comma separated into 4: + 1) xangle + 2) resolution + 3) tile number + 4) yangle + This is a legacy command. Clients should use SDS to specity the x,y angle and JTL + for the resolution and tile number. + */ + + Tokenizer izer( argument, "," ); + int i = 0; + + if( session->loglevel >= 2 ) *(session->logfile) << "JTLS handler reached" << endl; + + int values[4]; + while( izer.hasMoreTokens() && i<4 ){ + try{ + values[i++] = atoi( izer.nextToken().c_str() ); + } + catch( const string& error ){ + if( session->loglevel >= 1 ) *(session->logfile) << error << endl; + } + } + + if( i == 4 ){ + session->view->xangle = values[0]; + session->view->yangle = values[3]; + + // Simply pass this on to our JTL send command + JTL jtl; + jtl.send( session, values[1], values[2] ); + } + +} + + +void JTL::run( Session* session, const std::string& argument ){ + + /* The argument should consist of 2 comma separated values: + 1) resolution + 2) tile number + */ + + // Parse the argument list + int delimitter = argument.find( "," ); + int resolution = atoi( argument.substr( 0, delimitter ).c_str() ); + int tile = atoi( argument.substr( delimitter + 1, argument.length() ).c_str() ); + + // Send out the requested tile + this->send( session, resolution, tile ); +} + + +void SHD::run( Session* session, const std::string& argument ){ + + /* The argument is comma separated into the 3D angles of incidence of the + light source in degrees for the angle in the horizontal plane from 12 o'clock + and downwards in the vertical plane, where 0 represents a source pointing + horizontally + */ + + Tokenizer izer( argument, "," ); + int i = 0; + + if( session->loglevel >= 2 ) *(session->logfile) << "SHD handler reached" << endl; + + int values[2]; + while( izer.hasMoreTokens() && i<2 ){ + try{ + values[i++] = atoi( izer.nextToken().c_str() ); + } + catch( const string& error ){ + if( session->loglevel >= 1 ) *(session->logfile) << error << endl; + } + } + + if( i == 2 ){ + session->view->shaded = true; + session->view->shade[0] = values[0]; + session->view->shade[1] = values[1]; + } + + if( session->loglevel >= 3 ) *(session->logfile) << "SHD :: requested shade incidence angle is " + << values[0] << "," << values[1] << endl; +} + + +void CMP::run( Session* session, const std::string& argument ){ + + /* The argument is the colormap type: available colormaps are + HOT, COLD, JET, BLUE, GREEN, RED + */ + + // Convert to lower case in order to do our string comparison + string ctype = argument; + transform( ctype.begin(), ctype.end(), ctype.begin(), ::tolower ); + + if( session->loglevel >= 2 ) *(session->logfile) << "CMP handler reached" << endl; + if( session->loglevel >= 3 ) *(session->logfile) << "CMP :: requested colormap is " << ctype << endl; + session->view->cmapped = true; + + if (ctype=="hot") session->view->cmap = HOT; + else if (ctype=="cold") session->view->cmap = COLD; + else if (ctype=="jet") session->view->cmap = JET; + else if (ctype=="blue") session->view->cmap = BLUE; + else if (ctype=="green") session->view->cmap = GREEN; + else if (ctype=="red") session->view->cmap = RED; + else session->view->cmapped = false; +} + + +void INV::run( Session* session, const std::string& argument ){ + // Does not take an argument + if( session->loglevel >= 2 ) *(session->logfile) << "INV handler reached" << endl; + session->view->inverted = true; +} + + +void LYR::run( Session* session, const std::string& argument ){ + + if( argument.length() ){ + + int layer = atoi( argument.c_str() ); + + if( session->loglevel >= 2 ) *(session->logfile) << "LYR handler reached" << endl; + if( session->loglevel >= 3 ) *(session->logfile) << "LYR :: requested layer is " << layer << endl; + + // Check the value is realistic + if( layer < 1 || layer > 256 ){ + if( session->loglevel >= 2 ){ + *(session->logfile) << "LYR :: Number of quality layers " << argument + << " out of bounds. Must be 1-256" << endl; + } + } + + session->view->setLayers( layer ); + } + +} + + +void CTW::run( Session* session, const std::string& argument ){ + + /* Matrices should be formated as CTW=[a,b,c;d,e,f;g,h,i] where commas separate row values + and semi-colons separate columns. + Thus, the above argument represents the 3x3 square matrix: + [ a b c + d e f + g h i ] + */ + + if( argument.length() ){ + if( session->loglevel >= 2 ) *(session->logfile) << "CTW handler reached" << endl; + } + + int pos1 = argument.find("["); + int pos2 = argument.find("]"); + + // Extract the contents of the array + string line = argument.substr( pos1+1, pos2-pos1-1 ); + + // Tokenize on rows + Tokenizer col_izer( line, ";" ); + + while( col_izer.hasMoreTokens() ){ + + // Fill each row item + Tokenizer row_izer( col_izer.nextToken(), "," ); + vector row; + + while( row_izer.hasMoreTokens() ){ + try{ + row.push_back( atof( row_izer.nextToken().c_str() ) ); + } + catch( const string& error ){ + if( session->loglevel >= 1 ) *(session->logfile) << error << endl; + } + } + session->view->ctw.push_back( row ); + } + + if( session->loglevel >= 3 ){ + *(session->logfile) << "CTW :: " << session->view->ctw[0].size() << "x" << session->view->ctw.size() << " matrix: " << endl; + for( unsigned int i=0; iview->ctw.size(); i++ ){ + *(session->logfile) << "CTW :: "; + for( unsigned int j=0;jview->ctw[0].size(); j++ ){ + *(session->logfile) << session->view->ctw[i][j] << " "; + } + *(session->logfile) << endl; + } + } + +} diff --git a/iipsrv/src/Task.h b/iipsrv/src/Task.h new file mode 100644 index 0000000..b4d15e0 --- /dev/null +++ b/iipsrv/src/Task.h @@ -0,0 +1,341 @@ +/* + IIP Generic Task Class + + Copyright (C) 2006-2014 Ruven Pillay. + + 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 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + + +#ifndef _TASK_H +#define _TASK_H + + + +#include +#include +#include "IIPImage.h" +#include "IIPResponse.h" +#include "JPEGCompressor.h" +#include "View.h" +#include "TileManager.h" +#include "Timer.h" +#include "Writer.h" +#include "Cache.h" +#include "Watermark.h" +#ifdef HAVE_PNG +#include "PNGCompressor.h" +#endif + + +// Define our http header cache max age (24 hours) +#define MAX_AGE 86400 + +typedef ImageCache imageCacheMapType; + +//#ifdef HAVE_EXT_POOL_ALLOCATOR +//#include +//typedef HASHMAP < const std::string, IIPImage, +// __gnu_cxx::hash< const std::string >, +// std::equal_to< const std::string >, +// __gnu_cxx::__pool_alloc< std::pair > +// > imageCacheMapType; +//#else +//typedef HASHMAP imageCacheMapType; +//#endif + + + + + + +/// Structure to hold our session data +struct Session { + IIPImagePtr image; + //IIPImage **image; + JPEGCompressor* jpeg; +#ifdef HAVE_PNG + PNGCompressor* png; +#endif + View* view; + IIPResponse* response; + Watermark* watermark; + int loglevel; + std::ofstream* logfile; + std::map headers; + + imageCacheMapType *imageCache; + TileCache* tileCache; + +#ifdef DEBUG + FileWriter* out; +#else + FCGIWriter* out; +#endif + +}; + + + + +/// Generic class to encapsulate various commands +class Task { + + protected: + + /// Timer for each task + Timer command_timer; + + /// Pointer to our session data + Session* session; + + /// Argument supplied to the task + std::string argument; + + + public: + + /// Virtual destructor + virtual ~Task() {;}; + + /// Main public function + virtual void run( Session* session, const std::string& argument ) {;}; + + /// Factory function + /** @param type command type */ + static Task* factory( const std::string& type ); + + /// Check image + void checkImage(); + +}; + + + + +/// OBJ commands +class OBJ : public Task { + + public: + + void run( Session* session, const std::string& argument ); + + void iip(); + void iip_server(); + void max_size(); + void resolution_number(); + void colorspace( std::string arg ); + void tile_size(); + void bits_per_channel(); + void horizontal_views(); + void vertical_views(); + void min_max_values(); + void metadata( std::string field ); + +}; + + +/// JPEG Quality Command +class QLT : public Task { + public: + void run( Session* session, const std::string& argument ); +}; + + +/// SDS Command +class SDS : public Task { + public: + void run( Session* session, const std::string& argument ); +}; + + +/// MINMAX Command +class MINMAX : public Task { + public: + void run( Session* session, const std::string& argument ); +}; + + +/// Contrast Command +class CNT : public Task { + public: + void run( Session* session, const std::string& argument ); +}; + + +/// Gamma Command +class GAM : public Task { + public: + void run( Session* session, const std::string& argument ); +}; + + +/// CVT Width Command +class WID : public Task { + public: + void run( Session* session, const std::string& argument ); +}; + + +/// CVT Height Command +class HEI : public Task { + public: + void run( Session* session, const std::string& argument ); +}; + + +/// CVT Region Command +class RGN : public Task { + public: + void run( Session* session, const std::string& argument ); +}; + + +/// ROT Rotation Command +class ROT : public Task { + public: + void run( Session* session, const std::string& argument ); +}; + + +/// FIF Command +class FIF : public Task { + public: + void run( Session* session, const std::string& argument ); +}; + + +/// PNG Tile Command +/*class PTL : public Task { + public: + void run( Session* session, const std::string& argument ); +};*/ + + +/// JPEG Tile Export Command +class JTL : public Task { + public: + void run( Session* session, const std::string& argument ); + + /// Send out a single tile + /** @param session our current session + @param resolution requested image resolution + @param tile requested tile index + */ + void send( Session* session, int resolution, int tile ); +}; + + +/// JPEG Tile Sequence Command +class JTLS : public Task { + public: + void run( Session* session, const std::string& argument ); +}; + + +/// Tile Command +class TIL : public Task { + public: + void run( Session* session, const std::string& argument ); +}; + + +/// CVT Region Export Command +class CVT : public Task { + public: + void run( Session* session, const std::string& argument ); + + /// Send out our requested region + /** @param session our current session */ + void send( Session* session ); +}; + + +/// ICC Profile Command +class ICC : public Task { + public: + void run( Session* session, const std::string& argument ); +}; + + +/// Shading Command +class SHD : public Task { + public: + void run( Session* session, const std::string& argument ); +}; + +/// Colormap Command +class CMP : public Task { + public: + void run( Session* session, const std::string& argument ); +}; + +/// Inversion Command +class INV : public Task { + public: + void run( Session* session, const std::string& argument ); +}; + +/// Zoomify Request Command +class Zoomify : public Task { + public: + void run( Session* session, const std::string& argument ); +}; + + +/// SPECTRA Request Command +class SPECTRA : public Task { + public: + void run( Session* session, const std::string& argument ); +}; + + +/// SPECTRA Request Command +class PFL : public Task { + public: + void run( Session* session, const std::string& argument ); +}; + + +/// Quality Layers Command +class LYR : public Task { + public: + void run( Session* session, const std::string& argument ); +}; + + +/// DeepZoom Request Command +class DeepZoom : public Task { + public: + void run( Session* session, const std::string& argument ); +}; + + +/// IIIF Command +class IIIF : public Task { + public: + void run( Session* session, const std::string& argument ); +}; + + +/// Color Twist Command +class CTW : public Task { + public: + void run( Session* session, const std::string& argument ); +}; + + + +#endif diff --git a/iipsrv/src/TileManager.cc b/iipsrv/src/TileManager.cc new file mode 100644 index 0000000..f356a6a --- /dev/null +++ b/iipsrv/src/TileManager.cc @@ -0,0 +1,446 @@ + +// Member functions for TileManager.h + + +/* IIP Server: Tile Cache Handler + + Copyright (C) 2005-2014 Ruven Pillay. + + 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 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + + + +#include +#include "TileManager.h" + + +using namespace std; + + + +RawTilePtr TileManager::getNewTile( int resolution, int tile, int xangle, int yangle, int layers ){ + + if( loglevel >= 2 ) *logfile << "TileManager :: Cache Miss for resolution: " << resolution << ", tile: " << tile << endl + << "TileManager :: Cache Size: " << tileCache->getNumElements() + << " tiles, " << tileCache->getMemorySize() << " MB" << endl; + + + RawTilePtr ttt; + + // Get our raw tile from the IIPImage image object + ttt = image->getTile( xangle, yangle, resolution, layers, tile ); + + + // Apply the watermark if we have one. + // Do this before inserting into cache so that we cache watermarked tiles + if( watermark && watermark->isSet() ){ + + if( loglevel >= 2 ) insert_timer.start(); + unsigned int tw = ttt->padded? image->getTileWidth() : ttt->width; + unsigned int th = ttt->padded? image->getTileHeight() : ttt->height; + + watermark->apply( ttt->data, tw, th, ttt->channels, ttt->bpc ); + if( loglevel >= 2 ) *logfile << "TileManager :: Watermark applied: " << insert_timer.getTime() + << " microseconds" << endl; + } + + + // We need to crop our edge tiles if they are padded + if( ((ttt->width != image->getTileWidth()) || (ttt->height != image->getTileHeight())) && ttt->padded ){ + if( loglevel >= 5 ) * logfile << "TileManager :: Cropping tile" << endl; + this->crop( ttt ); + } + + // add the uncompressed to the tile cache - used by getRegion + if( loglevel >= 2 ) insert_timer.start(); + tileCache->insert( ttt ); + if( loglevel >= 2 ) *logfile << "TileManager :: Tile cache uncompressed insertion time: " << insert_timer.getTime() + << " microseconds" << endl; + + + return ttt; + +} + + + +void TileManager::crop( RawTilePtr ttt ){ + + int tw = image->getTileWidth(); + int th = image->getTileHeight(); + + if( loglevel >= 3 ){ + *logfile << "TileManager :: Edge tile: Base size: " << tw << "x" << th + << ": This tile: " << ttt->width << "x" << ttt->height + << endl; + } + + // Create a new buffer, fill it with the old data, then copy + // back the cropped part into the RawTilePtr buffer + int len = tw * th * ttt->channels * ttt->bpc/8; + unsigned char* buffer = (unsigned char*) malloc( len ); + unsigned char* src_ptr = (unsigned char*) memcpy( buffer, ttt->data, len ); + unsigned char* dst_ptr = (unsigned char*) ttt->data; + + // Copy one scanline at a time + for( unsigned int i=0; iheight; i++ ){ + len = ttt->width * ttt->channels * ttt->bpc/8; + memcpy( dst_ptr, src_ptr, len ); + dst_ptr += len; + src_ptr += tw * ttt->channels * ttt->bpc/8; + } + + free( buffer ); + + // Reset the data length + len = ttt->width * ttt->height * ttt->channels * ttt->bpc/8; + ttt->dataLength = len; + ttt->padded = false; + +} + + + +// returns cache instance, does not incur a copy. +RawTilePtr TileManager::getTileInternal( int resolution, int tile, int xangle, int yangle, int layers, CompressionType c ){ + + RawTilePtr rawtile; + string tileCompression; + string compName; + + + // Time the tile retrieval + if( loglevel >= 2 ) tile_timer.start(); + + + /* Try to get this tile from our cache first as a JPEG, then uncompressed + Otherwise decode one from the source image and add it to the cache + */ + switch( c ) + { + // TCP: automatically fall through to the next case if not break. + case JPEG: + if( (rawtile = tileCache->getObject( TileCache::getIndex(image->getImagePath(), resolution, tile, + xangle, yangle, JPEG, jpeg->getQuality() ) ) ) ) break; + case DEFLATE: + if( (rawtile = tileCache->getObject( TileCache::getIndex(image->getImagePath(), resolution, tile, + xangle, yangle, DEFLATE, 0 ) ) ) ) break; + case UNCOMPRESSED: + if( (rawtile = tileCache->getObject( TileCache::getIndex(image->getImagePath(), resolution, tile, + xangle, yangle, UNCOMPRESSED, 0 ) ) ) ) break; + default: + break; + + } +// if( loglevel >= 3 ) *logfile << "TileManager :: getTileInternal :: retrieved from cache " << endl; + if (!rawtile) + if (loglevel >= 3) *logfile << "TileManager :: getTileInternal :: cache miss." << endl; + + + // If we haven't been able to get a tile, get a raw one + if( !rawtile || (rawtile && (rawtile->timestamp < image->timestamp)) ){ + + if( rawtile && (rawtile->timestamp < image->timestamp) ){ + if( loglevel >= 3 ) *logfile << "TileManager :: Tile has old timestamp " + << rawtile->timestamp << " - " << image->timestamp + << " ... updating" << endl; + + // evict the tile from cache + tileCache->evict(rawtile); + } + + // get uncompressed tile +// if( loglevel >= 3 ) *logfile << "TileManager :: getTileInternal :: retrieved from file " << endl; + rawtile = this->getNewTile( resolution, tile, xangle, yangle, layers ); + + if( loglevel >= 2 ) *logfile << "TileManager :: Total Tile Access Time: " + << tile_timer.getTime() << " microseconds" << endl; + } + + + // Define our compression names + switch( rawtile->compressionType ){ + case JPEG: compName = "JPEG"; break; + case DEFLATE: compName = "DEFLATE"; break; + case UNCOMPRESSED: compName = "UNCOMPRESSED"; break; + default: break; + } + + if( loglevel >= 2 ) *logfile << "TileManager :: Cache Hit for resolution: " << resolution + << ", tile: " << tile + << ", compression: " << compName << endl + << "TileManager :: Cache Size: " + << tileCache->getNumElements() << " tiles, " + << tileCache->getMemorySize() << " MB" << endl; + + + // Check whether the compression used for out tile matches our requested compression type. + // If not, we must convert + + if( c == JPEG && rawtile->compressionType == UNCOMPRESSED ){ + + // Rawtile is a pointer to the cache data, so we need to create a copy of it in case we compress it + RawTilePtr ttt(new RawTile( *rawtile )); + + // Do our JPEG compression iff we have an 8 bit per channel image and either 1 or 3 bands + if( rawtile->bpc==8 && (rawtile->channels==1 || rawtile->channels==3) ){ + + // Crop if this is an edge tile + if( ( (ttt->width != image->getTileWidth()) || (ttt->height != image->getTileHeight()) ) && ttt->padded ){ + if( loglevel >= 5 ) * logfile << "TileManager :: Cropping tile" << endl; + this->crop( ttt ); + } + + if( loglevel >=2 ) compression_timer.start(); + unsigned int oldlen = rawtile->dataLength; + unsigned int newlen = jpeg->Compress( ttt ); + if( loglevel >= 2 ) *logfile << "TileManager :: JPEG requested, but UNCOMPRESSED compression found in cache." << endl + << "TileManager :: JPEG Compression Time: " + << compression_timer.getTime() << " microseconds" << endl + << "TileManager :: Compression Ratio: " << newlen << "/" << oldlen << " = " + << ( (float)newlen/(float)oldlen ) << endl; + + // Add our compressed tile to the cache + if( loglevel >= 2 ) insert_timer.start(); + tileCache->insert( ttt ); + if( loglevel >= 2 ) *logfile << "TileManager :: Tile cache insertion time: " << insert_timer.getTime() + << " microseconds" << endl; + + if( loglevel >= 2 ) *logfile << "TileManager :: Total Tile Access Time: " + << tile_timer.getTime() << " microseconds" << endl; + return ttt; // returns cache instance + } + } + + if( loglevel >= 2 ) *logfile << "TileManager :: Total Tile Access Time: " + << tile_timer.getTime() << " microseconds" << endl; + return rawtile; // cache's instance +} + + +RawTilePtr TileManager::getTile( int resolution, int tile, int xangle, int yangle, int layers, CompressionType c ){ +//if( loglevel >= 2 ) *logfile << "TileManager :: getTile :: begin " << endl; + + + RawTilePtr rawtile = getTileInternal(resolution, tile, xangle, yangle, layers, c); +//if( loglevel >= 2 ) *logfile << "TileManager :: getTile :: got it " << endl; + + + return RawTilePtr(new RawTile(*rawtile)); // returns copy of cache instance + +} + + +RawTilePtr TileManager::getRegion( unsigned int res, int seq, int ang, int layers, unsigned int x, unsigned int y, unsigned int width, unsigned int height ){ + + // If our image type can directly handle region compositing, simply return that + if( image->regionDecoding() ){ + if( loglevel >= 3 ){ + *logfile << "TileManager getRegion :: requesting region directly from image" << endl; + } + return image->getRegion( seq, ang, res, layers, x, y, width, height ); + } + + // Otherwise do the compositing ourselves + + // The tile size of the source tile + unsigned int src_tile_width = image->getTileWidth(); + unsigned int src_tile_height = image->getTileHeight(); + + // The tile size of the destination tile + unsigned int dst_tile_width = src_tile_width; + unsigned int dst_tile_height = src_tile_height; + + // The basic tile size ie. not the current tile + unsigned int basic_tile_width = src_tile_width; + unsigned int basic_tile_height = src_tile_height; + + int num_res = image->getNumResolutions(); + unsigned int im_width = image->image_widths[num_res-res-1]; + unsigned int im_height = image->image_heights[num_res-res-1]; + + unsigned int rem_x = im_width % src_tile_width; + unsigned int rem_y = im_height % src_tile_height; + + // The number of tiles in each direction + unsigned int ntlx = (im_width / src_tile_width) + (rem_x == 0 ? 0 : 1); + unsigned int ntly = (im_height / src_tile_height) + (rem_y == 0 ? 0 : 1); + + // Start and end tiles and pixel offsets + unsigned int startx, endx, starty, endy, xoffset, yoffset; + + + if( ! ( x==0 && y==0 && width==im_width && height==im_height ) ){ + // Calculate the start tiles + startx = (unsigned int) ( x / src_tile_width ); + starty = (unsigned int) ( y / src_tile_height ); + xoffset = x % src_tile_width; + yoffset = y % src_tile_height; + + endx = (unsigned int) ceil( (float)(width + x) / (float)src_tile_width ); + endy = (unsigned int) ceil( (float)(height + y) / (float)src_tile_height ); + + if( loglevel >= 3 ){ + *logfile << "TileManager getRegion :: Total tiles in image: " << ntlx << "x" << ntly << " tiles" << endl + << "TileManager getRegion :: Tile start: " << startx << "," << starty << " with offset: " + << xoffset << "," << yoffset << endl + << "TileManager getRegion :: Tile end: " << endx-1 << "," << endy-1 << endl; + } + } + else{ + startx = starty = xoffset = yoffset = 0; + endx = ntlx; + endy = ntly; + } + + + unsigned int channels = image->getNumChannels(); + unsigned int bpc = image->getNumBitsPerPixel(); + SampleType sampleType = image->getSampleType(); + + // Create an empty tile with the correct dimensions + RawTilePtr region(new RawTile( 0, res, seq, ang, width, height, channels, bpc )); + region->dataLength = width * height * channels * bpc/8; + region->sampleType = sampleType; + + // Allocate memory for the region + if( bpc == 8 ) region->data = new unsigned char[width*height*channels]; + else if( bpc == 16 ) region->data = new unsigned short[width*height*channels]; + else if( bpc == 32 && sampleType == FIXEDPOINT ) region->data = new int[width*height*channels]; + else if( bpc == 32 && sampleType == FLOATINGPOINT ) region->data = new float[width*height*channels]; + + unsigned int current_height = 0; + + // Decode the image strip by strip + for( unsigned int i=starty; i= 2 ) tile_timer.start(); + + // Get an uncompressed tile + RawTilePtr rawtile = this->getTile( res, (i*ntlx) + j, seq, ang, layers, UNCOMPRESSED ); + + if( loglevel >= 2 ){ + *logfile << "TileManager getRegion :: Tile access time " << tile_timer.getTime() << " microseconds for tile " + << (i*ntlx) + j << " at resolution " << res << endl; + } + + + // Only print this out once per image + if( (loglevel >= 4) && (i==starty) && (j==starty) ){ + *logfile << "TileManager getRegion :: Tile data is " << rawtile->channels << " channels, " + << rawtile->bpc << " bits per channel" << endl; + } + + // Set the tile width and height to be that of the source tile - Use the rawtile data + // because if we take a tile from cache the image pointer will not necessarily be pointing + // to the the current tile + src_tile_width = rawtile->width; + src_tile_height = rawtile->height; + dst_tile_width = src_tile_width; + dst_tile_height = src_tile_height; + + // Variables for the pixel offset within the current tile + unsigned int xf = 0; + unsigned int yf = 0; + + // If our viewport has been set, we need to modify our start + // and end points on the source image + if( !( x==0 && y==0 && width==im_width && height==im_height ) ){ + + unsigned int remainder; // Remaining pixels in the final row or column + + if( j == startx ){ + // Calculate the width used in the current tile + // If there is only 1 tile, the width is just the view width + if( j < endx - 1 ) dst_tile_width = src_tile_width - xoffset; + else dst_tile_width = width; + xf = xoffset; + } + else if( j == endx-1 ){ + // If this is the final row, calculate the remaining number of pixels + remainder = (width+x) % basic_tile_width; + if( remainder != 0 ) dst_tile_width = remainder; + } + + if( i == starty ){ + // Calculate the height used in the current row of tiles + // If there is only 1 row the height is just the view height + if( i < endy - 1 ) dst_tile_height = src_tile_height - yoffset; + else dst_tile_height = height; + yf = yoffset; + } + else if( i == endy-1 ){ + // If this is the final row, calculate the remaining number of pixels + remainder = (height+y) % basic_tile_height; + if( remainder != 0 ) dst_tile_height = remainder; + } + + if( loglevel >= 4 ){ + *logfile << "TileManager getRegion :: destination tile width: " << dst_tile_width + << ", tile height: " << dst_tile_height << endl; + } + } + + + // Copy our tile data into the appropriate part of the strip memory + // one whole tile width at a time + for( unsigned int k=0; kwidth*channels) + (xf*channels); + + // Simply copy the line of data across + if( bpc == 8 ){ + unsigned char* ptr = (unsigned char*) rawtile->data; + unsigned char* buf = (unsigned char*) region->data; + memcpy( &buf[buffer_index], &ptr[inx], dst_tile_width*channels ); + } + else if( bpc == 16 ){ + unsigned short* ptr = (unsigned short*) rawtile->data; + unsigned short* buf = (unsigned short*) region->data; + memcpy( &buf[buffer_index], &ptr[inx], dst_tile_width*channels*2 ); + } + else if( bpc == 32 && sampleType == FIXEDPOINT ){ + unsigned int* ptr = (unsigned int*) rawtile->data; + unsigned int* buf = (unsigned int*) region->data; + memcpy( &buf[buffer_index], &ptr[inx], dst_tile_width*channels*4 ); + } + else if( bpc == 32 && sampleType == FLOATINGPOINT ){ + float* ptr = (float*) rawtile->data; + float* buf = (float*) region->data; + memcpy( &buf[buffer_index], &ptr[inx], dst_tile_width*channels*4 ); + } + } + + current_width += dst_tile_width; + } + + current_height += dst_tile_height; + + } + + return region; + +} diff --git a/iipsrv/src/TileManager.h b/iipsrv/src/TileManager.h new file mode 100644 index 0000000..93507e3 --- /dev/null +++ b/iipsrv/src/TileManager.h @@ -0,0 +1,148 @@ +// Tile Cache Manager Class + +/* IIP Image Server + + Copyright (C) 2005-2013 Ruven Pillay. + + 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 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + + +#ifndef _TILEMANAGER_H +#define _TILEMANAGER_H + + +#include + +#include "RawTile.h" +#include "IIPImage.h" +#include "JPEGCompressor.h" +#include "Cache.h" +#include "Timer.h" +#include "Watermark.h" + + + +/// Class to manage access to the tile cache and tile cropping + +class TileManager{ + + + private: + + TileCache* tileCache; + JPEGCompressor* jpeg; + IIPImagePtr image; + Watermark* watermark; + std::ofstream* logfile; + int loglevel; + Timer compression_timer, tile_timer, insert_timer; + + /// Get a new tile from the image file + /** + * If the JPEG tile already exists in the cache, use that, otherwise check for + * an uncompressed tile. If that does not exist either, extract a tile from the + * image. If this is an edge tile, crop it. + * @param resolution resolution number + * @param tile tile number + * @param xangle horizontal sequence number + * @param yangle vertical sequence number + * @param number of quality layers within image to decode + * @return RawTile pointer, points to what's in CACHE. uncompressed version only. + */ + RawTilePtr getNewTile( int resolution, int tile, int xangle, int yangle, int layers); + + + /// Crop a tile to remove padding + /** @param t pointer to tile to crop, no copy. + */ + void crop( RawTilePtr t ); + + + public: + + + /// Constructor + /** + * @param tc pointer to tile cache object + * @param im pointer to IIPImage object + * @param w pointer to watermark object + * @param j pointer to JPEGCompressor object + * @param s pointer to output file stream + * @param l logging level + */ + TileManager( TileCache* tc, IIPImagePtr im, Watermark* w, JPEGCompressor* j, std::ofstream* s, int l ){ + tileCache = tc; + image = im; + watermark = w; + jpeg = j; + logfile = s ; + loglevel = l; + }; + + + + /// Get a tile from the cache + /** + * If the JPEG tile already exists in the cache, use that, otherwise check for + * an uncompressed tile. If that does not exist either, extract a tile from the + * image. If this is an edge tile, crop it. + * @param resolution resolution number + * @param tile tile number + * @param xangle horizontal sequence number + * @param yangle vertical sequence number + * @param layers number of quality layers within image to decode + * @param c CompressionType + * @return RawTile pointer. the instance that's in TileCache + */ + RawTilePtr getTileInternal( int resolution, int tile, int xangle, int yangle, int layers, CompressionType c ); + + + /// Get a tile from the cache + /** + * If the JPEG tile already exists in the cache, use that, otherwise check for + * an uncompressed tile. If that does not exist either, extract a tile from the + * image. If this is an edge tile, crop it. + * @param resolution resolution number + * @param tile tile number + * @param xangle horizontal sequence number + * @param yangle vertical sequence number + * @param layers number of quality layers within image to decode + * @param c CompressionType + * @return RawTile pointer. A COPY of what's in TileCache + */ + RawTilePtr getTile( int resolution, int tile, int xangle, int yangle, int layers, CompressionType c ); + + + /// Generate a complete region + /** + * Build up an arbitrary region by extracting tiles from the cache by using getTile function. + * Data returned as uncompressed data. + * @param res resolution number + * @param xangle horizontal sequence number + * @param yangle vertical sequence number + * @param layers number of quality layers within image to decode + * @param x left offset with respect to full image + * @param y top offset with respect to full image + * @param w width of region requested + * @param h height of region requested + * @return RawTile pointer. A COPY of what's in TileCache + */ + RawTilePtr getRegion( unsigned int res, int xangle, int yangle, int layers, unsigned int x, unsigned int y, unsigned int w, unsigned int h ); + +}; + + +#endif diff --git a/iipsrv/src/Timer.h b/iipsrv/src/Timer.h new file mode 100644 index 0000000..b6a0438 --- /dev/null +++ b/iipsrv/src/Timer.h @@ -0,0 +1,87 @@ +// Timer class + +/* IIP fcgi server module + + Copyright (C) 2005-2013 Ruven Pillay. + + 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 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + + +#ifndef _TIMER_H +#define _TIMER_H + + +#ifdef HAVE_SYS_TIME_H +#include +#endif + + +#ifdef WIN32 +#include "../windows/Time.h" +#endif + + +/// Simple Timer class to allow us to time our responses + +class Timer { + + + private: + + /// Time structure + struct timeval tv; + + /// Timezone structure + struct timezone tz; + + /// Our start time in seconds + long start_t; + + /// The microsecond component of our start time + long start_u; + + + public: + + /// Constructor + Timer() {;}; + + + /// Set our time + /** Initialise with our start time */ + void start() { + tz.tz_minuteswest = 0; + if( gettimeofday( &tv, NULL ) == 0 ){ + start_t = tv.tv_sec; + start_u = tv.tv_usec; + } + else start_t = start_u = 0; + } + + + /// Return time since we were initialised in microseconds + long getTime() { + if( gettimeofday( &tv, NULL ) == 0 ) return (tv.tv_sec - start_t) * 1000000 + (tv.tv_usec - start_u); + else return 0; + } + + +}; + + + +#endif + diff --git a/iipsrv/src/Tokenizer.h b/iipsrv/src/Tokenizer.h new file mode 100644 index 0000000..fdbd9ef --- /dev/null +++ b/iipsrv/src/Tokenizer.h @@ -0,0 +1,107 @@ +/* + Simple String Tokenizer Class + + Copyright (C) 2000-2013 Ruven Pillay. + + 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 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + + +#ifndef _TOKENIZER_H +#define _TOKENIZER_H + +#include + + +/// Simple utility class to split a string into tokens + +class Tokenizer{ + + private: + std::string arg; + std::string delim; + std::string _nextToken(); + + public: + + /// Constructor + /** \param s string to be split + \param d delimitter + */ + Tokenizer( const std::string& s, const std::string& d ); + + /// Return the next token + std::string nextToken(); + + /// Indicate whether there are any tokens remaining + int hasMoreTokens(); + +}; + + + +inline Tokenizer::Tokenizer( const std::string& s, const std::string& t ) +{ + arg = s; + delim = t; +} + + + +inline std::string Tokenizer::_nextToken() +{ + int n; + std::string result; + + n = arg.find( delim ); + + // No token in string, so return original + if( n < 0 ){ + result = arg; + arg = std::string(); + } + else{ + result = arg.substr( 0, n ); + arg = arg.substr( n + delim.length(), arg.length() ); + } + + return result; +} + + + +inline std::string Tokenizer::nextToken() +{ + std::string result; + do{ + result = _nextToken(); + } + while( result.empty() && !arg.empty() ); + + return result; + +} + + +inline int Tokenizer::hasMoreTokens() +{ + int n = arg.find_first_not_of( delim, 0 ); + if( n >= 0 ) return 1; + else return 0; +} + + + +#endif diff --git a/iipsrv/src/Transforms.cc b/iipsrv/src/Transforms.cc new file mode 100644 index 0000000..03ab0b4 --- /dev/null +++ b/iipsrv/src/Transforms.cc @@ -0,0 +1,775 @@ +// Image Transform Functions + +/* IIP fcgi server module - image processing routines + + Copyright (C) 2004-2014 Ruven Pillay. + + 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 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + + +#include +#include "Transforms.h" + + +// Define something similar to C99 std::isfinite if this does not exist +// Need to also check for a direct define as it can be implemented as a macro +#ifndef HAVE_ISFINITE +#ifndef isfinite +#include +static bool isfinite( float arg ) +{ + return arg == arg && + arg != std::numeric_limits::infinity() && + arg != -std::numeric_limits::infinity(); +} +#endif +#endif + + + +/* D65 temp 6504. + */ +#define D65_X0 95.0470 +#define D65_Y0 100.0 +#define D65_Z0 108.8827 + + +static const float _sRGB[3][3] = { { 3.240479, -1.537150, -0.498535 }, + { -0.969256, 1.875992, 0.041556 }, + { 0.055648, -0.204043, 1.057311 } }; + +using namespace std; + + +// Normalization function +void filter_normalize( RawTilePtr in, vector& max, vector& min ) { + + float *normdata; + unsigned int np = in->dataLength * 8 / in->bpc; + unsigned int nc = in->channels; + + // Type pointers + float* fptr; + unsigned int* uiptr; + unsigned short* usptr; + unsigned char* ucptr; + + if( in->bpc == 32 && in->sampleType == FLOATINGPOINT ) { + normdata = (float*)in->data; + } + else { + normdata = new float[np]; + } + + for( unsigned int c = 0 ; c 1e-30? 1./diffc : 1e30; + + // Normalize our data + if( in->bpc == 32 && in->sampleType == FLOATINGPOINT ) { + fptr = (float*)in->data; + // Loop through our pixels for floating point pixels +#pragma ivdep + for( unsigned int n=c; nbpc == 32 && in->sampleType == FIXEDPOINT ) { + uiptr = (unsigned int*)in->data; + // Loop through our pixels for unsigned int pixels +#pragma ivdep + for( unsigned int n=c; nbpc == 16 ) { + usptr = (unsigned short*)in->data; + // Loop through our unsigned short pixels +#pragma ivdep + for( unsigned int n=c; ndata; + // Loop through our unsigned char pixels +#pragma ivdep + for( unsigned int n=c; nbpc == 32 && in->sampleType == FIXEDPOINT ){ + delete[] (unsigned int*) in->data; + } + else if( in->bpc == 16 ){ + delete[] (unsigned short*) in->data; + } + else if( in->bpc == 8 ){ + delete[] (unsigned char*) in->data; + } + + // Assign our new buffer and modify some info + in->data = normdata; + in->bpc = 32; + in->dataLength = np * in->bpc / 8; + +} + + + +// Hillshading function +void filter_shade( RawTilePtr in, int h_angle, int v_angle ){ + + float o_x, o_y, o_z; + + // Incident light angle + float a = (h_angle * 2 * 3.14159) / 360.0; + + // We assume a hypotenous of 1.0 + float s_y = cos(a); + float s_x = sqrt( 1.0 - s_y*s_y ); + if( h_angle > 180 ){ + s_x = -s_x; + } + + a = (v_angle * 2 * 3.14159) / 360.0; + float s_z = - sin(a); + + float s_norm = sqrt( s_x*s_x + s_y*s_y + s_z*s_z ); + s_x = s_x / s_norm; + s_y = s_y / s_norm; + s_z = s_z / s_norm; + + float *buffer, *infptr; + + unsigned int k = 0; + unsigned int ndata = in->dataLength * 8 / in->bpc; + + infptr= (float*)in->data; + // Create new (float) data buffer + buffer = new float[ndata]; + + for( unsigned int n=0; n 1. ) dot_product = 1.; + + buffer[k++] = dot_product; + } + + + // Delete old data buffer + delete[] (float*) in->data; + + in->data = buffer; + in->channels = 1; + in->dataLength = in->width * in->height * in->bpc / 8; +} + + + +// Convert a single pixel from CIELAB to sRGB +static void LAB2sRGB( unsigned char *in, unsigned char *out ){ + + /* First convert to XYZ + */ + int l; + float L, a, b; + float X, Y, Z; + double cby, tmp; + double R, G, B; + + /* Extract our LAB - packed in TIFF as unsigned char for L + and signed char for a/b. We also need to rescale + correctly to 0-100 for L and -127 -> +127 for a/b. + */ + l = in[0]; + L = (float) ( in[0] / 2.55 ); + l = ( (signed char*)in )[1]; + a = (float) l; + l = ( (signed char*)in )[2]; + b = (float) l; + + + if( L < 8.0 ) { + Y = (L * D65_Y0) / 903.3; + cby = 7.787 * (Y / D65_Y0) + 16.0 / 116.0; + } + else { + cby = (L + 16.0) / 116.0; + Y = D65_Y0 * cby * cby * cby; + } + + tmp = a / 500.0 + cby; + if( tmp < 0.2069 ) X = D65_X0 * (tmp - 0.13793) / 7.787; + else X = D65_X0 * tmp * tmp * tmp; + + tmp = cby - b / 200.0; + if( tmp < 0.2069 ) Z = D65_Z0 * (tmp - 0.13793) / 7.787; + else Z = D65_Z0 * tmp * tmp * tmp; + + X /= 100.0; + Y /= 100.0; + Z /= 100.0; + + + /* Then convert to sRGB + */ + R = (X * _sRGB[0][0]) + (Y * _sRGB[0][1]) + (Z * _sRGB[0][2]); + G = (X * _sRGB[1][0]) + (Y * _sRGB[1][1]) + (Z * _sRGB[1][2]); + B = (X * _sRGB[2][0]) + (Y * _sRGB[2][1]) + (Z * _sRGB[2][2]); + + /* Clip any -ve values + */ + if( R < 0.0 ) R = 0.0; + if( G < 0.0 ) G = 0.0; + if( B < 0.0 ) B = 0.0; + + + /* We now need to convert these to non-linear display values + */ + if( R <= 0.0031308 ) R *= 12.92; + else R = 1.055 * pow( R, 1.0/2.4 ) - 0.055; + + if( G <= 0.0031308 ) G *= 12.92; + else G = 1.055 * pow( G, 1.0/2.4 ) - 0.055; + + if( B <= 0.0031308 ) B *= 12.92; + else B = 1.055 * pow( B, 1.0/2.4 ) - 0.055; + + /* Scale to 8bit + */ + R *= 255.0; + G *= 255.0; + B *= 255.0; + + /* Clip to our 8 bit limit + */ + if( R > 255.0 ) R = 255.0; + if( G > 255.0 ) G = 255.0; + if( B > 255.0 ) B = 255.0; + + + /* Return our sRGB values + */ + out[0] = (unsigned char) R; + out[1] = (unsigned char) G; + out[2] = (unsigned char) B; + +} + + + +// Convert whole tile from CIELAB to sRGB +void filter_LAB2sRGB( RawTilePtr in ){ + + unsigned long np = in->width * in->height * in->channels; + + // Parallelize code using OpenMP + unsigned int nstep = in->channels; +#pragma omp parallel for + for( unsigned long n=0; ndata; + unsigned char q[3]; + LAB2sRGB( &ptr[n], &q[0] ); + ((unsigned char*)in->data)[n] = q[0]; + ((unsigned char*)in->data)[n+1] = q[1]; + ((unsigned char*)in->data)[n+2] = q[2]; + } +} + + + +// Colormap function +void filter_cmap( RawTilePtr in, enum cmap_type cmap ){ + + float value; + unsigned out_chan = 3; + unsigned int ndata = in->dataLength * 8 / in->bpc / in->channels; + + const float max3=1./3.; + const float max8=1./8.; + + float *fptr = (float*)in->data; + float *outptr = new float[ndata*out_chan]; + float *outv = outptr; + + switch(cmap){ + case HOT: +#pragma ivdep + for( int unsigned n=0; n1.) + { outv[0]=outv[1]=outv[2]=1.; } + else if(value<=0.) + { outv[0]=outv[1]=outv[2]=0.; } + else if(value1.) + { outv[0]=outv[1]=outv[2]=1.; } + else if(value<=0.) + { outv[0]=outv[1]=outv[2]=0.; } + else if(valuedata; + in->data = outptr; + in->channels = out_chan; + in->dataLength = ndata * out_chan * in->bpc / 8; +} + + + +// Inversion function +void filter_inv( RawTilePtr in ){ + float* infptr; + unsigned int np = in->dataLength * 8 / in->bpc; + + infptr = (float*) in->data; + + // Loop through our pixels for floating values +#pragma ivdep + for( int n=np; n--; ){ + float v = *infptr; + *(infptr++) = 1.0 - v; + } +} + + + +// Resize image using nearest neighbour interpolation +void filter_interpolate_nearestneighbour( RawTilePtr in, unsigned int resampled_width, unsigned int resampled_height ){ + + // Pointer to input buffer + unsigned char *input = (unsigned char*) in->data; + + int channels = in->channels; + unsigned int width = in->width; + unsigned int height = in->height; + + // Pointer to output buffer + unsigned char *output; + + // Create new buffer if size is larger than input size + bool new_buffer = false; + if( resampled_width*resampled_height > in->width*in->height ){ + new_buffer = true; + output = new unsigned char[resampled_width*resampled_height*in->channels]; + } + else output = (unsigned char*) in->data; + + // Calculate our scale + float xscale = (float)width / (float)resampled_width; + float yscale = (float)height / (float)resampled_height; + + for( unsigned int j=0; jchannels; k++ ){ + output[resampled_index+k] = input[pyramid_index+k]; + } + } + } + + // Delete original buffer + if( new_buffer ) delete[] (unsigned char*) input; + + // Correctly set our Rawtile info + in->width = resampled_width; + in->height = resampled_height; + in->dataLength = resampled_width * resampled_height * channels * in->bpc/8; + in->data = output; +} + + + +// Resize image using bilinear interpolation +// - Floating point implementation which benchmarks about 2.5x slower than nearest neighbour +void filter_interpolate_bilinear( RawTilePtr in, unsigned int resampled_width, unsigned int resampled_height ){ + + // Pointer to input buffer + unsigned char *input = (unsigned char*) in->data; + + int channels = in->channels; + unsigned int width = in->width; + unsigned int height = in->height; + + // Create new buffer and pointer for our output + unsigned char *output = new unsigned char[resampled_width*resampled_height*in->channels]; + + // Calculate our scale + float xscale = (float)(width-1) / (float)resampled_width; + float yscale = (float)(height-1) / (float)resampled_height; + + // Index for our output buffer + unsigned int resampled_index = 0; + + for( unsigned int j=0; jchannels; k++ ){ + float tx = input[p11+k]*a + input[p21+k]*b; + float ty = input[p12+k]*a + input[p22+k]*b; + unsigned char r = (unsigned char)( c*tx + d*ty ); + output[resampled_index++] = r; + } + } + } + + // Delete original buffer + delete[] (unsigned char*) input; + + // Correctly set our Rawtile info + in->width = resampled_width; + in->height = resampled_height; + in->dataLength = resampled_width * resampled_height * channels * in->bpc/8; + in->data = output; +} + + + +// Function to apply a contrast adjustment and clip to 8 bit +void filter_contrast( RawTilePtr in, float c ){ + + unsigned int np = in->dataLength * 8 / in->bpc; + + unsigned char* buffer = new unsigned char[np]; + + float* infptr = (float*)in->data; + +#pragma ivdep + for( unsigned int n=0; ndata; + in->data = buffer; + in->bpc = 8; + in->dataLength = np * in->bpc/8; +} + + + +// Gamma correction +void filter_gamma( RawTilePtr in, float g ){ + + float* infptr; + unsigned int np = in->dataLength * 8 / in->bpc; + + if( g == 1.0 ) return; + + infptr = (float*)in->data; + + // Loop through our pixels for floating values +#pragma ivdep + for(int n=np; n--;){ + float v = *infptr; + *(infptr++) = powf( v<0.0 ? 0.0 : v, g ); + } +} + + + +// Rotation function +void filter_rotate( RawTilePtr in, float angle=0.0 ){ + + // Currently implemented only for rectangular rotations + if( (int)angle % 90 == 0 && (int)angle % 360 != 0 ){ + + // Intialize our counter + unsigned int n = 0; + + // Allocate memory for our temporary buffer - rotate function only ever operates on 8bit data + void *buffer = new unsigned char[in->width*in->height*in->channels]; + + // Rotate 90 + if( (int) angle % 360 == 90 ){ + for( unsigned int i=0; i < in->width; i++ ){ + for( int j=in->height-1; j>=0; j-- ){ + unsigned int index = (in->width*j + i)*in->channels; + for( int k=0; k < in->channels; k++ ){ + ((unsigned char*)buffer)[n++] = ((unsigned char*)in->data)[index+k]; + } + } + } + } + + // Rotate 270 + else if( (int) angle % 360 == 270 ){ + for( int i=in->width-1; i>=0; i-- ){ + for( unsigned int j=0; j < in->height; j++ ){ + unsigned int index = (in->width*j + i)*in->channels; + for( int k=0; k < in->channels; k++ ){ + ((unsigned char*)buffer)[n++] = ((unsigned char*)in->data)[index+k]; + } + } + } + } + + // Rotate 180 + else if( (int) angle % 360 == 180 ){ + for( int i=(in->width*in->height)-1; i >= 0; i-- ){ + unsigned index = i * in->channels; + for( int k=0; k < in->channels; k++ ){ + ((unsigned char*)buffer)[n++] = ((unsigned char*)in->data)[index+k]; + } + } + } + + // Delete old data buffer + delete[] (unsigned char*) in->data; + + // Assign new data to Rawtile + in->data = buffer; + + // For 90 and 270 rotation swap width and height + if( (int)angle % 180 == 90 ){ + unsigned int tmp = in->height; + in->height = in->width; + in->width = tmp; + } + } +} + + + +// Convert colour to grayscale using the conversion formula: +// Luminance = 0.2126*R + 0.7152*G + 0.0722*B +// Note that we don't linearize before converting +void filter_greyscale( RawTilePtr rawtile ){ + + if( rawtile->bpc != 8 || rawtile->channels != 3 ) return; + + unsigned int np = rawtile->width * rawtile->height; + unsigned char* buffer = new unsigned char[rawtile->width * rawtile->height]; + + // Calculate using fixed-point arithmetic + // - benchmarks to around 25% faster than floating point + unsigned int n = 0; + for( unsigned int i=0; idata)[n++]; + unsigned char G = ((unsigned char*)rawtile->data)[n++]; + unsigned char B = ((unsigned char*)rawtile->data)[n++]; + buffer[i] = (unsigned char)( ( 1254097*R + 2462056*G + 478151*B ) >> 22 ); + } + + // Delete our old data buffer and instead point to our grayscale data + delete[] (unsigned char*) rawtile->data; + rawtile->data = (void*) buffer; + + // Update our number of channels and data length + rawtile->channels = 1; + rawtile->dataLength = np; +} + + + +// Apply twist or channel recombination to colour or multi-channel image +void filter_twist( RawTilePtr rawtile, const vector< vector >& matrix ){ + + unsigned long np = rawtile->width * rawtile->height; + unsigned long n = 0; + + // Create temporary buffer for our calculated values + float* pixel = new float[rawtile->channels]; + + // Calculate the number of columns - limit to our number of channels if necessary + unsigned int ncols = (matrix.size()>(unsigned int)rawtile->channels) ? rawtile->channels : matrix.size(); + unsigned int* nrows = new unsigned int[ncols]; + + // Pre-calculate the size of each row + for( unsigned int i=0; i(unsigned int)rawtile->channels) ? rawtile->channels : matrix[i].size(); + } + + for( unsigned long i=0; idata)[n+j] : ((float*)rawtile->data)[n+j] * m; + } + } + } + + // Only write our values at the end as we reuse channel values several times during the twist loops + for( int k=0; kchannels; k++ ) ((float*)rawtile->data)[n++] = pixel[k]; + + } + delete[] nrows; + delete[] pixel; +} + + + +// Flatten a multi-channel image to a given number of bands by simply stripping +// away extra bands +void filter_flatten( RawTilePtr in, int bands ){ + + // We cannot increase the number of channels + if( bands >= in->channels ) return; + + unsigned long np = in->width * in->height; + unsigned long ni = 0; + unsigned long no = 0; + unsigned int gap = in->channels - bands; + + // Simply loop through assigning to the same buffer + for( unsigned long i=0; idata)[ni++] = ((unsigned char*)in->data)[no++]; + } + no += gap; + } + + in->channels = bands; + in->dataLength = ni * in->bpc/8; +} + + + +// Flip image in horizontal or vertical direction (0=horizontal,1=vertical) +void filter_flip( RawTilePtr in, int orientation ){ + + unsigned char* buffer = new unsigned char[in->width * in->height * in->channels]; + unsigned long n = 0; + + // Vertical + if( orientation == 2 ){ + for( int j=in->height-1; j>=0; j-- ){ + for( unsigned int i=0; iwidth; i++ ){ + unsigned long index = (in->width*j + i)*in->channels; + for( int k=0; kchannels; k++ ){ + buffer[n++] = ((unsigned char*)in->data)[index+k]; + } + } + } + } + // Horizontal + else{ + for( unsigned int j=0; jheight; j++ ){ + for( int i=in->width-1; i>=0; i-- ){ + unsigned long index = (in->width*j + i)*in->channels; + for( int k=0; kchannels; k++ ){ + buffer[n++] = ((unsigned char*)in->data)[index+k]; + } + } + } + } + + // Delete our old data buffer and instead point to our grayscale data + delete[] (unsigned char*) in->data; + in->data = (void*) buffer; +} diff --git a/iipsrv/src/Transforms.h b/iipsrv/src/Transforms.h new file mode 100644 index 0000000..c5fd7eb --- /dev/null +++ b/iipsrv/src/Transforms.h @@ -0,0 +1,127 @@ +/* + Image Transforms + + Copyright (C) 2004-2013 Ruven Pillay. + + 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 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + + +#ifndef _TRANSFORMS_H +#define _TRANSFORMS_H + +#include +#include "RawTile.h" + +/// Function to create normalized array +/** @param in tile data to be adjusted + @param min : vector of minima + @param max : vector of maxima +*/ +void filter_normalize( RawTilePtr in, std::vector& max, std::vector& min ); + +/// Function to apply colormap to gray images +/// based on the routine colormap.cpp in Imagin Raytracer by Olivier Ferrand +/// http://www.imagin-raytracer.org +/** @param in tile data to be converted + @param cmap color map to apply. +*/ +enum cmap_type { HOT, COLD, JET, BLUE, GREEN, RED }; +void filter_cmap( RawTilePtr in, enum cmap_type cmap ); + +/// Function to invert colormaps +/** @param in tile data to be adjusted +*/ +void filter_inv( RawTilePtr in ); + + +/// Hillshading function to simulate raking light images +/** @param in tile input data containing normal vectors at each point + @param h_angle angle in the horizontal plane from 12 o'clock in degrees + @param v_angle angle in the vertical plane in degrees. 0 is flat, 90 pointing directly down. +*/ +void filter_shade( RawTilePtr in, int h_angle, int v_angle ); + + +/// Convert from CIELAB to sRGB colour space +/** @param in tile data to be converted */ +void filter_LAB2sRGB( RawTilePtr in ); + + +/// Function to apply a contrast adjustment and clip to 8 bit +/** @param in tile data to be adjusted + @param c contrast value +*/ +void filter_contrast( RawTilePtr in, float c ); + + +/// Apply a gamma correction +/** @param in tile input data + @param g gamma +*/ +void filter_gamma( RawTilePtr in, float g ); + + +/// Resize image using nearest neighbour interpolation +/** @param in tile input data + @param w target width + @param h target height +*/ +void filter_interpolate_nearestneighbour( RawTilePtr in, unsigned int w, unsigned int h ); + + +/// Resize image using bilinear interpolation +/** @param in tile input data + @param w target width + @param h target height +*/ +void filter_interpolate_bilinear( RawTilePtr in, unsigned int w, unsigned int h ); + + +/// Rotate image - currently only by 90, 180 or 270 degrees, other values will do nothing +/** @param in tile input data + @param angle angle of rotation - currently only rotations by 90, 180 and 270 degrees + are suported, for other values, no rotation will occur +*/ +void filter_rotate( RawTilePtr in, float angle ); + + +/// Convert image to grayscale +/** @param in input image */ +void filter_greyscale( RawTilePtr in ); + + +/// Apply a color twist +/** @param in input image + @param ctw 2D color twist matrix +*/ +void filter_twist( RawTilePtr in, const std::vector< std::vector >& ctw ); + + +/// Extract bands +/** @param in input image + @param bands number of bands +*/ +void filter_flatten( RawTilePtr in, int bands ); + + +///Flip image +/** @param in input image + @param o orientation (0=horizontal,1=vertical) +*/ +void filter_flip( RawTilePtr in, int o ); + + +#endif diff --git a/iipsrv/src/URL.h b/iipsrv/src/URL.h new file mode 100644 index 0000000..220b119 --- /dev/null +++ b/iipsrv/src/URL.h @@ -0,0 +1,139 @@ +/* + Simple URL decoder Class + + Copyright (C) 2014 Ruven Pillay. + + 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 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + + +#ifndef _URL_H +#define _URL_H + +#include +#include + + +/// Simple utility class to decode and filter URLs + +class URL{ + + private: + + /// URL string + std::string url; + + /// Warning + std::string warning_message; + + // Internal utility function to decode hex values + char hexToChar( char first, char second ); + + public: + + /// Constructor + /** @param s input url string */ + URL( std::string s ){ url = s; }; + + /// Decode and filter URL + std::string decode(); + + /// String escaping for JSON etc + std::string Escape(); + + /// Return any warning message + std::string warning(){ return warning_message; }; + +}; + + +inline char URL::hexToChar( char first, char second ){ + int digit; + digit = (first >= 'A' ? ((first & 0xDF) - 'A') + 10 : (first - '0')); + digit *= 16; + digit += (second >= 'A' ? ((second & 0xDF) - 'A') + 10 : (second - '0')); + return static_cast(digit); +} + + +// The argument is a URL path, which may contain spaces or other hex encoded characters. +// So, first decode and filter this path (implementation taken from GNU cgicc: http://www.cgicc.org) +inline std::string URL::decode() +{ + std::string argument; + std::string::iterator iter; + char c; + + for(iter = url.begin(); iter != url.end(); ++iter) { + switch(*iter) { + case '+': + argument.append(1,' '); + break; + case '%': + // Don't assume well-formed input + if( std::distance(iter, url.end()) >= 2 && + std::isxdigit(*(iter + 1)) && std::isxdigit(*(iter + 2)) ){ + + // Filter out embedded NULL bytes of the form %00 from the URL + if( (*(iter+1)=='0' && *(iter+2)=='0') ){ + warning_message = "Warning! Detected embedded NULL byte in URL: " + url; + // Wind forward our iterator + iter+=2; + } + // Otherwise decode the character + else{ + c = *++iter; + argument.append(1,hexToChar(c,*++iter)); + } + } + // Just pass the % through untouched + else { + argument.append(1,'%'); + } + break; + + default: + argument.append(1,*iter); + break; + } + } + + return argument; +} + + +// Escape strings for JSON etc. +inline std::string URL::Escape() +{ + std::string json; + + for( unsigned int i=0; i +using namespace std; + + +void View::calculateResolution( unsigned int dimension, + unsigned int requested_size ){ + + unsigned int j = 1; + unsigned int d = dimension; + + // Calculate the resolution number for this request + while( d >= requested_size ){ + d = d/2; + j++; + } + + // Limit j to the maximum resolution + if( j > max_resolutions+1 ) j = max_resolutions + 1; + + // Only set this if our requested resolution is greater than that + // that has already been set. + if( resolution > (int)max_resolutions - (int)j + 1 ) resolution = (int)max_resolutions - (int)j + 1; + + // Make sure our value is possible + if( resolution > (signed int)(max_resolutions-1) ) resolution = max_resolutions - 1; + if( resolution < 0 ) resolution = 0; + +} + + +unsigned int View::getResolution(){ + + unsigned int i; + + resolution = max_resolutions - 1; + + // Note that we use floor() as that is how our resolutions are calculated + if( requested_width ) View::calculateResolution( width, floor((float)requested_width/(float)view_width) ); + if( requested_height ) View::calculateResolution( height, floor((float)requested_height/(float)view_height) ); + + res_width = width; + res_height = height; + + // Caluclate our new width and height based on the calculated resolution + for( i=1; i < (max_resolutions - resolution); i++ ){ + res_width = (int) floor(res_width / 2.0); + res_height = (int) floor(res_height / 2.0); + } + + // Check if we need to use a smaller resolution due to our max size limit + float scale = getScale(); + + if( (res_width*view_width*scale > max_size) || (res_height*view_height*scale > max_size) ){ + int dimension; + if( (res_width*view_width/max_size) > (res_height*view_width/max_size) ){ + dimension = (int) (res_width*view_width*scale); + } + else{ + dimension = (int) (res_height*view_height*scale); + } + + i = 1; + while( (dimension / i) > max_size ){ + dimension /= 2; + res_width = (int) floor(width / 2.0); + res_height = (int) floor(height / 2.0 ); + resolution--; + } + } + + return resolution; + +} + + +float View::getScale(){ + + unsigned int rw; + unsigned int rh; + if( requested_width == 0 && requested_height > 0 ){ + rw = static_cast( round(res_width * requested_height / res_height) ); + } + else rw = requested_width; + + if( requested_height == 0 && requested_width > 0 ){ + rh = static_cast( round( res_height * requested_width / res_width ) ); + } + else rh = requested_height; + + float scale = static_cast(rw) / static_cast(width); + + if( static_cast(rh) / static_cast(res_height) < scale ) scale = static_cast(rh) / static_cast(res_height); + + // Sanity check + if( scale <= 0 || scale > 1.0 ) scale = 1.0; + return scale; + +} + + +void View::setViewLeft( float x ) { + if( x > 1.0 ) view_left = 1.0; + else if( x < 0.0 ) view_left = 0.0; + else view_left = x; +} + + +void View::setViewTop( float y ) { + if( y > 1.0 ) view_top = 1.0; + else if( y < 0.0 ) view_top = 0.0; + else view_top = y; +} + + +void View::setViewWidth( float w ) { + if( w > 1.0 ) view_width = 1.0; + else if( w < 0.0 ) view_width = 0.0; + else view_width = w; +} + + +void View::setViewHeight( float h ) { + if( h > 1.0 ) view_height = 1.0; + else if( h < 0.0 ) view_height = 0.0; + else view_height = h; +} + + +bool View::viewPortSet() { + if( (view_width < 1.0) || (view_height < 1.0) || + (view_left > 0.0) || (view_top > 0.0) ){ + return true; + } + else return false; +} + + +unsigned int View::getViewLeft(){ + // Scale up our view to a real pixel value. + // Note that we calculate from our full resolution image to avoid errors from the rounding at each resolution size + unsigned int l = round( width*view_left/pow(2.0, max_resolutions-resolution-1) ); + return l; +} + + +unsigned int View::getViewTop(){ + // Scale up our view to a real pixel value + // Note that we calculate from our full resolution image to avoid errors from the rounding at each resolution size + unsigned int t = round( height*view_top/pow(2.0, max_resolutions-resolution-1) ); + return t; +} + + +unsigned int View::getViewWidth(){ + + // Scale up our viewport, then make sure our size is not too large or too small + unsigned int rw = width / pow(2.0, max_resolutions-resolution-1); + unsigned int w = round( view_width*rw ); + unsigned int left = (unsigned int) round( view_left*rw ); + + if( (w + left) > rw ) w = rw - left; + if( w < min_size ) w = min_size; + return w; +} + + +unsigned int View::getViewHeight(){ + + // Scale up our viewport, then make sure our size is not too large or too small + unsigned int rh = height / pow(2.0, max_resolutions-resolution-1); + unsigned int h = (unsigned int) round( view_height*rh ); + unsigned int top = (unsigned int) round( view_top*rh ); + + if( (h + top) > rh ) h = rh - top; + if( h < min_size ) h = min_size; + return h; +} + + +unsigned int View::getRequestWidth(){ + + // If our requested width has not been set, but height has, return a width proportional to + // this requested height + unsigned int w = requested_width; + if( requested_width == 0 ){ + if( requested_height != 0 ){ + w = (unsigned int) round( (float)(getViewWidth()*requested_height) / (float)getViewHeight() ); + } + + // If no width or height has been set, use the full image size + else if( requested_height==0 ) w = width; + } + + // Limit our requested width to the maximum export size + if( w > max_size ) w = max_size; + + return w; +} + + +unsigned int View::getRequestHeight(){ + + // If our requested height has not been set, but the width has, return a height proportional to + // this requested width + unsigned int h = requested_height; + if( requested_height == 0 ){ + if( requested_width != 0 ){ + h = (unsigned int) round( (float)(getViewHeight()*requested_width) / (float)getViewWidth() ); + } + + // If no width or height has been set, use the full image size + else if( requested_width==0 ) h = height; + } + + // Limit our requested height to the maximum export size + if( h > max_size ) requested_height = max_size; + + return h; +} + + +/// Return the number of layers to decode +int View::getLayers(){ + // If max_layers is set, limit to this value, otherwise return layers + if( max_layers > 0 ){ + return ((layers>0)&&(layers +#include + +#include "Transforms.h" + +//include round function for MSVC compiler +#if _MSC_VER +#include "../windows/Time.h" +#endif + + + + +/// Class to intelligently handle Image Transforms + +class View{ + + + private: + + // Resolution independent x,y,w,h region viewport + float view_left, view_top, view_width, view_height; /// viewport + + int resolution; /// Requested resolution + unsigned int max_resolutions; /// Total available resolutions + unsigned int width, height; /// Image width and height at full resolution + unsigned int res_width, res_height; /// Width and height at requested resolution + unsigned int min_size; /// Minimum viewport dimension + unsigned int max_size; /// Maximum viewport dimension + unsigned int requested_width; /// Width requested by WID command + unsigned int requested_height; /// Height requested by HEI command + float contrast; /// Contrast adjustment requested by CNT command + float gamma; /// Gamma adjustment requested by GAM command + float rotation; /// Rotation requested by ROT command + + + /// Internal function to calculate the resolution associated with a width + /// or height request. This also takes into account maximum size limits. + /** @param m maximum size + @param r requested size + */ + void calculateResolution( unsigned int m, unsigned int r ); + + + public: + + int xangle; /// Horizontal View + int yangle; /// Vertical View + bool shaded; /// Whether to use shading view + int shade[3]; /// Shading incident light angles (x,y,z) + bool cmapped; /// Whether to modify colormap + enum cmap_type cmap; /// colormap + bool inverted; /// Whether to invert colormap + int max_layers; /// Maximum number of quality layers allowed + int layers; /// Number of quality layers + ColourSpaces colourspace; /// Requested colourspace + std::vector< std::vector > ctw; /// Colour twist matrix + int flip; /// Flip (1=horizontal, 2=vertical) + bool maintain_aspect; /// Indicate whether aspect ratio should be maintained + + + /// Constructor + View() { + view_left = 0.0; view_top = 0.0; view_width = 1.0; view_height = 1.0; + resolution = 0; max_resolutions = 0; + width = 0; height = 0; + res_width = 0; res_height = 0; + min_size = 8; max_size = 0; + requested_width = 0; requested_height = 0; + contrast = 1.0; gamma = 1.0; + xangle = 0; yangle = 90; + shaded = false; shade[0] = 0; shade[1] = 0; shade[2] = 0; + cmapped = false; inverted = false; + max_layers = 0; layers = 0; + rotation = 0.0; flip = 0; + maintain_aspect = true; + colourspace = NONE; + }; + + + /// Set the contrast adjustment + /** @param c contrast (where 1.0 is no adjustment) */ + void setContrast( float c ){ contrast = c; }; + + + /// Set the maximum view port dimension + /** @param m maximum viewport dimension */ + void setMaxSize( unsigned int m ){ max_size = m; }; + + + /// Set the maximum view port dimension + /** @param r number of availale resolutions */ + void setMaxResolutions( unsigned int r ){ max_resolutions = r; resolution=r-1; }; + + + /// Get the size of the requested width + /* @return requested width */ + unsigned int getRequestWidth(); + + + /// Set the size of the requested width + /** @param w requested image width */ + void setRequestWidth( unsigned int w ){ + if( (max_size > 0) && (w > max_size) ) requested_width = max_size; + else requested_width = w; + }; + + + /// Get the size of the requested height + /* @return requested height */ + unsigned int getRequestHeight(); + + + /// Set the size of the requested height + /** @param h requested image height */ + void setRequestHeight( unsigned int h ){ + if( (max_size > 0) && (h > max_size) ) requested_height = max_size; + else requested_height = h; + }; + + + /// Return the requested resolution + /* @return requested resolution level */ + unsigned int getResolution(); + + + /// Return the scaling required in case our requested width or height is in between available resolutions + /* @return scaling factor */ + float getScale(); + + + /// Set the left co-ordinate of the viewport + /** @param x left resolution independent co-ordinate */ + void setViewLeft( float x ); + + + /// Set the top co-ordinate of the viewport + /** @param y top resolution independent co-ordinate */ + void setViewTop( float y ); + + + /// Set the width co-ordinate of the viewport + /** @param w width resolution independent co-ordinate */ + void setViewWidth( float w ); + + + /// Set the height co-ordinate of the viewport + /** @param h height resolution independent co-ordinate */ + void setViewHeight( float h ); + + + /// Set the source image pixel size + /** @param w pixel width + @param h pixel height + */ + void setImageSize( unsigned int w, unsigned int h ){ width = w; height = h; }; + + + /// Limit the maximum number of quality layers we are allowed to decode + /** @param l Max number of layers to decode */ + void setMaxLayers( int l ){ max_layers = l; }; + + /// Set the number of quality layers to decode, limiting to our max value + /** @param l Number of layers to decode */ + void setLayers( int l ){ layers = l; }; + + /// Return the number of layers to decode + int getLayers(); + + /// Return the contrast adjustment + /* @return requested contrast */ + float getContrast(){ return contrast; }; + + /// Return the image width at our requested resolution + /* @return image width */ + unsigned int getImageWidth(){ return width; }; + + /// Return the image height at our requested resolution + /* @return image height */ + unsigned int getImageHeight(){ return height; }; + + /// Return the left pixel of the viewport + /* @return position of left of viewport in pixels */ + unsigned int getViewLeft() ; + + /// Return the top pixel of the viewport + /* @return position of top of viewport in pixels */ + unsigned int getViewTop(); + + /// Return the pixel width of the viewport + /* @return width of viewport in pixels */ + unsigned int getViewWidth(); + + /// Return the pixel height of the viewport + /* @return height of viewport in pixels */ + unsigned int getViewHeight(); + + /// Indicate whether the viewport has been set + /* @return boolean indicating whether viewport specified */ + bool viewPortSet(); + + /// Set gamma + /** @param g gamma value */ + void setGamma( float g ){ gamma = g; }; + + /// Get gamma + /* @return requested gamma */ + float getGamma(){ return gamma; }; + + /// Set rotation + /** @param r angle of rotation in degrees */ + void setRotation( float r ){ rotation = r; }; + + /// Get rotation + /* @return requested rotation angle in degrees */ + float getRotation(){ return rotation; }; + +}; + + +#endif diff --git a/iipsrv/src/Watermark.cc b/iipsrv/src/Watermark.cc new file mode 100644 index 0000000..36ab960 --- /dev/null +++ b/iipsrv/src/Watermark.cc @@ -0,0 +1,148 @@ +/* + IIPImage Server - Member functions for Watermark.h + + Development supported by Moravian Library in Brno (Moravska zemska + knihovna v Brne, http://www.mzk.cz/) R&D grant MK00009494301 & Old + Maps Online (http://www.oldmapsonline.org/) from the Ministry of + Culture of the Czech Republic. + + + Copyright (C) 2010-2013 Ruven Pillay. + + 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 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + + +#include "Watermark.h" +#include +#include +#include +#include + + + +// Load up and initialize our watermark image +void Watermark::init() +{ + if( _image.length() > 0 ){ + + TIFF *tiff_watermark; + if( ( tiff_watermark = TIFFOpen( _image.c_str(), "r" ) ) ){ + + TIFFGetField( tiff_watermark, TIFFTAG_IMAGEWIDTH, &_width ); + TIFFGetField( tiff_watermark, TIFFTAG_IMAGELENGTH, &_height ); + TIFFGetField( tiff_watermark, TIFFTAG_BITSPERSAMPLE, &_bpc ); + + uint32 *buffer = new uint32[_width*_height]; + + if( TIFFReadRGBAImageOriented( tiff_watermark, _width, _height, buffer, ORIENTATION_TOPLEFT ) == 0 ){ + delete[] buffer; + TIFFClose( tiff_watermark ); + return; + } + + // Set our number of channels to 3 as TIFFReadRGBAImage always outputs an 8bit colour image + _channels = 3; + + // Set up the memory storage + _watermark = new unsigned char[_width*_height*_channels]; + memset( _watermark, 0, _width*_height*_channels ); + + // Load the data into our buffers + for( uint32 i=0; i<_width*_height; i++ ){ + uint32 rgba = buffer[i]; + unsigned char r,g,b; + float a; + // Extract the RGBA values + r = (unsigned char) TIFFGetR(rgba); + g = (unsigned char) TIFFGetG(rgba); + b = (unsigned char) TIFFGetB(rgba); + a = (float) TIFFGetA(rgba) / 255; + _watermark[i*3] = r * _opacity * a; + _watermark[i*3 + 1] = g * _opacity * a; + _watermark[i*3 + 2] = b * _opacity * a; + } + + delete[] buffer; + TIFFClose( tiff_watermark ); + _isSet = true; + } + + } + +} + + + +// Apply the watermark to a buffer of data +void Watermark::apply( void* data, unsigned int width, unsigned int height, unsigned int channels, unsigned int bpc ) +{ + + // Sanity check + if( !_isSet || (_probability==0) || (_opacity==0) ) return; + + // Get random number as a float between 0 and 1 + float random = (float) rand() / RAND_MAX; + + // Only apply if our random number is less than our given probability + if( random < _probability ){ + + // Vary watermark position randomly within the tile depending on available space + unsigned int xoffset = 0; + if( width > _width ){ + random = (float) rand() / RAND_MAX; + xoffset = random * (width - _width); + } + + unsigned int yoffset = 0; + if( height > _height ){ + random = (float) rand() / RAND_MAX; + yoffset = random * (height - _height); + } + + // Limit the area of the watermark to the size of the tile + unsigned int xlimit = _width; + unsigned int ylimit = _height; + if( _width > width ) xlimit = width; + if( _height > height ) ylimit = height; + + for( unsigned int j=0; j 65535 ) t = 65535; + d[id] = (unsigned short) t; + } + // TIFFReadRGBAImage always scales to 8bit, so never any need for downscaling, but clip to 255 + // We do our maths in unsigned short to allow us to clip correctly after + else{ + unsigned char* d = (unsigned char*) data; + unsigned short t = (unsigned short)( d[id] + _watermark[j*_width*_channels + i*_channels + k] ); + if( t > 255 ) t = 255; + d[id] = (unsigned char) t; + } + } + } + } + } + +} diff --git a/iipsrv/src/Watermark.h b/iipsrv/src/Watermark.h new file mode 100644 index 0000000..af62535 --- /dev/null +++ b/iipsrv/src/Watermark.h @@ -0,0 +1,136 @@ +/* + IIPImage Server - Watermark Class + + Enables dynamic watermarking of images with user-defined opacity and + random positioning within the image. + + Development supported by Moravian Library in Brno (Moravska zemska + knihovna v Brne, http://www.mzk.cz/) R&D grant MK00009494301 & Old + Maps Online (http://www.oldmapsonline.org/) from the Ministry of + Culture of the Czech Republic. + + + Copyright (C) 2010-2013 Ruven Pillay. + + 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 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + + + +#ifndef _WATERMARK_H +#define _WATERMARK_H + +#include + + + +/// Watermark class + +class Watermark { + + private: + + /// Width of watermark image + unsigned int _width; + + /// Height of watermark image + unsigned int _height; + + /// Number of colour channels in image + unsigned int _channels; + + /// Number of bits per channel + unsigned int _bpc; + + /// Watermark file + std::string _image; + + /// Watermark opacity + float _opacity; + + /// Watermark probability + float _probability; + + /// Whether we have a valid watermark + bool _isSet; + + /// Our watermark buffer + unsigned char* _watermark; + + + public: + + /// Constructor + Watermark(){ + _isSet=false; + _watermark = NULL; + _opacity = 0.0; + _probability = 0.0; + }; + + /// Constructor + /** @param file image file path + @param opacity opacity applied to watermark + @param probability probability that watermark will be applied to a particular tile + */ + Watermark( const std::string& file, float opacity, float probability ){ + _image = file; + _width = 0; + _height = 0; + _channels = 0; + _bpc = 0; + _opacity = opacity; + _probability = probability; + _isSet = false; + _watermark = NULL; + }; + + /// Destructor + ~Watermark(){ + if( _watermark ) delete[] _watermark; + }; + + /// Apply the watermark to a data buffer + /** @param data buffer of image data + @param width tile width + @param height tile height + @param channels number of channels + @param bpc bits per channel (8 or 16) + */ + void apply( void* data, unsigned int width, unsigned int height, unsigned int channels, unsigned int bpc ); + + /// Return watermark image path + std::string getImage(){ return _image; }; + + /// Return watermark opacity + float getOpacity(){ return _opacity; }; + + /// Return watermark probability + float getProbability(){ return _probability; }; + + /// Initialize our watermark image + void init(); + + /// Determine whether a watermark has been specified + bool isSet(){ + if( _isSet ) return true; + else return false; + } + +}; + + + +#endif diff --git a/iipsrv/src/Writer.h b/iipsrv/src/Writer.h new file mode 100644 index 0000000..acc567e --- /dev/null +++ b/iipsrv/src/Writer.h @@ -0,0 +1,140 @@ +/* + IIP Generic Output Writer Classes + + Copyright (C) 2006-2013 Ruven Pillay. + + 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 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + + +#ifndef _WRITER_H +#define _WRITER_H + + +#include +#include + + +/// Virtual base class for various writers +class Writer { + + public: + + virtual ~Writer() = 0; + + /// Write out a binary string + /** \param msg message string + \param len message string length + */ + virtual int putStr( const char* msg, int len ) = 0; + + /// Write out a string + /** \param msg message string */ + virtual int putS( const char* msg ) = 0; + + /// Write out a string + /** \param msg message string */ + virtual int printf( const char* msg ) = 0; + + /// Flush the output buffer + virtual int flush() = 0; + +}; + + + +/// FCGI Writer Class +class FCGIWriter { + + private: + + + FCGX_Stream *out; + static const unsigned int bufsize = 65536; + + /// Add the message to our buffer + void cpy2buf( const char* msg, size_t len ){ + if( sz+len > bufsize ) buffer = (char*) realloc( buffer, sz+len ); + if( buffer ){ + memcpy( &buffer[sz], msg, len ); + sz += len; + } + }; + + + public: + + char* buffer; + size_t sz; + + /// Constructor + FCGIWriter( FCGX_Stream* o ){ + out = o; + buffer = (char*) malloc(bufsize); + sz = 0; + }; + + /// Destructor + ~FCGIWriter(){ if(buffer) free(buffer); }; + + int putStr( const char* msg, int len ){ + cpy2buf( msg, len ); + return FCGX_PutStr( msg, len, out ); + }; + int putS( const char* msg ){ + cpy2buf( msg, strlen(msg) ); + return FCGX_PutS( msg, out ); + } + int printf( const char* msg ){ + cpy2buf( msg, strlen(msg) ); + return FCGX_FPrintF( out, msg ); + }; + int flush(){ + return FCGX_FFlush( out ); + }; + +}; + + + +/// File Writer Class +class FileWriter { + + private: + + FILE* out; + + public: + + FileWriter( FILE* o ){ out = o; }; + + int putStr( const char* msg, int len ){ + return fwrite( (void*) msg, sizeof(char), len, out ); + }; + int putS( const char* msg ){ + return fputs( msg, out ); + } + int printf( const char* msg ){ + return fprintf( out, "%s", msg ); + }; + int flush(){ + return fflush( out ); + }; + +}; + + + +#endif diff --git a/iipsrv/src/Zoomify.cc b/iipsrv/src/Zoomify.cc new file mode 100644 index 0000000..f52378b --- /dev/null +++ b/iipsrv/src/Zoomify.cc @@ -0,0 +1,169 @@ +/* + IIP Zoomify Request Command Handler Class Member Function + + * Development carried out thanks to R&D grant DC08P02OUK006 - Old Maps Online * + * (www.oldmapsonline.org) from Ministry of Culture of the Czech Republic * + + + Copyright (C) 2008-2014 Ruven Pillay. + + 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 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +#include + +#include "Task.h" +#include "Transforms.h" +#include "Tokenizer.h" + + + +using namespace std; + + + +void Zoomify::run( Session* session, const std::string& argument ){ + + if( session->loglevel >= 3 ) (*session->logfile) << "Zoomify handler reached" << endl; + + // Time this command + if( session->loglevel >= 2 ) command_timer.start(); + + + // The argument is in the form Zoomify=TileGroup0/r-x-y.jpg where r is the resolution + // number and x and y are the tile coordinates starting from the bottom left. + string prefix, suffix; + suffix = argument.substr( argument.find_last_of( "/" )+1, argument.length() ); + + // We need to extract the image path, which is not always the same + if( suffix == "ImageProperties.xml" ) + prefix = argument.substr( 0, argument.find_last_of( "/" ) ); + else + prefix = argument.substr( 0, argument.find( "TileGroup" )-1 ); + + + // As we don't have an independent FIF request, we need to run it now + FIF fif; + fif.run( session, prefix ); + + + // Get the full image size and the total number of resolutions available + unsigned int width = (session->image)->getImageWidth(); + unsigned int height = (session->image)->getImageHeight(); + + + unsigned int tw = (session->image)->getTileWidth(); + unsigned int numResolutions = (session->image)->getNumResolutions(); + + + // Zoomify does not accept arbitrary numbers of resolutions. The lowest + // level must be the largest size that can fit within a single tile, so + // we must discard any smaller than this + unsigned int n; + + unsigned int discard = 0; + + // compute the number of resolutions where there would be more than 1 tile. + for( n=numResolutions - 1; n >= 0; --n ){ + if( (session->image)->image_widths[n] < tw && (session->image)->image_heights[n] < tw ){ + discard++; + } else { + break; + } + } + + // keep the largest that fits inside a single tile. + if( discard > 0 ) discard -= 1; + + if( session->loglevel >= 2 ){ + if( discard > 0 ){ + *(session->logfile) << "Zoomify :: Discarding " << discard << " resolutions that are too small for Zoomify" << endl; + } + } + + // Zoomify clients have 2 phases, the initialization phase where they request + // an XML file containing image data and the tile requests themselves. + // These 2 phases are handled separately + if( suffix == "ImageProperties.xml" ){ + + if( session->loglevel >= 2 ){ + *(session->logfile) << "Zoomify :: ImageProperties.xml request" << endl; + *(session->logfile) << "Zoomify :: Total resolutions: " << numResolutions << ", image width: " << width + << ", image height: " << height << endl; + } + + int ntiles = (int) ceil( (double)width/tw ) * (int) ceil( (double)height/tw ); + + char str[1024]; + snprintf( str, 1024, + "Server: iipsrv/%s\r\n" + "Content-Type: application/xml\r\n" + "Cache-Control: max-age=%d\r\n" + "Last-Modified: %s\r\n" + "\r\n" + "", + VERSION, MAX_AGE,(session->image)->getTimestamp().c_str(), width, height, ntiles, tw ); + + session->out->printf( (const char*) str ); + session->response->setImageSent(); + + return; + } + + + // Get the tile coordinates. Zoomify requests are of the form r-x-y.jpg + // where r is the resolution number and x and y are the tile coordinates + Tokenizer izer( suffix, "-" ); + int resolution=0, x=0, y=0; + if( izer.hasMoreTokens() ) resolution = atoi( izer.nextToken().c_str() ); + if( izer.hasMoreTokens() ) x = atoi( izer.nextToken().c_str() ); + if( izer.hasMoreTokens() ) y = atoi( izer.nextToken().c_str() ); + + // Bump up to take account of any levels too small for Zoomify + resolution += discard; + + if( session->loglevel >= 2 ){ + *(session->logfile) << "Zoomify :: Tile request for resolution:" + << resolution << " at x:" << x << ", y:" << y << endl; + } + + + // Get the width and height for the requested resolution + width = (session->image)->getImageWidth(numResolutions-resolution-1); + height = (session->image)->getImageHeight(numResolutions-resolution-1); + + + // Get the width of the tiles and calculate the number + // of tiles in each direction + unsigned int rem_x = width % tw; + unsigned int ntlx = (width / tw) + (rem_x == 0 ? 0 : 1); + + + // Calculate the tile index for this resolution from our x, y + unsigned int tile = y*ntlx + x; + + + // Simply pass this on to our JTL send command + JTL jtl; + jtl.send( session, resolution, tile ); + + + // Total Zoomify response time + if( session->loglevel >= 2 ){ + *(session->logfile) << "Zoomify :: Total command time " << command_timer.getTime() << " microseconds" << endl; + } + + +} diff --git a/iipsrv/windows/MemcachedWindows.h b/iipsrv/windows/MemcachedWindows.h new file mode 100644 index 0000000..768f819 --- /dev/null +++ b/iipsrv/windows/MemcachedWindows.h @@ -0,0 +1,160 @@ +// Simple Wrapper to MemCacheClient + +/* IIP Image Server + + Copyright (C) 2010 Ruven Pillay, Michal Becak. + + 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 +*/ + + + +#ifndef _MEMCACHED_WINDOWS_H +#define _MEMCACHED_WINDOWS_H + +#include +#include +#include +#include "MemCacheClient.h" + +#ifdef WIN32 +#pragma comment(lib, "ws2_32.lib") +#endif + +/// Cache to store raw tile data + +class Memcache { + + + private: + + /// Memcached structure + MemCacheClient *_memc; + + /// Memcached return value + MCResult _rc; + + /// Memcached servers + std::vector *_servers; + + /// Cache expiry set to 1 hour + time_t _timeout; + + /// Length of data returned + size_t _length; + + /// Flag whether we are connected + bool _connected; + + + public: + + /// Constructor + /** @param servernames list of memcached servers + @param timeout memcached timeout - defaults to 1 hour (3600 seconds) + */ + Memcache( const std::string& servernames = "localhost", unsigned int timeout = 3600 ) { + + // Create our memcached object + _memc = new MemCacheClient; + + // Set our timeout + _timeout = timeout; + _memc->SetTimeout(timeout); + + // Create a list of servers + _servers = new std::vector(); + //split string on ',' and save chunks to vector + std::stringstream ss(servernames); + std::string serverItem; + while(std::getline(ss, serverItem, ',')) { + if (serverItem == "localhost")//MemCacheClient needs ip address, so we map localhost to 127.0.0.1 + serverItem = "127.0.0.1"; + _servers->push_back(serverItem); + } + + // Connect to the servers + _connected = false; + for (int i = 0; i < _servers->size(); i++) { + _connected = _connected || _memc->AddServer(_servers->at(i).c_str()); + } + }; + + + /// Destructor + ~Memcache() { + // Disconnect from our servers and free our memcached structure + if( _servers ) { + delete _servers; + _servers = NULL; + } + if( _memc ) _memc->~MemCacheClient(); + } + + + /// Insert data into our cache + /** @param key key used for cache + @param data pointer to the data to be stored + @param length length of data to be stored + */ + void store( const std::string& key, void* data, unsigned int length ){ + + if( !_connected ) return; + + MemCacheClient::MemRequest req; + req.mKey = "iipsrv::" + key; + req.mData.WriteBytes(data, length); + _memc->Set(req); + _rc = req.mResult; + } + + + /// Retrieve data from our cache + /** @param key key for cache data + @return pointer to data + */ + char* retrieve( const std::string& key ){ + + if( !_connected ) return NULL; + + MemCacheClient::MemRequest req; + req.mKey = "iipsrv::" + key; + int result = _memc->Get(req); + if (result == 0)//if 0 items retrieved + return NULL; + _rc = req.mResult; + _length = req.mData.GetReadSize(); + char * returnData = new char[_length]; + req.mData.ReadBytes(returnData,_length); + return returnData; + } + + + /// Get error string + const char* error(){ + return _memc->ConvertResult(_rc); + }; + + + /// Return the number of bytes in the result + unsigned int length(){ return _length; }; + + + /// Tell us whether we are connected to any memcached servers + bool connected(){ return _connected; }; + +}; + +#endif diff --git a/iipsrv/windows/Time.cc b/iipsrv/windows/Time.cc new file mode 100644 index 0000000..e2eb828 --- /dev/null +++ b/iipsrv/windows/Time.cc @@ -0,0 +1,505 @@ +/* Missing time implementations for Windows + Code taken largely from rtmpserver (www.rtmpd.com) + + Copyright (C) 2011-2012 Ruven Pillay + 2010 Gavriloaie Eugen-Andrei + 1997, 1998 Kungliga Tekniska Hogskolan + (Royal Institute of Technology, Stockholm, Sweden) + + 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 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +#ifdef WIN32 + +#include +#include +#include +#include +#include +#include + + +int +strncasecmp(const char *s1, const char *s2, size_t n) +{ + while(n > 0 + && toupper((unsigned char)*s1) == toupper((unsigned char)*s2)) + { + if(*s1 == '\0') + return 0; + s1++; + s2++; + n--; + } + if(n == 0) + return 0; + return toupper((unsigned char)*s1) - toupper((unsigned char)*s2); +} + +int +gettimeofday(struct timeval *tv, struct timezone* tz) { + FILETIME ft; + GetSystemTimeAsFileTime(&ft); + __int64 value = ((__int64) ft.dwHighDateTime << 32) | ft.dwLowDateTime; + tv->tv_usec = (long) ((value / 10LL) % 1000000LL); + tv->tv_sec = (long) ((value - 116444736000000000LL) / 10000000LL); + return (0); +} + +static int +is_leap(unsigned y) +{ + y += 1900; + return (y % 4) == 0 && ((y % 100) != 0 || (y % 400) == 0); +} + +time_t +timegm (struct tm *tm) +{ + static const unsigned ndays[2][12] ={ + {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}, + {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}}; + time_t res = 0; + int i; + + for (i = 70; i < tm->tm_year; ++i) + res += is_leap(i) ? 366 : 365; + + for (i = 0; i < tm->tm_mon; ++i) + res += ndays[is_leap(tm->tm_year)][i]; + res += tm->tm_mday - 1; + res *= 24; + res += tm->tm_hour; + res *= 60; + res += tm->tm_min; + res *= 60; + res += tm->tm_sec; + return res; +} + +static const char *abb_weekdays[] = { + "Sun", + "Mon", + "Tue", + "Wed", + "Thu", + "Fri", + "Sat", + NULL +}; + +static const char *full_weekdays[] = { + "Sunday", + "Monday", + "Tuesday", + "Wednesday", + "Thursday", + "Friday", + "Saturday", + NULL +}; + +static const char *abb_month[] = { + "Jan", + "Feb", + "Mar", + "Apr", + "May", + "Jun", + "Jul", + "Aug", + "Sep", + "Oct", + "Nov", + "Dec", + NULL +}; + +static const char *full_month[] = { + "January", + "February", + "Mars", + "April", + "May", + "June", + "July", + "August", + "September", + "October", + "November", + "December", + NULL, +}; + +static const char *ampm[] = { + "am", + "pm", + NULL +}; + +/* + * Try to match `*buf' to one of the strings in `strs'. Return the + * index of the matching string (or -1 if none). Also advance buf. + */ + +static int +match_string (const char **buf, const char **strs) +{ + int i = 0; + + for (i = 0; strs[i] != NULL; ++i) { + int len = strlen (strs[i]); + + if (strncasecmp (*buf, strs[i], len) == 0) { + *buf += len; + return i; + } + } + return -1; +} + +/* + * tm_year is relative this year */ + +const int tm_year_base = 1900; + +/* + * Return TRUE iff `year' was a leap year. + */ + +static int +is_leap_year (int year) +{ + return (year % 4) == 0 && ((year % 100) != 0 || (year % 400) == 0); +} + +/* + * Return the weekday [0,6] (0 = Sunday) of the first day of `year' + */ + +static int +first_day (int year) +{ + int ret = 4; + + for (; year > 1970; --year) + ret = (ret + 365 + is_leap_year (year) ? 1 : 0) % 7; + return ret; +} + +/* + * Set `timeptr' given `wnum' (week number [0, 53]) + */ + +static void +set_week_number_sun (struct tm *timeptr, int wnum) +{ + int fday = first_day (timeptr->tm_year + tm_year_base); + + timeptr->tm_yday = wnum * 7 + timeptr->tm_wday - fday; + if (timeptr->tm_yday < 0) { + timeptr->tm_wday = fday; + timeptr->tm_yday = 0; + } +} + +/* + * Set `timeptr' given `wnum' (week number [0, 53]) + */ + +static void +set_week_number_mon (struct tm *timeptr, int wnum) +{ + int fday = (first_day (timeptr->tm_year + tm_year_base) + 6) % 7; + + timeptr->tm_yday = wnum * 7 + (timeptr->tm_wday + 6) % 7 - fday; + if (timeptr->tm_yday < 0) { + timeptr->tm_wday = (fday + 1) % 7; + timeptr->tm_yday = 0; + } +} + +/* + * Set `timeptr' given `wnum' (week number [0, 53]) + */ + +static void +set_week_number_mon4 (struct tm *timeptr, int wnum) +{ + int fday = (first_day (timeptr->tm_year + tm_year_base) + 6) % 7; + int offset = 0; + + if (fday < 4) + offset += 7; + + timeptr->tm_yday = offset + (wnum - 1) * 7 + timeptr->tm_wday - fday; + if (timeptr->tm_yday < 0) { + timeptr->tm_wday = fday; + timeptr->tm_yday = 0; + } +} + +/* + * + */ + +char * +strptime (const char *buf, const char *fmt, struct tm *timeptr) +{ + char c; + + for (; (c = *fmt) != '\0'; ++fmt) { + char *s; + int ret; + + if (isspace (c)) { + while (isspace (*buf)) + ++buf; + } else if (c == '%' && fmt[1] != '\0') { + c = *++fmt; + if (c == 'E' || c == 'O') + c = *++fmt; + switch (c) { + case 'A' : + ret = match_string (&buf, full_weekdays); + if (ret < 0) + return NULL; + timeptr->tm_wday = ret; + break; + case 'a' : + ret = match_string (&buf, abb_weekdays); + if (ret < 0) + return NULL; + timeptr->tm_wday = ret; + break; + case 'B' : + ret = match_string (&buf, full_month); + if (ret < 0) + return NULL; + timeptr->tm_mon = ret; + break; + case 'b' : + case 'h' : + ret = match_string (&buf, abb_month); + if (ret < 0) + return NULL; + timeptr->tm_mon = ret; + break; + case 'C' : + ret = strtol (buf, &s, 10); + if (s == buf) + return NULL; + timeptr->tm_year = (ret * 100) - tm_year_base; + buf = s; + break; + case 'c' : + abort (); + case 'D' : /* %m/%d/%y */ + s = strptime (buf, "%m/%d/%y", timeptr); + if (s == NULL) + return NULL; + buf = s; + break; + case 'd' : + case 'e' : + ret = strtol (buf, &s, 10); + if (s == buf) + return NULL; + timeptr->tm_mday = ret; + buf = s; + break; + case 'H' : + case 'k' : + ret = strtol (buf, &s, 10); + if (s == buf) + return NULL; + timeptr->tm_hour = ret; + buf = s; + break; + case 'I' : + case 'l' : + ret = strtol (buf, &s, 10); + if (s == buf) + return NULL; + if (ret == 12) + timeptr->tm_hour = 0; + else + timeptr->tm_hour = ret; + buf = s; + break; + case 'j' : + ret = strtol (buf, &s, 10); + if (s == buf) + return NULL; + timeptr->tm_yday = ret - 1; + buf = s; + break; + case 'm' : + ret = strtol (buf, &s, 10); + if (s == buf) + return NULL; + timeptr->tm_mon = ret - 1; + buf = s; + break; + case 'M' : + ret = strtol (buf, &s, 10); + if (s == buf) + return NULL; + timeptr->tm_min = ret; + buf = s; + break; + case 'n' : + if (*buf == '\n') + ++buf; + else + return NULL; + break; + case 'p' : + ret = match_string (&buf, ampm); + if (ret < 0) + return NULL; + if (timeptr->tm_hour == 0) { + if (ret == 1) + timeptr->tm_hour = 12; + } else + timeptr->tm_hour += 12; + break; + case 'r' : /* %I:%M:%S %p */ + s = strptime (buf, "%I:%M:%S %p", timeptr); + if (s == NULL) + return NULL; + buf = s; + break; + case 'R' : /* %H:%M */ + s = strptime (buf, "%H:%M", timeptr); + if (s == NULL) + return NULL; + buf = s; + break; + case 'S' : + ret = strtol (buf, &s, 10); + if (s == buf) + return NULL; + timeptr->tm_sec = ret; + buf = s; + break; + case 't' : + if (*buf == '\t') + ++buf; + else + return NULL; + break; + case 'T' : /* %H:%M:%S */ + case 'X' : + s = strptime (buf, "%H:%M:%S", timeptr); + if (s == NULL) + return NULL; + buf = s; + break; + case 'u' : + ret = strtol (buf, &s, 10); + if (s == buf) + return NULL; + timeptr->tm_wday = ret - 1; + buf = s; + break; + case 'w' : + ret = strtol (buf, &s, 10); + if (s == buf) + return NULL; + timeptr->tm_wday = ret; + buf = s; + break; + case 'U' : + ret = strtol (buf, &s, 10); + if (s == buf) + return NULL; + set_week_number_sun (timeptr, ret); + buf = s; + break; + case 'V' : + ret = strtol (buf, &s, 10); + if (s == buf) + return NULL; + set_week_number_mon4 (timeptr, ret); + buf = s; + break; + case 'W' : + ret = strtol (buf, &s, 10); + if (s == buf) + return NULL; + set_week_number_mon (timeptr, ret); + buf = s; + break; + case 'x' : + s = strptime (buf, "%Y:%m:%d", timeptr); + if (s == NULL) + return NULL; + buf = s; + break; + case 'y' : + ret = strtol (buf, &s, 10); + if (s == buf) + return NULL; + if (ret < 70) + timeptr->tm_year = 100 + ret; + else + timeptr->tm_year = ret; + buf = s; + break; + case 'Y' : + ret = strtol (buf, &s, 10); + if (s == buf) + return NULL; + timeptr->tm_year = ret - tm_year_base; + buf = s; + break; + case 'Z' : + abort (); + case '\0' : + --fmt; + /* FALLTHROUGH */ + case '%' : + if (*buf == '%') + ++buf; + else + return NULL; + break; + default : + if (*buf == '%' || *++buf == c) + ++buf; + else + return NULL; + break; + } + } else { + if (*buf == c) + ++buf; + else + return NULL; + } + } + return (char *)buf; +} + + +/* Missing round() function in MS VC++ + */ +double round(double r) { + return (r > 0.0) ? floor(r + 0.5) : ceil(r - 0.5); +} + + +#endif /* WIN32 */ diff --git a/iipsrv/windows/Time.h b/iipsrv/windows/Time.h new file mode 100644 index 0000000..96b2c3c --- /dev/null +++ b/iipsrv/windows/Time.h @@ -0,0 +1,40 @@ +/* Missing time implementations for Windows + + Copyright (C) 2011-2012 Ruven Pillay. + + 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 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +#ifndef TIME_H +#define TIME_H + +// Define mising time related functions on Windows and add round function for MSVC compiler +#ifdef WIN32 + +#include + +struct timezone +{ + int tz_minuteswest; /* minutes W of Greenwich */ + int tz_dsttime; /* type of dst correction */ +}; + +time_t timegm(struct tm*); +char *strptime(const char*, const char*, struct tm*); +int gettimeofday(struct timeval*, struct timezone*); +double round(double); + +#endif +#endif diff --git a/iipsrv/windows/VISUAL_STUDIO_README.txt b/iipsrv/windows/VISUAL_STUDIO_README.txt new file mode 100644 index 0000000..d551db0 --- /dev/null +++ b/iipsrv/windows/VISUAL_STUDIO_README.txt @@ -0,0 +1 @@ +Please read "unified installers\Readme.txt" for more info about building iipimage and installers. \ No newline at end of file diff --git a/iipsrv/windows/dependencies/dlls/x64/64-bit kdu_v73, libfcgi and kdu_compress b/iipsrv/windows/dependencies/dlls/x64/64-bit kdu_v73, libfcgi and kdu_compress new file mode 100644 index 0000000..e69de29 diff --git a/iipsrv/windows/dependencies/dlls/x86/32-bit kdu_v73, libfcgi and kdu_compress b/iipsrv/windows/dependencies/dlls/x86/32-bit kdu_v73, libfcgi and kdu_compress new file mode 100644 index 0000000..e69de29 diff --git a/iipsrv/windows/dependencies/includes/header files and some kakadu source files b/iipsrv/windows/dependencies/includes/header files and some kakadu source files new file mode 100644 index 0000000..e69de29 diff --git a/iipsrv/windows/dependencies/libs/x64/64-bit libraries b/iipsrv/windows/dependencies/libs/x64/64-bit libraries new file mode 100644 index 0000000..e69de29 diff --git a/iipsrv/windows/dependencies/libs/x86/32-bit libraries b/iipsrv/windows/dependencies/libs/x86/32-bit libraries new file mode 100644 index 0000000..e69de29 diff --git a/iipsrv/windows/iipsrv-MSVC2008.sln b/iipsrv/windows/iipsrv-MSVC2008.sln new file mode 100644 index 0000000..f207e35 --- /dev/null +++ b/iipsrv/windows/iipsrv-MSVC2008.sln @@ -0,0 +1,26 @@ + +Microsoft Visual Studio Solution File, Format Version 10.00 +# Visual Studio 2008 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "iipsrv", "iipsrv.vcproj", "{926A2718-93A6-428D-B801-AEBD97A48977}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Debug|x64 = Debug|x64 + Release|Win32 = Release|Win32 + Release|x64 = Release|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {926A2718-93A6-428D-B801-AEBD97A48977}.Debug|Win32.ActiveCfg = Debug|Win32 + {926A2718-93A6-428D-B801-AEBD97A48977}.Debug|Win32.Build.0 = Debug|Win32 + {926A2718-93A6-428D-B801-AEBD97A48977}.Debug|x64.ActiveCfg = Debug|x64 + {926A2718-93A6-428D-B801-AEBD97A48977}.Debug|x64.Build.0 = Debug|x64 + {926A2718-93A6-428D-B801-AEBD97A48977}.Release|Win32.ActiveCfg = Release|Win32 + {926A2718-93A6-428D-B801-AEBD97A48977}.Release|Win32.Build.0 = Release|Win32 + {926A2718-93A6-428D-B801-AEBD97A48977}.Release|x64.ActiveCfg = Release|x64 + {926A2718-93A6-428D-B801-AEBD97A48977}.Release|x64.Build.0 = Release|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/iipsrv/windows/iipsrv-MSVC2010.sln b/iipsrv/windows/iipsrv-MSVC2010.sln new file mode 100644 index 0000000..cff624a --- /dev/null +++ b/iipsrv/windows/iipsrv-MSVC2010.sln @@ -0,0 +1,26 @@ + +Microsoft Visual Studio Solution File, Format Version 11.00 +# Visual Studio 2010 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "iipsrv", "iipsrv.vcxproj", "{18F529A3-258B-40C9-986C-57826894DD0B}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Debug|x64 = Debug|x64 + Release|Win32 = Release|Win32 + Release|x64 = Release|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {18F529A3-258B-40C9-986C-57826894DD0B}.Debug|Win32.ActiveCfg = Debug|Win32 + {18F529A3-258B-40C9-986C-57826894DD0B}.Debug|Win32.Build.0 = Debug|Win32 + {18F529A3-258B-40C9-986C-57826894DD0B}.Debug|x64.ActiveCfg = Release|x64 + {18F529A3-258B-40C9-986C-57826894DD0B}.Debug|x64.Build.0 = Release|x64 + {18F529A3-258B-40C9-986C-57826894DD0B}.Release|Win32.ActiveCfg = Release|Win32 + {18F529A3-258B-40C9-986C-57826894DD0B}.Release|Win32.Build.0 = Release|Win32 + {18F529A3-258B-40C9-986C-57826894DD0B}.Release|x64.ActiveCfg = Release|x64 + {18F529A3-258B-40C9-986C-57826894DD0B}.Release|x64.Build.0 = Release|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/iipsrv/windows/iipsrv.vcproj b/iipsrv/windows/iipsrv.vcproj new file mode 100644 index 0000000..9636af0 --- /dev/null +++ b/iipsrv/windows/iipsrv.vcproj @@ -0,0 +1,556 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/iipsrv/windows/iipsrv.vcxproj b/iipsrv/windows/iipsrv.vcxproj new file mode 100644 index 0000000..aaea776 --- /dev/null +++ b/iipsrv/windows/iipsrv.vcxproj @@ -0,0 +1,243 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + {18F529A3-258B-40C9-986C-57826894DD0B} + Win32Proj + IIPIMAGE + iipsrv + + + + Application + true + Unicode + + + Application + true + Unicode + + + Application + false + true + Unicode + + + Application + false + true + Unicode + + + + + + + + + + + + + + + + + + + true + .fcgi + + + false + .fcgi + + + false + .fcgi + + + false + .fcgi + false + + + + + + Level1 + Disabled + WIN32;_DEBUG;_CONSOLE;HAVE_MEMCACHED;HAVE_KAKADU;HAVE_TIME_H;VERSION="0.9.9";_BASETSD_H;%(PreprocessorDefinitions) + $(ProjectDir)\dependencies\includes;%(AdditionalIncludeDirectories) + + + Console + true + $(ProjectDir)\dependencies\libs\x86;%(AdditionalLibraryDirectories) + MemCacheClient.lib;kdu_v73R.lib;jpeg-static.lib;libfcgi.lib;libtiff.lib;zlibwapi.lib;%(AdditionalDependencies) + MSVCRT; + /LTCG %(AdditionalOptions) + + + + + + + Level1 + Disabled + WIN32;_DEBUG;_CONSOLE;HAVE_KAKADU;HAVE_MEMCACHED;HAVE_TIME_H;VERSION="0.9.9";_BASETSD_H;%(PreprocessorDefinitions) + $(ProjectDir)\dependencies\includes;%(AdditionalIncludeDirectories) + + + Console + true + $(ProjectDir)\dependencies\libs\x64;%(AdditionalLibraryDirectories) + MemCacheClient.lib;kdu_v73R.lib;jpeg-static.lib;libfcgi.lib;libtiff.lib;zlibwapi.lib;%(AdditionalDependencies) + MSVCRT;%(IgnoreSpecificDefaultLibraries) + /LTCG %(AdditionalOptions) + + + + + Level2 + + + MaxSpeed + true + true + WIN32;NDEBUG;_CONSOLE;VERSION="0.9.9";HAVE_MEMCACHED;HAVE_KAKADU;HAVE_TIME_H;_BASETSD_H;%(PreprocessorDefinitions) + $(ProjectDir)\dependencies\includes;%(AdditionalIncludeDirectories) + Speed + true + true + false + + + Console + true + true + true +<<<<<<< HEAD + $(ProjectDir)\dependencies\libs;%(AdditionalLibraryDirectories) + MemCacheClient.lib;kdu_v64R.lib;jpeg.lib;libfcgi.lib;libtiff.lib;zlibwapi.lib;%(AdditionalDependencies) +======= + $(ProjectDir)\dependencies\libs\x86;%(AdditionalLibraryDirectories) +<<<<<<< HEAD + MemCacheClient.lib;kdu_v73R.lib;jpeg.lib;libfcgi.lib;libtiff.lib;zlibstat.lib;%(AdditionalDependencies) +>>>>>>> 5f92adc... Big cleaning of unified installers folder +======= + MemCacheClient.lib;kdu_v73R.lib;jpeg-static.lib;libfcgi.lib;libtiff.lib;zlibstat.lib;%(AdditionalDependencies) +>>>>>>> 252035d... small fix of IIS script, removed redundant Time.h definition, changed + /LTCG %(AdditionalOptions) + + + Default + + + + + Level2 + + + MaxSpeed + true + true + WIN32;NDEBUG;_CONSOLE;HAVE_KAKADU;HAVE_MEMCACHED;VERSION="0.9.9";HAVE_TIME_H;_BASETSD_H;%(PreprocessorDefinitions) + $(ProjectDir)\dependencies\includes;%(AdditionalIncludeDirectories) + Speed + true + true + false + + + Console + true + true + true +<<<<<<< HEAD + $(ProjectDir)\dependencies\libs;%(AdditionalLibraryDirectories) + MemCacheClient.lib;kdu_v64R.lib;jpeg.lib;libfcgi.lib;libtiff.lib;zlibwapi.lib;%(AdditionalDependencies) +======= + $(ProjectDir)\dependencies\libs\x64;%(AdditionalLibraryDirectories) +<<<<<<< HEAD + MemCacheClient.lib;kdu_v73R.lib;jpeg.lib;libfcgi.lib;libtiff.lib;zlibstat.lib;%(AdditionalDependencies) +>>>>>>> 5f92adc... Big cleaning of unified installers folder +======= + MemCacheClient.lib;kdu_v73R.lib;jpeg-static.lib;libfcgi.lib;libtiff.lib;zlibstat.lib;%(AdditionalDependencies) +>>>>>>> 252035d... small fix of IIS script, removed redundant Time.h definition, changed + /LTCG %(AdditionalOptions) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/iipsrv/windows/iipsrv.vcxproj.filters b/iipsrv/windows/iipsrv.vcxproj.filters new file mode 100644 index 0000000..bc8699b --- /dev/null +++ b/iipsrv/windows/iipsrv.vcxproj.filters @@ -0,0 +1,159 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + \ No newline at end of file diff --git a/iipsrv/windows/unified installers/README.txt b/iipsrv/windows/unified installers/README.txt new file mode 100644 index 0000000..3d4f1bd --- /dev/null +++ b/iipsrv/windows/unified installers/README.txt @@ -0,0 +1,19 @@ +To make installers of iipimage you must do following steps. + +*************************************REQUIRED STEPS************************************* + +1. Build dependencies of iipimage and iipimage. Step by step tutorial, how to build them + is available here: http://help.oldmapsonline.org/jpeg2000/windows/how-to-build-windows-binaries + +2. Download download-and-build-pack.zip from following link and unpack it at the same + level as iipsrv folder, so you will have iipsrv and download-and-build-pack side by side + in a folder. + Link: https://github.com/klokantech/iipsrv/releases/download/D%26B-pack-1.0/download-and-build-pack.zip + + Note: If you want to build JPEG2000Transcoder for yourself, you must replace the one + in download-and-build-pack. Also, if you want to use version of kakadu other than 7.3, + you must edit this version in scripts. + +3. Open scripts in inno setup and build them + +***************************************************************************************** \ No newline at end of file diff --git a/iipsrv/windows/unified installers/iipimage_IIS_x86_x64.iss b/iipsrv/windows/unified installers/iipimage_IIS_x86_x64.iss new file mode 100644 index 0000000..ec7399e --- /dev/null +++ b/iipsrv/windows/unified installers/iipimage_IIS_x86_x64.iss @@ -0,0 +1,391 @@ +;Installer for IIPImage Server 32/64 bit for IIS server (Win Vista+) with Kakadu, +; Memcached and transcoder utility for JPEG 2000 conversions +[Setup] +ArchitecturesInstallIn64BitMode=x64 +PrivilegesRequired=admin +AppName=IIPImage JPEG2000 +AppVersion=0.9.9 +DefaultDirName={pf}\IIPImage JPEG2000 +DefaultGroupName=IIPImage JPEG2000 +UninstallDisplayIcon={app}\iipsrv.exe +LicenseFile={#file AddBackslash(SourcePath) + "IIPServerLicense.rtf"} +Compression=lzma2 +SolidCompression=yes +AllowNoIcons=no +OutputDir=. +OutputBaseFilename=IIPImage_IIS_x86_x64 +;maximal resolution is 164x314, picture has 163x314, which creates 1 pixel border +WizardImageFile=wizardImage.bmp +WizardImageStretch=no +;color which creates border +WizardImageBackColor=$A0A0A0 +;max resolution 55x58 pixels +WizardSmallImageFile=wizardSmallImage.bmp + +[Dirs] +;directories for images and Logs +Name: "{code:GetImagesDir}" +Name: "{code:GetVirtDir}\Logs" + +[Files] +;Program files 32bit (iipimage server files) +Source: "..\Release\iipsrv.exe"; DestDir: "{app}"; Check: not Is64BitInstallMode +Source: "..\dependencies\dlls\x86\kdu_v73R.dll"; DestDir: "{app}"; Check: not Is64BitInstallMode +Source: "..\dependencies\dlls\x86\libfcgi.dll"; DestDir: "{app}"; Check: not Is64BitInstallMode +Source: "..\..\..\download-and-build-pack\x86\msvcp100.dll"; DestDir: "{app}"; Check: not Is64BitInstallMode +Source: "..\..\..\download-and-build-pack\x86\msvcr100.dll"; DestDir: "{app}"; Check: not Is64BitInstallMode +;Program files 64 bit (iipimage server files) +Source: "..\x64\Release\iipsrv.exe"; DestDir: "{app}"; Check: Is64BitInstallMode +Source: "..\dependencies\dlls\x64\kdu_v73R.dll"; DestDir: "{app}"; Check: Is64BitInstallMode +Source: "..\dependencies\dlls\x64\libfcgi.dll"; DestDir: "{app}"; Check: Is64BitInstallMode +Source: "..\..\..\download-and-build-pack\x64\msvcp100.dll"; DestDir: "{app}"; Check: Is64BitInstallMode +Source: "..\..\..\download-and-build-pack\x64\msvcr100.dll"; DestDir: "{app}"; Check: Is64BitInstallMode +Source: "Readme\IIS\Readme.rtf"; DestDir: "{app}"; Flags: isreadme +;Virtual directory files - viewer + shortcuts +;index.html for MooViewer is created in index-Moo.bat +Source: "..\..\..\download-and-build-pack\iipsrv.fcgi"; DestDir: "{code:GetVirtDir}" +Source: "..\..\..\download-and-build-pack\MooViewer2.0\css\ie.css"; DestDir: "{code:GetVirtDir}\MooViewer2.0\css" +Source: "..\..\..\download-and-build-pack\MooViewer2.0\css\iip.css"; DestDir: "{code:GetVirtDir}\MooViewer2.0\css" +Source: "..\..\..\download-and-build-pack\MooViewer2.0\images\iip.32x32.png"; DestDir: "{code:GetVirtDir}\MooViewer2.0\images" +Source: "..\..\..\download-and-build-pack\MooViewer2.0\images\iip.png"; DestDir: "{code:GetVirtDir}\MooViewer2.0\images" +Source: "..\..\..\download-and-build-pack\MooViewer2.0\images\iip-favicon.png"; DestDir: "{code:GetVirtDir}\MooViewer2.0\images" +Source: "..\..\..\download-and-build-pack\MooViewer2.0\images\reset.png"; DestDir: "{code:GetVirtDir}\MooViewer2.0\images" +Source: "..\..\..\download-and-build-pack\MooViewer2.0\images\reset.svg"; DestDir: "{code:GetVirtDir}\MooViewer2.0\images" +Source: "..\..\..\download-and-build-pack\MooViewer2.0\images\zoomIn.png"; DestDir: "{code:GetVirtDir}\MooViewer2.0\images" +Source: "..\..\..\download-and-build-pack\MooViewer2.0\images\zoomIn.svg"; DestDir: "{code:GetVirtDir}\MooViewer2.0\images" +Source: "..\..\..\download-and-build-pack\MooViewer2.0\images\zoomOut.png"; DestDir: "{code:GetVirtDir}\MooViewer2.0\images" +Source: "..\..\..\download-and-build-pack\MooViewer2.0\images\zoomOut.svg"; DestDir: "{code:GetVirtDir}\MooViewer2.0\images" +Source: "..\..\..\download-and-build-pack\MooViewer2.0\javascript\iipmooviewer-2.0.js"; DestDir: "{code:GetVirtDir}\MooViewer2.0\javascript" +Source: "..\..\..\download-and-build-pack\MooViewer2.0\javascript\mootools-core-1.3.2-full-nocompat.js"; DestDir: "{code:GetVirtDir}\MooViewer2.0\javascript" +Source: "..\..\..\download-and-build-pack\MooViewer2.0\javascript\mootools-more-1.3.2.1.js"; DestDir: "{code:GetVirtDir}\MooViewer2.0\javascript" +Source: "..\..\..\download-and-build-pack\MooViewer2.0\javascript\protocols.js"; DestDir: "{code:GetVirtDir}\MooViewer2.0\javascript" +Source: "..\..\..\download-and-build-pack\index.html"; DestDir: "{code:GetVirtDir}" +Source: "..\..\..\download-and-build-pack\IIPImage MooViewer 2.0.url"; DestDir: "{code:GetVirtDir}" +Source: "..\..\..\download-and-build-pack\IIPImage Project Website.url"; DestDir: "{code:GetVirtDir}" +Source: "..\..\..\download-and-build-pack\Online Demo.url"; DestDir: "{code:GetVirtDir}" +;Images directory files - demo image +Source: "..\..\..\download-and-build-pack\demo.jp2"; DestDir: "{code:GetImagesDir}" + +;JPEG2000Transcoder files +;32bit wrapper + configuration.ini (wrapper is same for 32bit and 64bit version) +Source: "..\..\..\download-and-build-pack\Jpeg2000Transcoder.exe"; DestDir: "{code:GetTranscoderDir}" +Source: "..\..\..\download-and-build-pack\configuration.ini"; DestDir: "{code:GetTranscoderDir}" +Source: "..\..\..\download-and-build-pack\QtCore4.dll"; DestDir: "{code:GetTranscoderDir}" +Source: "..\..\..\download-and-build-pack\QtGui4.dll"; DestDir: "{code:GetTranscoderDir}" +Source: "..\..\..\download-and-build-pack\x86\msvcp100.dll"; DestDir: "{code:GetTranscoderDir}" +Source: "..\..\..\download-and-build-pack\x86\msvcr100.dll"; DestDir: "{code:GetTranscoderDir}" +;32bit transcoding apps (djpeg and kdu_compress) +Source: "..\..\..\download-and-build-pack\x86\djpeg.exe"; DestDir: "{code:GetTranscoderDir}\bins"; Check: not Is64BitInstallMode +Source: "..\dependencies\dlls\x86\kdu_compress.exe"; DestDir: "{code:GetTranscoderDir}\bins"; Check: not Is64BitInstallMode +Source: "..\dependencies\dlls\x86\kdu_v73R.dll"; DestDir: "{code:GetTranscoderDir}\bins"; Check: not Is64BitInstallMode +Source: "..\..\..\download-and-build-pack\x86\msvcp100.dll"; DestDir: "{code:GetTranscoderDir}\bins"; Check: not Is64BitInstallMode +Source: "..\..\..\download-and-build-pack\x86\msvcr100.dll"; DestDir: "{code:GetTranscoderDir}\bins"; Check: not Is64BitInstallMode +;64bit transcoding apps (djpeg and kdu_compress) +Source: "..\..\..\download-and-build-pack\x64\djpeg.exe"; DestDir: "{code:GetTranscoderDir}\bins"; Check: Is64BitInstallMode +Source: "..\dependencies\dlls\x64\kdu_compress.exe"; DestDir: "{code:GetTranscoderDir}\bins"; Check: Is64BitInstallMode +Source: "..\dependencies\dlls\x64\kdu_v73R.dll"; DestDir: "{code:GetTranscoderDir}\bins"; Check: Is64BitInstallMode +Source: "..\..\..\download-and-build-pack\x64\msvcp100.dll"; DestDir: "{code:GetTranscoderDir}\bins"; Check: Is64BitInstallMode +Source: "..\..\..\download-and-build-pack\x64\msvcr100.dll"; DestDir: "{code:GetTranscoderDir}\bins"; Check: Is64BitInstallMode +;Memcached +Source: "..\..\..\download-and-build-pack\x86\memcached.exe"; DestDir: "{code:GetMemcachedDir}"; Check: not Is64BitInstallMode +Source: "..\..\..\download-and-build-pack\x64\memcached.exe"; DestDir: "{code:GetMemcachedDir}"; Check: Is64BitInstallMode +;Temporary files - first sets rights and installs IIS, second configures everything, +; third creates index.html and starts it in browser +Source: "Batch_files\IIS\install.bat"; DestDir: "{tmp}" +Source: "Batch_files\IIS\configure.bat"; DestDir: "{tmp}" +Source: "Batch_files\IIS\index-Moo.bat"; DestDir: "{tmp}" + +[UninstallDelete] +;web.config is created during configuration of IIS +Type: files; Name: "{code:GetVirtDir}\web.config" + +[Icons] +Name: "{group}\IIPImage MooViewer 2.0"; Filename: "{code:GetVirtDir}\IIPImage MooViewer 2.0.url" +Name: "{group}\Jpeg2000 Transcoder"; Filename: "{code:GetTranscoderDir}\Jpeg2000Transcoder.exe" +Name: "{group}\Images"; Filename: "{code:GetImagesDir}" +Name: "{group}\Uninstall IIPImage"; Filename: "{app}\unins000.exe" +Name: "{group}\Readme"; Filename: "{app}\Readme.rtf" +Name: "{group}\IIPImage Project Website"; Filename: "{code:GetVirtDir}\IIPImage Project Website.url" +Name: "{group}\Online Demo"; Filename: "{code:GetVirtDir}\Online Demo.url" + +[Code] +var + //global variables - in whole code there is reference to this pages + VirtDirNamePage: TInputQueryWizardPage; + ImagesPathPage: TInputDirWizardPage; + MemcachedPathPage: TInputDirWizardPage; + TranscoderPathPage: TInputDirWizardPage; + ProgressPage: TOutputProgressWizardPage; + +{ Creates custom wizard pages } +procedure CreateTheWizardPages; +begin + VirtDirNamePage := CreateInputQueryPage(wpSelectDir, + 'Name of virtual directory', 'What will be name of directory?', + 'Please specify name for your virtual directory, it will be included in URL for all accesses to ImageServer.'); + VirtDirNamePage.Add('Name of virtual directory:', False); + VirtDirNamePage.Values[0] := 'imageserver-test'; + + MemcachedPathPage := CreateInputDirPage(VirtDirNamePage.ID, + 'Select directory for Memcached', 'Where should be Memcached installed?', + 'Select directory where will be installed Memcached, cache server improving performance of IIPImage, then click Next', + True, 'Memcached'); + MemcachedPathPage.Add('Memcached directory:'); + MemcachedPathPage.Values[0] := ExpandConstant('{pf}\Memcached'); + + TranscoderPathPage := CreateInputDirPage(MemcachedPathPage.ID, + 'Select directory for JPEG2000 Transcoder', 'Where should be JPEG2000 Transcoder installed?', + 'Select directory where will be installed JPEG2000 Transcoder, utility for transcoding images to jp2 format', + True, 'JPEG2000 Transcoder'); + TranscoderPathPage.Add('JPEG2000 Transcoder directory:'); + TranscoderPathPage.Values[0] := ExpandConstant('{pf}\JPEG2000 Transcoder'); + + ImagesPathPage := CreateInputDirPage(TranscoderPathPage.ID, + 'Select physical path for Images directory', 'Where should be stored images?', + 'Select directory where will be stored images, then click Next', + True, 'IIPImage Images'); + ImagesPathPage.Add('Images directory:'); + ImagesPathPage.Values[0] := ExpandConstant('{commondocs}\IIPImage Images'); + + ProgressPage := CreateOutputProgressPage('Configuration', 'Installer is now ' + +'installing and configuring required components'); +end; + +{ Getters for directories and names set by user in installation - needed in Setup section } +function GetImagesDir(Param: String): String; +begin + Result := ImagesPathPage.Values[0]; +end; + +function GetVirtDir(Param: String): String; +begin + Result := ExpandConstant('{app}\virtual-directory'); +end; + +function GetVirtDirName(Param: String): String; +begin + Result := VirtDirNamePage.Values[0]; +end; + +function GetMemcachedDir(Param: String): String; +begin + Result := MemcachedPathPage.Values[0]; +end; + +function GetTranscoderDir(Param: String): String; +begin + Result := TranscoderPathPage.Values[0]; +end; + +{ Updates information shown just before installation - adds information from custom pages} +function UpdateReadyMemo(Space, NewLine, MemoUserInfoInfo, MemoDirInfo, MemoTypeInfo, + MemoComponentsInfo, MemoGroupInfo, MemoTasksInfo: String): String; +var + S: String; +begin + S := ''; + S := S + MemoDirInfo + NewLine; + S := S + NewLine; + S := S + 'Memcached Directory:' + NewLine; + S := S + Space + 'Destination:' + MemcachedPathPage.Values[0] + NewLine; + S := S + NewLine; + S := S + 'JPEG2000 Transcoder Directory:' + NewLine; + S := S + Space + 'Destination:' + TranscoderPathPage.Values[0] + NewLine; + S := S + NewLine; + S := S + 'Virtual Directory:' + NewLine; + S := S + Space + 'Name: ' + VirtDirNamePage.Values[0] + NewLine; + S := S + Space + 'Destination:' + GetVirtDir('') + NewLine; + S := S + NewLine; + S := S + 'Images Directory:' + NewLine; + S := S + Space + 'Destination:' + ImagesPathPage.Values[0] + NewLine; + S := S + NewLine; + S := S + MemoGroupInfo + NewLine; + Result := S; +end; + +{ Configuration section and installation of IIS } +procedure MyAfterInstall(); +var + ResultCode,I: Integer; +begin + // Save the name of virtual directory into registry + RegWriteStringValue(HKEY_LOCAL_MACHINE, + 'SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\IIPImage JPEG2000_is1', + 'VirtDirName', VirtDirNamePage.Values[0]); + ProgressPage.SetText('Installing and configuring IIS', + 'Please wait, it will take max 10 minutes.'); + ProgressPage.SetProgress(0,0); + ProgressPage.Show; + // Install IIS and set rights for virtual directory: + // 1. param - physical path to virtual directory, + // 2. param - path to Images directory, + Exec(ExpandConstant('{tmp}\install.bat'), + '"'+GetVirtDir('')+'" "' + +ImagesPathPage.Values[0]+'"', '', + SW_HIDE, ewNoWait, ResultCode); + I := 0; + try + // active waiting for execution of script but maximum is cca 10 minutes + while((NOT RegValueExists(HKEY_LOCAL_MACHINE, + 'SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\IIPImage JPEG2000_is1', 'IISScript')) + and (I < 6000)) do + begin + //every tick increase by 0.1% and on 100% it starts again from zero + ProgressPage.SetProgress((I mod 1000), 1000); + sleep(100); + I := I+1; + end; + // Starts memcached as service and configures iis and virtual directory + // 1. param - path to app. directory, + // 2. param - name of virtual directory, + // 3. param - physical path to virtual directory, + // 4. param - path to Images folder, + // 5. param - path to memcached folder + Exec(ExpandConstant('{tmp}\configure.bat'), + '"'+ExpandConstant('{app}') + +'" "'+VirtDirNamePage.Values[0] + +'" "'+GetVirtDir('') + +'" "'+ImagesPathPage.Values[0] + +'" "'+MemcachedPathPage.Values[0]+'"', + '', SW_HIDE, ewWaitUntilTerminated, ResultCode); + if (ResultCode <> 0) then + MsgBox('CRITICAL ERROR:' #13#13 'Error occured during installation or configuration of IIS.' #13 + 'Please read Readme.txt file for information how to solve this problem.', + mbCriticalError, MB_OK); + // Create index.html, url shortcut to this file and configures configuration.ini for transcoder + // 1. param - name of virtual directory, + // 2. param - physical path to virtual directory, + // 3. param - path to Images folder, + // 4. param - path to transcoder dir + Exec(ExpandConstant('{tmp}\index-Moo.bat'), + '"'+VirtDirNamePage.Values[0] + +'" "'+GetVirtDir('') + +'" "'+ImagesPathPage.Values[0] + +'" "'+TranscoderPathPage.Values[0]+'"', + '', SW_HIDE, ewWaitUntilTerminated, ResultCode); + ProgressPage.SetProgress(100, 100); + finally + ProgressPage.Hide; + end; +end; + +{ Start of Installer } +procedure InitializeWizard(); +var + Version: TWindowsVersion; +begin + // Create custom wizard pages + CreateTheWizardPages; + // check whether we are installing on Vista or higher OS + GetWindowsVersionEx(Version); + if((not Version.NTPlatform) or (Version.Major < 6)) then + begin + MsgBox('Unsupported OS:' #13#13 + 'IIS version of installation works only on Windows Vista or higher OS.' + +' You may try installer with embedded apache server for Windows XP.', + mbCriticalError, MB_OK); + Abort(); + end; +end; + +{ Function after clicking Next button (checks for previous installation) } +function NextButtonClick(CurPageID: Integer): Boolean; +var UninstallString: String; ResultCode: Integer; +begin//b1 + //IIPIMAGE BRANCH + if CurPageID = wpWelcome then + begin//b2 + // check if previous installation exists + if (RegValueExists(HKEY_LOCAL_MACHINE, + 'SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\IIPImage JPEG2000_is1', 'UninstallString')) then + begin//b3 + RegQueryStringValue(HKEY_LOCAL_MACHINE, + 'SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\IIPImage JPEG2000_is1', + 'UninstallString', UninstallString); + //if uninstaller was removed, do nothing, we can't uninstall either, we will overwrite + if (FileExists(UninstallString)) then + begin//b4 + if (MsgBox('Already installed:' #13#13 'The previous IIPImage installation was found. ' + + 'Previous version should be uninstalled before installing new one.' + + 'Do you want to uninstall previous version now?', mbConfirmation, MB_YESNO) = IDYES) then + begin//b5 + //uninstall string contains quotes, so we have to pass the uninstall string using '>' + //see documentation of Exec for more info + Exec('>', UninstallString, '', SW_SHOW, ewWaitUntilTerminated, ResultCode) + if (ResultCode <> 0) then + begin//b6 + MsgBox('Uninstallation cancelled:' #13#13 'Uninstallation was cancelled, please uninstall again.', + mbInformation, MB_OK); + Abort(); + end;//e6 + MsgBox('Installation continue:' #13#13 'The previous IIPImage installation was removed. ' + + 'Installation may continue.', mbInformation, MB_OK); + end//e5 + else + begin//b7 + MsgBox('Installation failed:' #13#13 'Can''t continue installation without removing previous version.', + mbInformation, MB_OK); + Abort(); + end;//e7 + end;//e4 end of branch with existing previous IIPImage + end;//e3 + end;//e2 end of wpWelcome Next button click + Result := True; +end;//e1 + +{ After files were copied in appropriate directories, start installation and configuration of IIS } +procedure CurStepChanged(CurStep: TSetupStep); +begin + if CurStep = ssPostInstall then begin + MyAfterInstall(); + end; +end; + +{ Uninstall } +procedure CurUninstallStepChanged(CurUninstallStep: TUninstallStep); +var ResultCode,ErrorCode: Integer; App,VirtDirName: String; +begin + if CurUninstallStep = usUninstall then + begin + // Ask for removal of virtual directory + if (MsgBox('Remove virtual directory and FCGI application:' #13#13 + 'Do you want to remove virtual directory and FCGI application for IIP Image Server created during installation process?', + mbConfirmation, MB_YESNO) = idYes) then + begin + ErrorCode := -2; + if RegQueryStringValue(HKEY_LOCAL_MACHINE, 'SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\IIPImage JPEG2000_is1', + 'InstallLocation', App) then + begin + Exec(ExpandConstant('{cmd}'), '/C %windir%\system32\inetsrv\appcmd.exe set config -section:system.webServer/fastCgi /-"[fullPath='''+App+'iipsrv.exe'']" /commit:apphost', '', + SW_HIDE, ewWaitUntilTerminated, ResultCode); + if (ResultCode = 0) then ErrorCode := 0 + else ErrorCode := 2; + end; + if RegQueryStringValue(HKEY_LOCAL_MACHINE, 'SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\IIPImage JPEG2000_is1', + 'VirtDirName', VirtDirName) then + begin + Exec(ExpandConstant('{cmd}'), '/C %windir%\system32\inetsrv\appcmd.exe delete vdir /vdir.name:"Default Web Site/'+ + VirtDirName+'"', '', SW_HIDE, ewWaitUntilTerminated, ResultCode); + if (ResultCode <> 0) then ErrorCode := ErrorCode + 3; + end + else ErrorCode := ErrorCode - 3; + if (ErrorCode <> 0) then + {Info about ErrorCode (for developers, users don't care) + -5=Both registry values not found, + -3=First command successful, second registry not found, + -2=First registry not found, second command successful, + -1=First command failed, second registry not found, + 0=Both commands successful, + 1=First registry not found, second command failed, + 3=First command successful, second failed, + 5=Both commands failed} + MsgBox('ERROR '+IntToStr(ErrorCode)+':' #13#13 'Error occured during removing virtual directory or FCGI application.' + +' Please remove it manually.', mbInformation, MB_OK); + end; + //stop memcached so it can be uninstalled and remove memcached from Windows services + Exec(ExpandConstant('{cmd}'), '/C sc stop "memcached Server"', '', SW_HIDE, ewWaitUntilTerminated, ResultCode); + Exec(ExpandConstant('{cmd}'), '/C sc delete "memcached Server"', '', SW_HIDE, ewWaitUntilTerminated, ResultCode); + //kill iipsrv.exe if running, so it can be uninstalled + Exec(ExpandConstant('{cmd}'), '/C taskkill /F /IM iipsrv.exe', '', SW_HIDE, ewWaitUntilTerminated, ResultCode); + end; +end;